From 7c3394883887a6990b8dfc0d720734faa4800a3f Mon Sep 17 00:00:00 2001 From: Dylan Roy <249851642+d6g8k5htny-coder@users.noreply.github.com> Date: Tue, 6 Oct 2026 04:33:09 -0700 Subject: [PATCH] Authenticate fixed-r verifier negative-control reasons without changing mathematics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dylan Roy — delegated AI engineering. Author OpenAI / GPT-6 Astra Pro, release-integrity-fixed-r-protocol-20261006; issue322 pickup6014890577. Preserve inverse.py, proof, results, sources, all original packet tests, historical pins and all source/inventory functions. Add exact typed failure carriers and ordered mutant inventory guard; accept two complete argparse choice spellings with whitespace normalization. MANIFEST changes only verify.py identity; dedicated workflow adds regression wiring without changing pins or source commands. Actual test-first evidence: original seven-method/92-scenario suite fails by65 intended assertions per Python mode, zero errors. Two portability failures and one wiring failure observed before their fixes. Final nine methods/96 scenarios pass both modes; 16 original plus16 validated genuine checker invocations retain exact outputs. Hosted full historical-source replay and nonauthor review remain required. Scientific effect NONE; no self-merge or independent alignment claim. --- .../workflows/fixed-r-inverse-lifetime.yml | 6 + .../MANIFEST.json | 6 +- .../verify.py | 51 +++- reviews/fixed_r_protocol_20261006/SCOPE.md | 146 ++++++++++++ tests/test_fixed_r_replay_protocol.py | 218 ++++++++++++++++++ 5 files changed, 423 insertions(+), 4 deletions(-) create mode 100644 reviews/fixed_r_protocol_20261006/SCOPE.md create mode 100644 tests/test_fixed_r_replay_protocol.py diff --git a/.github/workflows/fixed-r-inverse-lifetime.yml b/.github/workflows/fixed-r-inverse-lifetime.yml index 92de6cb23..9923679f1 100644 --- a/.github/workflows/fixed-r-inverse-lifetime.yml +++ b/.github/workflows/fixed-r-inverse-lifetime.yml @@ -5,6 +5,7 @@ name: Fixed-r inverse-lifetime checks paths: - 'frontiers/fixed_r_inverse_lifetime_20260930/**' - '.github/workflows/fixed-r-inverse-lifetime.yml' + - 'tests/test_fixed_r_replay_protocol.py' workflow_dispatch: permissions: @@ -26,6 +27,11 @@ jobs: run: | set -euo pipefail git fetch --no-tags origin 7a1cb09a9d58d179393e6d29146252f714b9c9bf + - name: Verify failure-protocol regressions in both Python modes + run: | + set -euo pipefail + python -B -S tests/test_fixed_r_replay_protocol.py + python -B -O -S tests/test_fixed_r_replay_protocol.py - name: Verify source, packet and both Python modes env: PYTHONDONTWRITEBYTECODE: '1' diff --git a/frontiers/fixed_r_inverse_lifetime_20260930/MANIFEST.json b/frontiers/fixed_r_inverse_lifetime_20260930/MANIFEST.json index dd6871344..095d03903 100644 --- a/frontiers/fixed_r_inverse_lifetime_20260930/MANIFEST.json +++ b/frontiers/fixed_r_inverse_lifetime_20260930/MANIFEST.json @@ -59,9 +59,9 @@ }, { "path": "verify.py", - "bytes": 5190, - "sha256": "df2f54f44a95f1dc62022145feed2e22dca242bd37266e1eed82b12e519f6355", - "git_blob": "22db229cfc2be9d3486d7759c82c50bea83b14e0" + "bytes": 7753, + "sha256": "a69914084e999b863a037c4583e18bde531e0080b87af62a5151f651731fd3f5", + "git_blob": "af527e6ceeb402affbd424bc19a546f3c7df3494" } ] } diff --git a/frontiers/fixed_r_inverse_lifetime_20260930/verify.py b/frontiers/fixed_r_inverse_lifetime_20260930/verify.py index 22db229cf..af527e6ce 100644 --- a/frontiers/fixed_r_inverse_lifetime_20260930/verify.py +++ b/frontiers/fixed_r_inverse_lifetime_20260930/verify.py @@ -13,6 +13,53 @@ 'admit-critical-inverse','drop-endpoint-margin','unconditional-tail-shortcut') +# Independent expectations from the unchanged inverse.py CLI, not the child under test. +REJECTIONS = { + 'lose-determinant-weight': 'retain original maximum determinant weight', + 'wrong-cubic-power': 'cubic lifetime scale', + 'wrong-soft-direction': 'correct Schur soft direction', + 'admit-critical-inverse': 'critical inverse moment diverges', + 'drop-endpoint-margin': 'strict endpoint above birth', + 'unconditional-tail-shortcut': 'retain weighted near-zero eigenvalue integral', +} + + +def validate_rejection(result, label): + """Authenticate the entire failure carrier; only argparse wrapping is normalized.""" + if label not in (*REJECTIONS, 'unknown'): + raise ValueError('unknown rejection stage') + if type(result.returncode) is not int or result.returncode != (2 if label=='unknown' else 1): + raise ValueError('wrong rejection exit: '+label) + if not isinstance(result.stdout,bytes) or not isinstance(result.stderr,bytes): + raise ValueError('binary process captures required') + if label=='unknown': + usage='usage: inverse.py [-h] [--mutant {' + ','.join(REJECTIONS) + '}]\n' + prefix="inverse.py: error: argument --mutant: invalid choice: 'unknown' (choose from " + # Python 3.11 quotes choices; 3.13 displays these string choices without quotes. + # Both complete forms preserve every label, its order, the argument and the reason. + expected=[(usage+prefix+choices+')\n').encode('ascii').split() for choices in + (', '.join(REJECTIONS), ', '.join(repr(key) for key in REJECTIONS))] + if result.stdout or result.stderr.split() not in expected: + raise ValueError('wrong unknown-label diagnostic') + return + if result.stderr: + raise ValueError('unexpected mutant stderr: '+label) + def unique(pairs): + out={} + for key,value in pairs: + if key in out:raise ValueError('duplicate mutant JSON key') + out[key]=value + return out + def finite_only(value): + raise ValueError('nonfinite mutant JSON constant: '+value) + report=json.loads(result.stdout.decode('utf-8'), + object_pairs_hook=unique,parse_constant=finite_only) + if (type(report) is not dict or set(report)!={'passed','error'} + or type(report['passed']) is not bool or report['passed'] is not False + or type(report['error']) is not str or report['error']!=REJECTIONS[label]): + raise ValueError('wrong complete mutant report: '+label) + + def read_json(path): if path.is_symlink() or not path.is_file():raise ValueError('regular JSON required') def unique(pairs): @@ -92,6 +139,8 @@ def inventory(root): def main(): ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('--local-only',action='store_true');args=ap.parse_args() + if MUTANTS!=tuple(REJECTIONS): + raise ValueError('complete ordered mutant inventory required') root=Path(__file__).absolute().parent;inventory(root) ns=0 if args.local_only else sources(root) expected=(root/'RESULTS.json').read_bytes() @@ -102,7 +151,7 @@ def main(): if run.stdout!=expected or run.stderr:raise ValueError('baseline replay mismatch') for m in (*MUTANTS,'unknown'): run=subprocess.run(command+['--mutant',m],capture_output=True,timeout=45) - if run.returncode!=(2 if m=='unknown' else 1):raise ValueError('mutant not rejected: '+m) + validate_rejection(run,m) inventory(root) print(json.dumps({'passed':True,'source_count':ns,'source_pins_checked':not args.local_only, 'mathematical_acceptance':False,'scientific_effect':'NONE'},sort_keys=True)) diff --git a/reviews/fixed_r_protocol_20261006/SCOPE.md b/reviews/fixed_r_protocol_20261006/SCOPE.md new file mode 100644 index 000000000..31d04c4c5 --- /dev/null +++ b/reviews/fixed_r_protocol_20261006/SCOPE.md @@ -0,0 +1,146 @@ +# Fixed-r inverse-lifetime replay: authenticate negative-control reasons + +Dylan Roy — delegated AI engineering. Author: OpenAI / GPT-6 Astra Pro, +`release-integrity-fixed-r-protocol-20261006`; issue322 pickup6014890577. +Scientific effect NONE. Author checks are not nonauthor review or mathematical +acceptance. This is one additional execution-contract repair, not closure of +the entire legacy-wrapper class or of any theorem. + +## Original source and defect + +The source was read at `98c8fb0c626314f95a08145af61a284482af5f87`. +The complete verifier is blob `22db229cfc2be9d3486d7759c82c50bea83b14e0` +(5190 bytes); inverse.py is `62698d649ff1eba92656fb555bf57d603f2bbc37` +(6501 bytes); manifest is `dd68713445e08f113f6e93fb54372b691486bab8`. +The baseline is exactly 516 bytes, SHA256 +`46ccc0f5e2d8cba11040ca1bc617e9e99e54ca7b19ac85ff4091e2601104efeb`. + +The original verifier checks baseline bytes and stderr, authenticates a full +packet manifest and historical Git sources, and runs both interpreter modes. +However, its six named mutants are credited solely for exit1, and the unknown +label solely for exit2. Unrelated errors can therefore be accepted as intended +negative controls. This is an execution-protocol defect, not a counterexample +to the fixed-separation inverse-lifetime theorem. + +## Small bounded change + +Only verify.py's main function changes among its existing function bodies. +A fixed independent six-label/reason map and validate_rejection are added. +The complete ordered mutant tuple must equal the independent map before any +child execution. Each named negative result must have exit1, empty binary +stderr, and exactly the two JSON fields `error` and Boolean `passed:false`, +with the exact expected reason. Duplicate keys, invalid UTF-8/JSON, extra or +missing fields, nonfinite constants, false/int/null confusion and trailing +objects are rejected. JSON whitespace and key ordering remain immaterial. + +The unknown-label result requires exit2 and empty stdout. The entire usage and +error diagnostic is matched after ASCII-whitespace normalization. Exactly two +choice-list spellings are supported: Python3.11's quoted labels and Python3.13's +unquoted labels. Both retain every label, its order, the option, invalid value, +and reason. Arbitrary diagnostic text, changed choices or extra stdout/stderr +is not accepted. No extra production subprocess learns expected child output. + +Baseline matching, original 45-second child and Git budgets, 120-second unit +suite budget, source/inventory functions, historical parent pins and final +inventory check are unchanged. Exceptions still abort execution. MANIFEST.json +changes only the three identity fields for verify.py; every other entry and +the historical NONAUTHOR_REVIEW_OPEN field remain unchanged. + +The existing dedicated workflow adds one path trigger and invokes the new root +test file in both modes. Its action pins, Python3.11.16 pin, read-only +permissions, complete-history checkout, exact parent fetch, original genuine +verification command and final clean Git check remain byte-preserved. +No scientific proof, inverse.py, RESULTS.json, SOURCES.json, old packet test, +formal source, dependency pin, scientific register or other workflow is edited. + +## Actual test-first evidence + +Local runtime: CPython3.13.5 / Git2.47.3 on Linux, standard library only. +Complete original inverse.py bytes were authenticated before execution. +Sixteen genuine native invocations (baseline, six mutants, unknown; both modes) +produced eight byte-identical stdout/stderr pairs and the native baseline hash. +A further sixteen genuine invocations passed the repaired validator's contracts; +the scientific checker itself remained unchanged. + +The initial seven-method suite has 92 independent full-verifier scenarios. +Against the exact original verifier it completed in BOTH outer Python modes +with 65 intended assertion failures, zero test errors. It exposes wrong-reason +admission, not merely missing implementation. Complete raw logs and per-case +child sequences are retained in the requester delivery. + +The initial repair passed those same 92 scenarios per mode. Before publication, +official pinned3.11 argparse source exposed its quoted-choice spelling. A new +four-scenario compatibility method failed the first repair by two intended +assertions, then passed after accepting the two complete fixed diagnostic +forms. A separate workflow-wiring test failed the original YAML by one intended +assertion before the trigger and regression commands were added. + +Final frozen tests: NINE methods, 96 unique full-verifier scenarios in EACH +normal and optimized outer mode, all expected outcomes correct: seven valid +or harmless-formatting admissions and 89 rejections, with 772 checker children +per mode. Each verifier itself runs normal and optimized child stages until +the specified failure; stopping prefixes and unit-suite invocations are checked. +The tests use actual disposable Git histories, full source/inventory guards, +real test discovery and real checker child processes. Four workers use disjoint +temporary roots; no subprocess is mocked. They do not replace the scientific +checker with a fake and then claim a genuine mathematical replay: the full +verifier scenarios are explicitly synthetic execution-contract fixtures. + +Synthetic fixture commits have command-local maintenance and signing disabled; +system/global Git config is excluded only from those child environments. No +persistent real repository or user settings change. Original packet tests are +left intact, including their existing Git-fixture behavior. + +Some early sequential/parallel whole-suite invocations were interrupted by the +tool command envelope near30seconds despite longer requested outer limits. +Their partial logs have no completed verdict and are excluded. The completed +original and final runs described above retained all selected cases. An initial +file-ownership error before a Python retry launched no test; it is not a test +failure or a pass. No assertion was removed to resolve either tooling issue. + +## Scope of assurance and required next step + +These local executions use authenticated selected source, not a complete +repository checkout or the genuine historical parent proof. The complete +source-bound packet replay and its old tests must actually execute in the +dedicated hosted workflow at the pinned runtime. General/required checks and +all other path-triggered jobs must also pass at their exact tested candidate. +No local Lean execution or new independent mathematical alignment is claimed. + +An actual bounded nonauthor engineering review must check the carrier contract, +complete inventory, genuine outputs, both diagnostic spellings, unchanged old +source/test/pin boundaries and meaningful predecessor failures. Then a separate +eligible nonauthor/nonreader integrator must reconcile live refs, current +findings and all applicable execution before ordinary expected-head merge, +followed by landed/push readback. No author self-merge or old-receipt rebinding. + +This does not make a hostile executable safe, prove that an arbitrary program +failed internally at the advertised assertion, limit captured output memory, +supply durable timeout logs or eliminate every ambient Git configuration issue. +A malicious child can intentionally print an expected diagnostic. Source +identity and trusted execution remain separate boundaries. + +## Reproduce + +From an exact checkout: + +```sh +python -B -S tests/test_fixed_r_replay_protocol.py +python -B -O -S tests/test_fixed_r_replay_protocol.py +python -B -S frontiers/fixed_r_inverse_lifetime_20260930/verify.py +``` + +The last command requires the unchanged exact historical Git parent. Do not +silently substitute --local-only and call it a historical-source replay. + +## Primary references inspected + +- Python3.11 json: object_pairs_hook and parse_constant, + https://docs.python.org/3.11/library/json.html +- Python3.11 argparse error exit/usage contract, + https://docs.python.org/3.11/library/argparse.html +- Exact pinned argparse choice rendering, `_check_value`, + https://github.com/python/cpython/blob/v3.11.16/Lib/argparse.py + +These explain library behavior; the actual unchanged checker outputs and +source-bound tests establish this packet's expected diagnostics. diff --git a/tests/test_fixed_r_replay_protocol.py b/tests/test_fixed_r_replay_protocol.py new file mode 100644 index 000000000..bf9d75ed7 --- /dev/null +++ b/tests/test_fixed_r_replay_protocol.py @@ -0,0 +1,218 @@ +"""Real-process contract regressions; synthetic packets are not mathematical evidence.""" +import ast +from concurrent.futures import ThreadPoolExecutor +import hashlib +import json +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import unittest + +ROOT = Path(__file__).resolve().parents[1] +VERIFY = ROOT / 'frontiers/fixed_r_inverse_lifetime_20260930/verify.py' +MUTANTS = ( + 'lose-determinant-weight', 'wrong-cubic-power', 'wrong-soft-direction', + 'admit-critical-inverse', 'drop-endpoint-margin', 'unconditional-tail-shortcut', +) +REASONS = ( + 'retain original maximum determinant weight', 'cubic lifetime scale', + 'correct Schur soft direction', 'critical inverse moment diverges', + 'strict endpoint above birth', 'retain weighted near-zero eigenvalue integral', +) +UNKNOWN = ( + 'usage: inverse.py [-h] [--mutant {' + ','.join(MUTANTS) + '}]\n' + "inverse.py: error: argument --mutant: invalid choice: 'unknown' (choose from " + + ', '.join(MUTANTS) + ')\n' +).encode() +STAGES = [(mode, label) for mode in ('normal', 'optimized') + for label in ('baseline', *MUTANTS, 'unknown')] +RECORDS = [] # In-process inspection only; no audit files written in the checkout. + + +def entry(path, data, **extra): + return dict(path=path, bytes=len(data), sha256=hashlib.sha256(data).hexdigest(), + git_blob=hashlib.sha1(b'blob ' + str(len(data)).encode() + b'\0' + data).hexdigest(), + **extra) + + +CHECKER = r''' +import json,sys +from pathlib import Path +mode='optimized' if sys.flags.optimize else 'normal' +label='baseline' if len(sys.argv)==1 else sys.argv[2] +trace=Path(__file__).parent.parent/'children.jsonl' +with trace.open('a') as f:f.write(json.dumps([mode,label])+'\n') +exitcode=0 if label=='baseline' else 2 if label=='unknown' else 1 +out=b'{"fixture":true}\n' if label=='baseline' else b'' +err=UNKNOWN if label=='unknown' else b'' +if label in MUTANTS: + out=json.dumps({'error':REASONS[MUTANTS.index(label)],'passed':False}).encode()+b'\n' +if (mode,label)==TARGET: + if CASE=='crash':raise RuntimeError('synthetic unrelated crash') + if CASE=='silent':out=err=b'' + if CASE=='wrong-reason':out=b'{"error":"other failure","passed":false}\n' + if CASE=='extra-key':out=out.rstrip()[:-1]+b',"extra":true}\n' + if CASE=='passed-int':out=out.replace(b'false',b'0') + if CASE=='passed-null':out=out.replace(b'false',b'null') + if CASE=='passed-true':out=out.replace(b'false',b'true') + if CASE=='duplicate-key':out=out.rstrip()[:-1]+b',"passed":false}\n' + if CASE=='nan':out=out.rstrip()[:-1]+b',"extra":NaN}\n' + if CASE=='trailing':out+=b'{}' + if CASE=='stderr':err+=b'unexpected stderr\n' + if CASE=='wrong-exit':exitcode=0 if label!='baseline' else 1 + if CASE=='wrong-exit-two':exitcode=2 + if CASE=='unknown-reason':err=b'inverse.py: error: unrelated failure\n' + if CASE=='unknown-stdout':out=b'unexpected stdout\n' + if CASE=='unknown-extra':err+=b'additional diagnostic\n' + if CASE=='unknown-choices':err=err.replace(b'wrong-cubic-power',b'other-choice') + if CASE=='unknown-wrapping':err=b' \n '.join(err.split())+b'\n' + if CASE in ('unknown-quoted','unknown-quoted-wrong'): + err=err.replace((', '.join(MUTANTS)).encode(),(', '.join(repr(s) for s in MUTANTS)).encode()) + if CASE=='unknown-quoted-wrong':err=err.replace(b'wrong-cubic-power',b'other-choice') + if CASE=='json-format':out=json.dumps(json.loads(out),sort_keys=True,indent=3).encode()+b'\n' + if CASE=='baseline-changed':out=b'{"fixture":false}\n' + if CASE=='dirty-end':(Path(__file__).parent/'extra').write_text('not in manifest') +sys.stdout.buffer.write(out);sys.stderr.buffer.write(err);raise SystemExit(exitcode) +''' +SUITE = r''' +import sys,unittest +from pathlib import Path +class Probe(unittest.TestCase): + def test_live_suite(self): + with (Path(__file__).parent.parent/'suites.txt').open('a') as f: + f.write(('optimized' if sys.flags.optimize else 'normal')+'\n') + self.assertFalse(FAIL_SUITE,'intended synthetic test-suite failure') +''' + + +def run_case(case='valid', mode='normal', label='baseline', guard=None, inventory=None): + """Run the complete verifier, including real historical Git reads and source guards.""" + with tempfile.TemporaryDirectory(prefix='fixed-r-protocol-') as td: + repo=Path(td); packet=repo/'packet'; packet.mkdir() + env={k:v for k,v in os.environ.items() if not k.startswith('GIT_')} + env.update(GIT_CONFIG_NOSYSTEM='1', GIT_CONFIG_GLOBAL=os.devnull, + PYTHONDONTWRITEBYTECODE='1', LC_ALL='C.UTF-8') + def git(*args): + return subprocess.run(['git','-c','user.name=Fixture', + '-c','user.email=fixture@example.invalid','-c','maintenance.auto=false', + '-c','commit.gpgsign=false',*args],cwd=repo,env=env, + capture_output=True,check=True,timeout=15).stdout + git('init','-q'); parent=b'synthetic historical model\n' + (repo/'P.md').write_bytes(parent);git('add','P.md');git('commit','-qm','synthetic parent') + sha=git('rev-parse','HEAD').decode().strip() + source=entry('P.md',parent,id='P',commit=sha) + if guard=='source-hash':source['sha256']='0'*64 + if guard=='source-path':source['path']='../P.md' + if guard=='source-noncommit':source['commit']=git('rev-parse','HEAD^{tree}').decode().strip() + es=[] if guard=='source-empty' else [source] + text=VERIFY.read_text() + if inventory is not None: + tree=ast.parse(text) + node=next(n for n in tree.body if isinstance(n,ast.Assign) + and any(isinstance(t,ast.Name) and t.id=='MUTANTS' for t in n.targets)) + lines=text.splitlines(keepends=True) + text=''.join(lines[:node.lineno-1])+f'MUTANTS={inventory!r}\n'+''.join(lines[node.end_lineno:]) + (packet/'verify.py').write_text(text) + header=f'MUTANTS={MUTANTS!r}\nREASONS={REASONS!r}\nUNKNOWN={UNKNOWN!r}\nTARGET={(mode,label)!r}\nCASE={case!r}\n' + (packet/'inverse.py').write_text(header+CHECKER) + (packet/'test_fixture.py').write_text(f'FAIL_SUITE={guard=="suite-fail"!r}\n'+SUITE) + (packet/'RESULTS.json').write_bytes(b'{"fixture":true}\n') + (packet/'SOURCES.json').write_text(json.dumps({'sources':es})) + manifest={'files':[entry(p.name,p.read_bytes()) for p in sorted(packet.iterdir())]} + (packet/'MANIFEST.json').write_text(json.dumps(manifest)) + if guard=='payload-change':(packet/'inverse.py').write_text('changed') + if guard=='packet-extra':(packet/'extra').write_text('extra') + if guard=='packet-duplicate': + manifest['files'].append(manifest['files'][0]);(packet/'MANIFEST.json').write_text(json.dumps(manifest)) + if guard=='manifest-duplicate-key':(packet/'MANIFEST.json').write_text('{"files":[],"files":[]}') + flags=['-B','-S']+(['-O'] if sys.flags.optimize else []) + proc=subprocess.run([sys.executable,*flags,str(packet/'verify.py')],cwd=repo, + env=env,capture_output=True,timeout=30) + trace=repo/'children.jsonl'; suites=repo/'suites.txt' + seen=[tuple(json.loads(s)) for s in trace.read_text().splitlines()] if trace.exists() else [] + suite_seen=suites.read_text().splitlines() if suites.exists() else [] + RECORDS.append({'case':case,'target':[mode,label],'guard':guard, + 'inventory':inventory,'returncode':proc.returncode,'children':seen,'suites':suite_seen, + 'stdout':proc.stdout.decode(errors='backslashreplace'), + 'stderr':proc.stderr.decode(errors='backslashreplace')}) + return proc,seen,suite_seen + + +class FixedRProtocolTests(unittest.TestCase): + def check_many(self, cases): + # Independent disposable roots; assertions are reported by the parent thread. + cases=list(cases) + with ThreadPoolExecutor(max_workers=4) as pool: + jobs=[pool.submit(self.assert_case,*case) for case in cases] + for case,job in zip(cases,jobs): + with self.subTest(case=case):job.result() + + def assert_case(self,case,mode,label,accepted=False): + proc,seen,suites=run_case(case,mode,label) + want=STAGES if accepted or case=='dirty-end' else STAGES[:STAGES.index((mode,label))+1] + if accepted: + self.assertEqual(proc.returncode,0,proc.stderr.decode()) + record=json.loads(proc.stdout) + self.assertIs(record['passed'],True);self.assertEqual(record['source_count'],1) + self.assertIs(record['source_pins_checked'],True) + self.assertIs(record['mathematical_acceptance'],False) + else:self.assertNotEqual(proc.returncode,0,'unrelated/invalid child response was admitted') + self.assertEqual(seen,want,'verifier must stop at the actual failing stage') + self.assertEqual(suites,['normal'] if len(want)<=8 else ['normal','optimized']) + + def test_dedicated_workflow_wiring(self): + text=(ROOT/'.github/workflows/fixed-r-inverse-lifetime.yml').read_text() + self.assertIn(" - 'tests/test_fixed_r_replay_protocol.py'",text) + for flags in ('-B -S','-B -O -S'): + self.assertIn('python '+flags+' tests/test_fixed_r_replay_protocol.py',text) + self.assertIn('python -B -S frontiers/fixed_r_inverse_lifetime_20260930/verify.py',text) + self.assertIn('git fetch --no-tags origin 7a1cb09a9d58d179393e6d29146252f714b9c9bf',text) + + def test_valid_and_formatting(self): + self.assert_case('valid','normal','baseline',True) + for mode in ('normal','optimized'): + self.assert_case('json-format',mode,MUTANTS[0],True) + self.assert_case('unknown-wrapping',mode,'unknown',True) + + def test_every_mutant_rejects_unrelated_failure(self): + self.check_many((case,mode,label) for mode in ('normal','optimized') + for label in MUTANTS for case in ('crash','silent','wrong-reason')) + + def test_strict_complete_json_and_exit(self): + self.check_many((case,mode,MUTANTS[1]) for mode in ('normal','optimized') + for case in ('extra-key','passed-int','passed-null','passed-true','duplicate-key', + 'nan','trailing','stderr','wrong-exit','wrong-exit-two')) + + def test_unknown_contract(self): + self.check_many((case,mode,'unknown') for mode in ('normal','optimized') + for case in ('silent','unknown-reason','unknown-stdout','unknown-extra','unknown-choices','wrong-exit')) + + def test_pinned_and_local_argparse_forms(self): + self.check_many((case,mode,'unknown',case=='unknown-quoted') + for mode in ('normal','optimized') for case in ('unknown-quoted','unknown-quoted-wrong')) + + def test_baseline_and_final_inventory(self): + for mode in ('normal','optimized'): + for case in ('stderr','baseline-changed','wrong-exit'): + with self.subTest(mode=mode,case=case):self.assert_case(case,mode,'baseline') + self.assert_case('dirty-end','optimized','unknown') + + def test_preflight_source_guards_and_suite_failure(self): + for guard in ('source-hash','source-path','source-noncommit','source-empty','payload-change', + 'packet-extra','packet-duplicate','manifest-duplicate-key','suite-fail'): + with self.subTest(guard=guard): + proc,seen,suites=run_case(guard=guard) + self.assertNotEqual(proc.returncode,0);self.assertEqual(seen,[]) + self.assertEqual(suites,['normal'] if guard=='suite-fail' else []) + + def test_mutant_inventory_is_complete_before_execution(self): + for inv in (MUTANTS[1:],MUTANTS+(MUTANTS[0],),tuple(reversed(MUTANTS))): + with self.subTest(inventory=inv): + proc,seen,suites=run_case(inventory=inv) + self.assertNotEqual(proc.returncode,0,'incomplete/duplicated/reordered inventory admitted') + self.assertEqual(seen,[]);self.assertEqual(suites,[]) + + +if __name__=='__main__':unittest.main()