From 3ae7fa6ec80f6554ed8753bbf5eabdd79aff4d8e Mon Sep 17 00:00:00 2001 From: Sagar Thakrar <18622288+thakrarsagar@users.noreply.github.com> Date: Sun, 18 Oct 2026 18:23:05 +0530 Subject: [PATCH 1/4] Add independent audit of PR3605 staged 644/660 words New stdlib package research/staged-644-660-independent-audit checks PR3605 head 3efbb5de against the unchanged PR3133 parent words (single-change control) and the PR3148 root: - free-operator dirty-input identity in both orientations, by forward values with symbolic private buffers and by reverse pull-back; literal inverse cleanup; 632 inputs, 91 buffers, both providers - binary-frame chronology: profile {1:2433,2:724,3:228} -> {1:2439,2:726,3:224}, widths 8:99->97, 7:50->52 - PROOF.md prose reconstruction, P_new = P_old S1 S2 on all registers, target tables and per-register invoice; 19 mutants per provider - exact root brackets of both published histograms confirmed; the +2.29e-7 gain is smaller than one rank-48 idle child (3.5e-7); the idle histogram I is recounted from the published aggregate witness - optional crosscheck against the inherited interpreter: 200/200 agreeing verdicts on random mutants (not part of the replay) No kappa claim and no frontier change. Native phases, owner windows, the literal owner journal and the full wrapper replay are not checked. Co-Authored-By: Claude Opus 5.5 --- .../README.md | 252 ++++ .../RESULT.json | 1330 +++++++++++++++++ .../ROOT-RESULT.json | 133 ++ .../SOURCES.json | 145 ++ .../TASK.json | 78 + .../VERIFY.json | 33 + .../audit_core.py | 473 ++++++ .../crosscheck_inherited.py | 84 ++ .../inputs/AGGREGATE-INTEGER-FLOW.json.gz | Bin 0 -> 21785 bytes .../inputs/PR3605-CLAIM.json | 33 + .../inputs/STAGED-PAIR-RECORD-base.json.gz | Bin 0 -> 660 bytes .../inputs/STAGED-PAIR-RECORD-extra.json.gz | Bin 0 -> 661 bytes .../inputs/STAGED644-660-base.json.gz | Bin 0 -> 72570 bytes .../inputs/STAGED644-660-extra.json.gz | Bin 0 -> 72568 bytes .../staged-644-660-independent-audit/root.py | 282 ++++ .../verify.py | 431 ++++++ 16 files changed, 3274 insertions(+) create mode 100644 research/staged-644-660-independent-audit/README.md create mode 100644 research/staged-644-660-independent-audit/RESULT.json create mode 100644 research/staged-644-660-independent-audit/ROOT-RESULT.json create mode 100644 research/staged-644-660-independent-audit/SOURCES.json create mode 100644 research/staged-644-660-independent-audit/TASK.json create mode 100644 research/staged-644-660-independent-audit/VERIFY.json create mode 100644 research/staged-644-660-independent-audit/audit_core.py create mode 100644 research/staged-644-660-independent-audit/crosscheck_inherited.py create mode 100644 research/staged-644-660-independent-audit/inputs/AGGREGATE-INTEGER-FLOW.json.gz create mode 100644 research/staged-644-660-independent-audit/inputs/PR3605-CLAIM.json create mode 100644 research/staged-644-660-independent-audit/inputs/STAGED-PAIR-RECORD-base.json.gz create mode 100644 research/staged-644-660-independent-audit/inputs/STAGED-PAIR-RECORD-extra.json.gz create mode 100644 research/staged-644-660-independent-audit/inputs/STAGED644-660-base.json.gz create mode 100644 research/staged-644-660-independent-audit/inputs/STAGED644-660-extra.json.gz create mode 100644 research/staged-644-660-independent-audit/root.py create mode 100644 research/staged-644-660-independent-audit/verify.py diff --git a/research/staged-644-660-independent-audit/README.md b/research/staged-644-660-independent-audit/README.md new file mode 100644 index 0000000000..2c89b02178 --- /dev/null +++ b/research/staged-644-660-independent-audit/README.md @@ -0,0 +1,252 @@ +# Independent audit of PR3605's staged 644/660 words + +**All four audited claims of PR3605 hold at head `3efbb5de` for both providers.** +A new standard-library interpreter, which does not import the inherited auditor, +confirms the following. The changed `base` and `extra` words are exact +arbitrary-dirty identities in both orientations, with 632 independent inputs and +91 private buffers. Their cleanup is the literal inverse cleanup. Their chronological +binary frames give the local profile +`{1:2433,2:724,3:228,4:102,5:20,8:8} -> {1:2439,2:726,3:224,4:102,5:20,8:8}` +and the helper widths `8:99 -> 97`, `7:50 -> 52`. The published complex-root +brackets of PR3605 and PR3148 also hold. An exact rational interval engine +checks them, and a 70-digit decimal engine cross-checks the result. + +This is a finite exact **audit** of one local supplier change. It makes no κ +claim and no frontier change. It does not check native Gaussian phases, the +owner journal, complete admission or the inherited all-size hypotheses (see +Scope). The selected record stays `0.001672660197076918`. + +## What was audited + +Audited object: RossRichardson's +[PR3605](https://github.com/CrocSwap/integer-mult-bounds/pull/3605), head +`3efbb5de06a49ffeea6684482f2d3fe48cdca3fb`, package +`research/staged-644-660-width-reduction`. In its two words, eight early raw +helper-to-target writes (old `B184..187` for helper 644, `B216..219` for 660) +are replaced by four donor releases at `span(429,30)`: `640 += 2*644` and +`496 -= 2*644` before old B599, and `656 -= 660` and `520 -= 2*660` before +old B647. Helpers 644 and 660 then enter at `span(429,30)` instead of `span(30)` +and keep FULL terminals. The single-change control is dcharb78's unchanged +[PR3133](https://github.com/CrocSwap/integer-mult-bounds/pull/3133) parent words +(`51eb9c4e`, byte-identical on main). The root control is Jeremy Diviney's merged +[PR3148](https://github.com/CrocSwap/integer-mult-bounds/pull/3148) (`f2927a4b`). + +The open staged-width κ>0.00173 chain (#3624, #3626, #3633, #3638 and the #3630 +successor) reuses these words unchanged. On 2026-10-18 the GitHub API showed +byte-identical copies at these heads: #3624 `515a7c44`, #3626 `659fd5e7` and +#3633 `72c268f1` add word blobs `dc6d321b`/`78e7b2bb` and record blobs +`042dbc69`/`67f04ae3`. The same blobs sit inside #3638 `d62e1acd`'s vendored +`PR3624-SOURCE.tar.gz` and #3630 `bcac7fe0`'s `PR3605-SOURCES.tar.gz`. +PR3605's own semantic check runs the pinned inherited interpreter +(`audit_local.py`). This package supplies a separately implemented check of +those exact words. It does not check those PRs' own owner journals or roots +and does not admit any of them. + +| Quantity (each provider) | PR3133 parent (control) | PR3605 changed word | +|---|---|---| +| Local profile | `1:2433, 2:724, 3:228, 4:102, 5:20, 8:8` | `1:2439, 2:726, 3:224, 4:102, 5:20, 8:8` | +| Helper widths | `4:26, 5:2, 6:18, 7:50, 8:99, 9:213` | `4:26, 5:2, 6:18, 7:52, 8:97, 9:213` | +| Inputs / private buffers | 632 / 91 | 632 / 91 | +| Forward (dirty buffers), dual, reverse pull-back | PASS | PASS | +| Cleanup equals the literal inverse | yes | yes | + +The profile delta is `+6 H1 + 2 H2 - 4 H3` (local rank mass −2 per call). It is +confined to exactly six registers, and each change equals PROOF.md's written +invoice: pivots 644/660 `+H2 - H3`, first donors 640/656 `+H1 + H2 - H3`, +second donors 496/520 `+2 H1 - H2`. Applying either helper's edit alone keeps +the identity and moves the profile by `+3 H1 + H2 - 2 H3`. The two helpers' +shares are therefore separable and additive. + +## Method and independence + +The registered verifiers (`audit_core.py`, `verify.py`, `root.py`) import only +the standard library. The word format and contract were read from PR3133/PR3605 +and the inherited `audit_local.py`. No code was imported or copied from them or +from the earlier `coupled-carrier-independent-audit` (Arham Tahir). The optional +cross-check below is the only exception: it imports the inherited auditor on +purpose. + +- **Identity, algorithm 1 (forward values).** Each register's value is + propagated as exact rational combinations of `(input, reduced free-group word)`. + Warps are independent invertible free symbols. All 632 live inputs **and the + 91 private buffers** are independent symbols, so the buffers are dirty. The + check requires `y_t -> y_t + x_t` with every other live input restored, and no + buffer contribution in any live register. With dirty buffers, every buffer is + returned unchanged in both orientations. At the cleanup boundary, targets + are sheared and the 91 restored helpers equal their own inputs and are read + nowhere else. +- **Dual.** The contragredient circuit is run separately with independent `K^-T` + symbols and must give `x_s -> x_s - y_s` with clean buffers. +- **Identity, algorithm 2 (reverse pull-back).** The program is processed + backwards on covectors, with words growing on the right. The resulting + 723 × 723 symbolic matrix at return must equal algorithm 1 entry for entry. + A separate pull-back of the pre-cleanup program must satisfy the same + boundary contract. +- **Frames.** Subspaces of `F_2^9` are stored as 512-point masks. Each gate's + frame must contain the current frame of every register it touches. The checks + also cover warp frame maps and the lifted Lagrangian action of all 72 warps, + centre descents, target levels and end frames. The profile and widths are derived from these frame + chains; report fields are compared only afterwards. The inherited structural + rules are also checked: dyadic scalars, power-of-two scales, and wrapper and + correction access. +- **Reconstruction.** Each changed word is rebuilt from the parent using only + PROOF.md's prose. Every field except cleanup must equal the shipped word, and + cleanup must equal the independently derived literal inverse. Canonical and + compressed digests must match PR3605's records, and the declared edit record + must equal the prose. +- **Second method (written argument).** Two parts of PROOF.md are checked + symbolically. First, `P_new = P_old S1 S2` holds on **every register** at + the boundary after the old-B647 releases. The S matrices change exactly + the four donors and the eight tabled targets. Second, the two four-row target + tables hold exactly at old B599 and B647, every other target has zero + columns, and each table kills its `v`. A per-register frame invoice is also + computed and compared with PROOF.md's written per-pivot histograms. +- **Contract fidelity (optional; not in the registered replay).** + `crosscheck_inherited.py SEED TRIALS` compares this package's forward and dual + verdicts with the pinned inherited interpreter on random mutants of the + `base` word. The mutants flip, drop or swap B gates, change coefficients, + flip or drop cleanup gates, drop or flip corrections, and shift warps. Seeds + `3605 40` and `44 60` gave 200 of 200 agreeing verdicts. This script imports + the inherited auditor, so it checks that the contract was read correctly. It + is not independent evidence. + +## Required-failing mutants (19 per provider, all as predicted) + +| Mutant | Outcome | +|---|---| +| Omit one of the four releases (cleanup regenerated) | identity fails at targets: 644→640 `135,162`; 644→496 `135,220`; 660→656 `141,196`; 660→520 `141,171` | +| Flip one release sign, or both signs of one helper | identity fails at targets | +| Add releases but keep the raw target writes | frame containment fails at B184; identity fails at `162,171,196,220` | +| Entrance `span(429,30)` alone on the parent | frame containment fails at B184 (helper 644) | +| Releases at frame `[30]` | frame containment fails at the first release | +| Parent cleanup on the changed word / one cleanup gate removed | identity fails (donors 496,520,640,656 left dirty / helpers dirty) | +| Keep the old `[30]` entrance | identity holds; profile `+2 H1`, widths back to `8:99, 7:50` | +| Drop the restore-210 frame edit | identity and bill unchanged (that edit is bill-neutral) | +| 644-only or 660-only edit | identity holds; profile `{1:2436,2:725,3:226,…}`, widths `7:51, 8:98` | + +The old-entrance mutant shows that, within these words, the entire rank-mass +saving of 2 comes from the entrance frame. With the old entrance, the staged +releases leave local rank mass unchanged. The physical legitimacy of the +`span(429,30)` entrance therefore rests on the native wrapper identity +`L^-1 T_F T_P^-1 R^-1 = C_[7] ⊗ I_[2]` (PR3605 `check_residual.py`). That +identity is shared by every downstream PR and is not independently checked here +(open question 2). + +## Root brackets and attribution + +`root.py` uses `M(b) = Σ_r r·H[r]·(73/r)^b / (73·663040)` (PR3605 DERIVATION.md) +on the published complete histograms. Its primary engine is outward-rounded +exact rational interval arithmetic: atanh/Taylor series with explicit +remainders on a `2^-320` grid. The second engine is 70-digit decimal Newton +iteration. During preparation, python-flint 0.9.0 arb at 400 bits reproduced +both `M(C)-1` and `M(D)-1` to all printed digits. That third check is not +part of the shipped replay. + +| Histogram | Published bracket | Confirmed 30-digit bracket | +|---|---|---| +| PR3605 | `[0.001730006549538841847005, …006]` | `[0.001730006549538841847005854305, …306]` | +| PR3148 | `[0.0017297774946785970118869, …870]` | `[0.001729777494678597011886903656, …657]` | + +The root delta is `+2.29054860244835118950648e-7` to `…650e-7`. Both +histograms have the same rank mass, `48,165,120 = 65088·740`. The +decomposition is `H = 6660·L + I`, with the local change `+6H1+2H2−4H3` per +call and the idle change `{1:+996, 3:−617, 4:+1, 5:−3083, 6:+3, 48:+616}`. +Swapping one component at a time does not conserve mass and moves the root by +about ±9.7e-5. Those hybrids (0.0018266 and 0.0016331) are arithmetic +counterfactuals, not realized journals. **The net gain is a 0.2% residual of +two opposite mass shifts.** A single rank-48 idle child moves the PR3605 root by +`∓3.498e-7`, more than the whole gain over PR3148. A rank-1 child moves it by +`∓7.34e-9`. So the claimed gain over PR3148 also depends on every idle count +being exact. + +`root.py` also recounts PR3605's published aggregate integer witness +(`owners/AGGREGATE-INTEGER-FLOW.json.gz`, vendored). Over its 1,491,840 bins, +`idle = capacity − pattern width` reproduces `I` exactly. Its role flow meets +the per-call demand `20 × {4:26, 5:2, 6:18, 7:52, 8:97, 9:213}` (the audited +widths) for all 333 macro-calls. The capacity balance +`35,804,160 = mass(I) + 6660·3279` holds. Three controls are rejected: the +parent widths, a deleted pattern record and a deleted role-flow record. The +witness's source windows are taken as published. The literal 2,717,280-row +journal and its chronology are not re-derived here; they remain the +load-bearing unaudited input to the root. + +## Scope, inherited assumptions and unrun obligations + +Checked here: the finite free-operator identity for arbitrary independent inputs +in which warps are free invertible symbols, the binary-frame chronology and bill, +the cleanup, the PROOF.md factorization, tables and invoice, and arithmetic +on two published histograms. The free-operator proof uses inverse cancellation +only, so it applies to the actual invertible warps. + +Not checked: + +- native Gaussian/Clifford phases and the rank-7 residual `C_[7]⊗I_[2]` on 512 columns; +- the owner source windows and the literal T740 owner journal (the idle profile is recounted only from the aggregate witness); +- the PR3605 conditional release and full fresh-bootstrap wrapper replay requested in Ross's #1166 handoff; +- physical/prefix/outer release, precision, H1–H5 and the formal kernel. + +The binary-frame contract is taken from the inherited format. It is not +derived from first principles. Gzip streams are not compared; payloads and +pinned byte digests are. + +## Reproduce + +From the repository root, with Python 3.12 or later and the standard library only: + +```sh +python3 -I -B research/staged-644-660-independent-audit/verify.py +python3 -I -B research/staged-644-660-independent-audit/root.py +``` + +Expected output is `PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT` (after two +`CHECKED` lines, about 35 s) and `PASS_EXACT_MOMENT_BRACKETS` (about 31 s). Both +compare against the committed receipts `RESULT.json` and `ROOT-RESULT.json`; `--write` +regenerates a receipt deliberately. Failures raise explicit exceptions, also +under `-O`. Both commands passed directly on CPython 3.14.4 under `-I -B` and +`-I -O -B`, and `research_package.py --check-only` passed. The generic runner +(`python3.12 scripts/research_package.py --package +research/staged-644-660-independent-audit`) needs Python 3.12. That version +was not available here, so the runner has not been executed. + +## Sources + +Base main `20ecf2891d80b5acf18d980b2164fb44ea7faa90`, priority revision 6. +PR3605 is unmerged, so its two words, two edit records, its conditional-release +`CLAIM.json` and its aggregate owner witness are byte-preserved in `inputs/`. +[SOURCES.json](SOURCES.json) records their source path, commit, Git blob and SHA256, which `verify.py` +checks. The PR3133 parent words and PR3148 `CLAIM.json` are read from main; +their blobs equal those at the predecessor heads. The PR3605 files that were +read but not executed (PROOF.md, staged_pair.py, check_scope.py, verify.py, +DERIVATION.md) are pinned the same way. + +## Open next questions + +The structured list is in [TASK.json](TASK.json). + +1. **Are PR3605's owner windows and literal journal legal?** The root gain + over PR3148 is smaller than one rank-48 idle child. The arithmetic from the + aggregate witness to + `I={1:174156,3:48334,4:1,5:10792,6:3,48:283185}` is reproduced here, so the + decisive remaining check is the witness's 333 source windows and the + 2,717,280-row chronological expansion. First step: derive the window classes + from the T37 source template without the retained `owner.windows` routine, + and compare them with the witness's `groups`. +2. **Do the native phases of the paired `span(429,30)` entrance hold?** This + needs an independent check of the rank-7 residual on all 512 Gaussian + columns, without the `bw_*` lineage code. +3. **Is the restore-210 frame edit needed?** It is bill- and identity-neutral + here. Does any native stage require it? + +## Credit and provenance + +The construction is RossRichardson's PR3605. The parent words and coupled folds +are dcharb78's PR3133, and the T740 owner/cap root control is Jeremy Diviney's +PR3148. The word lineage retains its credited predecessors (PR2857, PR2908/2917, +Marius-Paul Dumitrean's PR2979, Jeremy Kothe's PR3015, PR3042) as recorded in +those packages. Arham Tahir's `coupled-carrier-independent-audit` gave +orientation on the contract; no code was taken from it. The PR3531 arithmetic +lineage is credited for the root model in PR3605. + +Prepared by Sagar Thakrar (thakrarsagar) with substantial AI assistance from +Claude (Anthropic, Claude Opus 5.5). No human or formal-kernel review is claimed. +Apache-2.0. diff --git a/research/staged-644-660-independent-audit/RESULT.json b/research/staged-644-660-independent-audit/RESULT.json new file mode 100644 index 0000000000..10eb174029 --- /dev/null +++ b/research/staged-644-660-independent-audit/RESULT.json @@ -0,0 +1,1330 @@ +{ + "providers": { + "base": { + "changed_word": { + "canonical_sha256": "94d33db98720483f57efcd7bf50657f29f710554474e4f6b4b90617ad4500263", + "cleanup_literal_inverse": true, + "declared_record_equals_PROOF_prose": true, + "entrance_frame_points": { + "644": [ + 0, + 30, + 429, + 435 + ], + "660": [ + 0, + 30, + 429, + 435 + ] + }, + "inherited_hygiene": true, + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "reconstructed_from_PROOF_prose": true, + "release_positions_new_B": [ + 591, + 641 + ], + "semantics": { + "boundary_defects": [], + "buffer_to_live_leaks": [], + "dirty_buffers_returned_unchanged": true, + "dual_bad_registers": [], + "dual_buffer_to_live_leaks": [], + "dual_dirty_buffers": [], + "dual_dirty_buffers_returned_unchanged": true, + "final_terms": 835, + "forward_bad_registers": [], + "forward_dirty_buffers": [], + "independent_inputs": 632, + "private_buffers": 91, + "reverse_boundary_defects": [], + "reverse_pullback_equals_forward": true + }, + "terminal_frames_full": true, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "mutants": { + "644-only staged edit": { + "dual": "PASS", + "forward": "PASS", + "forward_bad_other": [], + "forward_bad_targets": [], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2436, + "2": 725, + "3": 226, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 51, + "8": 98, + "9": 213 + } + }, + "660-only staged edit": { + "dual": "PASS", + "forward": "PASS", + "forward_bad_other": [], + "forward_bad_targets": [], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2436, + "2": 725, + "3": 226, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 51, + "8": 98, + "9": 213 + } + }, + "entrance change only, on the parent": { + "frames": "FAIL: frame containment fails ('B', 184) 644" + }, + "first 644 cleanup gate removed": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [ + 225, + 241, + 244, + 245, + 247, + 248, + 252, + 253, + 254, + 384, + 388, + 390, + 391, + 392, + 397, + 496, + 641, + 642, + 644 + ], + "forward_bad_targets": [], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "flip both releases of 644": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 162, + 220 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "flip both releases of 660": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 171, + 196 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "flip release 644->496": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 135, + 220 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "flip release 644->640": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 135, + 162 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "flip release 660->520": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 141, + 171 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "flip release 660->656": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 141, + 196 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "old [30] entrance kept": { + "dual": "PASS", + "forward": "PASS", + "forward_bad_other": [], + "forward_bad_targets": [], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2441, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 50, + "8": 99, + "9": 213 + } + }, + "omit release 644->496": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 135, + 220 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2437, + "2": 727, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "omit release 644->640": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 135, + 162 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2438, + "2": 725, + "3": 225, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "omit release 660->520": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 141, + 171 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2437, + "2": 727, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "omit release 660->656": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 141, + 196 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2438, + "2": 725, + "3": 225, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "parent cleanup on the changed word": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [ + 496, + 520, + 640, + 656 + ], + "forward_bad_targets": [], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "releases added but raw target writes kept": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 162, + 171, + 196, + 220 + ], + "forward_dirty_buffers": [], + "frames": "FAIL: frame containment fails ('B', 184) 644" + }, + "releases at frame [30]": { + "frames": "FAIL: frame containment fails ('B', 591) 644" + }, + "restore-210 frame edit dropped": { + "dual": "PASS", + "forward": "PASS", + "forward_bad_other": [], + "forward_bad_targets": [], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + } + }, + "parent_control": { + "canonical_sha256": "49bdc172f1f53253c15fa4bf5be2d5741701d2fe9d18943f8b79c3ded0b96a3e", + "cleanup_literal_inverse": true, + "inherited_hygiene": true, + "profile": { + "1": 2433, + "2": 724, + "3": 228, + "4": 102, + "5": 20, + "8": 8 + }, + "semantics": { + "boundary_defects": [], + "buffer_to_live_leaks": [], + "dirty_buffers_returned_unchanged": true, + "dual_bad_registers": [], + "dual_buffer_to_live_leaks": [], + "dual_dirty_buffers": [], + "dual_dirty_buffers_returned_unchanged": true, + "final_terms": 835, + "forward_bad_registers": [], + "forward_dirty_buffers": [], + "independent_inputs": 632, + "private_buffers": 91, + "reverse_boundary_defects": [], + "reverse_pullback_equals_forward": true + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 50, + "8": 99, + "9": 213 + } + }, + "second_method": { + "per_register_bill_delta": { + "496": { + "1": 2, + "2": -1 + }, + "520": { + "1": 2, + "2": -1 + }, + "640": { + "1": 1, + "2": 1, + "3": -1 + }, + "644": { + "2": 1, + "3": -1 + }, + "656": { + "1": 1, + "2": 1, + "3": -1 + }, + "660": { + "2": 1, + "3": -1 + } + }, + "prefix_identity_all_registers": true, + "register_96_bill_unchanged": true, + "registers_moved_by_S": [ + 135, + 141, + 146, + 162, + 171, + 185, + 196, + 220, + 496, + 520, + 640, + 656 + ], + "roles": { + "496": "second donor", + "520": "second donor", + "640": "first donor", + "644": "pivot", + "656": "first donor", + "660": "pivot" + }, + "sum": { + "1": 6, + "2": 2, + "3": -4 + }, + "target_tables_before_old_B599_and_B647": { + "644": { + "135": [ + "1/2", + "-1/4", + "0" + ], + "146": [ + "-1/2", + "1/4", + "0" + ], + "162": [ + "1/2", + "-1/4", + "0" + ], + "220": [ + "1/2", + "1/4", + "1/2" + ] + }, + "660": { + "141": [ + "1/2", + "1/2", + "0" + ], + "171": [ + "1/2", + "-1/2", + "1/2" + ], + "185": [ + "-1/2", + "-1/2", + "0" + ], + "196": [ + "1/2", + "1/2", + "0" + ] + } + } + } + }, + "extra": { + "changed_word": { + "canonical_sha256": "ec4b2e15beaf99be4a96a6056fd6e92d09ea2382a4d0e8ab321f10bb2fc1dd10", + "cleanup_literal_inverse": true, + "declared_record_equals_PROOF_prose": true, + "entrance_frame_points": { + "644": [ + 0, + 30, + 429, + 435 + ], + "660": [ + 0, + 30, + 429, + 435 + ] + }, + "inherited_hygiene": true, + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "reconstructed_from_PROOF_prose": true, + "release_positions_new_B": [ + 591, + 641 + ], + "semantics": { + "boundary_defects": [], + "buffer_to_live_leaks": [], + "dirty_buffers_returned_unchanged": true, + "dual_bad_registers": [], + "dual_buffer_to_live_leaks": [], + "dual_dirty_buffers": [], + "dual_dirty_buffers_returned_unchanged": true, + "final_terms": 835, + "forward_bad_registers": [], + "forward_dirty_buffers": [], + "independent_inputs": 632, + "private_buffers": 91, + "reverse_boundary_defects": [], + "reverse_pullback_equals_forward": true + }, + "terminal_frames_full": true, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "mutants": { + "644-only staged edit": { + "dual": "PASS", + "forward": "PASS", + "forward_bad_other": [], + "forward_bad_targets": [], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2436, + "2": 725, + "3": 226, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 51, + "8": 98, + "9": 213 + } + }, + "660-only staged edit": { + "dual": "PASS", + "forward": "PASS", + "forward_bad_other": [], + "forward_bad_targets": [], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2436, + "2": 725, + "3": 226, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 51, + "8": 98, + "9": 213 + } + }, + "entrance change only, on the parent": { + "frames": "FAIL: frame containment fails ('B', 184) 644" + }, + "first 644 cleanup gate removed": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [ + 225, + 241, + 244, + 245, + 247, + 248, + 252, + 253, + 254, + 384, + 388, + 390, + 391, + 392, + 397, + 496, + 641, + 642, + 644 + ], + "forward_bad_targets": [], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "flip both releases of 644": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 162, + 220 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "flip both releases of 660": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 171, + 196 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "flip release 644->496": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 135, + 220 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "flip release 644->640": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 135, + 162 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "flip release 660->520": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 141, + 171 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "flip release 660->656": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 141, + 196 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "old [30] entrance kept": { + "dual": "PASS", + "forward": "PASS", + "forward_bad_other": [], + "forward_bad_targets": [], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2441, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 50, + "8": 99, + "9": 213 + } + }, + "omit release 644->496": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 135, + 220 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2437, + "2": 727, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "omit release 644->640": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 135, + 162 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2438, + "2": 725, + "3": 225, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "omit release 660->520": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 141, + 171 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2437, + "2": 727, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "omit release 660->656": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 141, + 196 + ], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2438, + "2": 725, + "3": 225, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "parent cleanup on the changed word": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [ + 496, + 520, + 640, + 656 + ], + "forward_bad_targets": [], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + }, + "releases added but raw target writes kept": { + "dual": "FAIL", + "forward": "FAIL", + "forward_bad_other": [], + "forward_bad_targets": [ + 162, + 171, + 196, + 220 + ], + "forward_dirty_buffers": [], + "frames": "FAIL: frame containment fails ('B', 184) 644" + }, + "releases at frame [30]": { + "frames": "FAIL: frame containment fails ('B', 591) 644" + }, + "restore-210 frame edit dropped": { + "dual": "PASS", + "forward": "PASS", + "forward_bad_other": [], + "forward_bad_targets": [], + "forward_dirty_buffers": [], + "frames": "PASS", + "profile": { + "1": 2439, + "2": 726, + "3": 224, + "4": 102, + "5": 20, + "8": 8 + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 52, + "8": 97, + "9": 213 + } + } + }, + "parent_control": { + "canonical_sha256": "34af6f955bf8d95f68868cc282fa739532a5a6117df50d753fd996d44cea6731", + "cleanup_literal_inverse": true, + "inherited_hygiene": true, + "profile": { + "1": 2433, + "2": 724, + "3": 228, + "4": 102, + "5": 20, + "8": 8 + }, + "semantics": { + "boundary_defects": [], + "buffer_to_live_leaks": [], + "dirty_buffers_returned_unchanged": true, + "dual_bad_registers": [], + "dual_buffer_to_live_leaks": [], + "dual_dirty_buffers": [], + "dual_dirty_buffers_returned_unchanged": true, + "final_terms": 835, + "forward_bad_registers": [], + "forward_dirty_buffers": [], + "independent_inputs": 632, + "private_buffers": 91, + "reverse_boundary_defects": [], + "reverse_pullback_equals_forward": true + }, + "widths": { + "4": 26, + "5": 2, + "6": 18, + "7": 50, + "8": 99, + "9": 213 + } + }, + "second_method": { + "per_register_bill_delta": { + "496": { + "1": 2, + "2": -1 + }, + "520": { + "1": 2, + "2": -1 + }, + "640": { + "1": 1, + "2": 1, + "3": -1 + }, + "644": { + "2": 1, + "3": -1 + }, + "656": { + "1": 1, + "2": 1, + "3": -1 + }, + "660": { + "2": 1, + "3": -1 + } + }, + "prefix_identity_all_registers": true, + "register_96_bill_unchanged": true, + "registers_moved_by_S": [ + 135, + 141, + 146, + 162, + 171, + 185, + 196, + 220, + 496, + 520, + 640, + 656 + ], + "roles": { + "496": "second donor", + "520": "second donor", + "640": "first donor", + "644": "pivot", + "656": "first donor", + "660": "pivot" + }, + "sum": { + "1": 6, + "2": 2, + "3": -4 + }, + "target_tables_before_old_B599_and_B647": { + "644": { + "135": [ + "1/2", + "-1/4", + "0" + ], + "146": [ + "-1/2", + "1/4", + "0" + ], + "162": [ + "1/2", + "-1/4", + "0" + ], + "220": [ + "1/2", + "1/4", + "1/2" + ] + }, + "660": { + "141": [ + "1/2", + "1/2", + "0" + ], + "171": [ + "1/2", + "-1/2", + "1/2" + ], + "185": [ + "-1/2", + "-1/2", + "0" + ], + "196": [ + "1/2", + "1/2", + "0" + ] + } + } + } + } + }, + "scope": "Finite exact local audit of PR3605 head 3efbb5de words against the PR3133 parent words: free-operator dirty-input identity (forward with symbolic private buffers, contragredient dual, reverse pull-back), literal inverse cleanup, binary-frame chronology/profile/widths, PROOF.md prefix factorization, tables and invoice, and mutants. No native Gaussian phase, owner journal, complete admission, kappa or frontier claim.", + "status": "PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT" +} diff --git a/research/staged-644-660-independent-audit/ROOT-RESULT.json b/research/staged-644-660-independent-audit/ROOT-RESULT.json new file mode 100644 index 0000000000..d1a1edd365 --- /dev/null +++ b/research/staged-644-660-independent-audit/ROOT-RESULT.json @@ -0,0 +1,133 @@ +{ + "aggregate_witness_recount": { + "bins": 1491840, + "capacity_rank_units": 35804160, + "idle": { + "1": 174156, + "3": 48334, + "4": 1, + "48": 283185, + "5": 10792, + "6": 3 + }, + "scope": "arithmetic of the published integer witness with the audited widths; windows as published; no literal journal or chronology" + }, + "attribution": { + "PR3148 idle + PR3605 local": { + "bracket_30_digits": [ + "1826582763822943966796899637/1000000000000000000000000000000", + "913291381911471983398449819/500000000000000000000000000000" + ], + "rank_mass": 48151800, + "shift_from_PR3148_lower": 9.680526914434695e-05 + }, + "PR3148 local + PR3605 idle": { + "bracket_30_digits": [ + "65325438777578337491804849/40000000000000000000000000000", + "816567984719729218647560613/500000000000000000000000000000" + ], + "rank_mass": 48178440, + "shift_from_PR3148_lower": -9.664152523913857e-05 + } + }, + "histograms": { + "PR3148": { + "M_lower_at_D_minus_1": 2.7336604517475374e-25, + "M_upper_at_C_minus_1": -1.0375926953082e-26, + "bracket_30_digits": [ + "216222186834824626485862957/125000000000000000000000000000", + "1729777494678597011886903657/1000000000000000000000000000000" + ], + "decimal_engine_root_70_digits": "0.001729777494678597011886903656817803609005754813360929082708328901175575", + "histogram": { + "1": 16376940, + "2": 4821840, + "3": 1567431, + "4": 679320, + "48": 282569, + "5": 147075, + "8": 53280 + }, + "published_bracket": [ + "17297774946785970118869/10000000000000000000000000", + "1729777494678597011887/1000000000000000000000000" + ], + "published_digits": 25 + }, + "PR3605": { + "M_lower_at_D_minus_1": 4.1334262440831736e-25, + "M_upper_at_C_minus_1": -2.4237067270536225e-24, + "bracket_30_digits": [ + "346001309907768369401170861/200000000000000000000000000000", + "865003274769420923502927153/500000000000000000000000000000" + ], + "decimal_engine_root_70_digits": "0.001730006549538841847005854305451473616183688862135324240199051199479098", + "histogram": { + "1": 16417896, + "2": 4835160, + "3": 1540174, + "4": 679321, + "48": 283185, + "5": 143992, + "6": 3, + "8": 53280 + }, + "published_bracket": [ + "346001309907768369401/200000000000000000000000", + "865003274769420923503/500000000000000000000000" + ], + "published_digits": 24 + } + }, + "idle_delta": { + "1": 996, + "3": -617, + "4": 1, + "48": 616, + "5": -3083, + "6": 3 + }, + "local_delta_per_call": { + "1": 6, + "2": 2, + "3": -4 + }, + "model": "M(b)=sum_r r*H[r]*(73/r)^b/(73*663040)", + "rank_mass": 48165120, + "root_delta_PR3605_minus_PR3148": [ + "28631857530604389868831/125000000000000000000000000000", + "4581097204896702379013/20000000000000000000000000000" + ], + "single_child_sensitivity_PR3605": { + "+1 rank-1 child": { + "bracket_30_digits": [ + "1729999212951825119741563069/1000000000000000000000000000000", + "172999921295182511974156307/100000000000000000000000000000" + ], + "shift_from_PR3605_lower": -7.336587016727264e-09 + }, + "+1 rank-48 child": { + "bracket_30_digits": [ + "345931348752233296299287263/200000000000000000000000000000", + "432414185940291620374109079/250000000000000000000000000000" + ], + "shift_from_PR3605_lower": -3.4980577767536554e-07 + }, + "-1 rank-1 child": { + "bracket_30_digits": [ + "1730013886126120365249152379/1000000000000000000000000000000", + "86500694306306018262457619/50000000000000000000000000000" + ], + "shift_from_PR3605_lower": 7.336587278518243e-09 + }, + "-1 rank-48 child": { + "bracket_30_digits": [ + "865178177482133737937284553/500000000000000000000000000000", + "1730356354964267475874569107/1000000000000000000000000000000" + ], + "shift_from_PR3605_lower": 3.498054254256289e-07 + } + }, + "status": "PASS_EXACT_MOMENT_BRACKETS", + "stock_times_dimension": 48401920 +} diff --git a/research/staged-644-660-independent-audit/SOURCES.json b/research/staged-644-660-independent-audit/SOURCES.json new file mode 100644 index 0000000000..52e3d7d3a7 --- /dev/null +++ b/research/staged-644-660-independent-audit/SOURCES.json @@ -0,0 +1,145 @@ +{ + "schema_version": 1, + "base_commit": "20ecf2891d80b5acf18d980b2164fb44ea7faa90", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "b1fea0c94436b236cc2b7d41a7be032811b94c81", + "sha256": "bb2eaa58647b353f88d0aec2eafb9d30df1be53589231b23e12ceef3e4bad129" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "67f085acd86acd7d4e03922d9cf4b26bca66fed5", + "sha256": "47b42433f5a85809a3aadd29c2c339da2c6ed728e4f7762df6b88bccb7874cf0" + }, + { + "path": "research/coupled-carrier-cap740/CLAIM.json", + "usage": "input", + "git_blob": "aa3d8e87fc139d636cd19eaa4cd375fca2c780cf", + "sha256": "338165d75d87a1a576750ec92772640e641bc91076e91b686d8ec7ad6f9d6d19" + }, + { + "path": "research/rank7-coupled-586-588-carrier-fold/edits/FINAL-WORD-base.json.gz", + "usage": "input", + "git_blob": "cb4cc24a4545944627ad595c0c5080196952b9f0", + "sha256": "300a9b8ad1d554f0e6f84f43f3f5fd870a5b4e5f81ad856900b6e8999684892e" + }, + { + "path": "research/rank7-coupled-586-588-carrier-fold/edits/FINAL-WORD-extra.json.gz", + "usage": "input", + "git_blob": "decc8f26d8aab108baf75f0d8b2d1012eb06d076", + "sha256": "495d030f1e03b90e954dad3043994f03293d41b9ed220a3beaef849df435d3f0" + } + ], + "snapshot": [ + { + "local": "inputs/STAGED644-660-base.json.gz", + "source_path": "research/staged-644-660-width-reduction/STAGED644-660-base.json.gz", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "dc6d321b1e8e2a837a1ff7bb60e8f8f78d043db5", + "sha256": "735c540b1fe29d0ceeb4d2f304ec941e5f2bd3bc92bafc8cce2b4f9a67a3b653" + }, + { + "local": "inputs/STAGED644-660-extra.json.gz", + "source_path": "research/staged-644-660-width-reduction/STAGED644-660-extra.json.gz", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "78e7b2bb0653c8dcc0133980a19dd9d97ebdb67e", + "sha256": "886338fc32da14f3389a82c8120a1bcf9c5e2f0ec3e9b2d377fdae809e1d977f" + }, + { + "local": "inputs/STAGED-PAIR-RECORD-base.json.gz", + "source_path": "research/staged-644-660-width-reduction/STAGED-PAIR-RECORD-base.json.gz", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "042dbc69aee653e0a3c66a5910f14c741e5b39a7", + "sha256": "a6ae4188be998990ecb176fef5929e8e1dfce3726e372c0da2a290fe8ea73532" + }, + { + "local": "inputs/STAGED-PAIR-RECORD-extra.json.gz", + "source_path": "research/staged-644-660-width-reduction/STAGED-PAIR-RECORD-extra.json.gz", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "67f04ae395ec5f05586af438eeb2ad2db23c9c82", + "sha256": "33a39d46d4d19bdeb6f0b6abb38cc80c68219e1ae10dd7e1acaccedc14b47236" + }, + { + "local": "inputs/PR3605-CLAIM.json", + "source_path": "research/staged-644-660-conditional-release/CLAIM.json", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "445e6a83a4cdc6e8630e86f20990b50d1311f81d", + "sha256": "2e721209f626d5111142951b1f26383d6746b4f230a4625244b5e5c84d6079d5" + }, + { + "local": "inputs/AGGREGATE-INTEGER-FLOW.json.gz", + "source_path": "research/staged-644-660-conditional-release/owners/AGGREGATE-INTEGER-FLOW.json.gz", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "104962d079d315f3caf5269ff0e8ff0fbae7fee8", + "sha256": "392d9ff80e641a79c9375e71df7f745e9d48f6e0914851a4ed4ecd079e0df2e9" + } + ], + "read_only_references": [ + { + "source_path": "research/staged-644-660-width-reduction/PROOF.md", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "020ab84ae73b04a94d5f49dae77c37d766ceb532", + "sha256": "525b010f3a895bdb11313f9938ad1b742df64bcee0b5671399230b1ded541baf", + "usage": "read for the claims under audit; not imported or executed" + }, + { + "source_path": "research/staged-644-660-width-reduction/staged_pair.py", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "ca3e3effb97f46485ab7ac8c15ce4a92e1f93fbe", + "sha256": "25fc9b025dbb90358032013303adea650a5f19937fd3edf30b6c6fd023e2d747", + "usage": "read for the claims under audit; not imported or executed" + }, + { + "source_path": "research/staged-644-660-width-reduction/check_scope.py", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "cea3481a639a18f13d457c926d7a3db45525797e", + "sha256": "f8eefd425a0d570167e14febcacfbb38a6bb29d820d808be426180cf31b5a947", + "usage": "read for the claims under audit; not imported or executed" + }, + { + "source_path": "research/staged-644-660-width-reduction/verify.py", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "7f2f6170705a77a8ca5e31007d986912373a33f0", + "sha256": "0ef49b725fc132cd5fc26a9a81028739896232d938bae22cef132384c7cbab13", + "usage": "read for the claims under audit; not imported or executed" + }, + { + "source_path": "research/staged-644-660-conditional-release/DERIVATION.md", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "30710a70b9d9e2b8625ba69fcfbf4c2ba736a8e9", + "sha256": "0570b25a98261ed62c9c5709e14a8f6f6c5a921a73286739212c3954c3e7de27", + "usage": "read for the claims under audit; not imported or executed" + }, + { + "source_path": "research/rank7-coupled-586-588-carrier-fold/edits/FINAL-WORD-base.json.gz", + "source_commit": "51eb9c4ee9e4722010d308aa3309e039d3940cc2", + "source_pr": 3133, + "git_blob": "cb4cc24a4545944627ad595c0c5080196952b9f0", + "sha256": "300a9b8ad1d554f0e6f84f43f3f5fd870a5b4e5f81ad856900b6e8999684892e", + "usage": "identity of the main-branch input with its predecessor head" + }, + { + "source_path": "research/coupled-carrier-cap740/CLAIM.json", + "source_commit": "f2927a4b8afcf0701a6b945e14f30de1d94f5176", + "source_pr": 3148, + "git_blob": "aa3d8e87fc139d636cd19eaa4cd375fca2c780cf", + "sha256": "338165d75d87a1a576750ec92772640e641bc91076e91b686d8ec7ad6f9d6d19", + "usage": "identity of the main-branch input with its predecessor head" + } + ], + "snapshot_provenance": "Exact Git blob bytes of PR3605 head 3efbb5de (unmerged at base 20ecf289); verify.py authenticates them by SHA256. The PR3133 parent words and PR3148 claim are read from main and pinned in files." +} diff --git a/research/staged-644-660-independent-audit/TASK.json b/research/staged-644-660-independent-audit/TASK.json new file mode 100644 index 0000000000..99c9dca9d1 --- /dev/null +++ b/research/staged-644-660-independent-audit/TASK.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "task_id": "independent-moment", + "priority_revision": 6, + "base_commit": "20ecf2891d80b5acf18d980b2164fb44ea7faa90", + "original_card": { + "id": "independent-moment", + "question": "Does one changed supplier or assembly claim lack a source-bound independent check of a specific new implication?", + "starting_points": [ + "certificates/selected-result.json", + "research/rank7-joint-endframes/README.md", + "docs/research/research-family-status.md" + ], + "methods": [ + "Independently reconstruct a coordinated frame/circuit change and its single-change control, then derive the complete rank and physical ledger.", + "Implement certified moment inequalities through a different exact enclosure method." + ], + "acceptance_gate": "Demonstrate independence, source binding, positive cases and semantic failure controls. Name the existing checks and the missing coverage. More digits or another equivalent evaluation of an unchanged root is not by itself new verification coverage.", + "first_step": { + "command": [ + "python3", + "-B", + "scripts/research_baseline.py" + ], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Read #2979 joint rank-7 end-frame proposal and the revision-6 evidence status. Its claimed kappa is not selected. Compare coordinated changes with the losing single-change controls and locate the complete physical ledger; an aggregate moment alone does not validate the mechanism.", + "scope": "Positive control / source-bound orientation only; this is not a new construction or full cold replay." + }, + "first_experiment": "Prioritize a bounded independent audit of #2979: reconstruct one joint group and its single-lowering control, check the declared frames/chronology, then trace changed children, idle widths and cleanup buffers into the complete invoice and both supplier caps. Choose one still-missing implication after checking existing audits. Stop with exact unresolved dependencies if full admission exceeds the session; do not launch a new lowering census on an unvalidated premise or substitute extra root digits for mechanism checking.", + "bottleneck_link": "Independent pricing prevents unsupported frontier claims and can reveal genuine accounting slack.", + "allowed_variations": [ + "Reconstruct either a source ledger or a numeric enclosure with a different method." + ], + "scope_change_triggers": [ + "Importing the primary function and calling its output independent verification.", + "Promoting #2979 from merged source archive to validated supplier solely from author PASS receipts or aggregate pricing." + ], + "overlap_terms": [ + "independent moment", + "rank histogram", + "exact enclosure", + "2979", + "rank7 joint endframes", + "paired extraction", + "joint lowering" + ] + }, + "scope_status": "refined", + "actual_scope": "Independently audit PR3605 (head 3efbb5de)'s staged 644/660 width 8->7 change against its single-change control, the unchanged PR3133 parent words: exact dirty-input identity in both orientations by two algorithms, literal inverse cleanup, chronological binary frames, local profile and helper widths, PROOF.md's prefix factorization/tables/invoice, required-failing mutants, and exact root brackets for the published PR3605 and PR3148 complete histograms with their attribution.", + "scope_change_reason": "The card's first experiment names #2979's joint group; PR3605 is the live descendant of that joint-construction lineage (PR2979 -> PR3133 -> PR3605), and every open staged-width kappa>0.00173 claim (#3624/#3626/#3633/#3638/#3630) reuses its words unchanged with only author-run inherited-interpreter checks. Auditing one changed group against its single-change control is the card's method applied to the currently decision-relevant group.", + "bottleneck_link": "Independent pricing of the supplier words that the staged-width chain inherits: a failure would invalidate the whole chain; a pass supplies the independent local check while showing the root gain depends on the unaudited idle journal.", + "budget_minutes": 150, + "stop_rule": "Ship (c)+(e) with a handoff if the interpreter could not reproduce the parent control by ~75 min; stop and minimize on any identity/cleanup/profile failure; switch to p104-side-correction if another contributor claimed the words first. None triggered.", + "outcome": "completed", + "evidence": "PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT (RESULT.json): both providers, parent control {1:2433,2:724,3:228,4:102,5:20,8:8} / widths 7:50,8:99 reproduced; changed words {1:2439,2:726,3:224,4:102,5:20,8:8} / widths 7:52,8:97; 632 inputs, 91 buffers; forward with dirty buffers, dual, and reverse pull-back agree; cleanup literal inverse; PROOF.md factorization P_new=P_old S1 S2 on all registers, target tables and per-register invoice exact; 19 mutants per provider behave as predicted. PASS_EXACT_MOMENT_BRACKETS (ROOT-RESULT.json): PR3605 [0.001730006549538841847005,...006] and PR3148 [0.0017297774946785970118869,...870] confirmed by two engines; delta +2.2905486024e-7 is smaller than the effect of one rank-48 idle child (3.498e-7); the vendored PR3605 aggregate owner witness reproduces I={1:174156,3:48334,4:1,5:10792,6:3,48:283185} with the audited widths (windows taken as published; literal journal not re-derived).", + "author": "Sagar Thakrar (thakrarsagar)", + "ai_assistance": "Substantial AI assistance from Claude (Anthropic, Claude Opus 5.5): design, code, checks and write-up in an automated research loop. No human or formal-kernel review is claimed.", + "open_questions": [ + { + "question": "Are PR3605's 333 owner source windows and its 2,717,280-row chronological journal legal for the audited widths?", + "why_it_matters": "The root gain over PR3148 (+2.29e-7) is smaller than the root shift from one rank-48 idle child (3.5e-7). This package reproduces I from the published aggregate witness, but takes the witness's windows as published and does not re-derive the literal journal.", + "first_step": "Derive the window classes (capacity, lo, hi, bins) from the T37 source template without the retained owner.windows routine and compare with the witness's groups list; then re-expand and check chronological prefixes independently of portable_expand.py/independent_literal.py.", + "blocked_by": "Nothing; requires the T37 source template/order format. The sibling CLAIM on #3633 T488 owners covers a different journal." + }, + { + "question": "Do the native Gaussian phases of the paired span(429,30) entrance (rank-7 residual C_[7] tensor I_[2]) hold on all 512 columns when checked without the bw_* lineage code?", + "why_it_matters": "This audit checks free-operator semantics and binary frames only; the physical width-7 residual is certified only by the inherited native chain.", + "first_step": "Implement an independent exact monomial/Gaussian product for T_FULL T_P^-1 and compare with check_residual.py's recipe on all 512 columns, including global phase.", + "blocked_by": "Understanding of the native recipe format; no data blocker." + }, + { + "question": "Is the restore-210 frame edit (source 96 sign gate moved from a rank-8 hyperplane to FULL) needed by any native stage?", + "why_it_matters": "It is identity- and bill-neutral in the local audit; if unnecessary it is noise in the declared edit set, if necessary the native contract has an undocumented dependency.", + "first_step": "Run the native transport on the changed word with that single edit reverted and record the first failing stage, if any.", + "blocked_by": "Requires the numpy-based native chain (not run here)." + } + ] +} diff --git a/research/staged-644-660-independent-audit/VERIFY.json b/research/staged-644-660-independent-audit/VERIFY.json new file mode 100644 index 0000000000..c0326af269 --- /dev/null +++ b/research/staged-644-660-independent-audit/VERIFY.json @@ -0,0 +1,33 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [ + "research/coupled-carrier-cap740/CLAIM.json", + "research/rank7-coupled-586-588-carrier-fold/edits/FINAL-WORD-base.json.gz", + "research/rank7-coupled-586-588-carrier-fold/edits/FINAL-WORD-extra.json.gz" + ], + "commands": [ + { + "argv": [ + "{python}", + "-I", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 300, + "checks": "Both providers: PR3133 parent control table, PROOF.md-prose reconstruction and record digests, free-operator dirty-input identity (forward with symbolic private buffers, contragredient dual, reverse pull-back), literal inverse cleanup, binary-frame chronology/profile/widths, P_new=P_old S1 S2 on all registers, target tables, per-register invoice, 19 required-outcome mutants, receipt comparison." + }, + { + "argv": [ + "{python}", + "-I", + "-B", + "{package}/root.py" + ], + "timeout_seconds": 300, + "checks": "Exact interval and decimal-Newton enclosures of the PR3605 and PR3148 complex roots on their published complete histograms, H=6660L+I decompositions, rank-mass invariant, recount of I from the vendored aggregate owner witness with the audited widths (three rejecting controls), attribution hybrids, single-child sensitivity, receipt comparison." + } + ] +} diff --git a/research/staged-644-660-independent-audit/audit_core.py b/research/staged-644-660-independent-audit/audit_core.py new file mode 100644 index 0000000000..80ff8ad253 --- /dev/null +++ b/research/staged-644-660-independent-audit/audit_core.py @@ -0,0 +1,473 @@ +"""Independent exact semantics and binary-frame bill for the BORROW-WORD format. + +Standard library only. No predecessor evaluator, producer, cleanup generator or +frame solver is imported; the word format and its semantic contract were read +from the pinned PR3133/PR3605 sources and are credited there. + +Sagar Thakrar (thakrarsagar), with substantial AI assistance from Claude +(Anthropic, Claude Opus 5.5). Apache-2.0. +""" +from collections import Counter +from fractions import Fraction as Q + +V, N, H = 112, 704, 9 # sources 0..111, targets 112..223, helpers 224..703 +DUAL = 10 ** 6 # offset naming the independent dual symbols D_k = K_k^(-T) + + +class AuditFailure(Exception): + """Explicit failure; never disabled by python -O.""" + + +def need(ok, *why): + if not ok: + raise AuditFailure(' '.join(map(str, why))) + + +def is_target(r): + return V <= r < 2 * V + + +def touched(g): + return g[1:3] if g[0] == 'add' else g[1:2] + + +# ---------------------------------------------------------------------------- +# Binary frames: a subspace of F_2^9 is stored as a 512-bit point-set mask +# (bit x set iff x lies in the subspace). Containment is mask inclusion. +# ---------------------------------------------------------------------------- +_SPAN = {} + + +def span(vectors): + key = tuple(vectors) + mask = _SPAN.get(key) + if mask is None: + points = {0} + for u in key: + need(type(u) is int and 0 <= u < 512, 'frame vector out of range', u) + if u not in points: + points |= {p ^ u for p in points} + mask = sum(1 << p for p in points) + _SPAN[key] = mask + return mask + + +def points(mask): + return [x for x in range(512) if mask >> x & 1] + + +def dim(mask): + size = bin(mask).count('1') + need(size and size & (size - 1) == 0, 'not a subspace point set') + return size.bit_length() - 1 + + +FULL = (1 << 512) - 1 +ZERO = 1 + + +def hyperplane(port): + return sum(1 << x for x in range(512) if bin(x & port).count('1') % 2 == 0) + + +def warp_images(columns): + """Images of all 512 vectors under the F_2-linear map with columns G e_i.""" + need(len(columns) == H and all(type(c) is int and 0 <= c < 512 for c in columns), 'warp columns') + images = [0] * 512 + for x in range(1, 512): + low = x & -x + images[x] = images[x ^ low] ^ columns[low.bit_length() - 1] + need(len(set(images)) == 512, 'singular warp') + return images + + +def image_mask(images, mask): + return sum(1 << images[x] for x in points(mask)) + + +def lagrangian_action_ok(images, U, E): + """K_G(x,z)=(Gx, Gx+G^{-T}(x+z)) is symplectic and maps L_U to L_E, L_0 and L_FULL to themselves. + + L_U={(x,x+p): x in U, p in U^perp}. This is the binary frame action only; it + is not a Clifford phase or Gaussian-product certificate. + """ + inverse = [0] * 512 + for x, y in enumerate(images): + inverse[y] = x + # G^{-T} z: bit j of the result is . + git = lambda z: sum((bin(inverse[1 << j] & z).count('1') & 1) << j for j in range(H)) + lift = lambda x, z: (images[x], images[x] ^ git(x ^ z)) + pair = lambda a, b: (bin(a[0] & b[1]).count('1') + bin(a[1] & b[0]).count('1')) & 1 + basis = [(1 << i, 0) for i in range(H)] + [(0, 1 << i) for i in range(H)] + lifted = [lift(*b) for b in basis] + if any(pair(lifted[i], lifted[j]) != pair(basis[i], basis[j]) for i in range(18) for j in range(i + 1, 18)): + return False + + def frame(mask): + us = points(mask) + perp = [p for p in range(512) if all(bin(p & u).count('1') % 2 == 0 for u in us)] + return {(u, u ^ p) for u in us for p in perp} + return all({lift(*pt) for pt in frame(a)} == frame(b) for a, b in ((ZERO, ZERO), (FULL, FULL), (U, E))) + + +# ---------------------------------------------------------------------------- +# Chronological binary-frame bill (BORROW-WORD contract) +# ---------------------------------------------------------------------------- +def frame_bill(w, lagrangian=False): + rep = w['report'] + need((rep['v'], 2 * rep['v'] + rep['R'], rep['h']) == (V, N, H), 'word geometry') + removed = set(w['removed']) + need(len(removed) == len(w['removed']) and all(2 * V <= r < N for r in removed), 'removed helpers') + live = [r for r in range(N) if r not in removed] + liveset = set(live) + B, warps = w['B'], w['warps'] + for k, (pos, lender, cols, U, E) in enumerate(warps, 1): + need(0 <= pos <= len(B), 'warp position', k) + need(lender in liveset and not is_target(lender), 'warp lender', k) + images = warp_images(cols) + su, se = span(U), span(E) + need(dim(su) == len(U) == len(E) == dim(se), 'warp frame bases', k) + need(image_mask(images, su) == se, 'warp does not map its frame', k) + if lagrangian: + need(lagrangian_action_ok(images, su, se), 'lifted frame action', k) + for name in ('A', 'B', 'restore'): + for g in w[name]: + if g[0] != 'warp': + need(all(r in liveset for r in touched(g)), 'removed/out-of-range register', name, g) + if g[0] == 'add' and not is_target(g[1]): + need(not is_target(g[2]), 'non-target reads a target', name, g) + need(all(g[-1] is None and is_target(g[1]) and g[0] == 'add' for g in w['cut']), 'cut gates') + need(all(g[-1] == [] and is_target(g[1]) for g in w['precondition'] + w['compensation']), 'zero-frame wrapper writes') + need(all(not is_target(g[1]) for g in w['restore']), 'restore writes a target') + + ports = w['ports'] + start, end = {}, {} + for r in live: + if r < V: + start[r], end[r] = span((ports[r],)), FULL + elif r < 2 * V: + start[r], end[r] = ZERO, hyperplane(ports[r - V]) + else: + start[r], end[r] = ZERO, FULL + for q, U in w['start_extra'].items(): + need(int(q) in liveset and int(q) >= 2 * V, 'entrance names a live helper', q) + start[int(q)] = span(U) + for q, U in w['helper_final'].items(): + need(int(q) in liveset and int(q) >= 2 * V, 'terminal names a live helper', q) + end[int(q)] = span(U) + + current, bill, chain = dict(start), Counter(), {} + + def climb(r, mask, where): + need(current[r] & ~mask == 0, 'frame containment fails', where, r) + d = dim(mask) - dim(current[r]) + if d: + bill[d] += 1 + chain.setdefault(r, []).append((where, d, mask)) + current[r] = mask + + npre = w['prelude_events'] + for i, g in enumerate(w['A']): + if g[0] == 'warp': + need(i < npre and len(g) == 5, 'warp outside the prelude', i) + _, r, op, fr, to = g + need(op != 0 and abs(op) <= len(warps) and warps[abs(op) - 1][1] == r, 'prelude warp lender', i) + images = warp_images(warps[abs(op) - 1][2]) + if op < 0: + inverse = [0] * 512 + for x, y in enumerate(images): + inverse[y] = x + images = inverse + need(image_mask(images, span(fr)) == span(to), 'prelude warp frame action', i) + need(current[r] == span(fr), 'prelude warp entry frame', i, r) + current[r] = span(to) + chain.setdefault(r, []).append((('A', i), 'warp', span(to))) + else: + if i < npre: + need(is_target(g[1]), 'prelude scalar writes a non-target', i) + for r in touched(g): + climb(r, span(g[-1]), ('A', i)) + levels = {V + int(t): span(U) for t, U in w['target_levels'].items()} + need(all(current[t] == levels.get(t, ZERO) for t in range(V, 2 * V)), 'target cut levels') + for q, U in zip(w['centers'], w['center_frames']): + U = span(U) + need(current[q] == U, 'centre entry frame', q) + served = {levels.get(g[1], ZERO) for g in w['cut'] if g[2] == q} + for T in sorted(served, key=lambda m: -dim(m)): + need(T & ~U == 0, 'centre descent not nested', q) + d = dim(U) - dim(T) + if d: + bill[d] += 1 + chain.setdefault(q, []).append((('centre',), d, T)) + U = T + at = {} + for k, rec in enumerate(warps, 1): + at.setdefault(rec[0], []).append(k) + for p in range(len(B) + 1): + for k in at.get(p, ()): + _, lender, _, U, E = warps[k - 1] + need(current[lender] == span(U), 'native warp entry frame', k, lender) + current[lender] = span(E) + chain.setdefault(lender, []).append((('warp', k), 'warp', span(E))) + if p < len(B): + for r in touched(B[p]): + climb(r, span(B[p][-1]), ('B', p)) + for i, g in enumerate(w['restore']): + for r in touched(g): + climb(r, span(g[-1]), ('restore', i)) + for r in live: + climb(r, end[r], ('end',)) + restored = set(map(int, w['helper_final'])) + need(all(end[r] == FULL for r in live if r not in restored and not is_target(r)), 'a FULL-cleanup register ends low') + widths = Counter(dim(end[r]) - dim(start[r]) for r in live if r >= 2 * V) + return dict(sorted(bill.items())), dict(sorted(widths.items())), chain, start, end + + +def hygiene(w): + """Inherited structural contract: dyadic scalars, power-of-two scales, wrapper and correction access.""" + entering = set(map(int, w['start_extra'])) + restored = set(map(int, w['helper_final'])) + live = set(range(N)) - set(w['removed']) + for name in ('precondition', 'compensation', 'A', 'cut', 'B', 'restore', 'cleanup'): + for g in w[name]: + if g[0] == 'warp': + continue + q = Q(g[3], g[4]) if g[0] == 'add' else Q(g[2], g[3]) + need(q != 0 and q.denominator & (q.denominator - 1) == 0, 'non-dyadic scalar', name, g) + if g[0] == 'scale': + need(abs(q.numerator) & (abs(q.numerator) - 1) == 0, 'non power-of-two scale', name, g) + for g in w['precondition'] + w['compensation']: + need(not any(r in entering | restored for r in touched(g)), 'wrapper touches an entering or restored helper', g) + for c in w['initial_corrections']: + word = c['operator_word'] + need(is_target(c['target']) and c['source'] in live and c['source'] >= 2 * V + and c['source'] not in entering, 'correction access', c) + need(word and all(w['warps'][abs(o) - 1][1] == c['source'] for o in word), 'correction operator lender', c) + q = Q(c['coefficient']) + need(q != 0 and q.denominator & (q.denominator - 1) == 0, 'correction coefficient', c) + return True + + +# ---------------------------------------------------------------------------- +# Literal inverse cleanup, derived from the contract +# ---------------------------------------------------------------------------- +def ordinary_forward(w): + """Chronological non-wrapper actions whose inverse forms cleanup.""" + out = [g for g in w['A'][w['prelude_events']:]] + at = {} + for k, rec in enumerate(w['warps'], 1): + at.setdefault(rec[0], []).append(['warp', rec[1], k]) + for p in range(len(w['B']) + 1): + out += at.get(p, []) + if p < len(w['B']): + out.append(w['B'][p]) + return out + list(w['restore']) + + +def derive_cleanup(w): + restored = set(map(int, w['helper_final'])) + buf = lambda r: r + N if r in restored else r + full = [256, 128, 64, 32, 16, 8, 4, 2, 1] + out = [] + for g in reversed(ordinary_forward(w)): + if g[0] == 'warp': + out.append(['warp', buf(g[1]), -g[2], full]) + elif is_target(g[1]): + continue + elif g[0] == 'add': + out.append(['add', buf(g[1]), buf(g[2]), -g[3], g[4], full]) + else: + need(g[0] == 'scale', 'unknown primitive', g) + out.append(['scale', buf(g[1]), g[3], g[2], full]) + return out + + +def same_cleanup(a, b): + norm = lambda c: [(g[:-1], span(g[-1])) for g in c] + return len(a) == len(b) and norm(a) == norm(b) + + +# ---------------------------------------------------------------------------- +# Exact free-operator semantics. A value is a dict {(input, word): Fraction}; +# word is a reduced tuple of signed operator ids (leftmost = applied last). +# ---------------------------------------------------------------------------- +def program(w, cleanup=None): + """Literal executed sequence: corrections, wrapper, A, cut, B+warps, restore | cleanup.""" + items = [('corr', c['target'], c['source'], tuple(c['operator_word']), Q(c['coefficient'])) + for c in w['initial_corrections']] + items += w['precondition'] + w['compensation'] + w['A'] + w['cut'] + at = {} + for k, rec in enumerate(w['warps'], 1): + at.setdefault(rec[0], []).append(['warp', rec[1], k]) + for p in range(len(w['B']) + 1): + items += at.get(p, []) + if p < len(w['B']): + items.append(w['B'][p]) + items += w['restore'] + return items, list(w['cleanup'] if cleanup is None else cleanup) + + +def dual_op(op): + return (1 if op > 0 else -1) * (abs(op) + DUAL) + + +def _left(op, word): + return word[1:] if word and word[0] == -op else (op,) + word + + +def _right(word, op): + return word[:-1] if word and word[-1] == -op else word + (op,) + + +def _axpy(dst, src, q): + for key, x in src.items(): + y = dst.get(key, 0) + q * x + if y: + dst[key] = y + else: + dst.pop(key, None) + + +def forward_rows(w, cleanup=None, dual=False, symbolic_buffers=True, snapshot=None): + """Schrodinger pass: every register's value as a combination of initial inputs. + + Live inputs are independent symbols. Private buffers are independent symbols + when symbolic_buffers is set (dirty), otherwise zero. The optional snapshot + callback sees the rows at the cleanup boundary. + """ + removed = set(w['removed']) + live = [r for r in range(N) if r not in removed] + restored = sorted(map(int, w['helper_final'])) + rows = {r: {(r, ()): Q(1)} for r in live} + for c in restored: + rows[c + N] = {(c + N, ()): Q(1)} if symbolic_buffers else {} + prefix, tail = program(w, cleanup) + + def apply(g): + kind = g[0] + if kind == 'add': + t, s, q = g[1], g[2], Q(g[3], g[4]) + need(t != s and q, 'add gate', g) + if dual: + t, s, q = s, t, -q + _axpy(rows[t], rows[s], q) + elif kind == 'scale': + q = Q(g[2], g[3]) + need(q != 0, 'zero scale', g) + if dual: + q = 1 / q + rows[g[1]] = {k: q * x for k, x in rows[g[1]].items()} + elif kind == 'warp': + op = dual_op(g[2]) if dual else g[2] + rows[g[1]] = {(var, _left(op, word)): x for (var, word), x in rows[g[1]].items()} + elif kind == 'corr': + _, t, s, word, c = g + if dual: + src, ops, dst, c = rows[t], [-dual_op(o) for o in word], s, -c + else: + src, ops, dst = rows[s], list(reversed(word)), t + moved = {} + for (var, wd), x in src.items(): + for o in ops: + wd = _left(o, wd) + moved[var, wd] = x + _axpy(rows[dst], moved, c) + else: + raise AuditFailure('unknown primitive ' + repr(g)) + + for g in prefix: + apply(g) + if snapshot is not None: + snapshot(rows) + for g in tail: + apply(g) + return rows + + +def reverse_columns(w, cleanup=None, upto_cleanup=False): + """Heisenberg pull-back: process the forward program backwards. + + cols[s] = {(output, word): coefficient}: the final output register 'output' + contains coefficient*word*x_s. Words grow on the right. Every live input and + every private buffer is an independent symbol. + """ + removed = set(w['removed']) + live = [r for r in range(N) if r not in removed] + restored = sorted(map(int, w['helper_final'])) + regs = live + [c + N for c in restored] + cols = {r: {(r, ()): Q(1)} for r in regs} + prefix, tail = program(w, cleanup) + seq = prefix if upto_cleanup else prefix + tail + for g in reversed(seq): + kind = g[0] + if kind == 'add': + t, s, q = g[1], g[2], Q(g[3], g[4]) + need(t != s and q, 'add gate', g) + _axpy(cols[s], cols[t], q) + elif kind == 'scale': + q = Q(g[2], g[3]) + need(q != 0, 'zero scale', g) + cols[g[1]] = {k: q * x for k, x in cols[g[1]].items()} + elif kind == 'warp': + op = g[2] + cols[g[1]] = {(out, _right(word, op)): x for (out, word), x in cols[g[1]].items()} + elif kind == 'corr': + _, t, s, word, c = g + moved = {} + for (out, wd), x in cols[t].items(): + for o in word: + wd = _right(wd, o) + moved[out, wd] = x + _axpy(cols[s], moved, c) + else: + raise AuditFailure('unknown primitive ' + repr(g)) + return cols + + +def transpose(cols): + rows = {} + for s, col in cols.items(): + for (r, word), x in col.items(): + rows.setdefault(r, {})[s, word] = x + return rows + + +def endpoint_defects(w, rows, dual=False): + """Compare final rows with the contract on the zero-buffer (live-input) domain. + + Returns (bad live registers, dirty buffers, buffer->live leaks, buffer self-map identity). + """ + removed = set(w['removed']) + live = [r for r in range(N) if r not in removed] + restored = sorted(map(int, w['helper_final'])) + bad = [] + for r in live: + expect = {(r, ()): Q(1)} + if dual and r < V: + expect[r + V, ()] = Q(-1) + if not dual and is_target(r): + expect[r - V, ()] = Q(1) + got = {k: x for k, x in rows.get(r, {}).items() if k[0] < N} + if got != expect: + bad.append(r) + dirty = [c for c in restored if any(k[0] < N for k in rows.get(c + N, {}))] + leaks = sorted({r for r in live for k in rows.get(r, {}) if k[0] >= N}) + buffer_identity = all({k: x for k, x in rows.get(c + N, {}).items() if k[0] >= N} == {(c + N, ()): Q(1)} + for c in restored) + return bad, dirty, leaks, buffer_identity + + +def boundary_defects(w, rows): + """Contract at the cleanup boundary (forward): targets sheared, restored helpers clean and isolated.""" + restored = set(map(int, w['helper_final'])) + out = [] + for t in range(V, 2 * V): + if {k: x for k, x in rows[t].items() if k[0] < N} != {(t, ()): Q(1), (t - V, ()): Q(1)}: + out.append(('target', t)) + for c in restored: + if rows[c] != {(c, ()): Q(1)}: + out.append(('restored', c)) + for r, row in rows.items(): + if r < N and r not in restored and any(k[0] in restored for k in row): + out.append(('restored input read', r)) + return out diff --git a/research/staged-644-660-independent-audit/crosscheck_inherited.py b/research/staged-644-660-independent-audit/crosscheck_inherited.py new file mode 100644 index 0000000000..7d45364242 --- /dev/null +++ b/research/staged-644-660-independent-audit/crosscheck_inherited.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +"""Optional differential check (not part of the registered replay or of the independent evidence). + +Compares this package's forward/dual endpoint verdicts with the inherited +PR3133 `audit_local.walg_apply` contract on random mutants of the PR3605 base +word, to detect any misreading of the contract. It deliberately imports the +inherited auditor from main, so it is a fidelity check, not an independent one. +Usage: python3 -I -B crosscheck_inherited.py SEED TRIALS (expected: disagree 0). + +Sagar Thakrar (thakrarsagar), with substantial AI assistance from Claude +(Anthropic, Claude Opus 5.5). Apache-2.0. +""" +import copy, gzip, json, random, sys, types +from fractions import Fraction as Q +from pathlib import Path +PKG = Path(__file__).resolve().parent +REPO = PKG.parents[1] +sys.path.insert(0, str(PKG)) +import audit_core as C +import hashlib +src = REPO / 'research/rank7-coupled-586-588-carrier-fold/vendor/audit_local.py' +if hashlib.sha256(src.read_bytes()).hexdigest() != 'a38940094f7d19cd6376aafdd4734fa68eabc9aff4c98c3c4a3e9540328b1c90': + raise SystemExit('inherited auditor differs from the PR3605-pinned bytes') +audit = types.ModuleType('inherited'); audit.__file__ = str(src) +exec(compile(src.read_bytes(), str(src), 'exec'), audit.__dict__) + +# Program assembly follows the endpoint driver in PR3605 verify.py (RossRichardson), for a like-for-like comparison. +def inherited_endpoint(word, dual): + live = sorted(set(range(704)) - set(word['removed'])); restored = set(map(int, word['helper_final'])) + rows = {r: {(r, ()): Q(1)} for r in live}; rows.update({r + 704: {} for r in restored}) + program = [['corr', c['target'], c['source'], tuple(c['operator_word']), Q(c['coefficient'])] for c in word['initial_corrections']] + program += word['precondition'] + word['compensation'] + word['A'] + word['cut']; warps = {} + for op, rec in enumerate(word['warps'], 1): warps.setdefault(rec[0], []).append(['warp', rec[1], op]) + for i in range(len(word['B']) + 1): + program += warps.get(i, []) + if i < len(word['B']): program.append(word['B'][i]) + program += word['restore'] + word['cleanup'] + for g in program: audit.walg_apply(g, rows, dual, 10 ** 6) + expected = {r: {(r, ()): Q(1)} for r in live} + for t in range(112): expected[t if dual else 112 + t][(112 + t if dual else t, ())] = Q(-1 if dual else 1) + bad = [r for r in live if rows[r] != expected[r]]; dirty = [r for r in restored if rows[r + 704]] + return not bad and not dirty + +def mine(word, dual): + rows = C.forward_rows(word, dual=dual, symbolic_buffers=False) + bad, dirty, leaks, _ = C.endpoint_defects(word, rows, dual=dual) + return not bad and not dirty and not leaks + +w0 = json.loads(gzip.decompress((PKG / 'inputs/STAGED644-660-base.json.gz').read_bytes())) +rng = random.Random(int(sys.argv[1]) if len(sys.argv) > 1 else 3605) +agree = disagree = 0; kinds = {} +for trial in range(int(sys.argv[2]) if len(sys.argv) > 2 else 40): + w = copy.deepcopy(w0); kind = rng.choice(['flipB', 'dropB', 'swapB', 'coefB', 'flipcleanup', 'dropcorr', 'flipcorr', 'none', 'dropcleanupwarp', 'swapwarppos']) + regen = True + if kind == 'flipB': + i = rng.choice([i for i, g in enumerate(w['B']) if g[0] == 'add']); w['B'][i][3] *= -1 + elif kind == 'dropB': + i = rng.randrange(len(w['B'])); w['B'].pop(i) + for rec in w['warps']: + if rec[0] > i: rec[0] -= 1 + elif kind == 'swapB': + i = rng.randrange(len(w['B']) - 1); w['B'][i], w['B'][i + 1] = w['B'][i + 1], w['B'][i] + elif kind == 'coefB': + i = rng.choice([i for i, g in enumerate(w['B']) if g[0] == 'add']); w['B'][i][4] *= 2 + elif kind == 'flipcleanup': + regen = False; i = rng.choice([i for i, g in enumerate(w['cleanup']) if g[0] == 'add']); w['cleanup'][i][3] *= -1 + elif kind == 'dropcleanupwarp': + regen = False; i = rng.choice([i for i, g in enumerate(w['cleanup']) if g[0] == 'warp']); w['cleanup'].pop(i) + elif kind == 'dropcorr': + w['initial_corrections'].pop(rng.randrange(len(w['initial_corrections']))) + elif kind == 'flipcorr': + c = w['initial_corrections'][rng.randrange(len(w['initial_corrections']))]; c['coefficient'] = str(-Q(c['coefficient'])) + elif kind == 'swapwarppos': + k = rng.randrange(len(w['warps'])); w['warps'][k][0] = max(0, w['warps'][k][0] - 1) + if regen: w['cleanup'] = C.derive_cleanup(w) + for dual in (False, True): + a, b = mine(w, dual), inherited_endpoint(w, dual) + kinds.setdefault(kind, []).append((dual, a, b)) + if a == b: agree += 1 + else: disagree += 1; print('DISAGREE', trial, kind, dual, a, b) +print('agree', agree, 'disagree', disagree) +if disagree: + raise SystemExit('verdicts disagree with the inherited contract') +print({k: sum(1 for d, a, b in v if a) for k, v in kinds.items()}, {k: len(v) for k, v in kinds.items()}) diff --git a/research/staged-644-660-independent-audit/inputs/AGGREGATE-INTEGER-FLOW.json.gz b/research/staged-644-660-independent-audit/inputs/AGGREGATE-INTEGER-FLOW.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..104962d079d315f3caf5269ff0e8ff0fbae7fee8 GIT binary patch literal 21785 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 literal 0 HcmV?d00001 diff --git a/research/staged-644-660-independent-audit/inputs/STAGED644-660-extra.json.gz b/research/staged-644-660-independent-audit/inputs/STAGED644-660-extra.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..78e7b2bb0653c8dcc0133980a19dd9d97ebdb67e GIT binary patch literal 72568 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

