Files
EscapistsReintroduced/docs/evidence/playtest-refresh-2026-10-02-hq-memory-menu-fix/finalize.py
T
jakub 6a667d8deb Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
2026-10-13 22:52:53 +02:00

86 lines
8.5 KiB
Python

from pathlib import Path
import hashlib,json,shutil,subprocess,sys
r=Path('/home/jakub/devel/escapistsrereintroduced');b=Path('/tmp/erri-playtest-menu-fix-1349');p=Path('/tmp/erri-playtest-menu-fix-docs-1349');build=r/'.build/playtest-2026-10-02-hq-memory-menu-fix';e=r/'docs/evidence/playtest-refresh-2026-10-02-hq-memory-menu-fix'
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
read=lambda p:json.loads(p.read_text())
write=lambda p,v:p.write_text(json.dumps(v,indent=2)+'\n')
sys.path.insert(0,str(r/'tools'));from source_manifest import addon_manifest
baseline=read(b/'baseline.json');proposal=read(p/'proposal.json');assert proposal['mode']=='verified-final-proposal'
bindings=read(p/'validation-bindings.json');source=Path(bindings['source_root']);testroot=Path(bindings['suite_root']);live=read(Path(bindings['live_preservation']))
assert addon_manifest(source)==baseline['source']
assert addon_manifest(r)==live['source']
assert all(sha(r/n)==h for n,h in live['working_modified'].items())
assert hashlib.sha256(subprocess.check_output(['git','diff','--cached','--binary'],cwd=r)).hexdigest()==baseline['index_diff_sha256']
original=read(Path('/tmp/erri-heartbeat-20260930-1542-reference.json'))
prior=read(r/'docs/evidence/playtest-refresh-2026-10-02-objective-map/candidate-sha256.json')
assert all(sha(Path('/home/jakub/devel/escapists')/n)==h for n,h in original.items())
assert {str(x.relative_to(r/'.build/playtest-2026-10-02-objective-map')):sha(x) for x in (r/'.build/playtest-2026-10-02-objective-map').rglob('*') if x.is_file()}==prior
failedroot=r/'.build/playtest-2026-10-02-hq-memory'
failedmanifest=read(p/'failed-candidate-sha256.json')
assert len(failedmanifest)==418 and {str(x.relative_to(failedroot)):sha(x) for x in failedroot.rglob('*') if x.is_file()}==failedmanifest
oldbaseline=read(Path('/tmp/erri-playtest-1349/baseline.json'))
fixpaths={'addons/core/Scripts/Game/ERR/00_Core/ERR_TerrainTakeover.c','tests/test_terrain_takeover.py'}
assert {n for n,h in oldbaseline['source'].items() if baseline['source'][n]!=h}=={'addons/core/Scripts/Game/ERR/00_Core/ERR_TerrainTakeover.c'}
assert all(h==baseline['working_modified'][n] for n,h in oldbaseline['working_modified'].items() if n not in fixpaths)
assert len(baseline['working_modified'])==97
h=read(build/'handoff.json');assert h['authored_files']==409 and h['pak_payload_files']==351 and len(h['runtime_files'])==3
assert h['normal_mission_ready'] and h['local_participant_verified'] and h['repository_regression_programs']==285 and not h['release_qualified'] and not h['strict_packed_consumption_verified']
for n,v in proposal['documentation_baselines'].items():assert sha(r/n)==v
assert len(proposal['proposed_destinations'])==5
assert h['packed_script_failures']==0 and h['packed_resource_errors']==17
freshsuite=read(Path(bindings['suite_result']));assert freshsuite['exit']==0 and freshsuite['regression_programs']==285 and freshsuite['inputs_unchanged']
assert all(sha(testroot/n)==v for n,v in read(Path(bindings['suite_inputs'])).items())
assert addon_manifest(testroot)==baseline['source']
route=r/'docs/evidence/native-2026-10-02-hq-memory-menu-fix-normal'
rr=read(route/'report.json');assert rr['assertions_passed']==63 and rr['smoke_completions']==1 and not rr['script_or_runtime_failures'] and len(rr['engine_errors'])==13
assert read(route/'source-sha256.json')==baseline['source']
assert Path('/tmp/erri-playtest-menu-fix-review-1349/review.json').exists(), 'Independent final package review pending'
live_result=read(b/'suite-result.json');assert live_result['exit']==1 and not live_result['inputs_unchanged'] and live_result['regression_programs']==285 and all(row['exit']==0 for row in live_result['programs'])
e.mkdir(exist_ok=False)
concurrent=e/'concurrent-live-suite';concurrent.mkdir()
for name in ['suite-result.json','suite-inputs.json','regressions.log']:
shutil.copyfile(b/name,concurrent/name)
shutil.copyfile(p/'failed-candidate-sha256.json',e/'failed-candidate-sha256.json')
failed=e/'initial-failed-candidate';failed.mkdir()
shutil.copyfile('/tmp/erri-playtest-review-1349/review.json',failed/'independent-review.json')
oldrun=Path('/tmp/erri-packed-chat-20261002-hq-memory-final')
for name in ['packed-startup-report.json','packed-runner.json','packed-input-provenance.json']:
shutil.copyfile(oldrun/name,failed/name)
oldreport=read(oldrun/'packed-startup-report.json');assert len(oldreport['script_or_runtime_failures'])==1 and len(oldreport['engine_errors'])==18
oldlogs=Path(read(oldrun/'packed-runner.json')['session'])
for name in ['console.log','script.log','error.log']:
if (oldlogs/name).exists():shutil.copyfile(oldlogs/name,failed/(name+'.txt'))
fix=e/'menu-guard-fix';fix.mkdir()
for name in ['fix.patch','baseline.json','review.json','red.log','green.log']:
shutil.copyfile(Path('/tmp/erri-takeover-menu-fix-1349')/name,fix/name)
for name in ['takeover-guard-review.json','takeover-red.log','takeover-green.log']:
shutil.copyfile(Path('/tmp/erri-playtest-review-1349')/name,fix/('independent-'+name))
shutil.copyfile(b/'baseline.json',e/'baseline.json')
shutil.copyfile(Path(bindings['suite_result']),e/'suite-result.json')
shutil.copyfile(Path(bindings['suite_inputs']),e/'suite-inputs.json')
shutil.copyfile(Path(bindings['live_preservation']),e/'concurrent-live-preservation.json')
shutil.copyfile(p/'validation-bindings.json',e/'validation-bindings.json')
shutil.copyfile('/tmp/erri-package-20261002-hq-memory.log',e/'initial-package-concurrency-refusal.log.txt')
shutil.copyfile(b/'packed-concurrency-refusal.log',e/'packed-concurrency-refusal.log.txt')
shutil.copyfile('/tmp/erri-playtest-1349/concurrent-work.json',e/'concurrent-work.json')
shutil.copyfile('/tmp/erri-playtest-menu-fix-review-1349/review.json',e/'independent-package-review.json')
shutil.copyfile(p/'prepare.py',e/'prepare-documentation.py');shutil.copyfile(p/'proposal.json',e/'documentation-proposal.json')
for n,v in proposal['documentation_baselines'].items():
shutil.copyfile(r/n,e/(Path(n).name+'.before'))
for n in proposal['proposed_destinations']:
assert n in ['.build/playtest-2026-10-02-hq-memory-menu-fix/README.md',*proposal['documentation_baselines']]
shutil.copyfile(p/'proposed'/n,r/n)
summary={'artifact':str(build.relative_to(r)),'authored_files':409,'pak_payload_files':351,'runtime_files':3,'regression_programs':285,'fresh_suite_and_normal_route_match_packaged_source':True,'source_scope':'Sealed409 snapshot; newer concurrent live terrain-name/presentation work preserved but not packaged','included_changes':['Observer recovery/defeat guidance','Finite supported-launcher resupply','Radio-directed motorized interception from delivered travel history','Concurrent automatic terrain takeover work preserved, with mode-less menu preflight guard'],'native_normal_route':{'assertions':63,'rounds':1,'script_failures':0,'retained_engine_errors':13},'packed_ordinary_startup':{'normal_mission_ready':True,'local_prisoner_verified':True,'script_failures':0,'retained_engine_errors':17,'strict_failure_retained':True},'native_packaging':'Child exit0 and exact authored/payload identity; strict completion/prefix-active failure retained. Unqualified development candidate.','preserved':{'working_modified_paths_before_doc_updates':len(baseline['working_modified']),'captured_concurrent_working_paths':len(live['working_modified']),'original_reference_files':len(original),'previous_candidate_files':len(prior),'retained_failed_diagnostic_candidate_files':len(failedmanifest),'index_unchanged':True},'remaining':'Physical interception/holding/rejoin, physical launcher transfer, human escape, held-map rendering, real multiplayer/JIP/reconnect/twelve players, comparative FPS and clean release.','initial_failed_candidate':{'script_failures':1,'engine_errors':18,'bytes_preserved':True},'committed':False,'published':False,'release_qualified':False}
write(e/'review.json',summary)
write(e/'documentation-after.json',{n:sha(r/n) for n in proposal['proposed_destinations']})
write(e/'candidate-sha256.json',{str(x.relative_to(build)):sha(x) for x in sorted(build.rglob('*')) if x.is_file()})
shutil.copyfile(__file__,e/'finalize.py')
for n,v in live['working_modified'].items():
if n not in proposal['documentation_baselines']:assert sha(r/n)==v,n
assert {str(x.relative_to(failedroot)):sha(x) for x in failedroot.rglob('*') if x.is_file()}==failedmanifest
assert addon_manifest(source)==baseline['source']
assert addon_manifest(r)==live['source']
assert hashlib.sha256(subprocess.check_output(['git','diff','--cached','--binary'],cwd=r)).hexdigest()==baseline['index_diff_sha256']
subprocess.run(['git','diff','--check'],cwd=r,check=True)
print(json.dumps(summary,indent=2))