--- rename-scroll-native-bebf9f5.py +++ rename-scroll-native-feab202.py @@ -1,4 +1,4 @@ -"""Narrow one-launch Windows trial; prepare/launch require actual closed bebf gates.""" +"""Narrow one-launch Windows trial; prepare/launch require actual closed feab202 gates.""" from pathlib import Path from datetime import datetime, timezone import argparse, hashlib, json, os, re, subprocess, sys @@ -9,9 +9,9 @@ require(__debug__, 'Python -O is forbidden') ROOT = Path(__file__).resolve().parent.parent -SOURCE = 'bebf9f594c6722200e95e92be2734acbea0dd700' -PENDING_FINAL_SOURCE = True # Actual bebf preview gate failed; await reviewed test-only correction and fresh gates. -CONFIG = ROOT / '.local/rename-scroll-native-bebf9f5.config.json' +SOURCE = 'feab2020d8e5b6bfdb59c86ab4aee161617b8b6f' +PENDING_FINAL_SOURCE = False # Reviewed feab202 test-only correction; actual gate admission remains mandatory. +CONFIG = ROOT / '.local/rename-scroll-native-feab202.config.json' def now(): return datetime.now(timezone.utc).isoformat() def digest(raw): return {'bytes': len(raw), 'sha256': hashlib.sha256(raw).hexdigest()} def save(path, value): @@ -28,7 +28,7 @@ return result def admission(): - require(not PENDING_FINAL_SOURCE, 'Pending reviewed final source and fresh gates; bebf preview failed 4 passed / 1 failed') + require(not PENDING_FINAL_SOURCE, 'Pending final source admission') watched = {} def read(path): raw = path.read_bytes() @@ -51,7 +51,7 @@ gate_specs = [('list','list',None), ('preview','focused','preview_scroll_tests'), ('rename','focused','app::source_rename::tests::'), ('navigation','focused','navigation_union'), ('source-navigation','focused','source_navigation::'), ('full','full',None), ('strict','clippy',None)] manifests, test_artifact = [], None for stem, mode, selector in gate_specs: - name = stem + '-bebf9f5' + name = stem + '-feab202' record = value(gates / (name + '.result.json')) admitted = value(gates / (name + '.admission.json')) require(record['source'] == record['head_after'] == admitted['source'] == SOURCE, 'Wrong gate source: ' + name) @@ -91,7 +91,7 @@ totals = re.findall(r'^test result: ok\. (\d+) passed; (\d+) failed; (\d+) ignored; (\d+) measured; (\d+) filtered out;', log, re.M) require(totals == [(str(len(names)-len(ignored)), '0', str(len(ignored)), '0', str(1099-len(names)))], 'Runtime totals differ') require(digest(read(Path(test_artifact['path']))) == {k:test_artifact[k] for k in ('bytes','sha256')}, 'Test executable changed') - gui = gates / 'gui-bebf9f5' + gui = gates / 'gui-feab202' build = value(gui / 'result.json'); environment = value(gui / 'environment.json') require(build['source'] == build['head_after'] == SOURCE and type(build['exit']) is int and build['exit'] == 0 and build['outcome'] == 'passed' and build['failure'] is None and not build['changed_inputs'] and build['status_after'] == '', 'GUI build not closed PASS') require(datetime.fromisoformat(build['end']) >= datetime.fromisoformat(build['start']), 'Invalid GUI closure') @@ -125,7 +125,9 @@ blobs = git(work, 'cat-file','--batch',data=''.join(f'{SOURCE}:{p}\n' for p in paths).encode()); offset=0 entries = {i['path']:i for i in manifests[-1]['inputs']} for path in paths: - end=blobs.index(b'\n',offset); _,kind,size=blobs[offset:end].split(); size=int(size); raw=blobs[end+1:end+1+size]; offset=end+size+2 + end=blobs.index(b'\n',offset); _,kind,size=blobs[offset:end].split(); size=int(size); raw=blobs[end+1:end+1+size] + require(blobs[end+1+size:end+2+size] == b'\n', 'Missing Git blob terminator: '+path) + offset=end+size+2 require(kind == b'blob' and digest(raw) == {k:entries[path][k] for k in ('bytes','sha256')} and read(work/path) == raw, 'Source bytes differ: '+path) require(offset == len(blobs) and all(entries[i['path']] == i for i in manifests[0]['inputs']), 'Gate/GUI source disagreement') require(not git(work,'status','--porcelain','--untracked-files=all','--',*scopes,'scripts'), 'Source worktree dirty') @@ -135,6 +137,28 @@ attestation = {'source':SOURCE,'config':digest(read(CONFIG)),'helper':digest(Path(__file__).read_bytes()),'records':{str(p.relative_to(ROOT)):digest(raw) for p,raw in watched.items() if p.is_relative_to(ROOT) and not p.name.endswith('.exe') and not p.is_relative_to(work)},'gui':digest(executable),'runtime':digest(read(runtime_origin)),'baseline':baseline,'scope':'Closed source/build admission only; native outcome remains manual. No semantic oracle reuse.'} return cfg, attestation, executable, read(runtime_origin) +def capture_checkpoint_files(work, snapshot): + # Record every observed map, including failures; never describe an unchecked copy. + def observe(directory): + try: return files(directory), None + except Exception as error: return None, repr(error) + before, before_error = observe(work) + copy_error = None + snapshot.mkdir() + if before is not None: + try: + for name in before: + path=snapshot/name;path.parent.mkdir(parents=True,exist_ok=True) + with path.open('xb') as stream: stream.write((work/name).read_bytes()) + except Exception as error: + copy_error=repr(error) + copied, snapshot_error = observe(snapshot) + after, after_error = observe(work) + consistent = before is not None and before == copied == after and not any((before_error,copy_error,snapshot_error,after_error)) + return {'before':before,'snapshot':copied,'after':after,'before_error':before_error, + 'copy_error':copy_error,'snapshot_error':snapshot_error,'after_error':after_error, + 'copy_consistent':consistent} + def checkpoint(trial, stage, label): require(re.fullmatch(r'[a-z0-9-]+',label) is not None, 'Invalid checkpoint label') require((trial/'launch.json').is_file(), 'No owned launch') @@ -143,11 +167,15 @@ require(preparation['source']==launch['source']==SOURCE and launch['helper']==digest(Path(__file__).read_bytes()) and launch['config']==digest(CONFIG.read_bytes()), 'Checkpoint source/helper/config changed') destination=trial/'checkpoints'/label destination.mkdir(parents=True,exist_ok=False) - actual=files(trial/'source-work') - for name in actual: - path=destination/'snapshot'/name;path.parent.mkdir(parents=True,exist_ok=True);path.write_bytes((trial/'source-work'/name).read_bytes()) - unchanged=actual==preparation['baseline'] and files(trial/'source-baseline')==preparation['baseline'] - result={'utc':now(),'source':SOURCE,'label':label,'actual':actual,'expected':preparation['baseline'],'exact_disk_bytes_equal':unchanged,'stage_unchanged':stage_payload(stage)==preparation['payloads'],'scope':'Disk membership and complete-byte equality only; does not assert transient model/history or UI acceptance.'} + capture=capture_checkpoint_files(trial/'source-work',destination/'snapshot') + verification_error=None + try: + baseline_unchanged=files(trial/'source-baseline')==preparation['baseline'] + stage_unchanged=stage_payload(stage)==preparation['payloads'] + except Exception as error: + baseline_unchanged=stage_unchanged=False;verification_error=repr(error) + unchanged=capture['copy_consistent'] and capture['before']==preparation['baseline'] and baseline_unchanged + result={'utc':now(),'source':SOURCE,'label':label,**capture,'expected':preparation['baseline'],'baseline_unchanged':baseline_unchanged,'verification_error':verification_error,'exact_disk_bytes_equal':unchanged,'stage_unchanged':stage_unchanged,'scope':'Disk membership and complete-byte equality only; does not assert transient model/history or UI acceptance.'} save(destination/'result.json',result);print(json.dumps(result),flush=True) require(unchanged and result['stage_unchanged'], 'Checkpoint byte mismatch retained') @@ -157,7 +185,7 @@ def main(): parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('mode',choices=['check','prepare','launch','checkpoint']);parser.add_argument('--label');args=parser.parse_args() cfg=json.loads(CONFIG.read_bytes());trial=ROOT/cfg['trial'];stage=ROOT/cfg['stage'] - require(not PENDING_FINAL_SOURCE, 'Pending reviewed source correction and fresh gates; no native trial admitted') + require(not PENDING_FINAL_SOURCE, 'Pending final source admission') require(trial.parent == ROOT/'.local/native-qa' and stage.parent == trial.parent and trial != stage, 'Unexpected output containment') if args.mode=='checkpoint': checkpoint(trial,stage,args.label or '');return cfg,attestation,executable,runtime=admission()