diff --git a/research/jwr-chain-receipt/README.md b/research/jwr-chain-receipt/README.md new file mode 100644 index 000000000..48809590e --- /dev/null +++ b/research/jwr-chain-receipt/README.md @@ -0,0 +1,46 @@ +# jwr404 halo-absorption chain: disposition receipt + +**Task:** overlap-receipt. **Base:** canonical main `f626db5c`. **No new κ. No closures recommended.** + +This receipt covers 13 open PRs by jwr404 that extend the Gaussian halo-tensor chain after the merged #4506 (`research/gaussian-tensor-nine-faces`). + +## Disposition + +| PR | Package | Answers open question of | Status at base | +|----|---------|--------------------------|----------------| +| #4508 | gaussian-tensor-nine-axis | #4506 (merged) | open, not retained | +| #4509 | gaussian-tensor-nine-bridge | #4508 | open, not retained | +| #4511 | gaussian-axis-inheritance | #4509 | open, not retained | +| #4512 | gaussian-second-row | #4511 | open, not retained | +| #4515 | gaussian-operator-lift | #4512 | open, not retained | +| #4520 | gaussian-restricted-gate | (root; cites #4515, #4517) | open, not retained | +| #4523 | gaussian-global-tail | (root; cites #4520) | open, not retained | +| #4524 | gaussian-unequal-gate | (root) | open, not retained | +| #4526 | gaussian-heavy-slice | #4524 | open, not retained | +| #4527 | gaussian-slice-ten-gate | #4526 | open, not retained | +| #4528 | gaussian-slice-ten-copies | #4527 | open, not retained | +| #4530 | gaussian-slice-nine-gate | #4528 | open, not retained | +| #4531 | gaussian-slice-nine-copies | #4530 | open, not retained | + +- **Retention.** No package from the set is present at its merge base or on main `f626db5c`. Each PR is a single-package addition of 5 files. Exact heads, merge bases and per-file blobs are in `RECEIPT.json`. +- **Factor-9 versus factor-10.** #4530 and #4531 restate #4527 and #4528 with the factor-9 gate instead of factor 10. The factor-10 statements stay valid but are coarser, so a maintainer taking the slice results needs only the factor-9 pair, plus the factor-10 pair for attribution. +- **Outside the author's set.** #4517 (pinterbanget, open) answers #4515's open question; #4520 cites it. + +## Verify + +```text +python3 -B research/jwr-chain-receipt/verify.py +``` + +The verifier checks recorded facts only: SHA well-formedness, single-package additions, no retention at base, answer edges pointing backwards, and the factor-9/10 pairing. It does not test the working tree, so it still replays after any of these PRs merges. To compare heads, fetch `pull//head`. + +## Limitations + +- This records structure and provenance. It does not replay or review the mathematics of any PR. +- PR heads may move after recording; compare against `RECEIPT.json`. + +## Open next questions + +- An independent mathematical replay of the factor-9 slice pair #4530/#4531, which carries the chain's final absorption statements. First step: run each PR's registered verifier at its recorded head. + +Prepared by Ryanson Jonathan with substantial Claude Code (Claude Opus 5.5) assistance. Credit for all listed results: jwr404. diff --git a/research/jwr-chain-receipt/RECEIPT.json b/research/jwr-chain-receipt/RECEIPT.json new file mode 100644 index 000000000..2dfc5f6a7 --- /dev/null +++ b/research/jwr-chain-receipt/RECEIPT.json @@ -0,0 +1,314 @@ +{ + "schema": "jwr-chain-receipt/1", + "recorded_against_main": "f626db5c3a3d781d8f7695038776c621651f75e1", + "prs": { + "4508": { + "title": "Bound one tensor axis by two section errors at ceiling 9 (no new κ)", + "head": "def7e3f4b4b8e43536c2b808b26ef82b2e64e2b4", + "merge_base": "bbde3b0bedb8f7ce17159dfbe913b7e3e5194bab", + "package": "research/gaussian-tensor-nine-axis", + "files": { + "research/gaussian-tensor-nine-axis/README.md": "20ad3223899c7006651961b43c2f691202f1189f", + "research/gaussian-tensor-nine-axis/SOURCES.json": "b03a8b65e3559e8cece6df286c240c9839969047", + "research/gaussian-tensor-nine-axis/TASK.json": "ad2538315e18b3cf3169f2ab0d5dc3d749d7279c", + "research/gaussian-tensor-nine-axis/VERIFY.json": "e7b0cb1c7d843a6e9bbd617c8019b149cf2be82e", + "research/gaussian-tensor-nine-axis/verify.py": "4518ec7bf00d2ee220fe5125195b4988f38e96eb" + }, + "package_at_base": false, + "answers_open_question_of": 4506, + "paths_outside_package": [], + "mentions": [ + 4488, + 4506 + ] + }, + "4509": { + "title": "Split one axis through the section polynomial at ceiling 9 (no new κ)", + "head": "fefb6bce80cfc3f38a37b55a3bfd2beae9f78c68", + "merge_base": "f9f85c1e4fa1e955ff39f10fca447e3e2a4e4adc", + "package": "research/gaussian-tensor-nine-bridge", + "files": { + "research/gaussian-tensor-nine-bridge/README.md": "e56f0ade36a5c3ee6009a694e80ab6e747d92a9a", + "research/gaussian-tensor-nine-bridge/SOURCES.json": "03375d30cc5d6fdc292602da9f4fdab58f6b7566", + "research/gaussian-tensor-nine-bridge/TASK.json": "106e0250db04d2c8ee206c56e9d314a7241e1147", + "research/gaussian-tensor-nine-bridge/VERIFY.json": "db61e15e3cd5ec6b6b79ef31b8080344024a4076", + "research/gaussian-tensor-nine-bridge/verify.py": "fe04d581ac523412c7faea92013c8b36e4ba67bc" + }, + "package_at_base": false, + "answers_open_question_of": 4508, + "paths_outside_package": [], + "mentions": [ + 4490, + 4508 + ] + }, + "4511": { + "title": "Attribute the three axis hypotheses on one core row (no new κ)", + "head": "b6bbfaef1a736b8a15e1abb7148182fc5f750429", + "merge_base": "f9f85c1e4fa1e955ff39f10fca447e3e2a4e4adc", + "package": "research/gaussian-axis-inheritance", + "files": { + "research/gaussian-axis-inheritance/README.md": "8748ddaa5d2c4b0d729cbb2c2a3354cf3e15b98d", + "research/gaussian-axis-inheritance/SOURCES.json": "38ef9d625ec548fc651b650c6d8c841164cb1d82", + "research/gaussian-axis-inheritance/TASK.json": "671289c7cf0d699450befe6af9b20add74c3dcb8", + "research/gaussian-axis-inheritance/VERIFY.json": "f42f2ab3ca3e3ccdd28bdfe591c91b79ac53c416", + "research/gaussian-axis-inheritance/verify.py": "1dceec36d24ca3b155e0589e836ad92579076c91" + }, + "package_at_base": false, + "answers_open_question_of": 4509, + "paths_outside_package": [], + "mentions": [ + 4452, + 4491, + 4493, + 4509 + ] + }, + "4512": { + "title": "Add the two core-row section errors (no new κ)", + "head": "6687cd47bd720226d88b5c8441f0f63a425e0ca7", + "merge_base": "f9f85c1e4fa1e955ff39f10fca447e3e2a4e4adc", + "package": "research/gaussian-second-row", + "files": { + "research/gaussian-second-row/README.md": "41676a72445c50f380e83573bceef49c169ca471", + "research/gaussian-second-row/SOURCES.json": "b76b3ba7a8d7eade72659aa9c9ebdac65878ffab", + "research/gaussian-second-row/TASK.json": "7adad67359e8a6095b14e76209d416312102ce33", + "research/gaussian-second-row/VERIFY.json": "4053cbcabb61e927cdcf9d39ee5666258ac52b21", + "research/gaussian-second-row/verify.py": "01a995d908e68bbf72537f0d5f91491e84e7ca9b" + }, + "package_at_base": false, + "answers_open_question_of": 4511, + "paths_outside_package": [], + "mentions": [ + 4452, + 4491, + 4509, + 4511 + ] + }, + "4515": { + "title": "Separate the shared-row sum from the operator 2-norm (no new κ)", + "head": "535e4f578f8c19a11bd0a1202a392cbcfe932bfc", + "merge_base": "f9f85c1e4fa1e955ff39f10fca447e3e2a4e4adc", + "package": "research/gaussian-operator-lift", + "files": { + "research/gaussian-operator-lift/README.md": "4355c1a7e924009f27c429934ecdee8e019ded4b", + "research/gaussian-operator-lift/SOURCES.json": "f48e88f6f824c90d393ddf681c544dca0842456e", + "research/gaussian-operator-lift/TASK.json": "37fc07cd5557c3a68af09f77d3f66b4c5b33965e", + "research/gaussian-operator-lift/VERIFY.json": "a20f81610941e49579082be96be5e5aa3ae2ffef", + "research/gaussian-operator-lift/verify.py": "0e960f87dd8c7e8b0122c3f15fc6cddf09d366ca" + }, + "package_at_base": false, + "answers_open_question_of": 4512, + "paths_outside_package": [], + "mentions": [ + 4452, + 4490, + 4491, + 4509, + 4512 + ] + }, + "4520": { + "title": "Absorb the restricted monomial by the four-bit gate (no new κ)", + "head": "a25d6a1289daf53d9360889d8b2e82a04022173b", + "merge_base": "f9f85c1e4fa1e955ff39f10fca447e3e2a4e4adc", + "package": "research/gaussian-restricted-gate", + "files": { + "research/gaussian-restricted-gate/README.md": "a28c68f2b0b55a8f4f1aa22e43db51e6ce37c5e0", + "research/gaussian-restricted-gate/SOURCES.json": "e599896ee933783f9571683f124b83a355294d05", + "research/gaussian-restricted-gate/TASK.json": "bae3ff43c8934da9796c808c55a45851e353cda2", + "research/gaussian-restricted-gate/VERIFY.json": "2f0129bab1061372658e34f6fc768650604373d0", + "research/gaussian-restricted-gate/verify.py": "4e5c668b09ee19e73be0fd87b29f51972d91ed2f" + }, + "package_at_base": false, + "answers_open_question_of": null, + "paths_outside_package": [], + "mentions": [ + 4496, + 4506, + 4515, + 4517 + ] + }, + "4523": { + "title": "Record that the written global tail is p^10 exp(-p^2) (no new κ)", + "head": "fe53f24fdfa433f8ad88c29d24eed85add5634e6", + "merge_base": "f9f85c1e4fa1e955ff39f10fca447e3e2a4e4adc", + "package": "research/gaussian-global-tail", + "files": { + "research/gaussian-global-tail/README.md": "f6483fcb3656e7aadd4978ab11be2483a03d6485", + "research/gaussian-global-tail/SOURCES.json": "69dadd2851f3e4e2cd833c6842b539672504a96f", + "research/gaussian-global-tail/TASK.json": "e5925f2fe0bcf0591a508356afdb8afed598a00b", + "research/gaussian-global-tail/VERIFY.json": "498cc75f18403202276801fc931de13a512f7432", + "research/gaussian-global-tail/verify.py": "fcbb5036f600e5cef957acfb391e46462ae00eca" + }, + "package_at_base": false, + "answers_open_question_of": null, + "paths_outside_package": [], + "mentions": [ + 4406, + 4452, + 4520 + ] + }, + "4524": { + "title": "Absorb one section error and one global tail (no new κ)", + "head": "c416248f4d9964045db36c2b7edae0e9b6cc2d6c", + "merge_base": "f9f85c1e4fa1e955ff39f10fca447e3e2a4e4adc", + "package": "research/gaussian-unequal-gate", + "files": { + "research/gaussian-unequal-gate/README.md": "14851816651f46ddd7bb54cfaa1d14d6fe6a9cd8", + "research/gaussian-unequal-gate/SOURCES.json": "8e424731d9d9ab52490b8f0e50ccd5690371c5c7", + "research/gaussian-unequal-gate/TASK.json": "c4395663e874b86b478334d9d8a541f97d211b0e", + "research/gaussian-unequal-gate/VERIFY.json": "c77f648eece720d42d7e142b7307571ab486c8e7", + "research/gaussian-unequal-gate/verify.py": "262e7d3403198d4f61fb8efc57eab316462bec69" + }, + "package_at_base": false, + "answers_open_question_of": null, + "paths_outside_package": [], + "mentions": [] + }, + "4526": { + "title": "Absorb the heaviest trailing p^10 slice (no new κ)", + "head": "7392ecdb71403d9c9b31b7a349dbc82039f56514", + "merge_base": "f9f85c1e4fa1e955ff39f10fca447e3e2a4e4adc", + "package": "research/gaussian-heavy-slice", + "files": { + "research/gaussian-heavy-slice/README.md": "33144f496057f74cd090d3727e4327aa43f06806", + "research/gaussian-heavy-slice/SOURCES.json": "67e2fddfb68702bf6d46c09312b098b22edb9501", + "research/gaussian-heavy-slice/TASK.json": "8ebb0f4e7f182e8aba0c583fbc725d6e75977b3e", + "research/gaussian-heavy-slice/VERIFY.json": "84b76d65d519b47aacf6d72251c4bb353311ab5c", + "research/gaussian-heavy-slice/verify.py": "9636202c49e819dc4f91d768f0609ab4d151f03c" + }, + "package_at_base": false, + "answers_open_question_of": 4524, + "paths_outside_package": [], + "mentions": [ + 1166, + 4524 + ] + }, + "4527": { + "title": "Absorb the heavy slice by the factor-10 gate (no new κ)", + "head": "33f4920b4b68dba8373fd91a60dd0a3133a25be6", + "merge_base": "f9f85c1e4fa1e955ff39f10fca447e3e2a4e4adc", + "package": "research/gaussian-slice-ten-gate", + "files": { + "research/gaussian-slice-ten-gate/README.md": "8cfd987ed81570a25024a381e63fc6205c66db4a", + "research/gaussian-slice-ten-gate/SOURCES.json": "67e2fddfb68702bf6d46c09312b098b22edb9501", + "research/gaussian-slice-ten-gate/TASK.json": "959cec4cdc1a4783ae40fd609432d9000f598220", + "research/gaussian-slice-ten-gate/VERIFY.json": "90051181f55b76c0a31ca3b8328073a6c23bb72f", + "research/gaussian-slice-ten-gate/verify.py": "1f4249a97c0a8c0b31446d0c891bea471b2a1839" + }, + "package_at_base": false, + "answers_open_question_of": 4526, + "paths_outside_package": [], + "mentions": [ + 4526 + ] + }, + "4528": { + "title": "Absorb g copies of the heavy slice by the factor-10 gate (no new κ)", + "head": "b853775d514515e0d8a4406aa5748c6e5b36fe1e", + "merge_base": "f9f85c1e4fa1e955ff39f10fca447e3e2a4e4adc", + "package": "research/gaussian-slice-ten-copies", + "files": { + "research/gaussian-slice-ten-copies/README.md": "c9647f8f2e786e76ea8b93bb50306fccd98530ae", + "research/gaussian-slice-ten-copies/SOURCES.json": "67e2fddfb68702bf6d46c09312b098b22edb9501", + "research/gaussian-slice-ten-copies/TASK.json": "752fa5e93fac1d8f493a5ae150cf5936116f1855", + "research/gaussian-slice-ten-copies/VERIFY.json": "a244f4eb2fcd568c5b087384a4fc3ff008fb15fb", + "research/gaussian-slice-ten-copies/verify.py": "1d6548909bfa37bd688e8c1d941e2e52c7bf73f9" + }, + "package_at_base": false, + "answers_open_question_of": 4527, + "paths_outside_package": [], + "mentions": [ + 4527 + ] + }, + "4530": { + "title": "Absorb one heavy slice by the factor-9 gate (no new κ)", + "head": "2ea9a355c8c1ce6442959f778395e6e58656826d", + "merge_base": "f9f85c1e4fa1e955ff39f10fca447e3e2a4e4adc", + "package": "research/gaussian-slice-nine-gate", + "files": { + "research/gaussian-slice-nine-gate/README.md": "26f69577d9e8fbd327ff2c8f464b80e63cf4d3d5", + "research/gaussian-slice-nine-gate/SOURCES.json": "67e2fddfb68702bf6d46c09312b098b22edb9501", + "research/gaussian-slice-nine-gate/TASK.json": "120e3dfe842efe2479b20e25f2a507a70458387b", + "research/gaussian-slice-nine-gate/VERIFY.json": "f8112a4850d8d5fb5f9a70acf19e26c38d231634", + "research/gaussian-slice-nine-gate/verify.py": "46ce8d688c990082e7982e48f573f1e3591b94c7" + }, + "package_at_base": false, + "answers_open_question_of": 4528, + "paths_outside_package": [], + "mentions": [ + 4528 + ] + }, + "4531": { + "title": "Absorb g copies of the heavy slice by the factor-9 gate (no new κ)", + "head": "0fcfb608266b0190757fe307b4c3e52732afb298", + "merge_base": "f9f85c1e4fa1e955ff39f10fca447e3e2a4e4adc", + "package": "research/gaussian-slice-nine-copies", + "files": { + "research/gaussian-slice-nine-copies/README.md": "57703a34071a806c25ee1b71fa1a5afa1a948698", + "research/gaussian-slice-nine-copies/SOURCES.json": "67e2fddfb68702bf6d46c09312b098b22edb9501", + "research/gaussian-slice-nine-copies/TASK.json": "f0275efb9b4e073db9004996371e286d82e2849e", + "research/gaussian-slice-nine-copies/VERIFY.json": "46e2ddcf15a3cb3fd56230d2ac284eeb82a23530", + "research/gaussian-slice-nine-copies/verify.py": "935a312724bb9764eddc70359c73dc5a6ebe0b92" + }, + "package_at_base": false, + "answers_open_question_of": 4530, + "paths_outside_package": [], + "mentions": [ + 4530 + ] + } + }, + "chain": [ + 4506, + 4508, + 4509, + 4511, + 4512, + 4515, + 4517, + 4520, + 4523, + 4524, + 4526, + 4527, + 4528, + 4530, + 4531 + ], + "notes": { + "4517": "pinterbanget's core-row operator lift; #4520 answers its open question", + "4506": "merged predecessor", + "factor_variants": "#4527/#4528 use the factor-10 gate; #4530/#4531 redo them at factor 9 (ceiling 9p^2 from #4493) and answer #4528's question; the factor-10 statements remain valid but coarser" + }, + "author": "jwr404", + "predecessor_merged": { + "pr": 4506, + "package": "research/gaussian-tensor-nine-faces", + "on_main": true + }, + "outside_author": { + "4517": { + "author": "pinterbanget", + "state": "open", + "package": "research/core-row-operator-lift" + } + }, + "supersession": { + "4530": { + "refines": 4527, + "how": "factor-9 gate instead of factor-10" + }, + "4531": { + "refines": 4528, + "how": "factor-9 gate instead of factor-10" + } + } +} diff --git a/research/jwr-chain-receipt/SOURCES.json b/research/jwr-chain-receipt/SOURCES.json new file mode 100644 index 000000000..a2a5ea8bb --- /dev/null +++ b/research/jwr-chain-receipt/SOURCES.json @@ -0,0 +1,18 @@ +{ + "schema_version": 1, + "base_commit": "f626db5c3a3d781d8f7695038776c621651f75e1", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "ed33caef5c5827693e9572d252a66f99cbb73d40", + "sha256": "5732707cc1e460b090b53f2463162749ad860de878a18f7408938671d295a9d9" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "64bfc5af6709ed9811171e0a2108f05e1219cb65", + "sha256": "352a6184713b8843d96fd2c2071eb7aeaa655906b7c51d45ad444912666c8a96" + } + ] +} diff --git a/research/jwr-chain-receipt/TASK.json b/research/jwr-chain-receipt/TASK.json new file mode 100644 index 000000000..3a7d402e7 --- /dev/null +++ b/research/jwr-chain-receipt/TASK.json @@ -0,0 +1,60 @@ +{ + "schema_version": 1, + "task_id": "overlap-receipt", + "priority_revision": 7, + "base_commit": "f626db5c3a3d781d8f7695038776c621651f75e1", + "original_card": { + "id": "overlap-receipt", + "question": "What exact content and credit of a small named PR set has already been retained?", + "starting_points": [ + "docs/research/pr-ledger.md", + "CONTRIBUTORS.md" + ], + "methods": [ + "Compare exact heads and retained artifacts to write a source-bound disposition receipt.", + "Audit an existing receipt for missing content or predecessor attribution." + ], + "acceptance_gate": "Separate complete integration, partial retention and changed heads; make no autonomous closures.", + "first_step": { + "command": [ + "python3", + "-B", + "scripts/research_baseline.py" + ], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Read one small PR set in the ledger and identify exact reviewed heads and unresolved content.", + "scope": "Positive control / source-bound orientation only; this is not a new construction or full cold replay." + }, + "first_experiment": "Compare that set to retained artifacts; produce a complete or explicitly partial disposition receipt.", + "bottleneck_link": "Reliable overlap evidence preserves credit and prevents repeated review of already-retained material.", + "allowed_variations": [ + "One small related PR family or one existing integration receipt." + ], + "scope_change_triggers": [ + "Treating matching titles or one shared blob as proof of full incorporation." + ], + "overlap_terms": [ + "overlap receipt", + "partial integration", + "attribution" + ] + }, + "scope_status": "unchanged", + "actual_scope": "What exact content and credit of a small named PR set has already been retained?", + "scope_change_reason": null, + "bottleneck_link": "Consolidation: navigation for maintainers over 13 open halo-chain PRs, including which factor-10 results the factor-9 pair refines.", + "budget_minutes": 25, + "stop_rule": "Stop at the named 13-PR set.", + "outcome": "completed", + "evidence": "13 open single-package PRs, none retained at base or on main f626db5c; answer chain recorded; #4530/#4531 refine #4527/#4528.", + "author": "Ryanson Jonathan, with Claude Code (Claude Opus 5.5) assistance", + "ai_assistance": "Substantial Claude Code (Claude Opus 5.5) assistance; no independent human review.", + "open_questions": [ + { + "question": "Independent mathematical replay of the factor-9 slice pair #4530/#4531.", + "why_it_matters": "These carry the final absorption statements of the chain.", + "first_step": "Run each PR's registered verifier at its recorded head.", + "blocked_by": "None." + } + ] +} diff --git a/research/jwr-chain-receipt/VERIFY.json b/research/jwr-chain-receipt/VERIFY.json new file mode 100644 index 000000000..130882b93 --- /dev/null +++ b/research/jwr-chain-receipt/VERIFY.json @@ -0,0 +1,18 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [], + "commands": [ + { + "argv": [ + "{python}", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 60, + "checks": "Receipt for jwr404's 13-PR halo chain: SHAs well-formed, single-package additions, none retained at base, answer edges backward, factor-9 pair refines factor-10 pair." + } + ] +} diff --git a/research/jwr-chain-receipt/verify.py b/research/jwr-chain-receipt/verify.py new file mode 100644 index 000000000..6efd04454 --- /dev/null +++ b/research/jwr-chain-receipt/verify.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +"""Disposition receipt for jwr404's halo-absorption PR chain (13 open PRs, #4508-#4531, recorded at main f626db5c). + +Checks internal consistency of the recorded facts only (no working-tree checks, so the receipt still replays after any +of these PRs merges): every head and merge base is a full SHA, each PR is a single-package addition whose recorded +files lie inside its package, no package was present at its merge base, answer edges point to the merged predecessor +#4506, to #4517, or to earlier PRs in the set, and the factor-9 pair refines the factor-10 pair it answers. +Ryanson Jonathan with Claude Code (Claude Opus 5.5) assistance. Apache-2.0. +""" +import json +from pathlib import Path +import re +import sys + +HERE = Path(__file__).resolve().parent +SHA = re.compile(r"[0-9a-f]{40}") + + +def need(condition, message): + if not condition: + raise AssertionError(message) + + +def main(): + rec = json.loads((HERE / "RECEIPT.json").read_text(encoding="utf-8")) + prs = {int(n): r for n, r in rec["prs"].items()} + need(sorted(prs) == [4508, 4509, 4511, 4512, 4515, 4520, 4523, 4524, 4526, 4527, 4528, 4530, 4531], "the 13 PRs") + need(SHA.fullmatch(rec["recorded_against_main"]), "main SHA") + known = set(prs) | {rec["predecessor_merged"]["pr"]} | {int(n) for n in rec["outside_author"]} + packages = set() + for n, r in prs.items(): + need(SHA.fullmatch(r["head"]) and SHA.fullmatch(r["merge_base"]), f"#{n}: head and base") + need(r["package_at_base"] is False, f"#{n}: package not retained at its base") + need(r["paths_outside_package"] == [], f"#{n}: single-package addition") + need(len(r["files"]) >= 5 and all(SHA.fullmatch(b) for b in r["files"].values()), f"#{n}: blobs") + need(all(p.startswith(r["package"] + "/") for p in r["files"]), f"#{n}: files inside the package") + need(r["package"] not in packages, f"#{n}: distinct package") + packages.add(r["package"]) + a = r["answers_open_question_of"] + need(a is None or (a in known and a < n), f"#{n}: answer edge") + # The factor-9 pair branches from the factor-10 tip #4528: #4530 answers it, #4531 answers #4530. + sup = {int(n): s["refines"] for n, s in rec["supersession"].items()} + need(sup == {4530: 4527, 4531: 4528}, "factor-9 pair refines the factor-10 pair") + need(prs[4530]["answers_open_question_of"] == 4528 and prs[4531]["answers_open_question_of"] == 4530, "branch edges") + roots = [n for n, r in prs.items() if r["answers_open_question_of"] is None] + print(json.dumps({"status": "PASS_JWR_CHAIN_RECEIPT", "prs": len(prs), "retained_at_base": 0, + "chain_roots": roots, "factor9_refines": {k: v["refines"] for k, v in rec["supersession"].items()}, + "new_kappa_claimed": False}, indent=1)) + + +if __name__ == "__main__": + sys.exit(main())