docs: publish saved-view group selection verification and native evidence
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# Preserve the exact pinned evidence and verifier bytes through Git round trips.
|
||||
* -text whitespace=cr-at-eol
|
||||
incidents/**/*.arcadia whitespace=-blank-at-eof,cr-at-eol
|
||||
@@ -0,0 +1,96 @@
|
||||
# Closed multiselect gate evidence
|
||||
|
||||
This package preserves all 19 closed captures selected from
|
||||
`.local/group-movement-gates`: 14 recorded exit 0, and five recorded exit 101.
|
||||
Every run reports unchanged captured inputs. The five failures remain failures;
|
||||
their complete original receipts and streams are included. See the separate
|
||||
[saved-view report](../../../multiselect-saved-view-20260923.md) for scope and
|
||||
native observations. These standard-library Python 3.10+ tools do not run Cargo,
|
||||
Git, archived source or executables.
|
||||
|
||||
| Run | Recorded exit | Input files |
|
||||
| --- | ---: | ---: |
|
||||
| core-1 | 0 | 722 |
|
||||
| core-2 | 101 | 729 |
|
||||
| core-3 | 0 | 729 |
|
||||
| desktop-1 | 101 | 727 |
|
||||
| desktop-2 | 101 | 728 |
|
||||
| desktop-3 | 0 | 729 |
|
||||
| desktop-4 | 0 | 729 |
|
||||
| desktop-5 | 0 | 729 |
|
||||
| format-1 | 0 | 729 |
|
||||
| format-2 | 0 | 729 |
|
||||
| lint-1 | 101 | 729 |
|
||||
| lint-2 | 0 | 729 |
|
||||
| lint-3 | 0 | 729 |
|
||||
| native-build-1 | 0 | 729 |
|
||||
| native-build-2 | 0 | 729 |
|
||||
| oracle-2 | 101 | 729 |
|
||||
| oracle-3 | 0 | 729 |
|
||||
| windows-build-1 | 0 | 729 |
|
||||
| windows-build-2 | 0 | 729 |
|
||||
|
||||
Core-3, desktop-4, format-1, lint-2, native-build-1 and windows-build-1 share the
|
||||
729-file map `55a5f354bb5049a8c77ba9bafa833438ebf754649b0cf5d175d0c8dcfcedd7bb`.
|
||||
Desktop-5, format-2, lint-3, native-build-2 and windows-build-2 share the distinct
|
||||
729-file map `99dc46645236e674244e7c4867595a6000d3d85b54bcc9ab2b0c601923ecf66c`.
|
||||
The [source identity verifier](../source/README.md) compares those maps with Git
|
||||
commits `12a7352ddef5f69a144ead8219a50916233d63a9` and
|
||||
`f6a6010baed9e6164a1fcc7ecd58256a562827d7`, respectively. Earlier maps retain
|
||||
their own evidence scope; they are not reruns against the later source.
|
||||
|
||||
To validate this exact raw run list without writing a package, from the checkout
|
||||
root run:
|
||||
|
||||
```text
|
||||
python -B harness/experiments/multiselect-20260923/checks/prepare.py --root . --runs core-1 core-2 core-3 desktop-1 desktop-2 desktop-3 desktop-4 desktop-5 format-1 format-2 lint-1 lint-2 lint-3 native-build-1 native-build-2 oracle-2 oracle-3 windows-build-1 windows-build-2 --check-only
|
||||
```
|
||||
|
||||
Missing closure, changed inputs, inconsistent receipts, unavailable exact helpers,
|
||||
and extra/unexpected run files are refused. Run names must be supplied, must be
|
||||
unique, and cannot contain path separators.
|
||||
|
||||
To create a package, use the same explicit `--runs` list, omit `--check-only`, and
|
||||
optionally supply `--output PATH`. The default output is this checks directory.
|
||||
An output package is not overwritten. `--helper PATH` can be repeated to supply
|
||||
an older gate helper whose exact pinned bytes are no longer the current helper.
|
||||
Default helper candidates are `.local/group-movement-gates/*.py`.
|
||||
|
||||
Verify a completed package anywhere, without the original checkout:
|
||||
|
||||
```text
|
||||
python -B PATH_TO_PACKAGE/verify.py
|
||||
```
|
||||
|
||||
The packager preserves the seven original files per run: started/process/result
|
||||
receipts, stdout/stderr logs, the input map, and its source ZIP. It preserves the
|
||||
exact helper bytes named by each receipt. Only byte-identical input maps and ZIPs
|
||||
are deduplicated into hash-named capsules; their per-run logical mapping remains.
|
||||
ZIP member ordering and timestamps are fixed. Raw input/log bytes are unchanged.
|
||||
|
||||
`manifest.json` records the explicit run list, outcomes, commands, recorded HEADs,
|
||||
input counts, helper paths, logical mapping and every stored member pin.
|
||||
`files.json` pins `prepare.py`, `verify.py`, this README, the manifest and archive.
|
||||
The verifier checks safe exact ZIP membership (including nested source ZIPs),
|
||||
every recorded byte count/hash, input counts, the 71 vendored iced_widget files,
|
||||
start/process/finish order, receipt relationships, unchanged-input flags, helper
|
||||
identity, and exact ordered executable-artifact records parsed from Cargo JSON
|
||||
stdout. Missing JSON artifact records remain missing; they are not synthesized
|
||||
from paths or inferred from a successful exit. Non-null artifact readback pins
|
||||
are checked structurally; executable bytes are not included or independently
|
||||
verified by this package.
|
||||
|
||||
The source capsules are **local historical input snapshots**, including captured
|
||||
uncommitted work. A recorded HEAD alone does not identify their contents. They
|
||||
are not an integrated release, a hermetic toolchain distribution, or a claim that
|
||||
one run's gate applies to a later input map. Commands, paths, PIDs, times and
|
||||
artifact hashes are historical receipts, not authenticated execution records.
|
||||
The verifier checks their internal consistency and does not access historical
|
||||
absolute paths, contact services, extract archives or rerun tests. Pin integrity
|
||||
is not an external signature or proof against coordinated receipt alteration.
|
||||
|
||||
This package has no native interaction, focus, selection, movement, saved-model,
|
||||
Undo/Redo or full #29 acceptance implication. The native evidence and its
|
||||
independent evaluator belong in their separate reviewed record. The verification
|
||||
summary reports captured outcomes, including failures; it does not declare the
|
||||
feature or all captured gates successful.
|
||||
Binary file not shown.
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"prepare.py": {
|
||||
"bytes": 4818,
|
||||
"sha256": "29eedcec091874b26572530517f015ab690ed1a9040abea52248e99603ba5f25"
|
||||
},
|
||||
"verify.py": {
|
||||
"bytes": 8873,
|
||||
"sha256": "c03513407073bef092d57b968f982b8ffc0c58e095f834fe7464c6a0e8454a9a"
|
||||
},
|
||||
"README.md": {
|
||||
"bytes": 5001,
|
||||
"sha256": "3f5232af2ebb12003c833e6bc6643b4858950ebf015435a9b850c6a826fe27d0"
|
||||
},
|
||||
"manifest.json": {
|
||||
"bytes": 37083,
|
||||
"sha256": "c23269443cd059895c672330720a10508ab8ecade0d3686ec3d82ff792c9b457"
|
||||
},
|
||||
"evidence.zip": {
|
||||
"bytes": 25914867,
|
||||
"sha256": "261660dd8a5e93d917c1d36cad19d1eec0b93e312d1e0dd15f9ea16f5e11c864"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,935 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"kind": "multiselect-cargo-gates",
|
||||
"runs": {
|
||||
"core-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-core",
|
||||
"--test",
|
||||
"group_movement",
|
||||
"--test",
|
||||
"state_diagrams",
|
||||
"--",
|
||||
"--nocapture"
|
||||
],
|
||||
"head": "b8685416f56e53e30bd11ecf93a54cea10ac8458",
|
||||
"exitCode": 0,
|
||||
"inputCount": 722,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"core-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-core",
|
||||
"--test",
|
||||
"group_movement",
|
||||
"--test",
|
||||
"state_diagrams",
|
||||
"--example",
|
||||
"multiselect_native",
|
||||
"--",
|
||||
"--nocapture"
|
||||
],
|
||||
"head": "b8685416f56e53e30bd11ecf93a54cea10ac8458",
|
||||
"exitCode": 101,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"core-3": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-core",
|
||||
"--test",
|
||||
"group_movement",
|
||||
"--test",
|
||||
"state_diagrams",
|
||||
"--example",
|
||||
"multiselect_native",
|
||||
"--",
|
||||
"--nocapture"
|
||||
],
|
||||
"head": "b8685416f56e53e30bd11ecf93a54cea10ac8458",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"desktop-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"multiselect",
|
||||
"--",
|
||||
"--nocapture"
|
||||
],
|
||||
"head": "b8685416f56e53e30bd11ecf93a54cea10ac8458",
|
||||
"exitCode": 101,
|
||||
"inputCount": 727,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"desktop-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--",
|
||||
"--nocapture"
|
||||
],
|
||||
"head": "b8685416f56e53e30bd11ecf93a54cea10ac8458",
|
||||
"exitCode": 101,
|
||||
"inputCount": 728,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"desktop-3": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--",
|
||||
"--nocapture"
|
||||
],
|
||||
"head": "b8685416f56e53e30bd11ecf93a54cea10ac8458",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"desktop-4": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--",
|
||||
"--nocapture"
|
||||
],
|
||||
"head": "b8685416f56e53e30bd11ecf93a54cea10ac8458",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"desktop-5": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--",
|
||||
"--nocapture"
|
||||
],
|
||||
"head": "12a7352ddef5f69a144ead8219a50916233d63a9",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"format-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"fmt",
|
||||
"--all",
|
||||
"--",
|
||||
"--check"
|
||||
],
|
||||
"head": "12a7352ddef5f69a144ead8219a50916233d63a9",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"format-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"fmt",
|
||||
"--all",
|
||||
"--",
|
||||
"--check"
|
||||
],
|
||||
"head": "f6a6010baed9e6164a1fcc7ecd58256a562827d7",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"lint-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"clippy",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-core",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--all-targets",
|
||||
"--",
|
||||
"-D",
|
||||
"warnings"
|
||||
],
|
||||
"head": "b8685416f56e53e30bd11ecf93a54cea10ac8458",
|
||||
"exitCode": 101,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"lint-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"clippy",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-core",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--all-targets",
|
||||
"--",
|
||||
"-D",
|
||||
"warnings"
|
||||
],
|
||||
"head": "b8685416f56e53e30bd11ecf93a54cea10ac8458",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"lint-3": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"clippy",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-core",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--all-targets",
|
||||
"--",
|
||||
"-D",
|
||||
"warnings"
|
||||
],
|
||||
"head": "12a7352ddef5f69a144ead8219a50916233d63a9",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"native-build-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"build",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-core",
|
||||
"--example",
|
||||
"multiselect_native",
|
||||
"--message-format=json"
|
||||
],
|
||||
"head": "12a7352ddef5f69a144ead8219a50916233d63a9",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"native-build-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"build",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-core",
|
||||
"--example",
|
||||
"multiselect_native",
|
||||
"--message-format=json"
|
||||
],
|
||||
"head": "f6a6010baed9e6164a1fcc7ecd58256a562827d7",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"oracle-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-core",
|
||||
"--example",
|
||||
"multiselect_native",
|
||||
"--",
|
||||
"--nocapture"
|
||||
],
|
||||
"head": "b8685416f56e53e30bd11ecf93a54cea10ac8458",
|
||||
"exitCode": 101,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"oracle-3": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-core",
|
||||
"--example",
|
||||
"multiselect_native",
|
||||
"--",
|
||||
"--nocapture"
|
||||
],
|
||||
"head": "b8685416f56e53e30bd11ecf93a54cea10ac8458",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"windows-build-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"build",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--bin",
|
||||
"arcadia-studio",
|
||||
"--message-format=json"
|
||||
],
|
||||
"head": "12a7352ddef5f69a144ead8219a50916233d63a9",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"windows-build-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"build",
|
||||
"--locked",
|
||||
"--offline",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--bin",
|
||||
"arcadia-studio",
|
||||
"--message-format=json"
|
||||
],
|
||||
"head": "f6a6010baed9e6164a1fcc7ecd58256a562827d7",
|
||||
"exitCode": 0,
|
||||
"inputCount": 729,
|
||||
"helper": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
}
|
||||
},
|
||||
"logicalFiles": {
|
||||
"cargo/core-1/inputs.json": "capsules/a73d565f90b14c986e0f87a7ac3d368c93e053b7e591cffdfa20d8e81e2eae08.json",
|
||||
"cargo/core-1/inputs.zip": "capsules/2dcb54b1dd51a05cdd983432b114da8a08dce326c42b6e77a6b8772e75d2282f.zip",
|
||||
"cargo/core-1/process.json": "cargo/core-1/process.json",
|
||||
"cargo/core-1/result.json": "cargo/core-1/result.json",
|
||||
"cargo/core-1/started.json": "cargo/core-1/started.json",
|
||||
"cargo/core-1/stderr.log": "cargo/core-1/stderr.log",
|
||||
"cargo/core-1/stdout.log": "cargo/core-1/stdout.log",
|
||||
"cargo/core-2/inputs.json": "capsules/c5b23cd340869d57bd1bc4400041d499ea06a1a7619a6fd6b51e75278c1755e1.json",
|
||||
"cargo/core-2/inputs.zip": "capsules/df441a733bf28d1c59eab52063ca4b2645067b490b0a2f0072f98fc9225ea2e8.zip",
|
||||
"cargo/core-2/process.json": "cargo/core-2/process.json",
|
||||
"cargo/core-2/result.json": "cargo/core-2/result.json",
|
||||
"cargo/core-2/started.json": "cargo/core-2/started.json",
|
||||
"cargo/core-2/stderr.log": "cargo/core-2/stderr.log",
|
||||
"cargo/core-2/stdout.log": "cargo/core-2/stdout.log",
|
||||
"cargo/core-3/inputs.json": "capsules/55a5f354bb5049a8c77ba9bafa833438ebf754649b0cf5d175d0c8dcfcedd7bb.json",
|
||||
"cargo/core-3/inputs.zip": "capsules/e1c7f3abe7b32616d1081b4a2bb8af2d6d4b071bc2a7cbdd61e96a92ffdc0533.zip",
|
||||
"cargo/core-3/process.json": "cargo/core-3/process.json",
|
||||
"cargo/core-3/result.json": "cargo/core-3/result.json",
|
||||
"cargo/core-3/started.json": "cargo/core-3/started.json",
|
||||
"cargo/core-3/stderr.log": "cargo/core-3/stderr.log",
|
||||
"cargo/core-3/stdout.log": "cargo/core-3/stdout.log",
|
||||
"cargo/desktop-1/inputs.json": "capsules/c1083b630ad79ed1fea6933de3221f05b8eb9200694fb0e5dbd637527803579c.json",
|
||||
"cargo/desktop-1/inputs.zip": "capsules/8d6b08c2b1220cdb48d32cc74004cc9b82e4385f6f50a764f76c4a8630d070bf.zip",
|
||||
"cargo/desktop-1/process.json": "cargo/desktop-1/process.json",
|
||||
"cargo/desktop-1/result.json": "cargo/desktop-1/result.json",
|
||||
"cargo/desktop-1/started.json": "cargo/desktop-1/started.json",
|
||||
"cargo/desktop-1/stderr.log": "cargo/desktop-1/stderr.log",
|
||||
"cargo/desktop-1/stdout.log": "cargo/desktop-1/stdout.log",
|
||||
"cargo/desktop-2/inputs.json": "capsules/5f049dbbee443af86cde70efc74027f290a9bfbd434e5d644aa74ddb4e97566b.json",
|
||||
"cargo/desktop-2/inputs.zip": "capsules/bf7dc41142e6d087f213b2914e0ffb0e9cd52294f5830301e5e5b78c3470f725.zip",
|
||||
"cargo/desktop-2/process.json": "cargo/desktop-2/process.json",
|
||||
"cargo/desktop-2/result.json": "cargo/desktop-2/result.json",
|
||||
"cargo/desktop-2/started.json": "cargo/desktop-2/started.json",
|
||||
"cargo/desktop-2/stderr.log": "cargo/desktop-2/stderr.log",
|
||||
"cargo/desktop-2/stdout.log": "cargo/desktop-2/stdout.log",
|
||||
"cargo/desktop-3/inputs.json": "capsules/6f8eae7613666bca412e62f67151d6fee9f5bd32fb50363d0ff9b9ac8b190acf.json",
|
||||
"cargo/desktop-3/inputs.zip": "capsules/cc6233ddec2db0e322659a73a55e1681f5cb3554750ba183a756a29dadf8a8c9.zip",
|
||||
"cargo/desktop-3/process.json": "cargo/desktop-3/process.json",
|
||||
"cargo/desktop-3/result.json": "cargo/desktop-3/result.json",
|
||||
"cargo/desktop-3/started.json": "cargo/desktop-3/started.json",
|
||||
"cargo/desktop-3/stderr.log": "cargo/desktop-3/stderr.log",
|
||||
"cargo/desktop-3/stdout.log": "cargo/desktop-3/stdout.log",
|
||||
"cargo/desktop-4/inputs.json": "capsules/55a5f354bb5049a8c77ba9bafa833438ebf754649b0cf5d175d0c8dcfcedd7bb.json",
|
||||
"cargo/desktop-4/inputs.zip": "capsules/e1c7f3abe7b32616d1081b4a2bb8af2d6d4b071bc2a7cbdd61e96a92ffdc0533.zip",
|
||||
"cargo/desktop-4/process.json": "cargo/desktop-4/process.json",
|
||||
"cargo/desktop-4/result.json": "cargo/desktop-4/result.json",
|
||||
"cargo/desktop-4/started.json": "cargo/desktop-4/started.json",
|
||||
"cargo/desktop-4/stderr.log": "cargo/desktop-4/stderr.log",
|
||||
"cargo/desktop-4/stdout.log": "cargo/desktop-4/stdout.log",
|
||||
"cargo/desktop-5/inputs.json": "capsules/99dc46645236e674244e7c4867595a6000d3d85b54bcc9ab2b0c601923ecf66c.json",
|
||||
"cargo/desktop-5/inputs.zip": "capsules/aa8bb3d7fbd1f73c36913235b0b1d3aa79f6ac418b6c07ade94a7dee4a617bd9.zip",
|
||||
"cargo/desktop-5/process.json": "cargo/desktop-5/process.json",
|
||||
"cargo/desktop-5/result.json": "cargo/desktop-5/result.json",
|
||||
"cargo/desktop-5/started.json": "cargo/desktop-5/started.json",
|
||||
"cargo/desktop-5/stderr.log": "cargo/desktop-5/stderr.log",
|
||||
"cargo/desktop-5/stdout.log": "cargo/desktop-5/stdout.log",
|
||||
"cargo/format-1/inputs.json": "capsules/55a5f354bb5049a8c77ba9bafa833438ebf754649b0cf5d175d0c8dcfcedd7bb.json",
|
||||
"cargo/format-1/inputs.zip": "capsules/e1c7f3abe7b32616d1081b4a2bb8af2d6d4b071bc2a7cbdd61e96a92ffdc0533.zip",
|
||||
"cargo/format-1/process.json": "cargo/format-1/process.json",
|
||||
"cargo/format-1/result.json": "cargo/format-1/result.json",
|
||||
"cargo/format-1/started.json": "cargo/format-1/started.json",
|
||||
"cargo/format-1/stderr.log": "cargo/format-1/stderr.log",
|
||||
"cargo/format-1/stdout.log": "cargo/format-1/stdout.log",
|
||||
"cargo/format-2/inputs.json": "capsules/99dc46645236e674244e7c4867595a6000d3d85b54bcc9ab2b0c601923ecf66c.json",
|
||||
"cargo/format-2/inputs.zip": "capsules/aa8bb3d7fbd1f73c36913235b0b1d3aa79f6ac418b6c07ade94a7dee4a617bd9.zip",
|
||||
"cargo/format-2/process.json": "cargo/format-2/process.json",
|
||||
"cargo/format-2/result.json": "cargo/format-2/result.json",
|
||||
"cargo/format-2/started.json": "cargo/format-2/started.json",
|
||||
"cargo/format-2/stderr.log": "cargo/format-2/stderr.log",
|
||||
"cargo/format-2/stdout.log": "cargo/format-2/stdout.log",
|
||||
"cargo/lint-1/inputs.json": "capsules/292f6139450109875549801a1da337dac08a8bca4cfa0124139a5d8d042386b9.json",
|
||||
"cargo/lint-1/inputs.zip": "capsules/d2ec5025067db2c05736bb1c9c9b6250d9199f1b7190e8c09f5a777424790c10.zip",
|
||||
"cargo/lint-1/process.json": "cargo/lint-1/process.json",
|
||||
"cargo/lint-1/result.json": "cargo/lint-1/result.json",
|
||||
"cargo/lint-1/started.json": "cargo/lint-1/started.json",
|
||||
"cargo/lint-1/stderr.log": "cargo/lint-1/stderr.log",
|
||||
"cargo/lint-1/stdout.log": "cargo/lint-1/stdout.log",
|
||||
"cargo/lint-2/inputs.json": "capsules/55a5f354bb5049a8c77ba9bafa833438ebf754649b0cf5d175d0c8dcfcedd7bb.json",
|
||||
"cargo/lint-2/inputs.zip": "capsules/e1c7f3abe7b32616d1081b4a2bb8af2d6d4b071bc2a7cbdd61e96a92ffdc0533.zip",
|
||||
"cargo/lint-2/process.json": "cargo/lint-2/process.json",
|
||||
"cargo/lint-2/result.json": "cargo/lint-2/result.json",
|
||||
"cargo/lint-2/started.json": "cargo/lint-2/started.json",
|
||||
"cargo/lint-2/stderr.log": "cargo/lint-2/stderr.log",
|
||||
"cargo/lint-2/stdout.log": "cargo/lint-2/stdout.log",
|
||||
"cargo/lint-3/inputs.json": "capsules/99dc46645236e674244e7c4867595a6000d3d85b54bcc9ab2b0c601923ecf66c.json",
|
||||
"cargo/lint-3/inputs.zip": "capsules/aa8bb3d7fbd1f73c36913235b0b1d3aa79f6ac418b6c07ade94a7dee4a617bd9.zip",
|
||||
"cargo/lint-3/process.json": "cargo/lint-3/process.json",
|
||||
"cargo/lint-3/result.json": "cargo/lint-3/result.json",
|
||||
"cargo/lint-3/started.json": "cargo/lint-3/started.json",
|
||||
"cargo/lint-3/stderr.log": "cargo/lint-3/stderr.log",
|
||||
"cargo/lint-3/stdout.log": "cargo/lint-3/stdout.log",
|
||||
"cargo/native-build-1/inputs.json": "capsules/55a5f354bb5049a8c77ba9bafa833438ebf754649b0cf5d175d0c8dcfcedd7bb.json",
|
||||
"cargo/native-build-1/inputs.zip": "capsules/e1c7f3abe7b32616d1081b4a2bb8af2d6d4b071bc2a7cbdd61e96a92ffdc0533.zip",
|
||||
"cargo/native-build-1/process.json": "cargo/native-build-1/process.json",
|
||||
"cargo/native-build-1/result.json": "cargo/native-build-1/result.json",
|
||||
"cargo/native-build-1/started.json": "cargo/native-build-1/started.json",
|
||||
"cargo/native-build-1/stderr.log": "cargo/native-build-1/stderr.log",
|
||||
"cargo/native-build-1/stdout.log": "cargo/native-build-1/stdout.log",
|
||||
"cargo/native-build-2/inputs.json": "capsules/99dc46645236e674244e7c4867595a6000d3d85b54bcc9ab2b0c601923ecf66c.json",
|
||||
"cargo/native-build-2/inputs.zip": "capsules/aa8bb3d7fbd1f73c36913235b0b1d3aa79f6ac418b6c07ade94a7dee4a617bd9.zip",
|
||||
"cargo/native-build-2/process.json": "cargo/native-build-2/process.json",
|
||||
"cargo/native-build-2/result.json": "cargo/native-build-2/result.json",
|
||||
"cargo/native-build-2/started.json": "cargo/native-build-2/started.json",
|
||||
"cargo/native-build-2/stderr.log": "cargo/native-build-2/stderr.log",
|
||||
"cargo/native-build-2/stdout.log": "cargo/native-build-2/stdout.log",
|
||||
"cargo/oracle-2/inputs.json": "capsules/ae16337dbc617e26b23468adb86d963e3bcf7eddf177e8fb4654c69019904548.json",
|
||||
"cargo/oracle-2/inputs.zip": "capsules/e99bcaf1ab2becbcad0a005bdd0a4eb14fad2075bd7a38433857df4d3cad5e4d.zip",
|
||||
"cargo/oracle-2/process.json": "cargo/oracle-2/process.json",
|
||||
"cargo/oracle-2/result.json": "cargo/oracle-2/result.json",
|
||||
"cargo/oracle-2/started.json": "cargo/oracle-2/started.json",
|
||||
"cargo/oracle-2/stderr.log": "cargo/oracle-2/stderr.log",
|
||||
"cargo/oracle-2/stdout.log": "cargo/oracle-2/stdout.log",
|
||||
"cargo/oracle-3/inputs.json": "capsules/292f6139450109875549801a1da337dac08a8bca4cfa0124139a5d8d042386b9.json",
|
||||
"cargo/oracle-3/inputs.zip": "capsules/d2ec5025067db2c05736bb1c9c9b6250d9199f1b7190e8c09f5a777424790c10.zip",
|
||||
"cargo/oracle-3/process.json": "cargo/oracle-3/process.json",
|
||||
"cargo/oracle-3/result.json": "cargo/oracle-3/result.json",
|
||||
"cargo/oracle-3/started.json": "cargo/oracle-3/started.json",
|
||||
"cargo/oracle-3/stderr.log": "cargo/oracle-3/stderr.log",
|
||||
"cargo/oracle-3/stdout.log": "cargo/oracle-3/stdout.log",
|
||||
"cargo/windows-build-1/inputs.json": "capsules/55a5f354bb5049a8c77ba9bafa833438ebf754649b0cf5d175d0c8dcfcedd7bb.json",
|
||||
"cargo/windows-build-1/inputs.zip": "capsules/e1c7f3abe7b32616d1081b4a2bb8af2d6d4b071bc2a7cbdd61e96a92ffdc0533.zip",
|
||||
"cargo/windows-build-1/process.json": "cargo/windows-build-1/process.json",
|
||||
"cargo/windows-build-1/result.json": "cargo/windows-build-1/result.json",
|
||||
"cargo/windows-build-1/started.json": "cargo/windows-build-1/started.json",
|
||||
"cargo/windows-build-1/stderr.log": "cargo/windows-build-1/stderr.log",
|
||||
"cargo/windows-build-1/stdout.log": "cargo/windows-build-1/stdout.log",
|
||||
"cargo/windows-build-2/inputs.json": "capsules/99dc46645236e674244e7c4867595a6000d3d85b54bcc9ab2b0c601923ecf66c.json",
|
||||
"cargo/windows-build-2/inputs.zip": "capsules/aa8bb3d7fbd1f73c36913235b0b1d3aa79f6ac418b6c07ade94a7dee4a617bd9.zip",
|
||||
"cargo/windows-build-2/process.json": "cargo/windows-build-2/process.json",
|
||||
"cargo/windows-build-2/result.json": "cargo/windows-build-2/result.json",
|
||||
"cargo/windows-build-2/started.json": "cargo/windows-build-2/started.json",
|
||||
"cargo/windows-build-2/stderr.log": "cargo/windows-build-2/stderr.log",
|
||||
"cargo/windows-build-2/stdout.log": "cargo/windows-build-2/stdout.log",
|
||||
"helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py": "helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py"
|
||||
},
|
||||
"members": {
|
||||
"capsules/292f6139450109875549801a1da337dac08a8bca4cfa0124139a5d8d042386b9.json": {
|
||||
"bytes": 121985,
|
||||
"sha256": "292f6139450109875549801a1da337dac08a8bca4cfa0124139a5d8d042386b9"
|
||||
},
|
||||
"capsules/2dcb54b1dd51a05cdd983432b114da8a08dce326c42b6e77a6b8772e75d2282f.zip": {
|
||||
"bytes": 2885634,
|
||||
"sha256": "2dcb54b1dd51a05cdd983432b114da8a08dce326c42b6e77a6b8772e75d2282f"
|
||||
},
|
||||
"capsules/55a5f354bb5049a8c77ba9bafa833438ebf754649b0cf5d175d0c8dcfcedd7bb.json": {
|
||||
"bytes": 121985,
|
||||
"sha256": "55a5f354bb5049a8c77ba9bafa833438ebf754649b0cf5d175d0c8dcfcedd7bb"
|
||||
},
|
||||
"capsules/5f049dbbee443af86cde70efc74027f290a9bfbd434e5d644aa74ddb4e97566b.json": {
|
||||
"bytes": 121820,
|
||||
"sha256": "5f049dbbee443af86cde70efc74027f290a9bfbd434e5d644aa74ddb4e97566b"
|
||||
},
|
||||
"capsules/6f8eae7613666bca412e62f67151d6fee9f5bd32fb50363d0ff9b9ac8b190acf.json": {
|
||||
"bytes": 121984,
|
||||
"sha256": "6f8eae7613666bca412e62f67151d6fee9f5bd32fb50363d0ff9b9ac8b190acf"
|
||||
},
|
||||
"capsules/8d6b08c2b1220cdb48d32cc74004cc9b82e4385f6f50a764f76c4a8630d070bf.zip": {
|
||||
"bytes": 2903240,
|
||||
"sha256": "8d6b08c2b1220cdb48d32cc74004cc9b82e4385f6f50a764f76c4a8630d070bf"
|
||||
},
|
||||
"capsules/99dc46645236e674244e7c4867595a6000d3d85b54bcc9ab2b0c601923ecf66c.json": {
|
||||
"bytes": 121985,
|
||||
"sha256": "99dc46645236e674244e7c4867595a6000d3d85b54bcc9ab2b0c601923ecf66c"
|
||||
},
|
||||
"capsules/a73d565f90b14c986e0f87a7ac3d368c93e053b7e591cffdfa20d8e81e2eae08.json": {
|
||||
"bytes": 120844,
|
||||
"sha256": "a73d565f90b14c986e0f87a7ac3d368c93e053b7e591cffdfa20d8e81e2eae08"
|
||||
},
|
||||
"capsules/aa8bb3d7fbd1f73c36913235b0b1d3aa79f6ac418b6c07ade94a7dee4a617bd9.zip": {
|
||||
"bytes": 2918930,
|
||||
"sha256": "aa8bb3d7fbd1f73c36913235b0b1d3aa79f6ac418b6c07ade94a7dee4a617bd9"
|
||||
},
|
||||
"capsules/ae16337dbc617e26b23468adb86d963e3bcf7eddf177e8fb4654c69019904548.json": {
|
||||
"bytes": 121984,
|
||||
"sha256": "ae16337dbc617e26b23468adb86d963e3bcf7eddf177e8fb4654c69019904548"
|
||||
},
|
||||
"capsules/bf7dc41142e6d087f213b2914e0ffb0e9cd52294f5830301e5e5b78c3470f725.zip": {
|
||||
"bytes": 2909281,
|
||||
"sha256": "bf7dc41142e6d087f213b2914e0ffb0e9cd52294f5830301e5e5b78c3470f725"
|
||||
},
|
||||
"capsules/c1083b630ad79ed1fea6933de3221f05b8eb9200694fb0e5dbd637527803579c.json": {
|
||||
"bytes": 121652,
|
||||
"sha256": "c1083b630ad79ed1fea6933de3221f05b8eb9200694fb0e5dbd637527803579c"
|
||||
},
|
||||
"capsules/c5b23cd340869d57bd1bc4400041d499ea06a1a7619a6fd6b51e75278c1755e1.json": {
|
||||
"bytes": 121984,
|
||||
"sha256": "c5b23cd340869d57bd1bc4400041d499ea06a1a7619a6fd6b51e75278c1755e1"
|
||||
},
|
||||
"capsules/cc6233ddec2db0e322659a73a55e1681f5cb3554750ba183a756a29dadf8a8c9.zip": {
|
||||
"bytes": 2917494,
|
||||
"sha256": "cc6233ddec2db0e322659a73a55e1681f5cb3554750ba183a756a29dadf8a8c9"
|
||||
},
|
||||
"capsules/d2ec5025067db2c05736bb1c9c9b6250d9199f1b7190e8c09f5a777424790c10.zip": {
|
||||
"bytes": 2918296,
|
||||
"sha256": "d2ec5025067db2c05736bb1c9c9b6250d9199f1b7190e8c09f5a777424790c10"
|
||||
},
|
||||
"capsules/df441a733bf28d1c59eab52063ca4b2645067b490b0a2f0072f98fc9225ea2e8.zip": {
|
||||
"bytes": 2917518,
|
||||
"sha256": "df441a733bf28d1c59eab52063ca4b2645067b490b0a2f0072f98fc9225ea2e8"
|
||||
},
|
||||
"capsules/e1c7f3abe7b32616d1081b4a2bb8af2d6d4b071bc2a7cbdd61e96a92ffdc0533.zip": {
|
||||
"bytes": 2918309,
|
||||
"sha256": "e1c7f3abe7b32616d1081b4a2bb8af2d6d4b071bc2a7cbdd61e96a92ffdc0533"
|
||||
},
|
||||
"capsules/e99bcaf1ab2becbcad0a005bdd0a4eb14fad2075bd7a38433857df4d3cad5e4d.zip": {
|
||||
"bytes": 2917719,
|
||||
"sha256": "e99bcaf1ab2becbcad0a005bdd0a4eb14fad2075bd7a38433857df4d3cad5e4d"
|
||||
},
|
||||
"cargo/core-1/process.json": {
|
||||
"bytes": 210,
|
||||
"sha256": "92e5a88b5b86400c13bad4d0a9d490466bb2ef0b6077d14930ac5084187b5506"
|
||||
},
|
||||
"cargo/core-1/result.json": {
|
||||
"bytes": 1821,
|
||||
"sha256": "c90e020e6d912516fbc5ef5b4bf6a5df5fc668e5f5e19a9108c29bf3723cea9c"
|
||||
},
|
||||
"cargo/core-1/started.json": {
|
||||
"bytes": 1428,
|
||||
"sha256": "230ea369285569a0fa179fe420b0b2133e7fcb2349601a53d69881e9a66bd39b"
|
||||
},
|
||||
"cargo/core-1/stderr.log": {
|
||||
"bytes": 434,
|
||||
"sha256": "84a1b0b7352dcde2fe51293feabbddf8e94206d9278e4a38e6d354af8a1bcd48"
|
||||
},
|
||||
"cargo/core-1/stdout.log": {
|
||||
"bytes": 1671,
|
||||
"sha256": "eb04561c11e394cc368ea1c5e38aa4b1dc8b5c3c44acb168469dd941f80f14e8"
|
||||
},
|
||||
"cargo/core-2/process.json": {
|
||||
"bytes": 245,
|
||||
"sha256": "020d6cb0ce6e4b9122ac2dcbd86c9c1719479f29d3690247182ade858caba12d"
|
||||
},
|
||||
"cargo/core-2/result.json": {
|
||||
"bytes": 1870,
|
||||
"sha256": "c97cbcd85b60a3476135bf9026d41868ea091061c12ce4bbc18a40c6023c5b3e"
|
||||
},
|
||||
"cargo/core-2/started.json": {
|
||||
"bytes": 1473,
|
||||
"sha256": "f367b289c9d378975514fa450e4fa25049f4461156417ba5bd6e79836faf401e"
|
||||
},
|
||||
"cargo/core-2/stderr.log": {
|
||||
"bytes": 5287,
|
||||
"sha256": "4ea6f38eef014ab8176c3ab1ed9d3be3addb4463a8f073425f1b5493b33a7c86"
|
||||
},
|
||||
"cargo/core-2/stdout.log": {
|
||||
"bytes": 4138,
|
||||
"sha256": "a2dfdb0d7c6c7ba7e9ef86063a815f43111188a44ae4b0e20717cc3e518b7c3d"
|
||||
},
|
||||
"cargo/core-3/process.json": {
|
||||
"bytes": 245,
|
||||
"sha256": "b26f22b0aed07e55906b024d1fd94198da1ab1d56363fc5ad66868940ae1c9a4"
|
||||
},
|
||||
"cargo/core-3/result.json": {
|
||||
"bytes": 1867,
|
||||
"sha256": "6d04a2818750491cb73ebb1b257d214316c048e1ac6165a119a27534d636406c"
|
||||
},
|
||||
"cargo/core-3/started.json": {
|
||||
"bytes": 1473,
|
||||
"sha256": "49e9d637eb063277925c577266a63e5fd06723ca24726d609dc0e458596e8316"
|
||||
},
|
||||
"cargo/core-3/stderr.log": {
|
||||
"bytes": 539,
|
||||
"sha256": "f05f7ab2f0244968100eb0e0a82808af8e42dceb5b5de70d034b7ae56bad9489"
|
||||
},
|
||||
"cargo/core-3/stdout.log": {
|
||||
"bytes": 4797,
|
||||
"sha256": "d0f2180aaecc3b253b473200b77348a19a21594e193ce45c21f040b7242be253"
|
||||
},
|
||||
"cargo/desktop-1/process.json": {
|
||||
"bytes": 172,
|
||||
"sha256": "d9ba2b6a0968b702af0aa857e7bb8667680eeddc32a0403781cd3d5e2467c067"
|
||||
},
|
||||
"cargo/desktop-1/result.json": {
|
||||
"bytes": 1769,
|
||||
"sha256": "2384c076e4bbc0e15951671e3a830725213c31cfcded0a27e1bb72802c576dbc"
|
||||
},
|
||||
"cargo/desktop-1/started.json": {
|
||||
"bytes": 1375,
|
||||
"sha256": "6b1ba478ebe5e14d5ee76199a56874a6a10156c2dd7e9d3830fd5ba5311094d6"
|
||||
},
|
||||
"cargo/desktop-1/stderr.log": {
|
||||
"bytes": 4604,
|
||||
"sha256": "6a47286c4daaf9f4ac8ac8cca3e98931f7812a44b192128aa67880c1ac930b87"
|
||||
},
|
||||
"cargo/desktop-1/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/desktop-2/process.json": {
|
||||
"bytes": 157,
|
||||
"sha256": "cc037bab1ec44bd2e4095e165597f5e1d077bae5fce7a96c6a5fd814470d4244"
|
||||
},
|
||||
"cargo/desktop-2/result.json": {
|
||||
"bytes": 1753,
|
||||
"sha256": "9c037405572273086737e22b60796eff0745f4746ee3f25529f928da53c98fbc"
|
||||
},
|
||||
"cargo/desktop-2/started.json": {
|
||||
"bytes": 1355,
|
||||
"sha256": "18f71e571722bdb3696195623b3af3a2b9a45d38f98307a68049aacff3fbad9c"
|
||||
},
|
||||
"cargo/desktop-2/stderr.log": {
|
||||
"bytes": 1085,
|
||||
"sha256": "316e0179675fb071d7d9773d7073d771438ecd70e66c99559f4239e0638a3238"
|
||||
},
|
||||
"cargo/desktop-2/stdout.log": {
|
||||
"bytes": 145051,
|
||||
"sha256": "7c907317d106ff63347456b5ad2015fa8a9974ffbb7003d0a123afc99879ce42"
|
||||
},
|
||||
"cargo/desktop-3/process.json": {
|
||||
"bytes": 157,
|
||||
"sha256": "368d265e1ee5cceeb5995172c662dc3bc551591b9600a781c63ed64579760c24"
|
||||
},
|
||||
"cargo/desktop-3/result.json": {
|
||||
"bytes": 1751,
|
||||
"sha256": "32076fb49a6ddfcef63e77ca9f1edec34700ca80d36f32890581d56035f80054"
|
||||
},
|
||||
"cargo/desktop-3/started.json": {
|
||||
"bytes": 1355,
|
||||
"sha256": "da1ccd8352380b357d5954a70d86f2c51c8a2da8d1c4b553ca7b281d3000eab9"
|
||||
},
|
||||
"cargo/desktop-3/stderr.log": {
|
||||
"bytes": 626,
|
||||
"sha256": "5333e25e78f515449877867d0a2bf714b7cb3302c9497d4f4343a1e05e0f8b03"
|
||||
},
|
||||
"cargo/desktop-3/stdout.log": {
|
||||
"bytes": 145562,
|
||||
"sha256": "dc7e40a7d2ab1e78c74f0ee0344c4b2e5b1402bc6367e93a40780774000e4f81"
|
||||
},
|
||||
"cargo/desktop-4/process.json": {
|
||||
"bytes": 157,
|
||||
"sha256": "0823d0fbda95fe5efb08a7c11c98a7ac2409b5b3d170cf2e41b702895211abf4"
|
||||
},
|
||||
"cargo/desktop-4/result.json": {
|
||||
"bytes": 1750,
|
||||
"sha256": "d88b177e9d181f7c9c3685100c8676c0c8954cd0b071344ff5b4bb7a8e498865"
|
||||
},
|
||||
"cargo/desktop-4/started.json": {
|
||||
"bytes": 1355,
|
||||
"sha256": "0f9927d5c0b09c7fcc8922c68a2c88a4d840e0420a7be90193f566b02312a3d3"
|
||||
},
|
||||
"cargo/desktop-4/stderr.log": {
|
||||
"bytes": 628,
|
||||
"sha256": "992db238282b7acf1bbfeee7f2c459f9afe4bce814761d70df789e4f6239afcf"
|
||||
},
|
||||
"cargo/desktop-4/stdout.log": {
|
||||
"bytes": 145802,
|
||||
"sha256": "70c38e8c98cac4f220999481908beb549e5377f6f48c31931f9412ed25a67a41"
|
||||
},
|
||||
"cargo/desktop-5/process.json": {
|
||||
"bytes": 157,
|
||||
"sha256": "83bf9efc58fa5692f3ed038c107c081e5483d91117c73eddba62d3eb45cc7267"
|
||||
},
|
||||
"cargo/desktop-5/result.json": {
|
||||
"bytes": 1751,
|
||||
"sha256": "7cbbae8bbceec07cebb4696b999701cd29d46bfd047351aa3e20ea49d7c67ae6"
|
||||
},
|
||||
"cargo/desktop-5/started.json": {
|
||||
"bytes": 1355,
|
||||
"sha256": "0bfd2a6c185afb1b301e3b6b5f746d0e37251f147590aa2e9f25e370e99f53e8"
|
||||
},
|
||||
"cargo/desktop-5/stderr.log": {
|
||||
"bytes": 631,
|
||||
"sha256": "466f26c41956ed05629b633827d7ffca497c57c87ff67acff6351043c7bdefd4"
|
||||
},
|
||||
"cargo/desktop-5/stdout.log": {
|
||||
"bytes": 146577,
|
||||
"sha256": "e89cf5f2375fd40ae70261471d797cbaca5127cb27730e6094a616afa12514ae"
|
||||
},
|
||||
"cargo/format-1/process.json": {
|
||||
"bytes": 116,
|
||||
"sha256": "bb8e0a7620b40bb5f0932643848a57b0d207dde39006a9a20141c00f13d94284"
|
||||
},
|
||||
"cargo/format-1/result.json": {
|
||||
"bytes": 1687,
|
||||
"sha256": "967eeddb3fc6a0dc0fdf9a75f575d75fa8f8b0b5ea9c8a422590bcbece6de77b"
|
||||
},
|
||||
"cargo/format-1/started.json": {
|
||||
"bytes": 1299,
|
||||
"sha256": "ceb354dfbc4a41d72e496342e28475ddcce5a3c17a4e1553f0d699404c374657"
|
||||
},
|
||||
"cargo/format-1/stderr.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/format-1/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/format-2/process.json": {
|
||||
"bytes": 116,
|
||||
"sha256": "aa31b91d224845b7dd1df777e865c88c5b8f55b66f173053be318132d1bc3870"
|
||||
},
|
||||
"cargo/format-2/result.json": {
|
||||
"bytes": 1687,
|
||||
"sha256": "c4d5529c8d2feae1b805bd8d404a3817053a5a0cd4ec341aa8c1e0a5c05eed5b"
|
||||
},
|
||||
"cargo/format-2/started.json": {
|
||||
"bytes": 1299,
|
||||
"sha256": "2ea70bb29d7fef73a194acd7aa36836fd4a54ae8a4be173f919cd2fc32e97919"
|
||||
},
|
||||
"cargo/format-2/stderr.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/format-2/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/lint-1/process.json": {
|
||||
"bytes": 196,
|
||||
"sha256": "d30e400277dc0bb4a1618689b16ab86be7838cc1b42688185d655df235080286"
|
||||
},
|
||||
"cargo/lint-1/result.json": {
|
||||
"bytes": 1808,
|
||||
"sha256": "7ffb361d398def4520afc48683a69effbb8b066efd9442ba3b356c8124aae6d9"
|
||||
},
|
||||
"cargo/lint-1/started.json": {
|
||||
"bytes": 1414,
|
||||
"sha256": "771b5bdc31662fb3b4f76735e92b0e89d31a02188fbce35c5cfb0aea4c37c0ca"
|
||||
},
|
||||
"cargo/lint-1/stderr.log": {
|
||||
"bytes": 1023,
|
||||
"sha256": "9cbab357d810ce8164a0e614491f53529e61c1cad79793ca429e13897a8dc5ed"
|
||||
},
|
||||
"cargo/lint-1/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/lint-2/process.json": {
|
||||
"bytes": 196,
|
||||
"sha256": "f4aed65014ed120dc72bd08160559ae0285bc5c4968305a5fb86cf29e8c0d347"
|
||||
},
|
||||
"cargo/lint-2/result.json": {
|
||||
"bytes": 1805,
|
||||
"sha256": "b873add4777fd8f7516513e2423f9d3eb4a40505a3b1fa7edfbee89fb5c7e0d3"
|
||||
},
|
||||
"cargo/lint-2/started.json": {
|
||||
"bytes": 1414,
|
||||
"sha256": "0d01a20ec0f7cd796c066c95936c74df0abf8947fca655d900a5bdd4f8dbd610"
|
||||
},
|
||||
"cargo/lint-2/stderr.log": {
|
||||
"bytes": 207,
|
||||
"sha256": "e6f76746d5864a4de1e9d238c74799e2080e2c6214f51b68a4692d5e15f5b107"
|
||||
},
|
||||
"cargo/lint-2/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/lint-3/process.json": {
|
||||
"bytes": 196,
|
||||
"sha256": "620094b52dab8f23f389687cf72b8b3aa4effa55697842206a618293537eb869"
|
||||
},
|
||||
"cargo/lint-3/result.json": {
|
||||
"bytes": 1805,
|
||||
"sha256": "1e7dc472c03d653094850ed653599cee41e50d1639389bbc3fee45e40a754b5c"
|
||||
},
|
||||
"cargo/lint-3/started.json": {
|
||||
"bytes": 1414,
|
||||
"sha256": "b921ee7102386187c288c1b25aea96a3019ff00a4a508065aefbc4499b7c7818"
|
||||
},
|
||||
"cargo/lint-3/stderr.log": {
|
||||
"bytes": 137,
|
||||
"sha256": "d19e47547a69ce7956c74f2a65cd1064571985d073bcf497a11a0b0eebcfbd04"
|
||||
},
|
||||
"cargo/lint-3/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/native-build-1/process.json": {
|
||||
"bytes": 194,
|
||||
"sha256": "390cb979d680b9fdb7e0afa05d6b9d10a25dc27abaff16596d113bb0b2142b43"
|
||||
},
|
||||
"cargo/native-build-1/result.json": {
|
||||
"bytes": 3132,
|
||||
"sha256": "35f76499ac2a49446b896932c963fd8734a5755e00e3511cedf1e584e7b17704"
|
||||
},
|
||||
"cargo/native-build-1/started.json": {
|
||||
"bytes": 1397,
|
||||
"sha256": "5f37fc095aa00eae8fae043651a29f387f484bf4a0cc454e3919ea4f49567126"
|
||||
},
|
||||
"cargo/native-build-1/stderr.log": {
|
||||
"bytes": 130,
|
||||
"sha256": "731d61ee089d75c107edcd02d2cdedcddaad57ec06607ccd0822d9dc71a72720"
|
||||
},
|
||||
"cargo/native-build-1/stdout.log": {
|
||||
"bytes": 41700,
|
||||
"sha256": "832dc599cad2c9ba28ff9153537fb428390d8f25959f5b4a080cd432f6bea0e8"
|
||||
},
|
||||
"cargo/native-build-2/process.json": {
|
||||
"bytes": 194,
|
||||
"sha256": "46ff130840d8b12272be43f479adeb0b2ace94ee1d5389c5638a61b22d732496"
|
||||
},
|
||||
"cargo/native-build-2/result.json": {
|
||||
"bytes": 3131,
|
||||
"sha256": "fbecac3b0f7913db5e2ad19043c7df167a92287833ddf3ea4f24766e86ae523b"
|
||||
},
|
||||
"cargo/native-build-2/started.json": {
|
||||
"bytes": 1397,
|
||||
"sha256": "cbd2c7ad98baddc3719a5c03bef103747d4cb5c560d631376149f116ede49584"
|
||||
},
|
||||
"cargo/native-build-2/stderr.log": {
|
||||
"bytes": 60,
|
||||
"sha256": "b2558545bbfa50a0f0c26623c0982eb5f96d71ea228d7c56180edbac0d0b295d"
|
||||
},
|
||||
"cargo/native-build-2/stdout.log": {
|
||||
"bytes": 41699,
|
||||
"sha256": "7884b8ea1a92d58c7174657560ec38ff9a073e52f93cc19a78290840f2ab5486"
|
||||
},
|
||||
"cargo/oracle-2/process.json": {
|
||||
"bytes": 189,
|
||||
"sha256": "1e8ffd7a03b22bf2ec43b0d66ae3cc98016a431c4a07499faf3ca0c635b92337"
|
||||
},
|
||||
"cargo/oracle-2/result.json": {
|
||||
"bytes": 1789,
|
||||
"sha256": "e0b7331751bae8564ee5c28d05029071f1c8460195e6f9e2f0d00a5ae4e05a16"
|
||||
},
|
||||
"cargo/oracle-2/started.json": {
|
||||
"bytes": 1397,
|
||||
"sha256": "b7a8278dfa2324f0c3ff6e9616a65ef7a51c99699ad700adfe90e2accc435765"
|
||||
},
|
||||
"cargo/oracle-2/stderr.log": {
|
||||
"bytes": 520,
|
||||
"sha256": "9dd8b849afdbbb2207a9ad82f1b6c6f07fd9cd0846fe4591f33c40fdadcbb3ac"
|
||||
},
|
||||
"cargo/oracle-2/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/oracle-3/process.json": {
|
||||
"bytes": 189,
|
||||
"sha256": "a2cb30f512ee390bb03c9fcf5ea8069ca3a05da91f798985efc3f9f54670ace4"
|
||||
},
|
||||
"cargo/oracle-3/result.json": {
|
||||
"bytes": 1791,
|
||||
"sha256": "f0768fecc9f6711dd3cfc627c60aaf6118216bce47e76faa4cbdda571ac675e4"
|
||||
},
|
||||
"cargo/oracle-3/started.json": {
|
||||
"bytes": 1397,
|
||||
"sha256": "30cf614b6dede363ae4bdeca56fc4a1ddb7ee19a7e592b1b1616d4a98a53b535"
|
||||
},
|
||||
"cargo/oracle-3/stderr.log": {
|
||||
"bytes": 307,
|
||||
"sha256": "b4ccc583c5001d81b7208fe6f2e52788d0d40b63c7da034ca1fb90ec2adb18a4"
|
||||
},
|
||||
"cargo/oracle-3/stdout.log": {
|
||||
"bytes": 2968,
|
||||
"sha256": "e0a62ca8b008370c5a41378eb4c9e2a229a2fcde7bdba55426313c7d23da8aca"
|
||||
},
|
||||
"cargo/windows-build-1/process.json": {
|
||||
"bytes": 189,
|
||||
"sha256": "4e6b57dc0d5f10ac1b4af991f8b0f7558f4fc5b626e00f1a49c5782ea13abe18"
|
||||
},
|
||||
"cargo/windows-build-1/result.json": {
|
||||
"bytes": 3082,
|
||||
"sha256": "3cdd09a859288afe71dde6fb51bcc4bca84e47ceb9cb6389d57f6722d9e23fdf"
|
||||
},
|
||||
"cargo/windows-build-1/started.json": {
|
||||
"bytes": 1392,
|
||||
"sha256": "a3ebcdffc01e93fd5609005a0539eb11bf473b45bc28eee71dd175b943b387eb"
|
||||
},
|
||||
"cargo/windows-build-1/stderr.log": {
|
||||
"bytes": 319,
|
||||
"sha256": "7201ff3f71fe793907482992a00682023fc6ee1ac0a016f53a048b299ec2fffd"
|
||||
},
|
||||
"cargo/windows-build-1/stdout.log": {
|
||||
"bytes": 284182,
|
||||
"sha256": "3fc90b8c923415496c7990d33a5fe7211423b83df833a80111079fad71f04a2d"
|
||||
},
|
||||
"cargo/windows-build-2/process.json": {
|
||||
"bytes": 189,
|
||||
"sha256": "f18acb4c9feede438e1aa67bb86ce2d74f5b3aa0142499ae99b56b23daaf834b"
|
||||
},
|
||||
"cargo/windows-build-2/result.json": {
|
||||
"bytes": 3081,
|
||||
"sha256": "d7b191ee07c302ffed1017374b0c5d8b86245c0f3348fbac4778ae573397b9de"
|
||||
},
|
||||
"cargo/windows-build-2/started.json": {
|
||||
"bytes": 1392,
|
||||
"sha256": "b6a6656d966559060f01e87ccbd75837b0cf67e70c77246b20f587167bdbf651"
|
||||
},
|
||||
"cargo/windows-build-2/stderr.log": {
|
||||
"bytes": 137,
|
||||
"sha256": "aafe81cdd7c1e5558e957d4296d46e3238c72af79ba79d6147c5cc16f938d6ef"
|
||||
},
|
||||
"cargo/windows-build-2/stdout.log": {
|
||||
"bytes": 284179,
|
||||
"sha256": "cfba733cb79a9496004109bb0bc8b8996df5ec1645691fd79b952063faa519c5"
|
||||
},
|
||||
"helpers/6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06.py": {
|
||||
"bytes": 3502,
|
||||
"sha256": "6b8fcf64a1eb0869ae29abd66b4e89564a1813fef5898b54f2a17a3230dbaa06"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
"""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):
|
||||
gates = root / ".local/group-movement-gates"
|
||||
candidates = sorted(gates.glob("*.py")) + helpers
|
||||
helper_bytes = [path.read_bytes() for path in candidates]
|
||||
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
|
||||
for run in runs:
|
||||
folder = gates / run
|
||||
need(folder.is_dir(), "run directory missing: " + run)
|
||||
paths = list(folder.iterdir())
|
||||
need(all(path.is_file() and not path.is_symlink() for path in paths)
|
||||
and {path.name for path in paths} == RAW_FILES, "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
|
||||
manifest = {"schema": 1, "kind": "multiselect-cargo-gates", "runs": specs,
|
||||
"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, default=HERE.parents[3], help="checkout holding .local/group-movement-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("--output", type=Path, default=HERE, help="package directory; existing evidence is never overwritten")
|
||||
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")
|
||||
payload, manifest, summary = collect(args.root.resolve(), args.runs, args.helper)
|
||||
if args.check_only:
|
||||
print("PASS raw consistency; no package written:", summary)
|
||||
return
|
||||
out = args.output.resolve()
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
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,164 @@
|
||||
"""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"] == "multiselect-cargo-gates", "manifest schema")
|
||||
runs, logical, stored = manifest["runs"], manifest["logicalFiles"], manifest["members"]
|
||||
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())
|
||||
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])
|
||||
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")
|
||||
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), "logicalFiles": len(logical), "storedMembers": len(stored), "sourceCapsulePairs": len(seen_capsules)}
|
||||
|
||||
|
||||
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,35 @@
|
||||
# Run-2 baseline checker environment incident
|
||||
|
||||
The first baseline checker invocation exited `3221225781` (`0xC0000135`) at
|
||||
2026-09-23 09:07:10 UTC with empty stdout/stderr. The parent reported that this
|
||||
shell omitted dot-sourcing the toolchain `env.ps1`. After that environment setup,
|
||||
the same checker command succeeded at 09:08:08 UTC with a complete-Project PASS.
|
||||
This records a checker-process launch incident, not a failure of the running GUI.
|
||||
No particular missing DLL was measured or identified.
|
||||
|
||||
`run-2-baseline-runtime-environment/` is an exact copy of the failed snapshot:
|
||||
started/result receipts, empty streams and all nine source files. Its unchanged
|
||||
command text still names the original `run-2/snapshots/baseline` location; the
|
||||
parent moved the failed directory aside before retrying. Paths in these records
|
||||
are historical labels and have not been rewritten.
|
||||
|
||||
`retry-baseline/` preserves the successful retry's original started/result
|
||||
receipts and streams. Direct comparison confirmed identical command, build
|
||||
receipt, binary, helper, baseline and source pins between attempts. All three
|
||||
unchanged flags are true in both results. The nine retry source files were
|
||||
also compared byte for byte with the failed snapshot and are identical; they
|
||||
are not duplicated here. The successful run's complete snapshots belong in the
|
||||
separate native evidence package.
|
||||
|
||||
`helpers/check-snapshot-2.py` matches the helper pin in both receipts.
|
||||
`helpers/env.ps1` preserves the environment setup script available when this
|
||||
incident was packaged. It sets toolchain paths and runtime search paths and
|
||||
contains no credentials. The checker receipts do not record the environment or
|
||||
pin `env.ps1`, so the omitted/setup distinction is the parent's invocation
|
||||
observation, not an independently measured environment comparison. Both scripts
|
||||
are historical data; this package does not execute them.
|
||||
|
||||
The checker binary pin in both attempts is
|
||||
`4de47a2b62192be6a1394e654f368be19e36fb966d60d6c833a5d51d18247bb1`.
|
||||
`files.json` pins every included file except itself. Raw bytes are preserved.
|
||||
No frozen checks, source-identity or native packaging tools were changed.
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"helpers/check-snapshot-2.py": {
|
||||
"bytes": 2494,
|
||||
"sha256": "1dbfff41f07bd750d4e550660d91ae9790d2442fbfe685dc88b7f63a47f5acb8"
|
||||
},
|
||||
"helpers/env.ps1": {
|
||||
"bytes": 621,
|
||||
"sha256": "d7eb6249bef73adacdb05cebefe7ca478758c3c38de17a1731bf01f8b25dc379"
|
||||
},
|
||||
"README.md": {
|
||||
"bytes": 2146,
|
||||
"sha256": "d5a853c62713a6c87d28acfbe28c03bd95459275d0a2eb752d978e5a9b427bc8"
|
||||
},
|
||||
"retry-baseline/result.json": {
|
||||
"bytes": 2758,
|
||||
"sha256": "ae16cbc54bf5b6054750ef082f47bf0a26ee2dfb7bce46f19c8fd2c1ac622d7f"
|
||||
},
|
||||
"retry-baseline/started.json": {
|
||||
"bytes": 2356,
|
||||
"sha256": "e172a36f0872d49a8fe0f7200fb56d597b71fd1849dc9902d53ac1813a3c7d4a"
|
||||
},
|
||||
"retry-baseline/stderr.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"retry-baseline/stdout.log": {
|
||||
"bytes": 441,
|
||||
"sha256": "12842cc4e483e2546f5c8615b17fe72c5fe07f3fb4440469071433c82d9a9b30"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/result.json": {
|
||||
"bytes": 2765,
|
||||
"sha256": "539b950952461cc300876dbc45fa9ee02a9ecefb6d712fce6b74bad3fa701b30"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/source/oa/activities/activity_activity_a.arcadia": {
|
||||
"bytes": 474,
|
||||
"sha256": "9bf7c5637d87c97213cf869118e942e8a29a67b429fa58e4de42235bba0980ee"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/source/oa/activities/activity_activity_b.arcadia": {
|
||||
"bytes": 286,
|
||||
"sha256": "152007669b7c570674aff99615a48a6f557be50f88bbbb3a5edc20b423c79a1f"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/source/oa/activities/activity_activity_c.arcadia": {
|
||||
"bytes": 153,
|
||||
"sha256": "d726b6b4e1200edd9ef752bb767e38d3d69dcac8eb6135d5f83c93832ff849b1"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/source/project.arcadia": {
|
||||
"bytes": 597,
|
||||
"sha256": "e7bd67c5785a78766298255ed3d53ff6d65dcd24bde1570ac8a0ff45cc9dc385"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/source/sa/functions/function_sa_function.arcadia": {
|
||||
"bytes": 162,
|
||||
"sha256": "1c724a9204784435e729badd4ad164b1a6b891840bb1ddc354ac1e175e3d712c"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/source/traceability.arcadia": {
|
||||
"bytes": 522,
|
||||
"sha256": "26b0b10715ced7aefcde941e6d1c1a6973f174997eae989e32a25c695dfb7cd1"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/source/views/diagram_oa_other.arcadia": {
|
||||
"bytes": 315,
|
||||
"sha256": "06ceef9cfdbb3ef229a22db6c48d8bb808388e027c37294648555ecbfb6bfab9"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/source/views/diagram_oa_view.arcadia": {
|
||||
"bytes": 1896,
|
||||
"sha256": "4e7d47d6a03153070687136c89faf01fc6df45ae89e2695beeab2fe4872dbc88"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/source/views/diagram_sa_view.arcadia": {
|
||||
"bytes": 331,
|
||||
"sha256": "c75b0fe14496631c9b017a32e277d1e5ad5b25e00e06b804fc54d950d7fb57f6"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/started.json": {
|
||||
"bytes": 2356,
|
||||
"sha256": "338c14c7dc827bd4ab09009bb974ad3c481b07cdbad2437f5291b1ff67b5ba42"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/stderr.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"run-2-baseline-runtime-environment/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
"""Copy stable native-saved source and check its complete Project independently."""
|
||||
from pathlib import Path
|
||||
import datetime, hashlib, json, re, shutil, subprocess, sys
|
||||
root = Path('C:/ar-multiselect-9e8r6t')
|
||||
native = root / '.local/multiselect-native'
|
||||
label, mode, *rest = sys.argv[1:]
|
||||
assert not rest and re.fullmatch('[a-z0-9-]+', label)
|
||||
working = native / 'working-2'
|
||||
out = native / 'run-2/snapshots' / label
|
||||
out.mkdir(parents=True, exist_ok=False)
|
||||
gate_path = root / '.local/group-movement-gates/native-build-2/result.json'
|
||||
gate = json.loads(gate_path.read_bytes())
|
||||
assert gate['exitCode'] == 0 and gate['inputsUnchanged']
|
||||
artifact, = [a for a in gate['artifacts'] if a['cargo']['target']['name'] == 'multiselect_native']
|
||||
binary = Path(artifact['cargo']['executable'])
|
||||
baseline = native / 'fixture-2/baseline.json'
|
||||
def pin(path):
|
||||
b = path.read_bytes()
|
||||
return {'bytes': len(b), 'sha256': hashlib.sha256(b).hexdigest()}
|
||||
def inventory():
|
||||
return {p.relative_to(working).as_posix():pin(p) for p in sorted(working.rglob('*.arcadia')) if p.is_file()}
|
||||
def now(): return datetime.datetime.now(datetime.timezone.utc).isoformat()
|
||||
before = inventory()
|
||||
assert 'project.arcadia' in before and pin(binary) == artifact['readback']
|
||||
for name in before:
|
||||
target = out/'source'/name
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copyfile(working/name, target)
|
||||
assert before == inventory() == {name:pin(out/'source'/name) for name in before}
|
||||
command = [str(binary), 'check', mode, str(baseline), str(out/'source/project.arcadia')]
|
||||
start = {'start':now(), 'command':command, 'buildReceipt':pin(gate_path), 'binary':pin(binary), 'helper':pin(Path(__file__)), 'source':before, 'baseline':pin(baseline)}
|
||||
(out/'started.json').write_text(json.dumps(start,indent=2),encoding='utf-8')
|
||||
r = subprocess.run(command,cwd=root,capture_output=True)
|
||||
(out/'stdout.log').write_bytes(r.stdout)
|
||||
(out/'stderr.log').write_bytes(r.stderr)
|
||||
result = {**start, 'finish':now(), 'exitCode':r.returncode, 'binaryUnchanged':pin(binary)==artifact['readback'], 'workingSourceUnchanged':before==inventory(), 'baselineUnchanged':pin(baseline)==start['baseline'], 'stdout':pin(out/'stdout.log'), 'stderr':pin(out/'stderr.log')}
|
||||
(out/'result.json').write_text(json.dumps(result,indent=2),encoding='utf-8')
|
||||
print(r.stdout.decode(errors='replace'))
|
||||
print(r.stderr.decode(errors='replace'))
|
||||
assert result['binaryUnchanged'] and result['workingSourceUnchanged'] and result['baselineUnchanged']
|
||||
sys.exit(r.returncode)
|
||||
@@ -0,0 +1,9 @@
|
||||
$taskRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
|
||||
$env:RUSTUP_HOME = Join-Path $taskRoot '.local\toolchain\rustup'
|
||||
$env:CARGO_HOME = Join-Path $taskRoot '.local\toolchain\cargo'
|
||||
$env:RUSTUP_TOOLCHAIN = 'stable-x86_64-pc-windows-gnullvm'
|
||||
$env:PATH = "$env:CARGO_HOME\bin;$(Join-Path $taskRoot '.local\toolchain\llvm-mingw-20260826-ucrt-x86_64\bin');$env:PATH"
|
||||
$env:CARGO_TARGET_DIR = Join-Path $taskRoot '.local\target-gnullvm'
|
||||
# Keep this small development disk from accumulating multi-GiB incremental caches.
|
||||
$env:CARGO_INCREMENTAL = '0'
|
||||
$env:CARGO_TARGET_X86_64_PC_WINDOWS_GNULLVM_LINKER = 'clang.exe'
|
||||
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"start": "2026-09-23T09:08:07.906733+00:00",
|
||||
"command": [
|
||||
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\target-gnullvm\\debug\\examples\\multiselect_native.exe",
|
||||
"check",
|
||||
"unchanged",
|
||||
"C:\\ar-multiselect-9e8r6t\\.local\\multiselect-native\\fixture-2\\baseline.json",
|
||||
"C:\\ar-multiselect-9e8r6t\\.local\\multiselect-native\\run-2\\snapshots\\baseline\\source\\project.arcadia"
|
||||
],
|
||||
"buildReceipt": {
|
||||
"bytes": 3131,
|
||||
"sha256": "fbecac3b0f7913db5e2ad19043c7df167a92287833ddf3ea4f24766e86ae523b"
|
||||
},
|
||||
"binary": {
|
||||
"bytes": 22162432,
|
||||
"sha256": "4de47a2b62192be6a1394e654f368be19e36fb966d60d6c833a5d51d18247bb1"
|
||||
},
|
||||
"helper": {
|
||||
"bytes": 2494,
|
||||
"sha256": "1dbfff41f07bd750d4e550660d91ae9790d2442fbfe685dc88b7f63a47f5acb8"
|
||||
},
|
||||
"source": {
|
||||
"oa/activities/activity_activity_a.arcadia": {
|
||||
"bytes": 474,
|
||||
"sha256": "9bf7c5637d87c97213cf869118e942e8a29a67b429fa58e4de42235bba0980ee"
|
||||
},
|
||||
"oa/activities/activity_activity_b.arcadia": {
|
||||
"bytes": 286,
|
||||
"sha256": "152007669b7c570674aff99615a48a6f557be50f88bbbb3a5edc20b423c79a1f"
|
||||
},
|
||||
"oa/activities/activity_activity_c.arcadia": {
|
||||
"bytes": 153,
|
||||
"sha256": "d726b6b4e1200edd9ef752bb767e38d3d69dcac8eb6135d5f83c93832ff849b1"
|
||||
},
|
||||
"project.arcadia": {
|
||||
"bytes": 597,
|
||||
"sha256": "e7bd67c5785a78766298255ed3d53ff6d65dcd24bde1570ac8a0ff45cc9dc385"
|
||||
},
|
||||
"sa/functions/function_sa_function.arcadia": {
|
||||
"bytes": 162,
|
||||
"sha256": "1c724a9204784435e729badd4ad164b1a6b891840bb1ddc354ac1e175e3d712c"
|
||||
},
|
||||
"traceability.arcadia": {
|
||||
"bytes": 522,
|
||||
"sha256": "26b0b10715ced7aefcde941e6d1c1a6973f174997eae989e32a25c695dfb7cd1"
|
||||
},
|
||||
"views/diagram_oa_other.arcadia": {
|
||||
"bytes": 315,
|
||||
"sha256": "06ceef9cfdbb3ef229a22db6c48d8bb808388e027c37294648555ecbfb6bfab9"
|
||||
},
|
||||
"views/diagram_oa_view.arcadia": {
|
||||
"bytes": 1896,
|
||||
"sha256": "4e7d47d6a03153070687136c89faf01fc6df45ae89e2695beeab2fe4872dbc88"
|
||||
},
|
||||
"views/diagram_sa_view.arcadia": {
|
||||
"bytes": 331,
|
||||
"sha256": "c75b0fe14496631c9b017a32e277d1e5ad5b25e00e06b804fc54d950d7fb57f6"
|
||||
}
|
||||
},
|
||||
"baseline": {
|
||||
"bytes": 8944,
|
||||
"sha256": "d1278e58cd31e1d61093292eddc1d7b2cc9c8cdc7fe5dd3801de8411af8db89d"
|
||||
},
|
||||
"finish": "2026-09-23T09:08:08.158861+00:00",
|
||||
"exitCode": 0,
|
||||
"binaryUnchanged": true,
|
||||
"workingSourceUnchanged": true,
|
||||
"baselineUnchanged": true,
|
||||
"stdout": {
|
||||
"bytes": 441,
|
||||
"sha256": "12842cc4e483e2546f5c8615b17fe72c5fe07f3fb4440469071433c82d9a9b30"
|
||||
},
|
||||
"stderr": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"start": "2026-09-23T09:08:07.906733+00:00",
|
||||
"command": [
|
||||
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\target-gnullvm\\debug\\examples\\multiselect_native.exe",
|
||||
"check",
|
||||
"unchanged",
|
||||
"C:\\ar-multiselect-9e8r6t\\.local\\multiselect-native\\fixture-2\\baseline.json",
|
||||
"C:\\ar-multiselect-9e8r6t\\.local\\multiselect-native\\run-2\\snapshots\\baseline\\source\\project.arcadia"
|
||||
],
|
||||
"buildReceipt": {
|
||||
"bytes": 3131,
|
||||
"sha256": "fbecac3b0f7913db5e2ad19043c7df167a92287833ddf3ea4f24766e86ae523b"
|
||||
},
|
||||
"binary": {
|
||||
"bytes": 22162432,
|
||||
"sha256": "4de47a2b62192be6a1394e654f368be19e36fb966d60d6c833a5d51d18247bb1"
|
||||
},
|
||||
"helper": {
|
||||
"bytes": 2494,
|
||||
"sha256": "1dbfff41f07bd750d4e550660d91ae9790d2442fbfe685dc88b7f63a47f5acb8"
|
||||
},
|
||||
"source": {
|
||||
"oa/activities/activity_activity_a.arcadia": {
|
||||
"bytes": 474,
|
||||
"sha256": "9bf7c5637d87c97213cf869118e942e8a29a67b429fa58e4de42235bba0980ee"
|
||||
},
|
||||
"oa/activities/activity_activity_b.arcadia": {
|
||||
"bytes": 286,
|
||||
"sha256": "152007669b7c570674aff99615a48a6f557be50f88bbbb3a5edc20b423c79a1f"
|
||||
},
|
||||
"oa/activities/activity_activity_c.arcadia": {
|
||||
"bytes": 153,
|
||||
"sha256": "d726b6b4e1200edd9ef752bb767e38d3d69dcac8eb6135d5f83c93832ff849b1"
|
||||
},
|
||||
"project.arcadia": {
|
||||
"bytes": 597,
|
||||
"sha256": "e7bd67c5785a78766298255ed3d53ff6d65dcd24bde1570ac8a0ff45cc9dc385"
|
||||
},
|
||||
"sa/functions/function_sa_function.arcadia": {
|
||||
"bytes": 162,
|
||||
"sha256": "1c724a9204784435e729badd4ad164b1a6b891840bb1ddc354ac1e175e3d712c"
|
||||
},
|
||||
"traceability.arcadia": {
|
||||
"bytes": 522,
|
||||
"sha256": "26b0b10715ced7aefcde941e6d1c1a6973f174997eae989e32a25c695dfb7cd1"
|
||||
},
|
||||
"views/diagram_oa_other.arcadia": {
|
||||
"bytes": 315,
|
||||
"sha256": "06ceef9cfdbb3ef229a22db6c48d8bb808388e027c37294648555ecbfb6bfab9"
|
||||
},
|
||||
"views/diagram_oa_view.arcadia": {
|
||||
"bytes": 1896,
|
||||
"sha256": "4e7d47d6a03153070687136c89faf01fc6df45ae89e2695beeab2fe4872dbc88"
|
||||
},
|
||||
"views/diagram_sa_view.arcadia": {
|
||||
"bytes": 331,
|
||||
"sha256": "c75b0fe14496631c9b017a32e277d1e5ad5b25e00e06b804fc54d950d7fb57f6"
|
||||
}
|
||||
},
|
||||
"baseline": {
|
||||
"bytes": 8944,
|
||||
"sha256": "d1278e58cd31e1d61093292eddc1d7b2cc9c8cdc7fe5dd3801de8411af8db89d"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"baseline": "C:\\ar-multiselect-9e8r6t\\.local\\multiselect-native\\fixture-2\\baseline.json",
|
||||
"comparison": "complete Project equality",
|
||||
"inferred_common_delta": null,
|
||||
"limits": "Invariant evaluator only; no pointer/action/focus/Undo/source-byte acceptance claim",
|
||||
"mode": "unchanged",
|
||||
"result": "PASS",
|
||||
"saved": "C:\\ar-multiselect-9e8r6t\\.local\\multiselect-native\\run-2\\snapshots\\baseline\\source\\project.arcadia"
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"start": "2026-09-23T09:07:10.546708+00:00",
|
||||
"command": [
|
||||
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\target-gnullvm\\debug\\examples\\multiselect_native.exe",
|
||||
"check",
|
||||
"unchanged",
|
||||
"C:\\ar-multiselect-9e8r6t\\.local\\multiselect-native\\fixture-2\\baseline.json",
|
||||
"C:\\ar-multiselect-9e8r6t\\.local\\multiselect-native\\run-2\\snapshots\\baseline\\source\\project.arcadia"
|
||||
],
|
||||
"buildReceipt": {
|
||||
"bytes": 3131,
|
||||
"sha256": "fbecac3b0f7913db5e2ad19043c7df167a92287833ddf3ea4f24766e86ae523b"
|
||||
},
|
||||
"binary": {
|
||||
"bytes": 22162432,
|
||||
"sha256": "4de47a2b62192be6a1394e654f368be19e36fb966d60d6c833a5d51d18247bb1"
|
||||
},
|
||||
"helper": {
|
||||
"bytes": 2494,
|
||||
"sha256": "1dbfff41f07bd750d4e550660d91ae9790d2442fbfe685dc88b7f63a47f5acb8"
|
||||
},
|
||||
"source": {
|
||||
"oa/activities/activity_activity_a.arcadia": {
|
||||
"bytes": 474,
|
||||
"sha256": "9bf7c5637d87c97213cf869118e942e8a29a67b429fa58e4de42235bba0980ee"
|
||||
},
|
||||
"oa/activities/activity_activity_b.arcadia": {
|
||||
"bytes": 286,
|
||||
"sha256": "152007669b7c570674aff99615a48a6f557be50f88bbbb3a5edc20b423c79a1f"
|
||||
},
|
||||
"oa/activities/activity_activity_c.arcadia": {
|
||||
"bytes": 153,
|
||||
"sha256": "d726b6b4e1200edd9ef752bb767e38d3d69dcac8eb6135d5f83c93832ff849b1"
|
||||
},
|
||||
"project.arcadia": {
|
||||
"bytes": 597,
|
||||
"sha256": "e7bd67c5785a78766298255ed3d53ff6d65dcd24bde1570ac8a0ff45cc9dc385"
|
||||
},
|
||||
"sa/functions/function_sa_function.arcadia": {
|
||||
"bytes": 162,
|
||||
"sha256": "1c724a9204784435e729badd4ad164b1a6b891840bb1ddc354ac1e175e3d712c"
|
||||
},
|
||||
"traceability.arcadia": {
|
||||
"bytes": 522,
|
||||
"sha256": "26b0b10715ced7aefcde941e6d1c1a6973f174997eae989e32a25c695dfb7cd1"
|
||||
},
|
||||
"views/diagram_oa_other.arcadia": {
|
||||
"bytes": 315,
|
||||
"sha256": "06ceef9cfdbb3ef229a22db6c48d8bb808388e027c37294648555ecbfb6bfab9"
|
||||
},
|
||||
"views/diagram_oa_view.arcadia": {
|
||||
"bytes": 1896,
|
||||
"sha256": "4e7d47d6a03153070687136c89faf01fc6df45ae89e2695beeab2fe4872dbc88"
|
||||
},
|
||||
"views/diagram_sa_view.arcadia": {
|
||||
"bytes": 331,
|
||||
"sha256": "c75b0fe14496631c9b017a32e277d1e5ad5b25e00e06b804fc54d950d7fb57f6"
|
||||
}
|
||||
},
|
||||
"baseline": {
|
||||
"bytes": 8944,
|
||||
"sha256": "d1278e58cd31e1d61093292eddc1d7b2cc9c8cdc7fe5dd3801de8411af8db89d"
|
||||
},
|
||||
"finish": "2026-09-23T09:07:10.828848+00:00",
|
||||
"exitCode": 3221225781,
|
||||
"binaryUnchanged": true,
|
||||
"workingSourceUnchanged": true,
|
||||
"baselineUnchanged": true,
|
||||
"stdout": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"stderr": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
oa_activity activity_a "A - receive request" id "f0149281-4798-58d3-acff-131eed250959" {
|
||||
description "Preserve engineering record activity_a.";
|
||||
}
|
||||
|
||||
oa_activity activity_child "A.1 - classify request" id "5a80d3af-c7ee-59eb-9680-eb80d60cb94f" {
|
||||
description "Preserve engineering record activity_child.";
|
||||
parent @activity_a;
|
||||
}
|
||||
|
||||
interaction internal "Request assessment" id "be7a39d9-3463-534e-b37b-76a74077d434" {
|
||||
source @activity_a;
|
||||
target @activity_b;
|
||||
}
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
oa_activity activity_b "B - assess request" id "ecf076b7-e8be-5f64-8808-6a2edae5b9e2" {
|
||||
description "Preserve engineering record activity_b.";
|
||||
}
|
||||
|
||||
interaction external "Response decision" id "927dfa82-40d2-5c5f-a525-6a884725ea1d" {
|
||||
source @activity_b;
|
||||
target @activity_c;
|
||||
}
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
oa_activity activity_c "C - dispatch response" id "3b258d00-854d-5ddd-a057-16eedbe31714" {
|
||||
description "Preserve engineering record activity_c.";
|
||||
}
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
arcadia 7;
|
||||
project multiselect_native "Multiselect native" id "c1deb118-0fb0-5692-8b80-d24339e5b6c3" {
|
||||
description "Shift-select A and B; move together, retain C and engineering semantics.";
|
||||
include "oa/activities/activity_activity_a.arcadia";
|
||||
include "oa/activities/activity_activity_b.arcadia";
|
||||
include "oa/activities/activity_activity_c.arcadia";
|
||||
include "sa/functions/function_sa_function.arcadia";
|
||||
include "traceability.arcadia";
|
||||
include "views/diagram_oa_other.arcadia";
|
||||
include "views/diagram_oa_view.arcadia";
|
||||
include "views/diagram_sa_view.arcadia";
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
sa_function sa_function "Technical request processing" id "878a1b33-a7c2-5a68-a8b6-d8273c6354e0" {
|
||||
description "Preserve engineering record sa_function.";
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
trace preserved_refinement "Reviewed request refinement" id "b42fb6e3-db90-5349-b957-faeba373ba91" {
|
||||
baseline {
|
||||
oa {
|
||||
description "Preserve engineering record activity_a.";
|
||||
name "A - receive request";
|
||||
};
|
||||
sa {
|
||||
description "Preserve engineering record sa_function.";
|
||||
name "Technical request processing";
|
||||
};
|
||||
};
|
||||
description "Group geometry and Hide preserve this trace and both endpoints.";
|
||||
oa @activity_a;
|
||||
sa @sa_function;
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
diagram oa_other "Other OA view - preserve" id "c4a58011-d2d7-59b1-ad58-feacef0e2d78" {
|
||||
description "Selection changes placement geometry only.";
|
||||
}
|
||||
|
||||
node other_a id "9aa9a68b-4c26-5d21-bc35-63d3f0f311d6" {
|
||||
diagram @oa_other;
|
||||
element @activity_a;
|
||||
position {
|
||||
x 40.0;
|
||||
y 60.0;
|
||||
};
|
||||
}
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
diagram oa_view "Multiselect native - OA overview" id "00000000-0000-0000-0000-000000290001" {
|
||||
description "Selection changes placement geometry only.";
|
||||
routes [{
|
||||
edge @internal;
|
||||
label {
|
||||
fraction 0.44999998807907104;
|
||||
offset {
|
||||
x 7.0;
|
||||
y -19.0;
|
||||
};
|
||||
};
|
||||
source_attachment {
|
||||
offset 0.25;
|
||||
side Right;
|
||||
};
|
||||
target_attachment {
|
||||
offset 0.699999988079071;
|
||||
side Left;
|
||||
};
|
||||
waypoints [{
|
||||
x 420.0;
|
||||
y 145.0;
|
||||
}, {
|
||||
x 420.0;
|
||||
y 186.0;
|
||||
}];
|
||||
}, {
|
||||
edge @external;
|
||||
label {
|
||||
fraction 0.44999998807907104;
|
||||
offset {
|
||||
x 7.0;
|
||||
y -19.0;
|
||||
};
|
||||
};
|
||||
source_attachment {
|
||||
offset 0.25;
|
||||
side Right;
|
||||
};
|
||||
target_attachment {
|
||||
offset 0.699999988079071;
|
||||
side Left;
|
||||
};
|
||||
waypoints [{
|
||||
x 725.0;
|
||||
y 150.0;
|
||||
}, {
|
||||
x 725.0;
|
||||
y 336.0;
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
node node_a id "2670dd46-9fe7-5047-b13d-59817cff96dd" {
|
||||
diagram @oa_view;
|
||||
element @activity_a;
|
||||
position {
|
||||
x 80.0;
|
||||
y 80.0;
|
||||
};
|
||||
size {
|
||||
height 260.0;
|
||||
width 310.0;
|
||||
};
|
||||
}
|
||||
|
||||
node node_b id "70e322db-f401-58c8-a50e-2f71c61ad721" {
|
||||
diagram @oa_view;
|
||||
element @activity_b;
|
||||
position {
|
||||
x 470.0;
|
||||
y 120.0;
|
||||
};
|
||||
}
|
||||
|
||||
node node_c id "d6b89a5a-6e2f-50f9-9d1e-993304a54583" {
|
||||
diagram @oa_view;
|
||||
element @activity_c;
|
||||
position {
|
||||
x 780.0;
|
||||
y 270.0;
|
||||
};
|
||||
}
|
||||
|
||||
node node_child id "87f4652b-15ef-55ed-ad7e-cc5d22b7facb" {
|
||||
diagram @oa_view;
|
||||
element @activity_child;
|
||||
position {
|
||||
x 120.0;
|
||||
y 210.0;
|
||||
};
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
diagram sa_view "SA engineering - preserve" id "637b9a3e-bd74-534c-9be5-4470a408729f" {
|
||||
description "Selection changes placement geometry only.";
|
||||
layer Sa;
|
||||
}
|
||||
|
||||
node sa_node id "5f1b1c24-0583-5923-a69c-d0ea99ccb18c" {
|
||||
diagram @sa_view;
|
||||
element @sa_function;
|
||||
position {
|
||||
x 100.0;
|
||||
y 110.0;
|
||||
};
|
||||
}
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"start": "2026-09-23T09:07:10.546708+00:00",
|
||||
"command": [
|
||||
"C:\\Users\\User\\Documents\\Git\\ARCADIA-Studio\\.local\\target-gnullvm\\debug\\examples\\multiselect_native.exe",
|
||||
"check",
|
||||
"unchanged",
|
||||
"C:\\ar-multiselect-9e8r6t\\.local\\multiselect-native\\fixture-2\\baseline.json",
|
||||
"C:\\ar-multiselect-9e8r6t\\.local\\multiselect-native\\run-2\\snapshots\\baseline\\source\\project.arcadia"
|
||||
],
|
||||
"buildReceipt": {
|
||||
"bytes": 3131,
|
||||
"sha256": "fbecac3b0f7913db5e2ad19043c7df167a92287833ddf3ea4f24766e86ae523b"
|
||||
},
|
||||
"binary": {
|
||||
"bytes": 22162432,
|
||||
"sha256": "4de47a2b62192be6a1394e654f368be19e36fb966d60d6c833a5d51d18247bb1"
|
||||
},
|
||||
"helper": {
|
||||
"bytes": 2494,
|
||||
"sha256": "1dbfff41f07bd750d4e550660d91ae9790d2442fbfe685dc88b7f63a47f5acb8"
|
||||
},
|
||||
"source": {
|
||||
"oa/activities/activity_activity_a.arcadia": {
|
||||
"bytes": 474,
|
||||
"sha256": "9bf7c5637d87c97213cf869118e942e8a29a67b429fa58e4de42235bba0980ee"
|
||||
},
|
||||
"oa/activities/activity_activity_b.arcadia": {
|
||||
"bytes": 286,
|
||||
"sha256": "152007669b7c570674aff99615a48a6f557be50f88bbbb3a5edc20b423c79a1f"
|
||||
},
|
||||
"oa/activities/activity_activity_c.arcadia": {
|
||||
"bytes": 153,
|
||||
"sha256": "d726b6b4e1200edd9ef752bb767e38d3d69dcac8eb6135d5f83c93832ff849b1"
|
||||
},
|
||||
"project.arcadia": {
|
||||
"bytes": 597,
|
||||
"sha256": "e7bd67c5785a78766298255ed3d53ff6d65dcd24bde1570ac8a0ff45cc9dc385"
|
||||
},
|
||||
"sa/functions/function_sa_function.arcadia": {
|
||||
"bytes": 162,
|
||||
"sha256": "1c724a9204784435e729badd4ad164b1a6b891840bb1ddc354ac1e175e3d712c"
|
||||
},
|
||||
"traceability.arcadia": {
|
||||
"bytes": 522,
|
||||
"sha256": "26b0b10715ced7aefcde941e6d1c1a6973f174997eae989e32a25c695dfb7cd1"
|
||||
},
|
||||
"views/diagram_oa_other.arcadia": {
|
||||
"bytes": 315,
|
||||
"sha256": "06ceef9cfdbb3ef229a22db6c48d8bb808388e027c37294648555ecbfb6bfab9"
|
||||
},
|
||||
"views/diagram_oa_view.arcadia": {
|
||||
"bytes": 1896,
|
||||
"sha256": "4e7d47d6a03153070687136c89faf01fc6df45ae89e2695beeab2fe4872dbc88"
|
||||
},
|
||||
"views/diagram_sa_view.arcadia": {
|
||||
"bytes": 331,
|
||||
"sha256": "c75b0fe14496631c9b017a32e277d1e5ad5b25e00e06b804fc54d950d7fb57f6"
|
||||
}
|
||||
},
|
||||
"baseline": {
|
||||
"bytes": 8944,
|
||||
"sha256": "d1278e58cd31e1d61093292eddc1d7b2cc9c8cdc7fe5dd3801de8411af8db89d"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
# Native multiselect evidence package
|
||||
|
||||
This package preserves native run-1 and run-2, both closed with exit 0, empty app
|
||||
stdout/stderr and all three GUI/checker/fixture unchanged flags true. Each run
|
||||
contains nine positive complete-Project checker snapshots, nine source files per
|
||||
snapshot and three exact source-history equality groups. Only
|
||||
`views/diagram_oa_view.arcadia` differs from baseline in its move and hidden
|
||||
states. These artifacts do not establish native acceptance on their own; consult
|
||||
the separate [saved-view report](../../../multiselect-saved-view-20260923.md) for
|
||||
action observations, usability findings and the implemented subset of issue 29.
|
||||
|
||||
| Run | Source commit | Captures | Layout scope |
|
||||
| --- | --- | ---: | --- |
|
||||
| run-1 | `12a7352ddef5f69a144ead8219a50916233d63a9` | 27 | Before selection/status toolbar correction |
|
||||
| run-2 | `f6a6010baed9e6164a1fcc7ecd58256a562827d7` | 24 | Corrected toolbar layout build |
|
||||
|
||||
Run-1 GUI/checker build receipts refer to the 729-file input map
|
||||
`55a5f354bb5049a8c77ba9bafa833438ebf754649b0cf5d175d0c8dcfcedd7bb`;
|
||||
run-2 refers to the distinct 729-file map
|
||||
`99dc46645236e674244e7c4867595a6000d3d85b54bcc9ab2b0c601923ecf66c`.
|
||||
The [source identity evidence](../source/README.md) ties those maps to the commits
|
||||
above. The GUI binary pins differ; the recorded checker binary pins match.
|
||||
Run-1 is retained as evidence of the earlier layout, not as verification of the
|
||||
corrected build.
|
||||
|
||||
The first run-2 baseline checker attempt failed before the successful retry after
|
||||
the toolchain environment was initialized. Its unchanged raw snapshot and retry
|
||||
comparison are preserved separately in the [environment incident](../incidents/README.md).
|
||||
The successful retry is the baseline snapshot included in this native package;
|
||||
the failed invocation is not silently reclassified or presented as a GUI failure.
|
||||
|
||||
These Python 3.10+ standard-library tools never operate the GUI or rerun the model
|
||||
checker. From the checkout root, validate both raw runs without writing a package:
|
||||
|
||||
```text
|
||||
python -B harness/experiments/multiselect-20260923/native/prepare.py --root . --runs run-1 run-2 --check-only
|
||||
```
|
||||
|
||||
Omit `--check-only` to package; optionally choose `--output DIRECTORY`. The default
|
||||
is this native directory. Existing package outputs are not overwritten. A missing
|
||||
or unfinished run, changed recorded inputs, missing/extra fixture or snapshot
|
||||
files, unmatched helper bytes, or inconsistent receipts fails preparation.
|
||||
|
||||
Verify a completed package independently of the original machine:
|
||||
|
||||
```text
|
||||
python -B PATH_TO_PACKAGE/verify.py
|
||||
```
|
||||
|
||||
Each run includes all original capture JSON/images, process/start/finish records,
|
||||
generation and app streams, all nine source snapshots and checker streams/receipts,
|
||||
and the history-bytes record. Its fixture includes baseline JSON, the manifest,
|
||||
and canonical source files. Exact helpers are found by their recorded hashes among
|
||||
the native directory's `.py`/`.js` files, so original and suffixed run-2 helpers can
|
||||
coexist. Helpers are archived as data and never executed by these tools.
|
||||
|
||||
Referenced GUI/checker build results, exact gate helpers and input maps are
|
||||
included. The checker example is read from its pinned historical input ZIP, not
|
||||
from current source.
|
||||
Full build logs and large source ZIPs belong in the sibling `checks` package;
|
||||
verify that package separately. This package validates build receipt, input map,
|
||||
example-source and executable-pin relationships without duplicating those ZIPs.
|
||||
It does not contain or execute the GUI/checker binaries.
|
||||
|
||||
The verifier checks every archived byte pin and exact safe membership, clean
|
||||
recorded exit and unchanged flags, process and capture lifetimes, each capture's
|
||||
normalized executable path against the launched GUI, one consistent positive
|
||||
window ID per run, fixture/source inventories, nine positive complete-Project
|
||||
checker reports, baseline/binary/helper
|
||||
relationships, and the actual archived bytes in three history equality groups.
|
||||
It verifies that only `views/diagram_oa_view.arcadia` differs from baseline in the
|
||||
move and hidden source states, and that baseline source bytes match the fixture.
|
||||
Window identity checks join recorded metadata; the receipts do not independently
|
||||
map that window handle to the recorded PID. Source models are not recompiled by
|
||||
this offline Python verifier. Screenshot dimensions are recorded metadata, not a
|
||||
minimum-window usability evaluation.
|
||||
|
||||
`manifest.json` maps each run's original historical paths to archived run,
|
||||
fixture, helper, build and checker-source members and pins their bytes.
|
||||
`files.json` pins the packager, verifier, README, manifest and archive. Raw bytes
|
||||
are preserved; ZIP ordering and timestamps are fixed. Historic absolute paths are
|
||||
labels and are not accessed by offline verification.
|
||||
|
||||
GUI actions remain separately documented parent observations. Screenshots do
|
||||
not prove which inputs occurred, and the checker infers a bounded common delta
|
||||
from saved geometry; it cannot validate the exact pointer destination. Source
|
||||
history byte equality supports the stated saved-state relationships but does not
|
||||
independently authenticate button presses, focus behavior or Undo stack structure.
|
||||
Run-1 evidence does not establish the corrected toolbar's usability or any later
|
||||
binary's behavior. Consult the parent report for the evaluated version, observed
|
||||
limitations, run differences and the remaining full-issue acceptance work.
|
||||
Binary file not shown.
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"prepare.py": {
|
||||
"bytes": 7237,
|
||||
"sha256": "d9d49d3082e485e670b43010822ebd3ab7a79762b36a247dcd3bdfc6b5d7f41d"
|
||||
},
|
||||
"verify.py": {
|
||||
"bytes": 14703,
|
||||
"sha256": "7ef5f28b6c9a43bf0361eec2d8be33a1e9f284d0ffc21b50fd09a2d082642ce3"
|
||||
},
|
||||
"README.md": {
|
||||
"bytes": 5418,
|
||||
"sha256": "8d6fa25d8bd97c654e78b89194bd499637427ce027157d568215e13421b22c03"
|
||||
},
|
||||
"manifest.json": {
|
||||
"bytes": 72794,
|
||||
"sha256": "de7642ad43aa881f7d984629db52ea41b62d0ebacc09260edd80a5c1fee7dd7b"
|
||||
},
|
||||
"evidence.zip": {
|
||||
"bytes": 4399281,
|
||||
"sha256": "7dc3e0571179e0f67fefe3c73462308b79e4c7f7a09bbd805e0acf0e4faeb1cf"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,129 @@
|
||||
"""Package explicit completed native runs; helpers are pinned data, never executed."""
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import zipfile
|
||||
from verify import pin, parsed, need, norm, relative, safe, verify_data, verify_package
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
|
||||
|
||||
def collect(root, runs):
|
||||
native = root / ".local/multiselect-native"
|
||||
candidates = [path for path in native.iterdir() if path.is_file() and path.suffix in (".py", ".js")]
|
||||
candidates.extend(sorted((root / ".local/group-movement-gates").glob("*.py")))
|
||||
helpers = [(path.suffix, path.read_bytes()) for path in candidates]
|
||||
payload, specs = {}, {}
|
||||
def add(name, data):
|
||||
need(safe(name) and (name not in payload or payload[name] == data), "member collision: " + name)
|
||||
payload[name] = data
|
||||
def tree(folder, prefix):
|
||||
need(folder.is_dir(), "missing directory: " + str(folder))
|
||||
for path in sorted(folder.rglob("*")):
|
||||
need(not path.is_symlink(), "symlink evidence input")
|
||||
if path.is_file():
|
||||
add(prefix + path.relative_to(folder).as_posix(), path.read_bytes())
|
||||
for run in runs:
|
||||
folder = native / run
|
||||
start = parsed((folder / "started.json").read_bytes())
|
||||
end = parsed((folder / "finished.json").read_bytes())
|
||||
need(end["exitCode"] == 0 and all(end[k] is True for k in
|
||||
("guiUnchanged", "checkerUnchanged", "fixtureUnchanged")), "unfinished/changed native run: " + run)
|
||||
generation = parsed((folder / "generation.json").read_bytes())
|
||||
history = parsed((folder / "history-bytes.json").read_bytes())
|
||||
tree(folder, "runs/" + run + "/raw/")
|
||||
fixture_relative = relative(generation["command"][2], start["cwd"])
|
||||
need(fixture_relative.startswith(".local/multiselect-native/"), "fixture outside native root")
|
||||
tree(root / fixture_relative, "runs/" + run + "/fixture/")
|
||||
spec = {"originalRun": norm(start["cwd"]) + "/.local/multiselect-native/" + run,
|
||||
"originalFixture": norm(generation["command"][2]), "helpers": {}, "builds": {}}
|
||||
for key, expected in [("helper", start["helper"]), ("capture", start["capture"]),
|
||||
("snapshotHelper", start["snapshotHelper"]), ("history", history["helper"])]:
|
||||
matches = [(suffix, data) for suffix, data in helpers if pin(data) == expected]
|
||||
need(bool(matches), "exact historical helper unavailable: " + key)
|
||||
suffix, data = matches[0]
|
||||
member = "helpers/" + expected["sha256"] + suffix
|
||||
add(member, data)
|
||||
spec["helpers"][key] = member
|
||||
for kind in ("gui", "checker"):
|
||||
recorded = start[kind]
|
||||
rel = relative(recorded["receipt"], start["cwd"])
|
||||
need(rel.startswith(".local/group-movement-gates/") and rel.endswith("/result.json"), "unexpected build receipt location")
|
||||
receipt = root / rel
|
||||
data = receipt.read_bytes()
|
||||
need(pin(data) == recorded["receiptPin"], "historical build receipt changed")
|
||||
prefix = "builds/" + pin(data)["sha256"] + "/"
|
||||
add(prefix + "result.json", data)
|
||||
inputs_data = (receipt.parent / "inputs.json").read_bytes()
|
||||
need(pin(inputs_data) == recorded["inputs"], "historical build input map changed")
|
||||
add(prefix + "inputs.json", inputs_data)
|
||||
spec["builds"][kind] = {"receipt": prefix + "result.json", "inputs": prefix + "inputs.json", "originalRelative": rel}
|
||||
build_helper = parsed(data)["helper"]
|
||||
matching_helpers = [(suffix, value) for suffix, value in helpers if pin(value) == build_helper]
|
||||
need(bool(matching_helpers), "exact historical build helper unavailable")
|
||||
suffix, helper_data = matching_helpers[0]
|
||||
helper_member = "helpers/" + build_helper["sha256"] + suffix
|
||||
add(helper_member, helper_data)
|
||||
spec["builds"][kind]["helper"] = helper_member
|
||||
if kind == "checker":
|
||||
# Read only the pinned historical example, not today's checkout.
|
||||
archive_path = receipt.parent / "inputs.zip"
|
||||
need(pin(archive_path.read_bytes()) == parsed(data)["archive"], "checker input archive pin")
|
||||
source_path = "crates/oa-core/examples/multiselect_native.rs"
|
||||
with zipfile.ZipFile(archive_path) as archive:
|
||||
source = archive.read(source_path)
|
||||
need(pin(source) == parsed(inputs_data)[source_path], "historical checker source pin")
|
||||
member = "checker-source/" + pin(source)["sha256"] + ".rs"
|
||||
add(member, source)
|
||||
spec["checkerSource"] = {"inputPath": source_path, "member": member}
|
||||
specs[run] = spec
|
||||
manifest = {"schema": 1, "kind": "multiselect-native", "runs": specs,
|
||||
"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 stream:
|
||||
stream.write((json.dumps(value, indent=2) + "\n").encode())
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--root", type=Path, default=HERE.parents[3])
|
||||
parser.add_argument("--runs", nargs="+", required=True)
|
||||
parser.add_argument("--output", type=Path, default=HERE)
|
||||
parser.add_argument("--check-only", action="store_true")
|
||||
args = parser.parse_args()
|
||||
need(len(args.runs) == len(set(args.runs)) and all(re.fullmatch(r"run-[0-9]+", name) for name in args.runs), "explicit unique run-N names required")
|
||||
payload, manifest, summary = collect(args.root.resolve(), args.runs)
|
||||
if args.check_only:
|
||||
print("PASS raw consistency; no archive written:", summary)
|
||||
return
|
||||
out = args.output.resolve()
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
for name in ("evidence.zip", "manifest.json", "files.json"):
|
||||
need(not (out / name).exists(), "existing output refused: " + name)
|
||||
for name in ("prepare.py", "verify.py", "README.md"):
|
||||
data = (HERE / name).read_bytes()
|
||||
if (out / name).exists():
|
||||
need((out / name).read_bytes() == data, "different existing package tool")
|
||||
else:
|
||||
with (out / name).open("xb") as stream:
|
||||
stream.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 evidence")
|
||||
print("PASS package readback:", out, summary)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,235 @@
|
||||
"""Verify archived native receipts and bytes; do not rerun the GUI or checker."""
|
||||
from pathlib import Path, PurePosixPath
|
||||
from datetime import datetime
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import stat
|
||||
import zipfile
|
||||
|
||||
BASE = {"started.json", "finished.json", "generation.json", "generation.stdout.log",
|
||||
"generation.stderr.log", "app.stdout.log", "app.stderr.log", "processes.json", "history-bytes.json"}
|
||||
GROUPS = [["baseline", "move-undo", "before-hide", "hide-undo"], ["move", "move-redo"],
|
||||
["hidden", "hide-redo", "reopened-hidden"]]
|
||||
MODES = {name: mode for group, mode in zip(GROUPS, ["unchanged", "moved", "hide"]) for name in group}
|
||||
OUTER = {"prepare.py", "verify.py", "README.md", "manifest.json", "evidence.zip"}
|
||||
|
||||
|
||||
def need(ok, message):
|
||||
if not ok:
|
||||
raise ValueError(message)
|
||||
|
||||
|
||||
def pin(data):
|
||||
return {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()}
|
||||
|
||||
|
||||
def safe(name):
|
||||
return (isinstance(name, str) and bool(name) and "\\" not in name and ":" not in name
|
||||
and not PurePosixPath(name).is_absolute() and all(ord(c) >= 32 for c in name)
|
||||
and all(part not in ("", ".", "..") for part in name.split("/")))
|
||||
|
||||
|
||||
def parsed(data):
|
||||
def unique(items):
|
||||
result = {}
|
||||
for key, value in items:
|
||||
need(key not in result, "duplicate JSON key: " + key)
|
||||
result[key] = value
|
||||
return result
|
||||
return json.loads(data, object_pairs_hook=unique)
|
||||
|
||||
|
||||
def norm(path):
|
||||
return path.replace("\\", "/").rstrip("/")
|
||||
|
||||
|
||||
def relative(path, root):
|
||||
prefix = norm(root) + "/"
|
||||
need(norm(path).startswith(prefix), "recorded path outside owner: " + path)
|
||||
value = norm(path)[len(prefix):]
|
||||
need(safe(value), "unsafe recorded relative path")
|
||||
return value
|
||||
|
||||
|
||||
def ordered(*values):
|
||||
times = [datetime.fromisoformat(value) for value in values]
|
||||
return all(t.utcoffset() is not None for t in times) and times == sorted(times)
|
||||
|
||||
|
||||
def zip_inventory(archive, members):
|
||||
names = archive.namelist()
|
||||
need(len(names) == len(set(names)) and set(names) == set(members), "exact archive members")
|
||||
for info in archive.infolist():
|
||||
need(safe(info.filename) and not info.is_dir() and not stat.S_ISLNK(info.external_attr >> 16), "unsafe archive member")
|
||||
need(info.file_size == members[info.filename]["bytes"], "archive member size")
|
||||
|
||||
|
||||
def verify_data(manifest, read):
|
||||
need(manifest["schema"] == 1 and manifest["kind"] == "multiselect-native", "manifest kind")
|
||||
members, runs = manifest["members"], manifest["runs"]
|
||||
need(bool(runs) and all(safe(run) and "/" not in run for run in runs), "run names")
|
||||
need(all(safe(name) for name in members), "safe member names")
|
||||
for name, expected in members.items():
|
||||
need(pin(read(name)) == expected, "member pin: " + name)
|
||||
used = set()
|
||||
def raw(name):
|
||||
need(name in members, "missing member: " + name)
|
||||
used.add(name)
|
||||
return read(name)
|
||||
def obj(name):
|
||||
return parsed(raw(name))
|
||||
def tree(prefix):
|
||||
return {name[len(prefix):]: raw(name) for name in members if name.startswith(prefix)}
|
||||
def pinned_tree(prefix, expected):
|
||||
actual = tree(prefix)
|
||||
need({name: pin(data) for name, data in actual.items()} == expected, "exact pinned tree: " + prefix)
|
||||
return actual
|
||||
for run, spec in runs.items():
|
||||
prefix = "runs/" + run + "/raw/"
|
||||
start, end = obj(prefix + "started.json"), obj(prefix + "finished.json")
|
||||
generation, process = obj(prefix + "generation.json"), obj(prefix + "processes.json")
|
||||
history = obj(prefix + "history-bytes.json")
|
||||
need(end["exitCode"] == 0 and all(end[key] is True for key in
|
||||
("guiUnchanged", "checkerUnchanged", "fixtureUnchanged")), run + ": clean unchanged closure")
|
||||
need(ordered(generation["start"], generation["finish"], process["CreationDate"], start["start"], end["finish"], history["verified"]), run + ": process/generation times")
|
||||
need(process["ProcessId"] == start["pid"] and type(start["pid"]) is int and start["pid"] > 0, run + ": process identity")
|
||||
need(norm(process["ExecutablePath"]) == norm(start["gui"]["binary"])
|
||||
and start["command"] == [start["gui"]["binary"]], run + ": GUI command")
|
||||
need(spec["originalRun"] == norm(start["cwd"]) + "/.local/multiselect-native/" + run, run + ": original run mapping")
|
||||
need(generation["exitCode"] == 0 and generation["checker"] == start["checker"], run + ": generation checker")
|
||||
need(generation["command"][:2] == [start["checker"]["binary"], "generate"]
|
||||
and len(generation["command"]) == 3 and norm(generation["command"][2]) == spec["originalFixture"], run + ": generation command")
|
||||
for stream in ("stdout", "stderr"):
|
||||
need(end[stream] == pin(raw(prefix + "app." + stream + ".log")), run + ": app stream")
|
||||
need(generation[stream] == pin(raw(prefix + "generation." + stream + ".log")), run + ": generation stream")
|
||||
fixture = pinned_tree("runs/" + run + "/fixture/", start["fixture"])
|
||||
need(set(fixture) == {"baseline.json", "manifest.json"} | {"source/" + name for name in
|
||||
obj(prefix + "snapshots/baseline/result.json")["source"]}, run + ": fixture membership")
|
||||
fixture_manifest = parsed(fixture["manifest.json"])
|
||||
need(fixture_manifest["fixture"] == "multiselect-native-20260923"
|
||||
and fixture_manifest["source_entry"] == "project.arcadia", run + ": fixture identity")
|
||||
need(parsed(fixture["baseline.json"])["id"] == fixture_manifest["ids"]["project"], run + ": baseline identity")
|
||||
for key, expected in [("helper", start["helper"]), ("capture", start["capture"]),
|
||||
("snapshotHelper", start["snapshotHelper"]), ("history", history["helper"])]:
|
||||
need(pin(raw(spec["helpers"][key])) == expected, run + ": helper " + key)
|
||||
builds = {}
|
||||
for kind, target in [("gui", "arcadia-studio"), ("checker", "multiselect_native")]:
|
||||
recorded = start[kind]
|
||||
build = obj(spec["builds"][kind]["receipt"])
|
||||
need(pin(raw(spec["builds"][kind]["receipt"])) == recorded["receiptPin"], run + ": build receipt pin")
|
||||
need(relative(recorded["receipt"], start["cwd"]) == spec["builds"][kind]["originalRelative"], run + ": build path mapping")
|
||||
need(build["exitCode"] == 0 and build["inputsUnchanged"] is True
|
||||
and ordered(build["start"], build["finish"], generation["start"]), run + ": accepted preceding build")
|
||||
need(build["inputs"] == recorded["inputs"] == pin(raw(spec["builds"][kind]["inputs"])), run + ": build input map")
|
||||
need(pin(raw(spec["builds"][kind]["helper"])) == build["helper"], run + ": build helper pin")
|
||||
inputs = obj(spec["builds"][kind]["inputs"])
|
||||
need(len(inputs) == build["inputCount"] and sum(name.startswith("crates/vendor/iced_widget/") for name in inputs) == 71, run + ": build input count")
|
||||
artifacts = [item for item in build["artifacts"] if item["cargo"]["target"]["name"] == target]
|
||||
need(len(artifacts) == 1 and artifacts[0]["readback"] == recorded["pin"]
|
||||
and artifacts[0]["cargo"]["executable"] == recorded["binary"], run + ": executable relationship")
|
||||
builds[kind] = inputs
|
||||
need(start["gui"]["inputs"] == start["checker"]["inputs"], run + ": matching GUI/checker inputs")
|
||||
source = spec["checkerSource"]
|
||||
need(source["inputPath"] == "crates/oa-core/examples/multiselect_native.rs"
|
||||
and pin(raw(source["member"])) == builds["checker"][source["inputPath"]], run + ": archived exact checker source")
|
||||
|
||||
top = {name[len(prefix):] for name in members if name.startswith(prefix) and "/" not in name[len(prefix):]}
|
||||
captures = sorted(name for name in top - BASE if name.endswith(".json"))
|
||||
need(bool(captures), run + ": missing captures")
|
||||
expected_top = set(BASE) | set(captures)
|
||||
captured_window = None
|
||||
for name in captures:
|
||||
capture = obj(prefix + name)
|
||||
need(ordered(start["start"], capture["time"], end["finish"]), run + ": capture lifetime")
|
||||
window = capture["window"]
|
||||
app = window["app"]
|
||||
need(isinstance(app, str) and app.startswith("process:")
|
||||
and norm(app[len("process:"):]) == norm(start["gui"]["binary"]), run + ": captured executable relationship")
|
||||
need(type(window["id"]) is int and window["id"] > 0, run + ": captured window identity")
|
||||
if captured_window is None:
|
||||
captured_window = window["id"]
|
||||
need(window["id"] == captured_window, run + ": inconsistent captured window identity")
|
||||
need(isinstance(capture["images"], list), run + ": capture images")
|
||||
for image in capture["images"]:
|
||||
filename = image["file"]
|
||||
need(safe(filename) and "/" not in filename and filename.startswith(name[:-5] + "-")
|
||||
and filename.endswith((".jpg", ".png")), run + ": capture image mapping")
|
||||
need(type(image["width"]) is int and image["width"] > 0
|
||||
and type(image["height"]) is int and image["height"] > 0, run + ": image dimensions")
|
||||
need(filename not in expected_top, run + ": duplicate image reference")
|
||||
expected_top.add(filename)
|
||||
raw(prefix + filename)
|
||||
need(top == expected_top, run + ": extra/missing top-level run files")
|
||||
|
||||
snapshots = {name[len(prefix + "snapshots/"):].split("/")[0] for name in members if name.startswith(prefix + "snapshots/")}
|
||||
need(snapshots == set(MODES), run + ": exact nine snapshot labels")
|
||||
states = {}
|
||||
for label, mode in MODES.items():
|
||||
folder = prefix + "snapshots/" + label + "/"
|
||||
began, result = obj(folder + "started.json"), obj(folder + "result.json")
|
||||
need(all(result.get(key) == value for key, value in began.items()), label + ": start/result")
|
||||
need(result["exitCode"] == 0 and all(result[key] is True for key in
|
||||
("binaryUnchanged", "workingSourceUnchanged", "baselineUnchanged")), label + ": unchanged successful checker")
|
||||
need(ordered(start["start"], result["start"], result["finish"], end["finish"]), label + ": checker lifetime")
|
||||
need(result["buildReceipt"] == start["checker"]["receiptPin"] and result["binary"] == start["checker"]["pin"]
|
||||
and result["helper"] == start["snapshotHelper"], label + ": checker provenance")
|
||||
need(result["baseline"] == pin(fixture["baseline.json"]), label + ": baseline pin")
|
||||
command = result["command"]
|
||||
need(len(command) == 5 and command[:3] == [start["checker"]["binary"], "check", mode]
|
||||
and norm(command[3]) == spec["originalFixture"] + "/baseline.json"
|
||||
and norm(command[4]) == spec["originalRun"] + "/snapshots/" + label + "/source/project.arcadia", label + ": exact checker command")
|
||||
for stream in ("stdout", "stderr"):
|
||||
need(result[stream] == pin(raw(folder + stream + ".log")), label + ": stream pin")
|
||||
need(not raw(folder + "stderr.log"), label + ": checker stderr")
|
||||
report = obj(folder + "stdout.log")
|
||||
need(report["result"] == "PASS" and report["comparison"] == "complete Project equality"
|
||||
and report["mode"] == mode and report["baseline"] == command[3] and report["saved"] == command[4], label + ": positive checker report")
|
||||
delta = report["inferred_common_delta"]
|
||||
if mode == "moved":
|
||||
need(isinstance(delta, dict) and set(delta) == {"x", "y"}
|
||||
and all(type(v) in (int, float) and math.isfinite(v) and abs(v) <= 500 for v in delta.values())
|
||||
and math.hypot(delta["x"], delta["y"]) >= 10, label + ": inferred movement bounds")
|
||||
else:
|
||||
need(delta is None, label + ": unexpected inferred delta")
|
||||
states[label] = pinned_tree(folder + "source/", result["source"])
|
||||
need(len(states[label]) == history["sourceFilesPerSnapshot"] == 9, label + ": source count")
|
||||
expected = {folder + name for name in ("started.json", "result.json", "stdout.log", "stderr.log")}
|
||||
expected.update(folder + "source/" + name for name in states[label])
|
||||
need({name for name in members if name.startswith(folder)} == expected, label + ": extra snapshot files")
|
||||
need(history["status"] == "PASS" and history["equalByteGroups"] == GROUPS, run + ": history groups")
|
||||
for group in GROUPS:
|
||||
need(all(states[label] == states[group[0]] for label in group), run + ": actual history bytes " + str(group))
|
||||
need(all(states[a[0]] != states[b[0]] for i, a in enumerate(GROUPS) for b in GROUPS[i + 1:]), run + ": distinct history states")
|
||||
need(states["baseline"] == {name[7:]: data for name, data in fixture.items() if name.startswith("source/")}, run + ": baseline source exact")
|
||||
changed = {label: sorted(name for name in set(states["baseline"]) | set(states[label])
|
||||
if states["baseline"].get(name) != states[label].get(name)) for label in ("move", "hidden")}
|
||||
need(changed == history["changedFilesFromBaseline"]
|
||||
== {label: ["views/diagram_oa_view.arcadia"] for label in ("move", "hidden")}, run + ": changed source files")
|
||||
print(run, "closed exit 0;", len(captures), "captures; nine positive snapshots; exact three-group source history")
|
||||
need(used == set(members), "unreferenced/extra package members")
|
||||
return {"runs": len(runs), "members": len(members)}
|
||||
|
||||
|
||||
def verify_package(root):
|
||||
files = parsed((root / "files.json").read_bytes())
|
||||
need(set(files) == OUTER, "outer files")
|
||||
for name, expected in files.items():
|
||||
need(pin((root / name).read_bytes()) == expected, "outer pin: " + name)
|
||||
manifest = parsed((root / "manifest.json").read_bytes())
|
||||
with zipfile.ZipFile(root / "evidence.zip") as archive:
|
||||
zip_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 native evidence byte/receipt consistency:", verify_package(args.package))
|
||||
print("No GUI/checker execution; actions and native acceptance require the separate parent review.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,2 @@
|
||||
# Preserve pinned historical receipts and helper bytes through Git round trips.
|
||||
* -text whitespace=cr-at-eol
|
||||
@@ -0,0 +1,52 @@
|
||||
# Captured inputs and committed source identity
|
||||
|
||||
This directory preserves exact historical `committed-desktop-4.json` and
|
||||
`committed-desktop-5.json` receipts plus `verify-committed-inputs.py` as data.
|
||||
The original helper contains its historical absolute checkout path; do not run
|
||||
it for portable verification. The receipts do not themselves pin that helper;
|
||||
`files.json` pins the copies distributed here and the new verifier/README.
|
||||
The local `.gitattributes` preserves those pinned bytes through Git round trips;
|
||||
retain it with this directory rather than normalizing the historical text.
|
||||
|
||||
With Python 3.10+, Git, a repository containing both commits, and the completed
|
||||
sibling checks package, run:
|
||||
|
||||
```text
|
||||
python -B SOURCE_DIRECTORY/verify.py --repo REPOSITORY --checks CHECKS_PACKAGE_DIRECTORY
|
||||
```
|
||||
|
||||
Before that package exists, an explicitly optional raw-input mode is available:
|
||||
|
||||
```text
|
||||
python -B harness/experiments/multiselect-20260923/source/verify.py --repo . --raw-gates .local/group-movement-gates
|
||||
```
|
||||
|
||||
The verifier checks source-evidence pins, captured map byte hashes, recorded gate
|
||||
success/unchanged flags, counts and 71 vendored iced_widget inputs. It compares the
|
||||
complete relevant Git tree inventory and every blob's size/SHA-256 at these
|
||||
commits with their corresponding captured input maps:
|
||||
|
||||
- `desktop-4`: `12a7352ddef5f69a144ead8219a50916233d63a9`
|
||||
- `desktop-5`: `f6a6010baed9e6164a1fcc7ecd58256a562827d7`
|
||||
|
||||
The scope matches the historical helper: Cargo manifests/lock/toolchain file,
|
||||
`crates/`, `build/`, `.cargo/`, `scripts/`, `docs/`, `examples/`,
|
||||
`harness/fixtures/`, and `harness/prototypes/`. This is the complete inventory
|
||||
within that scope, not a whole-repository identity claim. Worktree contents,
|
||||
current HEAD, line-ending checkout conversion and original machine paths do not
|
||||
participate. Git objects are read by object ID; no checkout, build or archived
|
||||
helper runs. Both commits must already be available; lazy object fetching is
|
||||
disabled for these reads.
|
||||
|
||||
In package mode, outer checks-package pins and selected member/run relationships
|
||||
are also checked. Run the checks package's own verifier for its full source ZIP,
|
||||
logs, helpers and all other gate relationships. Raw mode reads the named local
|
||||
maps/receipts directly and is not a substitute for packaged-evidence verification.
|
||||
No source maps or ZIPs are duplicated in this directory.
|
||||
|
||||
Historical receipts report an earlier comparison. A successful run of this new
|
||||
verifier performs a fresh Git-object comparison against the pinned maps. A gate's
|
||||
recorded HEAD can predate its later source-identical commit; that difference is
|
||||
why blob comparison is necessary. This evidence identifies tested source bytes;
|
||||
it does not rerun tests or establish native usability, release integration or
|
||||
full #29 acceptance.
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"checked": "2026-09-23T08:11:54.115058+00:00",
|
||||
"commit": "12a7352ddef5f69a144ead8219a50916233d63a9",
|
||||
"gate": "desktop-4",
|
||||
"inputCount": 729,
|
||||
"inputMap": {
|
||||
"bytes": 121985,
|
||||
"sha256": "55a5f354bb5049a8c77ba9bafa833438ebf754649b0cf5d175d0c8dcfcedd7bb"
|
||||
},
|
||||
"comparison": "Exact committed Git blobs equal every captured input; same complete filtered inventory"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"checked": "2026-09-23T08:53:15.452246+00:00",
|
||||
"commit": "f6a6010baed9e6164a1fcc7ecd58256a562827d7",
|
||||
"gate": "desktop-5",
|
||||
"inputCount": 729,
|
||||
"inputMap": {
|
||||
"bytes": 121985,
|
||||
"sha256": "99dc46645236e674244e7c4867595a6000d3d85b54bcc9ab2b0c601923ecf66c"
|
||||
},
|
||||
"comparison": "Exact committed Git blobs equal every captured input; same complete filtered inventory"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
".gitattributes": {
|
||||
"bytes": 109,
|
||||
"sha256": "aca8eef17dbab8cfedcbe18e1175cfee115802376fac4ec69e8c3320a6399d6c"
|
||||
},
|
||||
"README.md": {
|
||||
"bytes": 2792,
|
||||
"sha256": "b8db0c2c71e491b6179b3e57d27e5dfb23c9283894219feea328bc632603f2aa"
|
||||
},
|
||||
"verify.py": {
|
||||
"bytes": 7255,
|
||||
"sha256": "2ed667c127470efb669fb43d5dcdb288f891e42e10e67ef98ca4cd1125df09d1"
|
||||
},
|
||||
"verify-committed-inputs.py": {
|
||||
"bytes": 2138,
|
||||
"sha256": "ac2b50a73f678456b9628684347484c013f5f9c78f054de72b74f56a34c990d5"
|
||||
},
|
||||
"committed-desktop-4.json": {
|
||||
"bytes": 390,
|
||||
"sha256": "47c6774bcb7d0c37c50e0ed50f8fb58ee9b55c6fcee30af488481c314a4e66e8"
|
||||
},
|
||||
"committed-desktop-5.json": {
|
||||
"bytes": 390,
|
||||
"sha256": "da1f08e06bd0af6512da4196618b71d0c4ecc090012f061bb82b6a36f5b7686c"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
"""Check the tested source inventory against exact Git blobs, not HEAD alone."""
|
||||
from pathlib import Path
|
||||
import datetime, hashlib, json, subprocess, sys
|
||||
root=Path('C:/ar-multiselect-9e8r6t')
|
||||
run,=sys.argv[1:]
|
||||
gate=root/'.local/group-movement-gates'/run
|
||||
inputs=json.loads((gate/'inputs.json').read_bytes())
|
||||
result=json.loads((gate/'result.json').read_bytes())
|
||||
assert result['exitCode']==0 and result['inputsUnchanged']
|
||||
head=subprocess.check_output(['git','rev-parse','HEAD'],cwd=root,text=True).strip()
|
||||
def relevant(p):
|
||||
return p in ('Cargo.toml','Cargo.lock','rust-toolchain.toml') or p.startswith(('crates/','build/','.cargo/','scripts/','docs/','examples/','harness/fixtures/','harness/prototypes/'))
|
||||
paths=subprocess.check_output(['git','ls-tree','-r','--name-only','-z',head],cwd=root).decode().split('\0')
|
||||
assert set(inputs)=={p for p in paths if p and relevant(p)}, 'Committed input inventory differs'
|
||||
assert all('\n' not in p for p in inputs)
|
||||
request=''.join(head+':'+p+'\n' for p in inputs).encode()
|
||||
raw=subprocess.run(['git','cat-file','--batch'],cwd=root,input=request,capture_output=True,check=True).stdout
|
||||
offset=0
|
||||
actual={}
|
||||
for path in inputs:
|
||||
end=raw.index(b'\n',offset)
|
||||
oid,kind,size=raw[offset:end].split()
|
||||
assert kind==b'blob'
|
||||
size=int(size)
|
||||
data=raw[end+1:end+1+size]
|
||||
assert len(data)==size and raw[end+1+size:end+2+size]==b'\n'
|
||||
actual[path]={'bytes':size,'sha256':hashlib.sha256(data).hexdigest()}
|
||||
offset=end+2+size
|
||||
assert offset==len(raw)
|
||||
changed=[p for p in inputs if inputs[p]!=actual[p]]
|
||||
assert not changed, 'Tested bytes differ from committed blobs: '+repr(changed)
|
||||
data=(gate/'inputs.json').read_bytes()
|
||||
report={'checked':datetime.datetime.now(datetime.timezone.utc).isoformat(),'commit':head,'gate':run,'inputCount':len(inputs),'inputMap':{'bytes':len(data),'sha256':hashlib.sha256(data).hexdigest()},'comparison':'Exact committed Git blobs equal every captured input; same complete filtered inventory'}
|
||||
out=root/'.local/group-movement-gates'/('committed-'+run+'.json')
|
||||
with out.open('x',encoding='utf-8') as f: json.dump(report,f,indent=2)
|
||||
print(json.dumps(report,indent=2))
|
||||
@@ -0,0 +1,149 @@
|
||||
"""Compare captured input maps to exact named Git trees; no builds or checkouts."""
|
||||
from pathlib import Path, PurePosixPath
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import zipfile
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
COMMITS = {"desktop-4": "12a7352ddef5f69a144ead8219a50916233d63a9",
|
||||
"desktop-5": "f6a6010baed9e6164a1fcc7ecd58256a562827d7"}
|
||||
COMPARISON = "Exact committed Git blobs equal every captured input; same complete filtered inventory"
|
||||
FILES = {".gitattributes", "verify.py", "README.md", "verify-committed-inputs.py",
|
||||
"committed-desktop-4.json", "committed-desktop-5.json"}
|
||||
|
||||
|
||||
def need(ok, message):
|
||||
if not ok:
|
||||
raise ValueError(message)
|
||||
|
||||
|
||||
def pin(data):
|
||||
return {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()}
|
||||
|
||||
|
||||
def parsed(data):
|
||||
def unique(items):
|
||||
result = {}
|
||||
for key, value in items:
|
||||
need(key not in result, "duplicate JSON key: " + key)
|
||||
result[key] = value
|
||||
return result
|
||||
return json.loads(data, object_pairs_hook=unique)
|
||||
|
||||
|
||||
def safe(name):
|
||||
return (isinstance(name, str) and bool(name) and "\\" not in name and ":" not in name
|
||||
and not PurePosixPath(name).is_absolute()
|
||||
and all(part not in ("", ".", "..") for part in name.split("/")))
|
||||
|
||||
|
||||
def relevant(path):
|
||||
return path in ("Cargo.toml", "Cargo.lock", "rust-toolchain.toml") or path.startswith(
|
||||
("crates/", "build/", ".cargo/", "scripts/", "docs/", "examples/", "harness/fixtures/", "harness/prototypes/"))
|
||||
|
||||
|
||||
def git(repo, *arguments, data=None):
|
||||
environment = dict(os.environ, GIT_NO_LAZY_FETCH="1")
|
||||
return subprocess.run(["git", *arguments], cwd=repo, input=data, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, check=True, env=environment).stdout
|
||||
|
||||
|
||||
def compare_commit(repo, commit, inputs):
|
||||
need(git(repo, "rev-parse", "--verify", commit + "^{commit}").decode().strip() == commit, "named commit unavailable")
|
||||
entries = git(repo, "ls-tree", "-r", "--full-tree", "-z", commit).split(b"\0")
|
||||
blobs = {}
|
||||
for entry in filter(None, entries):
|
||||
header, path_bytes = entry.split(b"\t", 1)
|
||||
path = path_bytes.decode("utf-8")
|
||||
if relevant(path):
|
||||
_mode, kind, oid = header.split()
|
||||
need(kind == b"blob", "relevant non-blob tree entry: " + path)
|
||||
need(path not in blobs, "duplicate tree path")
|
||||
blobs[path] = oid
|
||||
need(set(blobs) == set(inputs), "complete filtered Git inventory differs; missing="
|
||||
+ repr(sorted(set(inputs) - set(blobs))) + "; additional=" + repr(sorted(set(blobs) - set(inputs))))
|
||||
# Object IDs avoid path quoting and commit:path interpretation in batch input.
|
||||
paths = sorted(blobs)
|
||||
data = git(repo, "cat-file", "--batch", data=b"".join(blobs[path] + b"\n" for path in paths))
|
||||
offset, actual = 0, {}
|
||||
for path in paths:
|
||||
end = data.index(b"\n", offset)
|
||||
oid, kind, size_bytes = data[offset:end].split()
|
||||
size = int(size_bytes)
|
||||
need(oid == blobs[path] and kind == b"blob" and size >= 0, "Git batch object relationship")
|
||||
content = data[end + 1:end + 1 + size]
|
||||
need(len(content) == size and data[end + 1 + size:end + 2 + size] == b"\n", "Git batch framing")
|
||||
actual[path] = pin(content)
|
||||
offset = end + 2 + size
|
||||
need(offset == len(data), "trailing Git batch bytes")
|
||||
different = [path for path in paths if actual[path] != inputs[path]]
|
||||
need(not different, "captured bytes differ from named commit: " + repr(different))
|
||||
|
||||
|
||||
def packaged(checks, runs):
|
||||
files = parsed((checks / "files.json").read_bytes())
|
||||
need(set(files) == {"prepare.py", "verify.py", "README.md", "manifest.json", "evidence.zip"}, "checks outer inventory")
|
||||
for name, expected in files.items():
|
||||
need(pin((checks / name).read_bytes()) == expected, "checks outer pin: " + name)
|
||||
manifest = parsed((checks / "manifest.json").read_bytes())
|
||||
need(manifest["schema"] == 1 and manifest["kind"] == "multiselect-cargo-gates", "checks manifest kind")
|
||||
captured = {}
|
||||
with zipfile.ZipFile(checks / "evidence.zip") as archive:
|
||||
names = archive.namelist()
|
||||
need(len(names) == len(set(names)) and set(names) == set(manifest["members"])
|
||||
and all(safe(name) for name in names), "checks exact safe members")
|
||||
def raw(logical):
|
||||
member = manifest["logicalFiles"][logical]
|
||||
data = archive.read(member)
|
||||
need(pin(data) == manifest["members"][member], "checks member pin: " + logical)
|
||||
return data
|
||||
for run in runs:
|
||||
prefix = "cargo/" + run + "/"
|
||||
result = parsed(raw(prefix + "result.json"))
|
||||
spec = manifest["runs"][run]
|
||||
need(all(result[key] == spec[key] for key in ("command", "head", "exitCode", "inputCount")), run + ": checks run relationships")
|
||||
captured[run] = (raw(prefix + "inputs.json"), result)
|
||||
return captured
|
||||
|
||||
|
||||
def verify(repo, captured):
|
||||
outer = parsed((HERE / "files.json").read_bytes())
|
||||
need(set(outer) == FILES, "source evidence file inventory")
|
||||
for name, expected in outer.items():
|
||||
need(pin((HERE / name).read_bytes()) == expected, "source evidence pin: " + name)
|
||||
for run, commit in COMMITS.items():
|
||||
receipt = parsed((HERE / ("committed-" + run + ".json")).read_bytes())
|
||||
need(receipt["gate"] == run and receipt["commit"] == commit
|
||||
and receipt["comparison"] == COMPARISON, run + ": historical identity relationship")
|
||||
map_bytes, result = captured[run]
|
||||
inputs = parsed(map_bytes)
|
||||
need(pin(map_bytes) == receipt["inputMap"] == result["inputs"], run + ": exact captured input map")
|
||||
need(result["exitCode"] == 0 and result["inputsUnchanged"] is True, run + ": accepted unchanged gate")
|
||||
need(len(inputs) == receipt["inputCount"] == result["inputCount"], run + ": input counts")
|
||||
need(all(safe(path) and relevant(path) for path in inputs), run + ": input scope")
|
||||
need(sum(path.startswith("crates/vendor/iced_widget/") for path in inputs) == 71, run + ": vendor count")
|
||||
compare_commit(repo, commit, inputs)
|
||||
print("PASS exact Git tree/blobs:", run, commit, len(inputs), "captured inputs")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--repo", type=Path, required=True, help="repository with both named commits already present")
|
||||
source = parser.add_mutually_exclusive_group(required=True)
|
||||
source.add_argument("--checks", type=Path, help="portable checks package directory")
|
||||
source.add_argument("--raw-gates", type=Path, help="optional preparation mode: raw gate directory, not a packaged-evidence verification")
|
||||
args = parser.parse_args()
|
||||
if args.checks:
|
||||
captured = packaged(args.checks, COMMITS)
|
||||
else:
|
||||
captured = {run: ((args.raw_gates / run / "inputs.json").read_bytes(),
|
||||
parsed((args.raw_gates / run / "result.json").read_bytes())) for run in COMMITS}
|
||||
verify(args.repo, captured)
|
||||
print("Source identity only; no build, checkout, helper execution or native acceptance claim.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user