#!/usr/bin/env python3
"""Timestamped CLI evidence. All subprocess homes and outputs stay under ROOT.
No source worktree is changed. Helpers are sliced verbatim, then origins remapped.
"""
import argparse, concurrent.futures, datetime, difflib, errno, fcntl, hashlib, json, os, pathlib, pty, re, select, shlex, signal, socket, struct, subprocess, termios, threading, time, traceback
from fixture_server import Fixture, artifacts
from normalize_evidence import normalize
ROOT=pathlib.Path('/tmp/lead-32913-r1/evidence-capture-3')
REPO='/home/user/t3code'
BASE='bcee0f5d2872ba193c66ed9ba979bbe424f89ff9';HEAD='965b08b3060575186415df240c898a50c8736c5d'
NODE=subprocess.check_output(['node','-p','process.execPath'],text=True).strip()
PWSH='/tmp/lead-32913-r1/evidence-capture/powershell-7.4.6/pwsh'
ENV_LINE='Ubuntu 24.04.4 LTS Linux x86_64; kernel 6.8.0-117-generic; dash 0.5.12-6ubuntu5 or bash 5.2.21 --posix; curl 8.5.0; GNU wget 1.21.4; BusyBox 1.36.1; Node v26.12.1; PowerShell 7.4.6 Core on Linux (helpers only)'
SOURCES={side:{name:subprocess.check_output(['git','-C',REPO,'show',sha+':scripts/'+name],text=True) for name in ['install.sh','install.ps1','npm-launcher/t3.mjs']} for side,sha in [('before',BASE),('after',HEAD)]}
ART=artifacts(NODE)
LOCK=threading.Lock()

def utc():return datetime.datetime.now(datetime.timezone.utc).isoformat(timespec='milliseconds')
def stamp():return datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%dT%H%M%S.%fZ')
def write(path,data):
    path.parent.mkdir(parents=True,exist_ok=True);path.write_text(data);return path

def transport_path(run,kind):
    folder=run/'path';folder.mkdir()
    for name in ['cat','rm','grep','sed','head','cut','uname','tar','gzip','sha256sum','shasum','wc','tr','awk','sleep','mktemp','mkdir','mv','ln','readlink','dirname','pwd','bash','sh','env']:
        cmd=shutil_which(name)
        if cmd:(folder/name).symlink_to(cmd)
    (folder/'node').symlink_to(NODE)
    if kind=='busybox':
        wrapper='#!/usr/bin/python3\nimport os,time,json,sys\nf=open(os.environ["CAPTURE_TRANSPORT"],"a");f.write(json.dumps({"t":time.monotonic(),"utc":time.time(),"pid":os.getpid(),"event":"exec busybox wget","argv":sys.argv[1:]})+"\\n");f.close()\nos.execv("/usr/bin/busybox",["wget"]+sys.argv[1:])\n'
        file=write(folder/'wget',wrapper);file.chmod(0o755)
    else:
        command='curl' if kind.startswith('curl') else 'wget'
        real='/usr/bin/'+command
        if kind.startswith('curl-'):real=str(ROOT/kind/'bin/curl')
        wrapper='#!/usr/bin/python3\nimport os,time,json\nf=open(os.environ["CAPTURE_TRANSPORT"],"a")\nf.write(json.dumps({"t":time.monotonic(),"utc":time.time(),"pid":os.getpid(),"event":"exec '+command+'","argv":__import__("sys").argv[1:]})+"\\n");f.close()\nos.execv('+repr(real)+',['+repr(real)+']+__import__("sys").argv[1:])\n'
        file=write(folder/command,wrapper);file.chmod(0o755)
    return str(folder)
def shutil_which(name):
    import shutil
    return shutil.which(name)

FETCH_TRACE='''import fs from 'node:fs';
const emit=e=>fs.appendFileSync(process.env.CAPTURE_TRANSPORT,JSON.stringify({utc:Date.now()/1000,t:Number(process.hrtime.bigint())/1e9,pid:process.pid,...e})+'\\n');
const original=globalThis.fetch;
globalThis.fetch=async (...args)=>{emit({event:'fetch_start',url:String(args[0])});try{const r=await original(...args);emit({event:'fetch_response',status:r.status});if(r.body){const cancel=r.body.cancel.bind(r.body);r.body.cancel=async (...a)=>{emit({event:'body_cancel',status:r.status});return cancel(...a);};}return r;}catch(e){emit({event:'fetch_rejected',message:e.message});throw e;}};
'''
IPC_PARENT='''import {fork} from 'node:child_process';
const child=fork(process.argv[2],['service-fixture'],{stdio:['ignore','inherit','inherit','ipc']});
child.on('message',m=>console.log('SYNTHETIC_PARENT_RECEIVED '+JSON.stringify(m)));
child.send({fixture:'hello'});child.on('exit',(code,signal)=>process.exit(code??1));
'''

