Record verified Allocation assignment planner and portable evidence

This commit is contained in:
2026-09-23 11:29:58 -07:00
parent 33e880103c
commit 16b30a6760
13 changed files with 918 additions and 2 deletions
@@ -0,0 +1 @@
** -text whitespace=cr-at-eol
@@ -0,0 +1,24 @@
# Allocation captured-gate evidence tools
Adapted from the reviewed Process prepare/verify/selfcheck tools. Read-only preparation consumes explicitly selected **closed** runs in CHECKOUT/.local/allocation-group-gates. No Cargo, source execution, checkout, GUI, network or archived helper execution occurs.
```powershell
python -B prepare.py --root CHECKOUT --runs experiment-1 experiment-2 experiment-3 planner-document-1 probe-lint-1 format-1 --check-only
```
Keep failed experiment-2: verification preserves its recorded compile failure rather than converting archive consistency into test success. The example selects the first six closed gates. Later closed planner runs can be explicitly listed with the same interface; the final package manifest is authoritative for its exact inventory. No implicit discovery includes active directories.
To create a portable package, replace --check-only with `--output NEW_DIRECTORY`. Existing output refuses. The exact seven raw files are required, with only `source-proof.json` accepted as an optional eighth file. No raw byte normalization or receipt rewriting occurs. Maps and nested input ZIPs deduplicate by SHA-256; other logical raw files keep their names. All original helper bytes, failed-run streams and optional proof bytes remain archived. The Allocation-specific manifest kind distinguishes this extension from the seven-file Process schema.
The gate.py and source-proof.py helper catalog is preserved. Every gate's recorded helper must match available bytes; use repeatable `--helper PATH` for older captures. If a proof exists, its exact comparator bytes must be available at the default `.local/process-source-evidence-tools/verify.py` or a repeatable `--comparator PATH`. They are archived under their content hash and never executed.
An optional source proof is independently pinned in the manifest with its full named commit. Verification binds it to the enclosing run, exact result receipt, captured map/count, completed gate time, status and comparator bytes/hash. Captured HEAD is preserved as historical metadata and is not substituted for the named source commit. This packager checks historical proof consistency; it does **not** repeat Git blob comparison. A source proof on a failed gate is source-identity evidence only, never a passing-test claim.
```powershell
python -B PACKAGE/verify.py
python -B selfcheck.py --root CHECKOUT --runs experiment-1 experiment-2 experiment-3 planner-document-1 probe-lint-1 format-1 --output TOOLS/NEW_SELFCHECK_DIRECTORY
```
The verifier checks pins, exact ZIP inventory, process/start/result relationships, streams, command/exit identities, source capsules, vendor inventory and Cargo artifact relationships. Selfchecks compare packaged raw bytes to originals, reject existing output, and mutate only in-memory copies to test stream/helper/exit/capsule/proof corruption. The package contains tools, manifest, files.json and evidence.zip; selfcheck is a preparation utility, not packaged runtime input.
Limits: internal consistency is not external authentication, hermetic build proof, native usability, a new source comparison or production acceptance. Review exact run results and source identity separately. Run with `python -B` to avoid incidental bytecode writes.
@@ -0,0 +1,22 @@
{
"prepare.py": {
"bytes": 6316,
"sha256": "aa52592fb8e373c2a90007e187734d29129d38d9fce9dc45461482c7f6376bff"
},
"verify.py": {
"bytes": 11440,
"sha256": "584187370a1076e13190914158fc72a9ab65f07e72cc6a0d3b5c319f3dc7f05f"
},
"README.md": {
"bytes": 3284,
"sha256": "3ff0a61fb15ca26e54b8903962c99ba7802a87f0204e7b71f2d04c812b9588b7"
},
"manifest.json": {
"bytes": 17748,
"sha256": "f053e2f1492ee4fdfa2d4dfd7e48c5768d098cf96b629471699810d06cb61537"
},
"evidence.zip": {
"bytes": 8984108,
"sha256": "51b898205ee7a2907ce746389882f0607f7ad7290a1759b392cd307ef9e9ef5a"
}
}
@@ -0,0 +1,396 @@
{
"schema": 1,
"kind": "allocation-multiselect-cargo-gates",
"runs": {
"assignment-planner-1": {
"command": [
"cargo",
"test",
"-p",
"oa-desktop",
"--example",
"allocation_policy_probe",
"--message-format=json",
"--",
"--test-threads=1"
],
"head": "eed80ffd6e94c7127491de1fd45c0415685f6328",
"exitCode": 0,
"inputCount": 749,
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py"
},
"assignment-planner-2": {
"command": [
"cargo",
"test",
"-p",
"oa-desktop",
"--example",
"allocation_policy_probe",
"--message-format=json",
"--",
"--test-threads=1"
],
"head": "eed80ffd6e94c7127491de1fd45c0415685f6328",
"exitCode": 0,
"inputCount": 750,
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py"
},
"assignment-lint-1": {
"command": [
"cargo",
"clippy",
"-p",
"oa-desktop",
"--example",
"allocation_policy_probe",
"--tests",
"--message-format=json",
"--",
"-D",
"warnings"
],
"head": "eed80ffd6e94c7127491de1fd45c0415685f6328",
"exitCode": 0,
"inputCount": 750,
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py"
},
"assignment-format-1": {
"command": [
"cargo",
"fmt",
"--all",
"--",
"--check"
],
"head": "eed80ffd6e94c7127491de1fd45c0415685f6328",
"exitCode": 0,
"inputCount": 750,
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py"
},
"assignment-planner-3": {
"command": [
"cargo",
"test",
"-p",
"oa-desktop",
"--example",
"allocation_policy_probe",
"--message-format=json",
"--",
"--test-threads=1"
],
"head": "33e880103c5fa935a4431ec3dc089e2c4c92f680",
"exitCode": 0,
"inputCount": 750,
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py",
"sourceProof": {
"commit": "33e880103c5fa935a4431ec3dc089e2c4c92f680",
"pin": {
"bytes": 599,
"sha256": "3b249398b0ade218ec9737677e1021e21eae7aa03deeb6bc071e0e7e7fe6182b"
},
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
}
},
"assignment-lint-2": {
"command": [
"cargo",
"clippy",
"-p",
"oa-desktop",
"--example",
"allocation_policy_probe",
"--tests",
"--message-format=json",
"--",
"-D",
"warnings"
],
"head": "33e880103c5fa935a4431ec3dc089e2c4c92f680",
"exitCode": 0,
"inputCount": 750,
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py",
"sourceProof": {
"commit": "33e880103c5fa935a4431ec3dc089e2c4c92f680",
"pin": {
"bytes": 596,
"sha256": "3a8f4d17bc6e696f8c0a1373f739650da5aa5b84683478c697e71b280d07b430"
},
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
}
},
"assignment-format-2": {
"command": [
"cargo",
"fmt",
"--all",
"--",
"--check"
],
"head": "33e880103c5fa935a4431ec3dc089e2c4c92f680",
"exitCode": 0,
"inputCount": 750,
"helper": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py",
"sourceProof": {
"commit": "33e880103c5fa935a4431ec3dc089e2c4c92f680",
"pin": {
"bytes": 598,
"sha256": "41553cf5d5e5f6414930ad088fa82515630d3478da53a5ac961c8bf4191d1bc6"
},
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
}
}
},
"captureHelpers": {
"gate.py": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py",
"source-proof.py": "helpers/58597566ae1cb5c4021ddc7e86635b76d127bdb63b5d3026c427771aae7e2119.py"
},
"logicalFiles": {
"cargo/assignment-format-1/inputs.json": "capsules/e41e7d1a2b9519b78730821f96c1bf7ca8431935fe67efa203daa80d3f15c437.json",
"cargo/assignment-format-1/inputs.zip": "capsules/b471d434d8eac790ef7cc9073be0d395c9c9ad1472ba06a05b5818269ef03dfe.zip",
"cargo/assignment-format-1/process.json": "cargo/assignment-format-1/process.json",
"cargo/assignment-format-1/result.json": "cargo/assignment-format-1/result.json",
"cargo/assignment-format-1/started.json": "cargo/assignment-format-1/started.json",
"cargo/assignment-format-1/stderr.log": "cargo/assignment-format-1/stderr.log",
"cargo/assignment-format-1/stdout.log": "cargo/assignment-format-1/stdout.log",
"cargo/assignment-format-2/inputs.json": "capsules/ce988ecaeaca395d0f120844db7e3da90d039633beef10d2d4a8b8f19e92ee27.json",
"cargo/assignment-format-2/inputs.zip": "capsules/ae03a0a847a5c2000ba46e356e3dcd13a219e5fb699be8ad71a619b593e13c23.zip",
"cargo/assignment-format-2/process.json": "cargo/assignment-format-2/process.json",
"cargo/assignment-format-2/result.json": "cargo/assignment-format-2/result.json",
"cargo/assignment-format-2/source-proof.json": "cargo/assignment-format-2/source-proof.json",
"cargo/assignment-format-2/started.json": "cargo/assignment-format-2/started.json",
"cargo/assignment-format-2/stderr.log": "cargo/assignment-format-2/stderr.log",
"cargo/assignment-format-2/stdout.log": "cargo/assignment-format-2/stdout.log",
"cargo/assignment-lint-1/inputs.json": "capsules/e41e7d1a2b9519b78730821f96c1bf7ca8431935fe67efa203daa80d3f15c437.json",
"cargo/assignment-lint-1/inputs.zip": "capsules/b471d434d8eac790ef7cc9073be0d395c9c9ad1472ba06a05b5818269ef03dfe.zip",
"cargo/assignment-lint-1/process.json": "cargo/assignment-lint-1/process.json",
"cargo/assignment-lint-1/result.json": "cargo/assignment-lint-1/result.json",
"cargo/assignment-lint-1/started.json": "cargo/assignment-lint-1/started.json",
"cargo/assignment-lint-1/stderr.log": "cargo/assignment-lint-1/stderr.log",
"cargo/assignment-lint-1/stdout.log": "cargo/assignment-lint-1/stdout.log",
"cargo/assignment-lint-2/inputs.json": "capsules/ce988ecaeaca395d0f120844db7e3da90d039633beef10d2d4a8b8f19e92ee27.json",
"cargo/assignment-lint-2/inputs.zip": "capsules/ae03a0a847a5c2000ba46e356e3dcd13a219e5fb699be8ad71a619b593e13c23.zip",
"cargo/assignment-lint-2/process.json": "cargo/assignment-lint-2/process.json",
"cargo/assignment-lint-2/result.json": "cargo/assignment-lint-2/result.json",
"cargo/assignment-lint-2/source-proof.json": "cargo/assignment-lint-2/source-proof.json",
"cargo/assignment-lint-2/started.json": "cargo/assignment-lint-2/started.json",
"cargo/assignment-lint-2/stderr.log": "cargo/assignment-lint-2/stderr.log",
"cargo/assignment-lint-2/stdout.log": "cargo/assignment-lint-2/stdout.log",
"cargo/assignment-planner-1/inputs.json": "capsules/4e237aa6ba6359490d65efd40e15a697991ce53350af2080503c0635d2d9de3e.json",
"cargo/assignment-planner-1/inputs.zip": "capsules/1bb6e8b18022977f43e29bd44d25238acbf8c424bd4bf736474fce74bd8de8bc.zip",
"cargo/assignment-planner-1/process.json": "cargo/assignment-planner-1/process.json",
"cargo/assignment-planner-1/result.json": "cargo/assignment-planner-1/result.json",
"cargo/assignment-planner-1/started.json": "cargo/assignment-planner-1/started.json",
"cargo/assignment-planner-1/stderr.log": "cargo/assignment-planner-1/stderr.log",
"cargo/assignment-planner-1/stdout.log": "cargo/assignment-planner-1/stdout.log",
"cargo/assignment-planner-2/inputs.json": "capsules/e41e7d1a2b9519b78730821f96c1bf7ca8431935fe67efa203daa80d3f15c437.json",
"cargo/assignment-planner-2/inputs.zip": "capsules/b471d434d8eac790ef7cc9073be0d395c9c9ad1472ba06a05b5818269ef03dfe.zip",
"cargo/assignment-planner-2/process.json": "cargo/assignment-planner-2/process.json",
"cargo/assignment-planner-2/result.json": "cargo/assignment-planner-2/result.json",
"cargo/assignment-planner-2/started.json": "cargo/assignment-planner-2/started.json",
"cargo/assignment-planner-2/stderr.log": "cargo/assignment-planner-2/stderr.log",
"cargo/assignment-planner-2/stdout.log": "cargo/assignment-planner-2/stdout.log",
"cargo/assignment-planner-3/inputs.json": "capsules/ce988ecaeaca395d0f120844db7e3da90d039633beef10d2d4a8b8f19e92ee27.json",
"cargo/assignment-planner-3/inputs.zip": "capsules/ae03a0a847a5c2000ba46e356e3dcd13a219e5fb699be8ad71a619b593e13c23.zip",
"cargo/assignment-planner-3/process.json": "cargo/assignment-planner-3/process.json",
"cargo/assignment-planner-3/result.json": "cargo/assignment-planner-3/result.json",
"cargo/assignment-planner-3/source-proof.json": "cargo/assignment-planner-3/source-proof.json",
"cargo/assignment-planner-3/started.json": "cargo/assignment-planner-3/started.json",
"cargo/assignment-planner-3/stderr.log": "cargo/assignment-planner-3/stderr.log",
"cargo/assignment-planner-3/stdout.log": "cargo/assignment-planner-3/stdout.log",
"comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py",
"helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py": "helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py",
"helpers/58597566ae1cb5c4021ddc7e86635b76d127bdb63b5d3026c427771aae7e2119.py": "helpers/58597566ae1cb5c4021ddc7e86635b76d127bdb63b5d3026c427771aae7e2119.py"
},
"members": {
"capsules/1bb6e8b18022977f43e29bd44d25238acbf8c424bd4bf736474fce74bd8de8bc.zip": {
"bytes": 3008043,
"sha256": "1bb6e8b18022977f43e29bd44d25238acbf8c424bd4bf736474fce74bd8de8bc"
},
"capsules/4e237aa6ba6359490d65efd40e15a697991ce53350af2080503c0635d2d9de3e.json": {
"bytes": 125475,
"sha256": "4e237aa6ba6359490d65efd40e15a697991ce53350af2080503c0635d2d9de3e"
},
"capsules/ae03a0a847a5c2000ba46e356e3dcd13a219e5fb699be8ad71a619b593e13c23.zip": {
"bytes": 3013577,
"sha256": "ae03a0a847a5c2000ba46e356e3dcd13a219e5fb699be8ad71a619b593e13c23"
},
"capsules/b471d434d8eac790ef7cc9073be0d395c9c9ad1472ba06a05b5818269ef03dfe.zip": {
"bytes": 3013606,
"sha256": "b471d434d8eac790ef7cc9073be0d395c9c9ad1472ba06a05b5818269ef03dfe"
},
"capsules/ce988ecaeaca395d0f120844db7e3da90d039633beef10d2d4a8b8f19e92ee27.json": {
"bytes": 125659,
"sha256": "ce988ecaeaca395d0f120844db7e3da90d039633beef10d2d4a8b8f19e92ee27"
},
"capsules/e41e7d1a2b9519b78730821f96c1bf7ca8431935fe67efa203daa80d3f15c437.json": {
"bytes": 125659,
"sha256": "e41e7d1a2b9519b78730821f96c1bf7ca8431935fe67efa203daa80d3f15c437"
},
"cargo/assignment-format-1/process.json": {
"bytes": 116,
"sha256": "ea332ddf4129442f2a8f19b150a6c2fc21a41299eadc32287ba6ba67769e2b58"
},
"cargo/assignment-format-1/result.json": {
"bytes": 1872,
"sha256": "46047bb39986083c89d12751153b678eedd660963b9dafb02c1738986f0dd47a"
},
"cargo/assignment-format-1/started.json": {
"bytes": 1484,
"sha256": "3657a2a7ac270bca405c128328557fb5e1725f913ae0c9c5baa1ba08269bb501"
},
"cargo/assignment-format-1/stderr.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"cargo/assignment-format-1/stdout.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"cargo/assignment-format-2/process.json": {
"bytes": 116,
"sha256": "8371d4a455f0dd7678c5b8fb91f679355c05f9f0594985460aee9796bd6adc65"
},
"cargo/assignment-format-2/result.json": {
"bytes": 1872,
"sha256": "319d67031a3f30f70b21f869d755b91196ce0be68d8132775288b3d86b223d06"
},
"cargo/assignment-format-2/source-proof.json": {
"bytes": 598,
"sha256": "41553cf5d5e5f6414930ad088fa82515630d3478da53a5ac961c8bf4191d1bc6"
},
"cargo/assignment-format-2/started.json": {
"bytes": 1483,
"sha256": "a59985096b89da3518c367131b3ec257596725d18f62307bfc174ccb7969c362"
},
"cargo/assignment-format-2/stderr.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"cargo/assignment-format-2/stdout.log": {
"bytes": 0,
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
"cargo/assignment-lint-1/process.json": {
"bytes": 213,
"sha256": "b14d908c775b772f6993b40965a21ae894a406665fa5c2794ebfdb7ffe082769"
},
"cargo/assignment-lint-1/result.json": {
"bytes": 2006,
"sha256": "a8c6cc8a726c9bee821b2c12a0768d860bb1c40261783bcc23da2ea19a677959"
},
"cargo/assignment-lint-1/started.json": {
"bytes": 1610,
"sha256": "3f42270e22476b1698f19cfdc8cd6c78b0754480b613963d582d98d89bf541f6"
},
"cargo/assignment-lint-1/stderr.log": {
"bytes": 137,
"sha256": "d64f9789f0e3e22b0c98af77d19231a9026083ad317f6b2f989ebebd556f1269"
},
"cargo/assignment-lint-1/stdout.log": {
"bytes": 268845,
"sha256": "98a24be8306e586a1acb6a72c3e62005afc0db01fa4ec0b242c420aafadcf779"
},
"cargo/assignment-lint-2/process.json": {
"bytes": 212,
"sha256": "17b1f10f739cdf456da58ef2dcd9c15a8569132904876b8e2289ea543f1217d7"
},
"cargo/assignment-lint-2/result.json": {
"bytes": 2005,
"sha256": "ec3bc72c846cc08188ff95d38aa743c52ac9ec2c616fb8acb7566a6619490b68"
},
"cargo/assignment-lint-2/source-proof.json": {
"bytes": 596,
"sha256": "3a8f4d17bc6e696f8c0a1373f739650da5aa5b84683478c697e71b280d07b430"
},
"cargo/assignment-lint-2/started.json": {
"bytes": 1610,
"sha256": "afdad6e675e3351c749dccea6759c01f8b303a0d598f41592f62beecbc94fdf7"
},
"cargo/assignment-lint-2/stderr.log": {
"bytes": 137,
"sha256": "6ceb01ea1a2f7759c0f7e4fcc98504fae7f6f9cb758b16a2701f804c88ec401d"
},
"cargo/assignment-lint-2/stdout.log": {
"bytes": 268845,
"sha256": "8b993ec00e2a4a58b15af1e57051906cbee8d3d51f4314b71f71af28f582a675"
},
"cargo/assignment-planner-1/process.json": {
"bytes": 202,
"sha256": "1aec12d9a133576033cb736bdec098873005e8b248e09157a3e7608c2d551fdc"
},
"cargo/assignment-planner-1/result.json": {
"bytes": 3388,
"sha256": "b1bc1f3f3013c9df43f7af3cef801e0b977ec484457cfc314e4aa2f1c8d6db98"
},
"cargo/assignment-planner-1/started.json": {
"bytes": 1589,
"sha256": "75d0eeca99ff5f2819a0302cbdc739d2377a2f524890f448f040585288680d2e"
},
"cargo/assignment-planner-1/stderr.log": {
"bytes": 324,
"sha256": "8ee7484db45f8ddf1bf0057317feb689990758c35dc0946c12e0eef0de08e808"
},
"cargo/assignment-planner-1/stdout.log": {
"bytes": 301624,
"sha256": "7be201e6c1a812d8a32d73e75999e5e50a07af2f11eebc77f442aee44f64e5af"
},
"cargo/assignment-planner-2/process.json": {
"bytes": 202,
"sha256": "5837e6b91cbd5c6c95bbeaf08ac89a47149e84c4c3f20004457e80c316e388c9"
},
"cargo/assignment-planner-2/result.json": {
"bytes": 3387,
"sha256": "2dd1c6036eb805cd8e95050661e3dce9d132f9071186165097d4212f2b8253c0"
},
"cargo/assignment-planner-2/started.json": {
"bytes": 1589,
"sha256": "a4384901a0d3a29631a29d5e91b6d3dc944cefca1bb7653901d351a7bd906ec1"
},
"cargo/assignment-planner-2/stderr.log": {
"bytes": 324,
"sha256": "a046d75d45956402707b7c1089ec5005b0ba640857473e1f284a8f377f896f2c"
},
"cargo/assignment-planner-2/stdout.log": {
"bytes": 302839,
"sha256": "1905a2726b6e9c388566af75d7705b3916ade3a7d2c9dab772bffbb5b115762b"
},
"cargo/assignment-planner-3/process.json": {
"bytes": 202,
"sha256": "ec191e2d953d52f6da8c54bc6e9dfa5638273eb6c351823fc4871628320b3bab"
},
"cargo/assignment-planner-3/result.json": {
"bytes": 3388,
"sha256": "117bcfa31629682df708dfebb892464f01060888388ea680a231b12cd447db67"
},
"cargo/assignment-planner-3/source-proof.json": {
"bytes": 599,
"sha256": "3b249398b0ade218ec9737677e1021e21eae7aa03deeb6bc071e0e7e7fe6182b"
},
"cargo/assignment-planner-3/started.json": {
"bytes": 1589,
"sha256": "30cf725d9475a24b177c2dbddb3f59b7d298343556598bc0e760d51ad7e111e5"
},
"cargo/assignment-planner-3/stderr.log": {
"bytes": 324,
"sha256": "d3a0110134db80cd8715e6081027595056203feada2278053fdc62ae75c6df31"
},
"cargo/assignment-planner-3/stdout.log": {
"bytes": 302839,
"sha256": "aa832fe75c46be8990d0c679e6e321494c0ea6638657634010bae7022b7a2ee9"
},
"comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py": {
"bytes": 10094,
"sha256": "7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a"
},
"helpers/1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20.py": {
"bytes": 3827,
"sha256": "1368375b1fba0dfc50b77ea4f406dba71960a78317ce8f259d4c4a0254863a20"
},
"helpers/58597566ae1cb5c4021ddc7e86635b76d127bdb63b5d3026c427771aae7e2119.py": {
"bytes": 1399,
"sha256": "58597566ae1cb5c4021ddc7e86635b76d127bdb63b5d3026c427771aae7e2119"
}
}
}
@@ -0,0 +1,110 @@
"""Package explicitly selected closed gate captures without running Cargo."""
from pathlib import Path
import argparse
import json
import zipfile
from verify import RAW_FILES, pin, parsed, need, run_name, verify_data, verify_package
HERE = Path(__file__).resolve().parent
def collect(root, runs, helpers, comparators=()):
gates = root / ".local/allocation-group-gates"
candidates = [gates / name for name in ("gate.py", "source-proof.py")] + helpers
helper_bytes = [path.read_bytes() for path in candidates]
comparator_paths = [root / ".local/process-source-evidence-tools/verify.py", *comparators]
comparator_bytes = [path.read_bytes() for path in comparator_paths if path.is_file()]
payload, logical, specs = {}, {}, {}
def add(name, data):
stored = ("capsules/" + pin(data)["sha256"] + Path(name).suffix
if name.rsplit("/", 1)[1] in {"inputs.json", "inputs.zip"} else name)
need(stored not in payload or payload[stored] == data, "deduplication collision")
payload[stored] = data
logical[name] = stored
helper_catalog = {}
for name, data in zip(("gate.py", "source-proof.py"), helper_bytes):
helper = "helpers/" + pin(data)["sha256"] + ".py"
add(helper, data)
helper_catalog[name] = helper
for run in runs:
folder = gates / run
need(folder.is_dir(), "run directory missing: " + run)
paths = list(folder.iterdir())
names = {path.name for path in paths}
need(all(path.is_file() and not path.is_symlink() for path in paths)
and names in (RAW_FILES, RAW_FILES | {"source-proof.json"}), "exact closed raw files required: " + run)
raw = {path.name: path.read_bytes() for path in paths}
result = parsed(raw["result.json"])
need("finish" in result and result["inputsUnchanged"] is True, "unfinished/changed run refused: " + run)
matches = [data for data in helper_bytes if pin(data) == result["helper"]]
need(bool(matches), "exact historical helper unavailable for " + run + "; supply --helper PATH")
helper = "helpers/" + result["helper"]["sha256"] + ".py"
add(helper, matches[0])
for name, data in sorted(raw.items()):
add("cargo/" + run + "/" + name, data)
specs[run] = {key: result[key] for key in ("command", "head", "exitCode", "inputCount")}
specs[run]["helper"] = helper
if "source-proof.json" in raw:
proof = parsed(raw["source-proof.json"])
matches = [data for data in comparator_bytes if pin(data) == proof["comparator"]]
need(bool(matches), "exact source comparator unavailable for " + run + "; supply --comparator PATH")
comparator = "comparators/" + proof["comparator"]["sha256"] + ".py"
add(comparator, matches[0])
specs[run]["sourceProof"] = {"commit": proof["commit"], "pin": pin(raw["source-proof.json"]), "comparator": comparator}
manifest = {"schema": 1, "kind": "allocation-multiselect-cargo-gates", "runs": specs,
"captureHelpers": helper_catalog,
"logicalFiles": dict(sorted(logical.items())),
"members": {name: pin(data) for name, data in sorted(payload.items())}}
summary = verify_data(manifest, payload.__getitem__)
return payload, manifest, summary
def write_json(path, value):
with path.open("xb") as output:
output.write((json.dumps(value, indent=2) + "\n").encode("utf-8"))
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--root", type=Path, required=True, help="checkout holding .local/allocation-group-gates")
parser.add_argument("--runs", nargs="+", required=True, help="explicit run names, including failures to retain")
parser.add_argument("--helper", type=Path, action="append", default=[], help="additional exact historical helper (repeatable)")
parser.add_argument("--comparator", type=Path, action="append", default=[], help="additional exact historical source comparator (repeatable)")
parser.add_argument("--output", type=Path, help="fresh, nonexistent package directory (required unless --check-only)")
parser.add_argument("--check-only", action="store_true", help="validate raw captures in memory without creating an archive")
args = parser.parse_args()
need(all(run_name(run) for run in args.runs) and len(args.runs) == len(set(args.runs)), "unique safe run names required")
need(args.check_only or args.output is not None, "--output is required unless --check-only")
if not args.check_only:
need(not args.output.exists(), "output must be a fresh directory: " + str(args.output))
payload, manifest, summary = collect(args.root.resolve(), args.runs, args.helper, args.comparator)
if args.check_only:
print("PASS raw consistency; no package written:", summary)
return
out = args.output.resolve()
out.mkdir(parents=True, exist_ok=False)
for name in ("evidence.zip", "manifest.json", "files.json"):
need(not (out / name).exists(), "existing package output refused: " + name)
for name in ("prepare.py", "verify.py", "README.md"):
data = (HERE / name).read_bytes()
destination = out / name
if destination.exists():
need(destination.read_bytes() == data, "different existing package tool: " + name)
else:
with destination.open("xb") as output:
output.write(data)
with zipfile.ZipFile(out / "evidence.zip", "x", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as archive:
for name, data in sorted(payload.items()):
info = zipfile.ZipInfo(name, date_time=(2026, 9, 23, 0, 0, 0))
info.compress_type = zipfile.ZIP_DEFLATED
info.external_attr = 0o100644 << 16
archive.writestr(info, data)
write_json(out / "manifest.json", manifest)
names = ("prepare.py", "verify.py", "README.md", "manifest.json", "evidence.zip")
write_json(out / "files.json", {name: pin((out / name).read_bytes()) for name in names})
need(verify_package(out) == summary, "written package differs from validated captures")
print("PASS package readback:", out, summary)
if __name__ == "__main__":
main()
@@ -0,0 +1,194 @@
"""Offline consistency checks only; never execute or extract archived inputs."""
from pathlib import Path, PurePosixPath
from datetime import datetime
import argparse
import hashlib
import io
import json
import math
import re
import stat
import zipfile
RAW_FILES = {"started.json", "process.json", "result.json", "stdout.log", "stderr.log", "inputs.json", "inputs.zip"}
OUTER_FILES = {"prepare.py", "verify.py", "README.md", "manifest.json", "evidence.zip"}
def need(condition, message):
if not condition:
raise ValueError(message)
def pin(data):
return {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()}
def valid_pin(value):
return (isinstance(value, dict) and set(value) == {"bytes", "sha256"}
and type(value["bytes"]) is int and value["bytes"] >= 0
and isinstance(value["sha256"], str)
and re.fullmatch(r"[0-9a-f]{64}", value["sha256"]) is not None)
def safe(name):
return (isinstance(name, str) and bool(name) and "\\" not in name and ":" not in name
and all(ord(char) >= 32 for char in name)
and not PurePosixPath(name).is_absolute()
and all(part not in ("", ".", "..") for part in name.split("/")))
def run_name(name):
return isinstance(name, str) and re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]*", name) is not None
def parsed(data):
def pairs(items):
result = {}
for key, value in items:
need(key not in result, "duplicate JSON key: " + key)
result[key] = value
return result
def constant(value):
raise ValueError("nonfinite JSON constant: " + value)
return json.loads(data, object_pairs_hook=pairs, parse_constant=constant)
def inventory(archive, expected):
names = archive.namelist()
need(len(names) == len(set(names)) and set(names) == set(expected), "exact ZIP membership")
for entry in archive.infolist():
need(safe(entry.filename) and not entry.is_dir(), "unsafe ZIP member: " + entry.filename)
need(not stat.S_ISLNK(entry.external_attr >> 16), "ZIP symlink: " + entry.filename)
need(valid_pin(expected[entry.filename]), "invalid member pin: " + entry.filename)
need(entry.file_size == expected[entry.filename]["bytes"], "ZIP recorded size: " + entry.filename)
def ordered_times(*values):
times = [datetime.fromisoformat(value) for value in values]
return all(value.utcoffset() is not None for value in times) and times == sorted(times)
def verify_data(manifest, read):
"""Shared read-only verifier for packaged bytes or prepare's in-memory payload."""
need(manifest["schema"] == 1 and manifest["kind"] == "allocation-multiselect-cargo-gates", "manifest schema")
runs, logical, stored = manifest["runs"], manifest["logicalFiles"], manifest["members"]
helpers = manifest["captureHelpers"]
need(isinstance(helpers, dict) and set(helpers) == {"gate.py", "source-proof.py"}, "capture helper names")
need(all(isinstance(name, str) and re.fullmatch(r"helpers/[0-9a-f]{64}\.py", name)
for name in helpers.values()), "capture helper mapping")
need(isinstance(runs, dict) and bool(runs) and all(run_name(run) for run in runs), "explicit run inventory")
need(all(safe(name) for name in logical) and all(safe(name) for name in stored), "unsafe manifest path")
need(set(logical.values()) == set(stored), "unreferenced or absent stored members")
for name, expected in stored.items():
need(valid_pin(expected) and pin(read(name)) == expected, "stored member hash: " + name)
expected_logical = {"cargo/" + run + "/" + name for run in runs for name in RAW_FILES}
expected_logical.update(spec["helper"] for spec in runs.values())
expected_logical.update(helpers.values())
for run, spec in runs.items():
if "sourceProof" in spec:
proof_spec = spec["sourceProof"]
need(set(proof_spec) == {"commit", "pin", "comparator"}, run + ": exact source proof spec")
need(isinstance(proof_spec["commit"], str) and re.fullmatch(r"[0-9a-f]{40}", proof_spec["commit"]), run + ": named full source commit")
need(valid_pin(proof_spec["pin"]), run + ": source proof pin")
need(isinstance(proof_spec["comparator"], str) and re.fullmatch(r"comparators/[0-9a-f]{64}\.py", proof_spec["comparator"]), run + ": comparator path")
expected_logical.update({"cargo/" + run + "/source-proof.json", proof_spec["comparator"]})
need(set(logical) == expected_logical, "exact logical raw/helper inventory")
for name, destination in logical.items():
if name.startswith("cargo/") and name.rsplit("/", 1)[1] in {"inputs.json", "inputs.zip"}:
expected = "capsules/" + stored[destination]["sha256"] + PurePosixPath(name).suffix
need(destination == expected, "input capsule mapping: " + name)
else:
need(destination == name, "only input maps/archives may be deduplicated: " + name)
def raw(name):
return read(logical[name])
for name, helper in helpers.items():
need(helper == "helpers/" + pin(raw(helper))["sha256"] + ".py", "named helper hash: " + name)
seen_capsules = set()
for run, spec in runs.items():
prefix = "cargo/" + run + "/"
start = parsed(raw(prefix + "started.json"))
process = parsed(raw(prefix + "process.json"))
result = parsed(raw(prefix + "result.json"))
required_start = {"start", "command", "cwd", "head", "scope", "inputs", "archive",
"inputCount", "environment", "helper", "cargo", "rustc"}
need(required_start <= start.keys(), run + ": incomplete start receipt")
need(all(result.get(key) == value for key, value in start.items()), run + ": start/result relationship")
command = result["command"]
need(isinstance(command, list) and command and command[0] == "cargo"
and all(isinstance(arg, str) for arg in command), run + ": Cargo command")
need(command == process["command"] == spec["command"], run + ": command relationship")
need(result["head"] == spec["head"] and re.fullmatch(r"(?:[0-9a-f]{40}|[0-9a-f]{64})", result["head"]), run + ": HEAD")
need(type(result["exitCode"]) is int and result["exitCode"] == spec["exitCode"], run + ": recorded exit")
need(result["inputsUnchanged"] is True, run + ": changed inputs refused")
need(type(result["seconds"]) in (int, float) and math.isfinite(result["seconds"])
and result["seconds"] >= 0, run + ": duration")
need(type(process["pid"]) is int and process["pid"] > 0, run + ": process identity")
need(ordered_times(start["start"], process["observed"], result["finish"]), run + ": completed timestamp order")
for field, filename in [("inputs", "inputs.json"), ("archive", "inputs.zip"), ("stdout", "stdout.log"), ("stderr", "stderr.log")]:
need(result[field] == pin(raw(prefix + filename)), run + ": " + field + " pin")
need(valid_pin(result["helper"]) and result["helper"] == pin(raw(spec["helper"])), run + ": helper pin")
need(spec["helper"] == "helpers/" + result["helper"]["sha256"] + ".py", run + ": helper mapping")
inputs = parsed(raw(prefix + "inputs.json"))
need(isinstance(inputs, dict) and all(safe(name) for name in inputs), run + ": safe input inventory")
need(type(result["inputCount"]) is int and len(inputs) == result["inputCount"] == spec["inputCount"], run + ": input counts")
if "sourceProof" in spec:
proof_spec = spec["sourceProof"]
proof_bytes = raw(prefix + "source-proof.json")
proof = parsed(proof_bytes)
need(pin(proof_bytes) == proof_spec["pin"], run + ": source proof pinned bytes")
need(proof["run"] == run and proof["commit"] == proof_spec["commit"], run + ": proof run/commit identity")
need(proof["status"] == "PASS exact captured input inventory and Git blob bytes", run + ": source proof status")
need(proof["inputCount"] == len(inputs) and proof["inputMap"] == result["inputs"], run + ": proof input relationship")
need(proof["result"] == pin(raw(prefix + "result.json")), run + ": proof result relationship")
need(ordered_times(result["finish"], proof["verified"]), run + ": proof time after closed gate")
comparator = proof_spec["comparator"]
need(valid_pin(proof["comparator"]) and pin(raw(comparator)) == proof["comparator"], run + ": comparator bytes")
need(comparator == "comparators/" + proof["comparator"]["sha256"] + ".py", run + ": comparator identity")
need(sum(name.startswith("crates/vendor/iced_widget/") for name in inputs) == 71, run + ": vendor count")
capsule = (logical[prefix + "inputs.json"], logical[prefix + "inputs.zip"])
if capsule not in seen_capsules:
with zipfile.ZipFile(io.BytesIO(raw(prefix + "inputs.zip"))) as source:
inventory(source, inputs)
for name, expected in inputs.items():
need(pin(source.read(name)) == expected, run + ": source hash " + name)
seen_capsules.add(capsule)
artifacts = []
for line in raw(prefix + "stdout.log").decode("utf-8", errors="replace").splitlines():
try:
value = json.loads(line)
except json.JSONDecodeError:
continue
if isinstance(value, dict) and value.get("reason") == "compiler-artifact" and value.get("executable"):
artifacts.append(value)
need(isinstance(result["artifacts"], list), run + ": artifact records")
need(artifacts == [record["cargo"] for record in result["artifacts"]], run + ": Cargo JSON artifact relationship")
for record in result["artifacts"]:
need(set(record) == {"cargo", "readback"}
and (record["readback"] is None or valid_pin(record["readback"])), run + ": artifact readback pin")
print(run, "recorded exit", result["exitCode"], "inputs", len(inputs), "executable records", len(artifacts))
return {"runs": len(runs), "recordedFailures": sum(spec["exitCode"] != 0 for spec in runs.values()),
"logicalFiles": len(logical), "storedMembers": len(stored), "sourceCapsulePairs": len(seen_capsules),
"captureHelpers": helpers, "sourceProofs": sum("sourceProof" in spec for spec in runs.values())}
def verify_package(root):
files = parsed((root / "files.json").read_bytes())
need(set(files) == OUTER_FILES, "outer file inventory")
for name, expected in files.items():
need(valid_pin(expected) and pin((root / name).read_bytes()) == expected, "outer hash: " + name)
manifest = parsed((root / "manifest.json").read_bytes())
with zipfile.ZipFile(root / "evidence.zip") as archive:
inventory(archive, manifest["members"])
return verify_data(manifest, archive.read)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("package", nargs="?", type=Path, default=Path(__file__).resolve().parent)
args = parser.parse_args()
print("PASS offline consistency:", verify_package(args.package))
print("Historical receipts only; no source/binary execution or native acceptance claim.")
if __name__ == "__main__":
main()
@@ -0,0 +1,16 @@
# Assignment review archive
Exact historical design, fixtures and independent review notes, with original
`.local` paths preserved inside the archive. Their relative links refer to that
original checkout context; extract only into a separate scratch directory if
needed. Do not interpret historical plans or source-derived predictions as
executed results. The review addendum inspects the recorded 84-test gate without
claiming an independent rerun. The App adapter plan is design only.
The newline diagnosis records why three initial exact source comparisons
refused. Their captures were retained and canonical-byte gates rerun; historical
receipts were not rewritten. Current accepted facts and limitations are in the
[planner report](../../allocation-assignment-planner-20260923.md).
`files.json` pins this archive/index/readme; `members.json` pins every exact ZIP
member. Neither internal hashes nor independent review replace runtime evidence.
@@ -0,0 +1,14 @@
{
"reviews.zip": {
"bytes": 26141,
"sha256": "35a5faaf9f60eaa88d8c97f8a34dceac7a2cebf356ac6f69ec0e794cec258101"
},
"members.json": {
"bytes": 840,
"sha256": "3b1ce35c9b65b241b80367c90adc0ffbc65155d9cea8872f98e58901b2d52513"
},
"README.md": {
"bytes": 952,
"sha256": "a518a056c78b982c45f8d9a2098729f27df8f1702132c0e4cc6c555c603dbd22"
}
}
@@ -0,0 +1,22 @@
{
".local/allocation-group-design/assignment-plan.md": {
"bytes": 16268,
"sha256": "000b80e13845a1532e083281ee94486964306af0ce7fb27fee3a9eb2074f2405"
},
".local/allocation-group-design/assignment-fixtures.md": {
"bytes": 11563,
"sha256": "507e5d33745ffb65f096a8c5640f6e22d61ecb8701eb13769bfe538069e71ecc"
},
".local/allocation-group-design/assignment-review.md": {
"bytes": 11510,
"sha256": "f1c36cdba4a6f74770d541d9529d7f116473b2bc78bc2b2902c80f387eba82d1"
},
".local/allocation-group-design/app-adapter-plan.md": {
"bytes": 21648,
"sha256": "316633ae45d8f9836212d37e64639251cdb2fd96cda522d0a979d9bc81782cf7"
},
".local/allocation-evidence-tools/assignment-newline-diagnosis.json": {
"bytes": 622,
"sha256": "60631de3a45d0cb6c4108e7aaaf170b80e43e00e076674aabf379d05ee77a62a"
}
}
@@ -0,0 +1,115 @@
# Ordinary Allocation group assignment: pure planner checkpoint
Status: implemented and verified as a pure planner; App wiring and native
acceptance remain pending. Source commit
`33e880103c5fa935a4431ec3dc089e2c4c92f680`, on the Allocation contribution branch
above the [Arrange foundation](allocation-arrange-planner-20260923.md).
This is a branch-specific checkpoint, not an integrated application release.
Required behavior comes from [multiselect](multiselect-contract-20260923.md),
[Allocation v2](release-activity-allocation-drag-contract-v2-20260911.md) and the
[explicit Arrange amendment](allocation-arrange-amendment-20260923.md).
No core model, source schema or user-owned specification changed.
## Result and design
Ordinary assignment captures every original visible work placement before
normalizing selected semantic ancestors. It collects the union of leaf work,
including unplaced leaves, and existing active placements, including folded
descendants. Each normalized root retains its own accepted responsibility:
independent roots may start under different performers; a distributed composite
still refuses ordinary assignment. Already-correct role-only work does not gain
a direct Allocation merely because another selected root changes performer.
One destination plan accumulates stable IDs, unique aliases and intended edits,
prepares one semantic Batch, and compares the complete candidate Project with
the intended result. Existing Allocation IDs and header metadata survive
retargeting. Outside removes only intended direct Allocations and their own
saved routes across views. Role exits and collateral changes to surviving
records refuse the whole plan. Warning collection and changed/already-correct
leaf counts are retained for future App feedback.
One shared geometry helper now serves singleton assignment, group assignment
and explicit Arrange. It uses accepted endpoint ownership and the complete
movement map: internal pins translate once, one-ended pins stay fixed, labels
and attachments remain exact. Geometry checks compare whole visible scenes and
the affected/ancestor diagnostic expansion, require rigid affected footprints
and every original selected header, and authorize target unfolding only when
assignment actually changes. Accepted and candidate expansion use their own
ancestry. Per-pointer placement does not clone or validate a Project or rebuild
semantic indexes. Finish rechecks the entire live Project and recomputes the
placement before one exact source Batch. Zero movement can still change
assignment; complete Project equality alone yields no command.
## Verification
Windows gnullvm, cargo/rustc 1.98.1, LLVM-MinGW 20260826, one Cargo build job,
incremental disabled. Linux remains user-deferred. The focused example imports
the actual production planner and Document modules; it is not a substitute
implementation. Commands:
```powershell
cargo test -p oa-desktop --example allocation_policy_probe --message-format=json -- --test-threads=1
cargo clippy -p oa-desktop --example allocation_policy_probe --tests --message-format=json -- -D warnings
cargo fmt --all -- --check
```
Final canonical-byte gates: `assignment-planner-3` **84 passed, 0 failed**,
`assignment-lint-2` strict lint passed, `assignment-format-2` passed. Each captured
750 unchanged inputs, including 71 vendored dependency files and both explicit
compiled fixtures; all captured blobs compare exactly with source commit
`33e880103c5fa935a4431ec3dc089e2c4c92f680`.
Final input-map SHA256:
`ce988ecaeaca395d0f120844db7e3da90d039633beef10d2d4a8b8f19e92ee27`.
The 14 added test families cover OA/SA independent roots and original identity,
normalization/unplaced work, distributed composite versus independent leaves,
role provenance and unresolved OA roles, stable IDs/aliases, zero-delta semantic
change, target unfold and newly exposed overlap, simultaneous vacated-space
movement, internal/external routes with explicit attachments and SA port anchor,
own-route deletion across views, surviving Constraint collateral refusal,
stale/tampered results and all selected headers. Existing singleton/Arrange and
Document tests remain in the same passing suite.
Positive tests use independently authored complete Projects and actual Document
execute, source compilation/reopen and exact one-step Undo/Redo. The source-budget
case executes the actual group command against an existing Document with Undo
and Redo available, preserves Project/bundle/revision, and exercises both history
paths after refusal. The same command/IDs then succeed in a fresh normal-budget
Document; this is not evidence of same-session gesture retry.
Independent review found no concrete planner defect. A second pass reviewed
the added evaluators and found no blocking invalid fixture or circular oracle.
It inspected the captured 84-test result without claiming its own execution.
Exact historical notes and newline diagnosis are in the
[review archive](allocation-assignment-evidence-20260923/reviews/README.md).
## Evidence identity and limits
The [portable gate package](allocation-assignment-evidence-20260923/checks/README.md)
retains seven runs: the first 75-test capture, expanded 84-test capture, initial
lint/format and three final canonical-byte gates. Initial expanded checks
passed, but exact Git comparison refused because `arrange.rs` was CRLF in the
working tree and LF in the committed blob. The independently checked difference
was newline-only. Those historical captures are not attributed to the pristine
commit and have no source-proof receipt. The file was restored to the committed
bytes and all three gates rerun. No receipt or historical log was rewritten.
Run the package verifier with `python -B checks/verify.py` from the evidence
directory. It checks archive/receipt consistency and pinned historical source
proofs, not external authenticity or a new Git comparison. The report's named
source comparisons were executed separately against actual Git blobs.
Remaining focused protective coverage includes deeper folded-grandchild group
reassignment and a changed-assignment enclosure-growth blocker. Existing
singleton and shared geometry coverage reduces but does not remove those gaps.
Role warning collection is reviewed; the new role tests do not independently
assert every warning code/severity.
There is no new App execution, full desktop test run, matching GUI build or native
acceptance for this checkpoint. Exact typed selection, frozen pointer target,
minimum readable zoom, pending-click behavior, sticky drag threshold, selection
generation, clean-owner admission and focus/camera/token retirement remain the
App adapter's obligations. The archived App plan is design only. Neither this
checkpoint nor the earlier Arrange foundation closes issue 29 or authorizes a
combined release; the coordinated integration/release owner is unchanged.
+4 -2
View File
@@ -82,8 +82,10 @@ feedback and hit geometry remain stable throughout the gesture.
The [explicit Arrange amendment](allocation-arrange-amendment-20260923.md) defines
the bounded one-or-more work/performer footprint and diagnostic collision domain.
Its [pure planner evidence](allocation-arrange-planner-20260923.md) does not yet
establish App/native group input acceptance or ordinary group assignment.
Its [pure planner evidence](allocation-arrange-planner-20260923.md) and the
[ordinary assignment foundation](allocation-assignment-planner-20260923.md)
establish bounded source/planner behavior. App/native group input acceptance
remains pending.
## Related group actions