c^2e-a+VPhAq3>{xXm(b1#L+ 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 Q(1, 1 << (BITS + 8)): + total += term / (2 * k + 1) + term *= y2 + k += 1 + return down(total), up(total + term / (2 * k + 1) / (1 - y2)) + + +def scale(c, iv): + return (down(c * iv[0]), up(c * iv[1])) if c >= 0 else (down(c * iv[1]), up(c * iv[0])) + + +def plus(a, b): + return down(a[0] + b[0]), up(a[1] + b[1]) + + +LN2 = scale(2, atanh(Q(1, 3))) +LN3 = plus(LN2, scale(2, atanh(Q(1, 5)))) # ln 3 = ln 2 + ln(3/2) +LN5 = plus(scale(2, LN2), scale(2, atanh(Q(1, 9)))) # ln 5 = 2 ln 2 + ln(5/4) +LN73 = plus(scale(6, LN2), scale(2, atanh(Q(9, 137)))) # ln 73 = 6 ln 2 + ln(73/64) + + +def ln_ratio(r): + """Interval for ln(73/r), r a positive integer below 73 built from 2, 3, 5.""" + exps, rest = [], r + for p in (2, 3, 5): + e = 0 + while rest % p == 0: + rest //= p + e += 1 + exps.append(e) + need(rest == 1 and 0 < r < M_DIM, 'rank outside the stdlib log table', r) + lo = LN73[0] - sum(e * iv[1] for e, iv in zip(exps, (LN2, LN3, LN5))) + hi = LN73[1] - sum(e * iv[0] for e, iv in zip(exps, (LN2, LN3, LN5))) + return down(lo), up(hi) + + +def exp_interval(t_lo, t_hi): + """exp on [t_lo,t_hi] with 0<=t_lo<=t_hi<1: positive Taylor terms, explicit tail.""" + need(0 <= t_lo <= t_hi < 1, 'exp argument range') + + def partial(t): + total, term, k = Q(0), Q(1), 0 + while term > Q(1, 1 << (BITS + 8)): + total += term + k += 1 + term = term * t / k + return total, term, k + lo, _, _ = partial(t_lo) + hi, term, k = partial(t_hi) + return down(lo), up(hi + term / (1 - t_hi / (k + 1))) + + +LOGS = {} + + +def moment(hist, b): + """Interval enclosure of M(b) for a rational b>0.""" + lo = hi = Q(0) + for r, count in hist.items(): + if r not in LOGS: + LOGS[r] = ln_ratio(r) + e = exp_interval(down(b * LOGS[r][0]), up(b * LOGS[r][1])) + lo += r * count * e[0] + hi += r * count * e[1] + return down(lo / (M_DIM * STOCK)), up(hi / (M_DIM * STOCK)) + + +def bracket(hist, digits): + """Adjacent decimal endpoints C 1: + mid = (a + b) // 2 + lo, hi = moment(hist, mid * unit) + if hi < 1: + a = mid + elif lo > 1: + b = mid + else: + raise RootFailure('interval too wide to decide at %s' % (mid * unit)) + return a * unit, b * unit + + +def decimal_root(hist): + """Second engine: Newton in 70-digit decimal arithmetic; returns the root and a safe error radius.""" + D = decimal.Decimal + with decimal.localcontext(decimal.Context(prec=70, rounding=decimal.ROUND_HALF_EVEN)): + logs = {r: (D(M_DIM) / D(r)).ln() for r in hist} + weights = {r: D(r * c) for r, c in hist.items()} + denom = D(M_DIM * STOCK) + b = D('0.00173') + for _ in range(60): + f = sum(weights[r] * (b * logs[r]).exp() for r in hist) / denom - 1 + df = sum(weights[r] * logs[r] * (b * logs[r]).exp() for r in hist) / denom + step = f / df + b -= step + if abs(step) < D('1e-62'): + break + need(abs(step) < D('1e-62') and df > 1, 'decimal Newton did not settle') + # Each of the ~40 operations per evaluation is correctly rounded at 70 digits; + # |f| error < 1e-66 and df > 1, so 1e-55 is a deliberately loose radius. + return b, D('1e-55') + + +def load_hist(obj): + return {int(k): int(v) for k, v in obj.items()} + + +def aggregate_idle(cert, inventory): + """Recount PR3605's idle histogram from its published aggregate integer witness. + + Groups are [capacity, lo, hi, bins]; x rows are (group, width pattern, count); + z rows are (group, macro-call, width, roles). Checks bin counts, capacities, + the open/closed windows as published, width supply = role flow, and the + per-call demand S*inventory for all 333 macro-calls. The windows themselves + are taken as published, not derived from the source template. + """ + widths, S, groups = cert['widths'], cert['S'], cert['groups'] + need(widths == [4, 5, 6, 7, 8, 9] and S == 20 and len(cert['order']) == 333, 'aggregate shape') + idle, bins, supply, flow, demand = Counter(), Counter(), Counter(), Counter(), Counter() + for g, pattern, n in cert['x']: + used = sum(w * k for w, k in zip(widths, pattern)) + need(n > 0 and min(pattern) >= 0 and used <= groups[g][0] and sum(pattern) <= S, 'pattern', g) + bins[g] += n + if used < groups[g][0]: + idle[groups[g][0] - used] += n + for w, k in zip(widths, pattern): + supply[g, w] += n * k + need(all(bins[g] == S * groups[g][3] for g in range(len(groups))), 'bin inventory') + for g, t, w, n in cert['z']: + need(n > 0 and groups[g][1] < t <= groups[g][2], 'source window', g, t) + flow[g, w] += n + demand[t, w] += n + need(flow == +supply, 'pattern supply differs from role flow') + need(all(demand[t, w] == S * inventory[w] for t in range(333) for w in widths), 'per-call width demand') + return idle, sum(S * g[3] for g in groups), sum(S * g[3] * g[0] for g in groups) + + +def main(): + pr3605 = json.loads((HERE / 'inputs' / 'PR3605-CLAIM.json').read_text(encoding='utf-8')) + pr3148_path = ROOT / 'research/coupled-carrier-cap740/CLAIM.json' + pr3148 = json.loads(pr3148_path.read_text(encoding='utf-8')) + sources = json.loads((HERE / 'SOURCES.json').read_text(encoding='utf-8')) + pins = {row.get('local', row.get('path')): row['sha256'] for row in sources['files'] + sources['snapshot']} + need(hashlib.sha256((HERE / 'inputs' / 'PR3605-CLAIM.json').read_bytes()).hexdigest() == pins['inputs/PR3605-CLAIM.json'], 'PR3605 claim pin') + need(hashlib.sha256(pr3148_path.read_bytes()).hexdigest() == pins['research/coupled-carrier-cap740/CLAIM.json'], 'PR3148 claim pin') + + new, old = load_hist(pr3605['profile']), load_hist(pr3148['profile']) + local_new, local_old = Counter({1: 2439, 2: 726, 3: 224, 4: 102, 5: 20, 8: 8}), Counter(load_hist(pr3148['local_profile'])) + idle_new = Counter({1: 174156, 3: 48334, 4: 1, 5: 10792, 6: 3, 48: 283185}) # PR3605 DERIVATION.md + idle_old = Counter({1: 173160, 3: 48951, 5: 13875, 48: 282569}) # PR3148 README + times = lambda c: Counter({r: CALLS * x for r, x in c.items()}) + need(times(local_new) + idle_new == Counter(new), 'PR3605 H = 6660 L + I') + need(times(local_old) + idle_old == Counter(old), 'PR3148 H = 6660 L + I') + mass = lambda h: sum(r * c for r, c in h.items()) + need(mass(new) == mass(old) == 65088 * 740, 'rank mass invariant') + cert_path = HERE / 'inputs' / 'AGGREGATE-INTEGER-FLOW.json.gz' + need(hashlib.sha256(cert_path.read_bytes()).hexdigest() == pins['inputs/AGGREGATE-INTEGER-FLOW.json.gz'], 'aggregate pin') + audited_widths = {4: 26, 5: 2, 6: 18, 7: 52, 8: 97, 9: 213} # derived from frames by verify.py + idle_count, bin_count, capacity = aggregate_idle(json.loads(gzip.decompress(cert_path.read_bytes())), audited_widths) + need(idle_count == idle_new, 'aggregate witness idle histogram differs from DERIVATION.md', dict(idle_count)) + need(capacity == mass(idle_new) + CALLS * sum(w * c for w, c in audited_widths.items()), 'capacity balance') + cert = json.loads(gzip.decompress(cert_path.read_bytes())) + for label, bad_cert, widths in (('parent widths 7:50/8:99', cert, {**audited_widths, 7: 50, 8: 99}), + ('one pattern record deleted', {**cert, 'x': cert['x'][1:]}, audited_widths), + ('one role-flow record deleted', {**cert, 'z': cert['z'][1:]}, audited_widths)): + try: + aggregate_idle(bad_cert, widths) + except RootFailure: + continue + raise RootFailure('aggregate control accepted: ' + label) + + out = {'status': 'PASS_EXACT_MOMENT_BRACKETS', 'model': 'M(b)=sum_r r*H[r]*(73/r)^b/(73*663040)', + 'rank_mass': mass(new), 'stock_times_dimension': M_DIM * STOCK, 'histograms': {}, + 'aggregate_witness_recount': {'idle': {str(k): v for k, v in sorted(idle_count.items())}, + 'bins': bin_count, 'capacity_rank_units': capacity, + 'scope': 'arithmetic of the published integer witness with the audited ' + 'widths; windows as published; no literal journal or chronology'}} + published = {'PR3605': (new, [Q(x) for x in pr3605['root_interval']], 24), + 'PR3148': (old, [Q(x) for x in pr3148['root']], 25)} + roots = {} + for name, (hist, (c, d), digits) in published.items(): + lo_c, hi_c = moment(hist, c) + lo_d, hi_d = moment(hist, d) + need(hi_c < 1 < lo_d, 'published bracket fails', name) + own = bracket(hist, 30) + dec, radius = decimal_root(hist) + need(Q(dec) - Q(radius) > own[0] and Q(dec) + Q(radius) < own[1], 'decimal engine disagrees', name) + need(c <= own[0] and own[1] <= d, 'own 30-digit bracket outside the published one', name) + roots[name] = own + out['histograms'][name] = { + 'histogram': {str(k): v for k, v in sorted(hist.items())}, + 'published_bracket': [str(c), str(d)], 'published_digits': digits, + 'M_upper_at_C_minus_1': float(hi_c - 1), 'M_lower_at_D_minus_1': float(lo_d - 1), + 'bracket_30_digits': [str(own[0]), str(own[1])], + 'decimal_engine_root_70_digits': str(dec)} + # Counterfactual arithmetic attribution: swap one component at a time. The hybrid + # histograms are not realized owner journals and do not conserve rank mass. + hybrids = {'PR3148 idle + PR3605 local': times(local_new) + idle_old, + 'PR3148 local + PR3605 idle': times(local_old) + idle_new} + attribution = {} + for name, hist in hybrids.items(): + a, b = bracket(dict(hist), 30) + attribution[name] = {'bracket_30_digits': [str(a), str(b)], 'rank_mass': mass(hist), + 'shift_from_PR3148_lower': float(a - roots['PR3148'][0])} + out['attribution'] = attribution + out['root_delta_PR3605_minus_PR3148'] = [str(roots['PR3605'][0] - roots['PR3148'][1]), + str(roots['PR3605'][1] - roots['PR3148'][0])] + # Sensitivity of the PR3605 root to a single idle child of rank 1 or 48 (exact brackets). + sensitivity = {} + for r in (1, 48): + for sign in (1, -1): + hist = dict(new) + hist[r] += sign + a, b = bracket(hist, 30) + sensitivity['%+d rank-%d child' % (sign, r)] = { + 'bracket_30_digits': [str(a), str(b)], + 'shift_from_PR3605_lower': float(a - roots['PR3605'][0])} + out['single_child_sensitivity_PR3605'] = sensitivity + out['local_delta_per_call'] = {str(r): local_new[r] - local_old[r] for r in sorted(set(local_new) | set(local_old)) if local_new[r] != local_old[r]} + out['idle_delta'] = {str(r): idle_new[r] - idle_old[r] for r in sorted(set(idle_new) | set(idle_old)) if idle_new[r] != idle_old[r]} + encoded = json.dumps(out, indent=1, sort_keys=True) + '\n' + if '--write' in sys.argv: + (HERE / 'ROOT-RESULT.json').write_text(encoded, encoding='utf-8', newline='\n') + else: + need((HERE / 'ROOT-RESULT.json').read_text(encoding='utf-8') == encoded, 'ROOT-RESULT.json receipt differs') + print(out['status']) + + +if __name__ == '__main__': + main() diff --git a/research/staged-644-660-independent-audit/verify.py b/research/staged-644-660-independent-audit/verify.py new file mode 100644 index 0000000000..ad48b2920e --- /dev/null +++ b/research/staged-644-660-independent-audit/verify.py @@ -0,0 +1,431 @@ +#!/usr/bin/env python3 +"""Independent semantic audit of PR3605's staged 644/660 words against the PR3133 parent words. + +Checks, for both providers: the parent single-change control, an independent +reconstruction of the changed words from PROOF.md's prose, exact dirty-input +identity in both orientations by two different algorithms, literal inverse +cleanup, chronological binary frames, the local profile and widths, PROOF.md's +written prefix factorization and target tables, the per-register invoice, and +required-failing mutants. Standard library only; exact arithmetic throughout. + +`python3 -I -B verify.py` replays and compares with RESULT.json; `--write` +regenerates that receipt deliberately. + +Sagar Thakrar (thakrarsagar), with substantial AI assistance from Claude +(Anthropic, Claude Opus 5.5). Apache-2.0. +""" +from collections import Counter +import copy +from fractions import Fraction as Q +import gzip +import hashlib +import json +from pathlib import Path +import sys + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[1] +sys.path.insert(0, str(HERE)) +import audit_core as C # noqa: E402 (package-local; its bytes are authenticated in main) +from audit_core import need, AuditFailure # noqa: E402 + +P = [429, 30] # span(429,30): the new entrance and release frame +L = [30] # the old entrance +FULL9 = [256, 128, 64, 32, 16, 8, 4, 2, 1] +RANK8 = [256, 128, 64, 32, 16, 8, 5, 3] +# PROOF.md (PR3605 head 3efbb5de), "Two exact prefix directions": deleted raw +# target writes and the releases inserted before old B599 / old B647. +DELETED = {644: (184, 185, 186, 187), 660: (216, 217, 218, 219)} +RELEASE = {644: (599, ((640, 2), (496, -2))), 660: (647, ((656, -1), (520, -2)))} +TABLE = {644: {135: (Q(1, 2), Q(-1, 4), 0), 146: (Q(-1, 2), Q(1, 4), 0), + 162: (Q(1, 2), Q(-1, 4), 0), 220: (Q(1, 2), Q(1, 4), Q(1, 2))}, + 660: {141: (Q(1, 2), Q(1, 2), 0), 171: (Q(1, 2), Q(-1, 2), Q(1, 2)), + 185: (Q(-1, 2), Q(-1, 2), 0), 196: (Q(1, 2), Q(1, 2), 0)}} +# PROOF.md "Complete local invoice": per pivot, first donor, second donor. +INVOICE = {'pivot': {2: 1, 3: -1}, 'first donor': {1: 1, 2: 1, 3: -1}, 'second donor': {1: 2, 2: -1}} +ROLES = {644: 'pivot', 640: 'first donor', 496: 'second donor', 660: 'pivot', 656: 'first donor', 520: 'second donor'} +OLD_PROFILE = {1: 2433, 2: 724, 3: 228, 4: 102, 5: 20, 8: 8} +NEW_PROFILE = {1: 2439, 2: 726, 3: 224, 4: 102, 5: 20, 8: 8} +OLD_WIDTHS = {4: 26, 5: 2, 6: 18, 7: 50, 8: 99, 9: 213} +NEW_WIDTHS = {4: 26, 5: 2, 6: 18, 7: 52, 8: 97, 9: 213} +ONE_HELPER_PROFILE = {1: 2436, 2: 725, 3: 226, 4: 102, 5: 20, 8: 8} +ONE_HELPER_WIDTHS = {4: 26, 5: 2, 6: 18, 7: 51, 8: 98, 9: 213} + + +def sha(path): + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def load(path): + raw = path.read_bytes() + return json.loads(gzip.decompress(raw) if raw[:2] == b'\x1f\x8b' else raw) + + +def canonical(word): + return hashlib.sha256(json.dumps(word, sort_keys=True, separators=(',', ':')).encode()).hexdigest() + + +def keyed(d): + return {str(k): v for k, v in sorted(d.items())} + + +def authenticate(): + sources = json.loads((HERE / 'SOURCES.json').read_text(encoding='utf-8')) + for row in sources['files']: + if row['usage'] == 'input': + need(sha(ROOT / row['path']) == row['sha256'], 'input pin drift', row['path']) + for row in sources['snapshot']: + need(sha(HERE / row['local']) == row['sha256'], 'snapshot pin drift', row['local']) + + +# ---------------------------------------------------------------------------- +# Independent reconstruction of the staged words from PROOF.md's prose +# ---------------------------------------------------------------------------- +def stage(parent, helpers=(644, 660), entrance=True, delete=True, release=True, restore210=True, + release_frame=P, omit=(), flip=()): + w = copy.deepcopy(parent) + drop, inserts = set(), {} + for h in helpers: + if delete: + for i in DELETED[h]: + g = parent['B'][i] + need(g[0] == 'add' and g[2] == h and C.is_target(g[1]) and g[-1] == L, 'raw target write', h, i) + drop.add(i) + if release: + cut, gates = RELEASE[h] + for j, (donor, q) in enumerate(gates): + if (h, j) in omit: + continue + q = -q if (h, j) in flip else q + inserts.setdefault(cut, []).append(['add', donor, h, q, 1, list(release_frame)]) + if entrance: + need(w['start_extra'][str(h)] == L and str(h) not in w['helper_final'], 'ordinary L-entering helper', h) + w['start_extra'][str(h)] = list(P) + new_b, cutmap = [], {} + for i in range(len(parent['B']) + 1): + cutmap[i] = len(new_b) # warps recorded at old position i fire before the inserted gates + new_b += inserts.get(i, []) + if i < len(parent['B']) and i not in drop: + new_b.append(copy.deepcopy(parent['B'][i])) + w['B'] = new_b + for rec in w['warps']: + rec[0] = cutmap[rec[0]] + if restore210: + need(w['restore'][210] == ['scale', 96, -1, 1, RANK8], 'restore 210 preimage') + w['restore'][210][-1] = list(FULL9) + w['cleanup'] = C.derive_cleanup(w) + return w, cutmap + + +# ---------------------------------------------------------------------------- +# Semantic checks +# ---------------------------------------------------------------------------- +def semantics(w): + """Forward (dirty private buffers) and dual by the Schrodinger pass; forward again by reverse pull-back.""" + boundary = {} + rows = C.forward_rows(w, symbolic_buffers=True, + snapshot=lambda r: boundary.setdefault('d', C.boundary_defects(w, r))) + bad, dirty, leaks, buffer_identity = C.endpoint_defects(w, rows) + drows = C.forward_rows(w, dual=True, symbolic_buffers=False) + dbad, ddirty, _, _ = C.endpoint_defects(w, drows, dual=True) + _, _, dleaks, dbuffer_identity = C.endpoint_defects(w, C.forward_rows(w, dual=True, symbolic_buffers=True), dual=True) + pulled = C.transpose(C.reverse_columns(w)) + pre = C.transpose(C.reverse_columns(w, upto_cleanup=True)) + pre = {r: pre.get(r, {}) for r in set(pre) | set(range(C.N))} + return {'forward_bad_registers': bad, 'forward_dirty_buffers': dirty, 'buffer_to_live_leaks': leaks, + 'dirty_buffers_returned_unchanged': buffer_identity, 'boundary_defects': boundary['d'], + 'dual_bad_registers': dbad, 'dual_dirty_buffers': ddirty, + 'dual_buffer_to_live_leaks': dleaks, 'dual_dirty_buffers_returned_unchanged': dbuffer_identity, + 'reverse_pullback_equals_forward': pulled == {r: v for r, v in rows.items() if v}, + 'reverse_boundary_defects': C.boundary_defects(w, pre), + 'independent_inputs': C.N - len(w['removed']), 'private_buffers': len(w['helper_final']), + 'final_terms': sum(len(v) for v in rows.values())} + + +def semantic_pass(s): + return (not s['forward_bad_registers'] and not s['forward_dirty_buffers'] and not s['buffer_to_live_leaks'] + and not s['boundary_defects'] and not s['dual_bad_registers'] and not s['dual_dirty_buffers'] + and s['reverse_pullback_equals_forward'] and not s['reverse_boundary_defects'] + and s['dirty_buffers_returned_unchanged'] and s['dual_dirty_buffers_returned_unchanged'] + and not s['dual_buffer_to_live_leaks'] + and s['independent_inputs'] == 632 and s['private_buffers'] == 91) + + +def execute(rows, items): + """Literal forward execution of primitive items on the given symbolic rows.""" + for g in items: + if g[0] == 'corr': + _, t, s, word, c = g + moved = {} + for (var, wd), x in rows[s].items(): + for o in reversed(word): + wd = C._left(o, wd) + moved[var, wd] = x + C._axpy(rows[t], moved, c) + elif g[0] == 'add': + need(g[1] != g[2], 'self add') + C._axpy(rows[g[1]], rows[g[2]], Q(g[3], g[4])) + elif g[0] == 'scale': + q = Q(g[2], g[3]) + rows[g[1]] = {key: q * x for key, x in rows[g[1]].items()} + elif g[0] == 'warp': + rows[g[1]] = {(var, C._left(g[2], wd)): x for (var, wd), x in rows[g[1]].items()} + else: + raise AuditFailure('unknown primitive') + return rows + + +def prefix_rows(w, k, before=()): + """All register rows after the program prefix ending just before B[k] (warps recorded at k included).""" + removed = set(w['removed']) + rows = {r: {(r, ()): Q(1)} for r in range(C.N) if r not in removed} + items = [('corr', c['target'], c['source'], tuple(c['operator_word']), Q(c['coefficient'])) + for c in w['initial_corrections']] + items += w['precondition'] + w['compensation'] + w['A'] + w['cut'] + at = {} + for op, rec in enumerate(w['warps'], 1): + at.setdefault(rec[0], []).append(['warp', rec[1], op]) + for p in range(k + 1): + items += at.get(p, []) + if p < k: + items.append(w['B'][p]) + return execute(rows, list(before) + items) + + +def prefix_identity(parent, new, cutmap): + """PROOF.md: P_new = P_old S1 S2 on every register at the boundary after the old-B647 releases.""" + s_gates = [['add', d, h, q, 1, P] for h in (644, 660) for d, q in RELEASE[h][1]] + old = prefix_rows(parent, 647, s_gates) + new_rows = prefix_rows(new, cutmap[647] + len(RELEASE[660][1])) + unchanged = prefix_rows(parent, 647) + moved = sorted(r for r in old if old[r] != unchanged[r]) + return old == new_rows, moved + + +def target_tables(parent, k): + table = {} + rows = prefix_rows(parent, k) + for t in range(C.V, 2 * C.V): + for (var, word), x in rows[t].items(): + if var in ROLES: + need(word == (), 'operator word on a pivot column', t, var, word) + table.setdefault(t, {})[var] = x + return table + + +def check_tables(table): + out = {} + for h, expect in TABLE.items(): + cols = (h, *[d for d, _ in RELEASE[h][1]]) + v = (1, *[q for _, q in RELEASE[h][1]]) + got = {t: tuple(table.get(t, {}).get(c, 0) for c in cols) for t in range(C.V, 2 * C.V) + if any(table.get(t, {}).get(c, 0) for c in cols)} + need(got == expect, 'PROOF.md target table differs', h, got) + need(all(sum(a * b for a, b in zip(row, v)) == 0 for row in got.values()), 'table does not kill v', h) + out[str(h)] = {str(t): [str(x) for x in row] for t, row in sorted(got.items())} + return out + + +def register_bills(chain): + out = {} + for r, events in chain.items(): + c = Counter(d for _, d, _ in events if isinstance(d, int) and d > 0) + if c: + out[r] = c + return out + + +def bill_delta(a, b): + return {k: b.get(k, 0) - a.get(k, 0) for k in sorted(set(a) | set(b)) if b.get(k, 0) != a.get(k, 0)} + + +# ---------------------------------------------------------------------------- +# Mutants +# ---------------------------------------------------------------------------- +def evaluate(word, want_semantics=True): + out = {} + try: + bill, widths, _, _, _ = C.frame_bill(word) + out.update(frames='PASS', profile=keyed(bill), widths=keyed(widths)) + except AuditFailure as e: + out['frames'] = 'FAIL: ' + str(e) + if want_semantics: + rows = C.forward_rows(word, symbolic_buffers=True) + bad, dirty, leaks, _ = C.endpoint_defects(word, rows) + out['forward'] = 'PASS' if not (bad or dirty or leaks) else 'FAIL' + out['forward_bad_targets'] = [r for r in bad if C.is_target(r)] + out['forward_bad_other'] = [r for r in bad if not C.is_target(r)] + out['forward_dirty_buffers'] = dirty + dbad, ddirty, _, _ = C.endpoint_defects(word, C.forward_rows(word, dual=True, symbolic_buffers=False), dual=True) + out['dual'] = 'PASS' if not (dbad or ddirty) else 'FAIL' + return out + + +def mutants(parent, new): + res = {} + for h in (644, 660): + for j in range(2): + donor = RELEASE[h][1][j][0] + res['omit release %d->%d' % (h, donor)] = evaluate(stage(parent, omit={(h, j)})[0]) + res['flip release %d->%d' % (h, donor)] = evaluate(stage(parent, flip={(h, j)})[0]) + res['flip both releases of %d' % h] = evaluate(stage(parent, flip={(h, 0), (h, 1)})[0]) + res['releases added but raw target writes kept'] = evaluate(stage(parent, delete=False)[0]) + res['entrance change only, on the parent'] = evaluate( + stage(parent, delete=False, release=False, restore210=False)[0], want_semantics=False) + res['old [30] entrance kept'] = evaluate(stage(parent, entrance=False)[0]) + res['releases at frame [30]'] = evaluate(stage(parent, release_frame=L)[0], want_semantics=False) + res['restore-210 frame edit dropped'] = evaluate(stage(parent, restore210=False)[0]) + for h in (644, 660): + res['%d-only staged edit' % h] = evaluate(stage(parent, helpers=(h,), restore210=False)[0]) + stale = copy.deepcopy(new) + stale['cleanup'] = copy.deepcopy(parent['cleanup']) + res['parent cleanup on the changed word'] = evaluate(stale) + short = copy.deepcopy(new) + del short['cleanup'][next(i for i, g in enumerate(short['cleanup']) if g[0] == 'add' and 644 in g[1:3])] + res['first 644 cleanup gate removed'] = evaluate(short) + return res + + +def require_mutants(m): + release_mutants = [k for k in m if k.startswith(('omit', 'flip'))] + ['releases added but raw target writes kept'] + for k in release_mutants: + need(m[k]['forward'] == 'FAIL' and m[k]['forward_bad_targets'], 'release mutant not rejected at a target', k) + for k in ('parent cleanup on the changed word', 'first 644 cleanup gate removed'): + need(m[k]['forward'] == 'FAIL', 'cleanup mutant accepted', k) + for k in ('entrance change only, on the parent', 'releases at frame [30]'): + need(m[k]['frames'].startswith('FAIL: frame containment fails'), 'frame mutant accepted', k) + old_entry = m['old [30] entrance kept'] + need(old_entry['forward'] == old_entry['dual'] == 'PASS', 'old-entrance word keeps the identity') + need(old_entry['profile'] == keyed(Counter(NEW_PROFILE) + Counter({1: 2})) + and old_entry['widths'] == keyed(OLD_WIDTHS), 'old-entrance bill') + drop210 = m['restore-210 frame edit dropped'] + need(drop210['forward'] == drop210['dual'] == 'PASS' and drop210['profile'] == keyed(NEW_PROFILE) + and drop210['widths'] == keyed(NEW_WIDTHS), 'restore-210 edit bill-neutral') + for h in (644, 660): + one = m['%d-only staged edit' % h] + need(one['forward'] == one['dual'] == 'PASS', 'single-helper identity', h) + need(one['profile'] == keyed(ONE_HELPER_PROFILE) and one['widths'] == keyed(ONE_HELPER_WIDTHS), + 'single-helper bill', h) + + +# ---------------------------------------------------------------------------- +def provider(tag): + parent_path = ROOT / ('research/rank7-coupled-586-588-carrier-fold/edits/FINAL-WORD-%s.json.gz' % tag) + new_path = HERE / 'inputs' / ('STAGED644-660-%s.json.gz' % tag) + parent, new = load(parent_path), load(new_path) + record = load(HERE / 'inputs' / ('STAGED-PAIR-RECORD-%s.json.gz' % tag)) + out = {} + # (a) single-change control: the unchanged PR3133 parent word + need(canonical(parent) == record['source_canonical_sha256'], 'parent canonical digest') + need(sha(parent_path) == record['source_compressed_sha256'], 'parent compressed digest') + C.hygiene(parent) + pbill, pwidths, pchain, _, _ = C.frame_bill(parent, lagrangian=True) + need(pbill == OLD_PROFILE and pwidths == OLD_WIDTHS, 'parent control table', pbill, pwidths) + need(C.same_cleanup(C.derive_cleanup(parent), parent['cleanup']), 'parent cleanup is not the literal inverse') + psem = semantics(parent) + need(semantic_pass(psem), 'parent control semantics', psem) + out['parent_control'] = {'canonical_sha256': canonical(parent), 'profile': keyed(pbill), 'widths': keyed(pwidths), + 'cleanup_literal_inverse': True, 'inherited_hygiene': True, 'semantics': psem} + # (b) independent reconstruction and full audit of the changed word + rebuilt, cutmap = stage(parent) + declared = {'deleted': [[r['index'], r['old']] for r in record['B_deleted']], + 'inserted': [[r['before'], r['gates']] for r in record['B_inserted']], + 'frames': [record['A_frame_edits'], record['B_frame_edits'], + [[r['index'], r['old'], r['new']] for r in record['restore_frame_edits']]], + 'starts': record['start_frames']} + prose = {'deleted': [[i, parent['B'][i]] for h in (644, 660) for i in DELETED[h]], + 'inserted': [[RELEASE[h][0], [['add', d, h, q, 1, P] for d, q in RELEASE[h][1]]] for h in (644, 660)], + 'frames': [[], [], [[210, RANK8, FULL9]]], + 'starts': {str(h): {'old': L, 'new': P} for h in (644, 660)}} + need(declared == prose, 'declared edit record differs from PROOF.md prose') + need(canonical(new) == record['target_canonical_sha256'], 'changed canonical digest') + need(sha(new_path) == record['target_compressed_sha256'], 'changed compressed digest') + need(set(rebuilt) == set(new), 'field set') + differing = sorted(k for k in new if k not in ('cleanup', 'report') and new[k] != rebuilt[k]) + need(not differing, 'PROOF.md reconstruction differs from the shipped word', differing) + need(C.same_cleanup(rebuilt['cleanup'], new['cleanup']), 'shipped cleanup is not the literal inverse') + C.hygiene(new) + nbill, nwidths, nchain, nstart, nend = C.frame_bill(new, lagrangian=True) + need(nbill == NEW_PROFILE and nwidths == NEW_WIDTHS, 'changed profile/widths', nbill, nwidths) + need({int(k): v for k, v in new['report']['local_profile'].items()} == nbill + and {int(k): v for k, v in new['report']['width_inventory'].items()} == nwidths, 'report fields') + nsem = semantics(new) + need(semantic_pass(nsem), 'changed word semantics', nsem) + out['changed_word'] = {'canonical_sha256': canonical(new), 'reconstructed_from_PROOF_prose': True, + 'declared_record_equals_PROOF_prose': True, 'inherited_hygiene': True, + 'profile': keyed(nbill), 'widths': keyed(nwidths), 'cleanup_literal_inverse': True, + 'semantics': nsem, + 'entrance_frame_points': {str(h): C.points(nstart[h]) for h in (644, 660)}, + 'terminal_frames_full': all(nend[h] == C.FULL for h in (644, 660)), + 'release_positions_new_B': [cutmap[599], cutmap[647]]} + # (c) second method: per-register written invoice, prefix factorization, target tables + pb, nb = register_bills(pchain), register_bills(nchain) + changed = {r: bill_delta(pb.get(r, {}), nb.get(r, {})) for r in sorted(set(pb) | set(nb)) + if bill_delta(pb.get(r, {}), nb.get(r, {}))} + need(set(changed) == set(ROLES), 'registers whose bill changes', sorted(changed)) + need(all(changed[r] == INVOICE[ROLES[r]] for r in ROLES), 'PROOF.md per-register invoice', changed) + total = Counter() + for d in changed.values(): + total.update(d) + need(dict(total) == bill_delta(OLD_PROFILE, NEW_PROFILE), 'invoice sum') + same, moved = prefix_identity(parent, new, cutmap) + need(same, 'P_new != P_old S1 S2 at the old-B647 boundary') + tables = check_tables(target_tables(parent, 599)) + need(tables == check_tables(target_tables(parent, 647)), 'tables move between the cuts') + out['second_method'] = { + 'per_register_bill_delta': {str(r): keyed(d) for r, d in changed.items()}, + 'roles': {str(r): ROLES[r] for r in ROLES}, 'sum': keyed(total), + 'register_96_bill_unchanged': pb.get(96) == nb.get(96), + 'prefix_identity_all_registers': same, 'registers_moved_by_S': moved, + 'target_tables_before_old_B599_and_B647': tables} + # (d) mutants + m = mutants(parent, new) + require_mutants(m) + out['mutants'] = m + return out + + +def self_test(): + """Interpreter sanity on tiny words: operator order, cancellation, dual symbols, pull-back agreement.""" + tiny = {'removed': list(range(226, C.N)), 'helper_final': {}, 'initial_corrections': [], 'precondition': [], + 'compensation': [], 'A': [], 'cut': [], 'warps': [], 'restore': [], 'cleanup': [], + 'B': [['warp', 224, 1], ['warp', 224, 2], ['add', 225, 224, 3, 2, []], ['warp', 224, -2]]} + rows = C.forward_rows(tiny, symbolic_buffers=False) + need(rows[224] == {(224, (1,)): Q(1)} and rows[225] == {(225, ()): Q(1), (224, (2, 1)): Q(3, 2)}, 'free-group order') + need(C.transpose(C.reverse_columns(tiny)) == {r: v for r, v in rows.items() if v}, 'pull-back disagrees on tiny word') + dual = C.forward_rows(tiny, dual=True, symbolic_buffers=False) + # contragredient: 224 <- D1 x224 - 3/2 D2^{-1} x225, with D_k = K_k^{-T} independent symbols + need(dual[224] == {(224, (1 + C.DUAL,)): Q(1), (225, (-(2 + C.DUAL),)): Q(-3, 2)} + and dual[225] == {(225, ()): Q(1)}, 'dual symbols') + need(C.dual_op(-7) == -(7 + C.DUAL) and C._left(5, (-5, 3)) == (3,) and C._right((3, -5), 5) == (3,), 'reduction') + swapped = copy.deepcopy(tiny) + swapped['B'][0][2], swapped['B'][1][2] = 2, 1 + need(C.forward_rows(swapped, symbolic_buffers=False)[225] != rows[225], 'operator order ignored') + + +def main(): + self_test() + authenticate() + result = {'status': 'PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT', + 'scope': 'Finite exact local audit of PR3605 head 3efbb5de words against the PR3133 parent words: ' + 'free-operator dirty-input identity (forward with symbolic private buffers, contragredient ' + 'dual, reverse pull-back), literal inverse cleanup, binary-frame chronology/profile/widths, ' + 'PROOF.md prefix factorization, tables and invoice, and mutants. No native Gaussian phase, ' + 'owner journal, complete admission, kappa or frontier claim.', + 'providers': {}} + for tag in ('base', 'extra'): + result['providers'][tag] = provider(tag) + print('CHECKED', tag, 'parent control, changed word, second method,', + len(result['providers'][tag]['mutants']), 'mutants', flush=True) + need(result['providers']['base']['changed_word']['profile'] == result['providers']['extra']['changed_word']['profile'], + 'providers disagree') + encoded = json.dumps(result, indent=1, sort_keys=True, default=str) + '\n' + if '--write' in sys.argv: + (HERE / 'RESULT.json').write_text(encoded, encoding='utf-8', newline='\n') + else: + need((HERE / 'RESULT.json').read_text(encoding='utf-8') == encoded, 'RESULT.json receipt differs') + print(result['status']) + + +if __name__ == '__main__': + main() From e898b43d53341ef44db75f3450ab4952ec50e2b9 Mon Sep 17 00:00:00 2001 From: Sagar Thakrar <18622288+thakrarsagar@users.noreply.github.com> Date: Sun, 18 Oct 2026 19:20:40 +0530 Subject: [PATCH 2/4] Revise staged 644/660 audit after review round 1 Split the root sensitivity into mass-changing errors (group capacities, bin counts, widths: one rank-48 idle child moves the root by 3.498e-7, more than the gain) and mass-conserving placement errors at fixed groups and widths (exact intervals: at least 98 rank-48 -> 48 x rank-1 relabels, i.e. more than 4,656 units of idle mass, are needed to cancel the gain over PR3148; 3 to drop below 0.00173). Reimplement the remaining verify_aggregate.py legality checks in root.py (types/ranges, duplicates, per-copy group capacity, inventory and profile fields) with two more rejecting controls. Name #3642/#3653 as consumers whose RETIMED644-660 words are not covered, reorder open questions, and note concurrent #3659. Credit Arham Tahir's coupled-carrier audit as the structural model of audit_core.py, label the lifted-Lagrangian check as implied by the frame map, and pin check_residual.py, verify_aggregate.py, audit_local.py and Arham Tahir's verify.py in SOURCES.json. Co-Authored-By: Claude Opus 5.5 --- .../README.md | 367 ++++++++++++------ .../ROOT-RESULT.json | 47 ++- .../SOURCES.json | 30 +- .../TASK.json | 34 +- .../VERIFY.json | 2 +- .../audit_core.py | 15 +- .../staged-644-660-independent-audit/root.py | 99 ++++- .../verify.py | 2 +- 8 files changed, 429 insertions(+), 167 deletions(-) diff --git a/research/staged-644-660-independent-audit/README.md b/research/staged-644-660-independent-audit/README.md index 2c89b02178..c416d47848 100644 --- a/research/staged-644-660-independent-audit/README.md +++ b/research/staged-644-660-independent-audit/README.md @@ -1,20 +1,31 @@ # Independent audit of PR3605's staged 644/660 words -**All four audited claims of PR3605 hold at head `3efbb5de` for both providers.** -A new standard-library interpreter, which does not import the inherited auditor, -confirms the following. The changed `base` and `extra` words are exact -arbitrary-dirty identities in both orientations, with 632 independent inputs and -91 private buffers. Their cleanup is the literal inverse cleanup. Their chronological -binary frames give the local profile +PR3605 replaces eight early raw helper writes with four later donor releases, +so that helpers 644 and 660 drop from width 8 to width 7. This package checks +that change with a separately written exact interpreter, using the unchanged +parent words as the single-change control. **The changed words pass at head +`3efbb5de` for both providers**: they are exact identities, their cleanup is the +literal inverse, and their binary frames give exactly the claimed profile and +widths. A pass makes these words an independently checked local input for the +open staged-width chain that reuses them unchanged. It does not cover the +retimed words of #3642/#3653, the native phases of the new entrance frame, or +any owner journal. Those remain load-bearing. + +In detail, the changed `base` and `extra` words are exact arbitrary-dirty +identities in both orientations, with 632 independent inputs and 91 private +buffers. Their chronological binary frames give the local profile `{1:2433,2:724,3:228,4:102,5:20,8:8} -> {1:2439,2:726,3:224,4:102,5:20,8:8}` -and the helper widths `8:99 -> 97`, `7:50 -> 52`. The published complex-root -brackets of PR3605 and PR3148 also hold. An exact rational interval engine -checks them, and a 70-digit decimal engine cross-checks the result. +and the helper widths `8:99 -> 97`, `7:50 -> 52`. For PR3605's fourth claim, +the root, the check is narrower: exact arithmetic confirms the published +PR3605 and PR3148 root brackets **on their published histograms**, and recounts +PR3605's idle histogram from its aggregate owner witness, with the witness's +windows taken as published. This is a finite exact **audit** of one local supplier change. It makes no κ -claim and no frontier change. It does not check native Gaussian phases, the -owner journal, complete admission or the inherited all-size hypotheses (see -Scope). The selected record stays `0.001672660197076918`. +claim and no frontier change, and it admits none of the PRs named below. It +does not check native Gaussian phases, owner journals, complete admission or +the inherited all-size hypotheses (see Scope). The selected record stays +`0.001672660197076918`. ## What was audited @@ -31,16 +42,29 @@ and keep FULL terminals. The single-change control is dcharb78's unchanged (`51eb9c4e`, byte-identical on main). The root control is Jeremy Diviney's merged [PR3148](https://github.com/CrocSwap/integer-mult-bounds/pull/3148) (`f2927a4b`). -The open staged-width κ>0.00173 chain (#3624, #3626, #3633, #3638 and the #3630 -successor) reuses these words unchanged. On 2026-10-18 the GitHub API showed -byte-identical copies at these heads: #3624 `515a7c44`, #3626 `659fd5e7` and -#3633 `72c268f1` add word blobs `dc6d321b`/`78e7b2bb` and record blobs -`042dbc69`/`67f04ae3`. The same blobs sit inside #3638 `d62e1acd`'s vendored -`PR3624-SOURCE.tar.gz` and #3630 `bcac7fe0`'s `PR3605-SOURCES.tar.gz`. +**Who consumes these words** (GitHub API, 2026-10-18, heads re-checked before +submission): + +- *Unchanged reuse.* #3624 `515a7c44`, #3626 `659fd5e7` and #3633 `72c268f1` add + word blobs `dc6d321b`/`78e7b2bb` and record blobs `042dbc69`/`67f04ae3`. The + same blobs sit inside #3638 `d62e1acd`'s vendored `PR3624-SOURCE.tar.gz` and + #3630 `bcac7fe0`'s `PR3605-SOURCES.tar.gz`. For these PRs, the audited words + are the supplier words. +- *Parent only.* #3642 `044d24f1` (roger-sato, T530) and the draft #3653 + `607a09ff` (rohanarun, T488, vendoring #3642) carry the same STAGED blobs, but + their claims run `RETIMED644-660` words (`d69125e0`/`f3c580b0`). Those add two + commuting release retimings on top of the audited words, and **they are not + checked here**. Only their STAGED parent is. These are currently the two + highest staged-width claims. + PR3605's own semantic check runs the pinned inherited interpreter (`audit_local.py`). This package supplies a separately implemented check of -those exact words. It does not check those PRs' own owner journals or roots -and does not admit any of them. +the STAGED words. It does not check any of these PRs' own owner journals or +roots. Concurrent work: #3659 (jwr404) independently recomputes the PR3605 +T740 histogram mass and root bracket, and #3661 does the same for a T450 +allocation. This package's distinct parts are the word semantics, the +PR3148 delta attribution, the aggregate-witness recount and the sensitivity +analysis. | Quantity (each provider) | PR3133 parent (control) | PR3605 changed word | |---|---|---| @@ -50,31 +74,44 @@ and does not admit any of them. | Forward (dirty buffers), dual, reverse pull-back | PASS | PASS | | Cleanup equals the literal inverse | yes | yes | -The profile delta is `+6 H1 + 2 H2 - 4 H3` (local rank mass −2 per call). It is -confined to exactly six registers, and each change equals PROOF.md's written -invoice: pivots 644/660 `+H2 - H3`, first donors 640/656 `+H1 + H2 - H3`, -second donors 496/520 `+2 H1 - H2`. Applying either helper's edit alone keeps -the identity and moves the profile by `+3 H1 + H2 - 2 H3`. The two helpers' -shares are therefore separable and additive. +Per call, the profile changes by +6 rank-1, +2 rank-2 and −4 rank-3 children +(local rank mass −2). The change is confined to exactly six registers, and +each register's change equals PROOF.md's written invoice: + +- pivots 644/660: +1 rank-2, −1 rank-3; +- first donors 640/656: +1 rank-1, +1 rank-2, −1 rank-3; +- second donors 496/520: +2 rank-1, −1 rank-2. + +Applying either helper's edit alone keeps the identity and moves the profile by ++3 rank-1, +1 rank-2 and −2 rank-3 children. The two helpers' shares are +therefore separable and additive. ## Method and independence The registered verifiers (`audit_core.py`, `verify.py`, `root.py`) import only -the standard library. The word format and contract were read from PR3133/PR3605 -and the inherited `audit_local.py`. No code was imported or copied from them or -from the earlier `coupled-carrier-independent-audit` (Arham Tahir). The optional -cross-check below is the only exception: it imports the inherited auditor on -purpose. +the standard library. Nothing is imported or copied from the audited authors' +code (the PR3133/PR3605 producers, cleanup generators or the inherited +`audit_local.py`). The word format and contract were read from those pinned +sources. `root.py`'s aggregate legality checks re-implement the check list of +PR3605's `owners/verify_aggregate.py` without importing it. + +The checks are not independent of every earlier audit, though. +`audit_core.py`'s frame bill and free-word structure re-implement, without +importing, Arham Tahir's merged `coupled-carrier-independent-audit/verify.py`. +That includes the point-set spans, the warp-frame and lifted-frame checks, +target levels keyed by register, and the dual symbol naming. The two audits +therefore share a reading of the contract. The optional cross-check below +imports the inherited auditor on purpose. - **Identity, algorithm 1 (forward values).** Each register's value is propagated as exact rational combinations of `(input, reduced free-group word)`. Warps are independent invertible free symbols. All 632 live inputs **and the - 91 private buffers** are independent symbols, so the buffers are dirty. The - check requires `y_t -> y_t + x_t` with every other live input restored, and no - buffer contribution in any live register. With dirty buffers, every buffer is - returned unchanged in both orientations. At the cleanup boundary, targets - are sheared and the 91 restored helpers equal their own inputs and are read - nowhere else. + 91 private buffers** are independent symbols, so the buffers are dirty. + - The check requires `y_t -> y_t + x_t` with every other live input restored, + and no buffer contribution in any live register. + - With dirty buffers, every buffer is returned unchanged in both orientations. + - At the cleanup boundary, targets are sheared, and the 91 restored helpers + equal their own inputs and are read nowhere else. - **Dual.** The contragredient circuit is run separately with independent `K^-T` symbols and must give `x_s -> x_s - y_s` with clean buffers. - **Identity, algorithm 2 (reverse pull-back).** The program is processed @@ -84,31 +121,41 @@ purpose. boundary contract. - **Frames.** Subspaces of `F_2^9` are stored as 512-point masks. Each gate's frame must contain the current frame of every register it touches. The checks - also cover warp frame maps and the lifted Lagrangian action of all 72 warps, - centre descents, target levels and end frames. The profile and widths are derived from these frame - chains; report fields are compared only afterwards. The inherited structural - rules are also checked: dyadic scalars, power-of-two scales, and wrapper and - correction access. + also cover: + - the frame maps of all 72 warps; + - centre descents, target levels and end frames; + - the inherited structural rules: dyadic scalars, power-of-two scales, and + wrapper and correction access. + + The lifted-Lagrangian action is also computed for every warp. For an + invertible warp it follows from the frame-map check, so it only checks the + implementation and adds no evidence. The profile and widths are derived from + the frame chains; report fields are compared only afterwards. - **Reconstruction.** Each changed word is rebuilt from the parent using only - PROOF.md's prose. Every field except cleanup must equal the shipped word, and - cleanup must equal the independently derived literal inverse. Canonical and - compressed digests must match PR3605's records, and the declared edit record - must equal the prose. + PROOF.md's prose. + - Every field except cleanup must equal the shipped word. + - Cleanup must equal the independently derived literal inverse. + - Canonical and compressed digests must match PR3605's records. + - The declared edit record must equal the prose. - **Second method (written argument).** Two parts of PROOF.md are checked - symbolically. First, `P_new = P_old S1 S2` holds on **every register** at - the boundary after the old-B647 releases. The S matrices change exactly - the four donors and the eight tabled targets. Second, the two four-row target - tables hold exactly at old B599 and B647, every other target has zero - columns, and each table kills its `v`. A per-register frame invoice is also - computed and compared with PROOF.md's written per-pivot histograms. + symbolically: + - `P_new = P_old S1 S2` holds on **every register** at the boundary after the + old-B647 releases, and the S matrices change exactly the four donors and the + eight tabled targets; + - the two four-row target tables hold exactly at old B599 and B647, every + other target has zero columns, and each table kills its `v`. + + A per-register frame invoice is also computed and compared with PROOF.md's + written per-pivot histograms. - **Contract fidelity (optional; not in the registered replay).** `crosscheck_inherited.py SEED TRIALS` compares this package's forward and dual - verdicts with the pinned inherited interpreter on random mutants of the - `base` word. The mutants flip, drop or swap B gates, change coefficients, - flip or drop cleanup gates, drop or flip corrections, and shift warps. Seeds - `3605 40` and `44 60` gave 200 of 200 agreeing verdicts. This script imports - the inherited auditor, so it checks that the contract was read correctly. It - is not independent evidence. + verdicts with the inherited interpreter on random mutants of the `base` word. + That interpreter is pinned by SHA256 in the script and in SOURCES.json. The + mutants flip, drop or swap B gates, change coefficients, flip or drop cleanup + gates, drop or flip corrections, and shift warps. Seeds `3605 40` and `44 60` + gave 200 of 200 agreeing verdicts. This script imports the inherited auditor, + so it checks that the contract was read correctly. It is not independent + evidence. ## Required-failing mutants (19 per provider, all as predicted) @@ -119,28 +166,31 @@ purpose. | Add releases but keep the raw target writes | frame containment fails at B184; identity fails at `162,171,196,220` | | Entrance `span(429,30)` alone on the parent | frame containment fails at B184 (helper 644) | | Releases at frame `[30]` | frame containment fails at the first release | -| Parent cleanup on the changed word / one cleanup gate removed | identity fails (donors 496,520,640,656 left dirty / helpers dirty) | -| Keep the old `[30]` entrance | identity holds; profile `+2 H1`, widths back to `8:99, 7:50` | +| Parent cleanup on the changed word | identity fails at donors `496,520,640,656` (no buffer is left dirty) | +| First 644 cleanup gate removed | identity fails at 19 helper registers `225…644` (no buffer is left dirty) | +| Keep the old `[30]` entrance | identity holds; profile = changed word + 2 rank-1 children (`{1:2441,…}`); rank mass and widths return to the parent's `8:99, 7:50` | | Drop the restore-210 frame edit | identity and bill unchanged (that edit is bill-neutral) | -| 644-only or 660-only edit | identity holds; profile `{1:2436,2:725,3:226,…}`, widths `7:51, 8:98` | +| 644-only or 660-only edit (restore-210 edit not applied; bill-neutral) | identity holds; profile `{1:2436,2:725,3:226,…}`, widths `7:51, 8:98` | The old-entrance mutant shows that, within these words, the entire rank-mass saving of 2 comes from the entrance frame. With the old entrance, the staged releases leave local rank mass unchanged. The physical legitimacy of the `span(429,30)` entrance therefore rests on the native wrapper identity -`L^-1 T_F T_P^-1 R^-1 = C_[7] ⊗ I_[2]` (PR3605 `check_residual.py`). That -identity is shared by every downstream PR and is not independently checked here -(open question 2). +`L^-1 T_F T_P^-1 R^-1 = C_[7] ⊗ I_[2]` (PR3605 `check_residual.py`, pinned in +SOURCES.json but not run). Every consumer above shares that identity, and it is +not independently checked here (open question 1). ## Root brackets and attribution `root.py` uses `M(b) = Σ_r r·H[r]·(73/r)^b / (73·663040)` (PR3605 DERIVATION.md) -on the published complete histograms. Its primary engine is outward-rounded -exact rational interval arithmetic: atanh/Taylor series with explicit -remainders on a `2^-320` grid. The second engine is 70-digit decimal Newton -iteration. During preparation, python-flint 0.9.0 arb at 400 bits reproduced -both `M(C)-1` and `M(D)-1` to all printed digits. That third check is not -part of the shipped replay. +on the published complete histograms. + +- **Primary engine:** outward-rounded exact rational interval arithmetic, using + atanh/Taylor series with explicit remainders on a `2^-320` grid. +- **Second engine:** 70-digit decimal Newton iteration. +- **Third check, preparation only:** python-flint 0.9.0 arb at 400 bits + reproduced both `M(C)-1` and `M(D)-1` to all printed digits. It is not part + of the shipped replay. | Histogram | Published bracket | Confirmed 30-digit bracket | |---|---|---| @@ -149,41 +199,88 @@ part of the shipped replay. The root delta is `+2.29054860244835118950648e-7` to `…650e-7`. Both histograms have the same rank mass, `48,165,120 = 65088·740`. The -decomposition is `H = 6660·L + I`, with the local change `+6H1+2H2−4H3` per -call and the idle change `{1:+996, 3:−617, 4:+1, 5:−3083, 6:+3, 48:+616}`. +decomposition is `H = 6660·L + I`. The local change is +6 rank-1, +2 rank-2 +and −4 rank-3 children per call. The idle change is +`{1:+996, 3:−617, 4:+1, 5:−3083, 6:+3, 48:+616}`. + Swapping one component at a time does not conserve mass and moves the root by about ±9.7e-5. Those hybrids (0.0018266 and 0.0016331) are arithmetic counterfactuals, not realized journals. **The net gain is a 0.2% residual of -two opposite mass shifts.** A single rank-48 idle child moves the PR3605 root by -`∓3.498e-7`, more than the whole gain over PR3148. A rank-1 child moves it by -`∓7.34e-9`. So the claimed gain over PR3148 also depends on every idle count -being exact. - -`root.py` also recounts PR3605's published aggregate integer witness -(`owners/AGGREGATE-INTEGER-FLOW.json.gz`, vendored). Over its 1,491,840 bins, -`idle = capacity − pattern width` reproduces `I` exactly. Its role flow meets -the per-call demand `20 × {4:26, 5:2, 6:18, 7:52, 8:97, 9:213}` (the audited -widths) for all 333 macro-calls. The capacity balance -`35,804,160 = mass(I) + 6660·3279` holds. Three controls are rejected: the -parent widths, a deleted pattern record and a deleted role-flow record. The -witness's source windows are taken as published. The literal 2,717,280-row -journal and its chronology are not re-derived here; they remain the -load-bearing unaudited input to the root. +two opposite mass shifts.** + +**Recount from the aggregate owner witness.** `root.py` recounts PR3605's +published aggregate integer witness +(`owners/AGGREGATE-INTEGER-FLOW.json.gz`, vendored). + +- Over its 1,491,840 bins, `idle = capacity − pattern width` reproduces `I` + exactly. +- Its role flow meets the per-call demand + `20 × {4:26, 5:2, 6:18, 7:52, 8:97, 9:213}` (the audited widths) for all 333 + macro-calls. +- It passes the same legality checks as PR3605's `verify_aggregate.py`, + reimplemented: record types and ranges, no duplicate records, open/closed + windows, the per-copy group capacity, and its own inventory and profile + fields. +- The capacity balance `35,804,160 = mass(I) + 6660·3279` holds, so + `mass(I) = 13,966,020`. +- Five controls are rejected: the parent widths, a deleted pattern record, a + duplicated pattern record, a deleted role-flow record, and a role on an + excluded lower window endpoint. + +The witness's source windows are taken as published. The literal journal of +2,717,280 helper roles (6660 × 408) and its chronology are not re-derived here. + +**How fragile is the gain?** It depends on which kind of error is made. + +- *Mass-changing errors.* The group capacities and bin counts (bins come in + multiples of S = 20), together with the widths, fix `mass(I)` through the + capacity balance. Errors in any of them change idle mass, and at that scale + the gain is fragile. Adding or removing one rank-48 idle child (mass ±48) + moves the PR3605 root by `∓3.498e-7`, more than the whole gain. One rank-1 + child (mass ±1) moves it by `∓7.34e-9`, which is more than PR3605's margin of + `6.55e-9` above 0.00173. +- *Mass-conserving errors.* At fixed groups and widths, placement and journal + errors only redistribute idle mass among ranks 1 to 48, because the + capacities are 8, 16, 32 and 48. `M` is linear in the histogram and `(73/r)^b` + decreases in `r`. So a change that moves `m` units of idle mass changes `M(b)` + by at most `m·(73^b − (73/48)^b)/(73·663040)` at every `b`. Equality holds + when rank-48 children are relabelled as rank-1 children, 48 per relabel. + `root.py` proves with exact intervals that: + - one relabel moves the root by `∓2.35e-9`; + - 98 relabels are the fewest that put it below PR3148's root, and 3 the + fewest that put it below 0.00173. + + Hence no such error moving at most 4,656 units of idle mass can cancel the + gain over PR3148, and none moving at most 96 units can take the root below + 0.00173. A single placement error such as moving one width-8 role from a + full bin to an empty capacity-48 bin shifts the root by `−2.73e-10`. + +For the magnitude of the gain, the group capacities and bin counts are +therefore the critical inputs. The window bounds and the literal journal decide +legality; a placement error that keeps the groups fixed moves the root only +slightly. ## Scope, inherited assumptions and unrun obligations -Checked here: the finite free-operator identity for arbitrary independent inputs -in which warps are free invertible symbols, the binary-frame chronology and bill, -the cleanup, the PROOF.md factorization, tables and invoice, and arithmetic -on two published histograms. The free-operator proof uses inverse cancellation -only, so it applies to the actual invertible warps. +Checked here: + +- the finite free-operator identity for arbitrary independent inputs, with + warps as free invertible symbols; +- the binary-frame chronology and bill; +- the cleanup; +- the PROOF.md factorization, tables and invoice; +- arithmetic on two published histograms, and the aggregate-witness recount. + +The free-operator proof uses inverse cancellation only, so it applies to the +actual invertible warps. Not checked: - native Gaussian/Clifford phases and the rank-7 residual `C_[7]⊗I_[2]` on 512 columns; -- the owner source windows and the literal T740 owner journal (the idle profile is recounted only from the aggregate witness); +- the `RETIMED644-660` words of #3642/#3653; +- the owner source windows and the literal T740 owner journal (the idle profile is recounted only from the aggregate witness), and every consumer's own owner journal and root; - the PR3605 conditional release and full fresh-bootstrap wrapper replay requested in Ross's #1166 handoff; -- physical/prefix/outer release, precision, H1–H5 and the formal kernel. +- physical/prefix/outer release, precision, the inherited all-size hypotheses H1–H5 and the formal kernel. The binary-frame contract is taken from the inherited format. It is not derived from first principles. Gzip streams are not compared; payloads and @@ -198,12 +295,18 @@ python3 -I -B research/staged-644-660-independent-audit/verify.py python3 -I -B research/staged-644-660-independent-audit/root.py ``` -Expected output is `PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT` (after two -`CHECKED` lines, about 35 s) and `PASS_EXACT_MOMENT_BRACKETS` (about 31 s). Both -compare against the committed receipts `RESULT.json` and `ROOT-RESULT.json`; `--write` -regenerates a receipt deliberately. Failures raise explicit exceptions, also -under `-O`. Both commands passed directly on CPython 3.14.4 under `-I -B` and -`-I -O -B`, and `research_package.py --check-only` passed. The generic runner +Expected output: + +- `verify.py`: two `CHECKED` lines, then + `PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT` (about 35 s); +- `root.py`: `PASS_EXACT_MOMENT_BRACKETS` (about 45 s). + +Both compare against the committed receipts `RESULT.json` and +`ROOT-RESULT.json`; `--write` regenerates a receipt deliberately. Failures +raise explicit exceptions, also under `-O`. + +Both commands passed directly on CPython 3.14.4 under `-I -B` and `-I -O -B`, +and `research_package.py --check-only` passed. The generic runner (`python3.12 scripts/research_package.py --package research/staged-644-660-independent-audit`) needs Python 3.12. That version was not available here, so the runner has not been executed. @@ -211,41 +314,57 @@ was not available here, so the runner has not been executed. ## Sources Base main `20ecf2891d80b5acf18d980b2164fb44ea7faa90`, priority revision 6. -PR3605 is unmerged, so its two words, two edit records, its conditional-release -`CLAIM.json` and its aggregate owner witness are byte-preserved in `inputs/`. -[SOURCES.json](SOURCES.json) records their source path, commit, Git blob and SHA256, which `verify.py` -checks. The PR3133 parent words and PR3148 `CLAIM.json` are read from main; -their blobs equal those at the predecessor heads. The PR3605 files that were -read but not executed (PROOF.md, staged_pair.py, check_scope.py, verify.py, -DERIVATION.md) are pinned the same way. + +- **Snapshots.** PR3605 is unmerged, so its two words, two edit records, its + conditional-release `CLAIM.json` and its aggregate owner witness are + byte-preserved in `inputs/`. [SOURCES.json](SOURCES.json) records their + source path, commit, Git blob and SHA256, which `verify.py` checks. +- **Main inputs.** The PR3133 parent words and PR3148 `CLAIM.json` are read + from main; their blobs equal those at the predecessor heads. +- **Read, not executed.** These PR3605 files are pinned the same way: + PROOF.md, staged_pair.py, check_scope.py, verify.py, DERIVATION.md, + check_residual.py and owners/verify_aggregate.py. +- **Provenance rows.** Arham Tahir's audit `verify.py` and the inherited + `audit_local.py` are also pinned. ## Open next questions The structured list is in [TASK.json](TASK.json). -1. **Are PR3605's owner windows and literal journal legal?** The root gain - over PR3148 is smaller than one rank-48 idle child. The arithmetic from the - aggregate witness to - `I={1:174156,3:48334,4:1,5:10792,6:3,48:283185}` is reproduced here, so the - decisive remaining check is the witness's 333 source windows and the - 2,717,280-row chronological expansion. First step: derive the window classes - from the T37 source template without the retained `owner.windows` routine, - and compare them with the witness's `groups`. -2. **Do the native phases of the paired `span(429,30)` entrance hold?** This +1. **Do the native phases of the paired `span(429,30)` entrance hold?** Every + consumer shares this obligation, and the whole width saving rests on it. It needs an independent check of the rank-7 residual on all 512 Gaussian columns, without the `bw_*` lineage code. -3. **Is the restore-210 frame edit needed?** It is bill- and identity-neutral +2. **Are the `RETIMED644-660` words of #3642/#3653 correct?** First step: run + this package's interpreter on them, with the audited STAGED words as the + single-change control. Check the identity, the claimed per-invocation change + (−2 rank-1, −2 rank-2, +2 rank-3 children), unchanged widths and + release-retiming mutants. This is cheap and is now the most + decision-relevant local check. +3. **Is each live consumer's own owner journal legal?** These are the T8, T16, + T488, T360 and T530 allocations. By the sensitivity bound above, the group + capacities and bin counts decide the magnitude of the gain; the window + bounds and literal chronology decide legality. +4. **Are PR3605's own T740 owner windows legal?** PR3605's own κ is already + superseded by its consumers. The decisive check is the 333 source windows of + the aggregate witness. First step: derive the window classes from the T37 + source template without the retained `owner.windows` routine, and compare + them with the witness's `groups`. +5. **Is the restore-210 frame edit needed?** It is bill- and identity-neutral here. Does any native stage require it? ## Credit and provenance -The construction is RossRichardson's PR3605. The parent words and coupled folds -are dcharb78's PR3133, and the T740 owner/cap root control is Jeremy Diviney's -PR3148. The word lineage retains its credited predecessors (PR2857, PR2908/2917, -Marius-Paul Dumitrean's PR2979, Jeremy Kothe's PR3015, PR3042) as recorded in -those packages. Arham Tahir's `coupled-carrier-independent-audit` gave -orientation on the contract; no code was taken from it. The PR3531 arithmetic -lineage is credited for the root model in PR3605. +- **Construction:** RossRichardson's PR3605. +- **Parent words and coupled folds:** dcharb78's PR3133. +- **T740 owner/cap root control:** Jeremy Diviney's PR3148. +- **Word lineage:** the credited predecessors are retained as recorded in those + packages: PR2857, PR2908/2917, Marius-Paul Dumitrean's PR2979, Jeremy + Kothe's PR3015 and PR3042. +- **Frame-bill and free-word structure:** Arham Tahir's + `coupled-carrier-independent-audit/verify.py` (Apache-2.0). `audit_core.py` + re-implements it without importing it (see Method). +- **Root model:** the PR3531 arithmetic lineage, as credited in PR3605. Prepared by Sagar Thakrar (thakrarsagar) with substantial AI assistance from Claude (Anthropic, Claude Opus 5.5). No human or formal-kernel review is claimed. diff --git a/research/staged-644-660-independent-audit/ROOT-RESULT.json b/research/staged-644-660-independent-audit/ROOT-RESULT.json index d1a1edd365..c163341b0c 100644 --- a/research/staged-644-660-independent-audit/ROOT-RESULT.json +++ b/research/staged-644-660-independent-audit/ROOT-RESULT.json @@ -92,35 +92,29 @@ "2": 2, "3": -4 }, - "model": "M(b)=sum_r r*H[r]*(73/r)^b/(73*663040)", - "rank_mass": 48165120, - "root_delta_PR3605_minus_PR3148": [ - "28631857530604389868831/125000000000000000000000000000", - "4581097204896702379013/20000000000000000000000000000" - ], - "single_child_sensitivity_PR3605": { - "+1 rank-1 child": { + "mass_changing_sensitivity_PR3605": { + "+1 rank-1 child (rank mass +1)": { "bracket_30_digits": [ "1729999212951825119741563069/1000000000000000000000000000000", "172999921295182511974156307/100000000000000000000000000000" ], "shift_from_PR3605_lower": -7.336587016727264e-09 }, - "+1 rank-48 child": { + "+1 rank-48 child (rank mass +48)": { "bracket_30_digits": [ "345931348752233296299287263/200000000000000000000000000000", "432414185940291620374109079/250000000000000000000000000000" ], "shift_from_PR3605_lower": -3.4980577767536554e-07 }, - "-1 rank-1 child": { + "-1 rank-1 child (rank mass -1)": { "bracket_30_digits": [ "1730013886126120365249152379/1000000000000000000000000000000", "86500694306306018262457619/50000000000000000000000000000" ], "shift_from_PR3605_lower": 7.336587278518243e-09 }, - "-1 rank-48 child": { + "-1 rank-48 child (rank mass -48)": { "bracket_30_digits": [ "865178177482133737937284553/500000000000000000000000000000", "1730356354964267475874569107/1000000000000000000000000000000" @@ -128,6 +122,37 @@ "shift_from_PR3605_lower": 3.498054254256289e-07 } }, + "mass_conserving_sensitivity_PR3605": { + "+1 relabel (rank-48 idle child <-> 48 rank-1 children)": { + "bracket_30_digits": [ + "1730004198960502862962895247/1000000000000000000000000000000", + "108125262435031428935180953/62500000000000000000000000000" + ], + "shift_from_PR3605_lower": -2.350578338984043e-09 + }, + "-1 relabel (rank-48 idle child <-> 48 rank-1 children)": { + "bracket_30_digits": [ + "86500445006178693387823839/50000000000000000000000000000", + "1730008900123573867756476781/1000000000000000000000000000000" + ], + "shift_from_PR3605_lower": 2.3505847320207507e-09 + }, + "least relabels putting the PR3605 root below 0.00173": 3, + "least relabels putting the PR3605 root below the PR3148 root": 98, + "one width-8 role moved from a full bin to an empty capacity-48 bin": { + "bracket_30_digits": [ + "865003138289842471247704021/500000000000000000000000000000", + "1730006276579684942495408043/1000000000000000000000000000000" + ], + "shift_from_PR3605_lower": -2.7295915690451043e-10 + } + }, + "model": "M(b)=sum_r r*H[r]*(73/r)^b/(73*663040)", + "rank_mass": 48165120, + "root_delta_PR3605_minus_PR3148": [ + "28631857530604389868831/125000000000000000000000000000", + "4581097204896702379013/20000000000000000000000000000" + ], "status": "PASS_EXACT_MOMENT_BRACKETS", "stock_times_dimension": 48401920 } diff --git a/research/staged-644-660-independent-audit/SOURCES.json b/research/staged-644-660-independent-audit/SOURCES.json index 52e3d7d3a7..abd718ca8e 100644 --- a/research/staged-644-660-independent-audit/SOURCES.json +++ b/research/staged-644-660-independent-audit/SOURCES.json @@ -31,6 +31,18 @@ "usage": "input", "git_blob": "decc8f26d8aab108baf75f0d8b2d1012eb06d076", "sha256": "495d030f1e03b90e954dad3043994f03293d41b9ed220a3beaef849df435d3f0" + }, + { + "path": "research/coupled-carrier-independent-audit/verify.py", + "usage": "provenance", + "git_blob": "18044e841b53b3d3779d8f7c15f19d98ba3f00fe", + "sha256": "59d7f658992afbcb0e86b763c07d73f706b3841f177522126cd3def5adffc41d" + }, + { + "path": "research/rank7-coupled-586-588-carrier-fold/vendor/audit_local.py", + "usage": "provenance", + "git_blob": "8224873d0497cf0b4c202f31b145fa273553d978", + "sha256": "a38940094f7d19cd6376aafdd4734fa68eabc9aff4c98c3c4a3e9540328b1c90" } ], "snapshot": [ @@ -139,7 +151,23 @@ "git_blob": "aa3d8e87fc139d636cd19eaa4cd375fca2c780cf", "sha256": "338165d75d87a1a576750ec92772640e641bc91076e91b686d8ec7ad6f9d6d19", "usage": "identity of the main-branch input with its predecessor head" + }, + { + "source_path": "research/staged-644-660-width-reduction/check_residual.py", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "7e75bde5b4c3a0d345b89e71631abeb9994781ec", + "sha256": "e34b06ae725f062d15ad83cbd3ef2f91d3d78c380ccc93c8d2deba1c9e354c70", + "usage": "cited for the native rank-7 residual identity, which this package does not check; not imported or executed" + }, + { + "source_path": "research/staged-644-660-conditional-release/owners/verify_aggregate.py", + "source_commit": "3efbb5de06a49ffeea6684482f2d3fe48cdca3fb", + "source_pr": 3605, + "git_blob": "a5e828b6de7eb691e94eec1ee52ea47fd9a2971f", + "sha256": "c10a0eb62799f73dd577a5bec86e91b0124ec8b2cdf95bd68807299cf1521866", + "usage": "read for the aggregate-witness legality checks that root.py reimplements; not imported or executed" } ], - "snapshot_provenance": "Exact Git blob bytes of PR3605 head 3efbb5de (unmerged at base 20ecf289); verify.py authenticates them by SHA256. The PR3133 parent words and PR3148 claim are read from main and pinned in files." + "snapshot_provenance": "Exact Git blob bytes of PR3605 head 3efbb5de (unmerged at base 20ecf289); verify.py authenticates them by SHA256. The PR3133 parent words and PR3148 claim are read from main and pinned in files. Provenance rows: Arham Tahir's coupled-carrier-independent-audit/verify.py, whose frame-bill and free-word structure audit_core.py re-implements without importing; and the inherited auditor audit_local.py, which only the optional crosscheck_inherited.py executes (it also checks this SHA256 itself)." } diff --git a/research/staged-644-660-independent-audit/TASK.json b/research/staged-644-660-independent-audit/TASK.json index 99c9dca9d1..864e135472 100644 --- a/research/staged-644-660-independent-audit/TASK.json +++ b/research/staged-644-660-independent-audit/TASK.json @@ -47,27 +47,39 @@ }, "scope_status": "refined", "actual_scope": "Independently audit PR3605 (head 3efbb5de)'s staged 644/660 width 8->7 change against its single-change control, the unchanged PR3133 parent words: exact dirty-input identity in both orientations by two algorithms, literal inverse cleanup, chronological binary frames, local profile and helper widths, PROOF.md's prefix factorization/tables/invoice, required-failing mutants, and exact root brackets for the published PR3605 and PR3148 complete histograms with their attribution.", - "scope_change_reason": "The card's first experiment names #2979's joint group; PR3605 is the live descendant of that joint-construction lineage (PR2979 -> PR3133 -> PR3605), and every open staged-width kappa>0.00173 claim (#3624/#3626/#3633/#3638/#3630) reuses its words unchanged with only author-run inherited-interpreter checks. Auditing one changed group against its single-change control is the card's method applied to the currently decision-relevant group.", - "bottleneck_link": "Independent pricing of the supplier words that the staged-width chain inherits: a failure would invalidate the whole chain; a pass supplies the independent local check while showing the root gain depends on the unaudited idle journal.", + "scope_change_reason": "The card's first experiment names #2979's joint group; PR3605 is the live descendant of that joint-construction lineage (PR2979 -> PR3133 -> PR3605). Open staged-width kappa>0.00173 claims #3624/#3626/#3633/#3638/#3630 reuse its words unchanged, and #3642/#3653 build RETIMED644-660 words on top of them; all rely on author-run inherited-interpreter checks. Auditing one changed group against its single-change control is the card's method applied to the currently decision-relevant group.", + "bottleneck_link": "Independent pricing of the supplier words that the staged-width chain inherits: a failure would invalidate the whole chain; a pass supplies the independent local check for the unchanged reusers (only the STAGED parent of the retimed #3642/#3653 words), and separates mass-changing from mass-conserving idle errors in the root gain.", "budget_minutes": 150, "stop_rule": "Ship (c)+(e) with a handoff if the interpreter could not reproduce the parent control by ~75 min; stop and minimize on any identity/cleanup/profile failure; switch to p104-side-correction if another contributor claimed the words first. None triggered.", "outcome": "completed", - "evidence": "PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT (RESULT.json): both providers, parent control {1:2433,2:724,3:228,4:102,5:20,8:8} / widths 7:50,8:99 reproduced; changed words {1:2439,2:726,3:224,4:102,5:20,8:8} / widths 7:52,8:97; 632 inputs, 91 buffers; forward with dirty buffers, dual, and reverse pull-back agree; cleanup literal inverse; PROOF.md factorization P_new=P_old S1 S2 on all registers, target tables and per-register invoice exact; 19 mutants per provider behave as predicted. PASS_EXACT_MOMENT_BRACKETS (ROOT-RESULT.json): PR3605 [0.001730006549538841847005,...006] and PR3148 [0.0017297774946785970118869,...870] confirmed by two engines; delta +2.2905486024e-7 is smaller than the effect of one rank-48 idle child (3.498e-7); the vendored PR3605 aggregate owner witness reproduces I={1:174156,3:48334,4:1,5:10792,6:3,48:283185} with the audited widths (windows taken as published; literal journal not re-derived).", + "evidence": "PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT (RESULT.json): both providers, parent control {1:2433,2:724,3:228,4:102,5:20,8:8} / widths 7:50,8:99 reproduced; changed words {1:2439,2:726,3:224,4:102,5:20,8:8} / widths 7:52,8:97; 632 inputs, 91 buffers; forward with dirty buffers, dual, and reverse pull-back agree; cleanup literal inverse; PROOF.md factorization P_new=P_old S1 S2 on all registers, target tables and per-register invoice exact; 19 mutants per provider behave as predicted. PASS_EXACT_MOMENT_BRACKETS (ROOT-RESULT.json): on the published histograms, PR3605 [0.001730006549538841847005,...006] and PR3148 [0.0017297774946785970118869,...870] are confirmed by two engines; delta +2.2905486024e-7. The vendored PR3605 aggregate owner witness passes the verify_aggregate.py legality checks (reimplemented) and reproduces I={1:174156,3:48334,4:1,5:10792,6:3,48:283185} with the audited widths, mass(I)=13,966,020 (windows taken as published; literal journal not re-derived). Sensitivity: a mass-changing error of one rank-48 idle child moves the root by 3.498e-7 (more than the gain); a mass-conserving error at fixed groups and widths that moves at most 4,656 units of idle mass cannot cancel the gain (98 rank-48->48x rank-1 relabels are the fewest that do, proved by exact intervals), and one moving at most 96 units cannot take the root below 0.00173.", "author": "Sagar Thakrar (thakrarsagar)", "ai_assistance": "Substantial AI assistance from Claude (Anthropic, Claude Opus 5.5): design, code, checks and write-up in an automated research loop. No human or formal-kernel review is claimed.", "open_questions": [ - { - "question": "Are PR3605's 333 owner source windows and its 2,717,280-row chronological journal legal for the audited widths?", - "why_it_matters": "The root gain over PR3148 (+2.29e-7) is smaller than the root shift from one rank-48 idle child (3.5e-7). This package reproduces I from the published aggregate witness, but takes the witness's windows as published and does not re-derive the literal journal.", - "first_step": "Derive the window classes (capacity, lo, hi, bins) from the T37 source template without the retained owner.windows routine and compare with the witness's groups list; then re-expand and check chronological prefixes independently of portable_expand.py/independent_literal.py.", - "blocked_by": "Nothing; requires the T37 source template/order format. The sibling CLAIM on #3633 T488 owners covers a different journal." - }, { "question": "Do the native Gaussian phases of the paired span(429,30) entrance (rank-7 residual C_[7] tensor I_[2]) hold on all 512 columns when checked without the bw_* lineage code?", - "why_it_matters": "This audit checks free-operator semantics and binary frames only; the physical width-7 residual is certified only by the inherited native chain.", - "first_step": "Implement an independent exact monomial/Gaussian product for T_FULL T_P^-1 and compare with check_residual.py's recipe on all 512 columns, including global phase.", + "why_it_matters": "The old-entrance mutant shows the whole rank-mass saving comes from this entrance frame; every consumer (#3624/#3626/#3633/#3638/#3630/#3642/#3653) shares it, and it is certified only by the inherited native chain.", + "first_step": "Implement an independent exact monomial/Gaussian product for T_FULL T_P^-1 and compare with PR3605 check_residual.py's recipe (pinned in SOURCES.json) on all 512 columns, including global phase.", "blocked_by": "Understanding of the native recipe format; no data blocker." }, + { + "question": "Are the RETIMED644-660 words of #3642/#3653 (blobs d69125e0/f3c580b0) exact identities with the claimed per-invocation change -2 rank-1, -2 rank-2, +2 rank-3 and unchanged widths?", + "why_it_matters": "They carry the two highest staged-width claims and only their STAGED parent is covered by this audit.", + "first_step": "Run this package's audit_core interpreter on the RETIMED words with the audited STAGED words as the single-change control; add release-retiming mutants.", + "blocked_by": "Nothing; the words are public at #3642 head 044d24f1." + }, + { + "question": "Is each live consumer's own owner journal (T8, T16, T488, T360, T530 allocations) legal, with window classes derived independently?", + "why_it_matters": "Group capacities and bin counts fix idle mass and hence the magnitude of each gain; the window bounds and literal chronology decide legality.", + "first_step": "For one consumer, derive its window classes from the source template without the retained owner.windows routine and recount its idle histogram.", + "blocked_by": "Per-consumer journal formats." + }, + { + "question": "Are PR3605's own 333 T740 owner source windows legal for the audited widths?", + "why_it_matters": "PR3605's own kappa is superseded by its consumers, so this is lower priority; this package takes the witness windows as published.", + "first_step": "Derive the window classes (capacity, lo, hi, bins) from the T37 source template without the retained owner.windows routine and compare with the witness's groups list.", + "blocked_by": "Requires the T37 source template/order format." + }, { "question": "Is the restore-210 frame edit (source 96 sign gate moved from a rank-8 hyperplane to FULL) needed by any native stage?", "why_it_matters": "It is identity- and bill-neutral in the local audit; if unnecessary it is noise in the declared edit set, if necessary the native contract has an undocumented dependency.", diff --git a/research/staged-644-660-independent-audit/VERIFY.json b/research/staged-644-660-independent-audit/VERIFY.json index c0326af269..794460dd12 100644 --- a/research/staged-644-660-independent-audit/VERIFY.json +++ b/research/staged-644-660-independent-audit/VERIFY.json @@ -27,7 +27,7 @@ "{package}/root.py" ], "timeout_seconds": 300, - "checks": "Exact interval and decimal-Newton enclosures of the PR3605 and PR3148 complex roots on their published complete histograms, H=6660L+I decompositions, rank-mass invariant, recount of I from the vendored aggregate owner witness with the audited widths (three rejecting controls), attribution hybrids, single-child sensitivity, receipt comparison." + "checks": "Exact interval and decimal-Newton enclosures of the PR3605 and PR3148 complex roots on their published complete histograms, H=6660L+I decompositions, rank-mass invariant, recount of I from the vendored aggregate owner witness with the audited widths and the verify_aggregate.py legality checks (five rejecting controls), attribution hybrids, mass-changing and mass-conserving sensitivity with the exact least relabel counts, receipt comparison." } ] } diff --git a/research/staged-644-660-independent-audit/audit_core.py b/research/staged-644-660-independent-audit/audit_core.py index 80ff8ad253..8b5e1d5f2a 100644 --- a/research/staged-644-660-independent-audit/audit_core.py +++ b/research/staged-644-660-independent-audit/audit_core.py @@ -1,8 +1,13 @@ """Independent exact semantics and binary-frame bill for the BORROW-WORD format. -Standard library only. No predecessor evaluator, producer, cleanup generator or -frame solver is imported; the word format and its semantic contract were read -from the pinned PR3133/PR3605 sources and are credited there. +Standard library only. Nothing is imported from the audited authors' code +(PR3133/PR3605 producers, cleanup generator, evaluator or frame solver); the word +format and its semantic contract were read from those pinned sources and are +credited there. The frame-bill and free-word structure (point-set spans, warp +frame and lifted-frame checks, target levels keyed by register, dual symbol +naming) re-implements, without importing, Arham Tahir's +research/coupled-carrier-independent-audit/verify.py (Apache-2.0) and shares its +reading of the contract, so this module is not independent of that audit. Sagar Thakrar (thakrarsagar), with substantial AI assistance from Claude (Anthropic, Claude Opus 5.5). Apache-2.0. @@ -89,7 +94,9 @@ def lagrangian_action_ok(images, U, E): """K_G(x,z)=(Gx, Gx+G^{-T}(x+z)) is symplectic and maps L_U to L_E, L_0 and L_FULL to themselves. L_U={(x,x+p): x in U, p in U^perp}. This is the binary frame action only; it - is not a Clifford phase or Gaussian-product certificate. + is not a Clifford phase or Gaussian-product certificate. For invertible G with + G(U)=E it is implied by the frame-map check ( = ), so it is a + consistency check of the implementation, not extra evidence. """ inverse = [0] * 512 for x, y in enumerate(images): diff --git a/research/staged-644-660-independent-audit/root.py b/research/staged-644-660-independent-audit/root.py index 88c5607b13..3cc8eff209 100644 --- a/research/staged-644-660-independent-audit/root.py +++ b/research/staged-644-660-independent-audit/root.py @@ -157,21 +157,29 @@ def load_hist(obj): return {int(k): int(v) for k, v in obj.items()} -def aggregate_idle(cert, inventory): +def aggregate_idle(cert, inventory, local): """Recount PR3605's idle histogram from its published aggregate integer witness. Groups are [capacity, lo, hi, bins]; x rows are (group, width pattern, count); - z rows are (group, macro-call, width, roles). Checks bin counts, capacities, - the open/closed windows as published, width supply = role flow, and the - per-call demand S*inventory for all 333 macro-calls. The windows themselves - are taken as published, not derived from the source template. + z rows are (group, macro-call, width, roles). Checks record types and ranges, + duplicate records, bin counts, capacities, the open/closed windows as published, + width supply = role flow, the per-call demand S*inventory for all 333 macro-calls, + the per-copy group capacity, and the witness's own inventory and profile fields + (the same legality checks as PR3605 owners/verify_aggregate.py, reimplemented). + The windows themselves are taken as published, not derived from the source template. """ widths, S, groups = cert['widths'], cert['S'], cert['groups'] need(widths == [4, 5, 6, 7, 8, 9] and S == 20 and len(cert['order']) == 333, 'aggregate shape') - idle, bins, supply, flow, demand = Counter(), Counter(), Counter(), Counter(), Counter() + need({int(w): n for w, n in cert['inventory'].items()} == inventory, 'witness inventory field') + idle, bins, supply, flow, demand, per_copy = (Counter() for _ in range(6)) + seen_x, seen_z = set(), set() for g, pattern, n in cert['x']: + need(type(g) is int and 0 <= g < len(groups) and len(pattern) == 6 and type(n) is int and n > 0 + and all(type(k) is int and k >= 0 for k in pattern), 'pattern record', g) + need((g, tuple(pattern)) not in seen_x, 'duplicate pattern record', g) + seen_x.add((g, tuple(pattern))) used = sum(w * k for w, k in zip(widths, pattern)) - need(n > 0 and min(pattern) >= 0 and used <= groups[g][0] and sum(pattern) <= S, 'pattern', g) + need(used <= groups[g][0] and sum(pattern) <= S, 'pattern', g) bins[g] += n if used < groups[g][0]: idle[groups[g][0] - used] += n @@ -179,14 +187,45 @@ def aggregate_idle(cert, inventory): supply[g, w] += n * k need(all(bins[g] == S * groups[g][3] for g in range(len(groups))), 'bin inventory') for g, t, w, n in cert['z']: - need(n > 0 and groups[g][1] < t <= groups[g][2], 'source window', g, t) + need(all(type(k) is int for k in (g, t, w, n)) and 0 <= g < len(groups) and 0 <= t < 333 + and w in widths and n > 0, 'role-flow record', g, t) + need((g, t, w) not in seen_z, 'duplicate role-flow record', g, t, w) + seen_z.add((g, t, w)) + need(groups[g][1] < t <= groups[g][2], 'source window', g, t) flow[g, w] += n demand[t, w] += n + per_copy[g, t] += n need(flow == +supply, 'pattern supply differs from role flow') need(all(demand[t, w] == S * inventory[w] for t in range(333) for w in widths), 'per-call width demand') + need(all(n <= S * groups[g][3] for (g, t), n in per_copy.items()), 'per-copy group capacity') + profile = Counter({r: 333 * S * n for r, n in local.items()}) + idle + need({int(r): n for r, n in cert['profile'].items()} == profile, 'witness profile field') return idle, sum(S * g[3] for g in groups), sum(S * g[3] * g[0] for g in groups) +def relabel(hist, k): + """k rank-48 idle children relabelled as 48k rank-1 children (k<0: the reverse); rank mass unchanged.""" + out = dict(hist) + out[48] -= k + out[1] += 48 * k + need(min(out.values()) >= 0, 'relabel exceeds the histogram') + return out + + +def min_relabels(hist, lo_point, hi_point): + """Least k>0 proved to put the root below [lo_point, hi_point]: lower M_k(lo_point) > 1 while + upper M_(k-1)(hi_point) < 1. M is linear in the histogram; the float guess is only a start. + """ + base, one = moment(hist, lo_point)[0], moment(relabel(hist, 1), lo_point)[0] + k = max(1, math.ceil((1 - base) / (one - base))) + while moment(relabel(hist, k), lo_point)[0] <= 1: + k += 1 + while k > 1 and moment(relabel(hist, k - 1), lo_point)[0] > 1: + k -= 1 + need(k == 1 or moment(relabel(hist, k - 1), hi_point)[1] < 1, 'relabel threshold undecided', k) + return k + + def main(): pr3605 = json.loads((HERE / 'inputs' / 'PR3605-CLAIM.json').read_text(encoding='utf-8')) pr3148_path = ROOT / 'research/coupled-carrier-cap740/CLAIM.json' @@ -208,15 +247,20 @@ def main(): cert_path = HERE / 'inputs' / 'AGGREGATE-INTEGER-FLOW.json.gz' need(hashlib.sha256(cert_path.read_bytes()).hexdigest() == pins['inputs/AGGREGATE-INTEGER-FLOW.json.gz'], 'aggregate pin') audited_widths = {4: 26, 5: 2, 6: 18, 7: 52, 8: 97, 9: 213} # derived from frames by verify.py - idle_count, bin_count, capacity = aggregate_idle(json.loads(gzip.decompress(cert_path.read_bytes())), audited_widths) + idle_count, bin_count, capacity = aggregate_idle(json.loads(gzip.decompress(cert_path.read_bytes())), audited_widths, local_new) need(idle_count == idle_new, 'aggregate witness idle histogram differs from DERIVATION.md', dict(idle_count)) need(capacity == mass(idle_new) + CALLS * sum(w * c for w, c in audited_widths.items()), 'capacity balance') cert = json.loads(gzip.decompress(cert_path.read_bytes())) + window_cut = [row[:] for row in cert['z']] + j = next(j for j, row in enumerate(window_cut) if cert['groups'][row[0]][1] >= 0) + window_cut[j][1] = cert['groups'][window_cut[j][0]][1] # role on the excluded lower endpoint for label, bad_cert, widths in (('parent widths 7:50/8:99', cert, {**audited_widths, 7: 50, 8: 99}), ('one pattern record deleted', {**cert, 'x': cert['x'][1:]}, audited_widths), - ('one role-flow record deleted', {**cert, 'z': cert['z'][1:]}, audited_widths)): + ('one pattern record duplicated', {**cert, 'x': cert['x'] + cert['x'][:1]}, audited_widths), + ('one role-flow record deleted', {**cert, 'z': cert['z'][1:]}, audited_widths), + ('role on an excluded lower window endpoint', {**cert, 'z': window_cut}, audited_widths)): try: - aggregate_idle(bad_cert, widths) + aggregate_idle(bad_cert, widths, local_new) except RootFailure: continue raise RootFailure('aggregate control accepted: ' + label) @@ -257,17 +301,44 @@ def main(): out['attribution'] = attribution out['root_delta_PR3605_minus_PR3148'] = [str(roots['PR3605'][0] - roots['PR3148'][1]), str(roots['PR3605'][1] - roots['PR3148'][0])] - # Sensitivity of the PR3605 root to a single idle child of rank 1 or 48 (exact brackets). + # Mass-changing sensitivity: one idle child added or removed (rank mass changes by r). + # At fixed window classes, bin counts and widths the capacity balance fixes mass(I), so + # these perturbations model group-geometry or width errors, not placement errors. sensitivity = {} for r in (1, 48): for sign in (1, -1): hist = dict(new) hist[r] += sign a, b = bracket(hist, 30) - sensitivity['%+d rank-%d child' % (sign, r)] = { + sensitivity['%+d rank-%d child (rank mass %+d)' % (sign, r, sign * r)] = { 'bracket_30_digits': [str(a), str(b)], 'shift_from_PR3605_lower': float(a - roots['PR3605'][0])} - out['single_child_sensitivity_PR3605'] = sensitivity + out['mass_changing_sensitivity_PR3605'] = sensitivity + # Mass-conserving sensitivity. Idle ranks are capacities minus pattern widths, so lie in + # [1, 48] (capacities 8/16/32/48). For a change moving m units of idle mass, linearity of M + # and 1 <= (73/r)^b / (73/48)^b <= 73^b / (73/48)^b give |dM(b)| <= m*(73^b-(73/48)^b)/(73*663040) + # at every b>0, with equality for relabel(.., m/48). Since M increases in b, every such + # change leaves the root between those of relabel(.., +k) and relabel(.., -k) when m <= 48k. + capacities = sorted({g[0] for g in cert['groups']}) + need(capacities == [8, 16, 32, 48] and max(idle_new) == 48, 'idle ranks within [1,48]') + conserving = {} + for k in (1, -1): + a, b = bracket(relabel(new, k), 30) + conserving['%+d relabel (rank-48 idle child <-> 48 rank-1 children)' % k] = { + 'bracket_30_digits': [str(a), str(b)], 'shift_from_PR3605_lower': float(a - roots['PR3605'][0])} + move8 = dict(new) # one width-8 role: full bin -> empty 48-bin + move8[8] += 1 + move8[48] -= 1 + move8[40] = 1 + need(mass(move8) == mass(new), 'width-8 move conserves mass') + a, b = bracket(move8, 30) + conserving['one width-8 role moved from a full bin to an empty capacity-48 bin'] = { + 'bracket_30_digits': [str(a), str(b)], 'shift_from_PR3605_lower': float(a - roots['PR3605'][0])} + k_gain = min_relabels(new, *roots['PR3148']) + k_threshold = min_relabels(new, Q(173, 100000), Q(173, 100000)) + conserving['least relabels putting the PR3605 root below the PR3148 root'] = k_gain + conserving['least relabels putting the PR3605 root below 0.00173'] = k_threshold + out['mass_conserving_sensitivity_PR3605'] = conserving out['local_delta_per_call'] = {str(r): local_new[r] - local_old[r] for r in sorted(set(local_new) | set(local_old)) if local_new[r] != local_old[r]} out['idle_delta'] = {str(r): idle_new[r] - idle_old[r] for r in sorted(set(idle_new) | set(idle_old)) if idle_new[r] != idle_old[r]} encoded = json.dumps(out, indent=1, sort_keys=True) + '\n' diff --git a/research/staged-644-660-independent-audit/verify.py b/research/staged-644-660-independent-audit/verify.py index ad48b2920e..a6f73c7d12 100644 --- a/research/staged-644-660-independent-audit/verify.py +++ b/research/staged-644-660-independent-audit/verify.py @@ -26,7 +26,7 @@ HERE = Path(__file__).resolve().parent ROOT = HERE.parents[1] sys.path.insert(0, str(HERE)) -import audit_core as C # noqa: E402 (package-local; its bytes are authenticated in main) +import audit_core as C # noqa: E402 (package-local; bound by the package and commit-byte checks, not hashed here) from audit_core import need, AuditFailure # noqa: E402 P = [429, 30] # span(429,30): the new entrance and release frame From 211717dfcf751c6d60c0b27205f8160c23749090 Mon Sep 17 00:00:00 2001 From: Sagar Thakrar <18622288+thakrarsagar@users.noreply.github.com> Date: Sun, 18 Oct 2026 19:50:33 +0530 Subject: [PATCH 3/4] Revise staged 644/660 audit after review round 2 Reframe root-gain sensitivity around the coverage law 72W+64N: with the audited per-call constant 1,856 it forces owner capacity 54W, so mass-changing errors cannot pass undetected and the single-child shifts are only slopes. root.py now certifies the direct mass-conserving thresholds (4,678 units vs PR3148, 133 vs 0.00173) and checks them against the relabel counts; adds the complete-paid-rank-mass witness check; asserts each aggregate control's rejection reason and adds a parent-widths control that reaches the per-call demand check. README and TASK fix consumer allocation names, #3653 draft state, and mention #3681/#3677. Co-Authored-By: Claude Opus 5.5 --- .../README.md | 145 +++++++++++------- .../ROOT-RESULT.json | 9 ++ .../SOURCES.json | 2 +- .../TASK.json | 12 +- .../VERIFY.json | 2 +- .../staged-644-660-independent-audit/root.py | 77 +++++++--- 6 files changed, 168 insertions(+), 79 deletions(-) diff --git a/research/staged-644-660-independent-audit/README.md b/research/staged-644-660-independent-audit/README.md index c416d47848..7825d63b5b 100644 --- a/research/staged-644-660-independent-audit/README.md +++ b/research/staged-644-660-independent-audit/README.md @@ -50,7 +50,7 @@ submission): same blobs sit inside #3638 `d62e1acd`'s vendored `PR3624-SOURCE.tar.gz` and #3630 `bcac7fe0`'s `PR3605-SOURCES.tar.gz`. For these PRs, the audited words are the supplier words. -- *Parent only.* #3642 `044d24f1` (roger-sato, T530) and the draft #3653 +- *Parent only.* #3642 `044d24f1` (roger-sato, T530) and #3653 `607a09ff` (rohanarun, T488, vendoring #3642) carry the same STAGED blobs, but their claims run `RETIMED644-660` words (`d69125e0`/`f3c580b0`). Those add two commuting release retimings on top of the audited words, and **they are not @@ -60,11 +60,19 @@ submission): PR3605's own semantic check runs the pinned inherited interpreter (`audit_local.py`). This package supplies a separately implemented check of the STAGED words. It does not check any of these PRs' own owner journals or -roots. Concurrent work: #3659 (jwr404) independently recomputes the PR3605 -T740 histogram mass and root bracket, and #3661 does the same for a T450 -allocation. This package's distinct parts are the word semantics, the -PR3148 delta attribution, the aggregate-witness recount and the sensitivity -analysis. +roots. Concurrent work, none of which re-implements the word semantics: + +- #3659 (jwr404) adds the published PR3605 T740 histogram and compares its + root with 0.00173 and the selected κ; #3661 does the same for the T450 + allocation. +- #3677 (jwr404) checks only the arithmetic of the published RETIMED profile + (rank mass 5,135, lower moment), not the RETIMED words. +- #3681 (roger-sato, `9f781394`) replays the complete PR3605 wrapper with a + fresh retained bootstrap. It runs the inherited code, native chain included, + so it is a full replay but not an independent check. It is not reviewed here. + +This package's distinct parts are the independent word semantics, the PR3148 +delta attribution, the aggregate-witness recount and the sensitivity analysis. | Quantity (each provider) | PR3133 parent (control) | PR3605 changed word | |---|---|---| @@ -92,8 +100,10 @@ The registered verifiers (`audit_core.py`, `verify.py`, `root.py`) import only the standard library. Nothing is imported or copied from the audited authors' code (the PR3133/PR3605 producers, cleanup generators or the inherited `audit_local.py`). The word format and contract were read from those pinned -sources. `root.py`'s aggregate legality checks re-implement the check list of -PR3605's `owners/verify_aggregate.py` without importing it. +sources. `root.py`'s aggregate legality checks re-implement, without importing +it, every check of PR3605's `owners/verify_aggregate.py` except the two derived +from the source template (the literal T37 order, and the window classes and bin +counts computed by `owner.windows`). The checks are not independent of every earlier audit, though. `audit_core.py`'s frame bill and free-word structure re-implement, without @@ -217,48 +227,75 @@ published aggregate integer witness - Its role flow meets the per-call demand `20 × {4:26, 5:2, 6:18, 7:52, 8:97, 9:213}` (the audited widths) for all 333 macro-calls. -- It passes the same legality checks as PR3605's `verify_aggregate.py`, - reimplemented: record types and ranges, no duplicate records, open/closed - windows, the per-copy group capacity, and its own inventory and profile - fields. +- It passes every check of PR3605's `verify_aggregate.py` (reimplemented) + except the two derived from the source template: record types and ranges, + no duplicate records, bin counts, open/closed windows, supply equal to flow, + per-call demand, the per-copy group capacity, the complete paid rank mass, + and its own inventory and profile fields. Not reimplemented: the literal + T37 order, and the window classes and bin counts from `owner.windows`. - The capacity balance `35,804,160 = mass(I) + 6660·3279` holds, so `mass(I) = 13,966,020`. -- Five controls are rejected: the parent widths, a deleted pattern record, a - duplicated pattern record, a deleted role-flow record, and a role on an - excluded lower window endpoint. +- Six controls are rejected, each for its expected reason (asserted, as + `verify_aggregate.py` does): + - the parent widths, against the witness's inventory field; + - the parent widths with that field also set to them, rejected by the + per-call width demand; + - a deleted pattern record, and a duplicated one; + - a deleted role-flow record; + - a role on an excluded lower window endpoint. The witness's source windows are taken as published. The literal journal of 2,717,280 helper roles (6660 × 408) and its chronology are not re-derived here. -**How fragile is the gain?** It depends on which kind of error is made. - -- *Mass-changing errors.* The group capacities and bin counts (bins come in - multiples of S = 20), together with the widths, fix `mass(I)` through the - capacity balance. Errors in any of them change idle mass, and at that scale - the gain is fragile. Adding or removing one rank-48 idle child (mass ±48) - moves the PR3605 root by `∓3.498e-7`, more than the whole gain. One rank-1 - child (mass ±1) moves it by `∓7.34e-9`, which is more than PR3605's margin of - `6.55e-9` above 0.00173. -- *Mass-conserving errors.* At fixed groups and widths, placement and journal - errors only redistribute idle mass among ranks 1 to 48, because the - capacities are 8, 16, 32 and 48. `M` is linear in the histogram and `(73/r)^b` - decreases in `r`. So a change that moves `m` units of idle mass changes `M(b)` - by at most `m·(73^b − (73/48)^b)/(73·663040)` at every `b`. Equality holds - when rank-48 children are relabelled as rank-1 children, 48 per relabel. - `root.py` proves with exact intervals that: - - one relabel moves the root by `∓2.35e-9`; - - 98 relabels are the fewest that put it below PR3148's root, and 3 the - fewest that put it below 0.00173. - - Hence no such error moving at most 4,656 units of idle mass can cancel the - gain over PR3148, and none moving at most 96 units can take the root below - 0.00173. A single placement error such as moving one width-8 role from a - full bin to an empty capacity-48 bin shifts the root by `−2.73e-10`. - -For the magnitude of the gain, the group capacities and bin counts are -therefore the critical inputs. The window bounds and the literal journal decide -legality; a placement error that keeps the groups fixed moves the root only -slightly. +**How fragile is the gain?** Every complete histogram in this model obeys the +coverage law `Σ r·H[r] = 72W + 64N`, with live stock W = 663,040 and N = 6,660 +calls (the deficit form of PR1012, as used in +`research/complex-queue-ceiling-census`). Both histograms meet it at +48,165,120, and `root.py` checks it. + +For both audited words, a call's local rank mass minus its helper width units +is the same: 5,137 − 3,281 = 5,135 − 3,279 = 1,856. Since +`mass(H) = N·1,856 + total owner capacity`, the law forces total owner capacity +35,804,160 = 54W, for PR3605 and PR3148 alike. The witness meets it. + +- *Mass-changing errors cannot pass undetected.* A wrong capacity or bin + count, or an added or dropped idle child, changes `mass(H)` and breaks the + law. The ±1-child brackets in `ROOT-RESULT.json` are therefore only slopes of + law-violating histograms, kept to show scale: one rank-48 child would move + the root by `∓3.498e-7`, one rank-1 child by `∓7.34e-9`. +- *Every undetected error conserves rank mass.* Let `m` be the rank mass it + moves, the positive part of the net histogram change: + `m = Σ_{ΔH[r] > 0} r·ΔH[r]`. Suppose every rank before and after lies in + [1, 48]. (Idle ranks are capped by the largest capacity, 48, and the local + ranks here are at most 8.) `M` is linear in the histogram and + `(73/48)^b ≤ (73/r)^b ≤ 73^b`, so `|ΔM(b)| ≤ m·c(b)` at every `b`, with + `c(b) = (73^b − (73/48)^b)/(73·663040)`. Equality holds when rank-48 + children are relabelled as 48 rank-1 children. `M` increases in `b`, so + `m < (1 − M(b0))/c(b0)` keeps the root above `b0`. `root.py` evaluates this + threshold with exact intervals: + - at PR3148's root (upper 30-digit endpoint), any such error moving at most + **4,678** units keeps the PR3605 root above it, so it cannot cancel the + gain; + - at 0.00173, any such error moving at most **133** units keeps the root + above 0.00173. + + The relabels show these thresholds are nearly attained. By exact intervals, + 98 relabels (4,704 units) are the fewest that put the root below PR3148's, + and 3 (144 units) the fewest that put it below 0.00173; `root.py` checks + that both counts agree with the direct thresholds. One relabel moves the + root by `∓2.35e-9`. Moving one width-8 role from a full bin to an empty + capacity-48 bin moves it by `−2.73e-10`. The inequality itself is the short + written argument above (repeated in a `root.py` comment); the thresholds and + relabel counts are exact computations. + +So the size of the gain is not where the open risk lies. Owner-layer errors +(window classes, bin assignment, the literal journal) decide legality. They +change the gain's size only if they move more than 4,678 units of rank mass. +Per-call errors in the words or the native entrance act 6,660 times, so they +can: PR3605 and PR3148 have the same total owner capacity yet differ by 97,186 +units of moved rank mass. The open risks are therefore the native residual +(open question 1) and window and journal legality (questions 3 and 4), not +more digits of the root. ## Scope, inherited assumptions and unrun obligations @@ -279,7 +316,7 @@ Not checked: - native Gaussian/Clifford phases and the rank-7 residual `C_[7]⊗I_[2]` on 512 columns; - the `RETIMED644-660` words of #3642/#3653; - the owner source windows and the literal T740 owner journal (the idle profile is recounted only from the aggregate witness), and every consumer's own owner journal and root; -- the PR3605 conditional release and full fresh-bootstrap wrapper replay requested in Ross's #1166 handoff; +- the PR3605 conditional release and full fresh-bootstrap wrapper replay requested in Ross's #1166 handoff (#3681 claims this replay with the inherited code; not reviewed here); - physical/prefix/outer release, precision, the inherited all-size hypotheses H1–H5 and the formal kernel. The binary-frame contract is taken from the inherited format. It is not @@ -334,20 +371,24 @@ The structured list is in [TASK.json](TASK.json). 1. **Do the native phases of the paired `span(429,30)` entrance hold?** Every consumer shares this obligation, and the whole width saving rests on it. It needs an independent check of the rank-7 residual on all 512 Gaussian - columns, without the `bw_*` lineage code. + columns, without the `bw_*` lineage code. #3681's full wrapper replay runs + the inherited native chain, so independence is the open part. 2. **Are the `RETIMED644-660` words of #3642/#3653 correct?** First step: run this package's interpreter on them, with the audited STAGED words as the single-change control. Check the identity, the claimed per-invocation change (−2 rank-1, −2 rank-2, +2 rank-3 children), unchanged widths and release-retiming mutants. This is cheap and is now the most decision-relevant local check. -3. **Is each live consumer's own owner journal legal?** These are the T8, T16, - T488, T360 and T530 allocations. By the sensitivity bound above, the group - capacities and bin counts decide the magnitude of the gain; the window - bounds and literal chronology decide legality. +3. **Is each live consumer's own owner journal legal?** These are T450 + (#3624), T530 (#3626), T488 (#3633), T360 (#3638) and the retimed T530/T488 + (#3642/#3653); #3630 is a ceiling bound, not an allocation. Where a + consumer's histogram is checked against the coverage law, as here, the + same argument applies: the window bounds and literal chronology decide + legality, and an owner error changes the gain's size only by moving more + rank mass than that consumer's own threshold. 4. **Are PR3605's own T740 owner windows legal?** PR3605's own κ is already - superseded by its consumers. The decisive check is the 333 source windows of - the aggregate witness. First step: derive the window classes from the T37 + superseded by its consumers, so this is lower priority. The remaining check + is the 333 source windows of the aggregate witness. First step: derive the window classes from the T37 source template without the retained `owner.windows` routine, and compare them with the witness's `groups`. 5. **Is the restore-210 frame edit needed?** It is bill- and identity-neutral diff --git a/research/staged-644-660-independent-audit/ROOT-RESULT.json b/research/staged-644-660-independent-audit/ROOT-RESULT.json index c163341b0c..ac4270bb49 100644 --- a/research/staged-644-660-independent-audit/ROOT-RESULT.json +++ b/research/staged-644-660-independent-audit/ROOT-RESULT.json @@ -2,6 +2,7 @@ "aggregate_witness_recount": { "bins": 1491840, "capacity_rank_units": 35804160, + "controls_rejected": 6, "idle": { "1": 174156, "3": 48334, @@ -30,6 +31,12 @@ "shift_from_PR3148_lower": -9.664152523913857e-05 } }, + "coverage_law": { + "forced_capacity_54W": 35804160, + "per_call_mass_minus_width_units": 1856, + "rank_mass_72W_plus_64N": 48165120, + "rank_mass_moved_PR3148_to_PR3605": 97186 + }, "histograms": { "PR3148": { "M_lower_at_D_minus_1": 2.7336604517475374e-25, @@ -139,6 +146,8 @@ }, "least relabels putting the PR3605 root below 0.00173": 3, "least relabels putting the PR3605 root below the PR3148 root": 98, + "most rank-mass units moved that cannot put the PR3605 root below 0.00173": 133, + "most rank-mass units moved that cannot put the PR3605 root below the PR3148 root": 4678, "one width-8 role moved from a full bin to an empty capacity-48 bin": { "bracket_30_digits": [ "865003138289842471247704021/500000000000000000000000000000", diff --git a/research/staged-644-660-independent-audit/SOURCES.json b/research/staged-644-660-independent-audit/SOURCES.json index abd718ca8e..a132cf5787 100644 --- a/research/staged-644-660-independent-audit/SOURCES.json +++ b/research/staged-644-660-independent-audit/SOURCES.json @@ -166,7 +166,7 @@ "source_pr": 3605, "git_blob": "a5e828b6de7eb691e94eec1ee52ea47fd9a2971f", "sha256": "c10a0eb62799f73dd577a5bec86e91b0124ec8b2cdf95bd68807299cf1521866", - "usage": "read for the aggregate-witness legality checks that root.py reimplements; not imported or executed" + "usage": "read for the aggregate-witness legality checks that root.py reimplements (all but the literal T37 order and the owner.windows window classes/bin counts); not imported or executed" } ], "snapshot_provenance": "Exact Git blob bytes of PR3605 head 3efbb5de (unmerged at base 20ecf289); verify.py authenticates them by SHA256. The PR3133 parent words and PR3148 claim are read from main and pinned in files. Provenance rows: Arham Tahir's coupled-carrier-independent-audit/verify.py, whose frame-bill and free-word structure audit_core.py re-implements without importing; and the inherited auditor audit_local.py, which only the optional crosscheck_inherited.py executes (it also checks this SHA256 itself)." diff --git a/research/staged-644-660-independent-audit/TASK.json b/research/staged-644-660-independent-audit/TASK.json index 864e135472..a8b0da7135 100644 --- a/research/staged-644-660-independent-audit/TASK.json +++ b/research/staged-644-660-independent-audit/TASK.json @@ -48,17 +48,17 @@ "scope_status": "refined", "actual_scope": "Independently audit PR3605 (head 3efbb5de)'s staged 644/660 width 8->7 change against its single-change control, the unchanged PR3133 parent words: exact dirty-input identity in both orientations by two algorithms, literal inverse cleanup, chronological binary frames, local profile and helper widths, PROOF.md's prefix factorization/tables/invoice, required-failing mutants, and exact root brackets for the published PR3605 and PR3148 complete histograms with their attribution.", "scope_change_reason": "The card's first experiment names #2979's joint group; PR3605 is the live descendant of that joint-construction lineage (PR2979 -> PR3133 -> PR3605). Open staged-width kappa>0.00173 claims #3624/#3626/#3633/#3638/#3630 reuse its words unchanged, and #3642/#3653 build RETIMED644-660 words on top of them; all rely on author-run inherited-interpreter checks. Auditing one changed group against its single-change control is the card's method applied to the currently decision-relevant group.", - "bottleneck_link": "Independent pricing of the supplier words that the staged-width chain inherits: a failure would invalidate the whole chain; a pass supplies the independent local check for the unchanged reusers (only the STAGED parent of the retimed #3642/#3653 words), and separates mass-changing from mass-conserving idle errors in the root gain.", + "bottleneck_link": "Independent pricing of the supplier words that the staged-width chain inherits: a failure would invalidate the whole chain; a pass supplies the independent local check for the unchanged reusers (only the STAGED parent of the retimed #3642/#3653 words); the coverage law already excludes mass-changing errors in the root gain, so its size is robust to owner errors moving at most 4,678 units of rank mass and the open risks are the native residual and window/journal legality.", "budget_minutes": 150, "stop_rule": "Ship (c)+(e) with a handoff if the interpreter could not reproduce the parent control by ~75 min; stop and minimize on any identity/cleanup/profile failure; switch to p104-side-correction if another contributor claimed the words first. None triggered.", "outcome": "completed", - "evidence": "PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT (RESULT.json): both providers, parent control {1:2433,2:724,3:228,4:102,5:20,8:8} / widths 7:50,8:99 reproduced; changed words {1:2439,2:726,3:224,4:102,5:20,8:8} / widths 7:52,8:97; 632 inputs, 91 buffers; forward with dirty buffers, dual, and reverse pull-back agree; cleanup literal inverse; PROOF.md factorization P_new=P_old S1 S2 on all registers, target tables and per-register invoice exact; 19 mutants per provider behave as predicted. PASS_EXACT_MOMENT_BRACKETS (ROOT-RESULT.json): on the published histograms, PR3605 [0.001730006549538841847005,...006] and PR3148 [0.0017297774946785970118869,...870] are confirmed by two engines; delta +2.2905486024e-7. The vendored PR3605 aggregate owner witness passes the verify_aggregate.py legality checks (reimplemented) and reproduces I={1:174156,3:48334,4:1,5:10792,6:3,48:283185} with the audited widths, mass(I)=13,966,020 (windows taken as published; literal journal not re-derived). Sensitivity: a mass-changing error of one rank-48 idle child moves the root by 3.498e-7 (more than the gain); a mass-conserving error at fixed groups and widths that moves at most 4,656 units of idle mass cannot cancel the gain (98 rank-48->48x rank-1 relabels are the fewest that do, proved by exact intervals), and one moving at most 96 units cannot take the root below 0.00173.", + "evidence": "PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT (RESULT.json): both providers, parent control {1:2433,2:724,3:228,4:102,5:20,8:8} / widths 7:50,8:99 reproduced; changed words {1:2439,2:726,3:224,4:102,5:20,8:8} / widths 7:52,8:97; 632 inputs, 91 buffers; forward with dirty buffers, dual, and reverse pull-back agree; cleanup literal inverse; PROOF.md factorization P_new=P_old S1 S2 on all registers, target tables and per-register invoice exact; 19 mutants per provider behave as predicted. PASS_EXACT_MOMENT_BRACKETS (ROOT-RESULT.json): on the published histograms, PR3605 [0.001730006549538841847005,...006] and PR3148 [0.0017297774946785970118869,...870] are confirmed by two engines; delta +2.2905486024e-7. The vendored PR3605 aggregate owner witness passes the verify_aggregate.py legality checks (reimplemented) and reproduces I={1:174156,3:48334,4:1,5:10792,6:3,48:283185} with the audited widths, mass(I)=13,966,020 (windows taken as published; literal journal not re-derived). Sensitivity: both histograms meet the coverage law 72W+64N = 48,165,120 and both words have per-call constant 1,856, which forces total owner capacity 54W = 35,804,160 (the witness's), so mass-changing errors (e.g. one rank-48 idle child, root shift 3.498e-7) cannot pass undetected. By linear domination with exact-interval thresholds, any mass-conserving error moving at most 4,678 units of rank mass cannot cancel the gain over PR3148 (98 rank-48->48x rank-1 relabels, 4,704 units, are the fewest that do) and any moving at most 133 units cannot take the root below 0.00173 (3 relabels are the fewest that do). PR3605 and PR3148 differ by 97,186 moved units.", "author": "Sagar Thakrar (thakrarsagar)", "ai_assistance": "Substantial AI assistance from Claude (Anthropic, Claude Opus 5.5): design, code, checks and write-up in an automated research loop. No human or formal-kernel review is claimed.", "open_questions": [ { "question": "Do the native Gaussian phases of the paired span(429,30) entrance (rank-7 residual C_[7] tensor I_[2]) hold on all 512 columns when checked without the bw_* lineage code?", - "why_it_matters": "The old-entrance mutant shows the whole rank-mass saving comes from this entrance frame; every consumer (#3624/#3626/#3633/#3638/#3630/#3642/#3653) shares it, and it is certified only by the inherited native chain.", + "why_it_matters": "The old-entrance mutant shows the whole rank-mass saving comes from this entrance frame; every consumer (#3624/#3626/#3633/#3638/#3630/#3642/#3653) shares it, and it is certified only by the inherited native chain (also run by #3681's full wrapper replay), so independence is the open part.", "first_step": "Implement an independent exact monomial/Gaussian product for T_FULL T_P^-1 and compare with PR3605 check_residual.py's recipe (pinned in SOURCES.json) on all 512 columns, including global phase.", "blocked_by": "Understanding of the native recipe format; no data blocker." }, @@ -69,14 +69,14 @@ "blocked_by": "Nothing; the words are public at #3642 head 044d24f1." }, { - "question": "Is each live consumer's own owner journal (T8, T16, T488, T360, T530 allocations) legal, with window classes derived independently?", - "why_it_matters": "Group capacities and bin counts fix idle mass and hence the magnitude of each gain; the window bounds and literal chronology decide legality.", + "question": "Is each live consumer's own owner journal (T450 #3624, T530 #3626, T488 #3633, T360 #3638, retimed T530/T488 #3642/#3653) legal, with window classes derived independently?", + "why_it_matters": "Where a consumer's histogram is checked against the coverage law, mass-changing owner errors are excluded, so the window bounds and literal chronology decide legality and an owner error changes the gain's size only by moving more rank mass than that consumer's threshold.", "first_step": "For one consumer, derive its window classes from the source template without the retained owner.windows routine and recount its idle histogram.", "blocked_by": "Per-consumer journal formats." }, { "question": "Are PR3605's own 333 T740 owner source windows legal for the audited widths?", - "why_it_matters": "PR3605's own kappa is superseded by its consumers, so this is lower priority; this package takes the witness windows as published.", + "why_it_matters": "PR3605's own kappa is superseded by its consumers, so this is lower priority; this package takes the witness windows as published and does not reimplement verify_aggregate.py's template-derived window-class and literal T37 order checks.", "first_step": "Derive the window classes (capacity, lo, hi, bins) from the T37 source template without the retained owner.windows routine and compare with the witness's groups list.", "blocked_by": "Requires the T37 source template/order format." }, diff --git a/research/staged-644-660-independent-audit/VERIFY.json b/research/staged-644-660-independent-audit/VERIFY.json index 794460dd12..7f6ae985c6 100644 --- a/research/staged-644-660-independent-audit/VERIFY.json +++ b/research/staged-644-660-independent-audit/VERIFY.json @@ -27,7 +27,7 @@ "{package}/root.py" ], "timeout_seconds": 300, - "checks": "Exact interval and decimal-Newton enclosures of the PR3605 and PR3148 complex roots on their published complete histograms, H=6660L+I decompositions, rank-mass invariant, recount of I from the vendored aggregate owner witness with the audited widths and the verify_aggregate.py legality checks (five rejecting controls), attribution hybrids, mass-changing and mass-conserving sensitivity with the exact least relabel counts, receipt comparison." + "checks": "Exact interval and decimal-Newton enclosures of the PR3605 and PR3148 complex roots on their published complete histograms, H=6660L+I decompositions, coverage law 72W+64N and the forced owner capacity 54W, recount of I from the vendored aggregate owner witness with the audited widths and the verify_aggregate.py legality checks except the two template-derived ones (six controls, each rejected for its asserted reason), attribution hybrids, law-violating single-child slopes, and mass-conserving sensitivity with exact direct thresholds and least relabel counts, receipt comparison." } ] } diff --git a/research/staged-644-660-independent-audit/root.py b/research/staged-644-660-independent-audit/root.py index 3cc8eff209..5521b4f1b0 100644 --- a/research/staged-644-660-independent-audit/root.py +++ b/research/staged-644-660-independent-audit/root.py @@ -164,9 +164,10 @@ def aggregate_idle(cert, inventory, local): z rows are (group, macro-call, width, roles). Checks record types and ranges, duplicate records, bin counts, capacities, the open/closed windows as published, width supply = role flow, the per-call demand S*inventory for all 333 macro-calls, - the per-copy group capacity, and the witness's own inventory and profile fields - (the same legality checks as PR3605 owners/verify_aggregate.py, reimplemented). - The windows themselves are taken as published, not derived from the source template. + the per-copy group capacity, the complete paid rank mass 65088*37*S, and the witness's + own inventory and profile fields: every check of PR3605 owners/verify_aggregate.py, + reimplemented, except its two template-derived ones (the literal T37 order, and the + window classes and bin counts from owner.windows). Windows are taken as published. """ widths, S, groups = cert['widths'], cert['S'], cert['groups'] need(widths == [4, 5, 6, 7, 8, 9] and S == 20 and len(cert['order']) == 333, 'aggregate shape') @@ -199,10 +200,26 @@ def aggregate_idle(cert, inventory, local): need(all(demand[t, w] == S * inventory[w] for t in range(333) for w in widths), 'per-call width demand') need(all(n <= S * groups[g][3] for (g, t), n in per_copy.items()), 'per-copy group capacity') profile = Counter({r: 333 * S * n for r, n in local.items()}) + idle + need(sum(r * n for r, n in profile.items()) == 65088 * 37 * S, 'complete paid rank mass') need({int(r): n for r, n in cert['profile'].items()} == profile, 'witness profile field') return idle, sum(S * g[3] for g in groups), sum(S * g[3] * g[0] for g in groups) +def unit_spread(b): + """Interval for c(b) = (73^b - (73/48)^b)/(73*663040), the largest change of M(b) per unit of + rank mass moved between ranks in [1, 48].""" + top, low = moment({1: 1}, b), moment({48: 1}, b) + return down(top[0] - low[1] / 48), up(top[1] - low[0] / 48) + + +def safe_units(hist, point): + """Largest integer m with m*c(point) < 1 - M(point) certified, so that every mass-conserving + change moving at most m units (ranks in [1, 48]) keeps M(point) < 1, i.e. the root above point.""" + gap, spread = 1 - moment(hist, point)[1], unit_spread(point)[1] + need(gap > 0, 'point not below the root', point) + return math.ceil(gap / spread) - 1 + + def relabel(hist, k): """k rank-48 idle children relabelled as 48k rank-1 children (k<0: the reverse); rank mass unchanged.""" out = dict(hist) @@ -243,25 +260,38 @@ def main(): need(times(local_new) + idle_new == Counter(new), 'PR3605 H = 6660 L + I') need(times(local_old) + idle_old == Counter(old), 'PR3148 H = 6660 L + I') mass = lambda h: sum(r * c for r, c in h.items()) - need(mass(new) == mass(old) == 65088 * 740, 'rank mass invariant') + # Coverage law mass(H) = 72W + 64N (W = 896*740 live stock, N = 6660 calls; PR1012 deficit form). + need(mass(new) == mass(old) == 72 * STOCK + 64 * CALLS == 65088 * 740, 'coverage law (rank mass invariant)') cert_path = HERE / 'inputs' / 'AGGREGATE-INTEGER-FLOW.json.gz' need(hashlib.sha256(cert_path.read_bytes()).hexdigest() == pins['inputs/AGGREGATE-INTEGER-FLOW.json.gz'], 'aggregate pin') audited_widths = {4: 26, 5: 2, 6: 18, 7: 52, 8: 97, 9: 213} # derived from frames by verify.py idle_count, bin_count, capacity = aggregate_idle(json.loads(gzip.decompress(cert_path.read_bytes())), audited_widths, local_new) need(idle_count == idle_new, 'aggregate witness idle histogram differs from DERIVATION.md', dict(idle_count)) need(capacity == mass(idle_new) + CALLS * sum(w * c for w, c in audited_widths.items()), 'capacity balance') + # mass(H) = N*(mass(L) - sum w*n_w) + capacity. The per-call constant is 1856 for both audited + # words, so the coverage law forces total owner capacity 54W for PR3605 and PR3148 alike. + parent_widths = {**audited_widths, 7: 50, 8: 99} + per_call = {name: mass(loc) - sum(w * c for w, c in ws.items()) + for name, loc, ws in (('PR3605', local_new, audited_widths), ('PR3148', local_old, parent_widths))} + forced = mass(new) - CALLS * per_call['PR3605'] + need(per_call['PR3605'] == per_call['PR3148'] == 1856 and forced == 54 * STOCK == capacity + == mass(idle_old) + CALLS * sum(w * c for w, c in parent_widths.items()), 'coverage law forces capacity 54W') cert = json.loads(gzip.decompress(cert_path.read_bytes())) window_cut = [row[:] for row in cert['z']] j = next(j for j, row in enumerate(window_cut) if cert['groups'][row[0]][1] >= 0) window_cut[j][1] = cert['groups'][window_cut[j][0]][1] # role on the excluded lower endpoint - for label, bad_cert, widths in (('parent widths 7:50/8:99', cert, {**audited_widths, 7: 50, 8: 99}), - ('one pattern record deleted', {**cert, 'x': cert['x'][1:]}, audited_widths), - ('one pattern record duplicated', {**cert, 'x': cert['x'] + cert['x'][:1]}, audited_widths), - ('one role-flow record deleted', {**cert, 'z': cert['z'][1:]}, audited_widths), - ('role on an excluded lower window endpoint', {**cert, 'z': window_cut}, audited_widths)): + parent_cert = {**cert, 'inventory': {str(w): n for w, n in parent_widths.items()}} + for label, bad_cert, widths, reason in ( + ('parent widths against the witness inventory field', cert, parent_widths, 'witness inventory field'), + ('parent widths, inventory field also set to them', parent_cert, parent_widths, 'per-call width demand'), + ('one pattern record deleted', {**cert, 'x': cert['x'][1:]}, audited_widths, 'bin inventory'), + ('one pattern record duplicated', {**cert, 'x': cert['x'] + cert['x'][:1]}, audited_widths, 'duplicate pattern record'), + ('one role-flow record deleted', {**cert, 'z': cert['z'][1:]}, audited_widths, 'pattern supply differs from role flow'), + ('role on an excluded lower window endpoint', {**cert, 'z': window_cut}, audited_widths, 'source window')): try: aggregate_idle(bad_cert, widths, local_new) - except RootFailure: + except RootFailure as error: + need(str(error).startswith(reason), 'aggregate control rejected for the wrong reason:', label, '/', error) continue raise RootFailure('aggregate control accepted: ' + label) @@ -269,6 +299,7 @@ def main(): 'rank_mass': mass(new), 'stock_times_dimension': M_DIM * STOCK, 'histograms': {}, 'aggregate_witness_recount': {'idle': {str(k): v for k, v in sorted(idle_count.items())}, 'bins': bin_count, 'capacity_rank_units': capacity, + 'controls_rejected': 6, 'scope': 'arithmetic of the published integer witness with the audited ' 'widths; windows as published; no literal journal or chronology'}} published = {'PR3605': (new, [Q(x) for x in pr3605['root_interval']], 24), @@ -301,9 +332,12 @@ def main(): out['attribution'] = attribution out['root_delta_PR3605_minus_PR3148'] = [str(roots['PR3605'][0] - roots['PR3148'][1]), str(roots['PR3605'][1] - roots['PR3148'][0])] - # Mass-changing sensitivity: one idle child added or removed (rank mass changes by r). - # At fixed window classes, bin counts and widths the capacity balance fixes mass(I), so - # these perturbations model group-geometry or width errors, not placement errors. + out['coverage_law'] = {'rank_mass_72W_plus_64N': 72 * STOCK + 64 * CALLS, 'per_call_mass_minus_width_units': 1856, + 'forced_capacity_54W': forced, + 'rank_mass_moved_PR3148_to_PR3605': sum(r * (new.get(r, 0) - old.get(r, 0)) + for r in set(new) | set(old) if new.get(r, 0) > old.get(r, 0))} + # Slopes only: one child added or removed changes rank mass by r, so each perturbed histogram + # violates the coverage law checked above and could not pass undetected. They show scale. sensitivity = {} for r in (1, 48): for sign in (1, -1): @@ -314,13 +348,13 @@ def main(): 'bracket_30_digits': [str(a), str(b)], 'shift_from_PR3605_lower': float(a - roots['PR3605'][0])} out['mass_changing_sensitivity_PR3605'] = sensitivity - # Mass-conserving sensitivity. Idle ranks are capacities minus pattern widths, so lie in - # [1, 48] (capacities 8/16/32/48). For a change moving m units of idle mass, linearity of M - # and 1 <= (73/r)^b / (73/48)^b <= 73^b / (73/48)^b give |dM(b)| <= m*(73^b-(73/48)^b)/(73*663040) - # at every b>0, with equality for relabel(.., m/48). Since M increases in b, every such - # change leaves the root between those of relabel(.., +k) and relabel(.., -k) when m <= 48k. + # Mass-conserving sensitivity (every error the coverage law cannot see). Let m be the + # positive-part rank mass sum_{dH_r>0} r*dH_r of a change dH with sum r*dH_r = 0. If every + # rank before and after lies in [1, 48], linearity of M and (73/48)^b <= (73/r)^b <= 73^b give + # |dM(b)| <= m*c(b) at every b>0 (unit_spread), with equality for relabel(.., m/48). Since M + # increases in b, m <= safe_units(H, b0) keeps the root above b0. capacities = sorted({g[0] for g in cert['groups']}) - need(capacities == [8, 16, 32, 48] and max(idle_new) == 48, 'idle ranks within [1,48]') + need(capacities == [8, 16, 32, 48] and min(new) >= 1 and max(new) == max(old) == 48, 'ranks within [1,48]') conserving = {} for k in (1, -1): a, b = bracket(relabel(new, k), 30) @@ -338,6 +372,11 @@ def main(): k_threshold = min_relabels(new, Q(173, 100000), Q(173, 100000)) conserving['least relabels putting the PR3605 root below the PR3148 root'] = k_gain conserving['least relabels putting the PR3605 root below 0.00173'] = k_threshold + m_gain, m_threshold = safe_units(new, roots['PR3148'][1]), safe_units(new, Q(173, 100000)) + need(48 * (k_gain - 1) <= m_gain < 48 * k_gain and 48 * (k_threshold - 1) <= m_threshold < 48 * k_threshold, + 'direct threshold disagrees with the relabel counts', m_gain, m_threshold) + conserving['most rank-mass units moved that cannot put the PR3605 root below the PR3148 root'] = m_gain + conserving['most rank-mass units moved that cannot put the PR3605 root below 0.00173'] = m_threshold out['mass_conserving_sensitivity_PR3605'] = conserving out['local_delta_per_call'] = {str(r): local_new[r] - local_old[r] for r in sorted(set(local_new) | set(local_old)) if local_new[r] != local_old[r]} out['idle_delta'] = {str(r): idle_new[r] - idle_old[r] for r in sorted(set(idle_new) | set(idle_old)) if idle_new[r] != idle_old[r]} From f798838eb8ede4178e94f240e7b7e54b3f80c82d Mon Sep 17 00:00:00 2001 From: Sagar Thakrar <18622288+thakrarsagar@users.noreply.github.com> Date: Sun, 18 Oct 2026 20:12:34 +0530 Subject: [PATCH 4/4] Revise staged 644/660 audit after review round 3 Text-only fixes: the 4,678-unit threshold bounds cancelling the gain, not its size; name #3682's DELAYED words as a parent-only consumer; split the 97,186 moved units into 66,600 per-call and 30,586 idle repacking; list the coverage law as an inherited assumption; drop the bolded hybrid-residual sentence; weaken the domination hypothesis to published ranks <= 48 and true ranks >= 1 (root.py comment only); disambiguate bin counts; compress the fragility section; put the reproduce command up front. Co-Authored-By: Claude Opus 5.5 --- .../README.md | 146 +++++++++--------- .../TASK.json | 20 +-- .../staged-644-660-independent-audit/root.py | 9 +- 3 files changed, 86 insertions(+), 89 deletions(-) diff --git a/research/staged-644-660-independent-audit/README.md b/research/staged-644-660-independent-audit/README.md index 7825d63b5b..bfc15a07ca 100644 --- a/research/staged-644-660-independent-audit/README.md +++ b/research/staged-644-660-independent-audit/README.md @@ -8,8 +8,11 @@ parent words as the single-change control. **The changed words pass at head literal inverse, and their binary frames give exactly the claimed profile and widths. A pass makes these words an independently checked local input for the open staged-width chain that reuses them unchanged. It does not cover the -retimed words of #3642/#3653, the native phases of the new entrance frame, or -any owner journal. Those remain load-bearing. +retimed words of #3642/#3653/#3682, the native phases of the new entrance +frame, or any owner journal. Those remain load-bearing. + +Reproduce (standard library, about 1–2 min): +`python3 -I -B research/staged-644-660-independent-audit/verify.py && python3 -I -B research/staged-644-660-independent-audit/root.py` In detail, the changed `base` and `extra` words are exact arbitrary-dirty identities in both orientations, with 632 independent inputs and 91 private @@ -52,10 +55,12 @@ submission): are the supplier words. - *Parent only.* #3642 `044d24f1` (roger-sato, T530) and #3653 `607a09ff` (rohanarun, T488, vendoring #3642) carry the same STAGED blobs, but - their claims run `RETIMED644-660` words (`d69125e0`/`f3c580b0`). Those add two - commuting release retimings on top of the audited words, and **they are not - checked here**. Only their STAGED parent is. These are currently the two - highest staged-width claims. + their claims run `RETIMED644-660` words (`d69125e0`/`f3c580b0`). #3682 + `431e6c60` (zxv, T360) also vendors the STAGED blobs and runs its own + `DELAYED` words (`7ccd0962`/`3f1fb471`), which apply the same two commuting + release retimings to different bytes. **None of these retimed words is + checked here**; only their STAGED parent is. #3653 and #3682 report the same + endpoint, the highest among these staged-width claims. PR3605's own semantic check runs the pinned inherited interpreter (`audit_local.py`). This package supplies a separately implemented check of @@ -213,10 +218,10 @@ decomposition is `H = 6660·L + I`. The local change is +6 rank-1, +2 rank-2 and −4 rank-3 children per call. The idle change is `{1:+996, 3:−617, 4:+1, 5:−3083, 6:+3, 48:+616}`. -Swapping one component at a time does not conserve mass and moves the root by -about ±9.7e-5. Those hybrids (0.0018266 and 0.0016331) are arithmetic -counterfactuals, not realized journals. **The net gain is a 0.2% residual of -two opposite mass shifts.** +Swapping one component at a time moves the root by about ±9.7e-5 (hybrids +0.0018266 and 0.0016331). Both hybrids violate the coverage law below (rank +mass 48,165,120 ∓ 13,320), so this split is bookkeeping, not a measure of +fragility. **Recount from the aggregate owner witness.** `root.py` recounts PR3605's published aggregate integer witness @@ -229,10 +234,12 @@ published aggregate integer witness macro-calls. - It passes every check of PR3605's `verify_aggregate.py` (reimplemented) except the two derived from the source template: record types and ranges, - no duplicate records, bin counts, open/closed windows, supply equal to flow, - per-call demand, the per-copy group capacity, the complete paid rank mass, - and its own inventory and profile fields. Not reimplemented: the literal - T37 order, and the window classes and bin counts from `owner.windows`. + no duplicate records, pattern records filling every declared bin (S × bins), + open/closed windows, supply equal to flow, per-call demand, the per-copy + group capacity, the complete paid rank mass, and its own inventory and + profile fields. Not reimplemented: the literal T37 order, and whether the + declared window classes and bin counts equal those `owner.windows` derives + from the template. - The capacity balance `35,804,160 = mass(I) + 6660·3279` holds, so `mass(I) = 13,966,020`. - Six controls are rejected, each for its expected reason (asserted, as @@ -247,55 +254,37 @@ published aggregate integer witness The witness's source windows are taken as published. The literal journal of 2,717,280 helper roles (6660 × 408) and its chronology are not re-derived here. -**How fragile is the gain?** Every complete histogram in this model obeys the -coverage law `Σ r·H[r] = 72W + 64N`, with live stock W = 663,040 and N = 6,660 -calls (the deficit form of PR1012, as used in -`research/complex-queue-ceiling-census`). Both histograms meet it at -48,165,120, and `root.py` checks it. - -For both audited words, a call's local rank mass minus its helper width units -is the same: 5,137 − 3,281 = 5,135 − 3,279 = 1,856. Since -`mass(H) = N·1,856 + total owner capacity`, the law forces total owner capacity -35,804,160 = 54W, for PR3605 and PR3148 alike. The witness meets it. - -- *Mass-changing errors cannot pass undetected.* A wrong capacity or bin - count, or an added or dropped idle child, changes `mass(H)` and breaks the - law. The ±1-child brackets in `ROOT-RESULT.json` are therefore only slopes of - law-violating histograms, kept to show scale: one rank-48 child would move - the root by `∓3.498e-7`, one rank-1 child by `∓7.34e-9`. -- *Every undetected error conserves rank mass.* Let `m` be the rank mass it - moves, the positive part of the net histogram change: - `m = Σ_{ΔH[r] > 0} r·ΔH[r]`. Suppose every rank before and after lies in - [1, 48]. (Idle ranks are capped by the largest capacity, 48, and the local - ranks here are at most 8.) `M` is linear in the histogram and - `(73/48)^b ≤ (73/r)^b ≤ 73^b`, so `|ΔM(b)| ≤ m·c(b)` at every `b`, with - `c(b) = (73^b − (73/48)^b)/(73·663040)`. Equality holds when rank-48 - children are relabelled as 48 rank-1 children. `M` increases in `b`, so - `m < (1 − M(b0))/c(b0)` keeps the root above `b0`. `root.py` evaluates this - threshold with exact intervals: - - at PR3148's root (upper 30-digit endpoint), any such error moving at most - **4,678** units keeps the PR3605 root above it, so it cannot cancel the - gain; - - at 0.00173, any such error moving at most **133** units keeps the root - above 0.00173. - - The relabels show these thresholds are nearly attained. By exact intervals, - 98 relabels (4,704 units) are the fewest that put the root below PR3148's, - and 3 (144 units) the fewest that put it below 0.00173; `root.py` checks - that both counts agree with the direct thresholds. One relabel moves the - root by `∓2.35e-9`. Moving one width-8 role from a full bin to an empty - capacity-48 bin moves it by `−2.73e-10`. The inequality itself is the short - written argument above (repeated in a `root.py` comment); the thresholds and - relabel counts are exact computations. - -So the size of the gain is not where the open risk lies. Owner-layer errors -(window classes, bin assignment, the literal journal) decide legality. They -change the gain's size only if they move more than 4,678 units of rank mass. -Per-call errors in the words or the native entrance act 6,660 times, so they -can: PR3605 and PR3148 have the same total owner capacity yet differ by 97,186 -units of moved rank mass. The open risks are therefore the native residual -(open question 1) and window and journal legality (questions 3 and 4), not -more digits of the root. +**How fragile is the gain?** + +- *Coverage law.* Every complete histogram here obeys `Σ r·H[r] = 72W + 64N` + (W = 663,040, N = 6,660; inherited, see Scope). `root.py` checks both + histograms meet it at 48,165,120, and that both words have the same per-call + constant (local rank mass − helper width units = 1,856), which forces total + owner capacity 54W = 35,804,160, the witness's. So a wrong capacity, bin + count or added/dropped child breaks the law; the ±1-child shifts in + `ROOT-RESULT.json` (rank-48: `∓3.498e-7`) are slopes of law-violating + histograms only. +- *Mass-conserving errors.* Let `m = Σ_{ΔH[r] > 0} r·ΔH[r]` be the rank mass + an error moves. If the removed mass sits at published ranks (at most 48, + checked by `root.py`) and every true rank is at least 1, linearity and + `(73/48)^b ≤ (73/r)^b ≤ 73^b` give `ΔM(b) ≤ m·c(b)`, with + `c(b) = (73^b − (73/48)^b)/(73·663040)`; since `M` increases in `b`, + `m < (1 − M(b0))/c(b0)` keeps the root above `b0`. This inequality is a + written argument; its thresholds are exact-interval computations: an error + can **cancel the gain over PR3148 only if it moves more than 4,678 units**, + and take the root below 0.00173 only above 133. Both are nearly attained: + 98 rank-48 → 48 × rank-1 relabels (4,704 units) and 3 relabels (144 units) + are the fewest that do. Smaller errors still change the gain's size (one + relabel: `∓2.35e-9`; one width-8 role moved to an empty capacity-48 bin: + `−2.73e-10`). +- *Where the risk is.* PR3605 and PR3148 differ by 97,186 moved units: + 66,600 from the per-call word change and 30,586 from idle/owner repacking, + including 616 extra empty capacity-48 bins (29,568 units). So small + accounting slips cannot cancel the gain, but a window or journal legality + failure could, because the idle/owner repacking the gain depends on moves + 6.5 times the threshold. The open risks are the native residual (open + question 1) and window and journal legality (questions 3 and 4), not more + digits of the root. ## Scope, inherited assumptions and unrun obligations @@ -314,13 +303,17 @@ actual invertible warps. Not checked: - native Gaussian/Clifford phases and the rank-7 residual `C_[7]⊗I_[2]` on 512 columns; -- the `RETIMED644-660` words of #3642/#3653; +- the `RETIMED644-660` words of #3642/#3653 and the `DELAYED` words of #3682; - the owner source windows and the literal T740 owner journal (the idle profile is recounted only from the aggregate witness), and every consumer's own owner journal and root; - the PR3605 conditional release and full fresh-bootstrap wrapper replay requested in Ross's #1166 handoff (#3681 claims this replay with the inherited code; not reviewed here); - physical/prefix/outer release, precision, the inherited all-size hypotheses H1–H5 and the formal kernel. The binary-frame contract is taken from the inherited format. It is not -derived from first principles. Gzip streams are not compared; payloads and +derived from first principles. The coverage law `Σ r·H[r] = 72W + 64N` for +this template (the PR1012 deficit form, as used in +`research/complex-queue-ceiling-census`) is likewise inherited and cited, not +re-derived: `root.py` only checks that the published histograms meet it, and +the mass-changing/mass-conserving classification above depends on it. Gzip streams are not compared; payloads and pinned byte digests are. ## Reproduce @@ -335,8 +328,10 @@ python3 -I -B research/staged-644-660-independent-audit/root.py Expected output: - `verify.py`: two `CHECKED` lines, then - `PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT` (about 35 s); -- `root.py`: `PASS_EXACT_MOMENT_BRACKETS` (about 45 s). + `PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT`; +- `root.py`: `PASS_EXACT_MOMENT_BRACKETS`. + +Together they take about 1–2 min, depending on machine load. Both compare against the committed receipts `RESULT.json` and `ROOT-RESULT.json`; `--write` regenerates a receipt deliberately. Failures @@ -373,19 +368,20 @@ The structured list is in [TASK.json](TASK.json). needs an independent check of the rank-7 residual on all 512 Gaussian columns, without the `bw_*` lineage code. #3681's full wrapper replay runs the inherited native chain, so independence is the open part. -2. **Are the `RETIMED644-660` words of #3642/#3653 correct?** First step: run - this package's interpreter on them, with the audited STAGED words as the +2. **Are the retimed words correct?** These are the `RETIMED644-660` words of + #3642/#3653 and the separately built `DELAYED` words of #3682. First step: + run this package's interpreter on each, with the audited STAGED words as the single-change control. Check the identity, the claimed per-invocation change (−2 rank-1, −2 rank-2, +2 rank-3 children), unchanged widths and release-retiming mutants. This is cheap and is now the most decision-relevant local check. 3. **Is each live consumer's own owner journal legal?** These are T450 - (#3624), T530 (#3626), T488 (#3633), T360 (#3638) and the retimed T530/T488 - (#3642/#3653); #3630 is a ceiling bound, not an allocation. Where a - consumer's histogram is checked against the coverage law, as here, the - same argument applies: the window bounds and literal chronology decide - legality, and an owner error changes the gain's size only by moving more - rank mass than that consumer's own threshold. + (#3624), T530 (#3626), T488 (#3633), T360 (#3638), the retimed T530/T488 + (#3642/#3653) and the retimed T360 (#3682); #3630 is a ceiling bound, not + an allocation. Where a consumer's histogram is checked against the coverage + law, as here, the same argument applies: the window bounds and literal + chronology decide legality, and an owner error can cancel that consumer's + gain only by moving more rank mass than its own threshold. 4. **Are PR3605's own T740 owner windows legal?** PR3605's own κ is already superseded by its consumers, so this is lower priority. The remaining check is the 333 source windows of the aggregate witness. First step: derive the window classes from the T37 diff --git a/research/staged-644-660-independent-audit/TASK.json b/research/staged-644-660-independent-audit/TASK.json index a8b0da7135..55317f69c7 100644 --- a/research/staged-644-660-independent-audit/TASK.json +++ b/research/staged-644-660-independent-audit/TASK.json @@ -47,30 +47,30 @@ }, "scope_status": "refined", "actual_scope": "Independently audit PR3605 (head 3efbb5de)'s staged 644/660 width 8->7 change against its single-change control, the unchanged PR3133 parent words: exact dirty-input identity in both orientations by two algorithms, literal inverse cleanup, chronological binary frames, local profile and helper widths, PROOF.md's prefix factorization/tables/invoice, required-failing mutants, and exact root brackets for the published PR3605 and PR3148 complete histograms with their attribution.", - "scope_change_reason": "The card's first experiment names #2979's joint group; PR3605 is the live descendant of that joint-construction lineage (PR2979 -> PR3133 -> PR3605). Open staged-width kappa>0.00173 claims #3624/#3626/#3633/#3638/#3630 reuse its words unchanged, and #3642/#3653 build RETIMED644-660 words on top of them; all rely on author-run inherited-interpreter checks. Auditing one changed group against its single-change control is the card's method applied to the currently decision-relevant group.", - "bottleneck_link": "Independent pricing of the supplier words that the staged-width chain inherits: a failure would invalidate the whole chain; a pass supplies the independent local check for the unchanged reusers (only the STAGED parent of the retimed #3642/#3653 words); the coverage law already excludes mass-changing errors in the root gain, so its size is robust to owner errors moving at most 4,678 units of rank mass and the open risks are the native residual and window/journal legality.", + "scope_change_reason": "The card's first experiment names #2979's joint group; PR3605 is the live descendant of that joint-construction lineage (PR2979 -> PR3133 -> PR3605). Open staged-width kappa>0.00173 claims #3624/#3626/#3633/#3638/#3630 reuse its words unchanged, #3642/#3653 build RETIMED644-660 words and #3682 builds DELAYED words on top of them; all rely on author-run inherited-interpreter checks. Auditing one changed group against its single-change control is the card's method applied to the currently decision-relevant group.", + "bottleneck_link": "Independent pricing of the supplier words that the staged-width chain inherits: a failure would invalidate the whole chain; a pass supplies the independent local check for the unchanged reusers (only the STAGED parent of the retimed #3642/#3653/#3682 words); the coverage law (inherited) already excludes mass-changing errors in the root gain, so the gain's sign is robust to owner errors moving at most 4,678 units of rank mass; but the idle repacking behind the gain moves 30,586 units, so window/journal legality and the native residual are the open risks.", "budget_minutes": 150, "stop_rule": "Ship (c)+(e) with a handoff if the interpreter could not reproduce the parent control by ~75 min; stop and minimize on any identity/cleanup/profile failure; switch to p104-side-correction if another contributor claimed the words first. None triggered.", "outcome": "completed", - "evidence": "PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT (RESULT.json): both providers, parent control {1:2433,2:724,3:228,4:102,5:20,8:8} / widths 7:50,8:99 reproduced; changed words {1:2439,2:726,3:224,4:102,5:20,8:8} / widths 7:52,8:97; 632 inputs, 91 buffers; forward with dirty buffers, dual, and reverse pull-back agree; cleanup literal inverse; PROOF.md factorization P_new=P_old S1 S2 on all registers, target tables and per-register invoice exact; 19 mutants per provider behave as predicted. PASS_EXACT_MOMENT_BRACKETS (ROOT-RESULT.json): on the published histograms, PR3605 [0.001730006549538841847005,...006] and PR3148 [0.0017297774946785970118869,...870] are confirmed by two engines; delta +2.2905486024e-7. The vendored PR3605 aggregate owner witness passes the verify_aggregate.py legality checks (reimplemented) and reproduces I={1:174156,3:48334,4:1,5:10792,6:3,48:283185} with the audited widths, mass(I)=13,966,020 (windows taken as published; literal journal not re-derived). Sensitivity: both histograms meet the coverage law 72W+64N = 48,165,120 and both words have per-call constant 1,856, which forces total owner capacity 54W = 35,804,160 (the witness's), so mass-changing errors (e.g. one rank-48 idle child, root shift 3.498e-7) cannot pass undetected. By linear domination with exact-interval thresholds, any mass-conserving error moving at most 4,678 units of rank mass cannot cancel the gain over PR3148 (98 rank-48->48x rank-1 relabels, 4,704 units, are the fewest that do) and any moving at most 133 units cannot take the root below 0.00173 (3 relabels are the fewest that do). PR3605 and PR3148 differ by 97,186 moved units.", + "evidence": "PASS_INDEPENDENT_STAGED_644_660_WORD_AUDIT (RESULT.json): both providers, parent control {1:2433,2:724,3:228,4:102,5:20,8:8} / widths 7:50,8:99 reproduced; changed words {1:2439,2:726,3:224,4:102,5:20,8:8} / widths 7:52,8:97; 632 inputs, 91 buffers; forward with dirty buffers, dual, and reverse pull-back agree; cleanup literal inverse; PROOF.md factorization P_new=P_old S1 S2 on all registers, target tables and per-register invoice exact; 19 mutants per provider behave as predicted. PASS_EXACT_MOMENT_BRACKETS (ROOT-RESULT.json): on the published histograms, PR3605 [0.001730006549538841847005,...006] and PR3148 [0.0017297774946785970118869,...870] are confirmed by two engines; delta +2.2905486024e-7. The vendored PR3605 aggregate owner witness passes the verify_aggregate.py legality checks (reimplemented) and reproduces I={1:174156,3:48334,4:1,5:10792,6:3,48:283185} with the audited widths, mass(I)=13,966,020 (windows taken as published; literal journal not re-derived). Sensitivity: both histograms meet the coverage law 72W+64N = 48,165,120 (inherited PR1012 deficit form, checked but not re-derived) and both words have per-call constant 1,856, which forces total owner capacity 54W = 35,804,160 (the witness's), so mass-changing errors (e.g. one rank-48 idle child, root shift 3.498e-7) cannot pass undetected. By linear domination with exact-interval thresholds, any mass-conserving error moving at most 4,678 units of rank mass cannot cancel the gain over PR3148 (98 rank-48->48x rank-1 relabels, 4,704 units, are the fewest that do) and any moving at most 133 units cannot take the root below 0.00173 (3 relabels are the fewest that do). PR3605 and PR3148 differ by 97,186 moved units.", "author": "Sagar Thakrar (thakrarsagar)", "ai_assistance": "Substantial AI assistance from Claude (Anthropic, Claude Opus 5.5): design, code, checks and write-up in an automated research loop. No human or formal-kernel review is claimed.", "open_questions": [ { "question": "Do the native Gaussian phases of the paired span(429,30) entrance (rank-7 residual C_[7] tensor I_[2]) hold on all 512 columns when checked without the bw_* lineage code?", - "why_it_matters": "The old-entrance mutant shows the whole rank-mass saving comes from this entrance frame; every consumer (#3624/#3626/#3633/#3638/#3630/#3642/#3653) shares it, and it is certified only by the inherited native chain (also run by #3681's full wrapper replay), so independence is the open part.", + "why_it_matters": "The old-entrance mutant shows the whole rank-mass saving comes from this entrance frame; every consumer (#3624/#3626/#3633/#3638/#3630/#3642/#3653/#3682) shares it, and it is certified only by the inherited native chain (also run by #3681's full wrapper replay), so independence is the open part.", "first_step": "Implement an independent exact monomial/Gaussian product for T_FULL T_P^-1 and compare with PR3605 check_residual.py's recipe (pinned in SOURCES.json) on all 512 columns, including global phase.", "blocked_by": "Understanding of the native recipe format; no data blocker." }, { - "question": "Are the RETIMED644-660 words of #3642/#3653 (blobs d69125e0/f3c580b0) exact identities with the claimed per-invocation change -2 rank-1, -2 rank-2, +2 rank-3 and unchanged widths?", - "why_it_matters": "They carry the two highest staged-width claims and only their STAGED parent is covered by this audit.", - "first_step": "Run this package's audit_core interpreter on the RETIMED words with the audited STAGED words as the single-change control; add release-retiming mutants.", - "blocked_by": "Nothing; the words are public at #3642 head 044d24f1." + "question": "Are the RETIMED644-660 words of #3642/#3653 (blobs d69125e0/f3c580b0) and the separately built DELAYED words of #3682 (blobs 7ccd0962/3f1fb471) exact identities with the claimed per-invocation change -2 rank-1, -2 rank-2, +2 rank-3 and unchanged widths?", + "why_it_matters": "They carry the highest staged-width claims (#3653 and #3682 report the same endpoint) and only their STAGED parent is covered by this audit.", + "first_step": "Run this package's audit_core interpreter on the RETIMED and DELAYED words with the audited STAGED words as the single-change control; add release-retiming mutants.", + "blocked_by": "Nothing; the words are public at #3642 head 044d24f1 and #3682 head 431e6c60." }, { - "question": "Is each live consumer's own owner journal (T450 #3624, T530 #3626, T488 #3633, T360 #3638, retimed T530/T488 #3642/#3653) legal, with window classes derived independently?", - "why_it_matters": "Where a consumer's histogram is checked against the coverage law, mass-changing owner errors are excluded, so the window bounds and literal chronology decide legality and an owner error changes the gain's size only by moving more rank mass than that consumer's threshold.", + "question": "Is each live consumer's own owner journal (T450 #3624, T530 #3626, T488 #3633, T360 #3638, retimed T530/T488 #3642/#3653, retimed T360 #3682) legal, with window classes derived independently?", + "why_it_matters": "Where a consumer's histogram is checked against the coverage law, mass-changing owner errors are excluded, so the window bounds and literal chronology decide legality; an owner error can cancel that consumer's gain only by moving more rank mass than its own threshold, but idle repacking (30,586 units for PR3605 vs PR3148) can exceed such thresholds.", "first_step": "For one consumer, derive its window classes from the source template without the retained owner.windows routine and recount its idle histogram.", "blocked_by": "Per-consumer journal formats." }, diff --git a/research/staged-644-660-independent-audit/root.py b/research/staged-644-660-independent-audit/root.py index 5521b4f1b0..79c304c761 100644 --- a/research/staged-644-660-independent-audit/root.py +++ b/research/staged-644-660-independent-audit/root.py @@ -349,10 +349,11 @@ def main(): 'shift_from_PR3605_lower': float(a - roots['PR3605'][0])} out['mass_changing_sensitivity_PR3605'] = sensitivity # Mass-conserving sensitivity (every error the coverage law cannot see). Let m be the - # positive-part rank mass sum_{dH_r>0} r*dH_r of a change dH with sum r*dH_r = 0. If every - # rank before and after lies in [1, 48], linearity of M and (73/48)^b <= (73/r)^b <= 73^b give - # |dM(b)| <= m*c(b) at every b>0 (unit_spread), with equality for relabel(.., m/48). Since M - # increases in b, m <= safe_units(H, b0) keeps the root above b0. + # positive-part rank mass sum_{dH_r>0} r*dH_r of a change dH with sum r*dH_r = 0. If the + # removed mass sits at published ranks (<= 48, checked below) and every true rank is >= 1, + # linearity of M and (73/48)^b <= (73/r)^b <= 73^b give dM(b) <= m*c(b) at every b>0 + # (unit_spread), with equality for relabel(.., m/48). Since M increases in b, + # m <= safe_units(H, b0) keeps the root above b0. capacities = sorted({g[0] for g in cert['groups']}) need(capacities == [8, 16, 32, 48] and min(new) >= 1 and max(new) == max(old) == 48, 'ranks within [1,48]') conserving = {}