from pathlib import Path import hashlib,json,shutil,subprocess,sys r=Path('/home/jakub/devel/escapistsrereintroduced');b=Path('/tmp/erri-objective-map-0832');f=r/'.build/objective-map-native-0832-final' sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest() sys.path.insert(0,str(r/'tools'));from source_manifest import addon_manifest assert addon_manifest(r)==json.loads((f/'frozen-source.json').read_text()) bindings=json.loads((b/'suite-inputs.json').read_text());assert all(sha(r/p)==h for p,h in bindings.items()) assert json.loads((b/'integration-review.json').read_text())['verdict']=='PASS' assert subprocess.check_output(['git','diff','--cached','--binary'],cwd=r)==(b/'index-before.diff').read_bytes() copies=[ ('objective-map-native-0744','native-2026-10-02-objective-map-compile'), ('objective-map-native-0744-fixed','native-2026-10-02-objective-map-canvas'), ('objective-map-native-0832-container','native-2026-10-02-objective-map-close'), ('objective-map-native-0832-close','native-2026-10-02-objective-map-geometry'), ('objective-map-native-0832-close','native-2026-10-02-objective-map-ui'), ('objective-map-native-0832-readable','native-2026-10-02-objective-map-warning'), ('objective-map-native-0832-final','native-2026-10-02-objective-map-final'), ('objective-map-native-0832-final','native-2026-10-02-objective-map-normal'), ] reports={} for folder,name in copies: src=r/'.build'/folder/'docs/evidence'/name;report=json.loads((src/'report.json').read_text());runner=json.loads((src/'runner.json.txt').read_text()) assert runner['cleanup_confirmed'] and runner['source_unchanged_after_run'] and runner['external_addons_unchanged_after_run'] reports[name]={'assertions':report['assertions_passed'],'completions':report['smoke_completions'],'script_failures':len(report['script_or_runtime_failures']),'engine_errors':len(report['engine_errors']),'runner_result':runner['result'],'native_qualified':False} assert reports[copies[-2][1]]['assertions']==101 and reports[copies[-2][1]]['script_failures']==0 and reports[copies[-2][1]]['completions']==1 assert reports[copies[-1][1]]['assertions']==63 and reports[copies[-1][1]]['script_failures']==0 and reports[copies[-1][1]]['completions']==1 e=r/'docs/evidence/objective-map-2026-10-02';e.mkdir() for folder,name in copies:shutil.copytree(r/'.build'/folder/'docs/evidence'/name,r/'docs/evidence'/name) for name in ['review.json','integration-review.json','suite-result.json','suite-inputs.json','quota-failure.json','capture-final.py','implementation.md']: shutil.copy2(b/name,e/name) shutil.copy2(f/'regressions.log',e/'regressions.log') shutil.copy2('/tmp/erri-private-window-capture.py',e/'private-window-capture.py') shutil.copytree(r/'.build/objective-map-final-ui-0832',e/'ui') captures=json.loads((e/'ui/captures.json').read_text());assert len(captures)==7 and all(sha(e/'ui'/(x['stage']+'.png'))==x['sha256'] for x in captures) for folder,label in [('/tmp/erri-objective-map-proposal','producer'),('/tmp/erri-objective-map-native-proposal','fixture')]: for name in ['fix.patch','source-manifest.json','HANDOFF.txt']:shutil.copy2(Path(folder)/name,e/(label+'-'+name)) for source,label in [('/tmp/erri-objective-map-proposal/canvas-parent-mutation-red.log','canvas-parent-mutation-red.log'),('/tmp/erri-objective-map-review-0744/parent-offset-mutation/red.log','offset-mutation-red.log'),('/tmp/erri-objective-map-review-0744/async-close-mutation/red.log','async-close-mutation-red.log')]:shutil.copy2(source,e/label) summary={'implemented':'Authored discovery and recovered mine-warning UI outside native player-annotation lists, supported standard/shared parents, exact surface ownership and pan/zoom/close/reopen cleanup. No UGC override.','authored_files':407,'regression_programs':283,'native_runs':reports,'visual_review':{'standard':'Read-only private-window captures show question glyph, changed radio glyph/text, reopened marker and long-warning ink without obvious widget-edge truncation. Workbench viewport501x225 limits readability; full-resolution accessibility/manual-input review remains.','shared':'Disabled render-target screenshots show world view, not the shared map. Only native widget identity/geometry/lifecycle is verified; no held-texture or500ms capture claim.','engine_screenshots':'System.MakeScreenshot captures world only and is not counted as UI evidence.','private_capture':'Seven raw captures, exact process/display/socket/profile bindings, no input or focus changes. Initial observer failed writing due scratch-copy quota; failure and recovery retained.'},'preservation':'Original533 and existing owner-fixes candidate412 files unchanged. Of61 inherited paths59 byte-identical; two runner/registry overlaps preserve exact baselines with intended additions only. Index unchanged.','packaging':'Existing owner-fixes package unchanged and predates this increment.','remaining':'Human full escape, physical held map, manual map interaction, restricted-platform behavior, remote/JIP/reconnect/twelve-player multiplayer, physical logistics, comparative FPS and clean release.','committed':False,'published':False,'release_qualified':False} (e/'summary.json').write_text(json.dumps(summary,indent=2)+'\n') p=r/'docs/objective-map-presentation.md';assert not p.exists();shutil.copy2(b/'implementation.md',p) with p.open('a') as out:out.write('\n## Validation — 2 October 2026\n\nAll 283 registered regression programs pass. The [final isolated map fixture](evidence/native-2026-10-02-objective-map-final/report.json) completes 101 assertions and one completion with zero script/runtime failures; 16 engine errors remain. The [normal escape route](evidence/native-2026-10-02-objective-map-normal/report.json) completes 63 assertions and one round with zero script/runtime failures; 13 engine errors remain. All sessions were hidden/muted with confirmed cleanup and unchanged inputs. See [raw UI captures, preservation and exact limits](evidence/objective-map-2026-10-02/summary.json).\n') p=r/'docs/current-status.md';s=p.read_text();head='# Current development status\n\n';assert s.startswith(head) intro='''**2 October 2026 — independent objective map UI integrated:** discovered sites and recovered mine warnings now use authored UI outside the native player-annotation lists. Stable rough positions, exact identification, pan/zoom culling and close/reopen cleanup remain intact. Supported standard-map and shared-map containers replace the rejected Canvas parent. Player annotations and their restrictions are unchanged. [Implementation and limits](objective-map-presentation.md). All **283 registered regression programs pass**. The [final hidden/muted map fixture](evidence/native-2026-10-02-objective-map-final/report.json) completes **101 assertions and one completion**, and the [normal escape route](evidence/native-2026-10-02-objective-map-normal/report.json) completes **63 assertions and one round**. Both record zero script/runtime failures; **16/13 engine errors and strict failed verdicts remain**. Earlier compile, Canvas-parent and asynchronous-close fixture failures are retained. Read-only private-window captures show the standard question/radio glyphs, reopened marker and long-warning text at the small Workbench viewport. Shared-map checks establish widget geometry/lifecycle only: its disabled render target does not appear in screenshots, and physical held-map capture remains unverified. [Review, raw captures and preservation](evidence/objective-map-2026-10-02/summary.json). Source contains **407 authored files**. The existing owner-fixes playtest is unchanged and predates this increment. Original missions and inherited work are preserved; nothing was committed or published. Human play, manual map interaction, real multiplayer, physical logistics, comparative FPS and clean release remain unfinished. ''' p.write_text(head+intro+s[len(head):]) shutil.copy2(__file__,e/'finalize.py') before=json.loads((b/'preservation-before.json').read_text()) for root,key in [(Path('/home/jakub/devel/escapists'),'original'),(r/'.build/playtest-2026-10-02-owner-fixes','latest_candidate')]:assert all(sha(root/n)==h for n,h in before[key].items()) assert subprocess.check_output(['git','diff','--cached','--binary'],cwd=r)==(b/'index-before.diff').read_bytes() subprocess.run(['git','diff','--check'],cwd=r,check=True) print(json.dumps(summary,indent=2))