Record Process removal Windows and native verification
This commit is contained in:
@@ -95,3 +95,6 @@ harness/experiments/analysis-source-s2a-windows-20260913/** -text whitespace=-bl
|
||||
|
||||
# Preserve the pinned Iced dependency bytes and upstream manifest.
|
||||
crates/vendor/iced_widget/** -text whitespace=cr-at-eol
|
||||
|
||||
# Preserve exact Process removal review and portable evidence bytes.
|
||||
harness/process-group-removal-evidence-20260925/** -text whitespace=cr-at-eol
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
# Process aggregate removal — App implementation and verification, 2026-09-25 UTC
|
||||
|
||||
Local-only contribution for issue 29. Source `572e96ba03522cfb822b13fe4abb50e857a5de48` builds and runs on Windows. Process/FunctionalChain aggregate removal has source review, filtered regression checks and a native OA model/source/history/reopen receipt. Compact-window acceptance remains open. No integration, release or remote publication is claimed.
|
||||
|
||||
## Behavior and reviewed corrections
|
||||
|
||||
The [removal policy](process-group-removal-policy-20260925.md) defines this scope. Process/FunctionalChain removal captures the complete typed group of listed local contributions and maintained links, admits every original member, and evaluates one Batch. Occurrence cascade coverage suppresses redundant selected-link commands without hiding those selections from review. Qualified previews cause whole-set refusal; local ContextualLinks use explicit owner even with qualified endpoints. Actual before/after candidates determine removed identities and changed surviving records, including embedded placements. Referenced definitions, other uses and opposite-layer counterparts are preserved under existing core cascade rules.
|
||||
|
||||
Review separately reports stored impact, local listed order, expanded indexed order, contextual-analysis changes and surviving caller definitions. Caller impact includes ordinary explicit-to-explicit topology changes, and warns that reused entry/exit connectivity and diagnostics may change without creating stored identities. It does not claim complete expanded graph analysis or count repeated reference instances as separate caller definitions.
|
||||
|
||||
Source review found and corrected:
|
||||
|
||||
- P1: interpretation-only caller closure missed changed explicit topology. `affected_uses` now derives from actual changed definition topology, independently of interpretation deltas; literal OA/SA direct, repeated and transitive caller discriminators were added.
|
||||
- P2: empty local-order wording falsely denied surviving unlisted contributions. Review now says “Empty order” / “One item in this order,” retaining incomplete-flow qualifications and separate dimensions when they differ.
|
||||
- A same-input-batch queued Delete could precede a later private gesture while App admission lacked that evidence. Synchronous shared input generation and a gesture lease now revoke stale captures; mounted production-tree and lease lifecycle discriminators were added. The bounded source review found the specific race addressed, without claiming every viewport gesture is represented.
|
||||
- Independent planner review prompted literal tests for covered plus uncovered selected links and global attachment/trace/placement/diagram bookkeeping. Final source review at `fe637dcd277b17653139ffa234e601b29775c565` found no new actionable production finding in its bounded scope. Its later menu-correction addendum likewise found no actionable issue. These reviews did not execute runtime/native gates.
|
||||
|
||||
Exact historical review notes: [policy critique](process-group-removal-evidence-20260925/policy-critique.md), [planner](process-group-removal-evidence-20260925/planner-review.md), [adapter](process-group-removal-evidence-20260925/adapter-review.md), and [final review/addendum](process-group-removal-evidence-20260925/final-review.md). Their original source/runtime boundaries remain intact; source-only conclusions are not retroactively represented as executed tests.
|
||||
|
||||
## Closed failed gate history
|
||||
|
||||
Both runs used Windows `stable-x86_64-pc-windows-gnullvm`, Cargo/rustc 1.98.1, one build job, incremental compilation disabled, and:
|
||||
|
||||
```text
|
||||
cargo test -p oa-desktop --message-format=json -- process_ topology scenario_removal removal --test-threads=1
|
||||
```
|
||||
|
||||
The identified local closed receipts for `process-removal-tests-1` and `process-removal-tests-2` were inspected with their exact source proofs and logs. Raw evidence publication is pending; these local files are not a peer-accessible handoff. Both closed with exit 101 and unchanged captured inputs. Each separate source proof passed exact captured inventory/Git-blob comparison; that proof does not change the failed test outcome. Neither command is the full suite (1469 tests filtered out).
|
||||
|
||||
1. **Gate 1**, source `fe637dcd277b17653139ffa234e601b29775c565`, finished 03:12:51 UTC: **185 passed, 2 failed**. The existing qualified-definition navigation regression exposed a real menu omission. Correction `f20497b29bf637619bc35ffe41274fc0f66c387b` restores qualified navigation before the aggregate menu early return, preserving exact endpoint/context and whole-group removal. The other failure was the newly authored v1 lexical oracle: complete semantic Project equality passed, then exact Document source equality failed. Independent source-policy investigation derived retained declaration trivia (22/20/16 spaces and existing annotation LF boundaries) and unformatted surviving `[@e1,@e2]`. V2 was derived from the checksum-pinned baseline before separate comparison with observed output; it matched 2258 bytes, SHA256 `b4a2b07ad4c796f555c61945ca42b1c221b454b35488c60fefc86f96f7aa71ba`. V1 and failed evidence remain preserved. This was an incorrect lexical assumption, not evidence of a semantic deletion defect or a new writer regression. See the [exact source-oracle investigation](process-group-removal-evidence-20260925/source-oracle-investigation.md).
|
||||
2. **Gate 2**, source `f20497b29bf637619bc35ffe41274fc0f66c387b`, finished 03:20:16 UTC: **186 passed, 1 failed**. Qualified-navigation regression passed. In the literal test, complete Project and exact Document/v2 source assertions passed; the later `app.source_workspace.bundle()` equality failed. This is distinct from v1: the fixture helper replaced Document after `open_project` but retained its generated split workspace. `sync` preserves discovered files; it is not a new-document initializer. Commit `d93c0a801249f361d95721fb0fc239a95159af5c` initializes `Workspace::new(app.document.bundle(), true)` before sync and asserts baseline workspace equality. No production writer change or weakened source equality was needed. Undo/Redo assertions later in this failing test were not reached.
|
||||
|
||||
|
||||
## Closed correction and final-source gates
|
||||
|
||||
All gates below closed with unchanged captured inputs and a separate PASS proving exact input inventory/Git-blob bytes. The result/input-map hashes were checked against those proofs. A source-proof PASS means source binding; it does not turn a failed gate into a pass.
|
||||
|
||||
| Gate | Identified source | Result |
|
||||
| --- | --- | --- |
|
||||
| tests-3 | d93c0a801249f361d95721fb0fc239a95159af5c | 187 passed, 0 failed; 1469 filtered out |
|
||||
| clippy-1 | d93c0a801249f361d95721fb0fc239a95159af5c | Exit 101: two style lints under warnings-as-errors |
|
||||
| tests-4 | 572e96ba03522cfb822b13fe4abb50e857a5de48 | 27 passed, 0 failed; 1629 filtered out |
|
||||
| format-3 | 572e96ba03522cfb822b13fe4abb50e857a5de48 | PASS, exit 0 |
|
||||
| clippy-2 | 572e96ba03522cfb822b13fe4abb50e857a5de48 | PASS, exit 0 |
|
||||
| build-1 | 572e96ba03522cfb822b13fe4abb50e857a5de48 | Studio and CLI PASS, exit 0 |
|
||||
|
||||
Gate names have the prefix `process-removal-`. Tests-3 used the broad filtered test command above and passed the literal model/source/one-Undo/Redo case after the fixture initialization correction. Clippy-1 identified manual parity and manual saturating arithmetic in the input lifetime helper. Commit `572e96ba03522cfb822b13fe4abb50e857a5de48` replaces `generation % 2 == 0` with `generation.is_multiple_of(2)`, and `checked_add(2).unwrap_or(u64::MAX)` with `saturating_add(2)`; these retain the same unsigned-integer and terminal-overflow semantics. Tests-4 reran the affected Process removal, input generation and gesture coverage on that final source. The broad 187-test result belongs to d93c0a80, not a rerun of all 187 on 572e96ba.
|
||||
|
||||
Final-source commands:
|
||||
|
||||
```text
|
||||
cargo test -p oa-desktop --message-format=json -- process_removal removal_input group_gesture --test-threads=1
|
||||
cargo fmt --all --check
|
||||
cargo clippy -p oa-desktop --all-targets -- -D warnings
|
||||
cargo build -p oa-desktop -p oa-cli --message-format=json
|
||||
```
|
||||
|
||||
Runtime results are filtered Windows evidence, not a full-suite or Linux claim. Both passing test runs include the literal aggregate removal model/source history oracle and mounted queued-Delete/camera-boundary discriminator.
|
||||
|
||||
Receipt SHA-256 anchors (result.json; raw package publication pending):
|
||||
|
||||
| Gate | SHA-256 |
|
||||
| --- | --- |
|
||||
| tests-3 | 82709fef9b1aabdf2fcc07a7cb9300d16474bc62370d7157e6bb6270cd8264f8 |
|
||||
| tests-4 | 8513d24b9f05645908f4a475fcc90b5887362473f8046282bfd8af6a24c61dd5 |
|
||||
| format-3 | 7ec891fa7a881b4f04fc3f58047a15f3972b397b7d2595e4a0bb04a9f658d9a3 |
|
||||
| clippy-1 | 35e1afdd586853dbd992b3b944045e479297bf6dc2bf33db5186be0a51c3e41f |
|
||||
| clippy-2 | 12f3352607a1608fcd1242b48336ae877b81677df38d96d17bbe9dc6ed3ff49b |
|
||||
|
||||
## Native verification and portable records
|
||||
|
||||
The closed build has 832 unchanged captured inputs and an exact Git-blob source proof. Its copied Studio binary and explicitly pinned libunwind.dll launch with only Windows system directories on PATH. Current CLI preflight accepts both oracle-v2 files with warning-only model diagnostics. Run 1 removes Action @a, Control @c (both named Review gate) and their selected authored link @approved. The review distinguishes them by alias and exposes all ten effects through scrolling and two pages: three selected removals, one updated owner, before/after implicit-order consequences, the two remaining exchange positions and direct/transitive caller definitions. Search finds @outer; Enter does not confirm; empty search supplies recovery guidance. Cancel and Escape retain the full group and link primary. Header, context menu over an unselected object, focused Delete and focused Shift+Delete all open the complete review.
|
||||
|
||||
After restoring/reactivating the window, the captured review is expired and Remove is disabled; that native sequence does not isolate resizing from focus changes. Explicit confirmation of a fresh review leaves two exchange cards and their implicit connection. Save produces exactly 2258 oracle bytes; one Undo and Save restores all 2609 baseline bytes; one Redo and Save reproduces all 2258 removed bytes. Run 2 starts a fresh process from the saved Redo file, displays the same two exchanges/implicit connection and saves identical bytes. Both processes exit normally with empty logs and unchanged executable, runtime and fixture pins. These exact bytes preserve underlying work/exchanges, caller definitions/references and SA sentinels.
|
||||
|
||||
The [native action record](process-group-removal-evidence-20260925/native-actions.md) identifies capture labels, actual keys, source snapshots and automation failures. Captures are observations, not an instrumented input log. Membership used context Add, not native Shift-click. After Escape, Shift+Delete required F6 to restore canvas focus. A restored-window capture initially failed as minimized and recovered through fresh window selection/reactivation; a later out-of-bounds positioning drag was rejected before capture. These are recorded separately from application behavior. True compact 1100px layout is unverified; the restored view was partly clipped by the desktop. Maximum-window review reachability is established at 1605x872.
|
||||
|
||||
Portable [Cargo records and offline verifier](process-group-removal-evidence-20260925/checks/README.md) preserve all ten attempts, including three failures, with four distinct source input capsules. [Native archive](process-group-removal-evidence-20260925/native/native-evidence.zip) and [standalone verifier](process-group-removal-evidence-20260925/native/verify.py) preserve original v1, separately derived v2, 53 raw capture records, exact saved snapshots and closed process receipts. Both standalone verifiers pass. Native ZIP: 5,617,713 bytes, SHA256 `f77fd3abe7ecc5838395b94a95ba935c8dc5c10a36c8e3a2c1ec4a1da1521b84`, 327 members, six omitted executable/DLL payloads represented by pins. These evidence archives are not runnable releases.
|
||||
|
||||
Cargo ZIP: 13,162,535 bytes, SHA256 `13aeacd8b1326ec5d57d49a13e8fd0c2e8611f85da1244cbcb1362edcb6fd4d5`. The [independent native review](process-group-removal-evidence-20260925/native-review.md) found no blocking issue within the bounded flow, recomputed both runs' immutable file pins and checked all saved-source results. It preserves the distinction between parent-reported actions and captured states, and leaves compact layout and accessibility unaccepted. Exact source comparison and archive integrity do not substitute for this visual review. Recheck records offline with Python 3.11+:
|
||||
|
||||
```text
|
||||
python -B harness/process-group-removal-evidence-20260925/checks/verify.py
|
||||
python -B harness/process-group-removal-evidence-20260925/native/verify.py harness/process-group-removal-evidence-20260925/native
|
||||
```
|
||||
|
||||
## Remaining scope and publication
|
||||
|
||||
This native receipt covers OA derived layout and the bounded fixture. SA/qualified paths, cascades, stale input races and command-failure preservation have separate filtered-test evidence. Actual Process source-budget failure, native Shift-click, compact layout, comprehensive accessibility, full-suite and Linux acceptance are unclaimed. Preserve these limits when integrating; no issue closure is justified by this branch alone.
|
||||
|
||||
Fresh guarded push was rejected with `remote unpack failed: unable to create temporary object directory`; a Gitea MCP issue-comment write also failed. Read operations work, main AGENTS remains blob e76647f49913b314e1543c4464f6199533909bae, and the remote contribution branch remains 43340b94. WSL DNS still timed out after ten seconds; Linux builds remain explicitly user-paused. These are observed failed attempts, not a newly verified disk-full root cause. Pending Scenario follow-up and this Process contribution remain local-only. Reconcile and publish the buffered issue-29 handoff when writes recover; do not overwrite remote history. Historical local paths inside copied reviews identify their original context, not peer-accessible deliverables.
|
||||
@@ -0,0 +1,112 @@
|
||||
# Independent Process removal adapter source review
|
||||
|
||||
Read-only inspection of uncommitted production adapter surfaces on base
|
||||
`c62622cce71e06f0beae49bc3b4fe8e890eba951`. Inspected `app/process_removal.rs`,
|
||||
its `view.rs`, and the diffs/context in `app.rs`, `app/diagram_removal.rs`,
|
||||
`app/escape.rs`, `model_menu.rs`, `views.rs`, `behavior/topology/view.rs` and
|
||||
`behavior/topology/direct_selection.rs`. Adapter tests were still being authored;
|
||||
no Cargo/UI execution and no production edits. This is not native acceptance.
|
||||
|
||||
## P2: local empty-order wording can deny surviving unlisted contributions
|
||||
|
||||
At inspection, `matching_rows` rendered `Some([])` as “No remaining
|
||||
contributions; no ordered pair” for both order dimensions; `Some([E])` rendered
|
||||
“One contribution; no ordered pair.” This is false when describing local listed
|
||||
order in the supported owned-but-unlisted case.
|
||||
|
||||
Literal discriminator: owner P lists Action A and owns unlisted Action U. Remove
|
||||
A. U survives; local order changes from explicit to `Some([])`, expanded order
|
||||
stays explicit. The review must not tell the user that no contributions remain.
|
||||
Use “No listed contributions” for the local dimension, “No indexed
|
||||
contributions” for the expanded dimension, or dimension-neutral “Empty order.”
|
||||
Similarly qualify “One contribution.” This is a wording defect introduced by
|
||||
the new review, not a request to repair preexisting desktop/core semantics.
|
||||
Reported to parent for the adapter owner.
|
||||
|
||||
## P2 candidate: same input-batch newer gesture is invisible to App admission
|
||||
|
||||
`process_removal_enabled` checks modal/draft/tool state but has no Process
|
||||
gesture token. `direct_selection::selection_input` correctly captures Delete
|
||||
when `Input.group` already exists, and blocks ordinary press/source gestures.
|
||||
However starting a group press sets only private canvas `Input.group` and
|
||||
publishes a redraw, leaving the App context and selection generation unchanged.
|
||||
|
||||
A source-supported event ordering to test, instead of arbitrary packet replay:
|
||||
|
||||
1. Production tree has local A/B selected and a cursor over selected A.
|
||||
2. The same UI event batch receives Delete, then LeftPressed over A.
|
||||
3. Delete publishes a captured removal Begin. LeftPressed starts private
|
||||
`Input.group` with the same context/snapshot and publishes redraw only.
|
||||
4. App consumes Begin after the UI batch; admission has no evidence of that
|
||||
newer gesture and opens review, increments epoch and retires the gesture.
|
||||
|
||||
Source evidence: `direct_selection.rs:209–229` publishes Begin;
|
||||
`:316–334` creates private GroupPress without an App gesture message;
|
||||
`app/process_removal.rs:51–92` admits using App state alone.
|
||||
`app/escape.rs` explicitly documents Iced's batching behavior, and existing
|
||||
production `Mounted.batch` topology tests exercise multiple input events before
|
||||
App messages are applied. This is a concrete plausible production-event path,
|
||||
but this reviewer did not execute it. Parent was asked to run the literal batch
|
||||
discriminator before treating it as a reproduced defect.
|
||||
|
||||
This can violate the policy's “active gestures refuse admission” promise, but
|
||||
does not silently delete: an explicit current review confirmation is still
|
||||
required. It therefore does not justify P1/data-loss severity from current
|
||||
evidence. The successful admission represents an earlier Delete followed by a
|
||||
later gesture in one batch; the project should either test/enforce the promised
|
||||
lifetime ordering or state a narrower supported guarantee. Do not claim the App
|
||||
proves absence of every private canvas gesture.
|
||||
|
||||
## Verified source properties
|
||||
|
||||
- Whole-group admission happens before shared source/canvas boundaries.
|
||||
`process_removal_matches` validates exact topology context, selection
|
||||
generation/membership/primary and actual graph target visibility. The planner
|
||||
subsequently refuses mixed local/qualified content as a whole.
|
||||
- Header and focused Delete/Shift+Delete capture complete snapshots. Keyboard
|
||||
repeat and unsupported modifiers do not issue deletion. Active GroupPress
|
||||
captures keyboard input before Delete can reach removal.
|
||||
- Process context-menu requests retain selection. Menu invocation accepts the
|
||||
new group message before ordinary clicked-object `select`, so a menu opened
|
||||
over an unselected object does not silently replace the group. Menu validity
|
||||
now also captures the Process selection snapshot.
|
||||
- Legacy `Message::Delete` and singleton TopologyCanvas Remove packets are
|
||||
refused while a group exists before shared state is disturbed. Qualified
|
||||
singleton previews remain read-only. A direct arbitrary Command injection is
|
||||
not an established production removal entry point and was not presented as a
|
||||
user-reachable bypass.
|
||||
- Query/Page/Cancel packets are token scoped; ConfirmDelete is checked before
|
||||
forwarding. Unstamped CancelDelete/Escape cannot close a later Process review.
|
||||
Root Escape emits the captured current review's token before focused search
|
||||
receives it. Search has no Enter-submit confirmation handler.
|
||||
- Confirmation checks current document/revision/owner/epoch, exact selection,
|
||||
actual visibility, primary inspector identity, pending source/property/
|
||||
behavior drafts, source rename and Select tool. It executes one captured
|
||||
Document command. Failed source preparation remains the Document layer's
|
||||
responsibility; this source review does not independently establish its
|
||||
runtime preservation behavior.
|
||||
- Initial enabled gates include hosted/workflow/file/pending/menu/usages/
|
||||
reference-input states via `keyboard_owner_enabled`. Existing modal dispatch
|
||||
prevents ordinary new modal actions while review is open. Confirm's local
|
||||
guard does not re-enumerate every other modal, but no concrete production path
|
||||
establishing an intervening competing modal was found. Do not promote a
|
||||
manually mutated App test alone into a claimed user-reachable failure.
|
||||
- Review distinguishes actual removed/updated records, local/expanded order,
|
||||
contextual-analysis changes and caller definitions. Affected-caller rows merge
|
||||
the prior P1 correction with interpretation caller closure. Repeated reference
|
||||
instances are not falsely counted as separate caller rows. The explanatory
|
||||
text acknowledges possible reused entry/exit changes and disclaims complete
|
||||
expanded graph analysis.
|
||||
- All impact rows are searchable/pageable with full names and aliases. Long
|
||||
text wraps. Footer is separate from the scrolling body. These structural
|
||||
choices support usability but do not establish native layout/focus behavior.
|
||||
|
||||
## Remaining acceptance work
|
||||
|
||||
Resolve or narrow the two items above. Run App and actual production-tree tests
|
||||
for stale/ABA snapshots, menu selection preservation, wrong/old tokens,
|
||||
source-write failure, exact cancel/Undo/Redo and keyboard focus. Inspect compact
|
||||
native modal layout, every impact category and search/page access, including a
|
||||
long implicit order and multiple caller definitions. Validate save/reopen on the
|
||||
identified tested source. No additional P1 production defect was found in this
|
||||
bounded review.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Process aggregate removal: captured checks
|
||||
|
||||
Python 3.11+ offline packaging/verification for explicitly named closed
|
||||
`process-removal-*` runs under `CHECKOUT/.local/scenario-group-gates`.
|
||||
These tools reuse the Scenario removal verifier unchanged except for the
|
||||
manifest kind and run-name prefix. They do not run Cargo, Git, network requests
|
||||
or archived code. Input capsules are deduplicated by hash; every original
|
||||
logical path and failed attempt remains in the manifest.
|
||||
|
||||
```text
|
||||
python -B prepare.py --root CHECKOUT --runs CLOSED_RUN_NAMES --output NEW_DIRECTORY
|
||||
python -B NEW_DIRECTORY/verify.py
|
||||
```
|
||||
|
||||
Supply the complete explicit attempt inventory, including failures. Existing
|
||||
output directories, incomplete runs, changed-input runs and missing source
|
||||
proofs are refused. Verification checks exact outer/raw/nested ZIP inventories
|
||||
and hashes, safe paths, command/process/time consistency, dynamic input counts,
|
||||
unchanged captures, executable Cargo-record relationships, source-proof bindings
|
||||
and pinned comparator provenance. All 71 tracked patched-widget files must be
|
||||
present. Failed exits remain failures even when archive verification passes.
|
||||
|
||||
An offline proof check does not execute the comparator or read Git objects.
|
||||
The parent separately compares all captured inputs to the named Git commit.
|
||||
Executables are omitted; only their pins and Cargo metadata are retained.
|
||||
Neither package integrity nor compilation establishes native usability,
|
||||
integration, release acceptance or completion of the application.
|
||||
Binary file not shown.
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"prepare.py": {
|
||||
"bytes": 6319,
|
||||
"sha256": "3d82c4784109d41feb969c94e406358e42c19d08e56952b04df768fef2a3d3f0"
|
||||
},
|
||||
"verify.py": {
|
||||
"bytes": 11528,
|
||||
"sha256": "d9fd0f14d5a034acf82830b0bf66577be72e9002693f5b7397b3fefdf921a047"
|
||||
},
|
||||
"README.md": {
|
||||
"bytes": 1517,
|
||||
"sha256": "d1d3087d55d54ad9afa8d451166ddbae61c846396c8d81381c0f27a5f39e6d3c"
|
||||
},
|
||||
"manifest.json": {
|
||||
"bytes": 28845,
|
||||
"sha256": "91455965138d6dfa19d8359da6114ed7ece995390d8026b1a944cd473058c34c"
|
||||
},
|
||||
"evidence.zip": {
|
||||
"bytes": 13162535,
|
||||
"sha256": "13aeacd8b1326ec5d57d49a13e8fd0c2e8611f85da1244cbcb1362edcb6fd4d5"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,621 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"kind": "process-aggregate-removal-cargo-gates",
|
||||
"runs": {
|
||||
"process-removal-tests-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--message-format=json",
|
||||
"--",
|
||||
"process_",
|
||||
"topology",
|
||||
"scenario_removal",
|
||||
"removal",
|
||||
"--test-threads=1"
|
||||
],
|
||||
"head": "fe637dcd277b17653139ffa234e601b29775c565",
|
||||
"exitCode": 101,
|
||||
"inputCount": 831,
|
||||
"helper": "helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py",
|
||||
"sourceProof": {
|
||||
"commit": "fe637dcd277b17653139ffa234e601b29775c565",
|
||||
"pin": {
|
||||
"bytes": 602,
|
||||
"sha256": "4074db859ff385c14941ba8e45530a7e748e0db45101339d881937663c0ef512"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
},
|
||||
"process-removal-tests-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--message-format=json",
|
||||
"--",
|
||||
"process_",
|
||||
"topology",
|
||||
"scenario_removal",
|
||||
"removal",
|
||||
"--test-threads=1"
|
||||
],
|
||||
"head": "f20497b29bf637619bc35ffe41274fc0f66c387b",
|
||||
"exitCode": 101,
|
||||
"inputCount": 832,
|
||||
"helper": "helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py",
|
||||
"sourceProof": {
|
||||
"commit": "f20497b29bf637619bc35ffe41274fc0f66c387b",
|
||||
"pin": {
|
||||
"bytes": 602,
|
||||
"sha256": "4ab508f91efc34fde8cc1fc99fcc174d22f9eaf141730f608582b0067007eb56"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
},
|
||||
"process-removal-tests-3": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--message-format=json",
|
||||
"--",
|
||||
"process_",
|
||||
"topology",
|
||||
"scenario_removal",
|
||||
"removal",
|
||||
"--test-threads=1"
|
||||
],
|
||||
"head": "d93c0a801249f361d95721fb0fc239a95159af5c",
|
||||
"exitCode": 0,
|
||||
"inputCount": 832,
|
||||
"helper": "helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py",
|
||||
"sourceProof": {
|
||||
"commit": "d93c0a801249f361d95721fb0fc239a95159af5c",
|
||||
"pin": {
|
||||
"bytes": 602,
|
||||
"sha256": "0407b22338c2d7bf725c8fe7098515a484cf67067578b4bf4992fa0a49bd3f93"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
},
|
||||
"process-removal-tests-4": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"test",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--message-format=json",
|
||||
"--",
|
||||
"process_removal",
|
||||
"removal_input",
|
||||
"group_gesture",
|
||||
"--test-threads=1"
|
||||
],
|
||||
"head": "572e96ba03522cfb822b13fe4abb50e857a5de48",
|
||||
"exitCode": 0,
|
||||
"inputCount": 832,
|
||||
"helper": "helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py",
|
||||
"sourceProof": {
|
||||
"commit": "572e96ba03522cfb822b13fe4abb50e857a5de48",
|
||||
"pin": {
|
||||
"bytes": 602,
|
||||
"sha256": "ff045bf753ec4e09abc980018dd90f38338889dcd0877200364f5460418df5c6"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
},
|
||||
"process-removal-format-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"fmt",
|
||||
"--all",
|
||||
"--",
|
||||
"--check"
|
||||
],
|
||||
"head": "fe637dcd277b17653139ffa234e601b29775c565",
|
||||
"exitCode": 0,
|
||||
"inputCount": 831,
|
||||
"helper": "helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py",
|
||||
"sourceProof": {
|
||||
"commit": "fe637dcd277b17653139ffa234e601b29775c565",
|
||||
"pin": {
|
||||
"bytes": 603,
|
||||
"sha256": "d36d50d20b92c49c0867d1468ed9d8062e23aa8cda9a995ad8bd91938e337335"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
},
|
||||
"process-removal-format-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"fmt",
|
||||
"--all",
|
||||
"--",
|
||||
"--check"
|
||||
],
|
||||
"head": "f20497b29bf637619bc35ffe41274fc0f66c387b",
|
||||
"exitCode": 0,
|
||||
"inputCount": 832,
|
||||
"helper": "helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py",
|
||||
"sourceProof": {
|
||||
"commit": "f20497b29bf637619bc35ffe41274fc0f66c387b",
|
||||
"pin": {
|
||||
"bytes": 603,
|
||||
"sha256": "6f6a756569f3877223932253db0cea5380d646dd221f467c69b3572289d9a2fc"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
},
|
||||
"process-removal-format-3": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"fmt",
|
||||
"--all",
|
||||
"--check"
|
||||
],
|
||||
"head": "572e96ba03522cfb822b13fe4abb50e857a5de48",
|
||||
"exitCode": 0,
|
||||
"inputCount": 832,
|
||||
"helper": "helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py",
|
||||
"sourceProof": {
|
||||
"commit": "572e96ba03522cfb822b13fe4abb50e857a5de48",
|
||||
"pin": {
|
||||
"bytes": 603,
|
||||
"sha256": "05d86dd797bf3c1a0d9c8b0c00a49294009ead98cb9e9c3e258d0cb59e9331b1"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
},
|
||||
"process-removal-clippy-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"clippy",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--all-targets",
|
||||
"--",
|
||||
"-D",
|
||||
"warnings"
|
||||
],
|
||||
"head": "d93c0a801249f361d95721fb0fc239a95159af5c",
|
||||
"exitCode": 101,
|
||||
"inputCount": 832,
|
||||
"helper": "helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py",
|
||||
"sourceProof": {
|
||||
"commit": "d93c0a801249f361d95721fb0fc239a95159af5c",
|
||||
"pin": {
|
||||
"bytes": 603,
|
||||
"sha256": "a758a8df8dbc2aa86b907856b69ca74f8219a9b462a83d690f06929ba3cc1797"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
},
|
||||
"process-removal-clippy-2": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"clippy",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"--all-targets",
|
||||
"--",
|
||||
"-D",
|
||||
"warnings"
|
||||
],
|
||||
"head": "572e96ba03522cfb822b13fe4abb50e857a5de48",
|
||||
"exitCode": 0,
|
||||
"inputCount": 832,
|
||||
"helper": "helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py",
|
||||
"sourceProof": {
|
||||
"commit": "572e96ba03522cfb822b13fe4abb50e857a5de48",
|
||||
"pin": {
|
||||
"bytes": 603,
|
||||
"sha256": "d27fd807235a480aa0fe76f3ceefddbdc1756cc1782727829be99f86b00d7550"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
},
|
||||
"process-removal-build-1": {
|
||||
"command": [
|
||||
"cargo",
|
||||
"build",
|
||||
"-p",
|
||||
"oa-desktop",
|
||||
"-p",
|
||||
"oa-cli",
|
||||
"--message-format=json"
|
||||
],
|
||||
"head": "572e96ba03522cfb822b13fe4abb50e857a5de48",
|
||||
"exitCode": 0,
|
||||
"inputCount": 832,
|
||||
"helper": "helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py",
|
||||
"sourceProof": {
|
||||
"commit": "572e96ba03522cfb822b13fe4abb50e857a5de48",
|
||||
"pin": {
|
||||
"bytes": 602,
|
||||
"sha256": "3c40d37ad31dc3f23e2c3f57fa0ab780f8b7891f491f9f5382948a625e8ecf84"
|
||||
},
|
||||
"comparator": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py"
|
||||
}
|
||||
}
|
||||
},
|
||||
"captureHelpers": {
|
||||
"gate.py": "helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py",
|
||||
"source-proof.py": "helpers/c86f51d9b8465341dab73d045923ec306b15ebabf7c97b81beac7afe73bd72a1.py"
|
||||
},
|
||||
"logicalFiles": {
|
||||
"cargo/process-removal-build-1/inputs.json": "capsules/df764fd132235169050a761757a2761dcc36cdf08fb812edbfd3e18af50a5dfb.json",
|
||||
"cargo/process-removal-build-1/inputs.zip": "capsules/dec4a591276d0920e0b7940c9785a2fb9bf92af71a4c206ef3d692db7798f45b.zip",
|
||||
"cargo/process-removal-build-1/process.json": "cargo/process-removal-build-1/process.json",
|
||||
"cargo/process-removal-build-1/result.json": "cargo/process-removal-build-1/result.json",
|
||||
"cargo/process-removal-build-1/source-proof.json": "cargo/process-removal-build-1/source-proof.json",
|
||||
"cargo/process-removal-build-1/started.json": "cargo/process-removal-build-1/started.json",
|
||||
"cargo/process-removal-build-1/stderr.log": "cargo/process-removal-build-1/stderr.log",
|
||||
"cargo/process-removal-build-1/stdout.log": "cargo/process-removal-build-1/stdout.log",
|
||||
"cargo/process-removal-clippy-1/inputs.json": "capsules/f199e1a7a58f7d9093a2cb9da288120c35bd87c650bb971ecad3c9d964d1c76a.json",
|
||||
"cargo/process-removal-clippy-1/inputs.zip": "capsules/b2504689cfe1a461949673ba5ed67323571aa70ee7965230f980c20cafd317ba.zip",
|
||||
"cargo/process-removal-clippy-1/process.json": "cargo/process-removal-clippy-1/process.json",
|
||||
"cargo/process-removal-clippy-1/result.json": "cargo/process-removal-clippy-1/result.json",
|
||||
"cargo/process-removal-clippy-1/source-proof.json": "cargo/process-removal-clippy-1/source-proof.json",
|
||||
"cargo/process-removal-clippy-1/started.json": "cargo/process-removal-clippy-1/started.json",
|
||||
"cargo/process-removal-clippy-1/stderr.log": "cargo/process-removal-clippy-1/stderr.log",
|
||||
"cargo/process-removal-clippy-1/stdout.log": "cargo/process-removal-clippy-1/stdout.log",
|
||||
"cargo/process-removal-clippy-2/inputs.json": "capsules/df764fd132235169050a761757a2761dcc36cdf08fb812edbfd3e18af50a5dfb.json",
|
||||
"cargo/process-removal-clippy-2/inputs.zip": "capsules/dec4a591276d0920e0b7940c9785a2fb9bf92af71a4c206ef3d692db7798f45b.zip",
|
||||
"cargo/process-removal-clippy-2/process.json": "cargo/process-removal-clippy-2/process.json",
|
||||
"cargo/process-removal-clippy-2/result.json": "cargo/process-removal-clippy-2/result.json",
|
||||
"cargo/process-removal-clippy-2/source-proof.json": "cargo/process-removal-clippy-2/source-proof.json",
|
||||
"cargo/process-removal-clippy-2/started.json": "cargo/process-removal-clippy-2/started.json",
|
||||
"cargo/process-removal-clippy-2/stderr.log": "cargo/process-removal-clippy-2/stderr.log",
|
||||
"cargo/process-removal-clippy-2/stdout.log": "cargo/process-removal-clippy-2/stdout.log",
|
||||
"cargo/process-removal-format-1/inputs.json": "capsules/b09d4d557af5882c4d23c546394da9f1ff7aa0d6ac3de6f509e923d96c48f929.json",
|
||||
"cargo/process-removal-format-1/inputs.zip": "capsules/6e49c576b61f844341d6e84e4da44eea24045f6064467a9cf060646289a706ea.zip",
|
||||
"cargo/process-removal-format-1/process.json": "cargo/process-removal-format-1/process.json",
|
||||
"cargo/process-removal-format-1/result.json": "cargo/process-removal-format-1/result.json",
|
||||
"cargo/process-removal-format-1/source-proof.json": "cargo/process-removal-format-1/source-proof.json",
|
||||
"cargo/process-removal-format-1/started.json": "cargo/process-removal-format-1/started.json",
|
||||
"cargo/process-removal-format-1/stderr.log": "cargo/process-removal-format-1/stderr.log",
|
||||
"cargo/process-removal-format-1/stdout.log": "cargo/process-removal-format-1/stdout.log",
|
||||
"cargo/process-removal-format-2/inputs.json": "capsules/46a4532cb0bccafe9260df88d02781b29bf979c3277a45cad261852a2cfaf998.json",
|
||||
"cargo/process-removal-format-2/inputs.zip": "capsules/34d335f010637739cbb763f1436f4c640a2c472051c30e2a5a6beb39a2ed7e78.zip",
|
||||
"cargo/process-removal-format-2/process.json": "cargo/process-removal-format-2/process.json",
|
||||
"cargo/process-removal-format-2/result.json": "cargo/process-removal-format-2/result.json",
|
||||
"cargo/process-removal-format-2/source-proof.json": "cargo/process-removal-format-2/source-proof.json",
|
||||
"cargo/process-removal-format-2/started.json": "cargo/process-removal-format-2/started.json",
|
||||
"cargo/process-removal-format-2/stderr.log": "cargo/process-removal-format-2/stderr.log",
|
||||
"cargo/process-removal-format-2/stdout.log": "cargo/process-removal-format-2/stdout.log",
|
||||
"cargo/process-removal-format-3/inputs.json": "capsules/df764fd132235169050a761757a2761dcc36cdf08fb812edbfd3e18af50a5dfb.json",
|
||||
"cargo/process-removal-format-3/inputs.zip": "capsules/dec4a591276d0920e0b7940c9785a2fb9bf92af71a4c206ef3d692db7798f45b.zip",
|
||||
"cargo/process-removal-format-3/process.json": "cargo/process-removal-format-3/process.json",
|
||||
"cargo/process-removal-format-3/result.json": "cargo/process-removal-format-3/result.json",
|
||||
"cargo/process-removal-format-3/source-proof.json": "cargo/process-removal-format-3/source-proof.json",
|
||||
"cargo/process-removal-format-3/started.json": "cargo/process-removal-format-3/started.json",
|
||||
"cargo/process-removal-format-3/stderr.log": "cargo/process-removal-format-3/stderr.log",
|
||||
"cargo/process-removal-format-3/stdout.log": "cargo/process-removal-format-3/stdout.log",
|
||||
"cargo/process-removal-tests-1/inputs.json": "capsules/b09d4d557af5882c4d23c546394da9f1ff7aa0d6ac3de6f509e923d96c48f929.json",
|
||||
"cargo/process-removal-tests-1/inputs.zip": "capsules/6e49c576b61f844341d6e84e4da44eea24045f6064467a9cf060646289a706ea.zip",
|
||||
"cargo/process-removal-tests-1/process.json": "cargo/process-removal-tests-1/process.json",
|
||||
"cargo/process-removal-tests-1/result.json": "cargo/process-removal-tests-1/result.json",
|
||||
"cargo/process-removal-tests-1/source-proof.json": "cargo/process-removal-tests-1/source-proof.json",
|
||||
"cargo/process-removal-tests-1/started.json": "cargo/process-removal-tests-1/started.json",
|
||||
"cargo/process-removal-tests-1/stderr.log": "cargo/process-removal-tests-1/stderr.log",
|
||||
"cargo/process-removal-tests-1/stdout.log": "cargo/process-removal-tests-1/stdout.log",
|
||||
"cargo/process-removal-tests-2/inputs.json": "capsules/46a4532cb0bccafe9260df88d02781b29bf979c3277a45cad261852a2cfaf998.json",
|
||||
"cargo/process-removal-tests-2/inputs.zip": "capsules/34d335f010637739cbb763f1436f4c640a2c472051c30e2a5a6beb39a2ed7e78.zip",
|
||||
"cargo/process-removal-tests-2/process.json": "cargo/process-removal-tests-2/process.json",
|
||||
"cargo/process-removal-tests-2/result.json": "cargo/process-removal-tests-2/result.json",
|
||||
"cargo/process-removal-tests-2/source-proof.json": "cargo/process-removal-tests-2/source-proof.json",
|
||||
"cargo/process-removal-tests-2/started.json": "cargo/process-removal-tests-2/started.json",
|
||||
"cargo/process-removal-tests-2/stderr.log": "cargo/process-removal-tests-2/stderr.log",
|
||||
"cargo/process-removal-tests-2/stdout.log": "cargo/process-removal-tests-2/stdout.log",
|
||||
"cargo/process-removal-tests-3/inputs.json": "capsules/f199e1a7a58f7d9093a2cb9da288120c35bd87c650bb971ecad3c9d964d1c76a.json",
|
||||
"cargo/process-removal-tests-3/inputs.zip": "capsules/b2504689cfe1a461949673ba5ed67323571aa70ee7965230f980c20cafd317ba.zip",
|
||||
"cargo/process-removal-tests-3/process.json": "cargo/process-removal-tests-3/process.json",
|
||||
"cargo/process-removal-tests-3/result.json": "cargo/process-removal-tests-3/result.json",
|
||||
"cargo/process-removal-tests-3/source-proof.json": "cargo/process-removal-tests-3/source-proof.json",
|
||||
"cargo/process-removal-tests-3/started.json": "cargo/process-removal-tests-3/started.json",
|
||||
"cargo/process-removal-tests-3/stderr.log": "cargo/process-removal-tests-3/stderr.log",
|
||||
"cargo/process-removal-tests-3/stdout.log": "cargo/process-removal-tests-3/stdout.log",
|
||||
"cargo/process-removal-tests-4/inputs.json": "capsules/df764fd132235169050a761757a2761dcc36cdf08fb812edbfd3e18af50a5dfb.json",
|
||||
"cargo/process-removal-tests-4/inputs.zip": "capsules/dec4a591276d0920e0b7940c9785a2fb9bf92af71a4c206ef3d692db7798f45b.zip",
|
||||
"cargo/process-removal-tests-4/process.json": "cargo/process-removal-tests-4/process.json",
|
||||
"cargo/process-removal-tests-4/result.json": "cargo/process-removal-tests-4/result.json",
|
||||
"cargo/process-removal-tests-4/source-proof.json": "cargo/process-removal-tests-4/source-proof.json",
|
||||
"cargo/process-removal-tests-4/started.json": "cargo/process-removal-tests-4/started.json",
|
||||
"cargo/process-removal-tests-4/stderr.log": "cargo/process-removal-tests-4/stderr.log",
|
||||
"cargo/process-removal-tests-4/stdout.log": "cargo/process-removal-tests-4/stdout.log",
|
||||
"comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py": "comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py",
|
||||
"helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py": "helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py",
|
||||
"helpers/c86f51d9b8465341dab73d045923ec306b15ebabf7c97b81beac7afe73bd72a1.py": "helpers/c86f51d9b8465341dab73d045923ec306b15ebabf7c97b81beac7afe73bd72a1.py"
|
||||
},
|
||||
"members": {
|
||||
"capsules/34d335f010637739cbb763f1436f4c640a2c472051c30e2a5a6beb39a2ed7e78.zip": {
|
||||
"bytes": 3317469,
|
||||
"sha256": "34d335f010637739cbb763f1436f4c640a2c472051c30e2a5a6beb39a2ed7e78"
|
||||
},
|
||||
"capsules/46a4532cb0bccafe9260df88d02781b29bf979c3277a45cad261852a2cfaf998.json": {
|
||||
"bytes": 139818,
|
||||
"sha256": "46a4532cb0bccafe9260df88d02781b29bf979c3277a45cad261852a2cfaf998"
|
||||
},
|
||||
"capsules/6e49c576b61f844341d6e84e4da44eea24045f6064467a9cf060646289a706ea.zip": {
|
||||
"bytes": 3316503,
|
||||
"sha256": "6e49c576b61f844341d6e84e4da44eea24045f6064467a9cf060646289a706ea"
|
||||
},
|
||||
"capsules/b09d4d557af5882c4d23c546394da9f1ff7aa0d6ac3de6f509e923d96c48f929.json": {
|
||||
"bytes": 139641,
|
||||
"sha256": "b09d4d557af5882c4d23c546394da9f1ff7aa0d6ac3de6f509e923d96c48f929"
|
||||
},
|
||||
"capsules/b2504689cfe1a461949673ba5ed67323571aa70ee7965230f980c20cafd317ba.zip": {
|
||||
"bytes": 3317568,
|
||||
"sha256": "b2504689cfe1a461949673ba5ed67323571aa70ee7965230f980c20cafd317ba"
|
||||
},
|
||||
"capsules/dec4a591276d0920e0b7940c9785a2fb9bf92af71a4c206ef3d692db7798f45b.zip": {
|
||||
"bytes": 3317564,
|
||||
"sha256": "dec4a591276d0920e0b7940c9785a2fb9bf92af71a4c206ef3d692db7798f45b"
|
||||
},
|
||||
"capsules/df764fd132235169050a761757a2761dcc36cdf08fb812edbfd3e18af50a5dfb.json": {
|
||||
"bytes": 139818,
|
||||
"sha256": "df764fd132235169050a761757a2761dcc36cdf08fb812edbfd3e18af50a5dfb"
|
||||
},
|
||||
"capsules/f199e1a7a58f7d9093a2cb9da288120c35bd87c650bb971ecad3c9d964d1c76a.json": {
|
||||
"bytes": 139818,
|
||||
"sha256": "f199e1a7a58f7d9093a2cb9da288120c35bd87c650bb971ecad3c9d964d1c76a"
|
||||
},
|
||||
"cargo/process-removal-build-1/process.json": {
|
||||
"bytes": 153,
|
||||
"sha256": "dc004e0235427ba30d729f43829567c953fc8813805493d88aa8026735f38855"
|
||||
},
|
||||
"cargo/process-removal-build-1/result.json": {
|
||||
"bytes": 4454,
|
||||
"sha256": "5699e510ec2541de2b2f484da17fd99685182baf80a0046e5ad3f651d54749db"
|
||||
},
|
||||
"cargo/process-removal-build-1/source-proof.json": {
|
||||
"bytes": 602,
|
||||
"sha256": "3c40d37ad31dc3f23e2c3f57fa0ab780f8b7891f491f9f5382948a625e8ecf84"
|
||||
},
|
||||
"cargo/process-removal-build-1/started.json": {
|
||||
"bytes": 1527,
|
||||
"sha256": "4db0bbcf6a8bc0123b383f2652490b32398c8aaa67c01040fa8d0ac04db2b531"
|
||||
},
|
||||
"cargo/process-removal-build-1/stderr.log": {
|
||||
"bytes": 134,
|
||||
"sha256": "653b17b1fe092ae2a63bd8de1567a002926ba1e5490fc7cc6e2def5bc194f8a5"
|
||||
},
|
||||
"cargo/process-removal-build-1/stdout.log": {
|
||||
"bytes": 285562,
|
||||
"sha256": "02fd17e99b96025280cab7ce7cfe19bfcdc406530bbaa31d4277744b7f8ee219"
|
||||
},
|
||||
"cargo/process-removal-clippy-1/process.json": {
|
||||
"bytes": 154,
|
||||
"sha256": "e41df8b0608174388c261d28f7c3ee3cb20137ec33f5f2caa1ce6df9917a24ba"
|
||||
},
|
||||
"cargo/process-removal-clippy-1/result.json": {
|
||||
"bytes": 1927,
|
||||
"sha256": "35e1afdd586853dbd992b3b944045e479297bf6dc2bf33db5186be0a51c3e41f"
|
||||
},
|
||||
"cargo/process-removal-clippy-1/source-proof.json": {
|
||||
"bytes": 603,
|
||||
"sha256": "a758a8df8dbc2aa86b907856b69ca74f8219a9b462a83d690f06929ba3cc1797"
|
||||
},
|
||||
"cargo/process-removal-clippy-1/started.json": {
|
||||
"bytes": 1533,
|
||||
"sha256": "af25bb05f73bb02e64ab8f367aa33bcfefce11d23cafa4f2a0f0f82181a60c2b"
|
||||
},
|
||||
"cargo/process-removal-clippy-1/stderr.log": {
|
||||
"bytes": 1354,
|
||||
"sha256": "ab0b2ce019708e42eb13591a678c0c53a03805326568f07bf7a31849993031b7"
|
||||
},
|
||||
"cargo/process-removal-clippy-1/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/process-removal-clippy-2/process.json": {
|
||||
"bytes": 154,
|
||||
"sha256": "012134abc527a95c97027e1b969d50bff5e5b2fc1017521ec9999e8aea772543"
|
||||
},
|
||||
"cargo/process-removal-clippy-2/result.json": {
|
||||
"bytes": 1923,
|
||||
"sha256": "12f3352607a1608fcd1242b48336ae877b81677df38d96d17bbe9dc6ed3ff49b"
|
||||
},
|
||||
"cargo/process-removal-clippy-2/source-proof.json": {
|
||||
"bytes": 603,
|
||||
"sha256": "d27fd807235a480aa0fe76f3ceefddbdc1756cc1782727829be99f86b00d7550"
|
||||
},
|
||||
"cargo/process-removal-clippy-2/started.json": {
|
||||
"bytes": 1533,
|
||||
"sha256": "2e54d3d7bb6f1dca1ba771644dfd52d7c2557da4058fd9ce46f5758747e0ca20"
|
||||
},
|
||||
"cargo/process-removal-clippy-2/stderr.log": {
|
||||
"bytes": 134,
|
||||
"sha256": "fe9cc79b9f5e01c55fac8b73f57930aeb698f3a311a8e8eaab9dd9e5f45904ac"
|
||||
},
|
||||
"cargo/process-removal-clippy-2/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/process-removal-format-1/process.json": {
|
||||
"bytes": 116,
|
||||
"sha256": "6c78f04e1dacf3c96dbc71e106c9fa634a1f5f7d74d63659a52c71a51ef92956"
|
||||
},
|
||||
"cargo/process-removal-format-1/result.json": {
|
||||
"bytes": 1868,
|
||||
"sha256": "27181d72da07441a265453b2a76228ee92b77dfdd81995affbc874b61f10e26b"
|
||||
},
|
||||
"cargo/process-removal-format-1/source-proof.json": {
|
||||
"bytes": 603,
|
||||
"sha256": "d36d50d20b92c49c0867d1468ed9d8062e23aa8cda9a995ad8bd91938e337335"
|
||||
},
|
||||
"cargo/process-removal-format-1/started.json": {
|
||||
"bytes": 1480,
|
||||
"sha256": "30398f79fb193f3348222f7561c6b39a873ba4f832a71e82f3494ea8a5b357e0"
|
||||
},
|
||||
"cargo/process-removal-format-1/stderr.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/process-removal-format-1/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/process-removal-format-2/process.json": {
|
||||
"bytes": 116,
|
||||
"sha256": "7f289173389898a25c8313c5a91e1f66ce6249688aa7241dac0b171a78b85eaf"
|
||||
},
|
||||
"cargo/process-removal-format-2/result.json": {
|
||||
"bytes": 1868,
|
||||
"sha256": "dce00e380220b98c5ff51eb63a4a8ef71b4b3f936db08160ecef40f26169acdc"
|
||||
},
|
||||
"cargo/process-removal-format-2/source-proof.json": {
|
||||
"bytes": 603,
|
||||
"sha256": "6f6a756569f3877223932253db0cea5380d646dd221f467c69b3572289d9a2fc"
|
||||
},
|
||||
"cargo/process-removal-format-2/started.json": {
|
||||
"bytes": 1480,
|
||||
"sha256": "2892f3c304419b97ff95c9a554e6cee623751eda9764b98466e474e1fb80c034"
|
||||
},
|
||||
"cargo/process-removal-format-2/stderr.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/process-removal-format-2/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/process-removal-format-3/process.json": {
|
||||
"bytes": 110,
|
||||
"sha256": "17035416a3896914c8b79e0371362503ffa0ab21e8f4bc4e922cc21b32e15a79"
|
||||
},
|
||||
"cargo/process-removal-format-3/result.json": {
|
||||
"bytes": 1858,
|
||||
"sha256": "7ec891fa7a881b4f04fc3f58047a15f3972b397b7d2595e4a0bb04a9f658d9a3"
|
||||
},
|
||||
"cargo/process-removal-format-3/source-proof.json": {
|
||||
"bytes": 603,
|
||||
"sha256": "05d86dd797bf3c1a0d9c8b0c00a49294009ead98cb9e9c3e258d0cb59e9331b1"
|
||||
},
|
||||
"cargo/process-removal-format-3/started.json": {
|
||||
"bytes": 1470,
|
||||
"sha256": "6dae3900f3e53d89878ee0a9b89552bec60f351f56aa88505bbdba0a33348af8"
|
||||
},
|
||||
"cargo/process-removal-format-3/stderr.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/process-removal-format-3/stdout.log": {
|
||||
"bytes": 0,
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
},
|
||||
"cargo/process-removal-tests-1/process.json": {
|
||||
"bytes": 217,
|
||||
"sha256": "007c489991c9d8ab793dbaa530aa96020e991b2428188e06a6e3ff4b7c369bc9"
|
||||
},
|
||||
"cargo/process-removal-tests-1/result.json": {
|
||||
"bytes": 4695,
|
||||
"sha256": "f95efe6a49ecd21625cb93fc13a3c759fc5703ed41d16689a075964464b443b9"
|
||||
},
|
||||
"cargo/process-removal-tests-1/source-proof.json": {
|
||||
"bytes": 602,
|
||||
"sha256": "4074db859ff385c14941ba8e45530a7e748e0db45101339d881937663c0ef512"
|
||||
},
|
||||
"cargo/process-removal-tests-1/started.json": {
|
||||
"bytes": 1611,
|
||||
"sha256": "ab8ca8306f1ea1a909cb7c049d0503646b738570840dd800865c89d2a0b4d434"
|
||||
},
|
||||
"cargo/process-removal-tests-1/stderr.log": {
|
||||
"bytes": 355,
|
||||
"sha256": "8106f2b580d08ae4991b1bae18a158f7cc7cf0b6d27e62114492553f69fd6f83"
|
||||
},
|
||||
"cargo/process-removal-tests-1/stdout.log": {
|
||||
"bytes": 322947,
|
||||
"sha256": "aeb571241a21c246ac94ae64f698b478ded69988b9f811c806bb689bb8af6dc9"
|
||||
},
|
||||
"cargo/process-removal-tests-2/process.json": {
|
||||
"bytes": 217,
|
||||
"sha256": "2884ec9947c403f3185f7963b2313500f79409cde575f5279827b8cc4227a868"
|
||||
},
|
||||
"cargo/process-removal-tests-2/result.json": {
|
||||
"bytes": 4693,
|
||||
"sha256": "ebf26a86bf954f0e0f6819ff1f6dc8cb261b02d0c73cde548827ce5bbcc0812a"
|
||||
},
|
||||
"cargo/process-removal-tests-2/source-proof.json": {
|
||||
"bytes": 602,
|
||||
"sha256": "4ab508f91efc34fde8cc1fc99fcc174d22f9eaf141730f608582b0067007eb56"
|
||||
},
|
||||
"cargo/process-removal-tests-2/started.json": {
|
||||
"bytes": 1611,
|
||||
"sha256": "6e5e873ac87130f4e352fda135d31ade35d248eb7e9c0d826a92346a57264e1c"
|
||||
},
|
||||
"cargo/process-removal-tests-2/stderr.log": {
|
||||
"bytes": 355,
|
||||
"sha256": "fa12c89f816b914e7b32627e498d2913f175cec41e5c3b100f815e32f471e9a4"
|
||||
},
|
||||
"cargo/process-removal-tests-2/stdout.log": {
|
||||
"bytes": 325669,
|
||||
"sha256": "c557894a0c8dfeae7ca91191a97df758638f0cdb32b0bb8e871fa8d06c48177f"
|
||||
},
|
||||
"cargo/process-removal-tests-3/process.json": {
|
||||
"bytes": 217,
|
||||
"sha256": "cb98374a36dc5591268b0420213399e5bc4607b9877a4707ad265daa08ad2025"
|
||||
},
|
||||
"cargo/process-removal-tests-3/result.json": {
|
||||
"bytes": 4692,
|
||||
"sha256": "82709fef9b1aabdf2fcc07a7cb9300d16474bc62370d7157e6bb6270cd8264f8"
|
||||
},
|
||||
"cargo/process-removal-tests-3/source-proof.json": {
|
||||
"bytes": 602,
|
||||
"sha256": "0407b22338c2d7bf725c8fe7098515a484cf67067578b4bf4992fa0a49bd3f93"
|
||||
},
|
||||
"cargo/process-removal-tests-3/started.json": {
|
||||
"bytes": 1611,
|
||||
"sha256": "bf71f073afc1fcc56df6c6f51841d75cd189c8576602b8e43ecb4e7470593c86"
|
||||
},
|
||||
"cargo/process-removal-tests-3/stderr.log": {
|
||||
"bytes": 284,
|
||||
"sha256": "ae9e8161a2438edc48c8667594310c21c3103583ce9c289efabb6f2e031574af"
|
||||
},
|
||||
"cargo/process-removal-tests-3/stdout.log": {
|
||||
"bytes": 317009,
|
||||
"sha256": "ace568a568723a784e0736f0b2d9287401f7fbe6a9b5fc025dc047205406f22a"
|
||||
},
|
||||
"cargo/process-removal-tests-4/process.json": {
|
||||
"bytes": 215,
|
||||
"sha256": "07992dcb5311d345837f37093dc9eb1d699d1ede9f812496a7f964d2c0dc363d"
|
||||
},
|
||||
"cargo/process-removal-tests-4/result.json": {
|
||||
"bytes": 4685,
|
||||
"sha256": "8513d24b9f05645908f4a475fcc90b5887362473f8046282bfd8af6a24c61dd5"
|
||||
},
|
||||
"cargo/process-removal-tests-4/source-proof.json": {
|
||||
"bytes": 602,
|
||||
"sha256": "ff045bf753ec4e09abc980018dd90f38338889dcd0877200364f5460418df5c6"
|
||||
},
|
||||
"cargo/process-removal-tests-4/started.json": {
|
||||
"bytes": 1604,
|
||||
"sha256": "1c408cdce0995388fcc2ba6d17ab2786daef461a656384684b02777e3b5d887d"
|
||||
},
|
||||
"cargo/process-removal-tests-4/stderr.log": {
|
||||
"bytes": 284,
|
||||
"sha256": "ed791ebad3050c571f427686faacb85afa112e958c6a190b272881f0fa661fc9"
|
||||
},
|
||||
"cargo/process-removal-tests-4/stdout.log": {
|
||||
"bytes": 297004,
|
||||
"sha256": "39100d92c647f02ca6c172b0a859e9ee39caaafca9fa60426fd628bceeea633b"
|
||||
},
|
||||
"comparators/7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a.py": {
|
||||
"bytes": 10094,
|
||||
"sha256": "7805832d5f563ab2d7a50dd3de700792b5d6f459c68f7b1d8bcfcc9800fa0c3a"
|
||||
},
|
||||
"helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py": {
|
||||
"bytes": 3778,
|
||||
"sha256": "3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2"
|
||||
},
|
||||
"helpers/c86f51d9b8465341dab73d045923ec306b15ebabf7c97b81beac7afe73bd72a1.py": {
|
||||
"bytes": 1396,
|
||||
"sha256": "c86f51d9b8465341dab73d045923ec306b15ebabf7c97b81beac7afe73bd72a1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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/scenario-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 == RAW_FILES | {"source-proof.json"}, "exact closed raw files and source proof 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": "process-aggregate-removal-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/scenario-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,195 @@
|
||||
"""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"process-removal-[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"] == "process-aggregate-removal-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():
|
||||
need("sourceProof" in spec, run + ": source proof required")
|
||||
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,122 @@
|
||||
# Final bounded Process removal source review
|
||||
|
||||
Reviewed local commit `fe637dcd277b17653139ffa234e601b29775c565` on
|
||||
2026-09-25 UTC. `git status --porcelain` was empty before this ignored local
|
||||
review note. No production edits, Cargo, UI or Gitea operations were performed;
|
||||
the parent's frozen-input verification gate was running independently.
|
||||
|
||||
**Result:** no new actionable production finding in the requested final scope.
|
||||
The previous P1, P2 wording and same-batch gesture findings are addressed in
|
||||
source; the two requested planner coverage gaps now have independent literal
|
||||
test cases. Passing runtime/native gates remain the parent's separate evidence.
|
||||
|
||||
## Prior finding disposition
|
||||
|
||||
| Prior item | Final source assessment |
|
||||
| --- | --- |
|
||||
| P1 interpretation-only caller closure omitted explicit-to-explicit effects | Addressed. `Plan.affected_uses` remains independent of interpretation deltas, seeded from actual removed/changed definition topology. The OA/SA repeated/direct/transitive caller test is at `behavior/topology/group_removal/tests.rs:680`. |
|
||||
| P2 “No remaining contributions” denied surviving unlisted contributions | Addressed. `app/process_removal/view.rs:89–93` now says “Empty order” / “One item in this order,” with no false global contribution count. Empty order explicitly permits incomplete contextual flow. |
|
||||
| P2 candidate queued Delete admitted after a later private group press | Addressed in source with synchronous shared input generation and an active gesture lease; production-tree discriminator now exists at `app/process_removal/tests.rs:536`. Runtime result not independently observed by this reviewer. |
|
||||
| Coverage: selected occurrence + covered selected link + uncovered selected link | Added at `behavior/topology/group_removal/tests.rs:707`, both layers. Literal removed IDs, changed IDs, exact two Delete commands, reverse selection order and independent final Project/source history oracle. |
|
||||
| Coverage: global attachment/trace/placement/diagram impact | Added at `behavior/topology/group_removal/tests.rs:738`, both layers. Literal removed and changed sets include two placements, cascade-owned evidence, trace and surviving constraint/diagrams; counterpart, unrelated view, retained trace/artifact/placement remain exact. Full expected Project/source history oracle is independently constructed. |
|
||||
|
||||
## Input lifetime correction
|
||||
|
||||
`behavior/topology/removal_input.rs` supplies a shared `Arc<AtomicU64>` lifetime:
|
||||
even generations admit idle capture; an acquired group gesture owns an odd
|
||||
generation. A lease advances the generation on Drop, including ordinary
|
||||
release, cancellation and widget-state destruction. Checked arithmetic leaves
|
||||
overflow terminal/unavailable rather than revalidating old packets. Compare-
|
||||
exchange prevents a stale lease from resetting an unrelated generation.
|
||||
|
||||
The production topology view supplies the State's lifetime to the Graph.
|
||||
`direct_selection.rs` revokes idle captures synchronously on canvas presses and
|
||||
Unfocused/Resized boundaries. A selected-card GroupPress holds the lease. The
|
||||
shared viewport forwards synthetic Unfocused when camera ownership begins, so
|
||||
the same native batch can revoke an earlier Delete even though App has not yet
|
||||
consumed its queued Begin message.
|
||||
|
||||
`app/process_removal.rs:43–58` captures/requires an idle generation;
|
||||
`:90` compares it before any source/canvas boundary; `:185` compares it again at
|
||||
confirmation. This closes the specific prior race without substituting an App
|
||||
message-order check for synchronous widget state. Full typed selection/context
|
||||
admission remains present alongside the generation check.
|
||||
|
||||
The new mounted test at `app/process_removal/tests.rs:536` uses a real queued
|
||||
Delete, cursor move and selected-card press in one production input batch. Its
|
||||
assertions require no modal, unchanged canvas epoch, exact selection and shared
|
||||
Document snapshot, disabled fresh capture during the live gesture, and a fresh
|
||||
review after cancellation. The test at `:606` exercises Delete followed by
|
||||
middle/background-left camera pan start. Direct lifecycle tests at
|
||||
`behavior/topology/direct_selection_tests.rs:458` cover release, Escape,
|
||||
unfocus and Input destruction, requiring idle recovery with a different
|
||||
generation. The primitive lease test also checks concurrent acquisition refusal
|
||||
and explicit idle revocation.
|
||||
|
||||
These are meaningful discriminators for the reported paths. They are not a
|
||||
claim that the generation tracks every internal viewport gesture: existing
|
||||
viewport keyboard/capture rules still own camera input. No additional concrete
|
||||
production bypass was found in that composition.
|
||||
|
||||
## Review presentation correction
|
||||
|
||||
Identical local/expanded order dimensions are coalesced only when BOTH before
|
||||
and after vectors match (`app/process_removal/view.rs:62–80`). A divergence in
|
||||
either snapshot still produces separately labeled dimensions, preserving the
|
||||
owned-unlisted discriminator. Contextual-analysis changes remain independent.
|
||||
Affected caller definitions are deduplicated for the header count; rows retain
|
||||
definition-to-caller relationships, without claiming reference-instance counts.
|
||||
The text continues to disclose possible reused entry/exit changes and the lack
|
||||
of complete expanded-graph analysis.
|
||||
|
||||
## Precise verification boundary
|
||||
|
||||
This review establishes source consistency, test-oracle suitability and old
|
||||
finding disposition for the identified commit only. I did not execute any new
|
||||
or existing test, inspect the parent's gate output, run the native UI, verify
|
||||
compact layout/focus with real input, test packaged launch/save/reopen, or
|
||||
confirm remote publication/integration. In particular, the mounted race tests'
|
||||
presence and correct assertions do not by themselves establish their passing
|
||||
result. Parent gate/native evidence must remain attached to the tested commit;
|
||||
later changes invalidate only the affected portion of this source review.
|
||||
|
||||
## Addendum: qualified-definition menu restoration after runtime gate
|
||||
|
||||
The parent subsequently reported 185 passing and two failing tests for
|
||||
`fe637dcd277b17653139ffa234e601b29775c565`: an existing qualified-definition menu
|
||||
regression and a literal source-oracle whitespace mismatch. Those are parent-
|
||||
reported runtime results; I did not run or independently inspect their logs.
|
||||
|
||||
I reviewed the uncommitted `crates/oa-desktop/src/model_menu.rs` correction
|
||||
relative to that commit. Inspected file SHA256:
|
||||
`8BC2C74EA83EAEC8BD342AF5600FBF8E9963BED7290DC094E8B4FC7ABFC0B70D`.
|
||||
At inspection this was the only tracked modification. This addendum binds to
|
||||
that file content, not a claim that all current files equal the prior HEAD.
|
||||
|
||||
**No actionable finding in the correction.** The qualified navigation entry is
|
||||
now constructed before the aggregate-selection early return, so it remains
|
||||
available for a clicked selected or unselected preview while preserving group
|
||||
removal. Its message uses the captured request's Process context and exact
|
||||
qualified endpoint; it does not read the primary selection or strip reference
|
||||
paths. Preview-link navigation retains the prior source-endpoint convention.
|
||||
|
||||
The group branch still returns before singleton mutation entries are built.
|
||||
Outside the group branch, a qualified target still returns before those entries.
|
||||
The group Remove message continues to capture the entire current selection;
|
||||
adding navigation does not bypass the planner's qualified-member refusal or
|
||||
turn deletion into a clicked-object action. Selection-changing menu entries
|
||||
remain explicit.
|
||||
|
||||
Existing menu token/context/exact-selection validity checks apply unchanged.
|
||||
App menu invocation routes TopologyCanvas navigation before ordinary clicked-
|
||||
object selection. `app/process_canvas.rs:125` resolves the complete endpoint,
|
||||
remembers that exact invocation and opens its defining sequence; it retains
|
||||
pending-edit admission. No singleton destructive bypass was introduced by the
|
||||
entry relocation.
|
||||
|
||||
The previously passing source-only review did not catch the menu regression;
|
||||
the runtime gate supplied necessary additional evidence. The correction still
|
||||
requires its relevant regression rerun. The independent source-oracle whitespace
|
||||
repair is outside this addendum's inspected scope and is not treated as a
|
||||
production defect or as verified here. No Cargo/UI/Gitea or production edits
|
||||
were performed for this addendum.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Parent native observations, 2026-09-25 UTC
|
||||
|
||||
Source `572e96ba03522cfb822b13fe4abb50e857a5de48`, Windows gnullvm. These
|
||||
observations describe Computer Use actions; capture JSON is window/image state,
|
||||
not an instrumented input log. Both runs use independently derived oracle-v2.
|
||||
|
||||
## Run 1
|
||||
|
||||
PID 6524. Prepared immutable executable/DLL copies, normal launch and Alt+F4
|
||||
close; final receipt exit 0, empty stdout/stderr, all immutable pins unchanged.
|
||||
Opened only this run's working.arcadia through the native file picker.
|
||||
|
||||
- Captures 01–11: launch/open/navigation. Attempts 07/08 did not select the
|
||||
Process; after maximizing, 10 selected it and 11 opened Behavior. Use the
|
||||
largest returned screenshot for canvas coordinates; captures may also contain
|
||||
a tiny window-icon region. Native accessibility exposes the top-level window,
|
||||
not the Iced widget tree, so content/focus judgments use visible screenshots.
|
||||
- 12–16: selected local Action @a; context Add selected Control @c, then authored
|
||||
link @approved. Count 3, both same-name cards outlined, link primary with alias
|
||||
approved in the inspector. Context Add is demonstrated, not native Shift-click.
|
||||
- 17–19: header removal review shows three selected removals, one preserved
|
||||
updated Process, ten effects across two pages. Scrolling page 1 exposes the
|
||||
explicit-to-implicit order change. Page 2 names @e1 then @e2 and both caller
|
||||
definitions @caller/@outer, separately from stored-record counts. Full names,
|
||||
aliases, explanatory scope and fixed footer are reachable at 1605x872.
|
||||
- 20–23: focus search, type @outer, see one transitive caller. Enter leaves the
|
||||
review open. Appending -no-match shows zero results and recovery guidance.
|
||||
- 24: Cancel retains count 3 and link primary. 25 F6, 26 Delete opens full
|
||||
review; 27 Escape retains group. 28 Shift+Delete immediately after Escape does
|
||||
not open review. 29 F6 followed by 30 Shift+Delete opens full review. Canvas
|
||||
focus is required; do not infer success from capture 28's filename.
|
||||
- Attempt 31: titlebar Restore action returned a minimized-window capture error.
|
||||
Fresh window listing/reactivation recovered a restored 1442x790 view in 32;
|
||||
the review visibly expired and Remove was disabled. 33 Escape cancelled it.
|
||||
Attempt 34 to reposition the window was rejected by the automation API because
|
||||
its destination was outside window bounds. No 31/34 capture exists. 35 refreshed
|
||||
unchanged state; 36 maximized again. These failures are not native crash evidence.
|
||||
A genuinely compact 1100px review was NOT established; restored view was partly
|
||||
clipped by the visible desktop. Do not claim compact-layout acceptance.
|
||||
- 37 Save all after cancellation: captured cancelled-baseline is exactly 2609
|
||||
bytes, baseline SHA256 9965f4024584d64ac81442724aeb77b018b0cfae94e50bd412c5dcbbac49f6bf.
|
||||
- 38 right-clicked unselected @e1: existing group count 3 and link primary remain.
|
||||
39 context Remove opens same complete group. 40 explicit Remove commits once:
|
||||
two exchange cards remain with an implicit arrow, owner selected, group empty.
|
||||
- 41 Save all: removed snapshot is exactly 2258 expected bytes, SHA256
|
||||
b4a2b07ad4c796f555c61945ca42b1c221b454b35488c60fefc86f96f7aa71ba.
|
||||
- 42 one Ctrl+Z restores four cards and authored link. 43 Save all plus undo
|
||||
snapshot equals all original 2609 bytes. 44 one Ctrl+Y restores removed model;
|
||||
45 Save all plus redo snapshot equals all expected 2258 bytes. Normal close.
|
||||
|
||||
## Run 2
|
||||
|
||||
PID 7248. New process and isolated working file copied from run-1/snapshots/redo.arcadia;
|
||||
prepared receipt records the origin path and exact pin. 01–07 fresh launch,
|
||||
maximize, native file picker and open run-2/working.arcadia. 08 select Assessment,
|
||||
09 Behavior displays two surviving exchanges and implicit order. 10 Save all;
|
||||
reopened snapshot equals all 2258 expected bytes. Normal Alt+F4 close; exit 0,
|
||||
empty logs and unchanged immutable pins. No history carried between processes.
|
||||
|
||||
## Scope
|
||||
|
||||
Native evidence is OA, derived layout, this bounded fixture. SA/planner variants,
|
||||
stale event races and command failure are covered separately by recorded tests.
|
||||
No native Shift-click, compact 1100px acceptance, comprehensive accessibility,
|
||||
actual Process source-budget failure, full suite, Linux, integration or release
|
||||
is claimed. Source oracle equality preserves reusable definitions, caller
|
||||
references and SA sentinels; it is distinct from screenshot/gesture evidence.
|
||||
@@ -0,0 +1,124 @@
|
||||
{
|
||||
"status": "PASS",
|
||||
"scope": "Independent byte-level archive-to-original mapping and recursive run/preflight inventory; no native execution or Git/Cargo operations",
|
||||
"archive": {
|
||||
"bytes": 5617713,
|
||||
"sha256": "f77fd3abe7ecc5838395b94a95ba935c8dc5c10a36c8e3a2c1ec4a1da1521b84"
|
||||
},
|
||||
"members": 327,
|
||||
"mapped_original_files": 326,
|
||||
"normalized_config": 1,
|
||||
"member_groups": {
|
||||
"fixtures": 3,
|
||||
"gates": 70,
|
||||
"helpers": 11,
|
||||
"oracle-revisions": 5,
|
||||
"preflight": 15,
|
||||
"preparation": 6,
|
||||
"normalized_config": 1,
|
||||
"review-notes": 8,
|
||||
"runs": 208
|
||||
},
|
||||
"attempts": {
|
||||
"run-1": {
|
||||
"archived_files": 156,
|
||||
"capture_records": 43,
|
||||
"excluded_binaries": 2
|
||||
},
|
||||
"run-2": {
|
||||
"archived_files": 52,
|
||||
"capture_records": 10,
|
||||
"excluded_binaries": 2
|
||||
},
|
||||
"fixture-preflight-1": {
|
||||
"archived_files": 15,
|
||||
"excluded_binaries": 2
|
||||
}
|
||||
},
|
||||
"captures": 53,
|
||||
"omitted_binaries": 6,
|
||||
"errors": [],
|
||||
"report_review": {
|
||||
"material_overclaims": [],
|
||||
"limits_preserved": [
|
||||
"OA bounded fixture",
|
||||
"1100px compact layout open",
|
||||
"Shift-click not exercised",
|
||||
"capture helper not input logger",
|
||||
"focused Shift+Delete required F6 after Escape",
|
||||
"no full accessibility/full suite/Linux/integration/release/publication claim"
|
||||
],
|
||||
"accepted_true_interpretation": "Bounded recorded native run/preflight acceptance, not compact-layout or complete-application acceptance",
|
||||
"observation": "Main report says resizing expires review; raw sequence demonstrates review expired following Restore/minimized capture recovery/reactivation, not an isolated controlled resize experiment."
|
||||
},
|
||||
"standalone_verifiers": [
|
||||
{
|
||||
"kind": "native",
|
||||
"exit_code": 0,
|
||||
"stderr": "",
|
||||
"status": "PASS offline archive, exact source and receipt consistency checks",
|
||||
"runs": [
|
||||
{
|
||||
"run": "run-1",
|
||||
"reviewer_accepted": true,
|
||||
"checks_pass": true,
|
||||
"problems": [],
|
||||
"capture_records": 43,
|
||||
"source_checks": [
|
||||
{
|
||||
"file": "snapshots/cancelled-baseline.arcadia",
|
||||
"phase": "baseline"
|
||||
},
|
||||
{
|
||||
"file": "snapshots/redo.arcadia",
|
||||
"phase": "removed"
|
||||
},
|
||||
{
|
||||
"file": "snapshots/removed.arcadia",
|
||||
"phase": "removed"
|
||||
},
|
||||
{
|
||||
"file": "snapshots/undo.arcadia",
|
||||
"phase": "baseline"
|
||||
},
|
||||
{
|
||||
"file": "working.arcadia",
|
||||
"phase": "removed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"run": "run-2",
|
||||
"reviewer_accepted": true,
|
||||
"checks_pass": true,
|
||||
"problems": [],
|
||||
"capture_records": 10,
|
||||
"source_checks": [
|
||||
{
|
||||
"file": "snapshots/reopened.arcadia",
|
||||
"phase": "removed"
|
||||
},
|
||||
{
|
||||
"file": "working.arcadia",
|
||||
"phase": "removed"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"preflights": [
|
||||
{
|
||||
"preflight": "fixture-preflight-1",
|
||||
"reviewer_accepted": true,
|
||||
"checks_pass": true,
|
||||
"problems": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "checks",
|
||||
"exit_code": 0,
|
||||
"stderr": "",
|
||||
"stdout": "process-removal-tests-1 recorded exit 101 inputs 831 executable records 2\nprocess-removal-tests-2 recorded exit 101 inputs 832 executable records 2\nprocess-removal-tests-3 recorded exit 0 inputs 832 executable records 2\nprocess-removal-tests-4 recorded exit 0 inputs 832 executable records 2\nprocess-removal-format-1 recorded exit 0 inputs 831 executable records 0\nprocess-removal-format-2 recorded exit 0 inputs 832 executable records 0\nprocess-removal-format-3 recorded exit 0 inputs 832 executable records 0\nprocess-removal-clippy-1 recorded exit 101 inputs 832 executable records 0\nprocess-removal-clippy-2 recorded exit 0 inputs 832 executable records 0\nprocess-removal-build-1 recorded exit 0 inputs 832 executable records 2\nPASS offline consistency: {'runs': 10, 'recordedFailures': 3, 'logicalFiles': 83, 'storedMembers': 71, 'sourceCapsulePairs': 4, 'captureHelpers': {'gate.py': 'helpers/3e4cd38fd3807a4010a5a7102354f9139cab236ca55163c96090e416161e5fd2.py', 'source-proof.py': 'helpers/c86f51d9b8465341dab73d045923ec306b15ebabf7c97b81beac7afe73bd72a1.py'}, 'sourceProofs': 10}\nHistorical receipts only; no source/binary execution or native acceptance claim.\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
# Independent bounded native evidence review: Process removal
|
||||
|
||||
Reviewed 2026-09-25 UTC. Source identified by the supplied build/native receipts: `572e96ba03522cfb822b13fe4abb50e857a5de48`. This reviewer made no application inputs, source edits, Cargo invocations, Git mutations or Gitea writes. Parent owns execution and publication. Evidence root: `.local/process-removal-native/run-1`; local-only until published by parent.
|
||||
|
||||
## Conclusion
|
||||
|
||||
No new blocking correctness or readability finding in the inspected OA three-member removal workflow. The evidence supports the complete-group review and removal, visible interpretation/caller consequences, cancellation, expired-review feedback, exact saved-source removal/Undo/Redo and fresh-process reopen. Native compact-width acceptance remains open: the 1605x872 maximized images and restored 1442x790 image do not establish a 1100px window. Accessibility and keyboard-only navigation are also not established by this evidence. The closed run-2 reopen addendum below completes the persistence review without extending these layout/input boundaries.
|
||||
|
||||
## Evidence binding and its limits
|
||||
|
||||
- Inspected `prepared.json`, `started.json`, `finished.json`, build `evidence/result.json`, `evidence/source-proof.json`, `capture.js`, `verify-captured.py`, fixture files and every saved-source snapshot receipt/evaluator output. Independently recomputed the lengths/hashes of all 12 immutable entries in prepared.json; all match. This includes the executable, runtime DLL, oracle, helper, result and captured input-map/source-proof records.
|
||||
- The build receipt identifies exit 0, unchanged captured inputs, 832 captured inputs, and desktop artifact SHA-256 `a13190e41bdb2d05ee35f1e6e38d35ce9f7a8a46864d5a73522126c0529489ca`. The native executable matches this artifact. The source-proof receipt reports exact captured inventory/Git blob agreement at the identified source. I checked the receipt bindings; I did not independently repeat the Git-blob comparator.
|
||||
- Native run-1 starts PID 6524 from its isolated copied binary at 03:35:47 UTC; closes at 03:45:29 UTC with exit 0, unchanged immutable inputs and empty stdout/stderr. These are crash/log checks for this run, not assertions about all application behavior.
|
||||
- Capture JSON records window identity, time, accessibility snapshot and image filenames/dimensions. The capture helper does not record each input. Consequently screenshots prove visible states; descriptions of clicks/keys and the single Undo/Redo count are parent-reported execution observations, corroborated by before/after states and source snapshots. Labels alone are not instrumented input evidence.
|
||||
|
||||
## Directly inspected images and workflow findings
|
||||
|
||||
Images inspected with view_image: 17, 18, 19, 21, 22, 23, 24, 26, 27, 28, 30, 32, 38, 39, 40, 42 and 44 (the full-size `-1.jpg` variant when present, otherwise `-0.jpg`).
|
||||
|
||||
1. Captures 17/18/19 expose all ten effects across two pages and page-one scrolling: three selected removals (same-name Action/Control distinguished by @a/@c, plus @approved), one preserved/updated owner, explicit-before and implicit-after order, the two surviving ordered positions @e1/@e2, and caller definitions @caller/@outer. Full names and aliases are readable. The wording separates three removed records from one updated record and two affected caller definitions. It warns that reused topology, entry/exit connections and diagnostics may change and disclaims complete caller graph computation. This correctly avoids presenting the two caller definitions as a reference-instance count: @caller contains two references in the fixture. The transitive @outer row says it uses @assessment; the policy intentionally includes transitive use.
|
||||
2. Page-one content scrolls while search, pagination, Cancel and destructive action stay available. Capture 18 reveals the otherwise lower after-order result; capture 19 exposes both ordered positions and both caller rows. No hidden part of this fixture's reported ten-effect set remains uninspected. This does not establish reachability for arbitrarily long names or much larger effect sets.
|
||||
3. Capture 21 finds exactly @outer with full name and alias. Capture 22 retains that review and search after parent-reported Enter. Capture 23 shows zero matches and helpful recovery wording. The selection count and destructive action remain independent of the filter, as expected for reviewing the captured group.
|
||||
4. Capture 24 after parent-reported Cancel and 27 after Escape retain three selected members, both same-name cards and the maintained arrow at the same visible positions; status says model/selection unchanged. A later saved snapshot is byte-identical to baseline. Capture 26 shows the whole group review after focused Delete; 30 shows it after focused Shift+Delete. Capture 28 explicitly does NOT show a review, despite its filename: parent reports that Shift+Delete immediately after Escape was ineffective until F6 restored canvas focus (29), then Shift+Delete opened 30. This supports the focused shortcut contract; do not claim automatic focus restoration after cancellation.
|
||||
5. Capture 32 shows the restored window with the stale review warning, disabled removal button and available Cancel. Text and controls are readable. Its lower edge is clipped by the available capture/screen, so it cannot count as a fully visible compact-layout pass. Parent reports missing capture 31 followed a UIA restore action that yielded a minimized-window capture error; 32 was recovered through fresh enumeration/reactivation. Missing 34 followed a tool refusal to drag outside screen bounds; parent reports 35 unchanged. Neither absence is a native crash finding or evidence of successful resize.
|
||||
6. Capture 38 shows the menu over unselected Receive report while the original group remains three selected; its action is explicitly Remove selected contributions / links. Capture 39 then reviews @a/@c/@approved, not Receive report. This is a meaningful non-primary/context-subject discriminator.
|
||||
7. Capture 40 shows zero selection and owner inspection after confirmation. Only Receive report and Forward report remain, joined by the expected implicit arrow, and status reports three selected contributions/links removed in one change with referenced definitions preserved. Capture 42 restores the two removed cards and maintained arrow and reports model change undone. Capture 44 returns to the two exchange cards and reports model change redone. The status/canvas observations agree with the byte-exact snapshots below.
|
||||
|
||||
## Exact source and history evidence
|
||||
|
||||
Independently recomputed all snapshot SHA-256 hashes in addition to inspecting the four evaluator results (each PASS, exit 0). Full fixture source inspection confirms that the v2 expected file deletes @a, @c and @approved, changes assessment steps to [@e1,@e2], and retains all work/exchanges, both repeated caller references, transitive caller and opposite-layer sentinel records, with preserved writer trivia.
|
||||
|
||||
| Saved state | Bytes | SHA-256 | Expected |
|
||||
| --- | --- | --- | --- |
|
||||
| cancelled-baseline | 2609 | 9965f4024584d64ac81442724aeb77b018b0cfae94e50bd412c5dcbbac49f6bf | Complete baseline |
|
||||
| removed | 2258 | b4a2b07ad4c796f555c61945ca42b1c221b454b35488c60fefc86f96f7aa71ba | Complete v2 removal oracle |
|
||||
| undo | 2609 | 9965f4024584d64ac81442724aeb77b018b0cfae94e50bd412c5dcbbac49f6bf | Complete baseline |
|
||||
| redo / final working file | 2258 | b4a2b07ad4c796f555c61945ca42b1c221b454b35488c60fefc86f96f7aa71ba | Complete v2 removal oracle |
|
||||
|
||||
The saved-source comparisons establish exact full-file persistence at these checkpoints. Together with parent-reported single Undo/Redo actions and screenshots, they support the one-change history workflow. The source comparator itself does not introspect parser state, transaction count or history stack. This native case does not independently exercise SA removal, qualified-selection refusal, every ContextualLink purpose, a write failure, or every semantic discriminator in the broader automated suite.
|
||||
|
||||
## Residual acceptance gaps and small observations
|
||||
|
||||
- Native 1100px compact layout and complete modal visibility at that width remain untested; do not close that gate based on restored 1442px capture.
|
||||
- Parent created membership with context-menu Add, so native Shift+click selection is not established by this run. The failed early selection attempts 07/08 should not be counted as successful; parent reports selection took after maximize at 10.
|
||||
- Accessibility snapshots expose only the window/system chrome, not application controls; no screen-reader semantics or tab-order acceptance follows. Search caret and focused shortcuts provide only the specific focus evidence above.
|
||||
- No keyboard-only review completion, native failure recovery, or native SA group-removal evidence is included. Existing automated/source-review results must retain their distinct scopes.
|
||||
- The visible plural agreement strings (for example "1 records updated", "1 definitions", "1 adjacent ordered pairs") are minor copy defects, not a correctness or reachability blocker. No source change is proposed as part of this bounded review.
|
||||
- Packaged launch, integration and publication require their own closed records. Run-2 is a fresh native process using an isolated copied executable/runtime; it does not establish execution from the eventual distribution archive.
|
||||
|
||||
## Closed run-2 reopen addendum
|
||||
|
||||
After parent reported closure, inspected run-2 prepared/started/finished records, snapshot receipt/evaluator result, and actual full-size captures `09-reopened-implicit-order-1.jpg` and `10-reopened-saved-1.jpg`. Independently recomputed every prepared immutable file length/hash: all 12 match. Both final working file and independent reopened snapshot hash to the exact 2258-byte v2 removed oracle (`b4a2b07ad4c796f555c61945ca42b1c221b454b35488c60fefc86f96f7aa71ba`). The snapshot evaluator passed with exit 0.
|
||||
|
||||
The prepared record names run-1/snapshots/redo.arcadia as initial source with its matching removed-source pin. Run-2 launched a new process, PID 7248, at 03:45:38 UTC from its separately copied binary and isolated cwd. Capture 09 displays 01 Assessment with zero selection, only Receive report and Forward report joined by the implicit arrow, owner inspection, and the source-opened status. Capture 10 displays all changes saved / all source files saved. The full file remains byte-identical after this reopen/save. The process closed at 03:47:52 UTC, exit 0, empty stdout/stderr and immutableUnchanged true; parent reports normal Alt+F4. These observations support fresh-process load/render/save preservation for the actual removed native result. No parser/history-stack introspection or broad model completeness claim is inferred from them.
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,300 @@
|
||||
"""Offline archive/source/receipt checks. Never executes archived helpers or native binaries."""
|
||||
from pathlib import Path, PurePosixPath, PureWindowsPath
|
||||
import argparse
|
||||
import datetime
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import zipfile
|
||||
|
||||
KIND = 'process-aggregate-removal-native-evidence'
|
||||
PHASES = {'baseline': 'baseline.arcadia', 'removed': 'expected-removed.arcadia'}
|
||||
V2 = 'process-removal-v2-preserved-trivia'
|
||||
|
||||
|
||||
def pin(data):
|
||||
return {'bytes': len(data), 'sha256': hashlib.sha256(data).hexdigest()}
|
||||
|
||||
|
||||
def safe_name(name):
|
||||
p = PurePosixPath(name)
|
||||
assert name and not p.is_absolute() and str(p) == name, 'Unsafe member: ' + name
|
||||
assert '\\' not in name and ':' not in name and not any(x in ('.', '..', '') for x in name.split('/')), 'Unsafe member: ' + name
|
||||
|
||||
|
||||
def check_oracles(files, fixture, prefix='fixtures/'):
|
||||
revision = fixture['fixture_revision']
|
||||
assert revision in ('process-removal-v1-literal', V2)
|
||||
assert fixture['selection'] == fixture['removed'] == ['a', 'c', 'approved']
|
||||
assert fixture['changed'] == ['assessment']
|
||||
assert fixture['caller_definitions'] == ['caller', 'outer']
|
||||
assert fixture['remaining_implicit_order'] == ['e1', 'e2']
|
||||
assert set(fixture['files']) == set(PHASES.values()), 'Wrong fixture inventory'
|
||||
for name, expected in fixture['files'].items():
|
||||
assert pin(files[prefix + name]) == expected, 'Fixture pin mismatch: ' + name
|
||||
baseline = files[prefix + 'baseline.arcadia']
|
||||
assert pin(baseline) == {'bytes': 2609, 'sha256': '9965f4024584d64ac81442724aeb77b018b0cfae94e50bd412c5dcbbac49f6bf'}
|
||||
actual = files[prefix + 'expected-removed.arcadia']
|
||||
if revision != V2:
|
||||
# Preserve the original incorrect oracle as history, never acceptance.
|
||||
assert pin(actual) == {'bytes': 2186, 'sha256': '117b550f0c10753f53febb3ca6beb2c8088688ffa707f21eac654573e4a3d29c'}
|
||||
return
|
||||
text = baseline.decode('utf-8')
|
||||
assert '\r' not in text
|
||||
pattern = r'(?m)^ (?:oa_occurrence (?:a|c) |sequence_link approved )[^\n]*'
|
||||
# Independent fixture-specific lexical rules; never execute archived code.
|
||||
def trivia(line):
|
||||
return re.sub(r'\S', '', re.sub(r'"(?:\\.|[^"\\])*"', '', line))
|
||||
rows = re.findall(pattern, text)
|
||||
assert [trivia(row) for row in rows] == [' ' * 22, ' ' * 20, ' ' * 16]
|
||||
expected = re.sub(pattern, lambda m: '\n\n' + trivia(m.group()) + '\n\n', text)
|
||||
assert expected.count('steps [@a,@e1,@c,@e2]') == 1
|
||||
expected = expected.replace('steps [@a,@e1,@c,@e2]', 'steps [@e1,@e2]')
|
||||
assert actual == expected.encode('utf-8'), 'V2 differs from independently specified delta'
|
||||
assert pin(actual) == {'bytes': 2258, 'sha256': 'b4a2b07ad4c796f555c61945ca42b1c221b454b35488c60fefc86f96f7aa71ba'}
|
||||
|
||||
|
||||
def check_source(files, actual, phase, prefix='fixtures/'):
|
||||
assert phase in PHASES, 'Unknown source phase'
|
||||
assert actual == files[prefix + PHASES[phase]], 'Exact full source differs from ' + phase
|
||||
|
||||
|
||||
def verify(root):
|
||||
manifest = json.loads((root / 'manifest.json').read_text(encoding='utf-8'))
|
||||
assert manifest['kind'] == KIND, 'Wrong package kind'
|
||||
assert pin((root / 'native-evidence.zip').read_bytes()) == manifest['archive'], 'Archive pin mismatch'
|
||||
with zipfile.ZipFile(root / 'native-evidence.zip') as archive:
|
||||
names = archive.namelist()
|
||||
assert len(names) == len(set(names)) and set(names) == set(manifest['members']), 'Archive member inventory mismatch'
|
||||
for name in names:
|
||||
safe_name(name)
|
||||
assert ((archive.getinfo(name).external_attr >> 16) & 0o170000) != 0o120000, 'Symlink member'
|
||||
files = {name: archive.read(name) for name in names}
|
||||
for name, data in files.items():
|
||||
assert pin(data) == manifest['members'][name], 'Member pin mismatch: ' + name
|
||||
assert PurePosixPath(name).suffix.lower() not in ('.exe', '.dll'), 'Unexpected archived binary'
|
||||
for name in manifest['excluded_binary_bytes']:
|
||||
safe_name(name)
|
||||
assert name not in files and PurePosixPath(name).suffix.lower() in ('.exe', '.dll'), 'Invalid omitted binary entry'
|
||||
assert (root / 'verify.py').read_bytes() == files['helpers/native-evidence-verify.py'], 'External verifier differs from pinned helper'
|
||||
|
||||
def js(name):
|
||||
return json.loads(files[name].decode('utf-8-sig'))
|
||||
|
||||
def present_pin(name):
|
||||
return pin(files[name]) if name in files else manifest['excluded_binary_bytes'].get(name)
|
||||
|
||||
def build_binding(prefix, source):
|
||||
receipt = js(prefix + 'result.json')
|
||||
proof = js(prefix + 'source-proof.json')
|
||||
inputs = js(prefix + 'inputs.json')
|
||||
assert receipt['exitCode'] == 0 and receipt['inputsUnchanged'] is True, 'Build not successful/unchanged'
|
||||
assert proof['status'].startswith('PASS') and proof['result'] == pin(files[prefix + 'result.json']), 'Build proof result binding'
|
||||
assert proof['inputMap'] == receipt['inputs'] == pin(files[prefix + 'inputs.json']), 'Build input-map binding'
|
||||
assert proof['inputCount'] == receipt['inputCount'] == len(inputs), 'Build input count'
|
||||
assert proof['commit'] == receipt['head'] == source and re.fullmatch('[0-9a-f]{40}', source), 'Build source identity'
|
||||
return receipt
|
||||
|
||||
fixture = js('fixtures/fixture-manifest.json')
|
||||
check_oracles(files, fixture)
|
||||
for name in files:
|
||||
if name.startswith('oracle-revisions/') and name.endswith('/fixture-manifest.json'):
|
||||
check_oracles(files, js(name), name.removesuffix('fixture-manifest.json'))
|
||||
derivation = 'oracle-revisions/oracle-v2/derive-source-oracle-v2.ps1'
|
||||
assert pin(files[derivation]) == js('oracle-revisions/oracle-v2/fixture-manifest.json')['derivation']
|
||||
config = js('review-config.json')
|
||||
final_source = config['final_source']
|
||||
assert re.fullmatch('[0-9a-f]{40}', final_source)
|
||||
assert config['runs'] == manifest['runs'] and config['preflights'] == manifest['preflights']
|
||||
for entries, prefix, pattern in [(config['runs'], 'runs', r'run-[0-9]+'), (config['preflights'], 'preflight', r'fixture-preflight-[0-9]+')]:
|
||||
assert entries and len({x['name'] for x in entries}) == len(entries)
|
||||
assert all(re.fullmatch(pattern, x['name']) and type(x['accepted']) is bool for x in entries)
|
||||
assert {name.split('/')[1] for name in files if name.startswith(prefix + '/')} == {x['name'] for x in entries}, 'Undeclared archived attempts'
|
||||
|
||||
gates = config['gates']
|
||||
assert len(gates) == len(set(gates)) and {'process-removal-tests-1', 'process-removal-tests-2'} <= set(gates)
|
||||
assert all(re.fullmatch(r'process-removal-(?:tests|format|clippy|build)-[0-9]+', g) for g in gates)
|
||||
assert {n.split('/')[1] for n in files if n.startswith('gates/')} == set(gates)
|
||||
gate_reports = []
|
||||
for gate in gates:
|
||||
prefix = 'gates/' + gate + '/'
|
||||
result, proof, inputs = (js(prefix + f) for f in ('result.json', 'source-proof.json', 'inputs.json'))
|
||||
assert result['inputsUnchanged'] is True and 'finish' in result
|
||||
assert proof['status'].startswith('PASS') and proof['result'] == pin(files[prefix + 'result.json'])
|
||||
assert proof['inputMap'] == result['inputs'] == pin(files[prefix + 'inputs.json'])
|
||||
assert proof['inputCount'] == result['inputCount'] == len(inputs)
|
||||
assert proof['commit'] == result['head'] and re.fullmatch('[0-9a-f]{40}', result['head'])
|
||||
for stream in ('stdout', 'stderr'):
|
||||
assert result[stream] == pin(files[prefix + stream + '.log'])
|
||||
gate_reports.append({'gate': gate, 'source': result['head'], 'exitCode': result['exitCode']})
|
||||
# The original failed gates must remain failed historical facts.
|
||||
for gate, source in [('process-removal-tests-1', 'fe637dcd277b17653139ffa234e601b29775c565'),
|
||||
('process-removal-tests-2', 'f20497b29bf637619bc35ffe41274fc0f66c387b')]:
|
||||
receipt = js('gates/' + gate + '/result.json')
|
||||
assert receipt['head'] == source and receipt['exitCode'] == 101
|
||||
|
||||
reports, preflights = [], []
|
||||
accepted_cli_bindings = set()
|
||||
for entry in config['preflights']:
|
||||
prefix = 'preflight/' + entry['name'] + '/'
|
||||
problems = []
|
||||
try:
|
||||
current = js(prefix + 'result.json')
|
||||
started = js(prefix + 'started.json')
|
||||
fixture_name = prefix + 'evidence/fixture-manifest.json'
|
||||
current_fixture = js(fixture_name)
|
||||
check_oracles(files, current_fixture, prefix + 'fixtures/')
|
||||
revision = current_fixture.get('fixture_revision', 'removal-v1-source-derived')
|
||||
if 'fixture_revision' in current:
|
||||
assert current['fixture_revision'] == revision and current['fixture_manifest'] == pin(files[fixture_name]), 'Preflight fixture revision binding'
|
||||
assert current['fixture_comparator'] == pin(files[prefix + 'evidence/verify-captured.py']), 'Preflight comparator pin'
|
||||
assert started['checks'] == [] and all(current[key] == started[key] for key in started if key != 'checks'), 'Preflight started/result changed identity'
|
||||
assert current['status'].startswith('PASS') and current['cliUnchanged'] is True, 'Preflight not passed'
|
||||
receipt = build_binding(prefix + 'evidence/', current['source'])
|
||||
assert current['receipt'] == pin(files[prefix + 'evidence/result.json']) and current['proof'] == pin(files[prefix + 'evidence/source-proof.json']), 'Preflight proof pins'
|
||||
cli = [a for a in receipt['artifacts'] if a['cargo']['target']['name'] == 'arcadia' and not a['cargo']['profile']['test']]
|
||||
assert len(cli) == 1 and cli[0]['readback'] == current['cli'] == present_pin(prefix + 'bin/arcadia.exe'), 'CLI artifact binding'
|
||||
assert len(current['checks']) == len(PHASES) and {x['fixture'] for x in current['checks']} == set(PHASES.values()), 'Incomplete fixture preflight'
|
||||
for check in current['checks']:
|
||||
name = check['fixture']
|
||||
assert check['exitCode'] == 0 and check['json_report'] is True and check['fixtureUnchanged'] is True, 'Fixture check failed: ' + name
|
||||
assert check['stdout'] == pin(files[prefix + name + '.stdout.json']) and check['stderr'] == pin(files[prefix + name + '.stderr.log']), 'CLI output pins'
|
||||
assert pin(files[prefix + 'fixtures/' + name]) == current_fixture['files'][name], 'Preflight fixture differs'
|
||||
raw = js(prefix + name + '.stdout.json')
|
||||
assert raw['operation'] == 'check' and raw['exit_code'] == 0 and raw['written'] is False and not any(x['severity'] == 'error' for x in raw['diagnostics']), 'Raw CLI report rejects fixture'
|
||||
for runtime in current['runtime']:
|
||||
assert present_pin(prefix + 'bin/' + PureWindowsPath(runtime['source']).name) == {k: runtime[k] for k in ('bytes', 'sha256')}, 'CLI runtime pin'
|
||||
except (AssertionError, KeyError, ValueError, TypeError) as error:
|
||||
problems.append(str(error))
|
||||
preflights.append({'preflight': entry['name'], 'reviewer_accepted': entry['accepted'], 'checks_pass': not problems, 'problems': problems})
|
||||
if entry['accepted']:
|
||||
assert current_fixture['fixture_revision'] == V2, 'Historical v1 cannot be accepted'
|
||||
assert current['source'] == final_source, 'Accepted preflight source differs'
|
||||
assert not problems, json.dumps(preflights[-1])
|
||||
accepted_cli_bindings.add((current['source'], pin(files[fixture_name])['sha256']))
|
||||
|
||||
for entry in config['runs']:
|
||||
prefix = 'runs/' + entry['name'] + '/'
|
||||
problems, captures, sources = [], 0, []
|
||||
# Report the actual discovered count even when an earlier historical
|
||||
# source failure prevents the remaining per-run checks from passing.
|
||||
for name in files:
|
||||
if name.startswith(prefix) and name.endswith('.json'):
|
||||
try:
|
||||
record = js(name)
|
||||
captures += int(isinstance(record, dict) and 'images' in record)
|
||||
except (ValueError, UnicodeError):
|
||||
pass
|
||||
try:
|
||||
prepared, started, finished = (js(prefix + name + '.json') for name in ('prepared', 'started', 'finished'))
|
||||
fixture_name = prefix + 'evidence/fixture-manifest.json'
|
||||
run_fixture = js(fixture_name)
|
||||
check_oracles(files, run_fixture, prefix + 'evidence/')
|
||||
revision = run_fixture.get('fixture_revision', 'removal-v1-source-derived')
|
||||
if 'fixture_revision' in prepared:
|
||||
assert prepared['fixture_revision'] == revision and prepared['fixture_manifest'] == pin(files[fixture_name]), 'Run fixture revision binding'
|
||||
assert started['prepared'] == pin(files[prefix + 'prepared.json']), 'Started/prepared binding'
|
||||
for rel, expected in prepared['immutable'].items():
|
||||
safe_name(rel)
|
||||
assert present_pin(prefix + rel) == expected, 'Immutable pin: ' + rel
|
||||
assert prepared['helper'] == pin(files[prefix + 'evidence/native-harness.py']), 'Native helper binding'
|
||||
for helper in ('capture.js', 'verify-captured.py'):
|
||||
rel = 'evidence/' + helper
|
||||
assert prepared['immutable'].get(rel) == pin(files[prefix + rel]), 'Captured observation/source helper is not immutable: ' + helper
|
||||
for name in [*run_fixture['files'], 'fixture-manifest.json']:
|
||||
assert prepared['immutable'].get('evidence/' + name) == pin(files[prefix + 'evidence/' + name]), 'Run oracle is not immutable: ' + name
|
||||
receipt = build_binding(prefix + 'evidence/', prepared['source'])
|
||||
gui = [a for a in receipt['artifacts'] if a['cargo']['target']['name'] == 'arcadia-studio' and not a['cargo']['profile']['test']]
|
||||
assert len(gui) == 1 and gui[0]['readback'] == prepared['artifact'] == present_pin(prefix + 'bin/arcadia-studio.exe'), 'GUI artifact binding'
|
||||
for runtime in prepared['runtime_sources']:
|
||||
assert present_pin(prefix + 'bin/' + PureWindowsPath(runtime['path']).name) == {k: runtime[k] for k in ('bytes', 'sha256')}, 'GUI runtime pin'
|
||||
assert started['command'] == prepared['command'] and started['cwd'] == prepared['cwd'], 'Launch command/cwd changed'
|
||||
identity = started['identity']
|
||||
assert identity['pid'] == started['pid'] and identity['created_filetime'] > 0 and identity['running'] is True, 'Missing initial live process identity'
|
||||
assert PureWindowsPath(identity['image']) == PureWindowsPath(prepared['command'][0]), 'Wrong process image'
|
||||
assert finished['exitCode'] == 0 and finished['immutableUnchanged'] is True, 'Normal exit/immutability not established'
|
||||
for stream in ('stdout', 'stderr'):
|
||||
assert finished[stream] == pin(files[prefix + 'app.' + stream + '.log']), 'Final log binding'
|
||||
assert finished['working'] == pin(files[prefix + 'working.arcadia']), 'Final source binding'
|
||||
assert prepared.get('initial_pin', started['workingBefore']) == started['workingBefore'], 'Initial source pin changed'
|
||||
origin = entry.get('reopen_from')
|
||||
if prefix + 'reopen-origin.json' in files:
|
||||
old = js(prefix + 'reopen-origin.json')
|
||||
declared = {'run': old['from_run'], 'file': old['from_file']}
|
||||
assert origin is None or origin == declared, 'Contradictory reopen origins'
|
||||
origin = declared
|
||||
assert old['from_pin'] == old['copied_pin'] == started['workingBefore'], 'Reopen-origin pins disagree'
|
||||
if origin:
|
||||
assert origin['run'] != entry['name'] and origin['run'] in {x['name'] for x in config['runs']}, 'Unknown/self reopen origin'
|
||||
safe_name(origin['file'])
|
||||
assert pin(files['runs/' + origin['run'] + '/' + origin['file']]) == started['workingBefore'], 'Reopen source is not the exact captured copy'
|
||||
else:
|
||||
assert started['workingBefore'] == run_fixture['files']['baseline.arcadia'], 'Nonbaseline start needs explicit reopen_from'
|
||||
phases = entry.get('source_phases', {})
|
||||
actual_sources = [name for name in files if name.startswith(prefix) and name.endswith('.arcadia') and '/evidence/' not in name and name != prefix + 'baseline.arcadia']
|
||||
assert set(phases) <= {name[len(prefix):] for name in actual_sources}, 'Phase config references missing source'
|
||||
for name in actual_sources:
|
||||
rel = name[len(prefix):]
|
||||
sidecar = name[:-8] + '.json'
|
||||
phase = phases.get(rel)
|
||||
if sidecar in files and 'phase' in js(sidecar):
|
||||
saved = js(sidecar)
|
||||
assert phase is None or phase == saved['phase'], 'Contradictory snapshot phase'
|
||||
phase = saved['phase']
|
||||
assert saved['pin'] == pin(files[name]) and saved['exitCode'] == 0, 'Snapshot check/pin failed'
|
||||
evaluated = js(name[:-8] + '.evaluator.stdout.json')
|
||||
assert evaluated['status'] == 'PASS' and evaluated['phase'] == phase and evaluated['sha256'] == pin(files[name])['sha256'], 'Raw source evaluator report mismatch'
|
||||
assert not files[name[:-8] + '.evaluator.stderr.log'], 'Source evaluator stderr is nonempty'
|
||||
check_source(files, files[name], phase, prefix + 'evidence/')
|
||||
sources.append({'file': rel, 'phase': phase})
|
||||
start_time = datetime.datetime.fromisoformat(started['started'])
|
||||
finish_time = datetime.datetime.fromisoformat(finished['finished'])
|
||||
assert start_time <= finish_time, 'Reversed process lifetime'
|
||||
for name in files:
|
||||
if not name.startswith(prefix) or not name.endswith('.json'):
|
||||
continue
|
||||
record = js(name)
|
||||
if not isinstance(record, dict) or 'images' not in record:
|
||||
continue
|
||||
assert record['images'], 'Empty capture record'
|
||||
assert record['window']['app'].casefold() == ('process:' + identity['image']).casefold(), 'Capture uses a different executable surface'
|
||||
observed = datetime.datetime.fromisoformat(record['time'])
|
||||
assert start_time <= observed <= finish_time, 'Capture is outside process lifetime'
|
||||
for image in record['images']:
|
||||
safe_name(image['file'])
|
||||
assert prefix + image['file'] in files and image['width'] > 0 and image['height'] > 0, 'Missing/invalid capture image'
|
||||
assert captures > 0, 'No captured native observations'
|
||||
if entry['accepted']:
|
||||
assert run_fixture['fixture_revision'] == V2, 'Historical v1 cannot be accepted'
|
||||
assert prepared['source'] == final_source, 'Accepted native source differs'
|
||||
assert (prepared['source'], pin(files[fixture_name])['sha256']) in accepted_cli_bindings, 'No accepted current-source/current-oracle CLI fixture preflight'
|
||||
except (AssertionError, KeyError, ValueError, TypeError) as error:
|
||||
problems.append(str(error))
|
||||
reports.append({'run': entry['name'], 'reviewer_accepted': entry['accepted'], 'checks_pass': not problems, 'problems': problems, 'capture_records': captures, 'source_checks': sources})
|
||||
if entry['accepted']:
|
||||
assert not problems, json.dumps(reports[-1], indent=2)
|
||||
return {
|
||||
'status': 'PASS offline archive, exact source and receipt consistency checks',
|
||||
'gates': gate_reports,
|
||||
'runs': reports,
|
||||
'preflights': preflights,
|
||||
'accepted_run_count': sum(entry['accepted'] for entry in config['runs']),
|
||||
'limitations': [
|
||||
'Human visual, keyboard, selection and interaction claims are not inferred from screenshots.',
|
||||
'Omitted executable/DLL bytes cannot be rehashed offline.',
|
||||
'Build proof/input map consistency checked; Git blobs are not independently available offline.',
|
||||
'accepted=false failures are retained and reported, never silently promoted.',
|
||||
'No native history-depth introspection, usability acceptance, release or publication assertion.',
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('directory', type=Path)
|
||||
args = parser.parse_args()
|
||||
print(json.dumps(verify(args.directory.resolve()), indent=2))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,93 @@
|
||||
# Independent Process removal planner review
|
||||
|
||||
Read-only source/test review against the amended Process group-removal policy.
|
||||
Base `c62622cce71e06f0beae49bc3b4fe8e890eba951`; inspected uncommitted files:
|
||||
|
||||
- `crates/oa-desktop/src/behavior/topology/group_removal.rs`, SHA256
|
||||
`4F125AB9F5EFEE7B92700E2B23E5B805A16BF2529F662D5C4413368752960C79`.
|
||||
- `crates/oa-desktop/src/behavior/topology/group_removal/tests.rs`, SHA256
|
||||
`3E6E56A45738F5E377C0659C58AD782ECDA408657439B806DAEFD396E06A46D5`.
|
||||
|
||||
No production defect found in this bounded inspection. No Cargo/UI execution;
|
||||
this does not establish passing tests, App admission, native usability or release
|
||||
acceptance. Prior policy critique is `process-removal-policy-critique-20260925.md`.
|
||||
|
||||
## Prior P1 correction verified in source
|
||||
|
||||
`prepare:213–217` derives affected definition owners from actual removed and
|
||||
changed IDs using both project versions, then traverses unioned before/after
|
||||
reuse dependencies. `definition_owner:106–124` handles definition records,
|
||||
direct contributions and both maintained relation kinds with explicit owner for
|
||||
ContextualLink. It does not require interpretation changes. The test at `:372`
|
||||
uses Actions A/B/C, A→B and B→C, repeated direct references and a transitive
|
||||
caller; deleting A or A→B yields literal {caller,outer} with unchanged
|
||||
interpretation facts and unchanged caller records. This addresses the reported
|
||||
explicit-to-explicit false negative.
|
||||
|
||||
## Admission and transaction assessment
|
||||
|
||||
- `prepare:127–178` validates the initial structural model, every owner-listed
|
||||
contribution and every original typed member. Correct owner, body, layer,
|
||||
membership and uniqueness are enforced. Qualified occurrences/preview links,
|
||||
unlisted selected cards, wrong target classes and foreign maintained links
|
||||
refuse before mutation/normalization.
|
||||
- SequenceLink endpoints must both be validated listed contributions;
|
||||
ContextualLink admission uses its explicit owner. Initial core validation
|
||||
supplies remaining endpoint/purpose constraints and permits warning-only
|
||||
incomplete models.
|
||||
- `:181–187` unions occurrence cascades, omits only covered relation commands and
|
||||
evaluates one Batch. Sorting admitted occurrence roots before uncovered links
|
||||
avoids UUID/click-order dependency. This is valid for the admitted contribution
|
||||
and maintained-link domain; no mutual occurrence deletion dependency exists.
|
||||
- `:188–206` derives actual identity differences, rejects new IDs and verifies
|
||||
every original selection was removed. `Project::identities` includes embedded
|
||||
placements; complete surviving record comparisons include diagram records and
|
||||
embedded nodes, artifacts and traces. The implementation covers every mutable
|
||||
record map in the current Project schema.
|
||||
|
||||
## Semantic impact assessment
|
||||
|
||||
`interpretations:43–73` correctly separates desktop listed-step interpretation,
|
||||
core indexed-contribution/no-maintained-relation interpretation, and transitive
|
||||
ContextualLink presence. All surviving definitions are compared, independently
|
||||
of record deltas. Owned-unlisted contributions affect the core predicate and
|
||||
caller edges. Empty `Some([])` remains a classifier, not proof of a valid flow;
|
||||
the policy's user-visible wording condition remains applicable.
|
||||
|
||||
`callers:85–98` terminates with a seen set, deduplicates definition owners and
|
||||
filters to surviving definitions. It does not enumerate repeated instance paths
|
||||
or assert complete expanded connectivity. Both snapshots contribute reuse
|
||||
edges. Global dependent link removal seeds its explicit defining owner even
|
||||
when that owner's own record is unchanged.
|
||||
|
||||
## Test evidence and remaining gaps
|
||||
|
||||
The tests construct literal removal and surviving-change identity sets, literal
|
||||
interpretation vectors/flags/caller sets, and independently clone/prune the
|
||||
expected model (`expected_without:68`). They do not use the planner candidate as
|
||||
the expected result. `assert_history:76` compares the complete Project, reopens
|
||||
the emitted source bundle and verifies exact bundle/model Undo and Redo. OA and
|
||||
SA execute each scenario. This is meaningful source-level evaluator design.
|
||||
|
||||
Two useful remaining verification gaps were sent to the parent; they are not
|
||||
demonstrated production failures:
|
||||
|
||||
1. Mixed covered and uncovered selected relations in the same group. Current
|
||||
mixed occurrence/link tests cover every selected relation via occurrence
|
||||
roots; uncovered selected links are otherwise tested alone. Add A,B,C,D with
|
||||
L1=A→B and independent L2=C→D; select A,L1,L2; literal result removes exactly
|
||||
{A,L1,L2}, preserves B,C,D and runs exactly Delete(A),Delete(L2), regardless
|
||||
of click/UUID order. This discriminates accidentally dropping uncovered
|
||||
relations when occurrence roots exist.
|
||||
2. Aggregate identity bookkeeping outside process records. Existing fixtures
|
||||
contain no artifacts, traces, opposite-layer counterpart or embedded diagram
|
||||
placements. Add a valid attachment/trace/placement case and compare literal
|
||||
removed IDs, changed surviving diagram/owner IDs, and complete preserved
|
||||
counterpart/source model. Core cascade behavior has existing independent
|
||||
tests, but this new planner's review accounting still needs direct evidence.
|
||||
|
||||
Other bounded limitations: fixed adversarial UUID ordering is not explicitly
|
||||
constructed; source inspection proves occurrence-before-link partitioning, while
|
||||
tests reverse click order. App/source-write-failure/visibility/lifetime tests
|
||||
belong to the adapter review. Large reuse performance and incomplete expanded
|
||||
analysis are not runtime-tested here.
|
||||
@@ -0,0 +1,109 @@
|
||||
# Independent Process removal policy critique
|
||||
|
||||
Local-only review for parent session issue 29. Base inspected:
|
||||
`c62622cce71e06f0beae49bc3b4fe8e890eba951`; policy and concurrent planner work were
|
||||
uncommitted. Read-only inspection apart from this note; no Cargo, UI, Gitea or
|
||||
production edits. This is policy/source review, not runtime acceptance.
|
||||
|
||||
## P1: interpretation-only caller closure misses ordinary topology changes
|
||||
|
||||
**Status:** reported promptly; parent accepted and instructed planner/App to add
|
||||
`affected_uses` independently of interpretation changes. Concurrent planner
|
||||
source now contains that collection, but this review does not verify the final
|
||||
implementation or tests.
|
||||
|
||||
The initial policy computed caller closure only for changed `local_order`,
|
||||
`expanded_order` or transitive contextual-presence flags. Those facts detect
|
||||
implicit-order changes and diagnostic mode changes, but do not cover ordinary
|
||||
explicit-to-explicit topology changes. A caller's record can remain unchanged
|
||||
while its reused graph changes substantially.
|
||||
|
||||
Literal discriminator, separately instantiated for OA and SA:
|
||||
|
||||
- P owns Action A, Action B, Action C and links L1=A→B, L2=B→C.
|
||||
- Q owns R1(P) and R2(P); T owns RT(Q).
|
||||
- Remove L1. P's `steps` is still [A,B,C], both implicit-order facts remain
|
||||
`None`, contextual presence remains false. Removed IDs are exactly {L1}; L2,
|
||||
all actions, both Q references, T's reference, and all work definitions survive.
|
||||
- Nevertheless P's intrinsic entries change from {A} to {A,B}; expanding either
|
||||
Q reference adds synthetic connectivity from that reference's entry to B.
|
||||
Expected affected caller definition set for P is exactly {Q,T}.
|
||||
- Removing A instead also changes Q/T while the three interpretation facts can
|
||||
remain equal. Removing one ContextualLink while another remains yields the
|
||||
same kind of false negative for a contextual-presence-only detector.
|
||||
|
||||
Source: `crates/oa-core/src/topology_context/analysis.rs:262–298` expands callee
|
||||
entries/exits into synthetic edges; `:412–425` derives intrinsic boundaries from
|
||||
remaining precedence. `docs/language.rst:632–640` separates synthetic connectivity
|
||||
from authored degree and forbids complete-looking results from incomplete
|
||||
analysis. The multiple-selection contract requires aggregate removal impact.
|
||||
|
||||
Bounded correction: derive changed definition owners from actual removed/changed
|
||||
contribution and maintained-link records in both candidates; find surviving
|
||||
caller definitions using before/after reverse reuse closure. Keep interpretation
|
||||
facts as additional, more precise effects. Label the former “uses changed
|
||||
definition”; explain that reused topology, entry/exit connectivity and
|
||||
diagnostics can change. No full expanded graph is needed to establish this
|
||||
conservative affected set. Do not equate “no newly created stored identity” with
|
||||
“no new effective connectivity.”
|
||||
|
||||
## P2 wording conditions: empty definitions and repeated uses
|
||||
|
||||
These are review conditions, not verified defects in the unfinished App.
|
||||
|
||||
1. Empty expanded definition: `Builder::expand` returns an incomplete-analysis
|
||||
notice immediately when children are empty (`analysis.rs:212–221`), before
|
||||
the exchange-only discriminator at `:384`. Representing an empty classifier
|
||||
as `Some([])` is useful to distinguish it from explicit mode, but does not
|
||||
establish a valid implicit flow or any entry/exit. Literal discriminator:
|
||||
P has only A; remove A; review says no remaining contributions/no ordered
|
||||
pair, and does not promise connected or executable flow. Core incomplete
|
||||
diagnostics remain authoritative. The policy already disclaims full graph
|
||||
analysis; user-visible wording must carry that distinction.
|
||||
2. Caller-owner closure is not a use-instance count. In the P/Q/T discriminator
|
||||
above, Q is one caller definition containing two references to P. A map
|
||||
containing Q once must not say “one use.” “Caller definitions” or “uses changed
|
||||
definition” is accurate. No Cartesian expansion is necessary.
|
||||
|
||||
## Accepted boundaries and why
|
||||
|
||||
- Comparing both real order predicates is preferable to refusing every model
|
||||
where listed desktop and indexed core contributions differ. The inconsistency
|
||||
predates this operation: desktop `behavior.rs:1097–1123` looks at listed steps
|
||||
and SequenceLinks; core `topology_context.rs:97–145` includes unlisted owned
|
||||
contributions and ContextualLinks. Reporting both actual facts is sufficient
|
||||
for this bounded operation, provided it claims neither full graph preservation
|
||||
nor complete expanded analysis. Selected unlisted cards remain ineligible.
|
||||
- The actual final candidate and all changed surviving records are the correct
|
||||
authority for global stored impact. `references.rs:325–427` propagates every
|
||||
typed ContextualLink dependency, descendants, traces, attachments and embedded
|
||||
placements; `:459` onwards clears/prunes surviving records. A caller-owned
|
||||
ContextualLink must be identified by explicit owner, not leaf parent.
|
||||
- Occurrence-root cascade union plus uncovered selected relation commands is
|
||||
valid for the admitted kinds. These occurrences do not own one another;
|
||||
maintained Process relations cannot delete their contribution endpoints or
|
||||
another admitted maintained relation. Selected links covered by occurrence
|
||||
cascade remain selected review subjects. Control-flow cycles do not introduce
|
||||
deletion-dependency cycles. Generalizing admitted kinds requires revisiting
|
||||
this argument. The final Batch remains authoritative for compound effects.
|
||||
- ContextualLink Exchange/CommonWork removal is assembly impact, not necessarily
|
||||
precedence removal. Underlying work/exchange definitions survive. Qualified
|
||||
local ContextualLink endpoints do not make the caller-owned relation read-only;
|
||||
qualified preview occurrences/links are a different target class.
|
||||
- Capturing document/revision/owner/epoch plus selection membership, primary and
|
||||
generation is the right lifetime boundary. `diagram_selection.rs:169–175`
|
||||
explicitly handles remove/re-add and primary-change/restore ABA. Final
|
||||
admission must use rendered visibility and the current tool/draft/gesture
|
||||
gates, not just UUID existence. Token scoping prevents old modal packets from
|
||||
mutating the next review. This policy is sufficient; unfinished App execution
|
||||
was not independently verified here.
|
||||
|
||||
## Remaining verification focus
|
||||
|
||||
Literal tests should include the explicit-to-explicit caller case above,
|
||||
repeated-reference owner counting, empty definitions, mixed occurrence/link
|
||||
cascade normalization in reverse click/UUID order, and a secondary-selection
|
||||
ABA with the primary restored. Native review should inspect truthful meaning,
|
||||
all impact pages/search, input focus and Enter behavior, stale packets, Cancel,
|
||||
source-write failure and exact Undo/Redo/save/reopen. This critique does not
|
||||
substitute for those checks.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Process removal source-oracle investigation — 2026-09-25
|
||||
|
||||
Local-only, bounded investigation at source `fe637dcd277b17653139ffa234e601b29775c565`. Parent owns Process removal and oracle integration. No production code, tests, or versioned fixtures edited; no Cargo, build, UI or Gitea operation. Another worker's `model_menu.rs` edit was observed and left untouched.
|
||||
|
||||
## Conclusion
|
||||
|
||||
The full semantic Project comparison passed before the lexical assertion failed. The three selected/dependent declarations (Action `a`, Control `c`, SequenceLink `approved`) are removed, Process steps retain `e1,e2`, reused definitions and unrelated OA/SA records agree with the independently authored model oracle. The failed assertion is an incorrect **lossless-source oracle**, not evidence of a semantic deletion defect or a newly introduced writer regression.
|
||||
|
||||
The source contract explicitly says removed declarations erase syntax tokens while retaining their comments **and whitespace** as enclosing annotations (`docs/language.rst:1987-1989`). It also requires deletion annotations be separated from adjacent declarations with blank lines (`:1963-1964`) and preserves surviving reference-list chunks and their separator-adjacent trivia (`:1993-2000`). Canonical export is a different operation (`:1926-1929`); the mutation path must not silently reformat source (`:1969-1973`). `harness/release-source-project.md:43-45` and `harness/DECISIONS.md:87,93` corroborate this accepted policy.
|
||||
|
||||
This does not establish that blank space-only annotations are the ideal future editor UX. They follow an explicit existing contract and pre-existing implementation; changing them would require a separately scoped source-policy decision and source/core validation. Silently removing them solely to satisfy a newly authored Process oracle would change the common writer contract. No production formatting fix is justified within this aggregate-removal acceptance task.
|
||||
|
||||
## Independent derivation
|
||||
|
||||
Input `harness/fixtures/process-removal-baseline-20260925.arcadia`:
|
||||
|
||||
- Source commit: `fe637dcd277b17653139ffa234e601b29775c565`.
|
||||
- Git blob: `9570e150d160bea87dc70b5dacedc692eb3708b4`.
|
||||
- SHA-256: `9965f4024584d64ac81442724aeb77b018b0cfae94e50bd412c5dcbbac49f6bf`.
|
||||
- Original UTF-8/LF bytes are required; derivation refuses changed input or CR characters.
|
||||
|
||||
1. Original steps are `[@a,@e1,@c,@e2]`. Surviving entries have no leading/trailing trivia and the removed entries have no trivia. Retain `@e1` and `@e2`, emit their one comma, and invent no whitespace: **`[@e1,@e2]`**. `source_project.rs:1516-1651` implements unique-reference identity matching and chunk preservation; this is not canonical `, ` formatting.
|
||||
2. For each removed single-line declaration, quoted strings are indivisible syntax tokens. Their interior spaces disappear with those strings. Every whitespace byte outside strings survives, including the four-space indentation. Independent token-boundary counting yields **22 spaces for Action `a`, 20 for Control `c`, 16 for link `approved`**.
|
||||
3. `source_structure.rs:236-271` creates deleted-declaration pieces through `trivia`; `source_project.rs:1127-1139` retains only Whitespace/Comment tokens. `attached_span` at `source_structure.rs:435` includes the line indentation and leaves the ordinary following newline in the enclosing gap when there is no trailing comment.
|
||||
4. Existing concrete structural policy (`source_structure.rs:397-404`) surrounds each orphaned annotation with **two LF characters on each side**. The untouched original gap has one LF on either side. Consequently the exact post-predecessor sequence is `"\n\n\n" + " " * N + "\n\n\n"`, followed by the next declaration's unchanged four-space indentation. These are three LF characters per side, not three full empty lines per side.
|
||||
5. All other baseline bytes remain unchanged. The specification requires whitespace retention and blank-line separation; the exact two-LF inserted boundary is the established writer policy, not a claim that every conforming future writer must always choose that count.
|
||||
|
||||
The common structural file's latest historical change is `4e8575bd1127d132b8170b408163ef234b4d307e` (`feat: preserve nested source projects across desktop and REST`), predating this Process change. Existing tests `crates/oa-core/tests/source_project.rs:1065` (`removed_list_items_and_declarations_keep_comments_as_enclosing_annotations`) and `crates/oa-core/tests/source_nested_updates.rs:187` (`deleting_owner_retains_annotations_and_extracts_independently_moved_descendant`) verify comment retention, semantic equality and annotation ownership. Those tests support the policy but do not themselves prescribe the exact 22/20/16 whitespace-only output; the above input-specific derivation does.
|
||||
|
||||
## Created artifacts and separate observation check
|
||||
|
||||
- `.local/process-removal-native/derive-source-oracle-v2.ps1`: create-only fixture-specific derivation script. It reads only the checksum-pinned baseline, applies the independently stated lexical rules, and refuses to overwrite an existing output. It does **not** read production writer code, expected-v1, failure logs or actual output. Script SHA-256: `38979a4b233b7d28a6392070c72298fb6c17660b2a2c8dc2a3bff74c3c816fae`.
|
||||
- `.local/process-removal-native/expected-removed-v2.arcadia`: independently derived candidate, **2258 bytes**, SHA-256 `b4a2b07ad4c796f555c61945ca42b1c221b454b35488c60fefc86f96f7aa71ba`.
|
||||
- Reproduce into a new destination: `& .local/process-removal-native/derive-source-oracle-v2.ps1 -OutputPath <new-output.arcadia>`. The script refuses changed baseline and an existing destination.
|
||||
|
||||
Only **after creating** the candidate, I separately extracted the sole `left: SourceBundle` project's JSON-compatible ASCII debug string from the failed log using an anchored shape check and `ConvertFrom-Json`, then encoded UTF-8 and compared byte-for-byte. **MATCH**, 2258 derived bytes and 2258 observed bytes. This observation corroborates the rule derivation; actual output was not an input to the derivation script. Failure log `.local/scenario-group-gates/process-removal-tests-1/stdout.log` SHA-256: `aeb571241a21c246ac94ae64f698b478ded69988b9f811c806bb689bb8af6dc9`.
|
||||
|
||||
The original versioned expected-v1 remains untouched (SHA-256 `117b550f0c10753f53febb3ca6beb2c8088688ffa707f21eac654573e4a3d29c`). The original failed run remains a failure. No new test execution or native acceptance is claimed.
|
||||
|
||||
## Concrete next action
|
||||
|
||||
Parent should preserve v1/failure evidence, introduce a new versioned v2 literal fixture from the pinned independent candidate, and point the full-source comparison and separately versioned native oracle/manifest to v2. Keep the full Project comparison, exact-source assertion and Undo/Redo checks. Explain the lexical correction and explicitly preserve significant space-only lines against editor trimming; a narrowly scoped Git whitespace attribute may be needed for the fixture, consistent with other exact source oracles. Re-run the relevant failed gate on the identified new source and separately review the menu correction. Do not canonicalize the baseline or weaken exact-source equality to semantic-only equality.
|
||||
Reference in New Issue
Block a user