def ps_program(source,case,origin):
    # Retain exact prologue, terminal dispatch, Draw-Download, and Fetch bodies.
    end=source.index('\nif ($interactive) {\n  # Block')
    prefix=source[:end]
    prefix=re.sub(r'https://(?:api\.)?github\.com',origin,prefix)
    if case.get('ascii'):
        prefix='$captureWriter=[IO.StreamWriter]::new([Console]::OpenStandardError(),[Text.Encoding]::ASCII)\n$captureWriter.AutoFlush=$true\n[Console]::SetError($captureWriter)\n'+prefix
    mechanism=case.get('mech','W')
    if case.get('discovery'):
        # Exact channel and page-loop caller from each revision; no fake cmdlets.
        a=source.index('$channel = if ($env:T3CODE_CHANNEL)');b=source.index('\nif ($version -match',a)
        caller=re.sub(r'https://(?:api\.)?github\.com',origin,source[a:b])
        return prefix+'\n'+caller+'\nWrite-Output "RESOLVED_VERSION=$version"\n'
    if case.get('checksum_caller') or case.get('validation_caller'):
        a=source.index('    try {\n      Fetch "$baseUrl/v$version/SHA256SUMS"')
        b=source.index('    Fetch "$baseUrl/v$version/$archive"',a)
        caller=source[a:b]
        setup='\n$version="1.2.3"; $arch="x64"; $staging=$env:CAPTURE_STAGING; $archive="t3-1.2.3-win32-x64.zip"\nNew-Item -ItemType Directory -Force -Path $staging | Out-Null\n'
        if case.get('validation_caller'):
            b=source.index('    Step "Extracting T3 Code..."',a)
            caller=source[a:b]
        return prefix+setup+caller+'\nWrite-Output "CAPTURE_CHECKSUM_CALLER_SUCCESS"\n'
    common='''
[Console]::Error.WriteLine("CAPTURE_DISPATCH terminal=$terminal interactive=$interactive mechanism=MECH encoding=$([Console]::Error.Encoding.WebName)")
try {
'''.replace('MECH',mechanism)
    if mechanism=='R':
        expr='Invoke-RestMethod -Uri $env:CAPTURE_URL -Headers @{Accept="application/json"}'
        if 'function Invoke-Retrying' in source:expr='Invoke-Retrying { '+expr+' }'
        action='$result = '+expr+'\n$result | ConvertTo-Json -Depth 6\n'
    else:
        action='Fetch $env:CAPTURE_URL $env:CAPTURE_DEST'+(' -progress' if case.get('progress') or mechanism=='H' else '')+'\n'
        action+='Write-Output "DEST_LENGTH=$((Get-Item $env:CAPTURE_DEST).Length)"\nWrite-Output "DEST_SHA256=$((Get-FileHash $env:CAPTURE_DEST -Algorithm SHA256).Hash)"\n'
    return prefix+common+action+'''Write-Output "CAPTURE_SUCCESS"
} catch {
  [Console]::Error.WriteLine("EXCEPTION_TYPE=$($_.Exception.GetType().FullName)")
  [Console]::Error.WriteLine("ORIGINAL_STATUS=$([int]$_.Exception.Response.StatusCode)")
  [Console]::Error.WriteLine("STATUS_VALUE=$($_.Exception.Response.StatusCode.value__)")
  [Console]::Error.WriteLine("EXCEPTION=$($_.Exception.Message)")
  throw
} finally { [Console]::Error.WriteLine("CAPTURE_CALLER_FINALLY") }
'''

def sh_helper(source,case):
    start=source.index('\nbackoff()') if '\nbackoff()' in source else source.index('\nfetch()')
    end=source.index('\ncase "$(uname -s)"',start)
    prefix='set -eu\ninteractive='+('true' if case.get('pty') else 'false')+'\naccent= reset= muted= download_pid=\n'
    functions=source[start:end]
    operation='download' if case.get('path')=='D' else 'fetch'
    # Isolate destination failure; retain exact helper code, do not replace curl.
    return prefix+functions+'\n'+operation+' "$CAPTURE_URL" "$CAPTURE_DEST"\n'


