55 lines
5.1 KiB
Python
55 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Assemble complete whole-gate evidence from retained logs only."""
|
|
import hashlib,json,re
|
|
from pathlib import Path
|
|
HERE=Path(__file__).resolve().parent
|
|
RUN=HERE/'run3-gate'
|
|
def main():
|
|
sections={n:json.loads((RUN/n/'results.json').read_text()) for n in ['focused','changes','whole']}
|
|
header=json.loads((RUN/'HEADER.json').read_text());lists=json.loads((RUN/'FILE-LISTS.json').read_text())
|
|
whole=sections['whole']['steps'];expected=sum(map(len,lists.values()))+10
|
|
assert len(whole)==expected
|
|
assert all(s['code']==0 and not s['timeout'] for s in whole)
|
|
focused=sections['focused']['steps']
|
|
assert len(focused)==4 and all(not s['timeout'] and (s['code']!=0 if s['expected_red'] else s['code']==0) for s in focused)
|
|
changes=sections['changes']['changes'];assert len(changes)==40 and all(s['outcome']=='killed' and not s['timeout'] for s in changes)
|
|
limits=json.loads((HERE/'WHOLE-GATE-LIMITS.json').read_text())['files'];shell_limits=json.loads((HERE/'SHELL-LIMITS.json').read_text())['scripts']
|
|
counts={};skips=[];rows=[];shells=[];n9=[]
|
|
for package,files in lists.items():
|
|
steps=[s for s in whole if s['name'].startswith(package+'-')]
|
|
commands=[json.loads(Path(s['log']).with_suffix('.command.json').read_text()) for s in steps]
|
|
assert [c[-1] for c in commands]==files
|
|
counts[package]={k:sum(s['counts'].get(k,0) for s in steps) for k in ['pass','fail','skipped']}
|
|
for s,c,file in zip(steps,commands,files):
|
|
assert c==['timeout','-k','10',str(limits[file]),'node','--test','--test-reporter=tap',file]
|
|
text=Path(s['log']).read_text(errors='replace')
|
|
skips += [dict(file=file,line=line) for line in text.splitlines() if '# SKIP' in line]
|
|
if file.endswith('/case2-unit.test.mjs'):n9 += [line for line in text.splitlines() if line.startswith('ok ') and "inside a session's sandbox" in line]
|
|
rows.append(dict(file=file,counts=s['counts'],seconds=s['seconds'],limit_seconds=limits[file],log=s['log']))
|
|
for s in whole[-10:]:
|
|
command=json.loads(Path(s['log']).with_suffix('.command.json').read_text());file=command[-1]
|
|
assert command==['timeout','-k','10',str(shell_limits[file]['limit_seconds']),'bash',file]
|
|
text=Path(s['log']).read_text(errors='replace');found=re.findall(r'([^\n]*?: (\d+) passed, (\d+) failed)',text);assert found,file
|
|
line,passed,failed=found[-1];assert int(failed)==0
|
|
skips += [dict(file=file,line=line) for line in text.splitlines() if re.match(r'^\s*skip\b',line,re.I) or '# SKIP' in line]
|
|
shells.append(dict(file=file,pass_count=int(passed),fail_count=int(failed),seconds=s['seconds'],limit_seconds=shell_limits[file]['limit_seconds'],summary_line=line,log=s['log']))
|
|
assert len(n9)==1
|
|
counts['shell_self_assertions']=dict(pass_count=sum(s['pass_count'] for s in shells),fail_count=0)
|
|
result=dict(status='GREEN',header=header,sections=sections,counts=counts,files=rows,shells=shells,named_skips=skips,n9_exact_line=n9[0],killed=40,survived=0,timeouts=0,head_diff_outside_gander=(RUN/'HEAD-DIFF-OUTSIDE-GANDER.txt').read_text().splitlines())
|
|
repo=HERE.parents[3]
|
|
expected_hashes=json.loads((HERE/'CANDIDATE-SHAS.json').read_text())
|
|
assert all(hashlib.sha256((repo/n).read_bytes()).hexdigest()==v for n,v in expected_hashes.items())
|
|
assert all(hashlib.sha256((repo/n).read_bytes()).hexdigest()==v['script_sha256'] for n,v in shell_limits.items())
|
|
(RUN/'SUMMARY.json').write_text(json.dumps(result,indent=2)+'\n')
|
|
lines=['# Row253 whole gate RESULTS','','HEAD '+header['head']+', product '+header['product']+', manifest '+header['manifest']+'.','','0604..344 name-only outside agents/gander/:','','```text',*result['head_diff_outside_gander'],'```','','All listed whole files ran, with no unlisted-file coverage claim. Intended REDs and focused repeats are separate from package totals. Bus coverage is the20-file rebase union, not a bus-whole claim.','','| Whole file | Pass/fail/skip | Wall seconds | Limit seconds |','|---|---:|---:|---:|']
|
|
lines += [f"| {r['file']} | {r['counts']['pass']}/{r['counts']['fail']}/{r['counts']['skipped']} | {r['seconds']} | {r['limit_seconds']} |" for r in rows]
|
|
lines += [f"| {r['file']} | {r['pass_count']}/{r['fail_count']}/0 | {r['seconds']} | {r['limit_seconds']} |" for r in shells]
|
|
lines += ['','N9 verbatim: '+n9[0],'','Every named skip:','']+[f"- {s['file']}: {s['line']}" for s in skips]
|
|
(RUN/'RESULTS.md').write_text('\n'.join(lines)+'\n')
|
|
defs={d['id']:d for d in json.loads((HERE/'changes.json').read_text())}
|
|
table=['# M1-M40 kill table','','Every base passes; each change restored exact bytes and tracked status before the next. No timeout counts as kill.','','| Check | Named killer | Base seconds | Changed seconds | Outcome |','|---|---|---:|---:|---|']
|
|
table += [f"| {s['id']} | {defs[s['id']]['pattern']} | {s['base_seconds']} | {s['seconds']} | {s['outcome']} |" for s in changes]
|
|
(RUN/'KILL-TABLE.md').write_text('\n'.join(table)+'\n')
|
|
print(json.dumps(dict(counts=counts,named_skips=skips,n9=n9,killed=40),indent=2))
|
|
if __name__=='__main__':main()
|