from pathlib import Path
root=Path('/tmp/lead-33181-r1/capture')
harness=r'''import { vi, it, expect } from "vite-plus/test";
import { commands } from "vite-plus/test/browser";
import { EnvironmentId, ThreadId } from "@t3tools/contracts";
import "~/index.css";
const state = vi.hoisted(() => ({ projections: {} as Record<string, any>, environments: {} as Record<string, any>, parents: {} as Record<string, any>, providers: new Map() }));
vi.mock(import("../../state/query"), async original => ({ ...(await original()), useEnvironmentQuery: (() => ({data: {}, isSuccess: true, isPending: false})) as never }));
vi.mock(import("@effect/atom-react"), async original => ({ ...(await original()), useAtomValue: (() => false) as never }));
vi.mock(import("../../state/entities"), () => ({
 useQuietThreadShell: ((ref: any) => state.parents[ref?.threadId] ?? null) as never,
 useThreadProjection: ((ref: any) => ref ? {projection: state.projections[ref.threadId]} : null) as never,
 useThreadRelationshipShells: ((env: any) => Object.values(state.projections).filter((p:any) => p.thread.id === env?.threadId).map((p:any) => p.thread)) as never,
 useProjects: (()=>[]) as never, useHiddenThreadKeys: (()=>new Set()) as never, useAnyEnvironmentHiding: (()=>false) as never,
}));
vi.mock(import("../../state/environments"), () => ({useEnvironment: ((id:string) => state.environments[id] ?? null) as never, useEnvironmentProviders: (()=>state.providers) as never}));
vi.mock(import("../../lib/archivedThreadsState"), () => ({useArchivedThreadSnapshots: (()=>({snapshots:[]})) as never}));
vi.mock(import("../../state/use-atom-command"), () => ({useAtomCommand: (()=>async()=>undefined) as never}));
import { render } from "../../../test/render";
import { makeThreadProjectionFixture } from "../../test-fixtures";
import { ThreadRelationshipsPanel } from "./ThreadRelationshipsControl";
const longTitle="Audit relationship labels across the synthetic staging workspace";
const longLabel="QA Station with an intentionally very long synthetic environment name";
const unbrokenTitle="InvestigateSyntheticRemoteRelationshipLayoutAcrossEnvironments";
const unbrokenLabel="SyntheticEnvironmentWithAnIntentionallyVeryLongUnbrokenMachineLabel";
function projection(id:string) { const p:any=makeThreadProjectionFixture(); p.thread={...p.thread,id,title:id,modelSelection:{instanceId:"synthetic-provider",model:"synthetic"},providerInstanceId:"synthetic-provider"}; return p; }
function remote(id:string,title:string,label:string,status:string,known=true) {
 const env="env-"+id;
 if(known) state.environments[env]={id:env,label};
 if(known) state.providers.set(env,[{instanceId:"synthetic-provider",driver:"codex",displayName:"Synthetic provider",models:[],available:true}]);
 return {id,threadId:"active",runId:null,parentNodeId:null,origin:"app_owned",createdBy:"agent",driver:"codex",providerInstanceId:"synthetic-provider",providerThreadId:null,childThreadId:null,nativeTaskRef:null,prompt:"Synthetic evidence",title,model:null,status,result:null,startedAt:null,completedAt:null,updatedAt:makeThreadProjectionFixture().thread.updatedAt,remoteChild:{environmentId:env,threadId:"child-"+id,label}};
}
it("captures scoped synthetic evidence", async()=>{
 state.projections={}; state.environments={}; state.parents={}; state.providers=new Map();
 state.projections.active=projection("active");
 state.projections.active.subagents=[remote("R1","Scan","QA","pending"),remote("R2",longTitle,"QA","waiting"),remote("R3","Scan",longLabel,"running"),remote("R4",unbrokenTitle,unbrokenLabel,"running",false)];
 state.projections.previous=projection("previous");
 state.projections.previous.subagents=["completed","failed","cancelled","interrupted","idle"].map((status,i)=>remote("R5-"+status,i%2?unbrokenTitle:longTitle,i%2?unbrokenLabel:longLabel,status));
 const scenes=[{id:"active",label:"R1–R4 · active remote agents"},{id:"previous",label:"R5 · all five terminal statuses"}];
 for(const id of ["D1","D3","D4","D5"]) {
  const p=projection(id), env="parent-env-"+id, parent="parent-"+id;
  p.thread.delegatedFrom={environmentId:env,threadId:parent,title:id==="D5"?longTitle:"Old synthetic snapshot title"};
  p.thread.linkOrigin={label:id==="D5"?longLabel:"Old alias"};
  if(id!=="D5") {state.environments[env]={id:env,label:id==="D1"?"QA":longLabel};state.parents[parent]={...p.thread,id:parent,title:id==="D4"?longTitle:"Review"};}
  state.projections[id]=p;scenes.push({id,label:id+" · "+(id==="D5"?"unavailable parent":id==="D4"?"long live title + label":id==="D3"?"short live title + long label":"fit baseline / live label wins")});
 }
 using _clock=vi.spyOn(Date,"now").mockReturnValue(Date.parse("2026-01-01T12:00:00Z"));
 await using screen=await render(<main id="evidence-root"><header><h1>Component harness — synthetic data</h1><p id="coordinate">Lineage relationships · production 280px cards</p><p id="step">Resting rows · Previous agents expanded</p></header><div className="evidence-grid">{scenes.map(scene=><article data-fixture={scene.id} key={scene.id}><h2>{scene.label}</h2><div data-thread-details-card className="dropdown-glass isolate contain-paint overflow-hidden rounded-2xl" style={{width:280}}><ThreadRelationshipsPanel environmentId={EnvironmentId.make("synthetic")} threadId={ThreadId.make(scene.id)} showLineage showSideChats={false}/></div></article>)}</div><style>{`html,body {margin:0; min-height:100%;} body {background:var(--background);color:var(--foreground);} #evidence-root{padding:24px;font-family:var(--font-sans); min-height:100vh;} header{margin-bottom:24px;} h1{font-size:20px;font-weight:600;line-height:28px;} header p{font-size:13px;color:var(--muted-foreground);line-height:22px;} #step{min-height:44px;max-width:800px;color:var(--foreground);} .evidence-grid{display:grid;grid-template-columns:repeat(3,280px);gap:32px 28px;align-items:start;} article h2{font-size:12px;font-weight:500;line-height:18px;margin-bottom:8px;max-width:280px;} @media(max-width:600px){#evidence-root{padding:20px}.evidence-grid{grid-template-columns:280px;gap:24px;}}`}</style></main>);
 await screen.getByRole("button",{name:/Previous agents/}).click();
 await commands.captureEvidence();
 expect(document.querySelectorAll('[data-fixture]')).toHaveLength(6);
});
'''
config=r'''import base from "./vite.config";
import { defineConfig } from "vite-plus";
import { playwright } from "vite-plus/test/browser-playwright";
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
const out=process.env.EVIDENCE_OUT!;
const width=Number(process.env.EVIDENCE_WIDTH||1440), height=width===1440?1000:844;
const theme=process.env.EVIDENCE_THEME||"light";
const sleep=(ms:number)=>new Promise(resolve=>setTimeout(resolve,ms));
export default defineConfig(async env=>{
 const c:any=typeof base==="function"?await base(env):base;
 const original=c.test.projects[1];
 return {...c,test:{...c.test,projects:[{...original,test:{...original.test,testTimeout:90000,browser:{...original.test.browser,viewport:{width,height},provider:playwright({launchOptions:{executablePath:"/opt/google/chrome/chrome"},contextOptions:{viewport:{width,height},deviceScaleFactor:1,reducedMotion:"reduce",colorScheme:theme as any}}),instances:[{browser:"chromium"}],commands:{...original.test.browser.commands,captureEvidence:async({page,frame}:any)=>{
  await mkdir(out,{recursive:true});
  await page.setViewportSize({width,height});
  await page.emulateMedia({reducedMotion:"reduce",colorScheme:theme});
  const f=await frame();
  await f.evaluate(({theme,width,height}:any)=>{document.documentElement.classList.toggle("dark",theme==="dark");document.querySelector("#coordinate")!.textContent=`${width}×${height} CSS viewport · ${theme} · DPR 1 · font scaling 100%`;}, {theme,width,height});
  await page.waitForLoadState("networkidle");await f.evaluate(()=>document.fonts.ready);await page.mouse.move(-1,-1);
  async function settled(name:string,fullPage=true) {
    let last=await page.screenshot({fullPage,animations:"disabled"});
    for(let i=0;i<12;i++){await sleep(500);const next=await page.screenshot({fullPage,animations:"disabled"});if(last.equals(next)){await writeFile(join(out,name+".png"),next);return;}last=next;}
    throw new Error("Unsettled capture "+name);
  }
  await f.evaluate(()=>window.scrollTo(0,0));
  const actual=await f.evaluate(()=>({width:innerWidth,height:innerHeight,scrollHeight:document.documentElement.scrollHeight}));
  if(actual.width!==width||actual.height!==height)throw new Error("Wrong frame viewport "+JSON.stringify(actual));
  if(width===390){const tiles=[];const positions=[0,Math.max(0,actual.scrollHeight-height)];for(let i=0;i<positions.length;i++){await f.evaluate((y:number)=>window.scrollTo(0,y),positions[i]);await settled("rest-tile-"+i,false);tiles.push({file:"rest-tile-"+i+".png",y:await f.evaluate(()=>scrollY)});}await writeFile(join(out,"tiles.json"),JSON.stringify({width,height,totalHeight:actual.scrollHeight,tiles},null,2));await f.evaluate(()=>window.scrollTo(0,0));}else await settled("rest",false);
  const geometry=await f.evaluate(()=>Array.from(document.querySelectorAll<HTMLElement>('[data-fixture]')).map(card=>({fixture:card.dataset.fixture,cardWidth:card.querySelector('[data-thread-details-card]')!.getBoundingClientRect().width,lists:Array.from(card.querySelectorAll('ul')).map((el:any)=>({clientWidth:el.clientWidth,scrollWidth:el.scrollWidth})),rows:Array.from(card.querySelectorAll('li')).map((el:any)=>({text:el.textContent,clientWidth:el.clientWidth,scrollWidth:el.scrollWidth,titleWidth:el.querySelector('span.block.truncate')?.getBoundingClientRect().width,rowWidth:el.querySelector('button')?.getBoundingClientRect().width}))})));
  await writeFile(join(out,"geometry.json"),JSON.stringify({viewport:{width,height},theme,browser:await page.context().browser().version(),userAgent:await page.evaluate(()=>navigator.userAgent),geometry},null,2));
  const cdp=await page.context().newCDPSession(page);const frames:any[]=[];let seq=0;
  cdp.on("Page.screencastFrame",async(data:any)=>{const n=seq++;frames.push({file:`frame-${String(n).padStart(5,"0")}.jpg`,timestamp:data.metadata.timestamp});await writeFile(join(out,frames[n].file),Buffer.from(data.data,"base64"));await cdp.send("Page.screencastFrameAck",{sessionId:data.sessionId});});
  await cdp.send("Page.startScreencast",{format:"jpeg",quality:90,maxWidth:width,maxHeight:height,everyNthFrame:1});
  const steps=[{id:"H1-connected-R3",fixture:"active",index:2,text:"H1 · hover R3: connected remote / full environment label"},{id:"H1-unavailable-R4",fixture:"active",index:3,text:"H1 · hover R4: unavailable remote / connection hint"},{id:"H2-connected-D3",fixture:"D3",index:0,text:"H2 · hover D3: connected parent / full current environment label"},{id:"H2-unavailable-D5",fixture:"D5",index:0,text:"H2 · hover D5: unavailable parent / full fallback label"}];
  const timeline:any[]=[];const start=Date.now();
  for(const step of steps){
   await page.mouse.move(-1,-1);await f.locator('[data-slot="tooltip-popup"]').waitFor({state:"hidden"}).catch(()=>{});
   await f.evaluate((text:string)=>{document.querySelector('#step')!.textContent=text;},step.text);
   const target=f.locator(`[data-fixture="${step.fixture}"] li button`).nth(step.index);await target.scrollIntoViewIfNeeded();
   await sleep(500);timeline.push({id:step.id,action:"pointer enters row",seconds:(Date.now()-start)/1000});await target.hover();
   await f.locator('[data-slot="tooltip-popup"]').waitFor({state:"visible"});await settled(step.id,false);
   timeline.push({id:step.id,action:"tooltip visible",seconds:(Date.now()-start)/1000,text:await f.locator('[data-slot="tooltip-popup"]').innerText()});await sleep(1200);
   await page.mouse.move(-1,-1);await f.locator('[data-slot="tooltip-popup"]').waitFor({state:"hidden"});timeline.push({id:step.id,action:"pointer leaves; tooltip dismissed",seconds:(Date.now()-start)/1000});await sleep(500);
  }
  await cdp.send("Page.stopScreencast");await sleep(300);await cdp.detach();
  await writeFile(join(out,"frames.json"),JSON.stringify(frames,null,2));await writeFile(join(out,"timeline.json"),JSON.stringify(timeline,null,2));
 }}}}}]}};
});
'''
(root/'ThreadRelationshipsEvidence.browser.test.tsx').write_text(harness)
(root/'evidence.config.ts').write_text(config)
for path in ['/home/user/wt/pr-33181','/home/user/wt/pr-33181-before']:
 p=Path(path);(p/'apps/web/src/components/chat/ThreadRelationshipsEvidence.browser.test.tsx').write_text(harness);(p/'apps/web/evidence.config.ts').write_text(config)