def run_one(case,side,folder,fixture):
    run=folder/side;run.mkdir();(run/'home').mkdir();(run/'tmp').mkdir();(run/'bin').mkdir()
    start=time.monotonic();events=[]; out=[];eventlock=threading.RLock()
    tf=open(run/'transcript.txt','w')
    def emit(kind,data):
        with eventlock:
            ev={'utc':utc(),'t':round(time.monotonic()-start,6),'kind':kind,'data':data};events.append(ev)
            tf.write(f"{ev['utc']} +{ev['t']:.6f} {kind} {json.dumps(data,ensure_ascii=False)}\n");tf.flush()
    fixture.reset(case,emit)
    sha=BASE if side=='before' else HEAD
    env={'HOME':str(run/'home'),'T3CODE_HOME':str(run/'home/t3'),'T3CODE_INSTALL_BIN_DIR':str(run/'bin'),'TMPDIR':str(run/'tmp'),'TMP':str(run/'tmp'),'TEMP':str(run/'tmp'),'TERM':'xterm-256color' if case.get('pty') else 'dumb','LANG':'C.UTF-8','LC_ALL':'C.UTF-8','NO_COLOR':'1','CAPTURE_TRANSPORT':str(run/'transport.jsonl'),'T3CODE_VERSION':'1.2.3','T3CODE_RELEASE_BASE_URL':fixture.origin,'PROCESSOR_ARCHITECTURE':'AMD64','DOTNET_CLI_HOME':str(run/'home'),'POWERSHELL_TELEMETRY_OPTOUT':'1'}
    env['PATH']=transport_path(run,case.get('transport','curl'))
    target=case.get('target','sums')
    urlpath='/pingdotgg/t3code/releases/latest' if target=='latest' else '/repos/pingdotgg/t3code/releases?per_page=100&page=1' if target.startswith('api') else '/v1.2.3/SHA256SUMS' if target=='sums' else '/v1.2.3/t3-1.2.3-linux-x64.tar.gz'
    env['CAPTURE_STAGING']=str(run/'helper-staging')
    env['CAPTURE_URL']=fixture.origin+urlpath;env['CAPTURE_DEST']=str(run/('nonexistent/destination' if case.get('write_error') else 'downloaded'))
    if case.get('write_directory'):
        destination=run/'destination-directory';destination.mkdir();env['CAPTURE_DEST']=str(destination)
    surface=case['surface'];source=SOURCES[side]['install.sh' if surface=='S' else 'install.ps1' if surface=='P' else 'npm-launcher/t3.mjs']
    original_hash=hashlib.sha256(source.encode()).hexdigest()
    revision_source=run/('install.sh' if surface=='S' else 'install.ps1' if surface=='P' else 'package/bin/t3.mjs')
    program=source;transforms=[]
    if surface in ('S','P') and case.get('discovery'):
        env['T3CODE_VERSION']='';env['T3CODE_CHANNEL']=case.get('channel','stable')
    if surface=='S':
        shell=['/bin/dash'] if case.get('shell','dash')=='dash' else ['/bin/bash','--posix']
        if case.get('helper'):
            program=sh_helper(source,case);transforms.append('verbatim helper slice; standalone destination-error caller')
        if case.get('discovery'):
            program=re.sub(r'https://(?:api\.)?github\.com',fixture.origin,program);transforms.append('only discovery GitHub origins remapped to local HTTP')
        write(revision_source,program)
        cmd=shell+(['-s'] if case.get('pty') else [str(revision_source)])
    elif surface=='P':
        program=ps_program(source,case,fixture.origin)
        observer=('Set-PSDebug -Trace 1\n' if case.get('ps_trace') else '')+'& $env:CAPTURE_SCRIPT\n'
        if case.get('ps_trace'):transforms.append('Set-PSDebug -Trace 1 observes execution of exact helper source, including disposal and request commands')
        transforms.append('verbatim prologue/helper and release discovery caller; discovery origins remapped; appended resolved-version output' if case.get('discovery') else 'verbatim prologue and helper slice; real-HTTP synthetic caller; discovery origins only remapped')
        if case.get('ascii'):transforms.append('ASCII Console.Error writer to exercise exact glyph-based dispatch rejection')
        write(revision_source,program)
        env['CAPTURE_SCRIPT']=str(revision_source)
        observer_file=write(run/'observe.ps1',observer)
        cmd=[PWSH,'-NoLogo','-NoProfile','-File',str(observer_file)]
    else:
        write(revision_source,program);write(run/'package/package.json',json.dumps({'version':'1.2.3','type':'module'}))
        trace=write(run/'fetch-trace.mjs',FETCH_TRACE)
        cmd=[NODE,'--import',str(trace),str(revision_source),case.get('arg','--version')]
        if case.get('ipc'):
            write(run/'ipc-parent.mjs',IPC_PARENT)
            env['NODE_OPTIONS']='--import='+str(trace)
            cmd=[NODE,str(run/'ipc-parent.mjs'),str(revision_source)]
        transforms.append('launcher bytes unchanged; fetch observer logs invocation/response/cancel and forwards real fetch')
    if case.get('cached'):
        version='1.2.4-'+case['channel']+'.20261110.1' if case.get('channel') in ('nightly','preview') else '1.2.3'
        t=run/'home/t3/runtime/versions'/version;t.mkdir(parents=True)
        write(t/'.install-complete',version+'\n');exe=write(t/'t3',ART['exe'].decode());exe.chmod(0o755)
    closed=None
    if case.get('refused'):
        closed=socket.socket();closed.bind(('127.0.0.1',0));port=closed.getsockname()[1]
        # Bound but non-listening socket reserves a reliably refused port throughout run.
        if surface=='S' and case.get('path')=='D':fixture.refused_location='http://127.0.0.1:'+str(port)+'/refused-archive'
        else:
            env['T3CODE_RELEASE_BASE_URL']='http://127.0.0.1:'+str(port);env['CAPTURE_URL']=env['T3CODE_RELEASE_BASE_URL']+urlpath
    emit('MANIFEST',{'id':case['id'],'case':case['name'],'side':side,'sha':sha,'environment':ENV_LINE,'selected':{k:case.get(k) for k in ['surface','shell','transport','path','mech','pty']},'selected_transport_version':subprocess.check_output([str(ROOT/case['transport']/'bin/curl'),'--version'],text=True).splitlines()[0] if case.get('transport','').startswith('curl-') else case.get('transport','curl 8.5.0'),'command':shlex.join(cmd),'env':env,'original_source_sha256':original_hash,'executed_source_sha256':hashlib.sha256(program.encode()).hexdigest(),'transforms':transforms,'steps':'Start fixture; run command; deliver terminal Ctrl-C only when specified precondition is observed; capture exit, requests, install state, tracked PIDs.'})
    timeout=case.get('timeout',22);sig_sent=False;first_target=None;pid=None;master=None;proc=None;status=None;timedout=False
    try:
        if case.get('pty'):
            pid,master=pty.fork()
            if pid==0:
                os.chdir(run)
                if surface=='S':
                    readfd,writefd=os.pipe();os.write(writefd,program.encode());os.close(writefd);os.dup2(readfd,0);os.close(readfd)
                os.execve(cmd[0],cmd,env)
            fcntl.ioctl(master,termios.TIOCSWINSZ,struct.pack('HHHH',30,120,0,0));fd=master
        else:
            proc=subprocess.Popen(cmd,cwd=run,env=env,stdin=subprocess.DEVNULL,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,start_new_session=True);pid=proc.pid;fd=proc.stdout.fileno()
        emit('SPAWN',{'pid':pid,'pty':bool(master is not None),'stdin':'script piped on stdin; stderr is controlling PTY' if surface=='S' and master is not None else 'PTY' if master is not None else 'noninteractive'})
        os.set_blocking(fd,False)
        done=False;ended=None
        while not done:
            ready,_,_=select.select([fd],[],[],0.05)
            if ready:
                try:chunk=os.read(fd,65536)
                except OSError as e:
                    if e.errno==errno.EIO:chunk=b''
                    else:raise
                if chunk:
                    text=chunk.decode(errors='replace');out.append(text);emit('OUTPUT',text)
                    if master is not None and b'\x1b[6n' in chunk:
                        replies=chunk.count(b'\x1b[6n');os.write(master,b'\x1b[1;1R'*replies);emit('TERMINAL_REPLY',{'query':'DSR cursor position','reply':'row1 column1','count':replies})
            elapsed=time.monotonic()-start
            with fixture.lock:
                targets=[r for r in fixture.requests if r['endpoint']==case.get('target','sums')]
                targetcount=len(targets)
            if targetcount and first_target is None:first_target=time.monotonic()
            if case.get('interrupt') and not sig_sent and master is not None:
                condition=(targetcount>=2 and any(e['kind']=='SERVER' and e['data'].get('event')=='body_chunk' and e['data'].get('endpoint')==case.get('target','sums') and e['data'].get('offset',0)>0 for e in events) if case['interrupt']=='active' else targetcount>=2 and first_target is not None and time.monotonic()-first_target>=1.35)
                if condition:
                    emit('ACTION',{'step':'write terminal Ctrl-C byte','precondition':case['interrupt'],'requests_observed':targetcount});os.write(master,b'\x03');sig_sent=True
            if elapsed>timeout:
                emit('TIMEOUT',{'seconds':timeout,'action':'SIGTERM to spawned process group','pid':pid});os.killpg(pid,signal.SIGTERM);timedout=True
                try:
                    if master is not None:_,status=os.waitpid(pid,0)
                    else:status=proc.wait(timeout=3)
                except subprocess.TimeoutExpired:os.killpg(pid,signal.SIGKILL);status=proc.wait()
                done=True
            elif master is not None:
                result,stat=os.waitpid(pid,os.WNOHANG)
                if result:status=stat;done=True
            elif proc.poll() is not None:status=proc.returncode;done=True
        # Drain buffered terminal output after process exit.
        for _ in range(20):
            try:chunk=os.read(fd,65536)
            except (OSError,BlockingIOError):break
            if not chunk:break
            text=chunk.decode(errors='replace');out.append(text);emit('OUTPUT',text)
        exitcode=os.waitstatus_to_exitcode(status) if master is not None else status
        if exitcode<0:exitcode=128-exitcode
        elapsed=time.monotonic()-start
        with fixture.settled:fixture.settled.wait_for(lambda:fixture.active==0,timeout=1.5)
        emit('SERVER_STATE_BEFORE_DRIVER_CLEANUP',{'active_handlers':fixture.active})
        fixture.settle()
        # Let server report peer disconnect; no evidence assertions depend on a sleep.
        with fixture.lock:reqs=list(fixture.requests)
        transports=[]
        if (run/'transport.jsonl').exists():
            for line in (run/'transport.jsonl').read_text().splitlines():
                try:
                    event=json.loads(line);transports.append(event);emit('TRANSPORT_TRACE',event)
                except ValueError:emit('TRACE_PARSE_ERROR',line)
        pids=sorted({e['pid'] for e in transports if e.get('event','').startswith('exec ')})
        remaining=[]
        for p in pids:
            try:
                os.kill(p,0);state=pathlib.Path('/proc')/str(p)/'status'
                remaining.append({'pid':p,'status':state.read_text().splitlines()[2] if state.exists() else 'exists'})
            except ProcessLookupError:pass
        state=[]
        for p in sorted((run/'home').rglob('*')):
            if p.is_file() or p.is_symlink():state.append({'path':str(p.relative_to(run)), 'bytes':p.stat().st_size,'symlink':os.readlink(p) if p.is_symlink() else None})
        marker=list((run/'home').rglob('.install-complete'))
        state_summary={'marker':bool(marker),'files':state,'helper_outputs':[{'path':str(p.relative_to(run)),'bytes':p.stat().st_size} for p in run.glob('helper-staging/*') if p.is_file()]+([{'path':'downloaded','bytes':(run/'downloaded').stat().st_size}] if (run/'downloaded').is_file() else []),'staging':[str(p.relative_to(run)) for p in (run/'home').rglob('*') if '.staging-' in p.name], 'sidecars':[str(p.relative_to(run)) for p in run.rglob('*') if p.suffix in ('.headers','.errors','.status')],'tracked_downloader_pids':pids,'remaining_tracked_downloaders':remaining}
        verify=None
        if surface=='S' and (run/'bin/t3').exists():
            v=subprocess.run([str(run/'bin/t3'),'--version'],env=env,capture_output=True,text=True);verify={'exit':v.returncode,'stdout':v.stdout,'stderr':v.stderr}
        emit('RESULT',{'exit_code':exitcode,'elapsed_seconds':round(elapsed,6),'requests':len(reqs),'interrupt_sent':sig_sent,'timeout':timedout,'state':state_summary,'symlink_executable_check':verify})
        result={'id':case['id'],'case':case,'side':side,'sha':sha,'exit':exitcode,'elapsed':elapsed,'requests':reqs,'events':events,'state':state_summary,'output':''.join(out),'timeout':timedout,'interrupt_sent':sig_sent,'transports':transports,'path':str(run),'verify':verify}
        write(run/'result.json',json.dumps(result,indent=2));write(run/'output.txt',''.join(out))
        return result
    except Exception as e:
        emit('DRIVER_ERROR',traceback.format_exc())
        if pid:
            try:os.killpg(pid,signal.SIGKILL)
            except ProcessLookupError:pass
            if proc:proc.wait()
            elif master is not None:
                try:os.waitpid(pid,0)
                except ChildProcessError:pass
        raise
    finally:
        if master is not None:os.close(master)
        if proc and proc.stdout:proc.stdout.close()
        if closed:closed.close()
        fixture.settle();tf.close()

