Record verified Allocation assignment planner and portable evidence
This commit is contained in:
@@ -0,0 +1 @@
|
||||
** -text whitespace=cr-at-eol
|
||||
@@ -0,0 +1,24 @@
|
||||
# Allocation captured-gate evidence tools
|
||||
|
||||
Adapted from the reviewed Process prepare/verify/selfcheck tools. Read-only preparation consumes explicitly selected **closed** runs in CHECKOUT/.local/allocation-group-gates. No Cargo, source execution, checkout, GUI, network or archived helper execution occurs.
|
||||
|
||||
```powershell
|
||||
python -B prepare.py --root CHECKOUT --runs experiment-1 experiment-2 experiment-3 planner-document-1 probe-lint-1 format-1 --check-only
|
||||
```
|
||||
|
||||
Keep failed experiment-2: verification preserves its recorded compile failure rather than converting archive consistency into test success. The example selects the first six closed gates. Later closed planner runs can be explicitly listed with the same interface; the final package manifest is authoritative for its exact inventory. No implicit discovery includes active directories.
|
||||
|
||||
To create a portable package, replace --check-only with `--output NEW_DIRECTORY`. Existing output refuses. The exact seven raw files are required, with only `source-proof.json` accepted as an optional eighth file. No raw byte normalization or receipt rewriting occurs. Maps and nested input ZIPs deduplicate by SHA-256; other logical raw files keep their names. All original helper bytes, failed-run streams and optional proof bytes remain archived. The Allocation-specific manifest kind distinguishes this extension from the seven-file Process schema.
|
||||
|
||||
The gate.py and source-proof.py helper catalog is preserved. Every gate's recorded helper must match available bytes; use repeatable `--helper PATH` for older captures. If a proof exists, its exact comparator bytes must be available at the default `.local/process-source-evidence-tools/verify.py` or a repeatable `--comparator PATH`. They are archived under their content hash and never executed.
|
||||
|
||||
An optional source proof is independently pinned in the manifest with its full named commit. Verification binds it to the enclosing run, exact result receipt, captured map/count, completed gate time, status and comparator bytes/hash. Captured HEAD is preserved as historical metadata and is not substituted for the named source commit. This packager checks historical proof consistency; it does **not** repeat Git blob comparison. A source proof on a failed gate is source-identity evidence only, never a passing-test claim.
|
||||
|
||||
```powershell
|
||||
python -B PACKAGE/verify.py
|
||||
python -B selfcheck.py --root CHECKOUT --runs experiment-1 experiment-2 experiment-3 planner-document-1 probe-lint-1 format-1 --output TOOLS/NEW_SELFCHECK_DIRECTORY
|
||||
```
|
||||
|
||||
The verifier checks pins, exact ZIP inventory, process/start/result relationships, streams, command/exit identities, source capsules, vendor inventory and Cargo artifact relationships. Selfchecks compare packaged raw bytes to originals, reject existing output, and mutate only in-memory copies to test stream/helper/exit/capsule/proof corruption. The package contains tools, manifest, files.json and evidence.zip; selfcheck is a preparation utility, not packaged runtime input.
|
||||
|
||||
Limits: internal consistency is not external authentication, hermetic build proof, native usability, a new source comparison or production acceptance. Review exact run results and source identity separately. Run with `python -B` to avoid incidental bytecode writes.
|
||||
Binary file not shown.
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"prepare.py": {
|
||||
"bytes": 6316,
|
||||
"sha256": "aa52592fb8e373c2a90007e187734d29129d38d9fce9dc45461482c7f6376bff"
|
||||
},
|
||||
"verify.py": {
|
||||
"bytes": 11440,
|
||||
"sha256": "584187370a1076e13190914158fc72a9ab65f07e72cc6a0d3b5c319f3dc7f05f"
|
||||
},
|
||||
"README.md": {
|
||||
"bytes": 3284,
|
||||
"sha256": "3ff0a61fb15ca26e54b8903962c99ba7802a87f0204e7b71f2d04c812b9588b7"
|
||||
},
|
||||
"manifest.json": {
|
||||
"bytes": 17748,
|
||||
"sha256": "f053e2f1492ee4fdfa2d4dfd7e48c5768d098cf96b629471699810d06cb61537"
|
||||
},
|
||||
"evidence.zip": {
|
||||
"bytes": 8984108,
|
||||
"sha256": "51b898205ee7a2907ce746389882f0607f7ad7290a1759b392cd307ef9e9ef5a"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,396 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"kind": "allocation-multiselect-cargo-gates",
|
||||
"runs": {
|
||||
"assignment-planner-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--example",
|
||||
"allocation_policy_probe",
|
||||
"--message-format=json",
|
||||
"--",
|
||||
"--test-threads=1"
|
||||
],
|
||||
"head": "eed80ffd6e94c7127491de1fd45c0415685f6328",
|
||||
"exitCode": 0,
|
||||
"inputCount": 749,
|
||||
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py"
|
||||
},
|
||||
"assignment-planner-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--example",
|
||||
"allocation_policy_probe",
|
||||
"--message-format=json",
|
||||
"--",
|
||||
"--test-threads=1"
|
||||
],
|
||||
"head": "eed80ffd6e94c7127491de1fd45c0415685f6328",
|
||||
"exitCode": 0,
|
||||
"inputCount": 750,
|
||||
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py"
|
||||
},
|
||||
"assignment-lint-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"clippy",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--example",
|
||||
"allocation_policy_probe",
|
||||
"--tests",
|
||||
"--message-format=json",
|
||||
"--",
|
||||
"-D",
|
||||
"warnings"
|
||||
],
|
||||
"head": "eed80ffd6e94c7127491de1fd45c0415685f6328",
|
||||
"exitCode": 0,
|
||||
"inputCount": 750,
|
||||
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py"
|
||||
},
|
||||
"assignment-format-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"fmt",
|
||||
"--all",
|
||||
"--",
|
||||
"--check"
|
||||
],
|
||||
"head": "eed80ffd6e94c7127491de1fd45c0415685f6328",
|
||||
"exitCode": 0,
|
||||
"inputCount": 750,
|
||||
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py"
|
||||
},
|
||||
"assignment-planner-3": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--example",
|
||||
"allocation_policy_probe",
|
||||
"--message-format=json",
|
||||
"--",
|
||||
"--test-threads=1"
|
||||
],
|
||||
"head": "33e880103c5fa935a4431ec3dc089e2c4c92f680",
|
||||
"exitCode": 0,
|
||||
"inputCount": 750,
|
||||
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py",
|
||||
"sourceProof": {
|
||||
"commit": "33e880103c5fa935a4431ec3dc089e2c4c92f680",
|
||||
"pin": {
|
||||
"bytes": 599,
|
||||
"sha256": "3b249398b0ade218ec9737677e1021e21eae7aa03deeb6bc071e0e7e7fe6182b"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
},
|
||||
"assignment-lint-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"clippy",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--example",
|
||||
"allocation_policy_probe",
|
||||
"--tests",
|
||||
"--message-format=json",
|
||||
"--",
|
||||
"-D",
|
||||
"warnings"
|
||||
],
|
||||
"head": "33e880103c5fa935a4431ec3dc089e2c4c92f680",
|
||||
"exitCode": 0,
|
||||
"inputCount": 750,
|
||||
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py",
|
||||
"sourceProof": {
|
||||
"commit": "33e880103c5fa935a4431ec3dc089e2c4c92f680",
|
||||
"pin": {
|
||||
"bytes": 596,
|
||||
"sha256": "3a8f4d17bc6e696f8c0a1373f739650da5aa5b84683478c697e71b280d07b430"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
},
|
||||
"assignment-format-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"fmt",
|
||||
"--all",
|
||||
"--",
|
||||
"--check"
|
||||
],
|
||||
"head": "33e880103c5fa935a4431ec3dc089e2c4c92f680",
|
||||
"exitCode": 0,
|
||||
"inputCount": 750,
|
||||
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py",
|
||||
"sourceProof": {
|
||||
"commit": "33e880103c5fa935a4431ec3dc089e2c4c92f680",
|
||||
"pin": {
|
||||
"bytes": 598,
|
||||
"sha256": "41553cf5d5e5f6414930ad088fa82515630d3478da53a5ac961c8bf4191d1bc6"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
}
|
||||
},
|
||||
"captureHelpers": {
|
||||
"gate.py": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py",
|
||||
"source-proof.py": "helpers/58597566ae1cb5c4021ddc7e86635b76d127bdb63b5d3026c427771aae7e2119.py"
|
||||
},
|
||||
"logicalFiles": {
|
||||
"cargo/assignment-format-1/inputs.json": "capsules/e41e7d1a2b9519b78730821f96c1bf7ca8431935fe67efa203daa80d3f15c437.json",
|
||||
"cargo/assignment-format-1/inputs.zip": "capsules/b471d434d8eac790ef7cc9073be0d395c9c9ad1472ba06a05b5818269ef03dfe.zip",
|
||||
"cargo/assignment-format-1/process.json": "cargo/assignment-format-1/process.json",
|
||||
"cargo/assignment-format-1/result.json": "cargo/assignment-format-1/result.json",
|
||||
"cargo/assignment-format-1/started.json": "cargo/assignment-format-1/started.json",
|
||||
"cargo/assignment-format-1/stderr.log": "cargo/assignment-format-1/stderr.log",
|
||||
"cargo/assignment-format-1/stdout.log": "cargo/assignment-format-1/stdout.log",
|
||||
"cargo/assignment-format-2/inputs.json": "capsules/ce988ecaeaca395d0f120844db7e3da90d039633beef10d2d4a8b8f19e92ee27.json",
|
||||
"cargo/assignment-format-2/inputs.zip": "capsules/ae03a0a847a5c2000ba46e356e3dcd13a219e5fb699be8ad71a619b593e13c23.zip",
|
||||
"cargo/assignment-format-2/process.json": "cargo/assignment-format-2/process.json",
|
||||
"cargo/assignment-format-2/result.json": "cargo/assignment-format-2/result.json",
|
||||
"cargo/assignment-format-2/source-proof.json": "cargo/assignment-format-2/source-proof.json",
|
||||
"cargo/assignment-format-2/started.json": "cargo/assignment-format-2/started.json",
|
||||
"cargo/assignment-format-2/stderr.log": "cargo/assignment-format-2/stderr.log",
|
||||
"cargo/assignment-format-2/stdout.log": "cargo/assignment-format-2/stdout.log",
|
||||
"cargo/assignment-lint-1/inputs.json": "capsules/e41e7d1a2b9519b78730821f96c1bf7ca8431935fe67efa203daa80d3f15c437.json",
|
||||
"cargo/assignment-lint-1/inputs.zip": "capsules/b471d434d8eac790ef7cc9073be0d395c9c9ad1472ba06a05b5818269ef03dfe.zip",
|
||||
"cargo/assignment-lint-1/process.json": "cargo/assignment-lint-1/process.json",
|
||||
"cargo/assignment-lint-1/result.json": "cargo/assignment-lint-1/result.json",
|
||||
"cargo/assignment-lint-1/started.json": "cargo/assignment-lint-1/started.json",
|
||||
"cargo/assignment-lint-1/stderr.log": "cargo/assignment-lint-1/stderr.log",
|
||||
"cargo/assignment-lint-1/stdout.log": "cargo/assignment-lint-1/stdout.log",
|
||||
"cargo/assignment-lint-2/inputs.json": "capsules/ce988ecaeaca395d0f120844db7e3da90d039633beef10d2d4a8b8f19e92ee27.json",
|
||||
"cargo/assignment-lint-2/inputs.zip": "capsules/ae03a0a847a5c2000ba46e356e3dcd13a219e5fb699be8ad71a619b593e13c23.zip",
|
||||
"cargo/assignment-lint-2/process.json": "cargo/assignment-lint-2/process.json",
|
||||
"cargo/assignment-lint-2/result.json": "cargo/assignment-lint-2/result.json",
|
||||
"cargo/assignment-lint-2/source-proof.json": "cargo/assignment-lint-2/source-proof.json",
|
||||
"cargo/assignment-lint-2/started.json": "cargo/assignment-lint-2/started.json",
|
||||
"cargo/assignment-lint-2/stderr.log": "cargo/assignment-lint-2/stderr.log",
|
||||
"cargo/assignment-lint-2/stdout.log": "cargo/assignment-lint-2/stdout.log",
|
||||
"cargo/assignment-planner-1/inputs.json": "capsules/4e237aa6ba6359490d65efd40e15a697991ce53350af2080503c0635d2d9de3e.json",
|
||||
"cargo/assignment-planner-1/inputs.zip": "capsules/1bb6e8b18022977f43e29bd44d25238acbf8c424bd4bf736474fce74bd8de8bc.zip",
|
||||
"cargo/assignment-planner-1/process.json": "cargo/assignment-planner-1/process.json",
|
||||
"cargo/assignment-planner-1/result.json": "cargo/assignment-planner-1/result.json",
|
||||
"cargo/assignment-planner-1/started.json": "cargo/assignment-planner-1/started.json",
|
||||
"cargo/assignment-planner-1/stderr.log": "cargo/assignment-planner-1/stderr.log",
|
||||
"cargo/assignment-planner-1/stdout.log": "cargo/assignment-planner-1/stdout.log",
|
||||
"cargo/assignment-planner-2/inputs.json": "capsules/e41e7d1a2b9519b78730821f96c1bf7ca8431935fe67efa203daa80d3f15c437.json",
|
||||
"cargo/assignment-planner-2/inputs.zip": "capsules/b471d434d8eac790ef7cc9073be0d395c9c9ad1472ba06a05b5818269ef03dfe.zip",
|
||||
"cargo/assignment-planner-2/process.json": "cargo/assignment-planner-2/process.json",
|
||||
"cargo/assignment-planner-2/result.json": "cargo/assignment-planner-2/result.json",
|
||||
"cargo/assignment-planner-2/started.json": "cargo/assignment-planner-2/started.json",
|
||||
"cargo/assignment-planner-2/stderr.log": "cargo/assignment-planner-2/stderr.log",
|
||||
"cargo/assignment-planner-2/stdout.log": "cargo/assignment-planner-2/stdout.log",
|
||||
"cargo/assignment-planner-3/inputs.json": "capsules/ce988ecaeaca395d0f120844db7e3da90d039633beef10d2d4a8b8f19e92ee27.json",
|
||||
"cargo/assignment-planner-3/inputs.zip": "capsules/ae03a0a847a5c2000ba46e356e3dcd13a219e5fb699be8ad71a619b593e13c23.zip",
|
||||
"cargo/assignment-planner-3/process.json": "cargo/assignment-planner-3/process.json",
|
||||
"cargo/assignment-planner-3/result.json": "cargo/assignment-planner-3/result.json",
|
||||
"cargo/assignment-planner-3/source-proof.json": "cargo/assignment-planner-3/source-proof.json",
|
||||
"cargo/assignment-planner-3/started.json": "cargo/assignment-planner-3/started.json",
|
||||
"cargo/assignment-planner-3/stderr.log": "cargo/assignment-planner-3/stderr.log",
|
||||
"cargo/assignment-planner-3/stdout.log": "cargo/assignment-planner-3/stdout.log",
|
||||
"comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py",
|
||||
"helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py",
|
||||
"helpers/58597566ae1cb5c4021ddc7e86635b76d127bdb63b5d3026c427771aae7e2119.py": "helpers/58597566ae1cb5c4021ddc7e86635b76d127bdb63b5d3026c427771aae7e2119.py"
|
||||
},
|
||||
"members": {
|
||||
"capsules/1bb6e8b18022977f43e29bd44d25238acbf8c424bd4bf736474fce74bd8de8bc.zip": {
|
||||
"bytes": 3008043,
|
||||
"sha256": "1bb6e8b18022977f43e29bd44d25238acbf8c424bd4bf736474fce74bd8de8bc"
|
||||
},
|
||||
"capsules/4e237aa6ba6359490d65efd40e15a697991ce53350af2080503c0635d2d9de3e.json": {
|
||||
"bytes": 125475,
|
||||
"sha256": "4e237aa6ba6359490d65efd40e15a697991ce53350af2080503c0635d2d9de3e"
|
||||
},
|
||||
"capsules/ae03a0a847a5c2000ba46e356e3dcd13a219e5fb699be8ad71a619b593e13c23.zip": {
|
||||
"bytes": 3013577,
|
||||
"sha256": "ae03a0a847a5c2000ba46e356e3dcd13a219e5fb699be8ad71a619b593e13c23"
|
||||
},
|
||||
"capsules/b471d434d8eac790ef7cc9073be0d395c9c9ad1472ba06a05b5818269ef03dfe.zip": {
|
||||
"bytes": 3013606,
|
||||
"sha256": "b471d434d8eac790ef7cc9073be0d395c9c9ad1472ba06a05b5818269ef03dfe"
|
||||
},
|
||||
"capsules/ce988ecaeaca395d0f120844db7e3da90d039633beef10d2d4a8b8f19e92ee27.json": {
|
||||
"bytes": 125659,
|
||||
"sha256": "ce988ecaeaca395d0f120844db7e3da90d039633beef10d2d4a8b8f19e92ee27"
|
||||
},
|
||||
"capsules/e41e7d1a2b9519b78730821f96c1bf7ca8431935fe67efa203daa80d3f15c437.json": {
|
||||
"bytes": 125659,
|
||||
"sha256": "e41e7d1a2b9519b78730821f96c1bf7ca8431935fe67efa203daa80d3f15c437"
|
||||
},
|
||||
"cargo/assignment-format-1/process.json": {
|
||||
"bytes": 116,
|
||||
"sha256": "ea332ddf4129442f2a8f19b150a6c2fc21a41299eadc32287ba6ba67769e2b58"
|
||||
},
|
||||
"cargo/assignment-format-1/result.json": {
|
||||
"bytes": 1872,
|
||||
"sha256": "46047bb39986083c89d12751153b678eedd660963b9dafb02c1738986f0dd47a"
|
||||
},
|
||||
"cargo/assignment-format-1/started.json": {
|
||||
"bytes": 1484,
|
||||
"sha256": "3657a2a7ac270bca405c128328557fb5e1725f913ae0c9c5baa1ba08269bb501"
|
||||
},
|
||||
"cargo/assignment-format-1/stderr.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/assignment-format-1/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/assignment-format-2/process.json": {
|
||||
"bytes": 116,
|
||||
"sha256": "8371d4a455f0dd7678c5b8fb91f679355c05f9f0594985460aee9796bd6adc65"
|
||||
},
|
||||
"cargo/assignment-format-2/result.json": {
|
||||
"bytes": 1872,
|
||||
"sha256": "319d67031a3f30f70b21f869d755b91196ce0be68d8132775288b3d86b223d06"
|
||||
},
|
||||
"cargo/assignment-format-2/source-proof.json": {
|
||||
"bytes": 598,
|
||||
"sha256": "41553cf5d5e5f6414930ad088fa82515630d3478da53a5ac961c8bf4191d1bc6"
|
||||
},
|
||||
"cargo/assignment-format-2/started.json": {
|
||||
"bytes": 1483,
|
||||
"sha256": "a59985096b89da3518c367131b3ec257596725d18f62307bfc174ccb7969c362"
|
||||
},
|
||||
"cargo/assignment-format-2/stderr.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/assignment-format-2/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/assignment-lint-1/process.json": {
|
||||
"bytes": 213,
|
||||
"sha256": "b14d908c775b772f6993b40965a21ae894a406665fa5c2794ebfdb7ffe082769"
|
||||
},
|
||||
"cargo/assignment-lint-1/result.json": {
|
||||
"bytes": 2006,
|
||||
"sha256": "a8c6cc8a726c9bee821b2c12a0768d860bb1c40261783bcc23da2ea19a677959"
|
||||
},
|
||||
"cargo/assignment-lint-1/started.json": {
|
||||
"bytes": 1610,
|
||||
"sha256": "3f42270e22476b1698f19cfdc8cd6c78b0754480b613963d582d98d89bf541f6"
|
||||
},
|
||||
"cargo/assignment-lint-1/stderr.log": {
|
||||
"bytes": 137,
|
||||
"sha256": "d64f9789f0e3e22b0c98af77d19231a9026083ad317f6b2f989ebebd556f1269"
|
||||
},
|
||||
"cargo/assignment-lint-1/stdout.log": {
|
||||
"bytes": 268845,
|
||||
"sha256": "98a24be8306e586a1acb6a72c3e62005afc0db01fa4ec0b242c420aafadcf779"
|
||||
},
|
||||
"cargo/assignment-lint-2/process.json": {
|
||||
"bytes": 212,
|
||||
"sha256": "17b1f10f739cdf456da58ef2dcd9c15a8569132904876b8e2289ea543f1217d7"
|
||||
},
|
||||
"cargo/assignment-lint-2/result.json": {
|
||||
"bytes": 2005,
|
||||
"sha256": "ec3bc72c846cc08188ff95d38aa743c52ac9ec2c616fb8acb7566a6619490b68"
|
||||
},
|
||||
"cargo/assignment-lint-2/source-proof.json": {
|
||||
"bytes": 596,
|
||||
"sha256": "3a8f4d17bc6e696f8c0a1373f739650da5aa5b84683478c697e71b280d07b430"
|
||||
},
|
||||
"cargo/assignment-lint-2/started.json": {
|
||||
"bytes": 1610,
|
||||
"sha256": "afdad6e675e3351c749dccea6759c01f8b303a0d598f41592f62beecbc94fdf7"
|
||||
},
|
||||
"cargo/assignment-lint-2/stderr.log": {
|
||||
"bytes": 137,
|
||||
"sha256": "6ceb01ea1a2f7759c0f7e4fcc98504fae7f6f9cb758b16a2701f804c88ec401d"
|
||||
},
|
||||
"cargo/assignment-lint-2/stdout.log": {
|
||||
"bytes": 268845,
|
||||
"sha256": "8b993ec00e2a4a58b15af1e57051906cbee8d3d51f4314b71f71af28f582a675"
|
||||
},
|
||||
"cargo/assignment-planner-1/process.json": {
|
||||
"bytes": 202,
|
||||
"sha256": "1aec12d9a133576033cb736bdec098873005e8b248e09157a3e7608c2d551fdc"
|
||||
},
|
||||
"cargo/assignment-planner-1/result.json": {
|
||||
"bytes": 3388,
|
||||
"sha256": "b1bc1f3f3013c9df43f7af3cef801e0b977ec484457cfc314e4aa2f1c8d6db98"
|
||||
},
|
||||
"cargo/assignment-planner-1/started.json": {
|
||||
"bytes": 1589,
|
||||
"sha256": "75d0eeca99ff5f2819a0302cbdc739d2377a2f524890f448f040585288680d2e"
|
||||
},
|
||||
"cargo/assignment-planner-1/stderr.log": {
|
||||
"bytes": 324,
|
||||
"sha256": "8ee7484db45f8ddf1bf0057317feb689990758c35dc0946c12e0eef0de08e808"
|
||||
},
|
||||
"cargo/assignment-planner-1/stdout.log": {
|
||||
"bytes": 301624,
|
||||
"sha256": "7be201e6c1a812d8a32d73e75999e5e50a07af2f11eebc77f442aee44f64e5af"
|
||||
},
|
||||
"cargo/assignment-planner-2/process.json": {
|
||||
"bytes": 202,
|
||||
"sha256": "5837e6b91cbd5c6c95bbeaf08ac89a47149e84c4c3f20004457e80c316e388c9"
|
||||
},
|
||||
"cargo/assignment-planner-2/result.json": {
|
||||
"bytes": 3387,
|
||||
"sha256": "2dd1c6036eb805cd8e95050661e3dce9d132f9071186165097d4212f2b8253c0"
|
||||
},
|
||||
"cargo/assignment-planner-2/started.json": {
|
||||
"bytes": 1589,
|
||||
"sha256": "a4384901a0d3a29631a29d5e91b6d3dc944cefca1bb7653901d351a7bd906ec1"
|
||||
},
|
||||
"cargo/assignment-planner-2/stderr.log": {
|
||||
"bytes": 324,
|
||||
"sha256": "a046d75d45956402707b7c1089ec5005b0ba640857473e1f284a8f377f896f2c"
|
||||
},
|
||||
"cargo/assignment-planner-2/stdout.log": {
|
||||
"bytes": 302839,
|
||||
"sha256": "1905a2726b6e9c388566af75d7705b3916ade3a7d2c9dab772bffbb5b115762b"
|
||||
},
|
||||
"cargo/assignment-planner-3/process.json": {
|
||||
"bytes": 202,
|
||||
"sha256": "ec191e2d953d52f6da8c54bc6e9dfa5638273eb6c351823fc4871628320b3bab"
|
||||
},
|
||||
"cargo/assignment-planner-3/result.json": {
|
||||
"bytes": 3388,
|
||||
"sha256": "117bcfa31629682df708dfebb892464f01060888388ea680a231b12cd447db67"
|
||||
},
|
||||
"cargo/assignment-planner-3/source-proof.json": {
|
||||
"bytes": 599,
|
||||
"sha256": "3b249398b0ade218ec9737677e1021e21eae7aa03deeb6bc071e0e7e7fe6182b"
|
||||
},
|
||||
"cargo/assignment-planner-3/started.json": {
|
||||
"bytes": 1589,
|
||||
"sha256": "30cf725d9475a24b177c2dbddb3f59b7d298343556598bc0e760d51ad7e111e5"
|
||||
},
|
||||
"cargo/assignment-planner-3/stderr.log": {
|
||||
"bytes": 324,
|
||||
"sha256": "d3a0110134db80cd8715e6081027595056203feada2278053fdc62ae75c6df31"
|
||||
},
|
||||
"cargo/assignment-planner-3/stdout.log": {
|
||||
"bytes": 302839,
|
||||
"sha256": "aa832fe75c46be8990d0c679e6e321494c0ea6638657634010bae7022b7a2ee9"
|
||||
},
|
||||
"comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py": {
|
||||
"bytes": 10094,
|
||||
"sha256": "7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a"
|
||||
},
|
||||
"helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py": {
|
||||
"bytes": 3827,
|
||||
"sha256": "1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20"
|
||||
},
|
||||
"helpers/58597566ae1cb5c4021ddc7e86635b76d127bdb63b5d3026c427771aae7e2119.py": {
|
||||
"bytes": 1399,
|
||||
"sha256": "58597566ae1cb5c4021ddc7e86635b76d127bdb63b5d3026c427771aae7e2119"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
"""Package explicitly selected closed gate captures without running Cargo."""
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
import json
|
||||
import zipfile
|
||||
from verify import RAW_FILES, pin, parsed, need, run_name, verify_data, verify_package
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
|
||||
|
||||
def collect(root, runs, helpers, comparators=()):
|
||||
gates = root / ".local/allocation-group-gates"
|
||||
candidates = [gates / name for name in ("gate.py", "source-proof.py")] + helpers
|
||||
helper_bytes = [path.read_bytes() for path in candidates]
|
||||
comparator_paths = [root / ".local/process-source-evidence-tools/verify.py", *comparators]
|
||||
comparator_bytes = [path.read_bytes() for path in comparator_paths if path.is_file()]
|
||||
payload, logical, specs = {}, {}, {}
|
||||
def add(name, data):
|
||||
stored = ("capsules/" + pin(data)["sha256"] + Path(name).suffix
|
||||
if name.rsplit("/", 1)[1] in {"inputs.json", "inputs.zip"} else name)
|
||||
need(stored not in payload or payload[stored] == data, "deduplication collision")
|
||||
payload[stored] = data
|
||||
logical[name] = stored
|
||||
helper_catalog = {}
|
||||
for name, data in zip(("gate.py", "source-proof.py"), helper_bytes):
|
||||
helper = "helpers/" + pin(data)["sha256"] + ".py"
|
||||
add(helper, data)
|
||||
helper_catalog[name] = helper
|
||||
for run in runs:
|
||||
folder = gates / run
|
||||
need(folder.is_dir(), "run directory missing: " + run)
|
||||
paths = list(folder.iterdir())
|
||||
names = {path.name for path in paths}
|
||||
need(all(path.is_file() and not path.is_symlink() for path in paths)
|
||||
and names in (RAW_FILES, RAW_FILES | {"source-proof.json"}), "exact closed raw files required: " + run)
|
||||
raw = {path.name: path.read_bytes() for path in paths}
|
||||
result = parsed(raw["result.json"])
|
||||
need("finish" in result and result["inputsUnchanged"] is True, "unfinished/changed run refused: " + run)
|
||||
matches = [data for data in helper_bytes if pin(data) == result["helper"]]
|
||||
need(bool(matches), "exact historical helper unavailable for " + run + "; supply --helper PATH")
|
||||
helper = "helpers/" + result["helper"]["sha256"] + ".py"
|
||||
add(helper, matches[0])
|
||||
for name, data in sorted(raw.items()):
|
||||
add("cargo/" + run + "/" + name, data)
|
||||
specs[run] = {key: result[key] for key in ("command", "head", "exitCode", "inputCount")}
|
||||
specs[run]["helper"] = helper
|
||||
if "source-proof.json" in raw:
|
||||
proof = parsed(raw["source-proof.json"])
|
||||
matches = [data for data in comparator_bytes if pin(data) == proof["comparator"]]
|
||||
need(bool(matches), "exact source comparator unavailable for " + run + "; supply --comparator PATH")
|
||||
comparator = "comparators/" + proof["comparator"]["sha256"] + ".py"
|
||||
add(comparator, matches[0])
|
||||
specs[run]["sourceProof"] = {"commit": proof["commit"], "pin": pin(raw["source-proof.json"]), "comparator": comparator}
|
||||
manifest = {"schema": 1, "kind": "allocation-multiselect-cargo-gates", "runs": specs,
|
||||
"captureHelpers": helper_catalog,
|
||||
"logicalFiles": dict(sorted(logical.items())),
|
||||
"members": {name: pin(data) for name, data in sorted(payload.items())}}
|
||||
summary = verify_data(manifest, payload.__getitem__)
|
||||
return payload, manifest, summary
|
||||
|
||||
|
||||
def write_json(path, value):
|
||||
with path.open("xb") as output:
|
||||
output.write((json.dumps(value, indent=2) + "\n").encode("utf-8"))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--root", type=Path, required=True, help="checkout holding .local/allocation-group-gates")
|
||||
parser.add_argument("--runs", nargs="+", required=True, help="explicit run names, including failures to retain")
|
||||
parser.add_argument("--helper", type=Path, action="append", default=[], help="additional exact historical helper (repeatable)")
|
||||
parser.add_argument("--comparator", type=Path, action="append", default=[], help="additional exact historical source comparator (repeatable)")
|
||||
parser.add_argument("--output", type=Path, help="fresh, nonexistent package directory (required unless --check-only)")
|
||||
parser.add_argument("--check-only", action="store_true", help="validate raw captures in memory without creating an archive")
|
||||
args = parser.parse_args()
|
||||
need(all(run_name(run) for run in args.runs) and len(args.runs) == len(set(args.runs)), "unique safe run names required")
|
||||
need(args.check_only or args.output is not None, "--output is required unless --check-only")
|
||||
if not args.check_only:
|
||||
need(not args.output.exists(), "output must be a fresh directory: " + str(args.output))
|
||||
payload, manifest, summary = collect(args.root.resolve(), args.runs, args.helper, args.comparator)
|
||||
if args.check_only:
|
||||
print("PASS raw consistency; no package written:", summary)
|
||||
return
|
||||
out = args.output.resolve()
|
||||
out.mkdir(parents=True, exist_ok=False)
|
||||
for name in ("evidence.zip", "manifest.json", "files.json"):
|
||||
need(not (out / name).exists(), "existing package output refused: " + name)
|
||||
for name in ("prepare.py", "verify.py", "README.md"):
|
||||
data = (HERE / name).read_bytes()
|
||||
destination = out / name
|
||||
if destination.exists():
|
||||
need(destination.read_bytes() == data, "different existing package tool: " + name)
|
||||
else:
|
||||
with destination.open("xb") as output:
|
||||
output.write(data)
|
||||
with zipfile.ZipFile(out / "evidence.zip", "x", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as archive:
|
||||
for name, data in sorted(payload.items()):
|
||||
info = zipfile.ZipInfo(name, date_time=(2026, 9, 23, 0, 0, 0))
|
||||
info.compress_type = zipfile.ZIP_DEFLATED
|
||||
info.external_attr = 0o100644 << 16
|
||||
archive.writestr(info, data)
|
||||
write_json(out / "manifest.json", manifest)
|
||||
names = ("prepare.py", "verify.py", "README.md", "manifest.json", "evidence.zip")
|
||||
write_json(out / "files.json", {name: pin((out / name).read_bytes()) for name in names})
|
||||
need(verify_package(out) == summary, "written package differs from validated captures")
|
||||
print("PASS package readback:", out, summary)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,194 @@
|
||||
"""Offline consistency checks only; never execute or extract archived inputs."""
|
||||
from pathlib import Path, PurePosixPath
|
||||
from datetime import datetime
|
||||
import argparse
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import math
|
||||
import re
|
||||
import stat
|
||||
import zipfile
|
||||
|
||||
RAW_FILES = {"started.json", "process.json", "result.json", "stdout.log", "stderr.log", "inputs.json", "inputs.zip"}
|
||||
OUTER_FILES = {"prepare.py", "verify.py", "README.md", "manifest.json", "evidence.zip"}
|
||||
|
||||
|
||||
def need(condition, message):
|
||||
if not condition:
|
||||
raise ValueError(message)
|
||||
|
||||
|
||||
def pin(data):
|
||||
return {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()}
|
||||
|
||||
|
||||
def valid_pin(value):
|
||||
return (isinstance(value, dict) and set(value) == {"bytes", "sha256"}
|
||||
and type(value["bytes"]) is int and value["bytes"] >= 0
|
||||
and isinstance(value["sha256"], str)
|
||||
and re.fullmatch(r"[0-9a-f]{64}", value["sha256"]) is not None)
|
||||
|
||||
|
||||
def safe(name):
|
||||
return (isinstance(name, str) and bool(name) and "\\" not in name and ":" not in name
|
||||
and all(ord(char) >= 32 for char in name)
|
||||
and not PurePosixPath(name).is_absolute()
|
||||
and all(part not in ("", ".", "..") for part in name.split("/")))
|
||||
|
||||
|
||||
def run_name(name):
|
||||
return isinstance(name, str) and re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]*", name) is not None
|
||||
|
||||
|
||||
def parsed(data):
|
||||
def pairs(items):
|
||||
result = {}
|
||||
for key, value in items:
|
||||
need(key not in result, "duplicate JSON key: " + key)
|
||||
result[key] = value
|
||||
return result
|
||||
def constant(value):
|
||||
raise ValueError("nonfinite JSON constant: " + value)
|
||||
return json.loads(data, object_pairs_hook=pairs, parse_constant=constant)
|
||||
|
||||
|
||||
def inventory(archive, expected):
|
||||
names = archive.namelist()
|
||||
need(len(names) == len(set(names)) and set(names) == set(expected), "exact ZIP membership")
|
||||
for entry in archive.infolist():
|
||||
need(safe(entry.filename) and not entry.is_dir(), "unsafe ZIP member: " + entry.filename)
|
||||
need(not stat.S_ISLNK(entry.external_attr >> 16), "ZIP symlink: " + entry.filename)
|
||||
need(valid_pin(expected[entry.filename]), "invalid member pin: " + entry.filename)
|
||||
need(entry.file_size == expected[entry.filename]["bytes"], "ZIP recorded size: " + entry.filename)
|
||||
|
||||
|
||||
def ordered_times(*values):
|
||||
times = [datetime.fromisoformat(value) for value in values]
|
||||
return all(value.utcoffset() is not None for value in times) and times == sorted(times)
|
||||
|
||||
|
||||
def verify_data(manifest, read):
|
||||
"""Shared read-only verifier for packaged bytes or prepare's in-memory payload."""
|
||||
need(manifest["schema"] == 1 and manifest["kind"] == "allocation-multiselect-cargo-gates", "manifest schema")
|
||||
runs, logical, stored = manifest["runs"], manifest["logicalFiles"], manifest["members"]
|
||||
helpers = manifest["captureHelpers"]
|
||||
need(isinstance(helpers, dict) and set(helpers) == {"gate.py", "source-proof.py"}, "capture helper names")
|
||||
need(all(isinstance(name, str) and re.fullmatch(r"helpers/[0-9a-f]{64}\.py", name)
|
||||
for name in helpers.values()), "capture helper mapping")
|
||||
need(isinstance(runs, dict) and bool(runs) and all(run_name(run) for run in runs), "explicit run inventory")
|
||||
need(all(safe(name) for name in logical) and all(safe(name) for name in stored), "unsafe manifest path")
|
||||
need(set(logical.values()) == set(stored), "unreferenced or absent stored members")
|
||||
for name, expected in stored.items():
|
||||
need(valid_pin(expected) and pin(read(name)) == expected, "stored member hash: " + name)
|
||||
expected_logical = {"cargo/" + run + "/" + name for run in runs for name in RAW_FILES}
|
||||
expected_logical.update(spec["helper"] for spec in runs.values())
|
||||
expected_logical.update(helpers.values())
|
||||
for run, spec in runs.items():
|
||||
if "sourceProof" in spec:
|
||||
proof_spec = spec["sourceProof"]
|
||||
need(set(proof_spec) == {"commit", "pin", "comparator"}, run + ": exact source proof spec")
|
||||
need(isinstance(proof_spec["commit"], str) and re.fullmatch(r"[0-9a-f]{40}", proof_spec["commit"]), run + ": named full source commit")
|
||||
need(valid_pin(proof_spec["pin"]), run + ": source proof pin")
|
||||
need(isinstance(proof_spec["comparator"], str) and re.fullmatch(r"comparators/[0-9a-f]{64}\.py", proof_spec["comparator"]), run + ": comparator path")
|
||||
expected_logical.update({"cargo/" + run + "/source-proof.json", proof_spec["comparator"]})
|
||||
need(set(logical) == expected_logical, "exact logical raw/helper inventory")
|
||||
for name, destination in logical.items():
|
||||
if name.startswith("cargo/") and name.rsplit("/", 1)[1] in {"inputs.json", "inputs.zip"}:
|
||||
expected = "capsules/" + stored[destination]["sha256"] + PurePosixPath(name).suffix
|
||||
need(destination == expected, "input capsule mapping: " + name)
|
||||
else:
|
||||
need(destination == name, "only input maps/archives may be deduplicated: " + name)
|
||||
def raw(name):
|
||||
return read(logical[name])
|
||||
for name, helper in helpers.items():
|
||||
need(helper == "helpers/" + pin(raw(helper))["sha256"] + ".py", "named helper hash: " + name)
|
||||
seen_capsules = set()
|
||||
for run, spec in runs.items():
|
||||
prefix = "cargo/" + run + "/"
|
||||
start = parsed(raw(prefix + "started.json"))
|
||||
process = parsed(raw(prefix + "process.json"))
|
||||
result = parsed(raw(prefix + "result.json"))
|
||||
required_start = {"start", "command", "cwd", "head", "scope", "inputs", "archive",
|
||||
"inputCount", "environment", "helper", "cargo", "rustc"}
|
||||
need(required_start <= start.keys(), run + ": incomplete start receipt")
|
||||
need(all(result.get(key) == value for key, value in start.items()), run + ": start/result relationship")
|
||||
command = result["command"]
|
||||
need(isinstance(command, list) and command and command[0] == "cargo"
|
||||
and all(isinstance(arg, str) for arg in command), run + ": Cargo command")
|
||||
need(command == process["command"] == spec["command"], run + ": command relationship")
|
||||
need(result["head"] == spec["head"] and re.fullmatch(r"(?:[0-9a-f]{40}|[0-9a-f]{64})", result["head"]), run + ": HEAD")
|
||||
need(type(result["exitCode"]) is int and result["exitCode"] == spec["exitCode"], run + ": recorded exit")
|
||||
need(result["inputsUnchanged"] is True, run + ": changed inputs refused")
|
||||
need(type(result["seconds"]) in (int, float) and math.isfinite(result["seconds"])
|
||||
and result["seconds"] >= 0, run + ": duration")
|
||||
need(type(process["pid"]) is int and process["pid"] > 0, run + ": process identity")
|
||||
need(ordered_times(start["start"], process["observed"], result["finish"]), run + ": completed timestamp order")
|
||||
for field, filename in [("inputs", "inputs.json"), ("archive", "inputs.zip"), ("stdout", "stdout.log"), ("stderr", "stderr.log")]:
|
||||
need(result[field] == pin(raw(prefix + filename)), run + ": " + field + " pin")
|
||||
need(valid_pin(result["helper"]) and result["helper"] == pin(raw(spec["helper"])), run + ": helper pin")
|
||||
need(spec["helper"] == "helpers/" + result["helper"]["sha256"] + ".py", run + ": helper mapping")
|
||||
inputs = parsed(raw(prefix + "inputs.json"))
|
||||
need(isinstance(inputs, dict) and all(safe(name) for name in inputs), run + ": safe input inventory")
|
||||
need(type(result["inputCount"]) is int and len(inputs) == result["inputCount"] == spec["inputCount"], run + ": input counts")
|
||||
if "sourceProof" in spec:
|
||||
proof_spec = spec["sourceProof"]
|
||||
proof_bytes = raw(prefix + "source-proof.json")
|
||||
proof = parsed(proof_bytes)
|
||||
need(pin(proof_bytes) == proof_spec["pin"], run + ": source proof pinned bytes")
|
||||
need(proof["run"] == run and proof["commit"] == proof_spec["commit"], run + ": proof run/commit identity")
|
||||
need(proof["status"] == "PASS exact captured input inventory and Git blob bytes", run + ": source proof status")
|
||||
need(proof["inputCount"] == len(inputs) and proof["inputMap"] == result["inputs"], run + ": proof input relationship")
|
||||
need(proof["result"] == pin(raw(prefix + "result.json")), run + ": proof result relationship")
|
||||
need(ordered_times(result["finish"], proof["verified"]), run + ": proof time after closed gate")
|
||||
comparator = proof_spec["comparator"]
|
||||
need(valid_pin(proof["comparator"]) and pin(raw(comparator)) == proof["comparator"], run + ": comparator bytes")
|
||||
need(comparator == "comparators/" + proof["comparator"]["sha256"] + ".py", run + ": comparator identity")
|
||||
need(sum(name.startswith("crates/vendor/iced_widget/") for name in inputs) == 71, run + ": vendor count")
|
||||
capsule = (logical[prefix + "inputs.json"], logical[prefix + "inputs.zip"])
|
||||
if capsule not in seen_capsules:
|
||||
with zipfile.ZipFile(io.BytesIO(raw(prefix + "inputs.zip"))) as source:
|
||||
inventory(source, inputs)
|
||||
for name, expected in inputs.items():
|
||||
need(pin(source.read(name)) == expected, run + ": source hash " + name)
|
||||
seen_capsules.add(capsule)
|
||||
artifacts = []
|
||||
for line in raw(prefix + "stdout.log").decode("utf-8", errors="replace").splitlines():
|
||||
try:
|
||||
value = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
if isinstance(value, dict) and value.get("reason") == "compiler-artifact" and value.get("executable"):
|
||||
artifacts.append(value)
|
||||
need(isinstance(result["artifacts"], list), run + ": artifact records")
|
||||
need(artifacts == [record["cargo"] for record in result["artifacts"]], run + ": Cargo JSON artifact relationship")
|
||||
for record in result["artifacts"]:
|
||||
need(set(record) == {"cargo", "readback"}
|
||||
and (record["readback"] is None or valid_pin(record["readback"])), run + ": artifact readback pin")
|
||||
print(run, "recorded exit", result["exitCode"], "inputs", len(inputs), "executable records", len(artifacts))
|
||||
return {"runs": len(runs), "recordedFailures": sum(spec["exitCode"] != 0 for spec in runs.values()),
|
||||
"logicalFiles": len(logical), "storedMembers": len(stored), "sourceCapsulePairs": len(seen_capsules),
|
||||
"captureHelpers": helpers, "sourceProofs": sum("sourceProof" in spec for spec in runs.values())}
|
||||
|
||||
|
||||
def verify_package(root):
|
||||
files = parsed((root / "files.json").read_bytes())
|
||||
need(set(files) == OUTER_FILES, "outer file inventory")
|
||||
for name, expected in files.items():
|
||||
need(valid_pin(expected) and pin((root / name).read_bytes()) == expected, "outer hash: " + name)
|
||||
manifest = parsed((root / "manifest.json").read_bytes())
|
||||
with zipfile.ZipFile(root / "evidence.zip") as archive:
|
||||
inventory(archive, manifest["members"])
|
||||
return verify_data(manifest, archive.read)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("package", nargs="?", type=Path, default=Path(__file__).resolve().parent)
|
||||
args = parser.parse_args()
|
||||
print("PASS offline consistency:", verify_package(args.package))
|
||||
print("Historical receipts only; no source/binary execution or native acceptance claim.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,16 @@
|
||||
# Assignment review archive
|
||||
|
||||
Exact historical design, fixtures and independent review notes, with original
|
||||
`.local` paths preserved inside the archive. Their relative links refer to that
|
||||
original checkout context; extract only into a separate scratch directory if
|
||||
needed. Do not interpret historical plans or source-derived predictions as
|
||||
executed results. The review addendum inspects the recorded 84-test gate without
|
||||
claiming an independent rerun. The App adapter plan is design only.
|
||||
|
||||
The newline diagnosis records why three initial exact source comparisons
|
||||
refused. Their captures were retained and canonical-byte gates rerun; historical
|
||||
receipts were not rewritten. Current accepted facts and limitations are in the
|
||||
[planner report](../../allocation-assignment-planner-20260923.md).
|
||||
|
||||
`files.json` pins this archive/index/readme; `members.json` pins every exact ZIP
|
||||
member. Neither internal hashes nor independent review replace runtime evidence.
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"reviews.zip": {
|
||||
"bytes": 26141,
|
||||
"sha256": "35a5faaf9f60eaa88d8c97f8a34dceac7a2cebf356ac6f69ec0e794cec258101"
|
||||
},
|
||||
"members.json": {
|
||||
"bytes": 840,
|
||||
"sha256": "3b1ce35c9b65b241b80367c90adc0ffbc65155d9cea8872f98e58901b2d52513"
|
||||
},
|
||||
"README.md": {
|
||||
"bytes": 952,
|
||||
"sha256": "a518a056c78b982c45f8d9a2098729f27df8f1702132c0e4cc6c555c603dbd22"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
".local/allocation-group-design/assignment-plan.md": {
|
||||
"bytes": 16268,
|
||||
"sha256": "000b80e13845a1532e083281ee94486964306af0ce7fb27fee3a9eb2074f2405"
|
||||
},
|
||||
".local/allocation-group-design/assignment-fixtures.md": {
|
||||
"bytes": 11563,
|
||||
"sha256": "507e5d33745ffb65f096a8c5640f6e22d61ecb8701eb13769bfe538069e71ecc"
|
||||
},
|
||||
".local/allocation-group-design/assignment-review.md": {
|
||||
"bytes": 11510,
|
||||
"sha256": "f1c36cdba4a6f74770d541d9529d7f116473b2bc78bc2b2902c80f387eba82d1"
|
||||
},
|
||||
".local/allocation-group-design/app-adapter-plan.md": {
|
||||
"bytes": 21648,
|
||||
"sha256": "316633ae45d8f9836212d37e64639251cdb2fd96cda522d0a979d9bc81782cf7"
|
||||
},
|
||||
".local/allocation-evidence-tools/assignment-newline-diagnosis.json": {
|
||||
"bytes": 622,
|
||||
"sha256": "60631de3a45d0cb6c4108e7aaaf170b80e43e00e076674aabf379d05ee77a62a"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user