Capture current mission, AI, map and administration development

Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
This commit is contained in:
2026-10-13 22:52:53 +02:00
parent a951a96edc
commit 6a667d8deb
8104 changed files with 2124945 additions and 2061 deletions
@@ -0,0 +1,24 @@
# Separate gameplay-fixes package preparation
This directory contains a read-only preflight, an emitter, command list and parent-executed assembly/verification helpers. No native process, source edit or target write was performed to prepare them.
The parent-owned source snapshot is `.build/playtest-source-2026-10-02-gameplay-fixes` (420 authored files at freeze). Qualification binds that entire snapshot, not later live edits. The new handoff is `.build/playtest-2026-10-02-gameplay-fixes`. Every previous package remains untouched. Source counts, PAK payload counts and regression-program counts are computed from manifests/results; the helpers do not carry the prior 409/415/417 or 285 counts.
The already-generated `/tmp/erri-playtest-source-20261002-gameplay-fixes.zip` is reused read-only. Preflight and assembly verify unique exact ZIP membership and all bytes against its manifest and the frozen addon source. Do not regenerate it or point the bundle at live source.
## Parent execution order
Use `commands.txt` (exact argv plus output redirection) or `commands.json`. They specify the same `/tmp/erri-headless-compat` owned prefix used by the prior run and the audited installed RHS/WCS/BMP/Parachute closure. The emitter does not establish that the prefix is idle: retain the emitted read-only process inspections and all native runner concurrency/cleanup refusals.
1. Wait for the parent's fresh full frozen suite and same-source normal-route archive. `preflight.py` requires a complete passing suite and normal-route script pass with sealed source, console, external inputs and cleanup. It intentionally refuses the older 415-file reused suite or incomplete quota-limited checks.
2. Inspect native processes, then run one hidden/muted bounded `native_package.py --project core --timeout 300` against the frozen tools. Fresh package session: `/tmp/erri-package-20261002-gameplay-fixes-final`. The canonical direct `/tmp` session rule is mandatory; no alternate TMPDIR or symlink workaround.
3. Retain the native exit and strict package report even if runtime files exist. `assemble.py` requires natural native exit, confirmed cleanup, unchanged input/external/profile source, exact three-file runtime inventory, exact PAK payload hashes and matching normal-route/ZIP source. It creates only the new handoff/evidence directories, refusing existing destinations. Matching bytes may support an explicitly unqualified development candidate; they do not erase the strict packaging failure.
4. Inspect processes again, then run ordinary schema-4 startup: `headless_game.py --project chat --packed-addons NEW/packages --packed-session /tmp/erri-packed-chat-20261002-gameplay-fixes-final --timeout 180 --failure-grace 120` plus exact prefix/external args. No Workbench smoke, synthetic interception, input, camera or flight flags. The runner owns headless Gamescope and `-noSound`/silent-sink audio. Failure grace retains logs within the fixed timeout; it does not waive failures.
5. `verify.py` independently recomputes ordinary packed evidence from the sealed raw console, verifies launch UUID/hash/timestamps and all copied runtime bytes, requires normal mission/local prisoner and zero script errors, and retains the strict failed result and known 17 installed-resource errors. If the error set differs, stop and review it; do not change expected counts to obtain a pass. All source/suite checks run before evidence-directory creation. Schema-4 explicit raw archival is retained because the generic archive helper supports older schemas.
6. Parent final review/doc update may then label only this source-bound candidate. No complete human escape, physical interception/rearming, multiplayer/JIP, comparative FPS or release qualification follows from ordinary packaged startup. Nothing is published or committed.
## Inputs and artifact provenance
`config.json` holds all exact destinations. `template-provenance.json` hashes the prior reviewed assembly/verification templates and emitted files. `prep-review.json` records syntax validation, removal of old handoff identifiers, and verification-before-write ordering. The sole intentionally historical path in verification is the prior installed-error-set comparison (`packed-2026-10-02-owner-fixes`); no old source/suite/build path remains.
`assemble.py` and `verify.py` write new successor handoff/evidence paths only when explicitly run by the parent. They were generated but not executed here. `preflight.py` is read-only. The emitter itself writes only this scratch directory; regenerating it after changing config inputs does not launch commands.
@@ -0,0 +1,71 @@
from pathlib import Path
import hashlib,json,shutil,sys,zipfile
r=Path('/home/jakub/devel/escapistsrereintroduced');f=Path('/home/jakub/devel/escapistsrereintroduced/.build/playtest-source-2026-10-02-gameplay-fixes');sys.path.insert(0,str(f/'tools'))
from source_bundle import canonical,inventory as source_inventory
from packed_external import inventory as runtime_inventory
from pak_inventory import inventory as pak_inventory
def digest(p): return hashlib.sha256(p.read_bytes()).hexdigest()
def write(p,v): p.write_text(json.dumps(v,indent=2)+'\n')
package=Path('/tmp/erri-package-20261002-gameplay-fixes-final')
build=r/'.build/playtest-2026-10-02-gameplay-fixes'
e=r/'docs/evidence/package-2026-10-02-gameplay-fixes'
route=r/'docs/evidence/native-2026-10-02-gameplay-fixes-normal'
authored=json.loads((package/'authored-before.json').read_text())
suite_dir=Path('/tmp/erri-playtest-1631')
suite_result=json.loads((suite_dir/'suite-result.json').read_text())
suite_inputs=json.loads((suite_dir/'suite-inputs.json').read_text())
assert suite_result['exit']==0 and suite_result['inputs_unchanged']
assert all(p['exit']==0 for p in suite_result['programs'])
assert all(suite_inputs.get(n)==h for n,h in authored.items())
assert all(digest(f/n)==h for n,h in suite_inputs.items())
assert authored==source_inventory(f)==json.loads((route/'source-sha256.json').read_text())
report=json.loads((package/'package-report.json').read_text())
assert report['project_order']==['core'] and len(report['projects'])==1 and report['source_repository_unchanged']
attempt=report['projects'][0]
assert attempt['project']=='core' and attempt['copied_authored_unchanged'] and attempt['profile_addons_unchanged']
assert attempt['cleanup_confirmed'] and attempt['external_addons_unchanged_after_run'] and report['external_addons_unchanged_after_run']
assert attempt['native_exit_code']==0
payload=pak_inventory(package/'packages/core/data.pak')
actual={x['path']:x['sha256'] for x in payload['entries']}
assert len(actual)==len(payload['entries'])
expected={name.removeprefix('addons/core/'):sha for name,sha in authored.items() if not name.endswith('.meta') and not name.endswith('/addon.gproj')}
assert actual==expected
runtime=runtime_inventory(package/'packages')
assert runtime['core/addon.gproj']['sha256']==authored['addons/core/addon.gproj']
zip_path=Path('/tmp/erri-playtest-source-20261002-gameplay-fixes.zip')
with zipfile.ZipFile(zip_path) as z:
manifest=json.loads(z.read('BUNDLE-MANIFEST.json'))
names=z.namelist()
assert len(names)==len(set(names))==len({n.casefold() for n in names})
assert set(names)==set(manifest['files'])|{'BUNDLE-MANIFEST.json'}
assert {n:h for n,h in manifest['files'].items() if n.startswith('addons/')}==authored
contents={}
for n in names:
canonical(n);contents[n]=z.read(n)
if n in manifest['files']:assert hashlib.sha256(contents[n]).hexdigest()==manifest['files'][n]
route_report=json.loads((route/'report.json').read_text())
assert route_report['smoke_completions']==1 and not route_report['script_or_runtime_failures']
route_runner=json.loads((route/'runner.json.txt').read_text())
assert route_runner['cleanup_confirmed'] and route_runner['source_unchanged_after_run']
assert digest(route/'console.log.txt')==route_runner['console_sha256']
for p in (build,e):p.mkdir(exist_ok=False)
shutil.copytree(package/'packages',build/'packages')
shutil.copyfile(zip_path,build/'source.zip')
assert digest(zip_path)==digest(build/'source.zip')
for n,content in contents.items():
p=build/'source'/n;p.parent.mkdir(parents=True,exist_ok=True);p.write_bytes(content)
assert {str(p.relative_to(build/'source')) for p in (build/'source').rglob('*') if p.is_file()}==set(contents)
for n,content in contents.items(): assert (build/'source'/n).read_bytes()==content
assert runtime_inventory(build/'packages')==runtime
for p in package.iterdir():
if p.is_file() and p.suffix=='.json':shutil.copyfile(p,e/p.name)
shutil.copytree(package/'evidence',e/'native')
shutil.copyfile('/tmp/erri-package-20261002-gameplay-fixes-final.log',e/'runner-output.log.txt')
write(e/'bundle-summary.json',{'archive_sha256':digest(zip_path),'archive_bytes':zip_path.stat().st_size,'payload_files':len(manifest['files']),'projects':manifest['projects']})
shutil.copyfile(__file__,e/'assemble-handoff.py')
write(e/'pak-inventory.json',payload)
review={'kind':'UNQUALIFIED DEVELOPMENT CANDIDATE','authored_files':len(authored),'pak_payload_files':len(actual),'runtime_files':runtime,'source_zip_sha256':digest(zip_path),'source_manifest_sha256':route_runner['launch_source_sha256'],'route_package_source_match':True,'normal_route_reused_without_source_changes':True,'qualification_source_root':str(f),'qualification_source_is_frozen_snapshot':True,'live_source_match_not_claimed':True,'normal_route_console_sha256':digest(route/'console.log.txt'),'package_candidate_created':attempt['candidate_created'],'package_result':attempt['result'],'package_stopped_reason':report['stopped_reason'],'original_packaging_failure_retained':not attempt['candidate_created'],'normal_mission_ready':False,'local_participant_verified':False,'strict_packed_consumption_verified':False,'release_qualified':False,'published':False,'source_zip_exact_membership_and_hashes_verified':True,'extracted_source_and_runtime_reverified':True,'evidence':{'route':str(route.relative_to(r)),'package':str(e.relative_to(r)),'startup':'docs/evidence/packed-2026-10-02-gameplay-fixes'}}
for p in [build/'handoff.json',e/'handoff.json']:write(p,review)
(build/'README.md').write_text('# Development candidate preparation\n\nMatching source and package hashes are verified in handoff.json. Ordinary packed startup is still pending. This is not a release or Workshop publication.\n')
print(json.dumps({'build':str(build),'authored_files':len(authored),'pak_payload_files':len(actual),'runtime_files':len(runtime),'source_zip_sha256':review['source_zip_sha256']},indent=2))
@@ -0,0 +1,87 @@
[
{
"purpose": "READ-ONLY: first verify frozen suite and normal evidence; refuses pending or mismatched input",
"argv": [
"python3",
"/tmp/erri-package-prep-1631/preflight.py"
]
},
{
"purpose": "READ-ONLY: inspect processes; do not bypass a running game or runner",
"argv": [
"python3",
"/home/jakub/devel/escapistsrereintroduced/.build/playtest-source-2026-10-02-gameplay-fixes/tools/headless_game.py",
"--compat",
"/tmp/erri-headless-compat",
"--inspect-processes"
]
},
{
"purpose": "NATIVE: one bounded hidden/muted single-project pack; retain nonzero exit and raw report",
"argv": [
"python3",
"/home/jakub/devel/escapistsrereintroduced/.build/playtest-source-2026-10-02-gameplay-fixes/tools/native_package.py",
"--project",
"core",
"--session",
"/tmp/erri-package-20261002-gameplay-fixes-final",
"--compat",
"/tmp/erri-headless-compat",
"--external-addons",
"/home/jakub/.local/share/Steam/steamapps/compatdata/1874880/pfx/drive_c/users/steamuser/Documents/My Games/ArmaReforger/addons",
"--timeout",
"300"
],
"stdout_stderr_log": "/tmp/erri-package-20261002-gameplay-fixes-final.log"
},
{
"purpose": "Existing source ZIP is preserved; preflight/assembly verify its exact bytes. Do not recreate.",
"existing_path": "/tmp/erri-playtest-source-20261002-gameplay-fixes.zip"
},
{
"purpose": "FILES: exact authored/PAK/ZIP/normal-source checks, then create NEW candidate only",
"argv": [
"python3",
"/tmp/erri-package-prep-1631/assemble.py"
]
},
{
"purpose": "READ-ONLY: inspect again before packed startup",
"argv": [
"python3",
"/home/jakub/devel/escapistsrereintroduced/.build/playtest-source-2026-10-02-gameplay-fixes/tools/headless_game.py",
"--compat",
"/tmp/erri-headless-compat",
"--inspect-processes"
]
},
{
"purpose": "NATIVE: one ordinary packed startup, hidden/muted, schema4, no smoke/input/flight flags",
"argv": [
"python3",
"/home/jakub/devel/escapistsrereintroduced/.build/playtest-source-2026-10-02-gameplay-fixes/tools/headless_game.py",
"--project",
"chat",
"--packed-addons",
"/home/jakub/devel/escapistsrereintroduced/.build/playtest-2026-10-02-gameplay-fixes/packages",
"--packed-session",
"/tmp/erri-packed-chat-20261002-gameplay-fixes-final",
"--compat",
"/tmp/erri-headless-compat",
"--external-addons",
"/home/jakub/.local/share/Steam/steamapps/compatdata/1874880/pfx/drive_c/users/steamuser/Documents/My Games/ArmaReforger/addons",
"--timeout",
"180",
"--failure-grace",
"120"
],
"stdout_stderr_log": "/tmp/erri-packed-chat-20261002-gameplay-fixes-final.log"
},
{
"purpose": "FILES: recompute raw packed evidence, match all runtime bytes and update NEW candidate only",
"argv": [
"python3",
"/tmp/erri-package-prep-1631/verify.py"
]
}
]
@@ -0,0 +1,23 @@
# READ-ONLY: first verify frozen suite and normal evidence; refuses pending or mismatched input
python3 /tmp/erri-package-prep-1631/preflight.py
# READ-ONLY: inspect processes; do not bypass a running game or runner
python3 /home/jakub/devel/escapistsrereintroduced/.build/playtest-source-2026-10-02-gameplay-fixes/tools/headless_game.py --compat /tmp/erri-headless-compat --inspect-processes
# NATIVE: one bounded hidden/muted single-project pack; retain nonzero exit and raw report
python3 /home/jakub/devel/escapistsrereintroduced/.build/playtest-source-2026-10-02-gameplay-fixes/tools/native_package.py --project core --session /tmp/erri-package-20261002-gameplay-fixes-final --compat /tmp/erri-headless-compat --external-addons '/home/jakub/.local/share/Steam/steamapps/compatdata/1874880/pfx/drive_c/users/steamuser/Documents/My Games/ArmaReforger/addons' --timeout 300 > /tmp/erri-package-20261002-gameplay-fixes-final.log 2>&1
# Existing source ZIP is preserved; preflight/assembly verify its exact bytes. Do not recreate.
# /tmp/erri-playtest-source-20261002-gameplay-fixes.zip
# FILES: exact authored/PAK/ZIP/normal-source checks, then create NEW candidate only
python3 /tmp/erri-package-prep-1631/assemble.py
# READ-ONLY: inspect again before packed startup
python3 /home/jakub/devel/escapistsrereintroduced/.build/playtest-source-2026-10-02-gameplay-fixes/tools/headless_game.py --compat /tmp/erri-headless-compat --inspect-processes
# NATIVE: one ordinary packed startup, hidden/muted, schema4, no smoke/input/flight flags
python3 /home/jakub/devel/escapistsrereintroduced/.build/playtest-source-2026-10-02-gameplay-fixes/tools/headless_game.py --project chat --packed-addons /home/jakub/devel/escapistsrereintroduced/.build/playtest-2026-10-02-gameplay-fixes/packages --packed-session /tmp/erri-packed-chat-20261002-gameplay-fixes-final --compat /tmp/erri-headless-compat --external-addons '/home/jakub/.local/share/Steam/steamapps/compatdata/1874880/pfx/drive_c/users/steamuser/Documents/My Games/ArmaReforger/addons' --timeout 180 --failure-grace 120 > /tmp/erri-packed-chat-20261002-gameplay-fixes-final.log 2>&1
# FILES: recompute raw packed evidence, match all runtime bytes and update NEW candidate only
python3 /tmp/erri-package-prep-1631/verify.py
@@ -0,0 +1,17 @@
{
"root": "/home/jakub/devel/escapistsrereintroduced",
"frozen_root": "/home/jakub/devel/escapistsrereintroduced/.build/playtest-source-2026-10-02-gameplay-fixes",
"build": "/home/jakub/devel/escapistsrereintroduced/.build/playtest-2026-10-02-gameplay-fixes",
"package_session": "/tmp/erri-package-20261002-gameplay-fixes-final",
"package_log": "/tmp/erri-package-20261002-gameplay-fixes-final.log",
"source_zip": "/tmp/erri-playtest-source-20261002-gameplay-fixes.zip",
"packed_session": "/tmp/erri-packed-chat-20261002-gameplay-fixes-final",
"packed_log": "/tmp/erri-packed-chat-20261002-gameplay-fixes-final.log",
"package_evidence": "/home/jakub/devel/escapistsrereintroduced/docs/evidence/package-2026-10-02-gameplay-fixes",
"normal_evidence": "/home/jakub/devel/escapistsrereintroduced/docs/evidence/native-2026-10-02-gameplay-fixes-normal",
"packed_evidence": "/home/jakub/devel/escapistsrereintroduced/docs/evidence/packed-2026-10-02-gameplay-fixes",
"suite_directory": "/tmp/erri-playtest-1631",
"compat": "/tmp/erri-headless-compat",
"external_addons": "/home/jakub/.local/share/Steam/steamapps/compatdata/1874880/pfx/drive_c/users/steamuser/Documents/My Games/ArmaReforger/addons",
"qualification": "UNQUALIFIED DEVELOPMENT CANDIDATE; entire frozen snapshot, not necessarily later live source"
}
@@ -0,0 +1,75 @@
#!/usr/bin/env python3
"""Emit reviewed handoff commands/helpers into this scratch directory; never execute them."""
import argparse,json,shlex,hashlib
from pathlib import Path
HERE=Path(__file__).resolve().parent
ROOT=Path('/home/jakub/devel/escapistsrereintroduced')
OLD=Path('/tmp/erri-playtest-menu-fix-1349')
def sha(p): return hashlib.sha256(p.read_bytes()).hexdigest()
def main():
p=argparse.ArgumentParser(description=__doc__)
p.add_argument('--compat',type=Path,required=True,help='Existing idle disposable Tools prefix under /tmp; inspection only is separately emitted')
p.add_argument('--external-addons',type=Path,required=True)
p.add_argument('--suite-directory',type=Path,default=Path('/tmp/erri-playtest-1631'))
a=p.parse_args()
compat=a.compat.absolute();external=a.external_addons.resolve()
assert str(compat).startswith('/tmp/') and compat.exists(),'Need explicit existing disposable /tmp prefix'
assert external.is_dir(),'Installed external-addon directory must exist'
cfg={'root':str(ROOT),'frozen_root':str(ROOT/'.build/playtest-source-2026-10-02-gameplay-fixes'),
'build':str(ROOT/'.build/playtest-2026-10-02-gameplay-fixes'),
'package_session':'/tmp/erri-package-20261002-gameplay-fixes-final',
'package_log':'/tmp/erri-package-20261002-gameplay-fixes-final.log',
'source_zip':'/tmp/erri-playtest-source-20261002-gameplay-fixes.zip',
'packed_session':'/tmp/erri-packed-chat-20261002-gameplay-fixes-final',
'packed_log':'/tmp/erri-packed-chat-20261002-gameplay-fixes-final.log',
'package_evidence':str(ROOT/'docs/evidence/package-2026-10-02-gameplay-fixes'),
'normal_evidence':str(ROOT/'docs/evidence/native-2026-10-02-gameplay-fixes-normal'),
'packed_evidence':str(ROOT/'docs/evidence/packed-2026-10-02-gameplay-fixes'),
'suite_directory':str(a.suite_directory.absolute()),'compat':str(compat),'external_addons':str(external),
'qualification':'UNQUALIFIED DEVELOPMENT CANDIDATE; entire frozen snapshot, not necessarily later live source'}
(HERE/'config.json').write_text(json.dumps(cfg,indent=2)+'\n')
oldf='/home/jakub/devel/escapistsrereintroduced/.build/playtest-memory-menu-fix-native-1349'
replacements={oldf:cfg['frozen_root'],'/tmp/erri-playtest-menu-fix-1349/frozen-suite':cfg['suite_directory'],
'.build/playtest-memory-menu-fix-native-1349':'.build/playtest-source-2026-10-02-gameplay-fixes','20261002-hq-memory-menu-fix-final':'20261002-gameplay-fixes-final','2026-10-02-hq-memory-menu-fix':'2026-10-02-gameplay-fixes'}
for name in ['assemble.py','verify.py']:
s=(OLD/name).read_text()
for old,new in replacements.items(): s=s.replace(old,new)
s=s.replace('/tmp/erri-playtest-source-20261002-gameplay-fixes-final.zip',cfg['source_zip'])
s=s.replace("'frozen_snapshot_excludes_later_concurrent_terrain_presentation':True", "'qualification_source_root':str(f),'qualification_source_is_frozen_snapshot':True,'live_source_match_not_claimed':True")
if name=='assemble.py':
anchor="authored=json.loads((package/'authored-before.json').read_text())"
s=s.replace(anchor,anchor+"\nsuite_dir=Path("+repr(cfg['suite_directory'])+")\nsuite_result=json.loads((suite_dir/'suite-result.json').read_text())\nsuite_inputs=json.loads((suite_dir/'suite-inputs.json').read_text())\nassert suite_result['exit']==0 and suite_result['inputs_unchanged']\nassert all(p['exit']==0 for p in suite_result['programs'])\nassert all(suite_inputs.get(n)==h for n,h in authored.items())\nassert all(digest(f/n)==h for n,h in suite_inputs.items())")
if name=='verify.py':
s=s.replace("assert suite_result['exit']==0 and suite_result['inputs_unchanged']", "assert suite_result['exit']==0 and suite_result['inputs_unchanged']\nassert not suite_result.get('resumed'), 'This handoff helper requires the parent fresh full frozen suite; explicitly adapt evidence binding if split verification is intended'")
s=s.replace("repository_check_reused_for_identical_source=True", "repository_check_reused_for_identical_source=True,qualification_source_root=str(f),qualification_source_is_frozen_snapshot=True,live_source_match_not_claimed=True")
if name=='verify.py':
start=s.index('se.mkdir(exist_ok=False)');end=s.index('assert json.loads((r/',start)
writes=s[start:end];s=s[:start]+s[end:]
s=s.replace("(pe/'repository-check.log.txt').read_text()", "Path("+repr(cfg['suite_directory']+'/regressions.log')+").read_text()")
insert=s.index("for name in ['suite-inputs.json','suite-result.json']:")
s=s[:insert]+writes+s[insert:]
assert not any(old in s for old in ['1349','hq-memory','409 authored','285 registered']), 'Stale handoff identifier in emitted helper'
(HERE/name).write_text(s)
f=Path(cfg['frozen_root']); python='python3'; base=['--compat',str(compat),'--external-addons',str(external)]
commands=[
('READ-ONLY: first verify frozen suite and normal evidence; refuses pending or mismatched input', [python,str(HERE/'preflight.py')]),
('READ-ONLY: inspect processes; do not bypass a running game or runner', [python,str(f/'tools/headless_game.py'),'--compat',str(compat),'--inspect-processes']),
('NATIVE: one bounded hidden/muted single-project pack; retain nonzero exit and raw report', [python,str(f/'tools/native_package.py'),'--project','core','--session',cfg['package_session'],*base,'--timeout','300']),
('FILES: new development editable source ZIP from same frozen root', [python,str(f/'tools/source_bundle.py'),'--mode','development','--output',cfg['source_zip']]),
('FILES: exact authored/PAK/ZIP/normal-source checks, then create NEW candidate only', [python,str(HERE/'assemble.py')]),
('READ-ONLY: inspect again before packed startup', [python,str(f/'tools/headless_game.py'),'--compat',str(compat),'--inspect-processes']),
('NATIVE: one ordinary packed startup, hidden/muted, schema4, no smoke/input/flight flags', [python,str(f/'tools/headless_game.py'),'--project','chat','--packed-addons',cfg['build']+'/packages','--packed-session',cfg['packed_session'],*base,'--timeout','180','--failure-grace','120']),
('FILES: recompute raw packed evidence, match all runtime bytes and update NEW candidate only', [python,str(HERE/'verify.py')])]
entries=[]
for n,v in commands:
if str(f/'tools/source_bundle.py') in v and Path(cfg['source_zip']).exists():
entries.append({'purpose':'Existing source ZIP is preserved; preflight/assembly verify its exact bytes. Do not recreate.', 'existing_path':cfg['source_zip']});continue
entry={'purpose':n,'argv':v}
if str(f/'tools/native_package.py') in v:entry['stdout_stderr_log']=cfg['package_log']
if '--packed-session' in v:entry['stdout_stderr_log']=cfg['packed_log']
entries.append(entry)
(HERE/'commands.json').write_text(json.dumps(entries,indent=2)+'\n')
(HERE/'commands.txt').write_text('\n\n'.join('# '+e['purpose']+'\n'+(shlex.join(e['argv'])+(' > '+shlex.quote(e['stdout_stderr_log'])+' 2>&1' if 'stdout_stderr_log' in e else '') if 'argv' in e else '# '+e['existing_path']) for e in entries)+'\n')
(HERE/'template-provenance.json').write_text(json.dumps({'templates':{str(OLD/n):sha(OLD/n) for n in ['assemble.py','verify.py']},'generated':{n:sha(HERE/n) for n in ['assemble.py','verify.py','commands.json','config.json']},'executed_native':False,'target_writes':False},indent=2)+'\n')
print('Emitted scratch commands and helpers only; no launch, build or target write.')
if __name__=='__main__':main()
@@ -0,0 +1,101 @@
#!/usr/bin/env python3
"""Scratch draft by default. Parent may use --verified, then --verified --apply."""
import argparse,hashlib,json,shutil,subprocess,sys
from pathlib import Path
HERE=Path(__file__).resolve().parent;BASE=Path('/tmp/erri-playtest-1631')
ROOT=Path('/home/jakub/devel/escapistsrereintroduced');FROZEN=ROOT/'.build/playtest-source-2026-10-02-gameplay-fixes'
BUILD=ROOT/'.build/playtest-2026-10-02-gameplay-fixes';EVIDENCE=ROOT/'docs/evidence/playtest-refresh-2026-10-02-gameplay-fixes'
PE=ROOT/'docs/evidence/package-2026-10-02-gameplay-fixes';NE=ROOT/'docs/evidence/native-2026-10-02-gameplay-fixes-normal';SE=ROOT/'docs/evidence/packed-2026-10-02-gameplay-fixes'
REFUSAL=ROOT/'docs/evidence/native-2026-10-02-gameplay-fixes-cleanup-refusal'
load=lambda p:json.loads(p.read_text())
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
def write(p,v):p.parent.mkdir(parents=True,exist_ok=True);p.write_text(json.dumps(v,indent=2)+'\n')
def copy(a,b):
b.parent.mkdir(parents=True,exist_ok=True)
if a.is_dir():shutil.copytree(a,b,dirs_exist_ok=True)
else:shutil.copyfile(a,b)
def mismatches(root,m):return {n:{'expected':h,'actual':sha(root/n) if (root/n).is_file() else None} for n,h in m.items() if not (root/n).is_file() or sha(root/n)!=h}
def main():
ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('--verified',action='store_true');ap.add_argument('--apply',action='store_true')
ap.add_argument('--review',type=Path,default=Path('/tmp/erri-playtest-review-1631/review.json'))
ap.add_argument('--approved-concurrent',type=Path,help='Optional independently reviewed flat path-to-current-hash map for inherited concurrent changes; never docs')
a=ap.parse_args();assert not a.apply or a.verified,'--apply requires --verified'
baseline=load(BASE/'baseline.json');frozen=load(BASE/'frozen-source.json');approved=load(a.approved_concurrent) if a.approved_concurrent else {}
docs={'README.md':HERE/'docs-baseline/README.md','docs/current-status.md':HERE/'docs-baseline/current-status.md','docs/playtest-build.md':HERE/'docs-baseline/playtest-build.md'}
assert not set(docs)&set(approved),'Concurrent documentation requires explicit rebase; no hash allowlist bypass'
assert all((ROOT/n).read_bytes()==p.read_bytes() for n,p in docs.items()),'Live docs changed; rebase scratch and review before applying'
sys.path.insert(0,str(FROZEN/'tools'));from source_manifest import addon_manifest
current=addon_manifest(ROOT);source_delta={n:{'frozen':frozen.get(n),'live':current.get(n)} for n in set(frozen)|set(current) if frozen.get(n)!=current.get(n)}
check={'index_unchanged':hashlib.sha256(subprocess.check_output(['git','diff','--cached','--binary'],cwd=ROOT)).hexdigest()==baseline['index_diff_sha256'],
'inherited_paths':len(baseline['working_modified']),'inherited_mismatches':mismatches(ROOT,{n:approved.get(n,h) for n,h in baseline['working_modified'].items()}),
'frozen_source_mismatches':mismatches(FROZEN,frozen),'live_frozen_delta':source_delta,'concurrent_approval':approved,
'docs_before':{n:sha(p) for n,p in docs.items()}}
prior=ROOT/'.build/playtest-2026-10-02-hq-memory-menu-fix';priorseal=ROOT/'docs/evidence/playtest-refresh-2026-10-02-hq-memory-menu-fix/candidate-sha256.json';pm=load(priorseal)
check['previous_package_mismatches']=mismatches(prior,pm);check['previous_package_extra_files']=sorted(str(p.relative_to(prior)) for p in prior.rglob('*') if p.is_file() and str(p.relative_to(prior)) not in pm)
reference=load(Path('/tmp/erri-heartbeat-20260930-1542-reference.json'));check['original_reference_mismatches']=mismatches(Path('/home/jakub/devel/escapists'),reference);check['original_reference_files']=len(reference)
suite=load(BASE/'suite-result.json') if (BASE/'suite-result.json').exists() else None
count=suite['regression_programs'] if suite else 'pending';normal=None;packed=None;handoff=None
if a.verified:
assert a.review.is_file(),'Independent final review missing'
assert check['index_unchanged'] and not check['inherited_mismatches'] and not check['frozen_source_mismatches'],'Input preservation failed'
assert not check['previous_package_mismatches'] and not check['previous_package_extra_files'] and not check['original_reference_mismatches'],'Original/prior package changed'
assert all(approved.get(n)==v['live'] for n,v in source_delta.items()),'Concurrent live source changed without reviewed exact hashes'
assert suite and suite['exit']==0 and suite['inputs_unchanged'] and not suite.get('resumed'),'Need fresh full frozen suite'
assert len(suite['programs'])==count==len({p['path'] for p in suite['programs']}) and all(p['exit']==0 for p in suite['programs'])
inputs=load(BASE/'suite-inputs.json');assert not mismatches(FROZEN,inputs) and all(inputs.get(n)==h for n,h in frozen.items())
handoff=load(BUILD/'handoff.json');assert handoff==load(PE/'handoff.json')
assert handoff['authored_files']==len(frozen) and handoff['normal_mission_ready'] and handoff['local_participant_verified']
assert handoff['repository_regression_programs']==count and not handoff['release_qualified'] and not handoff['published']
assert handoff['qualification_source_root']==str(FROZEN)
assert load(PE/'authored-before.json')==frozen
normal=load(NE/'report.json');runner=load(NE/'runner.json.txt');assert load(NE/'source-sha256.json')==frozen==load(NE/'launch-source-sha256.json')
assert normal['smoke_completions']==1 and not normal['script_or_runtime_failures'] and len(normal['engine_errors'])==13
assert runner['cleanup_confirmed'] and runner['source_unchanged_after_run'] and runner['external_addons_unchanged_after_run'] and sha(NE/'console.log.txt')==runner['console_sha256']
packed=load(SE/'packed-startup-report.json');pr=load(SE/'packed-runner.json');assert not packed['script_or_runtime_failures'] and len(packed['engine_errors'])==17
assert packed['normal_mission_ready'] and packed['local_participant_verified'] and pr['cleanup_confirmed'] and pr['packed_inputs_unchanged_after_run'] and pr['packed_external_inputs_unchanged_after_run']
from packed_external import inventory
assert inventory(BUILD/'packages')==handoff['runtime_files'] and len(handoff['runtime_files'])==3
from source_bundle import inventory as authored_inventory
assert authored_inventory(BUILD/'source')==frozen and sha(BUILD/'source.zip')==handoff['source_zip_sha256']
assert (REFUSAL/'archive-review.json').is_file() and (REFUSAL/'runner.json').is_file(),'Initial cleanup refusal must remain retained'
assert load(REFUSAL/'runner.json').get('cleanup_confirmed') is False,'Initial refusal must not be relabeled as confirmed cleanup'
check['independent_review_sha256']=sha(a.review)
source_count=len(frozen);payload_count=handoff['pak_payload_files'] if handoff else 'pending';runtime_count=len(handoff['runtime_files']) if handoff else 'pending'
features='This frozen snapshot includes the rifle-supply callback cancellation guard, bounded HQ road-survey fairness, and the inherited terrain-selection, presentation and admin-item integration. These are included source changes; this handoff does not claim manual UI, physical resupply or physical interception qualification.'
limits='It remains an **unqualified development candidate**. Complete human escape, real multiplayer/JIP/reconnect/twelve-player play, physical interception/rearming, comparative FPS and a clean release remain unverified. The normal route targets Everon. Later live edits are outside this sealed snapshot; existing packages and original missions are preserved.'
if a.verified:
validation=f'The exact frozen source passes **{count} registered regression programs**. Its normal route completes **{normal["assertions_passed"]} assertions and {normal["smoke_completions"]} round**, with zero script/runtime failures and **13 retained engine errors**. Ordinary startup of the exact packaged bytes verifies the normal mission and local prisoner with zero script/runtime failures and **17 retained engine errors**. Strict packaging/startup failures remain recorded.'
counts=f'**{source_count} authored files**, **{payload_count} exact PAK payloads** and **{runtime_count} runtime files** match the editable source and `handoff.json`.'
else:
validation=f'Final package/startup qualification is pending. The frozen snapshot contains {source_count} authored files; recorded suite count: {count}. No new packaged-playability result is claimed by this draft.';counts='Package payload/runtime counts remain pending verification.'
refusal='The first normal-route attempt reached its scripted result but its runner refused cleanup confirmation after observing a compiler process (`cc1plus`) and an empty-argv process. That failed attempt remains archived separately; the later confirmed run does not erase it.'
summary=f'{counts}\n\n{features}\n\n{validation}\n\n{refusal}\n\n{limits}'
out=HERE/'proposed-docs';out.mkdir(exist_ok=True)
newreadme='# Gameplay-fixes development candidate — 2 October 2026\n\n'+summary+'\n\nUse `source/addons/core/addon.gproj` with the separately installed RHS, WCS, BMP and Parachute dependency closure. Select `Missions/ERR_Everon.conf`. Runtime files are in `packages/core/`; editable source is in `source/` and `source.zip`. Keep ordinary human play free of smoke/input/flight fixture flags. See [the player route](../../docs/player-route.md), [build guide](../../docs/playtest-build.md) and [sealed evidence](../../docs/evidence/playtest-refresh-2026-10-02-gameplay-fixes/review.json). Nothing was committed or published.\n'
(out/'candidate-README.md').write_text(newreadme)
status=(HERE/'docs-baseline/current-status.md').read_text();title,tail=status.split('\n',1)
newstatus=title+'\n\n**2 October 2026 — refreshed gameplay-fixes handoff:** [separate package and editable source](../.build/playtest-2026-10-02-gameplay-fixes/README.md).\n\n'+summary+' [Evidence and independent review](evidence/playtest-refresh-2026-10-02-gameplay-fixes/review.json).\n\n'+tail.lstrip('\n')
(out/'current-status.md').write_text(newstatus)
guide=(HERE/'docs-baseline/playtest-build.md').read_text();start=guide.index('The latest retained handoff is ');end=guide.index('## Identities and required dependencies')
old_intro=guide[start:end];new_intro='The latest retained handoff is [2 October — gameplay fixes](../.build/playtest-2026-10-02-gameplay-fixes/README.md).\n\n'+summary+'\n\n'
newguide=guide[:start]+new_intro+guide[end:]+'\n## Historical prior latest-handoff description\n\n'+old_intro
(out/'playtest-build.md').write_text(newguide)
readme=(HERE/'docs-baseline/README.md').read_text();paragraph=next(p for p in readme.split('\n\n') if p.startswith('The [local development playtest handoff]'))
replacement='The [local development playtest handoff](.build/playtest-2026-10-02-gameplay-fixes/README.md) contains the 2 October gameplay-fixes frozen snapshot, as one combined addon package plus matching editable source and the authorized external dependency graph. '+validation+' '+limits+' See [current status](docs/current-status.md) for exact source-bound evidence and limitations.'
assert readme.count(paragraph)==1;(out/'README.md').write_text(readme.replace(paragraph,replacement,1))
review={'state':'verified proposal' if a.verified else 'pending draft','source_count':source_count,'pak_payload_files':payload_count,'runtime_files':runtime_count,'suite':suite,'normal':normal,'packed':packed,'preservation':check,'qualification':'development only; no manual UI/physical interception/MP/FPS/release claim','proposed_sha256':{p.name:sha(p) for p in out.iterdir() if p.is_file()}}
write(HERE/'docs-proposal.json',review)
if a.apply:
assert not EVIDENCE.exists(),'Never overwrite existing evidence'
expected='# Development candidate preparation\n\nMatching source and package hashes are verified in handoff.json. Ordinary packed startup is still pending. This is not a release or Workshop publication.\n'
assert (BUILD/'README.md').read_text()==expected,'Candidate README changed since assembly; review before overwrite'
EVIDENCE.mkdir()
for n in ['baseline.json','frozen-source.json','suite-inputs.json','suite-result.json','regressions.log','source-bundle.log','concurrent-source-delta.json','normal-native.log','normal-native-retry.log']:
if (BASE/n).exists():copy(BASE/n,EVIDENCE/n)
copy(REFUSAL,EVIDENCE/'initial-normal-cleanup-refusal');copy(a.review,EVIDENCE/'independent-review.json');copy(Path(__file__),EVIDENCE/'finalize-docs.py')
copy(HERE/'template-provenance.json',EVIDENCE/'helper-template-provenance.json');write(EVIDENCE/'review.json',review)
for n,dest in [('candidate-README.md',BUILD/'README.md'),('README.md',ROOT/'README.md'),('current-status.md',ROOT/'docs/current-status.md'),('playtest-build.md',ROOT/'docs/playtest-build.md')]:copy(out/n,dest)
write(EVIDENCE/'candidate-sha256.json',{str(p.relative_to(BUILD)):sha(p) for p in sorted(BUILD.rglob('*')) if p.is_file()})
write(EVIDENCE/'docs-after.json',{n:sha(ROOT/n) for n in docs})
print(json.dumps({'state':review['state'],'applied':a.apply,'proposal':str(out),'source_files':source_count,'suite_count':count},indent=2))
if __name__=='__main__':main()
@@ -0,0 +1,32 @@
#!/usr/bin/env python3
"""Read-only qualification/input check; never launches native or changes a package."""
from pathlib import Path
import json,hashlib,sys,zipfile
HERE=Path(__file__).resolve().parent
load=lambda p:json.loads(p.read_text())
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
c=load(HERE/'config.json');f=Path(c['frozen_root']);suite=Path(c['suite_directory']);normal=Path(c['normal_evidence'])
sys.path.insert(0,str(f/'tools'));from source_bundle import inventory
source=inventory(f);result=load(suite/'suite-result.json');inputs=load(suite/'suite-inputs.json')
assert result['exit']==0 and result['inputs_unchanged'] and not result.get('resumed'),'Requires completed fresh full frozen suite'
assert len(result['programs'])==result['regression_programs']==len({p['path'] for p in result['programs']})
assert all(p['exit']==0 for p in result['programs'])
assert all(inputs.get(n)==h for n,h in source.items()) and all((f/n).is_file() and sha(f/n)==h for n,h in inputs.items())
report=load(normal/'report.json');runner=load(normal/'runner.json.txt')
assert report['smoke_completions']==1 and not report['script_or_runtime_failures']
assert runner['cleanup_confirmed'] and runner['source_unchanged_after_run'] and runner['external_addons_unchanged_after_run']
assert sha(normal/'console.log.txt')==runner['console_sha256']
assert source==load(normal/'source-sha256.json')==load(normal/'launch-source-sha256.json')
for n in ['build','package_session','package_evidence','packed_session','packed_evidence']:
p=Path(c[n]);assert not p.exists() and not p.is_symlink(),f'Never reuse/overwrite {p}'
zip_path=Path(c['source_zip'])
if zip_path.exists():
with zipfile.ZipFile(zip_path) as z:
bm=load_manifest=json.loads(z.read('BUNDLE-MANIFEST.json'));names=z.namelist()
assert len(names)==len(set(names))==len({n.casefold() for n in names})
assert set(names)==set(bm['files'])|{'BUNDLE-MANIFEST.json'}
assert {n:h for n,h in bm['files'].items() if n.startswith('addons/')}==source
assert all(hashlib.sha256(z.read(n)).hexdigest()==h for n,h in bm['files'].items())
for n in ['package_session','packed_session']:
p=Path(c[n]);assert p.parent==Path('/tmp') and p==p.resolve(),'Native sessions must be direct canonical /tmp children'
print(json.dumps({'read_only':True,'authored_files':len(source),'regression_programs':result['regression_programs'],'normal_assertions':report['assertions_passed'],'retained_normal_engine_errors':len(report['engine_errors']),'qualified_for_next_diagnostic_step':True,'release_qualified':False},indent=2))
@@ -0,0 +1,15 @@
{
"syntax_valid": true,
"stale_old_identifiers": false,
"verification_before_evidence_creation": true,
"existing_zip_preserved": true,
"source_count_is_derived": true,
"native_run": false,
"target_writes": false,
"sha256": {
"emit.py": "1ac290be0c662deef84fd5cd4d271eb86d590ac3e2a907dd62622501b2b9e4ba",
"preflight.py": "a019b2bf7163276291137a289280b31112fcd71dc1906ad4eb6dfa47f0e0e05b",
"assemble.py": "00fa8c768b7993b41d1f62c47b30f3613ae204e10a9175fea32eaf94fffa8332",
"verify.py": "4ae0bcdd3829b0f6ee1373120f1489d1745f486e44a3e9e02737e5ee3b3d1af1"
}
}
@@ -0,0 +1,14 @@
{
"templates": {
"/tmp/erri-playtest-menu-fix-1349/assemble.py": "8f80ad39af129fab63194850570d2b974d4fc4c620470773fd74d4323bbd4cbc",
"/tmp/erri-playtest-menu-fix-1349/verify.py": "96014d34e2415c31e9ff95c07e10a0194cf30abf7f0181b583d936bbb916c846"
},
"generated": {
"assemble.py": "00fa8c768b7993b41d1f62c47b30f3613ae204e10a9175fea32eaf94fffa8332",
"verify.py": "4ae0bcdd3829b0f6ee1373120f1489d1745f486e44a3e9e02737e5ee3b3d1af1",
"commands.json": "b75f084e46377b1b7043875e4a29aa45569bd089eac86b5de56f11b420cc9f39",
"config.json": "b31bdb748a80c059c810dd148ea8c5404c9d57407eea2f3560268c34fa10c454"
},
"executed_native": false,
"target_writes": false
}
@@ -0,0 +1,68 @@
from pathlib import Path
import ast
_tree=ast.parse(Path('/home/jakub/devel/escapistsrereintroduced/.build/playtest-source-2026-10-02-gameplay-fixes/tools/check.py').read_text())
REGRESSION_PROGRAMS=len([n.value for n in ast.walk(_tree) if isinstance(n,ast.Constant) and isinstance(n.value,str) and n.value.endswith('.py') and (n.value.split('/')[-1].startswith('test_') or n.value.endswith('_regression.py'))])
import hashlib,json,re,shutil,sys
r=Path('/home/jakub/devel/escapistsrereintroduced');f=Path('/home/jakub/devel/escapistsrereintroduced/.build/playtest-source-2026-10-02-gameplay-fixes');sys.path.insert(0,str(f/'tools'))
from packed_external import inventory,evidence
import headless_game
def digest(p):return hashlib.sha256(p.read_bytes()).hexdigest()
def write(p,v):p.write_text(json.dumps(v,indent=2)+'\n')
build=r/'.build/playtest-2026-10-02-gameplay-fixes';startup=Path('/tmp/erri-packed-chat-20261002-gameplay-fixes-final')
pe=r/'docs/evidence/package-2026-10-02-gameplay-fixes';se=r/'docs/evidence/packed-2026-10-02-gameplay-fixes'
runner=json.loads((startup/'packed-runner.json').read_text());report=json.loads((startup/'packed-startup-report.json').read_text());manifest=json.loads((startup/'packed-input-provenance.json').read_text())
assert manifest['schema_version']==4 and manifest['kind']=='packed-chat-external-runtime-input'
assert manifest['project']=='chat' and manifest['addon_order']==['core']
assert runner['cleanup_confirmed'] and runner['packed_inputs_unchanged_after_run'] and runner['packed_external_inputs_unchanged_after_run']
assert runner['packed_input_error'] is None and runner['runner_error'] is None
assert runner['packed_input_provenance_sha256']==digest(startup/'packed-input-provenance.json')
assert runner['packed_launch_id']==manifest['launch_id']
assert manifest['captured_unix']<=runner['started_unix']<=runner['stopped_unix']
assert runner['display']=='headless Gamescope' and runner['audio']=='-noSound plus own silent sink'
assert runner['failure_observed_during_polling'] and not runner['packed_consumption_verified']
logs=Path(runner['session']);assert logs.resolve().is_relative_to(startup.resolve()) and logs.is_dir()
assert digest(logs/'console.log')==runner['console_sha256']
assert (logs/'packed-input-provenance.json').read_bytes()==(startup/'packed-input-provenance.json').read_bytes()
assert (logs/'runner.json').read_bytes()==(startup/'packed-runner.json').read_bytes()
assert (logs/'game-startup-report.json').read_bytes()==(startup/'packed-startup-report.json').read_bytes()
packed={'input':Path(manifest['runtime_directory']),'external_records':manifest['external_addons'],'external_names':manifest['external_project_names']}
steam=Path(runner['executable']).parents[3]
recomputed=evidence((logs/'console.log').read_text(),packed,steam,Path(manifest['profile']),headless_game)
for k,v in recomputed.items():assert report[k]==v,(k,report[k],v)
assert report['normal_mission_ready'] and report['local_participant_verified'] and report['packed_loaded_paths_verified'] and report['packed_normal_modules']
assert report['workbench_undefined'] and not report['unexpected_smoke_fixture'] and not report['script_or_runtime_failures'] and not report['packed_input_violations']
assert report['packed_schema_version']==4 and report['external_addon_count']==7 and len(report['engine_errors'])==17
old=json.loads((r/'docs/evidence/packed-2026-10-02-owner-fixes/packed-startup-report.json').read_text())
normal=lambda rows:sorted(re.sub(r'\s+',' ',re.sub(r'^\d\d:\d\d:\d\d\.\d+\s*','',x)).strip() for x in rows)
assert normal(report['engine_errors'])==normal(old['engine_errors']),'Different installed error set'
runtime=inventory(build/'packages');assert runtime==inventory(startup/'input/addons')==manifest['artifacts']
assert runtime==json.loads((build/'handoff.json').read_text())['runtime_files']
assert json.loads((r/'.build/playtest-source-2026-10-02-gameplay-fixes/frozen-source.json').read_text())==json.loads((r/'docs/evidence/native-2026-10-02-gameplay-fixes-normal/source-sha256.json').read_text())
assert 'All repository checks passed.' in Path('/tmp/erri-playtest-1631/regressions.log').read_text()
suite_result=json.loads(Path('/tmp/erri-playtest-1631/suite-result.json').read_text())
suite_inputs=json.loads(Path('/tmp/erri-playtest-1631/suite-inputs.json').read_text())
assert suite_result['exit']==0 and suite_result['inputs_unchanged']
assert not suite_result.get('resumed'), 'This handoff helper requires the parent fresh full frozen suite; explicitly adapt evidence binding if split verification is intended'
assert suite_result['regression_programs']==REGRESSION_PROGRAMS==len(suite_result['programs'])
assert len({p['path'] for p in suite_result['programs']})==REGRESSION_PROGRAMS
assert all(p['exit']==0 for p in suite_result['programs'])
authored=json.loads((pe/'authored-before.json').read_text())
assert all(suite_inputs.get(n)==h for n,h in authored.items())
assert all(digest(f/n)==h for n,h in suite_inputs.items())
se.mkdir(exist_ok=False)
for name in ['packed-runner.json','packed-startup-report.json','packed-input-provenance.json','external-addons-inputs.json','external-addons-policy.json']:shutil.copyfile(startup/name,se/name)
for p in logs.iterdir():
if p.is_file() and p.suffix in ('.log','.json'):shutil.copyfile(p,se/(p.name+'.txt' if p.suffix=='.log' else p.name))
shutil.copyfile('/tmp/erri-packed-chat-20261002-gameplay-fixes-final.log',se/'runner-output.log.txt')
shutil.copyfile(__file__,se/'verify-and-finish.py')
shutil.copyfile(Path('/tmp/erri-playtest-1631/regressions.log'),pe/'repository-check.log.txt')
for name in ['suite-inputs.json','suite-result.json']:
shutil.copyfile(Path('/tmp/erri-playtest-1631')/name,pe/name)
review=json.loads((build/'handoff.json').read_text());review.update(normal_mission_ready=True,local_participant_verified=True,strict_packed_consumption_verified=False,packed_script_failures=0,packed_resource_errors=17,repository_check_exit=0,repository_regression_programs=REGRESSION_PROGRAMS,repository_check_reused_for_identical_source=True,qualification_source_root=str(f),qualification_source_is_frozen_snapshot=True,live_source_match_not_claimed=True)
assert not review['release_qualified'] and not review['published']
for p in [build/'handoff.json',pe/'handoff.json']:write(p,review)
write(se/'archive-review.json',{'runtime_bytes_match_handoff':True,'copied_runtime_bytes_match_launch_manifest':True,'raw_console_sha256_verified':True,'launch_manifest_hash_and_uuid_verified':True,'native_and_root_reports_identical':True,'normal_modules_and_ten_mounts_recomputed_from_raw_console':True,'local_prisoner_verified':True,'known_resource_error_set_matches_previous_handoff':True,'cleanup_confirmed':True,'source_qualification':'Packed-only startup; source binding established separately by handoff manifest, not asserted by runner','strict_failure_retained':True,'archive_method':'archive_packed.py supports schemas 1 and 2 only; this schema 4 archive uses the explicit verifier and retained raw files.'})
write(se/'archive-sha256.json',{str(p.relative_to(se)):digest(p) for p in sorted(se.iterdir()) if p.is_file()})
print('Verified and retained packed startup, exact runtime bytes and full regression log. Strict failure preserved.')