def run_pair(case,session):
    folder=session/(case['id']+'-'+case['name']);folder.mkdir()
    fixture=Fixture(ART)
    try:
        before=run_one(case,'before',folder,fixture)
        # Separate handlers finish before swapping fixture state to the next revision.
        fixture.settle()
        after=run_one(case,'after',folder,fixture)
        a=(folder/'before/transcript.txt').read_text();b=(folder/'after/transcript.txt').read_text()
        write(folder/'Diff0.diff',''.join(difflib.unified_diff(a.splitlines(True),b.splitlines(True),fromfile='before '+BASE,tofile='after '+HEAD)))
        write(folder/'DiffT.diff',''.join(difflib.unified_diff(normalize(folder/'before/transcript.txt').splitlines(True),normalize(folder/'after/transcript.txt').splitlines(True),fromfile='before normalized',tofile='after normalized')))
        with LOCK:print(case['id'],case['name'],'before',before['exit'],'after',after['exit'],'requests',len(before['requests']),len(after['requests']),flush=True)
        return {'case':case,'before':before,'after':after,'folder':str(folder)}
    finally:fixture.close()

# Case factory: each expansion is separately captured on both revisions.
def cases():
    result=[]
    def add(id,name,surface='S',**kw):result.append(dict(id=id,name=name,surface=surface,**kw))
    def shell(id,name,paths=('F',),**kw):
        for sh in ('dash','bash'):
            for path in paths:add(id,name+'-'+sh+'-'+path,shell=sh,path=path,pty=path=='D',target='archive' if path=='D' else 'sums',**kw)
    # Discovery and caller boundaries.
    shell('S01','latest-504',discovery=True,cached=True,seq=[504,200],**{})
    result[-2]['target']=result[-1]['target']='latest'
    for channel in ('nightly','preview'):
        shell('S02',channel+'-page2',discovery=True,cached=True,channel=channel,seq=[504,200])
        result[-2]['target']=result[-1]['target']='api2'
    shell('S03','latest-missing-tag',discovery=True,seq=[504,200],latest={})
    result[-2]['target']=result[-1]['target']='latest'
    for end in ('empty','cap'):
        shell('S04','train-'+end,discovery=True,channel='nightly',seq=[504,200],**{end:True})
        result[-2]['target']=result[-1]['target']='api2'
    shell('S05','checksum-504',seq=[504,200])
    shell('S06','archive-nontty-504',seq=[504,200]);result[-2]['target']=result[-1]['target']='archive'
    shell('S07','archive-pty-504-slow',('D',),seq=[504,'slow'])
    shell('S08','archive-chunked',('D',),seq=[504,'chunked'])
    shell('S08','archive-redirect-chunked',('D',),seq=[504,'redirect'],redirect_chunked=True)
    for id,status in [('S09',408),('S10',429),('S11',507)]:shell(id,'status-'+str(status),('F','D'),seq=[status,200])
    shell('S11','status-503',('F','D'),seq=[503,200])
    shell('S12','permanent-403',('F','D'),seq=[403,200])
    shell('S13','checksum-404',seq=[404,200])
    for endpoint in ('latest','api1'):
        shell('S14',endpoint+'-404',discovery=True,channel='nightly' if endpoint=='api1' else 'stable',seq=[404,200])
        result[-2]['target']=result[-1]['target']=endpoint
    shell('S14','archive-404',('F','D'),seq=[404,200])
    # F archive in this row, rather than checksum.
    for c in result:
        if c['id']=='S14' and c['name'].startswith('archive'):c['target']='archive'
    shell('S15','four-504',('F','D'),seq=[504,504,504,504,200])
    shell('S16','fourth-success',('F','D'),seq=[504,504,504,200])
    shell('S17','preheader-drop',('F','D'),seq=['drop',200])
    shell('S18','refused',('F','D'),refused=True)
    shell('S19','truncated-checksum',seq=['truncate',200])
    shell('S19','truncated-archive',('F','D'),seq=['truncate',200])
    for c in result:
        if c['id']=='S19' and c['name'].startswith('truncated-archive'):c['target']='archive'
    for status,ra in [(429,'120'),(503,'120'),(503,'Tue, 10 Nov 2026 23:59:59 GMT')]:shell('S20','retry-after-'+str(status)+('-date' if ra!='120' else '-120'),('F','D'),seq=[status,200],retry_after=ra)
    for name,seq in [('504-403',[504,403,200]),('504-404',[504,404,200]),('drop-504-200',['drop',504,200])]:shell('S21',name,('F','D'),seq=seq)
    shell('S22','unresolved-302',('F','D'),seq=[302,302,302,302,200])
    shell('S23','write-error',('F','D'),helper=True,write_error=True,seq=[200])
    shell('S23','write-directory',('F','D'),helper=True,write_directory=True,seq=[200])
    shell('S24','ctrlc-active',('D',),seq=[504,'hold'],interrupt='active')
    shell('S25','ctrlc-backoff',('D',),seq=[504,504,504,504,200],interrupt='backoff')
    for transport in ('wget','busybox'):
        add('S26' if transport=='wget' else 'S30',transport+'-foreground-504',transport=transport,seq=[504,200])
        add('S26' if transport=='wget' else 'S30',transport+'-checksum-404',transport=transport,seq=[404,200])
        for sh in ('dash','bash'):
            for kind,seq in [('success',[200]),('retry',[504,200]),('403',[403,200])]:add('S27' if transport=='wget' else 'S30',transport+'-'+sh+'-pty-'+kind,shell=sh,transport=transport,pty=True,path='D',target='archive',seq=seq)
    add('S28','complete-cache',cached=True,seq=[403])
    for old in ('7.68','7.74'):
        for status in (429,503):
            for path in ('F','D'):add('S29','curl-'+old+'-'+str(status)+'-'+path,transport='curl-'+old,shell='dash',path=path,pty=path=='D',target='archive' if path=='D' else 'sums',seq=[status,200],retry_after='120')
    # PS7 real HTTP helper captures. Linux execution is explicitly not Windows install proof.
    def ps(id,name,mechs=('R','W','H'),**kw):
        for m in mechs:add(id,name+'-'+m,'P',mech=m,pty=m=='H',progress=m=='H',target='archive' if m=='H' else 'sums',**kw)
    add('P01','latest-504','P',mech='R',discovery=True,target='latest',seq=[504,200])
    for channel in ('nightly','preview'):add('P02',channel+'-page2','P',mech='R',discovery=True,channel=channel,target='api2',seq=[504,200],draft_first=True)
    ps('P03','checksums-504',('W',),seq=[504,200])
    add('P03','checksums-terminal','P',mech='W',pty=True,target='sums',seq=[504,200])
    add('P04','archive-redirected','P',mech='W',progress=True,target='archive',seq=[504,200])
    add('P05','ascii-terminal-fallback','P',mech='W',pty=True,ascii=True,progress=True,target='archive',seq=[504,200])
    ps('P06','httpclient-slow',('H',),seq=[504,'slow'])
    ps('P07','httpclient-chunked',('H',),seq=[503,'chunked'])
    for id,status in [('P08',408),('P09',429),('P10',507)]:ps(id,'status-'+str(status),seq=[status,200])
    for status in (403,404):ps('P11','status-'+str(status),seq=[status,200])
    add('P12','checksum-404-caller','P',mech='W',checksum_caller=True,target='sums',seq=[404,200])
    add('P19','checksum-504-404-caller','P',mech='W',checksum_caller=True,target='sums',seq=[504,404,200])
    for invalid in ('missing','digest'):add('P20','checksum-invalid-'+invalid,'P',mech='W',validation_caller=True,target='sums',invalid=invalid,seq=[200])
    for id,name,seq in [('P13','four-504',[504,504,504,504,200]),('P14','fourth-success',[504,504,504,200]),('P14','drop-504-200',['drop',504,200]),('P15','preheader-drop',['drop',200])]:ps(id,name,seq=seq)
    ps('P15','refused',refused=True)
    ps('P15','four-preheader-drops',seq=['drop','drop','drop','drop',200])
    ps('P16','truncated-body',('R','W'),seq=['truncate',200])
    add('P16','truncated-archive-W','P',mech='W',progress=True,target='archive',seq=['truncate',200])
    ps('P17','httpclient-truncated',('H',),seq=['truncate',200])
    for status,ra in [(429,'120'),(503,'120'),(503,'Tue, 10 Nov 2026 23:59:59 GMT')]:ps('P18','retry-after-'+str(status)+('-date' if ra!='120' else '-120'),seq=[status,200],retry_after=ra)
    for status in (403,404):ps('P19','504-'+str(status),seq=[504,status,200])
    add('P20','latest-missing','P',mech='R',discovery=True,target='latest',latest={},seq=[504,200])
    for end in ('empty','cap'):add('P20','train-'+end,'P',mech='R',discovery=True,channel='nightly',target='api2',seq=[504,200],**{end:True})
    ps('P21','write-error',('W','H'),write_error=True,seq=[200])
    for m in ('R','W','H'):add('P22','ctrlc-backoff-'+m,'P',mech=m,pty=True,progress=m=='H',target='archive' if m=='H' else 'sums',seq=[504,504,504,504,200],interrupt='backoff')
    ps('P23','ctrlc-active',('H',),seq=[504,'hold'],interrupt='active')
    # Launcher, both real endpoint callers and unchanged validation boundaries.
    def launcher(id,name,**kw):add(id,name,'L',**kw)
    launcher('L01','checksum-504',seq=[504,200])
    launcher('L02','archive-nontty-504',target='archive',seq=[504,200])
    launcher('L02','archive-pty-504',pty=True,target='archive',seq=[504,'slow'])
    for status in (408,429,500,502,503):launcher('L03','status-'+str(status),seq=[status,200])
    for status in (501,505,507,524,599):launcher('L04','status-'+str(status),seq=[status,200])
    for endpoint in ('sums','archive'):
        for status in (403,404):launcher('L05',endpoint+'-'+str(status),target=endpoint,seq=[status,200])
    launcher('L06','four-504',seq=[504,504,504,504,200])
    launcher('L07','fourth-success',seq=[504,504,504,200])
    for endpoint in ('sums','archive'):launcher('L08','preheader-drop-'+endpoint,target=endpoint,seq=['drop',200])
    launcher('L09','network-drops',seq=['drop','drop','drop','drop',200])
    for name,seq in [('mixed',[504,'drop',200]),('504-403',[504,403,200]),('504-404',[504,404,200])]:launcher('L10',name,seq=seq)
    for status,ra in [(429,'120'),(503,'120'),(503,'Tue, 10 Nov 2026 23:59:59 GMT')]:launcher('L11','retry-after-'+str(status)+('-date' if ra!='120' else '-120'),seq=[status,200],retry_after=ra)
    launcher('L12','truncated-checksum',seq=['truncate',200])
    launcher('L13','truncated-archive',target='archive',seq=['truncate',200])
    for invalid in ('missing','digest'):launcher('L15','invalid-'+invalid,invalid=invalid,seq=[200])
    launcher('L16','cached',cached=True,seq=[403],arg='ordinary-fixture')
    launcher('L16','fresh-up',seq=[504,200],arg='up')
    launcher('L16','service-ipc',seq=[504,200],ipc=True)
    launcher('L17','ctrlc-backoff',pty=True,seq=[504,504,504,504,200],interrupt='backoff')
    launcher('L17','ctrlc-active',pty=True,target='archive',seq=[504,'hold'],interrupt='active')
    return result

