diff --git a/research/selected-invoice-reference-rebinding/README.md b/research/selected-invoice-reference-rebinding/README.md new file mode 100644 index 0000000000..09e5f31d4b --- /dev/null +++ b/research/selected-invoice-reference-rebinding/README.md @@ -0,0 +1,231 @@ +# Authenticate invoice references before portable comparison + +**Verifier engineering; an opt-in three-node comparison, not mathematical +admission. No new supplier, physical claim, paid profile or κ.** This closes the +explicit invoice-reference handoff in [PR2040](https://github.com/CrocSwap/integer-mult-bounds/pull/2040) +without editing a frozen caller or any selected source. + +## Result and concrete scope + +The reviewed PR1094 strict-output corpus has **105 files**. Its generated +`global/audit/PREFIX-AND-INVOICE.json` has exactly **two direct raw SHA-256 +references** in that corpus: + +- `ADMISSION-CONTROLS.json#/input_sha256/fresh_invoice`; +- `ASSEMBLY.json#/input_sha256/fresh_invoice`. + +The census inspects every plain/gzip JSON payload and every decompressed file's +literal digest occurrences, including logs. Both the count and the precise +locations are checked, not inferred from filenames. The actual input is the +raw-hash-pinned `community-frontier1094-audit/selected-replay.tar.gz`; its archived +assembly is also byte-equal to the selected committed certificate and bound by +the archived and committed `RESULT.json`. + +PR2040 reports that Linux reordered invoice object keys: the invoice raw digest +changed from `212cf4ee…0d12` to `e3fc03bf…6ca2`, and both references changed with +it. Its strict comparator intentionally flags those references and leaves their +source-bound normalization open. **That Linux observation is predecessor +attribution, not a platform run performed here.** Our experiment constructs a +format-only variant of the authenticated invoice, updates both literal raw +references, and independently establishes complete typed payload equality. On +this fixture the retained PR1824 comparator calls the invoice `json-format` but +flags each consumer `proof-relevant-candidate`, with exactly one differing field. +The new predicate accepts this valid graph without ignoring either reference. + +| Authenticated artifact | Bytes | Tree nodes | Contents retained | +| --- | ---: | ---: | --- | +| Invoice | 78,165 | 2,649 | Every field, list position, scalar and empty container | +| Admission controls | 4,184 | 96 | Every field; the one validated invoice edge is rebound | +| Assembly | 85,147 | 296 | Every field; the one validated invoice edge is rebound | +| **Total** | **167,496** | **3,041** | No timing/path/digest-name exemptions | + +`compare_invoice.py` is deliberately limited to these three named artifacts. +It is **not** a replacement for a full-output comparator, a new production +acceptance rule, a supplier replay, or a validator of all other digest edges. +The unchanged external references remain exact strings in the comparison. Its +CLI reads these three paths below each `strict` directory; other files are out +of scope. The Python API requires an exact three-file mapping. + +## Exact predicate and why no field disappears + +Let `I` be the invoice bytes, `R₁,R₂` the two consumer bytes, `H` SHA-256, and +`C` the complete canonical encoding of parsed JSON. The accepted domain is the +reviewed JSON tree grammar: objects with unique string keys, arrays, strings, +integers, Booleans and null. Decimal/exponent number tokens, nonfinite values, +and duplicate keys **reject**, rather than falling back to binary64 or treating +`true` as `1`. All three actual artifacts lie within this domain. Numbers in +rational/decimal **strings** remain exact strings. +Integers compare by exact parsed value (thus `-0` and `0` denote the same +integer), not by the spelling of their source token. + +For **each side separately**, before performing any equality shortcut: + +1. Parse all three files and require object roots. +2. Require **both** `Rᵢ.input_sha256.fresh_invoice = H(I)` as literal strings. +3. Form `C(I)` with sorted object keys, fixed separators and escaped strings. +4. In each freshly parsed consumer, replace exactly that authenticated edge + value with `H(C(I))`; retain every other key and value. +5. Compare `C(I)` and both complete rebound consumer encodings **by bytes** + against the corresponding reference encodings. Digests in the report are + receipts; they do not replace those three byte comparisons. + +**Critical proof step.** On this grammar, canonical JSON is injective modulo +object-key order, insignificant whitespace and equivalent JSON string escapes: +the JSON grammar distinguishes each scalar type, preserves every object key and +array index, and the serializer retains every value. Thus invoice equality +implies equality of the entire invoice tree, not only its status, κ or hash. +Only after the literal raw links have authenticated on both sides is their +representation changed. If the invoice payload changes, its byte comparison +fails even when both raw links are consistently updated. If either link is +stale, normalization is never reached. For equal invoices, the two substitutions +are equal; complete consumer comparison then checks every remaining field. +SHA-256 collision resistance is the inherited assumption for authenticating raw +links and immutable inputs, not a claim of universal mathematical injectivity. + +The independent oracle does **not** use this serializer or the canonical digest +as its expected identity. It recursively tags every value by type, includes all +keys/positions/empty containers, and represents each authenticated edge as the +explicit tuple `("edge", invoice_path)`. The primary projection must agree with +the full original oracle tree after these two role substitutions. A focused +oracle-fault control deletes `provider_phase_semantic_sha256` and detects the +loss. This is a written argument plus executable evidence, not a formal kernel +proof of Python or JSON. + +## Evidence and semantic controls + +[`RESULT.json`](RESULT.json) is deterministic and contains the complete source +census, raw/canonical hashes, type counts, positive-witness hashes, before +classifications, per-artifact negative counts and a reproducible mutation +transcript SHA-256. The transcript covers the declared full enumeration, not a +random sample: + +- **6,076 field mutations:** omit and replace each of the 3,038 nonroot tree + nodes once. This includes all nested objects, array positions, receipt fields, + known and unknown digests, proof values, and empty containers. +- **5,296 of those mutations change the invoice** and then correctly update + **both** consumer raw links. Every one still rejects. This is the crucial + difference from unvalidated whole-file hash substitution. +- **57 further negatives:** stale links, just one repaired link, links misbound + to `owner_audit`, identical stale graphs, duplicate keys, nonfinite or decimal + tokens, missing files, unfamiliar fields, and all **27 Boolean-to-integer** + substitutions in these artifacts. **6,133 negatives total.** +- **Seven positive controls:** identical valid input; sorted/compact invoice; + recursively reversed object order; an equivalent string escape; each consumer + reformatted independently; and all three reformatted together. Every invoice + format change carries freshly authenticated links. List order is never free. + +Eight focused tests additionally cover CLI exit status (0 equivalent, 1 different, +2 invalid/missing), both-side edge validation, the independent oracle, precise +number/type handling, and immutable-source handling. The source-header control +changes only the pinned archive's gzip MTIME byte, proves its decompressed tar +unchanged, then requires **raw source-pin rejection**. Generated JSON formatting +permission is never applied to immutable source archives. + +## Reproduce + +CPython 3.12 standard library, from the repository root: + +```sh +uv run --python 3.12 --no-project python -I -B research/selected-invoice-reference-rebinding/verify.py +uv run --python 3.12 --no-project python -I -O -B research/selected-invoice-reference-rebinding/test_compare.py +uv run --python 3.12 --no-project python -B scripts/research_package.py --package research/selected-invoice-reference-rebinding +``` + +Expected direct marker: + +```text +PASS_SELECTED_INVOICE_REFERENCE_REBINDING files=105 nodes=3041 edges=2 positives=7 field_mutations=6076 synchronized_invoice_mutations=5296 negatives=6133 no_new_kappa +``` + +The first-generation experiment (`verify.py --write-result`) completed in +17.14 seconds including the uv launcher on macOS arm64, CPython 3.12. It refuses +to overwrite a result. Ordinary replay writes only temporary before-comparison +fixtures and compares the **complete** generated receipt against `RESULT.json`. +No archive is regenerated; no network, native compiler or third-party package is +used. This is not a replay-runtime/speedup claim. + +Final focused verification on **CPython 3.12.12** ran the direct audit, all eight +tests under `-I -O -B`, the metadata/pin check, then the registered replay in one +serial batch (**31.45 seconds** including launchers). Every command passed; +the registered replay repeated the audit and eight tests, ending with +`PASS_REGISTERED_RESEARCH_PACKAGE research/selected-invoice-reference-rebinding outcome=completed`. +The focused test runs took 0.298 and 0.299 seconds. No remote CI was run or claimed. + +To compare two already-produced strict directories: + +```sh +python3.12 -I -B research/selected-invoice-reference-rebinding/compare_invoice.py REF_STRICT RUN_STRICT +``` + +The CLI establishes equivalence/integrity of these three nodes only. Its caller +must trust its reference independently. The registered verifier supplies that +trust through the immutable archive pins; it does not infer mathematical truth +from self-consistent hashes. The chosen card's first working example, +`research_baseline.py`, returned `PASS_RESEARCH_BASELINE_BINDINGS_ONLY` at the +unchanged selected κ `0.001672660197076918` before the experiment. + +## Provenance, overlap and limits + +Base: `e112d71c8d7bb32435debcc54df932593dd8223a`. The chooser was run exactly +once without overrides; complete seed/cards are in [`SELECTION.json`](SELECTION.json), +seed `a2e5a793b5e1a2555a2466367171c2ea`. The refined scope and full optimistic +engineering acceptance budget were written in [`TASK.json`](TASK.json) before +substantial computation. [`SOURCES.json`](SOURCES.json) pins exact Git blobs and +raw SHA-256; [`VERIFY.json`](VERIFY.json) registers all live external inputs. +Claim: [discussion2049](https://github.com/CrocSwap/integer-mult-bounds/discussions/2049#discussioncomment-18931179). + +Nearest work and distinctions: + +- PR2040, head `d31c1418c0c23994d1444dbd9d356b9a8238fd5e`, establishes typed/path + false equivalences and explicitly hands off invoice reference rebinding. This + contribution consumes no unmerged PR2040 code or unverifiable Linux payload. +- PR1824, head `ad5b1248f25a71983b20617e2f3a80be22f03990`, supplies the retained + before comparator. We do not weaken its frozen expectations in place. +- [Selected generated identity audit](../selected-generated-identity-audit/README.md) + covers seven **different local artifacts**, not these invoice consumers. Its + underlying `generated_identity.py` is precedent for authenticate-then-rebind; + that source remains unchanged and its attribution pin is retained. +- [PR695 digest audit](../pr695-digest-audit/README.md) warns that propagating a + hash alone can hide semantic change. Here all invoice fields are present and + compared, including 5,296 synchronized-mutation rejections. We make no claim + about its unavailable historical CI payloads or different template graph. + +The shared overlap snapshot covered 329 open PRs including drafts (18:11:09Z) +and 692 discussions with comments/replies (18:12:32Z), complete pagination on +2026-10-14. Exact `rebinding` search, local/merged predecessors and PR2040's live +body/head were inspected. The final targeted check confirmed PR2040 still open +at the pinned head and PR1824 merged at its pinned head (2026-10-14 16:34:44Z). +The repeated cached query added only this package's README/TASK to its prior +matches. Cached coverage can miss later changes; no-match is not novelty. +No older contribution has been resubmitted. + +Not established: all-output equivalence, a Linux/Windows run, a full cold +supplier replay, production adoption, mathematical admission, improved κ, any +all-size/compiler/hosting/precision/analytic discharge, or GitHub CI success. +This package does not modify the selected record, source archives, shared indices +or predecessor code. Decimal JSON tokens outside the actual grammar fail closed; +a future format requiring them needs a separately reviewed exact extension. + +## Open next questions + +Should a future selected-final-stage wrapper adopt this predicate? This matters +because it supplies the missing source-bound handling of the two raw invoice +references. The feasible first step is to compose it with a separately reviewed +full-output comparator and explicit per-field time/path policy, then replay that +whole caller. **Blocked by maintainer adoption and caller/source-pin review, not +by an assertion that the remaining graph is already certified.** The structured +question is in `TASK.json`. + +## Credit and license + +Credit Josie Elliston (@JosieElliston, PR1824), commdata2338 (PR2040 and its named +handoff), Maxime Fleury and Antoine Olivier (gzip reproducibility convention), +Rohan Guliani and Joshua Snider (PR695 diagnostic/warning), Adam Gall's earlier +local generated-identity audit, and the retained selected supplier/compiler +lineage including Rohan Arun, Jeremy Kothe, Hao Yan and Douglas Colkitt. Exact +selected source head: PR1094 `0fc329d0bec93ca7cd288eaea1295172e8789810`. + +Prepared for Adam Gall (@adamgall) with **substantial OpenAI Codex (GPT-6 Astra) +assistance** in design, implementation, experiments, tests and writing. No +independent human review claimed. New work is Apache-2.0; all predecessor files +and notices are unchanged. diff --git a/research/selected-invoice-reference-rebinding/RESULT.json b/research/selected-invoice-reference-rebinding/RESULT.json new file mode 100644 index 0000000000..fdc0170084 --- /dev/null +++ b/research/selected-invoice-reference-rebinding/RESULT.json @@ -0,0 +1,412 @@ +{ + "artifacts": { + "ADMISSION-CONTROLS.json": { + "bytes": 4184, + "canonical_sha256": "213e9a511d3d9c8fbe82d4d490348ffc75f9f65438b313aa614b89b478098cf1", + "nodes": 96, + "raw_sha256": "9d408a0c84fbca7e873b2411590c6c2b526951bc975a26430c9a4baf3fb0fb27", + "types": { + "dict": 2, + "list": 5, + "str": 89 + } + }, + "ASSEMBLY.json": { + "bytes": 85147, + "canonical_sha256": "29c9e97e1da586d0172fce5a31592d3522b5e78bde6f8c0c4d7d7107e21e8331", + "nodes": 296, + "raw_sha256": "1122cb3a575f8c788345fc1bf4c108ac7c3250fb81a5988671f5eb04b3ab3045", + "types": { + "bool": 14, + "dict": 29, + "int": 22, + "list": 20, + "str": 211 + } + }, + "global/audit/PREFIX-AND-INVOICE.json": { + "bytes": 78165, + "canonical_sha256": "4772da5f1373b20d622104e7ee85b64902704e2a5b7fc90f93e17de3c38280ed", + "nodes": 2649, + "raw_sha256": "212cf4ee3b16081bf66f300fa18b4070d25c17210c21c78c2967892c91870d12", + "types": { + "bool": 13, + "dict": 162, + "int": 2007, + "list": 3, + "str": 464 + } + } + }, + "before_comparison": { + "ADMISSION-CONTROLS.json": { + "cls": "json-diff", + "differing": 1, + "examples": [ + [ + "/input_sha256/fresh_invoice", + "'212cf4ee3b16081bf66f300fa18b4070d25c17210c21c78c2967892c91870d12'", + "'384e1f00761e07e3bb301f5579caa439e9db8798faa2571563e9153b55789d54'" + ] + ], + "gzip": false, + "verdict": "proof-relevant-candidate" + }, + "ASSEMBLY.json": { + "cls": "json-diff", + "differing": 1, + "examples": [ + [ + "/input_sha256/fresh_invoice", + "'212cf4ee3b16081bf66f300fa18b4070d25c17210c21c78c2967892c91870d12'", + "'384e1f00761e07e3bb301f5579caa439e9db8798faa2571563e9153b55789d54'" + ] + ], + "gzip": false, + "verdict": "proof-relevant-candidate" + }, + "global/audit/PREFIX-AND-INVOICE.json": { + "cls": "json-format", + "gzip": false + } + }, + "edge_and_parser_controls": [ + { + "name": "reformatted-invoice-both-edges-stale", + "verdict": "invalid-graph" + }, + { + "name": "identical-stale-graphs-no-byte-shortcut", + "verdict": "invalid-graph" + }, + { + "name": "only-other-edge-rebound:ADMISSION-CONTROLS.json", + "verdict": "invalid-graph" + }, + { + "name": "misbound-to-owner-audit:ADMISSION-CONTROLS.json", + "verdict": "invalid-graph" + }, + { + "name": "only-other-edge-rebound:ASSEMBLY.json", + "verdict": "invalid-graph" + }, + { + "name": "misbound-to-owner-audit:ASSEMBLY.json", + "verdict": "invalid-graph" + }, + { + "name": "duplicate-key:global/audit/PREFIX-AND-INVOICE.json", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:global/audit/PREFIX-AND-INVOICE.json:NaN", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:global/audit/PREFIX-AND-INVOICE.json:Infinity", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:global/audit/PREFIX-AND-INVOICE.json:-Infinity", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:global/audit/PREFIX-AND-INVOICE.json:1.0", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:global/audit/PREFIX-AND-INVOICE.json:1e0", + "verdict": "invalid-graph" + }, + { + "name": "missing-file:global/audit/PREFIX-AND-INVOICE.json", + "verdict": "invalid-graph" + }, + { + "name": "unfamiliar-field-retained:global/audit/PREFIX-AND-INVOICE.json", + "verdict": "different-complete-payload" + }, + { + "name": "duplicate-key:ADMISSION-CONTROLS.json", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:ADMISSION-CONTROLS.json:NaN", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:ADMISSION-CONTROLS.json:Infinity", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:ADMISSION-CONTROLS.json:-Infinity", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:ADMISSION-CONTROLS.json:1.0", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:ADMISSION-CONTROLS.json:1e0", + "verdict": "invalid-graph" + }, + { + "name": "missing-file:ADMISSION-CONTROLS.json", + "verdict": "invalid-graph" + }, + { + "name": "unfamiliar-field-retained:ADMISSION-CONTROLS.json", + "verdict": "different-complete-payload" + }, + { + "name": "duplicate-key:ASSEMBLY.json", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:ASSEMBLY.json:NaN", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:ASSEMBLY.json:Infinity", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:ASSEMBLY.json:-Infinity", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:ASSEMBLY.json:1.0", + "verdict": "invalid-graph" + }, + { + "name": "unsupported-number:ASSEMBLY.json:1e0", + "verdict": "invalid-graph" + }, + { + "name": "missing-file:ASSEMBLY.json", + "verdict": "invalid-graph" + }, + { + "name": "unfamiliar-field-retained:ASSEMBLY.json", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('providers', 'gauge44', 'local', 'backward', 'all_dirty_helper_columns_restored')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('providers', 'gauge44', 'local', 'backward', 'private_centres_and_coefficient_work_cleared')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('providers', 'gauge44', 'local', 'forward', 'all_dirty_helper_columns_restored')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('providers', 'gauge44', 'local', 'forward', 'private_centres_and_coefficient_work_cleared')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('strict_checks', 'halving')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('strict_checks', 'literal')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('strict_checks', 'local_primitive_bound')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('strict_checks', 'logical')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('strict_checks', 'mass')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('strict_checks', 'precision')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('strict_checks', 'router')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('strict_checks', 'row')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:global/audit/PREFIX-AND-INVOICE.json:('strict_checks', 'tape')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('conservative_moments', 0, 'accept')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('conservative_moments', 0, 'surcharge')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('conservative_moments', 1, 'accept')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('conservative_moments', 1, 'surcharge')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('moments', 0, 'accept')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('moments', 0, 'surcharge')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('moments', 1, 'accept')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('moments', 1, 'surcharge')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('moments', 2, 'accept')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('moments', 2, 'surcharge')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('moments', 3, 'accept')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('moments', 3, 'surcharge')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('surcharge_model', 'bit')", + "verdict": "different-complete-payload" + }, + { + "name": "boolean-to-integer:ASSEMBLY.json:('surcharge_model', 'complex')", + "verdict": "different-complete-payload" + } + ], + "field_mutation_total": 6076, + "field_mutation_transcript_sha256": "d424e9a5cecb45396094199005fdf944e31a81b9ed48c603f950ca7b18d234e5", + "field_mutations": { + "ADMISSION-CONTROLS.json": { + "different-complete-payload": 186, + "invalid-raw-edge": 4 + }, + "ASSEMBLY.json": { + "different-complete-payload": 586, + "invalid-raw-edge": 4 + }, + "global/audit/PREFIX-AND-INVOICE.json": { + "different-complete-payload": 5296 + } + }, + "negative_controls": 6133, + "positive_controls": [ + { + "name": "identical-valid-subgraph", + "raw_sha256": { + "ADMISSION-CONTROLS.json": "9d408a0c84fbca7e873b2411590c6c2b526951bc975a26430c9a4baf3fb0fb27", + "ASSEMBLY.json": "1122cb3a575f8c788345fc1bf4c108ac7c3250fb81a5988671f5eb04b3ab3045", + "global/audit/PREFIX-AND-INVOICE.json": "212cf4ee3b16081bf66f300fa18b4070d25c17210c21c78c2967892c91870d12" + } + }, + { + "name": "sorted-compact-invoice-both-edges-rebound", + "raw_sha256": { + "ADMISSION-CONTROLS.json": "ae8d5756f36ccdc4231571c21d25b9d1b5cb23aa67442bd170aa0b03f7320a7c", + "ASSEMBLY.json": "98d15f8a7cb5e45e13fd2ab4c20b19c7c18d55e5df2887c3f2f6cfe9eca770a8", + "global/audit/PREFIX-AND-INVOICE.json": "384e1f00761e07e3bb301f5579caa439e9db8798faa2571563e9153b55789d54" + } + }, + { + "name": "reverse-every-invoice-object-both-edges-rebound", + "raw_sha256": { + "ADMISSION-CONTROLS.json": "09af187591160e1141cd2c1be0f8f500b6c31c8a206ce333af7a5aef411dc006", + "ASSEMBLY.json": "965afa59dc2c55eacc5e4b4feb64e66cf841f985543ad4bcb595046461eb1bdf", + "global/audit/PREFIX-AND-INVOICE.json": "f4e65a1e865bb2a8f5d2994ca0d96037caa9f811d1874ad8b3eb80d2f28aa33a" + } + }, + { + "name": "equivalent-string-escape-both-edges-rebound", + "raw_sha256": { + "ADMISSION-CONTROLS.json": "d49d5d90fb37ed2c6e5f79017fca3c8922dc42819fb58e0fc7d89bf4d138e5e8", + "ASSEMBLY.json": "7412f7e6f547f068cc0bce42621d2e3e0f2b4ed701c20a5581f989d9de76a05c", + "global/audit/PREFIX-AND-INVOICE.json": "566931c4d676320225206d2e8c3277f2c0b3bfee1eef69b115840c9484f179c0" + } + }, + { + "name": "receipt-format-only:ADMISSION-CONTROLS.json", + "raw_sha256": { + "ADMISSION-CONTROLS.json": "701225794f9cf34f78016e1ec03cd9989873f1c1d432d35ef473dd8b82fb72c2", + "ASSEMBLY.json": "1122cb3a575f8c788345fc1bf4c108ac7c3250fb81a5988671f5eb04b3ab3045", + "global/audit/PREFIX-AND-INVOICE.json": "212cf4ee3b16081bf66f300fa18b4070d25c17210c21c78c2967892c91870d12" + } + }, + { + "name": "receipt-format-only:ASSEMBLY.json", + "raw_sha256": { + "ADMISSION-CONTROLS.json": "9d408a0c84fbca7e873b2411590c6c2b526951bc975a26430c9a4baf3fb0fb27", + "ASSEMBLY.json": "fa445403d6fdd3a162d5415c72a87450e730fb61ac09ea080a842d947e799f0f", + "global/audit/PREFIX-AND-INVOICE.json": "212cf4ee3b16081bf66f300fa18b4070d25c17210c21c78c2967892c91870d12" + } + }, + { + "name": "all-three-reformatted-with-authenticated-links", + "raw_sha256": { + "ADMISSION-CONTROLS.json": "a03c4e4de8d120651f35d8e4adbbb91cc818488227771cee75872614bef8159b", + "ASSEMBLY.json": "aa62c69307b2346ed2878c27e1f24afd6912acf2d44f302f344089e7e8fb44aa", + "global/audit/PREFIX-AND-INVOICE.json": "9d2c8d9e607d25c891297dd2c77e066c8f5079b640e1ac2a6f2d66ab3afa8f1b" + } + } + ], + "schema_version": 1, + "scope": "PR1094 three-node invoice subgraph only; not mathematical admission", + "source_census": { + "direct_references": [ + { + "file": "ADMISSION-CONTROLS.json", + "path": [ + "input_sha256", + "fresh_invoice" + ] + }, + { + "file": "ASSEMBLY.json", + "path": [ + "input_sha256", + "fresh_invoice" + ] + } + ], + "gzip_payloads": 22, + "json_payloads": 94, + "raw_digest_occurrences": [ + { + "count": 1, + "file": "ADMISSION-CONTROLS.json" + }, + { + "count": 1, + "file": "ASSEMBLY.json" + } + ], + "strict_files": 105 + }, + "status": "PASS_SELECTED_INVOICE_REFERENCE_REBINDING", + "synchronized_invoice_mutations": 5296 +} diff --git a/research/selected-invoice-reference-rebinding/SELECTION.json b/research/selected-invoice-reference-rebinding/SELECTION.json new file mode 100644 index 0000000000..0b87ea955c --- /dev/null +++ b/research/selected-invoice-reference-rebinding/SELECTION.json @@ -0,0 +1,60 @@ +{ + "seed": "a2e5a793b5e1a2555a2466367171c2ea", + "track": "verifier-engineering", + "suggestions": [ + { + "task_id": "portable-replay", + "scope_key": "91a9a2afec282c926282", + "question": "Can one reproducible environment or artifact-comparison failure be repaired?", + "method": "Audit one canonical-payload comparison for omitted proof-relevant fields.", + "starting_points": ["research/gzip-container-reproducibility/README.md", "docs/ci-verification.md"], + "acceptance_gate": "Preserve immutable source hashes and proof-relevant content; a different compressed byte stream alone is not a mathematical mismatch.", + "first_step": { + "command": ["python3", "-B", "scripts/research_baseline.py"], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Read the gzip-container reproducibility examples and distinguish frozen source bytes from regenerated payloads.", + "scope": "Positive control / source-bound orientation only; this is not a new construction or full cold replay." + }, + "first_experiment": "Reproduce one specific mismatch or audit one canonical comparison for omitted proof-relevant fields.", + "bottleneck_link": "Portable exact checks prevent environment failures from blocking valid contributions.", + "allowed_variations": ["One interpreter/version mismatch or one payload field comparison."], + "scope_change_triggers": ["Removing immutable-source pins because generated compressed bytes differ."], + "overlap_terms": ["gzip container", "reproducibility", "canonical payload"], + "scope_rule": "If you change the card's premise, record scope_status=changed and explain why. A package metadata check cannot establish mathematical relevance." + }, + { + "task_id": "replay-runtime", + "scope_key": "a76657a85478d269d19f", + "question": "Can one measured replay bottleneck be sped up without dropping coverage?", + "method": "Design source-bound reuse with explicit dependency invalidation and negative controls.", + "starting_points": ["scripts/run_isolated_tests.py", "scripts/verify_replay_coverage.py", "certificates/selected-result.json"], + "acceptance_gate": "Report before/after wall time on the same fixture, retained checks and invalidation behavior.", + "first_step": { + "command": ["python3", "-B", "scripts/research_baseline.py"], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Read the selected reproduction command and choose a single replay stage for profiling.", + "scope": "Positive control / source-bound orientation only; this is not a new construction or full cold replay." + }, + "first_experiment": "Measure one unchanged fixture, preserve check coverage, and test one optimization with invalidation controls.", + "bottleneck_link": "Faster trustworthy replays increase review throughput and let mechanism candidates be checked sooner.", + "allowed_variations": ["Profile one stage or design one source-bound cache boundary."], + "scope_change_triggers": ["Skipping coverage or comparing different fixtures to claim speedup."], + "overlap_terms": ["replay runtime", "cache invalidation", "isolated tests"], + "scope_rule": "If you change the card's premise, record scope_status=changed and explain why. A package metadata check cannot establish mathematical relevance." + } + ], + "base_commit": "e112d71c8d7bb32435debcc54df932593dd8223a", + "catalog_assessed_on": "2026-10-13", + "priority_revision": 3, + "priority_log": "docs/research/research-priority-log.md", + "catalog_sha256": "6686ad58f1fbdbc87134a78901b60fd53a20d3984355e91defbbebc9e9fa8075", + "selected_record_sha256": "10b9e340fd8e354a37a0c4813c90e5de1dd42044b5f6aca4a3fc5a42b685fa32", + "selected": { + "kappa": "836330098538459/500000000000000000", + "review": "docs/research/community-batch1099-review.md", + "source_manifest": "research/community-frontier1094-audit/SELECTED-SOURCE.json", + "reproduce": "make frontier1094-verify" + }, + "status": "SUGGESTIONS_ONLY_NOT_RESERVED", + "next_step": "Check live overlap, refine one question's object and domain, and record a bounded task card. A different seed or scope key is not evidence of novelty." +} diff --git a/research/selected-invoice-reference-rebinding/SOURCES.json b/research/selected-invoice-reference-rebinding/SOURCES.json new file mode 100644 index 0000000000..48eea32a3b --- /dev/null +++ b/research/selected-invoice-reference-rebinding/SOURCES.json @@ -0,0 +1,48 @@ +{ + "schema_version": 1, + "base_commit": "e112d71c8d7bb32435debcc54df932593dd8223a", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "ae6a99f28aa468649eb66a361e764d769363bf11", + "sha256": "10b9e340fd8e354a37a0c4813c90e5de1dd42044b5f6aca4a3fc5a42b685fa32" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "06c96f5579bb67ed1b86d334e78fbed7da6945f1", + "sha256": "6686ad58f1fbdbc87134a78901b60fd53a20d3984355e91defbbebc9e9fa8075" + }, + { + "path": "research/community-frontier1094-audit/ASSEMBLY.json", + "usage": "input", + "git_blob": "5fd676df060f3b450782fdf5ff5f6beb63a5eeb0", + "sha256": "1122cb3a575f8c788345fc1bf4c108ac7c3250fb81a5988671f5eb04b3ab3045" + }, + { + "path": "research/community-frontier1094-audit/RESULT.json", + "usage": "input", + "git_blob": "131d9c96a54632ae385ced4138fd7f30ad448a3e", + "sha256": "1e3e47e9ec24bcb6fb5f703b7fce0aab658d84ff72bfae5da3ae429d17b6e752" + }, + { + "path": "research/community-frontier1094-audit/selected-replay.tar.gz", + "usage": "input", + "git_blob": "c24daf067f9c543421d89ca2eeaa4eb78a57fb6f", + "sha256": "f1da80610bf33c58527f18ad63b4350d0b864e1d4486141ee17ac9bed4d529d6" + }, + { + "path": "research/gauge44-slots-t16/code/generated_identity.py", + "usage": "input", + "git_blob": "74a9b604793f21a9f064c78874341e287ded7a68", + "sha256": "c8af22719c0f3097a991a3f6ccac8f090afd2faba554745733d9ea88f2c25708" + }, + { + "path": "research/selected-final-stage-portability/compare_payloads.py", + "usage": "input", + "git_blob": "a2a2aea73bda06c2358065388a30fd4cbc7d423f", + "sha256": "3aa3459404265188e51a4a74a57f6c01d9ea7cad205edb962e5d51c5a45a50cb" + } + ] +} diff --git a/research/selected-invoice-reference-rebinding/TASK.json b/research/selected-invoice-reference-rebinding/TASK.json new file mode 100644 index 0000000000..e832206817 --- /dev/null +++ b/research/selected-invoice-reference-rebinding/TASK.json @@ -0,0 +1,86 @@ +{ + "schema_version": 1, + "task_id": "portable-replay", + "priority_revision": 3, + "base_commit": "e112d71c8d7bb32435debcc54df932593dd8223a", + "original_card": { + "id": "portable-replay", + "question": "Can one reproducible environment or artifact-comparison failure be repaired?", + "starting_points": [ + "research/gzip-container-reproducibility/README.md", + "docs/ci-verification.md" + ], + "methods": [ + "Reproduce one portability failure and add a minimal cross-environment fix.", + "Audit one canonical-payload comparison for omitted proof-relevant fields." + ], + "acceptance_gate": "Preserve immutable source hashes and proof-relevant content; a different compressed byte stream alone is not a mathematical mismatch.", + "first_step": { + "command": [ + "python3", + "-B", + "scripts/research_baseline.py" + ], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Read the gzip-container reproducibility examples and distinguish frozen source bytes from regenerated payloads.", + "scope": "Positive control / source-bound orientation only; this is not a new construction or full cold replay." + }, + "first_experiment": "Reproduce one specific mismatch or audit one canonical comparison for omitted proof-relevant fields.", + "bottleneck_link": "Portable exact checks prevent environment failures from blocking valid contributions.", + "allowed_variations": [ + "One interpreter/version mismatch or one payload field comparison." + ], + "scope_change_triggers": [ + "Removing immutable-source pins because generated compressed bytes differ." + ], + "overlap_terms": [ + "gzip container", + "reproducibility", + "canonical payload" + ] + }, + "scope_status": "refined", + "actual_scope": "Source-bound portability of the selected PR1094 invoice subgraph: global/audit/PREFIX-AND-INVOICE.json and its two input_sha256/fresh_invoice consumers ADMISSION-CONTROLS.json and ASSEMBLY.json. Authenticate both literal edges before replacing them with the complete typed invoice identity; compare every other field without exemptions.", + "scope_change_reason": "PR2040 explicitly leaves the observed Linux invoice-key-order/raw-reference mismatch unresolved. This changes neither its typed/path audit nor the prior seven-local-artifact identity audit; it supplies the missing reference-binding comparison for this three-node generated subgraph.", + "bottleneck_link": "Portable replay must accept a generated JSON reformat only with freshly valid raw receipt references, without mistaking synchronized semantic tampering for an environment difference. No supplier, paid profile or kappa change.", + "budget_minutes": 120, + "stop_rule": "One three-node selected1094 subgraph only. Stop after a complete field-preservation argument, source-bound transformation experiment, semantic rejection census and focused replay. Do not rebuild the cold supplier or investigate CI.", + "outcome": "completed", + "evidence": "RESULT.json:105strictfiles,3041tree nodes,two direct raw references; seven formatting positives;6076field mutations including5296synchronized invoice mutations;57edge/parser/type negatives;6133total rejections. README proves the exact authenticate-before-rebind boundary. Verification engineering only, not mathematical admission.", + "author": "Adam Gall (@adamgall), with OpenAI Codex assistance", + "ai_assistance": "Substantial OpenAI Codex (GPT-6 Astra) assistance in audit design, implementation, experiments, tests and writing. No independent human review claimed.", + "selection_seed": "a2e5a793b5e1a2555a2466367171c2ea", + "selection_file": "SELECTION.json", + "scope_key": "selected1094/invoice-two-consumer/raw-authentication-before-typed-rebinding", + "method": "Exact standard-library typed JSON comparison, independent full-tree oracle, complete direct-consumer census over all 105 reviewed strict output files, formatting permutations and synchronized semantic mutations.", + "claim_url": "https://github.com/CrocSwap/integer-mult-bounds/discussions/2049#discussioncomment-18931179", + "domain": { + "invoice": "global/audit/PREFIX-AND-INVOICE.json", + "consumers": ["ADMISSION-CONTROLS.json", "ASSEMBLY.json"], + "allowed_variation": "Object order, insignificant JSON whitespace and equivalent JSON string escapes only. No excluded timing, path, digest, list order, numerical or proof field.", + "negative_controls": "Stale and cross-wired edges; one edge repaired but the other stale; both sides malformed; receipt semantic fields; synchronized invoice mutations with both edges updated; duplicate keys and nonfinite or unexpected decimal numbers." + }, + "optimistic_full_budget": "Verification engineering, not a construction proposal: recursive word, all physical/interface costs and selected kappa unchanged. Acceptance requires every field retained, both raw links authenticated on each side, a legitimate portable formatting variant accepted, and every declared semantic fault rejected. No speedup claim.", + "success_evidence": "A complete source-bound graph equivalence checker and portable positive witness with exhaustive declared mutation coverage, not whole-file hash substitution alone.", + "falsification_test": "Any semantic edit accepted after consistently rebinding both raw invoice references falsifies the required comparator property.", + "predecessors": [ + {"pr": 2040, "head": "d31c1418c0c23994d1444dbd9d356b9a8238fd5e", "credit": "commdata2338, with OpenAI Codex assistance", "scope": "Typed/path false equivalences in PR1824; invoice raw-reference handoff explicitly remains open. No code dependency."}, + {"pr": 1824, "head": "ad5b1248f25a71983b20617e2f3a80be22f03990", "credit": "Josie Elliston", "scope": "Selected final-stage interpreter comparison; retained comparator is the before-control."}, + {"pr": 1094, "head": "0fc329d0bec93ca7cd288eaea1295172e8789810", "credit": "Rohan Arun, Jeremy Kothe and inherited selected compiler/supplier lineage", "scope": "Actual reviewed strict output source."} + ], + "overlap": { + "snapshot_open_prs": {"count": 329, "fetched_at": "2026-10-14T18:11:09.770757+00:00", "complete_pagination": true}, + "snapshot_discussions": {"count": 692, "fetched_at": "2026-10-14T18:12:32.610168+00:00", "complete_pagination": true}, + "targeted_live": "PR2040 full body/head and discussions1163/1166 read; exact rebinding offline query has10matches.", + "local_predecessors": ["selected-generated-identity-audit", "selected-final-stage-portability", "pr695-digest-audit", "gzip-container-reproducibility"], + "limitations": "Cached snapshot may miss later changes; local/merged notes and exact premises checked. No-match is not novelty." + }, + "open_questions": [ + { + "question": "Should the reviewed subgraph comparison be adopted by a future selected-final-stage replay wrapper?", + "why_it_matters": "It resolves the demonstrated invoice formatting/reference obstruction without blanket digest exclusions.", + "first_step": "Compose this exact three-node predicate with a separately reviewed full-output comparator and its explicit timing/path policy.", + "blocked_by": "Maintainer adoption and caller/source-pin review; this opt-in package changes no frozen caller and does not certify the remaining graph." + } + ] +} diff --git a/research/selected-invoice-reference-rebinding/VERIFY.json b/research/selected-invoice-reference-rebinding/VERIFY.json new file mode 100644 index 0000000000..5c35d37f91 --- /dev/null +++ b/research/selected-invoice-reference-rebinding/VERIFY.json @@ -0,0 +1,30 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [ + "research/community-frontier1094-audit/ASSEMBLY.json", + "research/community-frontier1094-audit/RESULT.json", + "research/community-frontier1094-audit/selected-replay.tar.gz", + "research/gauge44-slots-t16/code/generated_identity.py", + "research/selected-final-stage-portability/compare_payloads.py" + ], + "commands": [ + { + "argv": [ + "{python}", + "-I", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 180, + "checks": "Authenticate frozen corpus, census105outputs and both raw edges, preserve3041nodes, accept7portable variants, reject6076field mutations plus57edge/parser/type faults, compare complete deterministic RESULT." + }, + { + "argv": ["{python}", "-I", "-O", "-B", "{package}/test_compare.py"], + "timeout_seconds": 60, + "checks": "Eight focused tests: both-side edge integrity, synchronized tampering, strict number/types, complete shape/list order, independent oracle, CLI exit codes, immutable archive-header rejection and missing files." + } + ] +} diff --git a/research/selected-invoice-reference-rebinding/compare_invoice.py b/research/selected-invoice-reference-rebinding/compare_invoice.py new file mode 100755 index 0000000000..2b2460f5ca --- /dev/null +++ b/research/selected-invoice-reference-rebinding/compare_invoice.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 +"""Compare only PR1094's three-node invoice subgraph, never admit a supplier. + +Authenticate each side's two literal raw invoice references before replacing +those two fields by a complete canonical invoice digest. Every other field is +retained. The accepted JSON domain is the reviewed integer/string/Boolean/null +schema: decimal/exponent numbers, duplicate keys and nonfinite values fail. + +Adam Gall, with substantial OpenAI Codex assistance. Apache-2.0. +""" +import argparse +import hashlib +import json +from pathlib import Path + +INVOICE = "global/audit/PREFIX-AND-INVOICE.json" +CONSUMERS = ("ADMISSION-CONTROLS.json", "ASSEMBLY.json") +FILES = (INVOICE, *CONSUMERS) +REFERENCE_PATH = ("input_sha256", "fresh_invoice") +SCOPE = "PR1094 three-node invoice subgraph only; not mathematical admission" + + +class InvalidGraph(ValueError): + """Malformed JSON, incomplete subgraph, or an unauthenticated raw edge.""" + + +def sha256(raw): + return hashlib.sha256(raw).hexdigest() + + +def _unique_object(pairs): + result = {} + for key, value in pairs: + if key in result: + raise InvalidGraph("duplicate JSON key: " + repr(key)) + result[key] = value + return result + + +def _unsupported_number(value): + raise InvalidGraph("outside reviewed integer JSON domain: " + value) + + +def parse(raw): + """Parse without binary64 rounding or Python Boolean/integer conflation.""" + try: + return json.loads(raw, object_pairs_hook=_unique_object, + parse_float=_unsupported_number, + parse_constant=_unsupported_number) + except (ValueError, UnicodeError) as exc: + raise InvalidGraph(str(exc)) from exc + + +def canonical(value): + """An injective encoding of parsed trees up to object order/string escapes.""" + return json.dumps(value, sort_keys=True, ensure_ascii=True, + separators=(",", ":"), allow_nan=False).encode("ascii") + + +def normalized(files): + """Return complete canonical bytes, after authenticating BOTH raw edges. + + Callers must establish trust in their reference separately. Byte-identical + inputs do not bypass parsing or edge checks. No path, time, generic digest, + or unknown field is masked. Only the named three files are in this API. + """ + if set(files) != set(FILES): + raise InvalidGraph("expected exactly the three declared subgraph files") + values = {name: parse(files[name]) for name in FILES} + if any(type(value) is not dict for value in values.values()): + raise InvalidGraph("each subgraph artifact must be a JSON object") + raw_digest = sha256(files[INVOICE]) + for name in CONSUMERS: + inputs = values[name].get("input_sha256") + if type(inputs) is not dict: + raise InvalidGraph(name + ": missing input_sha256 object") + digest = inputs.get("fresh_invoice") + if type(digest) is not str or digest != raw_digest: + raise InvalidGraph(name + ": stale or misbound fresh_invoice") + invoice = canonical(values[INVOICE]) + content_digest = sha256(invoice) + result = {INVOICE: invoice} + for name in CONSUMERS: + values[name]["input_sha256"]["fresh_invoice"] = content_digest + result[name] = canonical(values[name]) + return result + + +def compare(reference, candidate): + """A fresh parse and edge check on each side, then complete byte equality.""" + left, right = normalized(reference), normalized(candidate) + different = [name for name in FILES if left[name] != right[name]] + return { + "scope": SCOPE, + "equivalent": not different, + "different_files": different, + "authenticated_edges_per_side": len(CONSUMERS), + "reference_invoice_raw_sha256": sha256(reference[INVOICE]), + "candidate_invoice_raw_sha256": sha256(candidate[INVOICE]), + "reference_canonical_sha256": {name: sha256(left[name]) for name in FILES}, + "candidate_canonical_sha256": {name: sha256(right[name]) for name in FILES}, + } + + +def read_graph(directory): + """Read the three documented paths; other directory files are OUT OF SCOPE.""" + return {name: (directory / name).read_bytes() for name in FILES} + + +def main(argv=None): + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("reference", type=Path, help="trusted strict-output directory") + parser.add_argument("candidate", type=Path, help="candidate strict-output directory") + args = parser.parse_args(argv) + try: + report = compare(read_graph(args.reference), read_graph(args.candidate)) + except (OSError, InvalidGraph) as exc: + print(json.dumps({"scope": SCOPE, "valid_graph": False, "error": str(exc)})) + return 2 + print(json.dumps(report, sort_keys=True, indent=2)) + return 0 if report["equivalent"] else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/research/selected-invoice-reference-rebinding/test_compare.py b/research/selected-invoice-reference-rebinding/test_compare.py new file mode 100755 index 0000000000..89561e9949 --- /dev/null +++ b/research/selected-invoice-reference-rebinding/test_compare.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +"""Focused semantic controls; normal and optimized execution must agree. + +Adam Gall, with substantial OpenAI Codex assistance. Apache-2.0. +""" +import contextlib +import gzip +import io +import json +from pathlib import Path +import subprocess +import sys +import tempfile +import unittest + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +import compare_invoice as engine +import verify + + +class InvoiceComparisonTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + corpus = verify.load_corpus() + cls.source = {name: corpus[name] for name in engine.FILES} + cls.portable = verify.rebound(cls.source, verify.dump( + json.loads(cls.source[engine.INVOICE]), sort_keys=True)) + + def test_valid_portability_and_stale_edges(self): + self.assertTrue(engine.compare(self.source, self.portable)["equivalent"]) + for name in engine.CONSUMERS: + stale = dict(self.portable) + stale[name] = self.source[name] + with self.assertRaisesRegex(engine.InvalidGraph, "fresh_invoice"): + engine.compare(self.source, stale) + # The reference is validated too; equal bad inputs never shortcut. + with self.assertRaisesRegex(engine.InvalidGraph, "fresh_invoice"): + engine.compare(stale, stale) + + def test_synchronized_semantic_change_and_unknown_digest(self): + invoice = json.loads(self.source[engine.INVOICE]) + invoice["providers"]["gauge44"]["local"]["forward"]["all_dirty_helper_columns_restored"] = False + changed = verify.rebound(self.source, verify.dump(invoice)) + report = engine.compare(self.source, changed) + self.assertFalse(report["equivalent"]) + self.assertEqual(set(report["different_files"]), set(engine.FILES)) + # No blanket treatment of other digest-looking fields. + value = json.loads(self.source["ASSEMBLY.json"]) + value["input_sha256"]["owner_audit"] = "0" * 64 + changed = dict(self.source) + changed["ASSEMBLY.json"] = verify.dump(value) + self.assertFalse(engine.compare(self.source, changed)["equivalent"]) + + def test_typed_json_duplicate_and_number_domain(self): + self.assertNotEqual(engine.canonical(engine.parse(b'{"x":true}')), + engine.canonical(engine.parse(b'{"x":1}'))) + self.assertEqual(engine.canonical(engine.parse(b'{"x":"P"}')), + engine.canonical(engine.parse(b'{"x":"\\u0050"}'))) + for raw in (b'{"x":1,"x":1}', b'{"x":NaN}', b'{"x":Infinity}', + b'{"x":-Infinity}', b'{"x":1.0}', b'{"x":1e0}', + b'{"x":0.10000000000000000000000000001}', b'\xff'): + with self.subTest(raw=raw): + with self.assertRaises(engine.InvalidGraph): + engine.parse(raw) + + def test_complete_shape_and_list_order(self): + for extra in (False, True): + malformed = dict(self.source) + if extra: + malformed["unexpected.json"] = b'{}' + else: + del malformed[engine.INVOICE] + with self.assertRaises(engine.InvalidGraph): + engine.normalized(malformed) + changed = dict(self.source) + changed["ADMISSION-CONTROLS.json"] = b'[]' + with self.assertRaisesRegex(engine.InvalidGraph, "JSON object"): + engine.normalized(changed) + value = json.loads(self.source["ADMISSION-CONTROLS.json"]) + value["rejected_controls"].reverse() + changed["ADMISSION-CONTROLS.json"] = verify.dump(value) + self.assertFalse(engine.compare(self.source, changed)["equivalent"]) + + def test_independent_oracle_retains_types_and_empty_containers(self): + for a, b in ((True, 1), ({"empty": []}, {}), ({"empty": {}}, {}), + ([1, 2], [2, 1]), ("1", 1)): + self.assertNotEqual(verify.typed(a), verify.typed(b)) + self.assertEqual(verify.oracle(self.source), verify.oracle(self.portable)) + faulty = dict(engine.normalized(self.source)) + value = json.loads(faulty[engine.INVOICE]) + del value["provider_phase_semantic_sha256"] + faulty[engine.INVOICE] = engine.canonical(value) + self.assertNotEqual(verify.typed(json.loads(faulty[engine.INVOICE])), + verify.typed(json.loads(self.source[engine.INVOICE]))) + + def test_cli_equivalent_different_and_invalid(self): + with tempfile.TemporaryDirectory(prefix="invoice-cli-") as tmp: + base = Path(tmp) + reference, candidate = base / "reference", base / "candidate" + for directory, files in ((reference, self.source), (candidate, self.portable)): + for name, raw in files.items(): + target = directory / name + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(raw) + argv = [sys.executable, "-I", "-O", "-B", str(HERE / "compare_invoice.py"), + str(reference), str(candidate)] + good = subprocess.run(argv, capture_output=True, text=True, check=False, timeout=10) + self.assertEqual(good.returncode, 0, good.stderr + good.stdout) + self.assertTrue(json.loads(good.stdout)["equivalent"]) + value = json.loads((candidate / "ASSEMBLY.json").read_bytes()) + value["kappa"] = "0" + (candidate / "ASSEMBLY.json").write_bytes(verify.dump(value)) + changed = subprocess.run(argv, capture_output=True, text=True, check=False, timeout=10) + self.assertEqual(changed.returncode, 1, changed.stderr + changed.stdout) + self.assertFalse(json.loads(changed.stdout)["equivalent"]) + (candidate / "ASSEMBLY.json").write_bytes(self.source["ASSEMBLY.json"]) + invalid = subprocess.run(argv, capture_output=True, text=True, check=False, timeout=10) + self.assertEqual(invalid.returncode, 2, invalid.stderr + invalid.stdout) + self.assertFalse(json.loads(invalid.stdout)["valid_graph"]) + + def test_immutable_archive_header_drift_rejected(self): + manifest = json.loads((HERE / "SOURCES.json").read_bytes()) + with tempfile.TemporaryDirectory(prefix="invoice-pin-") as tmp: + exported = Path(tmp) + for row in manifest["files"]: + if row["usage"] != "input": + continue + target = exported / row["path"] + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes((verify.ROOT / row["path"]).read_bytes()) + archive = exported / verify.ARCHIVE + original = archive.read_bytes() + modified = bytearray(original) + modified[4] ^= 1 # MTIME only: does not change the decompressed tar. + self.assertEqual(gzip.decompress(original), gzip.decompress(modified)) + archive.write_bytes(modified) + with self.assertRaisesRegex(RuntimeError, "immutable source hash mismatch"): + verify.check_sources(exported) + + def test_missing_cli_file_is_not_equivalent(self): + with tempfile.TemporaryDirectory(prefix="invoice-missing-") as tmp: + with contextlib.redirect_stdout(io.StringIO()) as output: + code = engine.main([tmp, tmp]) + self.assertEqual(code, 2) + self.assertFalse(json.loads(output.getvalue())["valid_graph"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/research/selected-invoice-reference-rebinding/verify.py b/research/selected-invoice-reference-rebinding/verify.py new file mode 100755 index 0000000000..b4dba73211 --- /dev/null +++ b/research/selected-invoice-reference-rebinding/verify.py @@ -0,0 +1,356 @@ +#!/usr/bin/env python3 +"""Source-bound experiment and replay for the PR1094 invoice subgraph. + +No supplier execution, network, generated-source edits, or third-party modules. +Adam Gall, with substantial OpenAI Codex assistance. Apache-2.0. +""" +import argparse +from collections import Counter +import gzip +import hashlib +import importlib.util +import json +from pathlib import Path +import sys +import tarfile +import tempfile + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[1] +sys.path.insert(0, str(HERE)) +import compare_invoice as engine + +SOURCE = "research/community-frontier1094-audit/" +ARCHIVE = SOURCE + "selected-replay.tar.gz" +BEFORE = "research/selected-final-stage-portability/compare_payloads.py" +CLAIM = "https://github.com/CrocSwap/integer-mult-bounds/discussions/2049#discussioncomment-18931179" + + +def require(condition, message): + if not condition: + raise RuntimeError(message) + + +def dump(value, **kwargs): + return (json.dumps(value, ensure_ascii=True, allow_nan=False, **kwargs) + "\n").encode("ascii") + + +def check_sources(root=ROOT): + manifest = json.loads((HERE / "SOURCES.json").read_bytes()) + for row in manifest["files"]: + if row["usage"] == "input": + require(engine.sha256((root / row["path"]).read_bytes()) == row["sha256"], + "immutable source hash mismatch: " + row["path"]) + + +def load_corpus(root=ROOT): + check_sources(root) + prefix = "candidate/strict/" + with tarfile.open(root / ARCHIVE) as archive: + corpus = {} + for member in archive.getmembers(): + if not member.isfile() or not member.name.startswith(prefix): + continue + name = member.name[len(prefix):] + require(name not in corpus, "duplicate archive member: " + name) + corpus[name] = archive.extractfile(member).read() + receipt = archive.extractfile("RESULT.json").read() + require(receipt == (root / SOURCE / "RESULT.json").read_bytes(), "archive receipt differs") + require(corpus["ASSEMBLY.json"] == (root / SOURCE / "ASSEMBLY.json").read_bytes(), + "archive assembly differs from committed selected certificate") + require(engine.sha256(corpus["ASSEMBLY.json"]) == json.loads(receipt)["assembly_sha256"], + "receipt assembly binding differs") + require(len(corpus) == 105, "reviewed strict-output inventory differs") + return corpus + + +def walk(value, path=()): + yield path, value + if type(value) is dict: + for key in sorted(value): + yield from walk(value[key], path + (key,)) + elif type(value) is list: + for index, item in enumerate(value): + yield from walk(item, path + (index,)) + + +def typed(value): + """Independent structural oracle: no serializer and no digest projection.""" + if type(value) is dict: + return ("object", tuple((key, typed(value[key])) for key in sorted(value))) + if type(value) is list: + return ("array", tuple(typed(item) for item in value)) + return (type(value).__name__, value) + + +def oracle(files): + """Preserve the two edge ROLES as tuples, independently of content hashes.""" + values = {name: json.loads(files[name]) for name in engine.FILES} + digest = hashlib.sha256(files[engine.INVOICE]).hexdigest() + for name in engine.CONSUMERS: + require(values[name]["input_sha256"]["fresh_invoice"] == digest, + "oracle raw edge mismatch") + values[name]["input_sha256"]["fresh_invoice"] = ("edge", engine.INVOICE) + return tuple((name, typed(values[name])) for name in engine.FILES) + + +def alter(value, path, replacement=None, omit=False): + """Copy only containers on the edited path; never change the reference tree.""" + if not path: + require(not omit, "cannot omit root") + return replacement + key, *rest = path + changed = value.copy() + if rest: + changed[key] = alter(value[key], rest, replacement, omit) + elif omit: + del changed[key] + else: + changed[key] = replacement + return changed + + +def replacement(value): + if type(value) is bool: + return not value + if type(value) is int: + return value + 1 + if type(value) is str: + return value + "#semantic-change" + if type(value) is dict: + return {"semantic-change": None} + if type(value) is list: + return ["semantic-change"] + if value is None: + return "semantic-change" + raise RuntimeError("unexpected fixture value type") + + +def rebound(files, invoice_bytes): + candidate = dict(files) + candidate[engine.INVOICE] = invoice_bytes + digest = engine.sha256(invoice_bytes) + for name in engine.CONSUMERS: + value = json.loads(candidate[name]) + value["input_sha256"]["fresh_invoice"] = digest + candidate[name] = dump(value, indent=2) + return candidate + + +def reverse_objects(value): + if type(value) is dict: + return {key: reverse_objects(item) for key, item in reversed(tuple(value.items()))} + if type(value) is list: + return [reverse_objects(item) for item in value] + return value + + +def source_census(corpus): + invoice_digest = engine.sha256(corpus[engine.INVOICE]) + occurrences, byte_occurrences = [], [] + json_files = gzip_files = 0 + for name, raw in sorted(corpus.items()): + if name.endswith(".gz"): + raw = gzip.decompress(raw) + gzip_files += 1 + count = raw.count(invoice_digest.encode("ascii")) + if count: + byte_occurrences.append({"file": name, "count": count}) + if name.removesuffix(".gz").endswith(".json"): + json_files += 1 + for path, value in walk(json.loads(raw)): + if value == invoice_digest: + occurrences.append({"file": name, "path": list(path)}) + expected = [{"file": name, "path": list(engine.REFERENCE_PATH)} for name in engine.CONSUMERS] + require(occurrences == expected, "invoice has an unaccounted direct JSON consumer") + require(byte_occurrences == [{"file": name, "count": 1} for name in engine.CONSUMERS], + "invoice digest occurs outside the two declared references") + return {"strict_files": len(corpus), "json_payloads": json_files, + "gzip_payloads": gzip_files, "direct_references": occurrences, + "raw_digest_occurrences": byte_occurrences} + + +def before_classification(reference, candidate): + spec = importlib.util.spec_from_file_location("pinned_before_comparator", ROOT / BEFORE) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + with tempfile.TemporaryDirectory(prefix="invoice-before-") as tmp: + directory = Path(tmp) + result = {} + for name in engine.FILES: + a, b = directory / "ref" / name, directory / "run" / name + a.parent.mkdir(parents=True, exist_ok=True) + b.parent.mkdir(parents=True, exist_ok=True) + a.write_bytes(reference[name]) + b.write_bytes(candidate[name]) + result[name] = module.classify(a, b, (), ()) + require(result[engine.INVOICE]["cls"] == "json-format", "before invoice fixture differs") + for name in engine.CONSUMERS: + require(result[name]["verdict"] == "proof-relevant-candidate", "before did not flag reference") + require(result[name]["differing"] == 1, "before differs beyond the single fresh_invoice edge") + return result + + +def audit(): + corpus = load_corpus() + source = {name: corpus[name] for name in engine.FILES} + trees = {name: json.loads(source[name]) for name in engine.FILES} + reference = engine.normalized(source) + reference_oracle = oracle(source) + summary = {"schema_version": 1, "status": "PASS_SELECTED_INVOICE_REFERENCE_REBINDING", + "scope": engine.SCOPE, "source_census": source_census(corpus), + "artifacts": {}, "positive_controls": [], "field_mutations": {}, + "edge_and_parser_controls": []} + for name in engine.FILES: + counts = Counter(type(value).__name__ for _, value in walk(trees[name])) + # Oracle comparison retains full trees; only the authenticated edge values + # use a content hash in the primary representation, versus a role token here. + projected = json.loads(reference[name]) + original = json.loads(source[name]) + if name in engine.CONSUMERS: + projected["input_sha256"]["fresh_invoice"] = ("edge", engine.INVOICE) + original["input_sha256"]["fresh_invoice"] = ("edge", engine.INVOICE) + require(typed(projected) == typed(original), "normalization dropped or changed a field") + summary["artifacts"][name] = { + "raw_sha256": engine.sha256(source[name]), + "canonical_sha256": engine.sha256(reference[name]), + "bytes": len(source[name]), "nodes": sum(counts.values()), + "types": dict(sorted(counts.items())), + } + + def accepted(label, candidate): + require(engine.normalized(candidate) == reference, "positive rejected: " + label) + require(oracle(candidate) == reference_oracle, "positive oracle differs: " + label) + summary["positive_controls"].append({"name": label, + "raw_sha256": {name: engine.sha256(candidate[name]) for name in engine.FILES}}) + + accepted("identical-valid-subgraph", source) + portable = rebound(source, dump(trees[engine.INVOICE], sort_keys=True, separators=(",", ":"))) + require(portable[engine.INVOICE] != source[engine.INVOICE], "positive must change invoice bytes") + accepted("sorted-compact-invoice-both-edges-rebound", portable) + accepted("reverse-every-invoice-object-both-edges-rebound", + rebound(source, dump(reverse_objects(trees[engine.INVOICE]), indent=1))) + # Replace a JSON string escape, not a value. The invoice has many letter P's. + escaped = source[engine.INVOICE].replace(b"PASS_", b"\\u0050ASS_", 1) + require(escaped != source[engine.INVOICE], "escape positive did not change source") + accepted("equivalent-string-escape-both-edges-rebound", rebound(source, escaped)) + for name in engine.CONSUMERS: + candidate = dict(source) + candidate[name] = dump(reverse_objects(trees[name]), separators=(",", ":")) + accepted("receipt-format-only:" + name, candidate) + candidate = rebound(source, dump(reverse_objects(trees[engine.INVOICE]), separators=(",", ":"))) + for name in engine.CONSUMERS: + candidate[name] = dump(reverse_objects(json.loads(candidate[name])), sort_keys=True) + accepted("all-three-reformatted-with-authenticated-links", candidate) + summary["before_comparison"] = before_classification(source, portable) + + transcript = hashlib.sha256() + total = 0 + for name in engine.FILES: + counts = Counter() + for path, value in walk(trees[name]): + if not path: + continue + for operation in ("omit", "replace"): + mutated = alter(trees[name], path, replacement(value), omit=operation == "omit") + candidate = dict(source) + candidate[name] = dump(mutated) + if name == engine.INVOICE: + candidate = rebound(candidate, candidate[name]) + try: + normalized = engine.normalized(candidate) + except engine.InvalidGraph: + verdict = "invalid-raw-edge" + else: + require(normalized != reference, f"semantic mutation accepted: {name} {path} {operation}") + require(oracle(candidate) != reference_oracle, "independent oracle missed mutation") + verdict = "different-complete-payload" + transcript.update(dump([name, list(path), operation, verdict, + engine.sha256(candidate[name])], separators=(",", ":"))) + counts[verdict] += 1 + total += 1 + summary["field_mutations"][name] = dict(sorted(counts.items())) + summary["field_mutation_total"] = total + summary["field_mutation_transcript_sha256"] = transcript.hexdigest() + summary["synchronized_invoice_mutations"] = 2 * (summary["artifacts"][engine.INVOICE]["nodes"] - 1) + + def rejected(label, candidate, left=source): + try: + report = engine.compare(left, candidate) + except engine.InvalidGraph: + verdict = "invalid-graph" + else: + require(not report["equivalent"], "control accepted: " + label) + verdict = "different-complete-payload" + summary["edge_and_parser_controls"].append({"name": label, "verdict": verdict}) + + stale = dict(source) + stale[engine.INVOICE] = portable[engine.INVOICE] + rejected("reformatted-invoice-both-edges-stale", stale) + rejected("identical-stale-graphs-no-byte-shortcut", stale, stale) + for name in engine.CONSUMERS: + partial = dict(portable) + partial[name] = source[name] + rejected("only-other-edge-rebound:" + name, partial) + wrong = dict(source) + value = json.loads(wrong[name]) + value["input_sha256"]["fresh_invoice"] = value["input_sha256"]["owner_audit"] + wrong[name] = dump(value) + rejected("misbound-to-owner-audit:" + name, wrong) + for name in engine.FILES: + duplicate = dict(source) + duplicate[name] = b'{"status":"forged",' + duplicate[name].lstrip()[1:] + if name == engine.INVOICE: + duplicate = rebound(duplicate, duplicate[name]) + rejected("duplicate-key:" + name, duplicate) + for token in (b"NaN", b"Infinity", b"-Infinity", b"1.0", b"1e0"): + malformed = dict(source) + malformed[name] = b'{"unexpected-number":' + token + b',' + source[name].lstrip()[1:] + if name == engine.INVOICE: + malformed = rebound(malformed, malformed[name]) + rejected("unsupported-number:" + name + ":" + token.decode(), malformed) + missing = dict(source) + del missing[name] + rejected("missing-file:" + name, missing) + unexpected = dict(source) + value = json.loads(source[name]) + value["unexpected-proof-field"] = True + unexpected[name] = dump(value) + if name == engine.INVOICE: + unexpected = rebound(unexpected, unexpected[name]) + rejected("unfamiliar-field-retained:" + name, unexpected) + # Type-distinct equal Python values are especially plausible canonicalization bugs. + for name in engine.FILES: + for path, value in walk(trees[name]): + if type(value) is bool: + candidate = dict(source) + candidate[name] = dump(alter(trees[name], path, int(value))) + if name == engine.INVOICE: + candidate = rebound(candidate, candidate[name]) + rejected("boolean-to-integer:" + name + ":" + repr(path), candidate) + summary["negative_controls"] = total + len(summary["edge_and_parser_controls"]) + return summary + + +def main(): + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("--write-result", action="store_true", + help="initial experiment only: exclusively create RESULT.json") + args = parser.parse_args() + result = audit() + path = HERE / "RESULT.json" + if args.write_result: + with path.open("xb") as stream: + stream.write(dump(result, indent=2, sort_keys=True)) + else: + recorded = engine.parse(path.read_bytes()) + require(engine.canonical(result) == engine.canonical(recorded), "complete result receipt differs") + print("PASS_SELECTED_INVOICE_REFERENCE_REBINDING" + f" files={result['source_census']['strict_files']} nodes={sum(a['nodes'] for a in result['artifacts'].values())}" + f" edges=2 positives={len(result['positive_controls'])} field_mutations={result['field_mutation_total']}" + f" synchronized_invoice_mutations={result['synchronized_invoice_mutations']}" + f" negatives={result['negative_controls']} no_new_kappa") + + +if __name__ == "__main__": + main()