From ed88a03f51194a17b465c1d3e4a4417e6c31e869 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 26 Oct 2026 22:47:47 +0000 Subject: [PATCH 1/2] Authenticate the SIDE24 d = 5, 6 wrappers' mutant rejections The three wrappers accepted each mutant on exit status 1 alone (status_only in 01Cz's ledger, Math-#322). A shared helper now replays the fixed inventory in both modes and requires, for every child, the exact exit status, exactly one timing line on stderr, and the report measured from the unchanged checker (or, for the two vandermonde mutants that raise the checker's own structural guard, that exact exception). Baseline stdout still equals RESULTS.json. No packet file changes. Adds tools/side24_mutant_replay.py, per-family references in tools/side24_mutant_contracts/, a whole-shell regression test run by each wrapper in both modes, and reviews/side24_mutant_wrappers_20261026/SCOPE.md. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017Mi3hxjaxV45x6zo6o1ee3 --- .github/workflows/side24-d5-closed-form.yml | 40 +- .github/workflows/side24-d5-coefficient.yml | 36 +- .github/workflows/side24-d6-coefficient.yml | 36 +- .../side24_mutant_wrappers_20261026/SCOPE.md | 176 +++++++++ tests/test_side24_mutant_workflows.py | 361 ++++++++++++++++++ .../side24-d5-closed-form.json | 1 + .../side24-d5-coefficient.json | 1 + .../side24-d6-coefficient.json | 1 + tools/side24_mutant_replay.py | 166 ++++++++ 9 files changed, 762 insertions(+), 56 deletions(-) create mode 100644 reviews/side24_mutant_wrappers_20261026/SCOPE.md create mode 100644 tests/test_side24_mutant_workflows.py create mode 100644 tools/side24_mutant_contracts/side24-d5-closed-form.json create mode 100644 tools/side24_mutant_contracts/side24-d5-coefficient.json create mode 100644 tools/side24_mutant_contracts/side24-d6-coefficient.json create mode 100644 tools/side24_mutant_replay.py diff --git a/.github/workflows/side24-d5-closed-form.yml b/.github/workflows/side24-d5-closed-form.yml index 7c3989295..e438b0f8e 100644 --- a/.github/workflows/side24-d5-closed-form.yml +++ b/.github/workflows/side24-d5-closed-form.yml @@ -5,6 +5,10 @@ name: SIDE24 d5 closed form paths: - 'coefficients/side24_d5_closed_form_20260930/**' - '.github/workflows/side24-d5-closed-form.yml' + - 'tools/**' + - 'tools.py' + - 'tests/test_side24_mutant_workflows.py' + - 'tests/test_legacy_workflow_triggers.py' - 'imports/lifetime_parent_20260925/UNIFORM_MATRIX_CAP_AND_LIFETIME.md' - 'coefficients/side24_v1/PROOF.md' workflow_dispatch: @@ -23,6 +27,13 @@ jobs: - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 with: python-version: '3.11.16' + - name: Check trigger coverage and the SIDE24 replay contract in both modes + env: + SIDE24_MUTANT_TEST_FAMILY: 'side24-d5-closed-form' + PYTHONDONTWRITEBYTECODE: '1' + run: | + python -B -S tests/test_side24_mutant_workflows.py + python -B -O -S tests/test_side24_mutant_workflows.py - name: Verify sources and pins, replay both modes, reject mutants env: PYTHONDONTWRITEBYTECODE: '1' @@ -54,27 +65,16 @@ jobs: blob = hashlib.sha1(b'blob %d\0' % len(data) + data).hexdigest() if blob != pin['git_blob']: raise ValueError('pinned source drifted: ' + pin['path'] + ' ' + blob) - script = str(root / 'closed_form_d4.py') expected = (root / 'RESULTS.json').read_bytes() - mutants = ['shift-variance', 'vandermonde', 'erfc-sign', 'jacobian', 'mehta', 'by-parts', 'one-erf', 'two-erf', 'jk-init', 'gauss-half', 'boundary-term', 'atom-pi', 'cumulative-init', 'cumulative-recurrence'] - def mutant_rc(args): - flags, m = args - return m, flags, subprocess.run([sys.executable, *flags, script, '--mutant', m], - capture_output=True, timeout=600).returncode - for flags in (['-B', '-S'], ['-B', '-O', '-S']): - out = subprocess.run([sys.executable, *flags, script], - check=True, capture_output=True, timeout=600).stdout - if out != expected: - raise RuntimeError('output differs from RESULTS.json under ' + ' '.join(flags)) - doc = json.loads(out) - if not (doc['passed'] and len(doc['checks']) == 16 and all(doc['checks'].values())): - raise RuntimeError('certification did not pass under ' + ' '.join(flags)) - if doc['closed_forms']['D_4'] != '6695/54 + -405/32 sqrt(6) + -1375/72 sqrt(21) pi^(-1) + -405/16 sqrt(6) pi^(-1) arctan(1/4 sqrt(14)) + -6695/27 pi^(-1) arctan(1/7 sqrt(21)) + 405/16 sqrt(6) pi^(-1) arctan(1/7 sqrt(14))' or doc['closed_forms']['Z_4'] != '1536 pi^(1)': - raise RuntimeError('closed form differs from the stated one') - with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool: - for m, fl, rc in pool.map(mutant_rc, [(flags, m) for m in mutants]): - if rc != 1: - raise RuntimeError('mutant ' + m + ' not rejected under ' + ' '.join(fl)) + doc = json.loads(expected) + if not (doc['passed'] and len(doc['checks']) == 16 and all(doc['checks'].values())): + raise RuntimeError('RESULTS.json is not a passing certification') + if doc['closed_forms']['D_4'] != '6695/54 + -405/32 sqrt(6) + -1375/72 sqrt(21) pi^(-1) + -405/16 sqrt(6) pi^(-1) arctan(1/4 sqrt(14)) + -6695/27 pi^(-1) arctan(1/7 sqrt(21)) + 405/16 sqrt(6) pi^(-1) arctan(1/7 sqrt(14))' or doc['closed_forms']['Z_4'] != '1536 pi^(1)': + raise RuntimeError('closed form differs from the stated one') + # Every child: exact exit status, one timing line on stderr, baseline stdout equal + # to RESULTS.json, each mutant's report equal to the measured one (both modes). + from tools.side24_mutant_replay import replay + replay('side24-d5-closed-form', pathlib.Path.cwd(), timeout=600) print(json.dumps({'scientific_effect': 'NONE', 'mathematical_acceptance': False, 'exact_identity_checked': True, 'side24_v1': 'unchanged'})) PY git diff --exit-code diff --git a/.github/workflows/side24-d5-coefficient.yml b/.github/workflows/side24-d5-coefficient.yml index 9f46fffa4..2c50da0ab 100644 --- a/.github/workflows/side24-d5-coefficient.yml +++ b/.github/workflows/side24-d5-coefficient.yml @@ -5,6 +5,10 @@ name: SIDE24 d5 coefficient paths: - 'coefficients/side24_d5_20260930/**' - '.github/workflows/side24-d5-coefficient.yml' + - 'tools/**' + - 'tools.py' + - 'tests/test_side24_mutant_workflows.py' + - 'tests/test_legacy_workflow_triggers.py' - 'imports/lifetime_parent_20260925/UNIFORM_MATRIX_CAP_AND_LIFETIME.md' - 'coefficients/side24_v1/PROOF.md' - 'coefficients/side24_v1/ENCLOSURE.json' @@ -24,6 +28,13 @@ jobs: - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 with: python-version: '3.11.16' + - name: Check trigger coverage and the SIDE24 replay contract in both modes + env: + SIDE24_MUTANT_TEST_FAMILY: 'side24-d5-coefficient' + PYTHONDONTWRITEBYTECODE: '1' + run: | + python -B -S tests/test_side24_mutant_workflows.py + python -B -O -S tests/test_side24_mutant_workflows.py - name: Verify sources and pins, replay both modes, reject mutants env: PYTHONDONTWRITEBYTECODE: '1' @@ -61,25 +72,14 @@ jobs: for d in ('2', '3'): if ('"%s", "%s"' % (enc[d]['lower'], enc[d]['upper'])) not in src: raise ValueError('SIDE24 d = ' + d + ' enclosure quoted in the script differs from ENCLOSURE.json') - script = str(root / 'cone_moment_d5.py') expected = (root / 'RESULTS.json').read_bytes() - mutants = ['shift-variance', 'vandermonde', 'erfc-branch', 'remainder-dropped', 'mehta', 'sphere-area', 'image-shells', 'sandwich-exponent', 'recurrence', 'jacobian', 'cumulative-half'] - def mutant_rc(args): - flags, m = args - return m, flags, subprocess.run([sys.executable, *flags, script, '--mutant', m], - capture_output=True, timeout=1500).returncode - for flags in (['-B', '-S'], ['-B', '-O', '-S']): - out = subprocess.run([sys.executable, *flags, script], - check=True, capture_output=True, timeout=1500).stdout - if out != expected: - raise RuntimeError('output differs from RESULTS.json under ' + ' '.join(flags)) - doc = json.loads(out) - if not (doc['passed'] and len(doc['checks']) == 13 and all(doc['checks'].values())): - raise RuntimeError('certification did not pass under ' + ' '.join(flags)) - with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool: - for m, fl, rc in pool.map(mutant_rc, [(flags, m) for m in mutants]): - if rc != 1: - raise RuntimeError('mutant ' + m + ' not rejected under ' + ' '.join(fl)) + doc = json.loads(expected) + if not (doc['passed'] and len(doc['checks']) == 13 and all(doc['checks'].values())): + raise RuntimeError('RESULTS.json is not a passing certification') + # Every child: exact exit status, one timing line on stderr, baseline stdout equal + # to RESULTS.json, each mutant's report equal to the measured one (both modes). + from tools.side24_mutant_replay import replay + replay('side24-d5-coefficient', pathlib.Path.cwd(), timeout=1500) print(json.dumps({'scientific_effect': 'NONE', 'mathematical_acceptance': False, 'certified_enclosures': True, 'side24_v1': 'unchanged'})) PY git diff --exit-code diff --git a/.github/workflows/side24-d6-coefficient.yml b/.github/workflows/side24-d6-coefficient.yml index 6059c2ecd..7a851d9a4 100644 --- a/.github/workflows/side24-d6-coefficient.yml +++ b/.github/workflows/side24-d6-coefficient.yml @@ -5,6 +5,10 @@ name: SIDE24 d6 coefficient paths: - 'coefficients/side24_d6_20260930/**' - '.github/workflows/side24-d6-coefficient.yml' + - 'tools/**' + - 'tools.py' + - 'tests/test_side24_mutant_workflows.py' + - 'tests/test_legacy_workflow_triggers.py' - 'imports/lifetime_parent_20260925/UNIFORM_MATRIX_CAP_AND_LIFETIME.md' - 'coefficients/side24_v1/PROOF.md' - 'coefficients/side24_v1/ENCLOSURE.json' @@ -24,6 +28,13 @@ jobs: - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 with: python-version: '3.11.16' + - name: Check trigger coverage and the SIDE24 replay contract in both modes + env: + SIDE24_MUTANT_TEST_FAMILY: 'side24-d6-coefficient' + PYTHONDONTWRITEBYTECODE: '1' + run: | + python -B -S tests/test_side24_mutant_workflows.py + python -B -O -S tests/test_side24_mutant_workflows.py - name: Verify sources and pins, replay both modes, reject mutants env: PYTHONDONTWRITEBYTECODE: '1' @@ -61,25 +72,14 @@ jobs: for d in ('2', '3'): if ('"%s", "%s"' % (enc[d]['lower'], enc[d]['upper'])) not in src: raise ValueError('SIDE24 d = ' + d + ' enclosure quoted in the script differs from ENCLOSURE.json') - script = str(root / 'cone_moment_d6.py') expected = (root / 'RESULTS.json').read_bytes() - mutants = ['shift-variance', 'vandermonde', 'erfc-branch', 'jacobian', 'mehta', 'recurrence', 'layer-init', 'two-erf', 'cumulative-half', 'remainder-dropped', 'erf-inside', 'tail-dropped', 'image-shells', 'sandwich-exponent'] - def mutant_rc(args): - flags, m = args - return m, flags, subprocess.run([sys.executable, *flags, script, '--mutant', m], - capture_output=True, timeout=3000).returncode - for flags in (['-B', '-S'], ['-B', '-O', '-S']): - out = subprocess.run([sys.executable, *flags, script], - check=True, capture_output=True, timeout=3000).stdout - if out != expected: - raise RuntimeError('output differs from RESULTS.json under ' + ' '.join(flags)) - doc = json.loads(out) - if not (doc['passed'] and len(doc['checks']) == 20 and all(doc['checks'].values())): - raise RuntimeError('certification did not pass under ' + ' '.join(flags)) - with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool: - for m, fl, rc in pool.map(mutant_rc, [(flags, m) for m in mutants]): - if rc != 1: - raise RuntimeError('mutant ' + m + ' not rejected under ' + ' '.join(fl)) + doc = json.loads(expected) + if not (doc['passed'] and len(doc['checks']) == 20 and all(doc['checks'].values())): + raise RuntimeError('RESULTS.json is not a passing certification') + # Every child: exact exit status, one timing line on stderr, baseline stdout equal + # to RESULTS.json, each mutant's report equal to the measured one (both modes). + from tools.side24_mutant_replay import replay + replay('side24-d6-coefficient', pathlib.Path.cwd(), timeout=3000) print(json.dumps({'scientific_effect': 'NONE', 'mathematical_acceptance': False, 'certified_enclosures': True, 'side24_v1': 'unchanged'})) PY git diff --exit-code diff --git a/reviews/side24_mutant_wrappers_20261026/SCOPE.md b/reviews/side24_mutant_wrappers_20261026/SCOPE.md new file mode 100644 index 000000000..e842dacb3 --- /dev/null +++ b/reviews/side24_mutant_wrappers_20261026/SCOPE.md @@ -0,0 +1,176 @@ +# SIDE24 d = 5, 6 mutant wrappers: authenticate the intended rejections + +Dylan Roy — delegated AI engineering. Actual author: Anthropic Claude, session +`session_017Mi3hxjaxV45x6zo6o1ee3` (Claude017), stage +`SIDE24-WRAPPERS-REPAIR-017-20261026`, pickup Math-#322/6427944196. Dylan approved +this stage in the author's session at about 21:30Z on 26 October 2026. This session +wrote the three packets. Scientific effect NONE; shared-account organizational +credit 0. Author-side implementation only: a separate nonauthor engineering review +and a separate integrator are required. No mathematical acceptance is asserted. + +The method is the one C8 used for its own wrappers in #518/#519 +(`reviews/c8_check_mode_wrappers_20261026/SCOPE.md`). The helper, references and +test are new, separate files, and C8's `tools/check_mode_*` and +`tests/test_check_mode_workflows.py` are untouched. + +## Finding and exact source + +01Cz's ledger (Math-#322/6388271177) classifies all three wrappers as +`status_only`. Each mutant was accepted on exit status 1 alone, with its stdout and +stderr discarded. So an unrelated crash, a silent exit 1, or a report that fails +for another reason counted as an intended rejection. The baseline was already +compared byte for byte with `RESULTS.json`, but its stderr was discarded. + +| Object | Identity | +|---|---| +| Math- `main` at characterization and branch base | `7d63d08f6cfadfd9c2ef28039a370d741126f9a0` (the merge of #519) | +| `side24-d5-closed-form.yml` before | blob `7c39892950068e1e7f9c9e0f4c1897cfbdfb3a30` | +| `side24-d5-coefficient.yml` before | blob `9f46fffa48b4162356bbe269e54f68602deef1c6` | +| `side24-d6-coefficient.yml` before | blob `6059c2ecde9e7edf4fda1efeece3ce964483e322` | +| `closed_form_d4.py` (unchanged) | blob `e087f4c0007ae2473d28230771588da57f794aab`, 45,019 B | +| `cone_moment_d5.py` (unchanged) | blob `9d918805865031c8ef9ae5d4d0c3266e1a396a98`, 46,082 B | +| `cone_moment_d6.py` (unchanged) | blob `c5e56694d96c885373a7b70868259eeb9fdfa746`, 68,731 B | +| d=5 closed-form `RESULTS.json` (unchanged) | 16,765 B, SHA-256 `b878c1d3534a1ce72f01bb461a06b8777888bc0a5fdd9413fc1a4f8a565a2bb3` | +| d=5 coefficient `RESULTS.json` (unchanged) | 5,435 B, SHA-256 `81c4bc072b7eab4d2f1725b3d873076dac6bc31ab1a06779d3299d9e81b3cbaf` | +| d=6 coefficient `RESULTS.json` (unchanged) | 8,319 B, SHA-256 `82d1c19f9f503fd9211c6dcf356ec62aee9ec9eda44792bc38be4f3690637832` | + +The three packet trees are `d2e9f088`, `dc7dfac0` and `dcbeffef`. The ledger read +the workflows at `d1f6ad28` as blobs `40fe9334`, `93ac2e5e` and `c45d9a5a`. The +only change since is 2c041de (24 October), which moved each file's +`actions/setup-python` pin from `5fda3b95` to `6d4fd22b`. The mutant logic the +ledger classified is unchanged. The imported `tools/legacy_json_replay.py` (blob +`854db466`) and `tests/test_legacy_workflow_triggers.py` (blob `c2e37a3a`) are +the blobs every local run below used. + +## Repair and preservation + +Eight files: `tools/side24_mutant_replay.py`, the three files in +`tools/side24_mutant_contracts/` and `tests/test_side24_mutant_workflows.py` (all +new), the three workflows, and this note. + +`tools/side24_mutant_replay.py` follows `tools/legacy_json_replay.py` and reuses +that module's strict JSON reader and structural comparison instead of copying +them. For each family it binds the checker's git blob and the `RESULTS.json` size +and digest. It then runs the fixed inventory in both modes, exactly as the old +wrappers did: from the repository root, with the absolute script path, and with +`