if __name__=='__main__':
    parser=argparse.ArgumentParser();parser.add_argument('--ids',default='');parser.add_argument('--name',default='');parser.add_argument('--workers',type=int,default=4);parser.add_argument('--ps-trace',action='store_true');args=parser.parse_args()
    selected=[c for c in cases() if (not args.ids or c['id'] in args.ids.split(',')) and (not args.name or args.name in c['name'])]
    if args.ps_trace:
        for c in selected:c['ps_trace']=True
    session=ROOT/('runs-'+stamp());session.mkdir();write(session/'cases.json',json.dumps(selected,indent=2));write(session/'environment.txt',ENV_LINE+'\n')
    print('SESSION',session,'CASES',len(selected),flush=True)
    results=[];errors=[]
    with concurrent.futures.ThreadPoolExecutor(max_workers=args.workers) as pool:
        futures={pool.submit(run_pair,c,session):c for c in selected}
        for future in concurrent.futures.as_completed(futures):
            try:results.append(future.result())
            except Exception as e:
                errors.append({'case':futures[future],'error':traceback.format_exc()});print('ERROR',futures[future],repr(e),flush=True)
            write(session/'summary.json',json.dumps({'environment':ENV_LINE,'results':results,'errors':errors},indent=2))
    print('DONE',session,'PAIRS',len(results),'ERRORS',len(errors),flush=True)
