Preserve combined peer strict lint and scoped core gate evidence

This commit is contained in:
2026-09-23 04:52:43 -07:00
parent f9c5165cb9
commit 2e7c39965c
8 changed files with 837 additions and 0 deletions
+12
View File
@@ -115,6 +115,18 @@ failures and corrections. Earlier authoring and allocation checkpoints remain in
## Isolated contributions and material limitations
Combined peer candidate **f82e29d6b8ed2b5fd23ac806675d3eafe851d104**, published on
`codex/peer-union-956atf-20260923`, composes current Text/Tab with saved Scenario,
final inspector actions, attachments, State bends and the transition footer.
Strict Windows workspace/all-target lint passes on 760 unchanged inputs after
repairing an example constructor and restoring the exact peer compile-time
fixture. Earlier combined core checks pass 27 Scenario and 22 source-default
cases at source-identical crate revision015273a. The
[partial gate archive](experiments/peer-union-windows-20260923/README.md) retains
the original seven Scenario failures, both lint failures, source boundaries and
helper/clock capture limits. Full workspace, desktop/native, public format and
release acceptance are not established; accepted root production remains4ffff0d.
Analysis/core source checkpoint **a2a28f8d23a46ba1696b6a8410d4d3b5c1808f49**,
publication branch `codex/analysis-core-956atf-20260911`, is not integrated into
production. Its private staged typed parser/lowerer has142 listed tests,
@@ -0,0 +1,6 @@
evidence.zip -text
manifest.json -text
verify.py -text
README.md -text
negative-controls-original.py -text
negative-controls-result.json -text whitespace=cr-at-eol
@@ -0,0 +1,99 @@
# Combined peer candidate — partial Windows verification
This checkpoint records completed gates through strict workspace lint at source
`f82e29d6b8ed2b5fd23ac806675d3eafe851d104`, published and ref-verified on
`codex/peer-union-956atf-20260923`. It is not full workspace, desktop/native,
public source8 or release acceptance. The live integration task is Gitea issue27;
the source provenance and reviewed seams are in
`f82e29d:harness/peer-union-20260923.md`.
## What ran
Windows Rust/Cargo 1.98.1 gnullvm, LLVM-MinGW 20260908 UCRT, offline locked
dependencies, one compiler at a time. Each receipt records command, environment,
source HEAD before/after, input hashes, original log and test executable hashes.
The final strict gate uses `CARGO_BUILD_JOBS=1` and `CARGO_INCREMENTAL=0`.
| Source | Gate | Observed result | Captured inputs |
| --- | --- | --- | --- |
| `0b61771` | Core inventory / Scenario layout | 129 listed; 20 pass / 7 fail | 742 |
| `2a0579d` | Core inventory / Scenario layout / source defaults | 129 listed; 27 / 22 pass | 742 |
| `2a0579d` | Default omission integration target | 11 listed / 11 pass | 742 |
| `015273a` | Combined core inventory / Scenario layout / source defaults | 129 listed; 27 / 22 pass | 758 |
| `015273a` | Strict workspace all-target Clippy | Failed: example Diagram constructor missing layout | 758 |
| `c489748` | Strict workspace all-target Clippy | Failed: missing attachment compile-time fixture | 758 |
| `f82e29d` | Strict workspace all-target Clippy | Exit 0, no diagnostics | 760 |
These are 13 completed gate receipts. Passing scoped runs are matched to their
actual same-source, same-executable inventories, with exact selected membership
and outcomes. No historical counts are added into a combined total. The first
seven failures are all source-lifecycle cases: parser field admission omitted
`layout`. Fix `2a0579d` (combined cherry-pick `846cae8`) admits the field without
adding synthetic layout-null editor defaults. Original failing logs remain.
The example fix `c4897485b7058570a563707c4f5840f500a6c265` adds only
`layout: None` to `examples/release1/model.rs`. The fixture restoration
`f82e29d6b8ed2b5fd23ac806675d3eafe851d104` imports exact peer `b8685416` bytes at
`harness/experiments/edge-attachments-20260922/native-fixture.arcadia` (Git blob
`f6419892143c9c08c22780de6060a7315be17930`). Neither changes crate implementation.
An include-file audit also identified the existing textual-authoring
`alarm-response.arcadia` fixture outside the previous manifest roots. The final
760-input scope explicitly includes both compile-time fixtures; historical
742/758-input receipts are not retrospectively expanded.
## Reproduce the evidence audit
Fetch the source commits named in `manifest.json`, then run from any directory:
```powershell
python path/to/this/folder/verify.py --repo path/to/ARCADIA-Studio
```
The standard-library verifier reads the ZIP in memory without extraction or
executing archived code. It checks every payload hash, receipt/log/manifest
binding, frozen source, unchanged inputs, recorded command/exit, exact test
membership/outcomes (including the seven failures), helper hashes and 3,760
distinct source-commit/input pairs against Git blobs. Executable bytes are not
distributed in this archive; their recorded identity binds each scoped run to
its listing but is not a substitute for rerunning the build.
The positive audit passes. Four falsification trials reject a corrupt payload,
wrong outcome count, removed selected test outcome (with renewed wrapper hashes),
and forged source input hash (also with renewed wrappers). The original local
driver and hash-bound result are retained beside this report. The driver uses
the original workspace paths; it is a record of these trials, not a second
portable entrypoint.
To repeat the final strict gate from the identified source with the documented
Windows toolchain and cached dependencies:
```powershell
cargo clippy --locked --offline --workspace --all-targets -- -D warnings
```
Focused test commands, filters and tool environment are preserved verbatim in
the receipts. The archived launchers document capture behavior; they reference
the original local layout and are evidence rather than portable build setup.
## Capture limits and pending acceptance
- Earlier helper `596dd821...` was reconstructed by reversing the known scope
extension and package selection change; its exact hash matches the historical
receipts. Helper `ddb37f5c...` was copied after its last run. Neither is claimed
to be a launch-time copy. `launchers/capture-provenance.json` preserves this.
Later gates retain immutable hash-keyed helper bytes before launch.
- The final strict receipt's raw UTC span is 08:29:41–11:35:25, while Cargo reports
5m42s. The clock discontinuity is retained; that span is not a duration claim.
- The input inventory is a declared source scope, not a complete compiler file
access trace. The discovered fixture omission and subsequent repair remain
explicit. All recorded included inputs match their identified Git blobs.
- Desktop discovery/execution, remaining integration targets, full workspace
tests, matching GUI build and a combined native save/reopen workflow remain
pending at this checkpoint. No running gate is included in the archive.
- Public format adoption and normative Scenario language/API/OpenAPI coverage
remain unresolved. The private analysis parser is a separate branch and is
not part of this combined candidate. Linux remains user-deferred.
The source reviews retain their original pins and pre-execution dispositions.
Passing these gates does not retroactively make a source review a runtime or
native observation. Existing peer native evidence remains tied to its own source.
@@ -0,0 +1,512 @@
{
"archive_bytes": 580378,
"archive_sha256": "4f4ef08a718296b7991908bfe7fd9ac02c0187eaeace0f2bdb77102d49eb9032",
"payloads": {
"gates/combined-core-defaults-1.admission.json": {
"bytes": 2386,
"sha256": "65bcad22c89ad57288d9dc350ecbfa8ee4eeb39cb9baa61255dc6cbac8872db5"
},
"gates/combined-core-defaults-1.inputs.json": {
"bytes": 140816,
"sha256": "418819b2c6e3032839cb70a8f8f49c7e8a7175a63be7463198f5be01be151e7f"
},
"gates/combined-core-defaults-1.log": {
"bytes": 2402,
"sha256": "ddd5f659e3dd728af38e317b5e893502cd43dc8e9520ce2be31ecf32f3243dd4"
},
"gates/combined-core-defaults-1.result.json": {
"bytes": 1732,
"sha256": "47768d9f82ce95596dc7ebc2517ab7120dace3a97f8153b393f267e70dc1c160"
},
"gates/combined-core-list-1.inputs.json": {
"bytes": 140816,
"sha256": "418819b2c6e3032839cb70a8f8f49c7e8a7175a63be7463198f5be01be151e7f"
},
"gates/combined-core-list-1.log": {
"bytes": 13051,
"sha256": "fd260e2847b22d569569828874849019579a06c66cea1197d8210ff1b2920030"
},
"gates/combined-core-list-1.result.json": {
"bytes": 14548,
"sha256": "a277ffe7c07c8897bb3d53d526e1d16d2b419f5d98037b8701d64b3d6f1cea6a"
},
"gates/combined-core-scenario-1.admission.json": {
"bytes": 3369,
"sha256": "b9669acff9abd0f129059aada8737c4c8f4ccc1ad7c92a5df10caa8110059ca2"
},
"gates/combined-core-scenario-1.inputs.json": {
"bytes": 140816,
"sha256": "418819b2c6e3032839cb70a8f8f49c7e8a7175a63be7463198f5be01be151e7f"
},
"gates/combined-core-scenario-1.log": {
"bytes": 3405,
"sha256": "1204984d0c27cfb2d4ebd950dd22a44b7d07e8244a486e034ae270050d86f640"
},
"gates/combined-core-scenario-1.result.json": {
"bytes": 1732,
"sha256": "bfe54a0f93444247a87ecdd0ffab722dec423daeb7f3e23bff9b4e92d00974ec"
},
"gates/combined-strict-1.inputs.json": {
"bytes": 140816,
"sha256": "418819b2c6e3032839cb70a8f8f49c7e8a7175a63be7463198f5be01be151e7f"
},
"gates/combined-strict-1.log": {
"bytes": 1083,
"sha256": "5e02d1cb074aad07aef432ec3c03628557152d4a9fb2b8dfb345515e0bdb75ee"
},
"gates/combined-strict-1.result.json": {
"bytes": 1463,
"sha256": "a76b065c39e89a88f23066d5a612c44561f36b648297058e53ef8319e0ccadaf"
},
"gates/combined-strict-2.inputs.json": {
"bytes": 140816,
"sha256": "2fde588400f967f7c5cef510cc38261fd1e5f46cba6e14915be83c9efe3a9654"
},
"gates/combined-strict-2.log": {
"bytes": 633,
"sha256": "c14924f72d19daa9cc50b1a73049bba93220354ab89da6c395071e7bc588adbf"
},
"gates/combined-strict-2.result.json": {
"bytes": 1652,
"sha256": "2fa1e8323385f45a796a1e07519b19980448e4cda065d0e92c0bfb795ca464ef"
},
"gates/combined-strict-3.inputs.json": {
"bytes": 141223,
"sha256": "91d917e0c329f74223eef11f02b25ecbd2b69ce7cc6482eede0a65548fd95255"
},
"gates/combined-strict-3.log": {
"bytes": 265,
"sha256": "b94556ab2b7c78e5375750201716449b58beb33782d470778d6eaf5789b9e909"
},
"gates/combined-strict-3.result.json": {
"bytes": 1650,
"sha256": "7e255308cc8f4fd077aada293d638badeef67faa1b7b56ecf597d2241193499c"
},
"gates/core-defaults-2.admission.json": {
"bytes": 2368,
"sha256": "750dc34cbfbc0f8ff2392f97de5161bf4216aa50a1c09c12b3ee5587c870d162"
},
"gates/core-defaults-2.inputs.json": {
"bytes": 137890,
"sha256": "8478620ab2deeef2625b9b3a485e2a2d39c9a958cbc8bbbcd1466e977aac57b7"
},
"gates/core-defaults-2.log": {
"bytes": 2402,
"sha256": "21c020d7a2131502c67c94db8781bb7905066661e6ee468112d138c1272ef026"
},
"gates/core-defaults-2.result.json": {
"bytes": 1723,
"sha256": "45f368f909bd94a0604cb51a7c13b752a72167d3ab779474ab87d7264ad9cd1d"
},
"gates/core-list-1.inputs.json": {
"bytes": 137890,
"sha256": "0bb00e62be1453a0a7cda619eae38d7014b95484f846e2242d36e940f9720a46"
},
"gates/core-list-1.log": {
"bytes": 13051,
"sha256": "0441f20249b8aa3a72a37e32fc692c4a132fc22847f4cdc5a4c5b34267f18c7d"
},
"gates/core-list-1.result.json": {
"bytes": 14539,
"sha256": "0a3697f101aeeb518381a885256df329471701fd5ab14a127324fe5e8e870e5a"
},
"gates/core-list-2.inputs.json": {
"bytes": 137890,
"sha256": "8478620ab2deeef2625b9b3a485e2a2d39c9a958cbc8bbbcd1466e977aac57b7"
},
"gates/core-list-2.log": {
"bytes": 13051,
"sha256": "74c0eebab60b4c832f402e5e7ddf9d71660f21153beb605b11b5c7baad2885de"
},
"gates/core-list-2.result.json": {
"bytes": 14539,
"sha256": "e12415ae2e5cf186990c977c933de7a35e7c7e9bf88e94980f089ef808d6c405"
},
"gates/core-scenario-1.inputs.json": {
"bytes": 137890,
"sha256": "0bb00e62be1453a0a7cda619eae38d7014b95484f846e2242d36e940f9720a46"
},
"gates/core-scenario-1.log": {
"bytes": 9188,
"sha256": "f91242c9be5b54163bb6b6f91d6057d9f525e8b21554c1e4ee782f67dc7eb3df"
},
"gates/core-scenario-1.result.json": {
"bytes": 1725,
"sha256": "60801831493c6dd1b714b3ed34b10a51b17e74e18489fa9270c4da8492d429d3"
},
"gates/core-scenario-2.admission.json": {
"bytes": 3351,
"sha256": "99c7636e643fb751f9655538f7320bd2f29e545127add3a7d60bf3bedb08f66c"
},
"gates/core-scenario-2.inputs.json": {
"bytes": 137890,
"sha256": "8478620ab2deeef2625b9b3a485e2a2d39c9a958cbc8bbbcd1466e977aac57b7"
},
"gates/core-scenario-2.log": {
"bytes": 3405,
"sha256": "3c9431f0eb0e156f227302012a4fd563378100615b192a84dd2ceedb41773d40"
},
"gates/core-scenario-2.result.json": {
"bytes": 1723,
"sha256": "c325748e5bf63ec4715f11e42135b20c9676884d9d310970dbde684ae52f183d"
},
"gates/defaults-list-2.inputs.json": {
"bytes": 137890,
"sha256": "8478620ab2deeef2625b9b3a485e2a2d39c9a958cbc8bbbcd1466e977aac57b7"
},
"gates/defaults-list-2.log": {
"bytes": 1049,
"sha256": "26f07434fce51f6607aef43832345c0be7dd28c173d7efccae8b0e981d99ea09"
},
"gates/defaults-list-2.result.json": {
"bytes": 2447,
"sha256": "1f7617e6cea7e89be6db15b59f66a18d5f5f9b1764a4e947a4294204915b6057"
},
"gates/defaults-run-2.admission.json": {
"bytes": 1080,
"sha256": "4b9b7924b93fedce7dbea9fac55bfc9a3c51cdb8237192c13f4733eb1b6e0326"
},
"gates/defaults-run-2.inputs.json": {
"bytes": 137890,
"sha256": "8478620ab2deeef2625b9b3a485e2a2d39c9a958cbc8bbbcd1466e977aac57b7"
},
"gates/defaults-run-2.log": {
"bytes": 1102,
"sha256": "fd14010517c7af06147efac854d888272021590fa49e7510ab510eb16b31417e"
},
"gates/defaults-run-2.result.json": {
"bytes": 1748,
"sha256": "e529b4bcd8aecbcbb1100c90a91777ea306b1813bf180d8ad3647d706d6e912d"
},
"launchers/0b14e2e80e4c02ecd31f6dfa5fdfaf1594a6bc3ac319530eca1a3c81505a478e.py": {
"bytes": 7475,
"sha256": "0b14e2e80e4c02ecd31f6dfa5fdfaf1594a6bc3ac319530eca1a3c81505a478e"
},
"launchers/596dd8212886096eb629cc690efa788ed72a1c2b44e40f8a0c2b691a1c13f7b5.py": {
"bytes": 6532,
"sha256": "596dd8212886096eb629cc690efa788ed72a1c2b44e40f8a0c2b691a1c13f7b5"
},
"launchers/capture-provenance.json": {
"bytes": 966,
"sha256": "a13d0b82f3b78604fa2a086cb16a7ae7df05592ed4dc3d4e0d0e6dd06d341936"
},
"launchers/ddb37f5c1ac03403b1f4d01fd04e1207e6f718c5b02401b885d78db7e1a89b20.py": {
"bytes": 6802,
"sha256": "ddb37f5c1ac03403b1f4d01fd04e1207e6f718c5b02401b885d78db7e1a89b20"
},
"launchers/df812935028c17145a72650c5e083c8609398e903139907d5d76db817b1524f6.py": {
"bytes": 7314,
"sha256": "df812935028c17145a72650c5e083c8609398e903139907d5d76db817b1524f6"
},
"reviews/composition-review.md": {
"bytes": 13847,
"sha256": "cb2391e8d4d84690b2852cca83f8c14aceb155ad363a257295063038a3e68d50"
},
"tools/admit-scenario-union-gate.py": {
"bytes": 2887,
"sha256": "15b248da53caadc3961650d5855d557dd41e72f35f055c323059684faf138816"
}
},
"gates": [
{
"source": "015273ac8a7ce97d4aee678d653256abde222695",
"exit": 0,
"command": [
"cargo",
"test",
"--locked",
"--offline",
"-p",
"oa-core",
"--lib",
"source_defaults",
"--",
"--test-threads=1"
],
"mode": "test",
"scope": "core",
"name": "combined-core-defaults-1",
"inputs": 758,
"listing": "combined-core-list-1",
"outcomes": [
22,
0,
0
],
"ignored": []
},
{
"source": "015273ac8a7ce97d4aee678d653256abde222695",
"exit": 0,
"command": [
"cargo",
"test",
"--locked",
"--offline",
"-p",
"oa-core",
"--lib",
"--",
"--list"
],
"mode": "list",
"scope": "core",
"name": "combined-core-list-1",
"inputs": 758,
"listed": 129
},
{
"source": "015273ac8a7ce97d4aee678d653256abde222695",
"exit": 0,
"command": [
"cargo",
"test",
"--locked",
"--offline",
"-p",
"oa-core",
"--lib",
"scenario_layout",
"--",
"--test-threads=1"
],
"mode": "test",
"scope": "core",
"name": "combined-core-scenario-1",
"inputs": 758,
"listing": "combined-core-list-1",
"outcomes": [
27,
0,
0
],
"ignored": []
},
{
"source": "015273ac8a7ce97d4aee678d653256abde222695",
"exit": 101,
"command": [
"cargo",
"clippy",
"--locked",
"--offline",
"--workspace",
"--all-targets",
"--",
"-D",
"warnings"
],
"mode": "clippy",
"scope": "workspace",
"name": "combined-strict-1",
"inputs": 758
},
{
"source": "c4897485b7058570a563707c4f5840f500a6c265",
"exit": 101,
"command": [
"cargo",
"clippy",
"--locked",
"--offline",
"--workspace",
"--all-targets",
"--",
"-D",
"warnings"
],
"mode": "clippy",
"scope": "workspace",
"name": "combined-strict-2",
"inputs": 758
},
{
"source": "f82e29d6b8ed2b5fd23ac806675d3eafe851d104",
"exit": 0,
"command": [
"cargo",
"clippy",
"--locked",
"--offline",
"--workspace",
"--all-targets",
"--",
"-D",
"warnings"
],
"mode": "clippy",
"scope": "workspace",
"name": "combined-strict-3",
"inputs": 760
},
{
"source": "2a0579daafb89994730284c108f460782e5e6650",
"exit": 0,
"command": [
"cargo",
"test",
"--locked",
"--offline",
"-p",
"oa-core",
"--lib",
"source_defaults",
"--",
"--test-threads=1"
],
"mode": "test",
"scope": "core",
"name": "core-defaults-2",
"inputs": 742,
"listing": "core-list-2",
"outcomes": [
22,
0,
0
],
"ignored": []
},
{
"source": "0b61771d079cae4a513958fad04e6c3e785d458f",
"exit": 0,
"command": [
"cargo",
"test",
"--locked",
"--offline",
"-p",
"oa-core",
"--lib",
"--",
"--list"
],
"mode": "list",
"scope": "core",
"name": "core-list-1",
"inputs": 742,
"listed": 129
},
{
"source": "2a0579daafb89994730284c108f460782e5e6650",
"exit": 0,
"command": [
"cargo",
"test",
"--locked",
"--offline",
"-p",
"oa-core",
"--lib",
"--",
"--list"
],
"mode": "list",
"scope": "core",
"name": "core-list-2",
"inputs": 742,
"listed": 129
},
{
"source": "0b61771d079cae4a513958fad04e6c3e785d458f",
"exit": 101,
"command": [
"cargo",
"test",
"--locked",
"--offline",
"-p",
"oa-core",
"--lib",
"scenario_layout",
"--",
"--test-threads=1"
],
"mode": "test",
"scope": "core",
"name": "core-scenario-1",
"inputs": 742,
"listing": "core-list-1",
"outcomes": [
20,
7,
0
],
"ignored": []
},
{
"source": "2a0579daafb89994730284c108f460782e5e6650",
"exit": 0,
"command": [
"cargo",
"test",
"--locked",
"--offline",
"-p",
"oa-core",
"--lib",
"scenario_layout",
"--",
"--test-threads=1"
],
"mode": "test",
"scope": "core",
"name": "core-scenario-2",
"inputs": 742,
"listing": "core-list-2",
"outcomes": [
27,
0,
0
],
"ignored": []
},
{
"source": "2a0579daafb89994730284c108f460782e5e6650",
"exit": 0,
"command": [
"cargo",
"test",
"--locked",
"--offline",
"-p",
"oa-core",
"--test",
"default_omission_preservation",
"--",
"--list"
],
"mode": "list",
"scope": "defaults",
"name": "defaults-list-2",
"inputs": 742,
"listed": 11
},
{
"source": "2a0579daafb89994730284c108f460782e5e6650",
"exit": 0,
"command": [
"cargo",
"test",
"--locked",
"--offline",
"-p",
"oa-core",
"--test",
"default_omission_preservation",
"--",
"--test-threads=1"
],
"mode": "test",
"scope": "defaults",
"name": "defaults-run-2",
"inputs": 742,
"listing": "defaults-list-2",
"outcomes": [
11,
0,
0
],
"ignored": []
}
]
}
@@ -0,0 +1,73 @@
from pathlib import Path
import copy
import hashlib
import importlib.util
import json
import zipfile
root = Path(__file__).resolve().parent.parent
original = root / 'harness/experiments/peer-union-windows-20260923'
scratch = root / '.local/peer-union-verifier-controls-20260923'
scratch.mkdir(exist_ok=True)
spec = importlib.util.spec_from_file_location('peer_verify', original / 'verify.py')
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
manifest = json.loads((original / 'manifest.json').read_bytes())
with zipfile.ZipFile(original / 'evidence.zip') as z:
data = {name: z.read(name) for name in z.namelist()}
def sha(raw):
return hashlib.sha256(raw).hexdigest()
def refresh(payloads, claim, name, raw):
payloads[name] = raw
claim['payloads'][name] = {'bytes': len(raw), 'sha256': sha(raw)}
reports = []
for case in ('payload-corruption', 'outcome-count', 'missing-selected-outcome', 'git-input-binding'):
payloads, claim = dict(data), copy.deepcopy(manifest)
folder = scratch / case
folder.mkdir(exist_ok=True)
if case == 'payload-corruption':
payloads['gates/combined-strict-3.log'] += b'corruption'
elif case == 'outcome-count':
next(g for g in claim['gates'] if g['name'] == 'combined-core-scenario-1')['outcomes'] = [26, 0, 0]
elif case == 'missing-selected-outcome':
name = 'gates/combined-core-scenario-1.log'
lines = payloads[name].splitlines(keepends=True)
removed = next(i for i, line in enumerate(lines) if line.startswith(b'test ') and b' ... ok' in line)
del lines[removed]
changed = b''.join(lines)
refresh(payloads, claim, name, changed)
receipt_name = 'gates/combined-core-scenario-1.result.json'
receipt = json.loads(payloads[receipt_name])
receipt['log_sha256'] = sha(changed)
refresh(payloads, claim, receipt_name, json.dumps(receipt).encode())
else:
input_name = 'gates/combined-strict-3.inputs.json'
inputs = json.loads(payloads[input_name])
inputs['inputs'][0]['sha256'] = '0' * 64
changed = json.dumps(inputs).encode()
refresh(payloads, claim, input_name, changed)
receipt_name = 'gates/combined-strict-3.result.json'
receipt = json.loads(payloads[receipt_name])
receipt['inputs_sha256'] = sha(changed)
refresh(payloads, claim, receipt_name, json.dumps(receipt).encode())
with zipfile.ZipFile(folder / 'evidence.zip', 'w', compression=zipfile.ZIP_DEFLATED) as z:
for name, raw in payloads.items():
z.writestr(name, raw)
archive = (folder / 'evidence.zip').read_bytes()
claim['archive_bytes'], claim['archive_sha256'] = len(archive), sha(archive)
(folder / 'manifest.json').write_text(json.dumps(claim), encoding='utf-8')
try:
module.verify(folder, root)
except AssertionError:
reports.append({'case': case, 'result': 'REJECTED_AS_EXPECTED'})
else:
raise AssertionError('Corrupted evidence accepted: ' + case)
report = {'source_archive_sha256': manifest['archive_sha256'], 'verifier_sha256': sha((original / 'verify.py').read_bytes()), 'controls': reports}
(scratch / 'result.json').write_text(json.dumps(report, indent=2), encoding='utf-8')
print(json.dumps(report, indent=2))
@@ -0,0 +1,22 @@
{
"source_archive_sha256": "4f4ef08a718296b7991908bfe7fd9ac02c0187eaeace0f2bdb77102d49eb9032",
"verifier_sha256": "d0d85cef3beaa41b1e03110d566043f1dee91d82d27fe6075f776a612962cab6",
"controls": [
{
"case": "payload-corruption",
"result": "REJECTED_AS_EXPECTED"
},
{
"case": "outcome-count",
"result": "REJECTED_AS_EXPECTED"
},
{
"case": "missing-selected-outcome",
"result": "REJECTED_AS_EXPECTED"
},
{
"case": "git-input-binding",
"result": "REJECTED_AS_EXPECTED"
}
]
}
@@ -0,0 +1,113 @@
"""Audit the accompanying frozen-source gate archive without running its commands."""
from pathlib import Path
import argparse
import hashlib
import json
import re
import subprocess
import zipfile
def sha(raw):
return hashlib.sha256(raw).hexdigest()
def verify(folder, repo):
manifest = json.loads((folder / 'manifest.json').read_bytes())
archive = (folder / 'evidence.zip').read_bytes()
assert len(archive) == manifest['archive_bytes']
assert sha(archive) == manifest['archive_sha256']
with zipfile.ZipFile(folder / 'evidence.zip') as z:
assert len(z.namelist()) == len(set(z.namelist()))
assert set(z.namelist()) == set(manifest['payloads'])
data = {name: z.read(name) for name in z.namelist()}
for name, raw in data.items():
expected = manifest['payloads'][name]
assert len(raw) == expected['bytes'] and sha(raw) == expected['sha256'], name
source_inputs = {}
gates = {}
for claim in manifest['gates']:
name = claim['name']
r = json.loads(data[f'gates/{name}.result.json'])
raw = data[f'gates/{name}.log']
input_raw = data['gates/' + r['inputs']]
inputs = json.loads(input_raw)
assert sha(raw) == r['log_sha256']
assert sha(input_raw) == r['inputs_sha256']
assert r['source'] == r['head_after'] == claim['source'] == inputs['source']
assert r['changed_inputs'] == []
assert r['exit'] == claim['exit']
assert r['command'] == claim['command']
assert r['mode'] == claim['mode'] and r['scope'] == claim['scope']
assert r['launcher_sha256'] == r['launcher_sha256_after']
launcher = data['launchers/' + r['launcher_sha256'] + '.py']
assert sha(launcher) == r['launcher_sha256']
assert len(inputs['inputs']) == claim['inputs']
paths = [item['path'] for item in inputs['inputs']]
assert len(paths) == len(set(paths))
for item in inputs['inputs']:
key = (r['source'], item['path'])
assert key not in source_inputs or source_inputs[key] == item
source_inputs[key] = item
output = raw.decode('utf-8', errors='strict')
if r['mode'] == 'list' and r['exit'] == 0:
names = re.findall(r'^([^\r\n]+): test\r?$', output, re.M)
assert names and len(names) == len(set(names))
assert names == r['listing_members']
assert len(names) == r['listing_count'] == claim['listed']
assert len(r['artifacts']) == 1
if r['mode'] == 'clippy' and r['exit'] == 0:
assert re.search(r'Finished `dev` profile', output)
assert not re.search(r'^error(?:\[|:)', output, re.M)
gates[name] = (r, output, input_raw)
tests = []
for claim in manifest['gates']:
if 'listing' not in claim:
continue
r, output, input_raw = gates[claim['name']]
listing, _, listed_inputs = gates[claim['listing']]
assert r['mode'] == 'test' and listing['mode'] == 'list'
assert r['source'] == listing['source'] and r['scope'] == listing['scope']
assert input_raw == listed_inputs and r['artifacts'] == listing['artifacts']
selected = {name for name in listing['listing_members'] if r['filter'] in name}
assert selected
outcomes = re.findall(r'^test ([^\r\n]+) \.\.\. (ok|FAILED|ignored)(?:, ([^\r\n]*))?\r?$', output, re.M)
assert len(outcomes) == len({name for name, _, _ in outcomes}) == len(selected)
assert {name for name, _, _ in outcomes} == selected
counts = [sum(status == wanted for _, status, _ in outcomes) for wanted in ('ok', 'FAILED', 'ignored')]
assert counts == claim['outcomes']
summaries = re.findall(r'^test result: (?:ok|FAILED)\. (\d+) passed; (\d+) failed; (\d+) ignored; (\d+) measured; (\d+) filtered out;', output, re.M)
assert summaries == [tuple(map(str, [*counts, 0, len(listing['listing_members']) - len(selected)]))]
ignores = [{'name': name, 'reason': reason} for name, status, reason in outcomes if status == 'ignored']
assert ignores == claim.get('ignored', [])
tests.append({'name': claim['name'], 'outcomes': counts, 'selected': len(selected)})
keys = sorted(source_inputs)
run = subprocess.run(['git', 'cat-file', '--batch'], cwd=repo,
input=''.join(f'{commit}:{path}\n' for commit, path in keys).encode(),
capture_output=True, check=True)
offset = 0
for key in keys:
end = run.stdout.index(b'\n', offset)
fields = run.stdout[offset:end].split()
assert len(fields) == 3 and fields[1] == b'blob', key
size = int(fields[2])
blob = run.stdout[end + 1:end + 1 + size]
expected = source_inputs[key]
assert size == expected['bytes'] and sha(blob) == expected['sha256'], key
offset = end + 2 + size
assert offset == len(run.stdout)
return {'payloads': len(data), 'gates': len(gates), 'source_inputs': len(keys), 'tests': tests,
'status': 'ARCHIVE_AND_RECORDED_SCOPE_VERIFIED',
'limitation': 'Does not rerun commands, reconstruct executable bytes, establish native behavior, or accept a release. Historical failures and launcher-capture limits remain in README.'}
if __name__ == '__main__':
if not __debug__:
raise SystemExit('Optimized Python is not supported')
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--repo', type=Path, required=True)
args = parser.parse_args()
print(json.dumps(verify(Path(__file__).resolve().parent, args.repo), indent=2))