# Proof audit pass 1 — lineage stable gutter

Target: [#22385 on GitCafe](https://git.cafe/pingdotgg/t3code/pulls/22385), [#22385 on GitHub](https://github.com/pingdotgg/t3code/pull/22385).
Contributor branch: FllipEis:philipp/fix-lineage-scrollbar-shift. Original remote head: `1ff2c383984bf2e4a1e40a0fb556c042acf82469` (not the capture target).
Reviewed local head / AFTER: `c652da37518db84baa6025b3347cd2158ef5e916`.
Base: origin/main; merge-base / BEFORE: `67c0fc0cdaf963b103518862dd7b68a9c758ecf2`.
Read-only inspection in `/home/ubuntu/wt/pr-22385`, machine freestyle. No fetch, checkout/reset, server launch, captures, tests, forge comments, pushes or PR edits performed. Artifact alone is outside worktree. Pass 1 budget 60 minutes.

## Findings first

No implementation defect identified in the full origin/main...HEAD diff. It changes only ThreadRelationshipsControl.tsx: one `scrollbar-gutter-stable` class and a comment. Original max-height 13.5rem, six initial rows, +12 pagination and workflow expansion cap min(28rem,55dvh) remain unchanged. Stable classic gutter deliberately reduces the width of NON-overflowing lists too; the short-list capture must disclose that visible change. This is the smallest direct fix for content-width stability and preserves the original partial-row overflow hint. Do not promise the hint on the initial six fixed-height rows: six × 2rem = 12rem, below 13.5rem; it appears after expansion when content exceeds the cap.

Evidence is missing, as expected at this step. Implementation verdict: reasonable / no defect found by inspection. Evidence verdict: pending gate; no visual approval or merge readiness is asserted. Previously reported tests were not rerun or independently verified by this read-only auditor.

## Render-path inventory and collapse rationale

Production caller chain: ChatView → ThreadDetailsPanel → ThreadRelationshipsPanel → ThreadLineageGroup → ThreadLineageRowList. No other production caller of the changed list. ThreadDetailsCard presents inline at wide available canvas width or in a popover at narrow width. Panel is omitted for drafts, compact/essential density, or no relationship rows and no running native agents. Empty groups and collapsed Previous agents have no list, so the CSS change cannot affect them. There is no list-level loading/error branch; unavailable nodes render disabled rows; failed/error statuses affect trailing text/icons and Previous agents header count.

Three groups each own an independent six-row window: related (fork parent/child, transfer and parent-agent), active child subagents, Previous agents (terminal child subagents, initially collapsed). Show more adds 12, shows min(hidden,12), disappears when exhausted. Non-workflow rows are h-8. Merge-target rows split the link from a merge action. Other rows use a normal link; agents may show elapsed/status and hover/focus/coarse-pointer stop affordances. Labels truncate. Missing title falls back to agent title or ID; unavailable nodes disable navigation. These content variants change horizontal competition but do not change the gutter rule, and are combined into F1 rather than multiplied by every provider/status.

Workflow coordinator rows use the same outer list but have variable height: expanding sets data-workflow-expanded and increases its max-height; phase toggles and member rows can then overflow it. Empty workflow says No agents yet. Nested member lists do not receive the new class. F3 tests the distinctive expanded cap branch with long member labels and enough members to overflow. Phase status, phased/unphased members and disabled members can share that fixture; empty-workflow content is equivalent to a short nonoverflowing expanded list for this CSS rule and does not need a separate screenshot. Themes and viewport widths are crossed below. Provider icons, local/remote environments, archived data, permission and busy states do not select different gutter CSS; do not run live agents or real stop/merge mutations for evidence.

## Fixture matrix

All rows below are affected when their list is mounted with classic scrollbars. Every row is PENDING CAPTURE. Real app seeding is feasible; no isolated harness is required by the known data shapes.

| Row | Named fixture and exact state | Data needed / real-app seed | Interaction and expected observable proof | Minimum capture axes | Status |
|---|---|---|---|---|---|
| F1 | Short mixed lineage | Current fork with its merge-target parent and one long-title fork child; one waiting app-owned child agent (no elapsed clock), one completed and one failed child agent under Previous agents; optional missing related target. Expand Previous agents. Keep each group ≤6. | Full details panel, no inner list overflow; disclose reserved gutter / earlier text truncation after. Include split merge control, ordinary link and agent status in same surface. Hover/focus a row once as a supplemental sequence if claiming affordance retention. No destructive action. | 1440×900 and 390×844, each light/dark | PENDING |
| F2a | Pagination: six visible of twenty | Current thread with 20 fork children, deterministic ordered titles mixing short and long. One group only. Related shells use lineage parentThreadId=current and relationshipToParent=fork. | Initial six rows, Show 12 more. Capture list geometry and first row text box before click. Both commits have 13.5rem cap and no inner scrollbar initially. | Same four axes | PENDING |
| F2b | Pagination: overflow and exhaustion | Same data as F2a; first click gives 18 visible + Show 2 more; second gives 20 and removes button. | Capture at first overflow, same scrollTop=0; measure unchanged AFTER row content width across F2a→F2b and baseline narrowing with classic scrollbar. Record/capture sequence through second click and scroll to bottom, then back to top. Retain partial last-row hint under unchanged 13.5rem cap. First overflow is the required Before/After still; exhaustion/bottom are flow supplements. | Same four axes | PENDING |
| F3a | Workflow collapsed | A stopped/completed provider-native workflow coordinator + workflow chat and 18 available member shells; 2 phases (9 members each), deterministic long labels, finite timestamps/durations; at least one failed member, one unphased member may replace a phased member. Open Previous agents if terminal coordinator. | Collapsed coordinator row; no outer overflow. Establish geometry before workflow expansion. | Same four axes | PENDING |
| F3b | Workflow expanded and overflowing | Same F3a data; expand coordinator and both phases so >min(28rem,55dvh) content is present. | Capture expanded cap, gutter and indented members at scrollTop=0; sequence toggles phase closed/open, scrolls within list, collapses coordinator. Verify no unexpected horizontal clipping caused by reserved gutter. | Same four axes | PENDING |

Minimum required stills: 5 states × 2 viewports × 2 themes = 20 Before/After pairs (40 full-surface images). Flow sequences may reuse these frames and add terminal/bottom/phase-toggle states; do not replace whole-page stills with crops. This is three data fixtures, not a full product QA matrix. F2 covers pagination counts 6→18→20 and hidden-button branches without separate datasets. F1 combines ordinary row geometry and all three group containers; F3 covers the only alternate max-height branch. Empty, hidden panel, compact/essential and collapsed-only groups are unaffected controls, not additional screenshot requirements. If 390 layout hides lineage through density, use the real details popover at full density and record that presentation; a hidden lineage screenshot does not prove these rows.

## Real-app seeding route (capturer executes next)

1. From the required worktree, use node_modules/.bin/vp (present; vp absent on current ambient PATH). Start isolated dev once for schema migrations, retain only its own session/PID, then stop before fixture writes. Never use the live T3 home. `vp run migrate-dev-db` is an available route to realistic copied stopped threads; the script preserves lineage families. It is not itself the deterministic fixture script.
2. Inspect `node apps/server/scripts/t3-sqlite-state.ts query --base-dir <isolated-home> --sql "PRAGMA table_info(orchestration_v2_projection_threads)"` and analogous project/subagent tables. Use current schema, not guessed SQL columns. Clone app-created valid rows. Projects come from projection_projects; V2 data from orchestration_v2_projection_* payload_json. Seed consistent IDs, lineage, subagent workflow payloads, project IDs and finite timestamps. Leave event history unchanged; this proves visual layout only.
3. F1/F2 need thread shell lineage and valid project/current thread projection; F3 additionally needs a projection subagent with `workflow: {name, phases, agents}` and matching coordinator/member childThreadId shells. Reference existing realistic workflow data shape in ThreadRelationshipsControl.agents.browser.test.tsx around line 303 and workflowMembersToRuntime in packages/client-runtime/src/state/subagentRuntime.ts. That test mocks hooks and is NOT real-app evidence.
4. Restart server with the same isolated home. Pair via startup URL, navigate the real `/$environmentId/$threadId` route through buildThreadRouteParams (do not guess encoded environment IDs), open Thread details, ensure data-density=full. Use identical fixture copies on both commits. No checkout/reset in this pass; lead controls before/after workspace preparation.
5. Save the actual executable seed script, data and capture configuration outside the worktree and upload/link them with the evidence (or commit them only if lead authorizes). This matrix describes required seed data; it is NOT a delivered runnable fixture. Linked reproducible seed remains a pending prerequisite.

## Browser and classic-scrollbar prerequisites

Approved workflow read: test-t3-app skill and sqlite-fixtures reference. Use T3 Browser panel: preview_status → preview_open → pairing navigation → snapshot/interactions. Tools are exposed in this session, but runtime availability was deliberately NOT probed and no tab opened in pass 1. Do not switch to standalone Playwright/agent-browser under this workflow. If panel unavailable, report prerequisite, stop verification.

Local tools: node_modules/.bin/vp exists; node_modules exists; ~/.bun/bin/cafe exists (not invoked); ghdrop at ~/.local/bin/ghdrop. Playwright cache includes chromium_headless_shell-1223 and ffmpeg-1011. Existing isolated .t3 was not found by the directory check, so capturer must create/seed it. No healthy server assumed.

Repository ServerBrowserContexts launches headless Chromium, deviceScaleFactor=2, --force-device-scale-factor=2 and desktop UA. preview_resize supports freeform exact CSS viewport; use that instead of mobile emulation, font scaling 100%, browser zoom 100%. State measured DPR, actual browser/version/tool, viewport, no device emulation, theme and scrollbar configuration in evidence. Assert computed font sizes match before/after. Theme override must agree with the app setting; prefers-color-scheme alone will not override an explicit app theme.

Classic scrollbars are a HARD reproduction prerequisite, not an assumed property of headless Linux. App CSS already sets ::-webkit-scrollbar width:var(--app-scrollbar-width), normally 6px. First measure actual gutter: on target ul, offsetWidth-clientWidth minus horizontal borders, computed scrollbarGutter, and first row bounding box; repeat before/after overflow. Baseline F2a must have no reserved lane, baseline F2b must acquire a nonzero lane; AFTER must reserve that same lane in both states. An overlay-only run (zero width consumption) cannot prove the bug/fix. preview_open exposes no launch flags, and source launchOptions has no configurable scrollbar flag. Do not claim a supported launch flag configuration was verified here.

If native preview remains overlay-only, capturer may use an IDENTICAL, documented rendering-only stylesheet on both real-app pages to select explicit ::-webkit-scrollbar width (6px, matching product CSS), then remeasure. This is a labelled classic-scrollbar rendering configuration on the real app, not a component harness, and must not alter list width, overflow, height or scrollbar-gutter itself. Whether this forces classic mode in the installed Chromium remains UNVERIFIED. If it does not yield nonzero measured width consumption, classic configuration is a blocker: report evidence missing; do not simulate the fix with padding or widen/narrow rows manually. Optional overlay control is useful but not a substitute and not part of minimum set.

## Required delivery / pass 2 contract

Every pair: identical fixture, viewport, theme, scroll position, app settings, timestamps, rendering-only configuration and fonts. Whole page/panel context, not just list crop. Label BEFORE with merge-base above; AFTER with local head above (not original remote head). Head movement invalidates after evidence. Each pair gets amplified zero-threshold diff plus a second diff at stated threshold (recommend max per-channel delta >16/255, record exact algorithm). Record every visible change: intended stable lane, initial short-list width/truncation change, and any unrelated delta. Nothing else changed is permitted only with zero-threshold support. Flow captures show Show more and workflow/phase expansion, not merely a final still. Upload via ghdrop; lead handles PR body, not this agent.

Expected evidence claims are limited to measured width stability, unchanged caps, observed truncation/partial-row appearance and access to final rows. Do not claim readability or preserved controls unless the delivered view shows them. No desktop requirement: sole changed path is apps/web. No mobile file is touched.

VERDICT: INSUFFICIENT F1, F2a, F2b, F3a, F3b (capture step pending; classic scrollbar reproduction and reproducible seed not yet delivered)
