Document verified Scenario reorder App and native workflows

This commit is contained in:
2026-09-24 18:22:29 -07:00
parent 1c4099a9ef
commit cdd5a0462b
14 changed files with 4208 additions and 1 deletions
@@ -48,8 +48,18 @@ Aggregate removal remains separate required work. Until it exists, an interface
Use the existing shared Selection/Snapshot with a full Scenario Context envelope. Map a derived representation to `Surface::Scenario(owner)` and a saved representation to `Surface::Saved(diagram)`. Representation navigation clears the group; the envelope additionally admits document, owner, representation, visit, revision and epoch, including A-to-B-to-A visits. Exact visibility comes from the actual presented scene. This choice preserves existing selection semantics without adding Scenario-specific fields to every generic adapter.
The saved-view gesture is still an open design decision. The initial [adapter mapping](scenario-group-planner-evidence-20260924/reviews/adapter-design.md) proposed a one-shot arm; the [independent critique](scenario-group-planner-evidence-20260924/reviews/adapter-critique.md) identified a simpler group handle and an operation-local order preview worth comparing first. Authored message coordinates may remain visually unchanged after a real semantic reorder, so an arm label alone does not establish observable success. Compare a handle plus order preview with an arm plus order preview using the same noncontiguous A/C-before-D task, then an ordinary spacing edit. Preserve the active saved representation and captured group during the operation preview; do not transfer selection across actual representation navigation.
At this historical review boundary, the saved-view gesture remained open. The initial [adapter mapping](scenario-group-planner-evidence-20260924/reviews/adapter-design.md) proposed a one-shot arm; the [independent critique](scenario-group-planner-evidence-20260924/reviews/adapter-critique.md) identified a simpler group handle and an operation-local order preview worth comparing first. Authored coordinates may remain visually unchanged after semantic reorder, so an arm label alone cannot establish observable success. The later destination experiment and implemented chooser decision below supersede that open choice for this increment; the earlier alternatives remain historical evidence. Preserve the active saved representation and captured group during preview; do not transfer selection across representation navigation.
Before enabling group input, specify a consumed gesture identity (or prove equivalent epoch retirement) so canceled, completed/no-op and duplicate packets cannot affect a newer gesture on the same unchanged selection. Match captured selection identity on spacing packets too; group-size checks alone miss selection ABA. If returning to the original press position promises no change, define that screen-space rule separately from nearest-slot selection; the nearest slot need not be the pressed occurrence's anchor. Close raw Details arrows, menus and singleton removal/reorder paths before they can apply to only the primary of a visible group.
The planner's [verification record](scenario-group-planner-20260924.md) establishes the bounded semantic foundation. It does not accept any of these future UI choices or claim group gestures are implemented.
## Implemented successor: explicit semantic destination chooser
The [App implementation and Windows evidence](scenario-reorder-app-20260924.md) at `1c4099a9ef76dd28d17ef892e95edf89e860569f` promotes the shared frozen session into production input. The header Reorder control offers exact same-parent before-anchor/end identities with search, paging, and a before/after semantic-order preview. This is the selected bounded implementation following the tied-Y counterexample; no one-shot arm or nearest-Y-only group drag is enabled. Ordinary Saved body/header spacing retains its meaning. Future graphical access must preserve exact identity reachability and the same whole-set semantics.
Begin retires captured input before acquiring the new full Context/Snapshot/token. Every proposal retains the requested representation, complete selection and primary. Apply/Finish captures the exact displayed Slot; queued Apply for another preview is inert. No default destination exists. Enter previews a unique match; nonrepeated Ctrl+Enter applies an eligible displayed proposal after child-overlay precedence; Escape cancels. Stale token-specific focus tasks cannot disturb newer focus. The current Slot alone is cached, bounding retained scene memory.
Baseline Fallback admits semantic choice only when every selected target is visible. Candidate Fallback may commit after an explicit adjacent warning, retaining the requested Saved view and all authored layout records. Candidate Unavailable or loss of any selected rendered target blocks commit. These are explicit App policies, not implicit permissions from semantic validation. The completed result shows actual semantic order with full aliases; its lifetime tolerates camera/diagnostic input-epoch changes but remains bound to document/revision/view/visit and exact selection generation. Subsequent spacing commits retire that explanation.
Scenario tests, formatting, strict lint and build pass at this source with exact 818-input source proofs. Windows native run 2 exercises tied/distant identity destinations, ordinary/compact preview readability, cancellation/no-op Redo retention, semantic result feedback and keyboard entry; fresh-process run 3 verifies exact saved-source reopen. Native selection used contextual Add, not demonstrated Shift-click; F6 followed by six reverse Tab steps is reachable but remains a discoverability limitation. Real App source-write failure remains a runtime coverage gap. These scoped results do not claim default-branch integration, a new release, aggregate removal or full issue-29 completion. The linked report retains failed attempts and evidence boundaries.
+81
View File
@@ -0,0 +1,81 @@
# Scenario semantic reorder App increment — Windows evidence
Implementation and bounded Windows verification at `1c4099a9ef76dd28d17ef892e95edf89e860569f`, on the issue-29 working branch. This succeeds the historical [interaction experiment](scenario-reorder-interaction-20260924.md) and implements the [reorder policy](scenario-group-reorder-policy-20260924.md). It does not claim integration into the default branch, a new release, or completion of all issue-29 work. The issue-37 prerelease is unchanged; Linux remains user-paused.
At this exact source, Scenario tests **315 passed / 0 failed / 1 ignored / 1,296 filtered**, formatting, strict desktop Clippy and the desktop/CLI build passed, each with 818 unchanged inputs and exact source proof. Native run 2 confirms the corrected chooser at ordinary and compact sizes; fresh-process run 3 confirms exact saved-source reopen. The complete checks package retains **17 runs including five failures**, rather than replacing failed history.
[Portable evidence and verification](scenario-reorder-app-evidence-20260924/README.md): checks ZIP 29,229,448 bytes, SHA-256 `80406d81e0a5d47bea2ef284bc50a079713d828e8ea291cb96cfcedfeaa16235`; native ZIP 12,792,711 bytes, SHA-256 `0686d691a6ecea80310c5ee31056de36a7389d89a41ca501e6db9427f1ba4a82`. Both standalone verifiers pass their documented consistency checks. Source, command, UI and platform limits below remain part of acceptance.
## Implemented behavior and design
The Scenario header's Reorder control opens an explicit semantic destination chooser for the entire exact selection. Ordinary Saved message/lifeline drags retain their spacing meaning. Ordered local occurrences must be visible and share one immediate Scenario/Branch parent; unsupported or cross-parent members refuse the complete set. Selection does not grant movement permission. A selected anchor is an explicit no-op; append is explicit; there is no default destination.
The chooser searches full names, aliases and positions, pages five exact destinations at a time, and compares before/after semantic neighborhoods. The selected block follows original sequence order, independent of click order or primary. Exact destination and display consequences remain beside Apply in a fixed footer. This addresses the preceding experiment's counterexample: tied Saved Y positions make some semantic destinations unreachable through unchanged nearest-Y-only dragging. The chooser is a justified identity-based implementation; it does not establish that a graphical handle can never work or that all future interaction choices are settled.
Header access uses the existing keyboard control mechanism. Successful Begin requests token-specific query focus. Enter previews a unique search match; Ctrl+Enter applies the exact displayed proposal, ignores autorepeat, and is consumed when no valid proposal exists. Escape cancels. The current child overlay gets priority: an arrangement picker opened earlier in the same Iced input batch must block cached Apply. A stale focus task first checks for its exact target and cannot blur a newer query. The chooser is outside the camera Viewport so that its input reaches text and scrolling controls.
One immutable Session captures Project, full Scenario Context, complete selection Snapshot and token. It retains only the current exact-Slot proposal; repeated current Slot reuses it, a changed/revisited Slot recomputes. Commands remain private until consumed Finish. The App rejects stale packets before touching a newer session, retires admitted Begin before fresh capture, and retires terminal success/no-op/refusal/source-write failure. Finish binds the actual displayed Slot, preventing queued Apply(A) from committing preview(B). One Document transaction changes the parent list and preserves all authored layouts, unrelated views, selection and primary. No-op/cancel preserve history, including Redo.
Semantic validity and candidate presentation are separate. Baseline Fallback permits explicit semantic choice only when all selected subjects are actually visible; it does not enable coordinate editing. Candidate Fallback may commit after explicit adjacent warning while retaining the requested Saved representation and authored coordinates. Unavailable candidates or candidates hiding any original selected target cannot commit. Real fallback tests and synthetic guard injections have different evidential scope.
A post-commit result identifies parent, destination, affected count and actual ordered neighborhood using ordinals and full aliases, so repeated names and unchanged Saved Y positions do not obscure the result. The revised summary lifetime ignores passive input-epoch changes but retains document/owner/representation/visit/revision and exact selection generation/membership/primary checks. Live operation admission still requires the full epoch. At `1c4099a9`, admitted spacing Finish reconciles the summary after multiselection reconciliation; stale spacing rejects still return before this change. The passing regression commits real spacing after reorder, checks immediate summary removal without another event, confirms the semantic list/selection remain, and verifies Undo returns to the reordered source. This closes the earlier early-return gap at the source/test level.
## Executed gates and retained failures
Raw receipts, streams, input inventories/archives and source proofs originated under `.local/scenario-group-gates/` and are published in the checks archive's logical-file map. Every entry below records unchanged captured inputs; scenario gates 1–8 each have a PASS exact-inventory/Git-blob source proof. This report reads those records; it does not rerun gates or independently repeat their Git comparison. Commands were Windows GNU/LLVM Rust/Cargo 1.98.1, using the project toolchain environment, one Cargo job and incremental compilation disabled (format-2 records no job variable; formatting does not compile).
| Gate | Exact source | Result and interpretation |
| --- | --- | --- |
| `reorder-app-test-1` | `61099ed4742eaa51c3bd81129bc072d8321961b7` | Compile failure: ambiguous `column` macros and private test fixture helper import. |
| `reorder-app-test-2` | `f3ed6e97dd3caf06046711cf74d268c7274bc780` | `reorder_` filter: 23 pass, 0 fail, 1,581 filtered. Selected only one of nine App tests; not nine-test coverage. |
| `reorder-app-scenario-1` | `f3ed6e97dd3caf06046711cf74d268c7274bc780` | 301 pass, 6 fail, 1 ignore. Five fixtures omitted Derived Behavior navigation; sixth incorrectly expected comma normalization to exceed the source budget. |
| `reorder-app-scenario-2` | `c9f6a3da40e288e9f993d9cacf516142c0017cf3` | 307 pass, 0 fail, 1 ignore after fixture/oracle corrections. |
| `reorder-app-scenario-3` | `652ffb4d1b21f414a69ebac549459f4bb9e3c16a` | Compile failure: nonexistent `text_input::focus` API. |
| `reorder-app-scenario-4` | `9bfa113aa52a957ef268839b5e6d87f97b20d6ea` | Compile failure: widget operation `finish` receiver required `&self`, not `&mut self`. |
| `reorder-app-scenario-5` | `04485e001798430fb1b2e8d1347e6bde51e6e7a1` | 310 pass, 0 fail, 1 ignore; all 12 App tests included. Strict Clippy also passed at this source. |
| `reorder-app-scenario-6` | `14df924b98d74144c1e40fbe7098994ff5eb2e94` | 310 pass, 0 fail, 1 ignore; format, strict Clippy and build also passed at this source. Used for native run 1. |
| `reorder-app-scenario-7` | `201097793c010a181d113bdec7c5bf7ec81eacf9` | Compile failure in new summary test: `oa_core::SourceBundle` is not exported at that path. This does not validate the new layout/summary fixes. |
| `reorder-app-scenario-8` | `1c4099a9ef76dd28d17ef892e95edf89e860569f` | 315 pass, 0 fail, 1 ignore. Includes all 17 App tests: 12 previous adapter/keyboard cases, one long-alias mounted layout case, four summary-lifetime cases. Format-2 also passes at this source. |
The other final-source receipts are `reorder-app-format-2` (`cargo fmt --all -- --check`), `reorder-app-clippy-3` (`cargo clippy -p oa-desktop --all-targets --message-format=json -- -D warnings`) and `reorder-app-build-2` (`cargo build -p oa-desktop -p oa-cli --message-format=json`), all exit 0 with exact 818-input source proofs. The complete 17-run package additionally retains the earlier format-1, clippy-1/2 and build-1 receipts; the five failures are test-1 and scenario-1/3/4/7.
Scenario gates use `cargo test -p oa-desktop scenario --message-format=json -- --nocapture`; completed test executions above each exclude 1,296 other tests. The single ignored test is the existing timing case. Inventories contain 817 inputs through scenario-6 and 818 at scenario-7/8. Scenario-8 and format-2 both record exact 818-input source proofs. The bounded evidence review independently counted all 17 named App passes in raw scenario-8 output and verified both runs' stdout/stderr/input-map/archive hashes and lengths against receipts; it did not repeat Git-blob comparison. Passing source proofs establish source attribution, not functional success for failed gates. All failures must remain in portable evidence.
Coverage includes exact whole-model/source Undo/Redo, selection preservation, no-op Redo, temporal refusal, stale packets/selection ABA, real baseline Fallback, synthetic Unavailable/hidden-target guards, and mounted query/keyboard/overlay ownership. The source writer reorders existing identity chunks with their trivia; the corrected exact-budget test establishes successful byte-preserving permutation and exact Undo readback. **No real App source-write failure fixture was established.** Its error branch remains a runtime coverage gap; separate Document atomicity evidence is not a substitute for executing that adapter branch.
## Native run 1: observations and defects
The retained `.local/scenario-reorder-app-native/run-1-observations.md` records source `14df924b…`, build-1 and current CLI preflight-2. All four fixture checks exited zero with expected incomplete-model warnings. The fixture has 24 repeated display names, tied B/C positions and a distant report_24. Selection used click plus contextual Add to selection; this is **not** native Shift-click evidence. Initial nonmaximized navigation misses and a file-picker UIA failure remain disclosed; maximizing and ordinary filename typing allowed the trial to proceed.
Observed: no initial destination; Enter alone did not enable Apply; search `@c` auto-focused and Enter previewed B/A/D/C despite tied geometry; Escape and explicit Cancel retained selection; scrolling kept the footer available and did not pan the canvas. Ctrl+Enter applied before-C once, retaining count two/primary A and authored coordinates. One Undo restored the exact 12,764-byte baseline; one Redo restored the exact applied source SHA-256 `f48147dbc5101d8dd0386f72ef769d8684935a410d7e60b85d420033d5243f06`. Normal close exited zero with empty process streams and unchanged immutable inputs.
Two product defects prevent treating this run as final acceptance:
- Captures 24/28 show After text clipped beneath the floating scrollbar. The later source reserves a gutter, propagates Fill widths and uses WordOrGlyph wrapping. The mounted long-alias layout evaluator passes in scenario-8; corrected-source native screenshots in run 2 confirm readable columns and a reserved scrollbar gutter.
- New Saved-order diagnostics reduced viewport height by 40px and erased the result summary through epoch equality. The revised lifetime described above preserves passive-resize/camera results while retiring substantive changes in four passing summary tests at scenario-8. Diagnostic wording now identifies aliases and explains disagreement between positions and execution order. Corrected-source native run 2 confirms persistent result summaries after real diagnostic height changes.
The original native full-file oracle also failed at byte 647: expected comma spacing differed from the writer's moved reference trivia. This was an evaluator error, not evidence of coordinate/semantic corruption. Keep its failed receipt and original expectations intact; a corrected exact oracle must be separately pinned and must continue to compare every other source byte. Do not silently normalize arbitrary differences.
## Corrected native run 2 and fresh-process run 3
Run 2 uses source `1c4099a9…` and build-2. The executable is 119,900,672 bytes, SHA-256 `123e5bebda06c8446cb86c3e071599feea318e69953a949f64b29ec3010d2717`. Independent review of original captures finds readable Before/After columns, a fixed destination/action footer, and a persistent semantic result after diagnostics resize the viewport. Actual image sizes are **1605 × 872** and **1104 × 732**. At compact size the comparison body requires scrolling; footer and result remain visible. These dimensions are capture sizes, not exact client-area claims.
The repeated-name D-then-A selection moves in semantic A/D order. Before-C is separately reachable despite B/C tied Y. Search reaches offscreen `@report_24`; a later no-match query preserves the previously explicit proposal and labeled destination. Cancellation and selected-anchor no-op preserve Redo. Exact snapshots independently confirm baseline after Undo/cancel/no-op, identical before-C after Redo, far-anchor commit, and the final before-C commit. All are 12,764 bytes, compared without normalization against separately pinned v2 expected files:
| Phase | Snapshot numbers | SHA-256 |
| --- | --- | --- |
| baseline | 29, 34 | `0ad45e5ec3768862823175d9664c0e746e2a3afbc4df367b14477dc9f8705bf7` |
| before-C | 27, 36, 76 | `f48147dbc5101d8dd0386f72ef769d8684935a410d7e60b85d420033d5243f06` |
| before report_24 | 62 | `0b1cf1bba8ba2df869d34210b611d9551821ab24fdd4fbefd29effa76167dd3e` |
Captures 64–71 confirm native keyboard entry: F6 enters the viewport; six Shift+Tab steps reach Reorder through Actual Size, Zoom In, Zoom Out, Fit and Details; Enter opens the focused query. This relatively long route and subtle viewport outline remain discoverability limitations. Earlier F6/Tab/Shift+Tab returned to the viewport and was not a blocked Reorder route. Escape cancellation is observed. Native selection remains click plus contextual Add; native Shift-click is not claimed. Captures 44–56 retain system window-sizing recovery; resize cancels the live operation under exact-epoch rules, followed by a fresh compact operation.
Run 3 starts a fresh copied process and explicitly uses run-2 snapshot 76 as its prepared initial source. Original captures 14/15 show Saved A with persisted ordinals B1/A2/D3/C4 and the expected alias-based diagnostic notices. Selection is zero in the new process, as appropriate for transient selection. Independently, the prepared initial pin, run-2 snapshot 76, run-3 snapshot 15, final working source and pinned v2 before-C expectation are all exactly equal, with SHA `f48147…3f06` above. This is saved-source persistence evidence, not persistence of transient selection or operation history.
Runs 2 and 3 both closed normally with exit 0 and empty stdout/stderr. Their complete prepared immutable inventories were independently rehashed and matched; final source and log pins match the close receipts. Separate local reviews are retained as `run-2-review.md` and `run-3-review.md` in the native evidence materials. Run 1 remains findings-only evidence, including original evaluator failure; v2 expectations do not retroactively turn it into an accepted run.
## Verification and delivery limits
The bounded increment is implemented and verified for the stated source and Windows workflows. Tests and native observations do not establish arbitrary window sizes, native temporal-refusal/fallback scenarios, screen-reader completeness, or Linux behavior. Accessibility captures expose mostly the window shell; native focus is supported by visual highlights and the observed route, with separate mounted input coverage. The real App source-write error branch still lacks a runtime failure fixture; Document atomicity evidence remains separate. Aggregate removal and broader issue-29 completeness remain separate work.
The native package retains all 535 members from three closed run attempts and two CLI preflights, including original failures, exact helpers, source proofs and original captures. Run 1 remains unaccepted with its failed source-oracle receipt; run 2/3 and matching current CLI preflight are explicitly accepted only for the bounded cases above. Omitted executable/DLL bytes retain their build/readback pins; an offline archive check cannot rehash omitted bytes. No default-branch integration or new published release is asserted by this report.
@@ -0,0 +1,42 @@
# Scenario semantic reorder: portable Windows evidence
Tested production source: `1c4099a9ef76dd28d17ef892e95edf89e860569f`, branch `codex/scenario-multiselect-9e8r6t-20260924`. The delivery descendant adds records only. [Implementation, exact gate history, native observations and limitations](../scenario-reorder-app-20260924.md); [policy](../scenario-group-reorder-policy-20260924.md). Live coordination belongs to [issue 29](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/29). This is branch evidence, not integrated/release acceptance. Linux remains user-paused.
## Offline verification
From the checkout, Python 3.11+ standard library:
```text
python -B harness/scenario-reorder-app-evidence-20260924/checks/verify.py
python -B harness/scenario-reorder-app-evidence-20260924/native/verify.py harness/scenario-reorder-app-evidence-20260924/native
```
Neither verifier executes archived code/binaries, launches a GUI or contacts a network. A consistency PASS does not turn a failed historical run into a passing test. The native verifier reports the original run-1 snapshot failure explicitly, with that attempt unaccepted.
| Archive | Bytes | SHA-256 |
| --- | ---: | --- |
| [checks/evidence.zip](checks/evidence.zip) | 29,229,448 | `80406d81e0a5d47bea2ef284bc50a079713d828e8ea291cb96cfcedfeaa16235` |
| [native/native-evidence.zip](native/native-evidence.zip) | 12,792,711 | `0686d691a6ecea80310c5ee31056de36a7389d89a41ca501e6db9427f1ba4a82` |
Checks retain 17 runs, five failures, 17 exact source proofs and nine source capsules. Final-source Scenario315/0/1, format, strict desktop all-target Clippy and Studio+CLI build pass; final inventories each contain818 inputs. Filters are scoped, not the full desktop suite. The checks README describes the generic capture format; manifest records the actual selected reorder runs.
Native retains535 members: three closed native attempts, two closed CLI preflights, every original capture/receipt, strict source snapshots, two separately pinned oracle revisions, helpers and reviews. Run1 at14df is historical findings-only; its original whitespace-oracle failure stays unchanged. Current-source run2 has78 capture records and six exact snapshots; fresh-process run3 has15 capture records and one exact reopened snapshot. Both accepted attempts exit0 with empty streams and unchanged immutables. CLI preflight3 matches their source and v2 fixture manifest. Excluded executable/DLL bytes are represented by measured build/runtime/readback pins, not bundled runnable release assets.
Inside the native ZIP, `helpers/run-2-observations.md` records parent actions and recovery; `helpers/run-2-review.md` and `helpers/run-3-review.md` independently inspect original screenshots and exact source/lifecycle bytes. `review-config.json` declares each attempt's scope, phases and reopen relationship. `runs/run-2/` and `runs/run-3/` contain originals; `oracle-revisions/oracle-v2/README.md` explains the strict corrected expectation. Use the [development review](reviews/development-review.md) for the sequence of findings/corrections, with historical pending statements interpreted at their stated source.
## Reproduce the Windows checks
Use the project's documented Windows GNU/LLVM toolchain and Rust/Cargo1.98.1 with `CARGO_BUILD_JOBS=1`, `CARGO_INCREMENTAL=0`. Original commands/environment and measured compiler/binary inputs are in receipts. At the tested commit:
```text
cargo test -p oa-desktop scenario --message-format=json -- --nocapture
cargo fmt --all -- --check
cargo clippy -p oa-desktop --all-targets --message-format=json -- -D warnings
cargo build -p oa-desktop -p oa-cli --message-format=json
```
The native launcher copies the build's Studio executable and measured `libunwind.dll` into a clean bin directory, uses a separate cwd and a Windows-system-only child PATH, and opens working.arcadia through the application File UI. It does not claim a GUI model-path command-line argument. Preparation, launch, source phase snapshots, and normal closes are captured by helpers in the archive. Required runtime SHA is `f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4`.
Native selection used contextual Add; mounted tests separately cover modifier handling. Actual capture sizes1605×872 and1104×732 do not establish all sizes or screen-reader accessibility. Runtime coverage of a real App source-write failure remains open. Aggregate removal and full issue29 acceptance are separate work. The published issue37 prerelease is unchanged.
[Final bounded audit](reviews/final-audit.md) independently repeats both offline verifiers, compares package members with original records, checks local omitted-binary pins and inspects selected original native images. It records reviewer authorship limits and makes no remote-publication claim.
@@ -0,0 +1,14 @@
# Scenario selection captured checks
These tools package explicitly named, completed runs from `CHECKOUT/.local/scenario-group-gates` without executing archived source or running Cargo. Adapted only in input-directory and manifest-kind names from the published prerelease Connection/Route evidence tools at `93d2a6f9af40061bf92cd81ba33d5648d0181cb1`.
```powershell
python -B prepare.py --root CHECKOUT --runs selection-scenario-1 selection-scenario-2 selection-format-1 --output NEW_DIRECTORY
python -B NEW_DIRECTORY/verify.py
```
The manifest is authoritative for the selected runs. Failed runs remain failures: archive consistency is not a test pass. Every raw stream and receipt retains its original bytes. Identical input maps and ZIPs are stored by hash; the logical-file map preserves their original run paths. Historical capture helpers and exact source comparators are included as data, never executed by verification.
Source proofs compare every captured input with a named Git commit; the offline package verifier checks those receipts and their pinned comparator identity but does not repeat the Git comparison. The captured HEAD and the named proof commit retain their respective meanings. The verifier checks archive inventory, hashes, input ZIP contents, process/command/result consistency and executable artifact relationships. It does not establish hermetic builds, native workflow acceptance, UI integration, or release acceptance.
Use `--check-only` instead of `--output` for an in-memory consistency check. Existing output directories refuse. Python 3.11+ standard library is sufficient; `-B` avoids bytecode writes.
@@ -0,0 +1,22 @@
{
"prepare.py": {
"bytes": 6308,
"sha256": "2d500f5d43a49893abb3936f880e61b8adc623531e26f0288983502e386894db"
},
"verify.py": {
"bytes": 11436,
"sha256": "ea8e781003bec21f2ac4af23e21b68ca5639a98eb31505c10b2869f57565e917"
},
"README.md": {
"bytes": 1641,
"sha256": "4c5c582cbdf02c8704b9add656d273c275b10eed87219131e3bba639a4c4bd8a"
},
"manifest.json": {
"bytes": 47794,
"sha256": "4044c2c4ba6985022c68ba2802bee66f0f24ee454f77fbd0db2c6eee4d936ed4"
},
"evidence.zip": {
"bytes": 29229448,
"sha256": "80406d81e0a5d47bea2ef284bc50a079713d828e8ea291cb96cfcedfeaa16235"
}
}
File diff suppressed because it is too large Load Diff
@@ -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 in (RAW_FILES, RAW_FILES | {"source-proof.json"}), "exact closed raw files required: " + run)
raw = {path.name: path.read_bytes() for path in paths}
result = parsed(raw["result.json"])
need("finish" in result and result["inputsUnchanged"] is True, "unfinished/changed run refused: " + run)
matches = [data for data in helper_bytes if pin(data) == result["helper"]]
need(bool(matches), "exact historical helper unavailable for " + run + "; supply --helper PATH")
helper = "helpers/" + result["helper"]["sha256"] + ".py"
add(helper, matches[0])
for name, data in sorted(raw.items()):
add("cargo/" + run + "/" + name, data)
specs[run] = {key: result[key] for key in ("command", "head", "exitCode", "inputCount")}
specs[run]["helper"] = helper
if "source-proof.json" in raw:
proof = parsed(raw["source-proof.json"])
matches = [data for data in comparator_bytes if pin(data) == proof["comparator"]]
need(bool(matches), "exact source comparator unavailable for " + run + "; supply --comparator PATH")
comparator = "comparators/" + proof["comparator"]["sha256"] + ".py"
add(comparator, matches[0])
specs[run]["sourceProof"] = {"commit": proof["commit"], "pin": pin(raw["source-proof.json"]), "comparator": comparator}
manifest = {"schema": 1, "kind": "scenario-selection-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,194 @@
"""Offline consistency checks only; never execute or extract archived inputs."""
from pathlib import Path, PurePosixPath
from datetime import datetime
import argparse
import hashlib
import io
import json
import math
import re
import stat
import zipfile
RAW_FILES = {"started.json", "process.json", "result.json", "stdout.log", "stderr.log", "inputs.json", "inputs.zip"}
OUTER_FILES = {"prepare.py", "verify.py", "README.md", "manifest.json", "evidence.zip"}
def need(condition, message):
if not condition:
raise ValueError(message)
def pin(data):
return {"bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()}
def valid_pin(value):
return (isinstance(value, dict) and set(value) == {"bytes", "sha256"}
and type(value["bytes"]) is int and value["bytes"] >= 0
and isinstance(value["sha256"], str)
and re.fullmatch(r"[0-9a-f]{64}", value["sha256"]) is not None)
def safe(name):
return (isinstance(name, str) and bool(name) and "\\" not in name and ":" not in name
and all(ord(char) >= 32 for char in name)
and not PurePosixPath(name).is_absolute()
and all(part not in ("", ".", "..") for part in name.split("/")))
def run_name(name):
return isinstance(name, str) and re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]*", name) is not None
def parsed(data):
def pairs(items):
result = {}
for key, value in items:
need(key not in result, "duplicate JSON key: " + key)
result[key] = value
return result
def constant(value):
raise ValueError("nonfinite JSON constant: " + value)
return json.loads(data, object_pairs_hook=pairs, parse_constant=constant)
def inventory(archive, expected):
names = archive.namelist()
need(len(names) == len(set(names)) and set(names) == set(expected), "exact ZIP membership")
for entry in archive.infolist():
need(safe(entry.filename) and not entry.is_dir(), "unsafe ZIP member: " + entry.filename)
need(not stat.S_ISLNK(entry.external_attr >> 16), "ZIP symlink: " + entry.filename)
need(valid_pin(expected[entry.filename]), "invalid member pin: " + entry.filename)
need(entry.file_size == expected[entry.filename]["bytes"], "ZIP recorded size: " + entry.filename)
def ordered_times(*values):
times = [datetime.fromisoformat(value) for value in values]
return all(value.utcoffset() is not None for value in times) and times == sorted(times)
def verify_data(manifest, read):
"""Shared read-only verifier for packaged bytes or prepare's in-memory payload."""
need(manifest["schema"] == 1 and manifest["kind"] == "scenario-selection-cargo-gates", "manifest schema")
runs, logical, stored = manifest["runs"], manifest["logicalFiles"], manifest["members"]
helpers = manifest["captureHelpers"]
need(isinstance(helpers, dict) and set(helpers) == {"gate.py", "source-proof.py"}, "capture helper names")
need(all(isinstance(name, str) and re.fullmatch(r"helpers/[0-9a-f]{64}\.py", name)
for name in helpers.values()), "capture helper mapping")
need(isinstance(runs, dict) and bool(runs) and all(run_name(run) for run in runs), "explicit run inventory")
need(all(safe(name) for name in logical) and all(safe(name) for name in stored), "unsafe manifest path")
need(set(logical.values()) == set(stored), "unreferenced or absent stored members")
for name, expected in stored.items():
need(valid_pin(expected) and pin(read(name)) == expected, "stored member hash: " + name)
expected_logical = {"cargo/" + run + "/" + name for run in runs for name in RAW_FILES}
expected_logical.update(spec["helper"] for spec in runs.values())
expected_logical.update(helpers.values())
for run, spec in runs.items():
if "sourceProof" in spec:
proof_spec = spec["sourceProof"]
need(set(proof_spec) == {"commit", "pin", "comparator"}, run + ": exact source proof spec")
need(isinstance(proof_spec["commit"], str) and re.fullmatch(r"[0-9a-f]{40}", proof_spec["commit"]), run + ": named full source commit")
need(valid_pin(proof_spec["pin"]), run + ": source proof pin")
need(isinstance(proof_spec["comparator"], str) and re.fullmatch(r"comparators/[0-9a-f]{64}\.py", proof_spec["comparator"]), run + ": comparator path")
expected_logical.update({"cargo/" + run + "/source-proof.json", proof_spec["comparator"]})
need(set(logical) == expected_logical, "exact logical raw/helper inventory")
for name, destination in logical.items():
if name.startswith("cargo/") and name.rsplit("/", 1)[1] in {"inputs.json", "inputs.zip"}:
expected = "capsules/" + stored[destination]["sha256"] + PurePosixPath(name).suffix
need(destination == expected, "input capsule mapping: " + name)
else:
need(destination == name, "only input maps/archives may be deduplicated: " + name)
def raw(name):
return read(logical[name])
for name, helper in helpers.items():
need(helper == "helpers/" + pin(raw(helper))["sha256"] + ".py", "named helper hash: " + name)
seen_capsules = set()
for run, spec in runs.items():
prefix = "cargo/" + run + "/"
start = parsed(raw(prefix + "started.json"))
process = parsed(raw(prefix + "process.json"))
result = parsed(raw(prefix + "result.json"))
required_start = {"start", "command", "cwd", "head", "scope", "inputs", "archive",
"inputCount", "environment", "helper", "cargo", "rustc"}
need(required_start <= start.keys(), run + ": incomplete start receipt")
need(all(result.get(key) == value for key, value in start.items()), run + ": start/result relationship")
command = result["command"]
need(isinstance(command, list) and command and command[0] == "cargo"
and all(isinstance(arg, str) for arg in command), run + ": Cargo command")
need(command == process["command"] == spec["command"], run + ": command relationship")
need(result["head"] == spec["head"] and re.fullmatch(r"(?:[0-9a-f]{40}|[0-9a-f]{64})", result["head"]), run + ": HEAD")
need(type(result["exitCode"]) is int and result["exitCode"] == spec["exitCode"], run + ": recorded exit")
need(result["inputsUnchanged"] is True, run + ": changed inputs refused")
need(type(result["seconds"]) in (int, float) and math.isfinite(result["seconds"])
and result["seconds"] >= 0, run + ": duration")
need(type(process["pid"]) is int and process["pid"] > 0, run + ": process identity")
need(ordered_times(start["start"], process["observed"], result["finish"]), run + ": completed timestamp order")
for field, filename in [("inputs", "inputs.json"), ("archive", "inputs.zip"), ("stdout", "stdout.log"), ("stderr", "stderr.log")]:
need(result[field] == pin(raw(prefix + filename)), run + ": " + field + " pin")
need(valid_pin(result["helper"]) and result["helper"] == pin(raw(spec["helper"])), run + ": helper pin")
need(spec["helper"] == "helpers/" + result["helper"]["sha256"] + ".py", run + ": helper mapping")
inputs = parsed(raw(prefix + "inputs.json"))
need(isinstance(inputs, dict) and all(safe(name) for name in inputs), run + ": safe input inventory")
need(type(result["inputCount"]) is int and len(inputs) == result["inputCount"] == spec["inputCount"], run + ": input counts")
if "sourceProof" in spec:
proof_spec = spec["sourceProof"]
proof_bytes = raw(prefix + "source-proof.json")
proof = parsed(proof_bytes)
need(pin(proof_bytes) == proof_spec["pin"], run + ": source proof pinned bytes")
need(proof["run"] == run and proof["commit"] == proof_spec["commit"], run + ": proof run/commit identity")
need(proof["status"] == "PASS exact captured input inventory and Git blob bytes", run + ": source proof status")
need(proof["inputCount"] == len(inputs) and proof["inputMap"] == result["inputs"], run + ": proof input relationship")
need(proof["result"] == pin(raw(prefix + "result.json")), run + ": proof result relationship")
need(ordered_times(result["finish"], proof["verified"]), run + ": proof time after closed gate")
comparator = proof_spec["comparator"]
need(valid_pin(proof["comparator"]) and pin(raw(comparator)) == proof["comparator"], run + ": comparator bytes")
need(comparator == "comparators/" + proof["comparator"]["sha256"] + ".py", run + ": comparator identity")
need(sum(name.startswith("crates/vendor/iced_widget/") for name in inputs) == 71, run + ": vendor count")
capsule = (logical[prefix + "inputs.json"], logical[prefix + "inputs.zip"])
if capsule not in seen_capsules:
with zipfile.ZipFile(io.BytesIO(raw(prefix + "inputs.zip"))) as source:
inventory(source, inputs)
for name, expected in inputs.items():
need(pin(source.read(name)) == expected, run + ": source hash " + name)
seen_capsules.add(capsule)
artifacts = []
for line in raw(prefix + "stdout.log").decode("utf-8", errors="replace").splitlines():
try:
value = json.loads(line)
except json.JSONDecodeError:
continue
if isinstance(value, dict) and value.get("reason") == "compiler-artifact" and value.get("executable"):
artifacts.append(value)
need(isinstance(result["artifacts"], list), run + ": artifact records")
need(artifacts == [record["cargo"] for record in result["artifacts"]], run + ": Cargo JSON artifact relationship")
for record in result["artifacts"]:
need(set(record) == {"cargo", "readback"}
and (record["readback"] is None or valid_pin(record["readback"])), run + ": artifact readback pin")
print(run, "recorded exit", result["exitCode"], "inputs", len(inputs), "executable records", len(artifacts))
return {"runs": len(runs), "recordedFailures": sum(spec["exitCode"] != 0 for spec in runs.values()),
"logicalFiles": len(logical), "storedMembers": len(stored), "sourceCapsulePairs": len(seen_capsules),
"captureHelpers": helpers, "sourceProofs": sum("sourceProof" in spec for spec in runs.values())}
def verify_package(root):
files = parsed((root / "files.json").read_bytes())
need(set(files) == OUTER_FILES, "outer file inventory")
for name, expected in files.items():
need(valid_pin(expected) and pin((root / name).read_bytes()) == expected, "outer hash: " + name)
manifest = parsed((root / "manifest.json").read_bytes())
with zipfile.ZipFile(root / "evidence.zip") as archive:
inventory(archive, manifest["members"])
return verify_data(manifest, archive.read)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("package", nargs="?", type=Path, default=Path(__file__).resolve().parent)
args = parser.parse_args()
print("PASS offline consistency:", verify_package(args.package))
print("Historical receipts only; no source/binary execution or native acceptance claim.")
if __name__ == "__main__":
main()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,264 @@
"""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 = 'scenario-semantic-reorder-native-evidence'
PHASES = {'baseline': 'baseline.arcadia', **{phase: f'expected-{phase}.arcadia' for phase in ('before-c', 'before-b', 'before-last')}}
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/'):
assert set(fixture['files']) == set(PHASES.values()), 'Wrong fixture inventory'
baseline = files[prefix + 'baseline.arcadia']
aliases = ['a', 'b', 'c', 'd'] + [f'report_{i:02d}' for i in range(5, 25)]
orders = {
'baseline': aliases,
'before-c': ['b', 'a', 'd', 'c'] + aliases[4:],
'before-b': ['a', 'd', 'b', 'c'] + aliases[4:],
'before-last': ['b', 'c'] + aliases[4:-1] + ['a', 'd', 'report_24'],
}
clause = lambda ids: ('steps [' + ', '.join('@' + alias for alias in ids) + '];').encode()
revision = fixture.get('fixture_revision', 'oracle-v1-canonical-spacing')
assert revision in ('oracle-v1-canonical-spacing', 'oracle-v2-trivia-chunks'), 'Unknown fixture revision'
if revision == 'oracle-v2-trivia-chunks':
# Baseline A owns no prefix; each other item owns one leading space.
# These exact chunks move with identity in source_project.rs:1581-1632.
result_clause = lambda ids: ('steps [' + ','.join(('' if alias == 'a' else ' ') + '@' + alias for alias in ids) + '];').encode()
else:
result_clause = clause
assert baseline.count(clause(aliases)) == 1 and len(re.findall(rb'\bsteps\s*\[', baseline)) == 1
assert baseline.count(b'oa_occurrence ') == baseline.count(b'"Repeated report awaiting engineering review"') == 24
assert fixture['orders'] == orders, 'Wrong declared semantic oracles'
for phase, name in PHASES.items():
data = files[prefix + name]
assert pin(data) == fixture['files'][name], 'Fixture pin mismatch: ' + name
assert data == baseline.replace(clause(aliases), result_clause(orders[phase])), 'Oracle changes more than literal expected steps: ' + name
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'))
config = js('review-config.json')
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'
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', 'oracle-v1-canonical-spacing')
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 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', 'oracle-v1-canonical-spacing')
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 (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',
'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,139 @@
# Scenario reorder App and UX policy review
Bounded independent critique on the parent's identified `a16e0140` base in `C:/ar-scenario-9e8r6t`. No production edits, Cargo, native actions or Gitea. Initial policy review precedes the writers' source handoff. A working exact destination chooser is a candidate interaction, not full acceptance of the user's graphical editing and low-cognitive-load requirements.
## Initial concrete challenges
1. **Bind Apply to the proposal actually displayed.** Context, selection Snapshot and operation token remain identical while a destination changes. A queued Apply for Ready destination A must not commit subsequently chosen Fallback destination B under the same token. Capture exact Slot or proposal generation in Finish, check it before taking/retiring the session, and bind warning acknowledgement to that same proposal. An explicit Apply button can serve as acknowledgement without adding a modal, provided its packet approves the displayed exact destination/status. Verify A-Apply/B-Choose/replayed-A and destination ABA. The existing context/session freshness checks alone do not establish this invariant.
2. **Resolve existing fallback copy.** `behavior/scenario/workspace.rs` currently says canvas insertion and reordering are unavailable until saved positions are repaired. Baseline Fallback semantic reorder would make that blanket statement misleading. Distinguish coordinate input from explicit sequence reorder. The proposal warning must explain that the requested saved view stays selected and authored coordinates survive, while the actual drawing uses automatic geometry. Do not imply that committing repairs those coordinates or leaves the visible drawing unchanged.
3. **Retain the exact set across candidate geometry and commit reconciliation.** Baseline actual-scene visibility is necessary, but final selection is also constrained by actual candidate presentation. If a successful candidate can make an original member latent/unrendered, silently pruning it after commit conflicts with the promised full-set/primary preservation. Either establish that this cannot occur for admitted reorder targets in supported Ready/Fallback candidates, or reject/explain that candidate before effects. This is an invariant to verify, not a demonstrated present defect.
## Proportionate policy assessment
Allowing a semantically valid whole set from a visible Fallback baseline is coherent for exact semantic input: the chooser does not infer destinations from unusable saved coordinates. Candidate Fallback can be an explicit supported outcome when preview and commit show the same requested view and clear automatic-geometry consequences, with model/source preservation and Undo. Candidate Unavailable refusal is a defensible bounded initial policy because no usable resulting diagram can be previewed. The App must enforce these rules independently of button disabling; session Completion is not commit permission.
No destination should exist initially. Search/paging must leave the chosen exact Slot clearly identified and never substitute a row index after filtering. A destination selected on another page must remain named next to Apply; selected anchors remain explicit no-change choices, and temporal failures remain discoverable choices with reasons. Before/after order should emphasize the changed block and its neighbors without expanding into long unstructured lists. Repeated long names need visible position/alias disambiguation at ordinary and compact sizes. These requirements still need actual native evidence; tests cannot accept the chooser by themselves.
## Adapter source handoff review
Reviewed the initial frozen `app/scenario_reorder.rs` and its six tests. Exact `Finish(Slot)` now checks the current preview before taking the session or advancing any lifetime, addressing the queued-Apply/different-destination problem. Same-Slot return within the frozen immutable Project is the same semantic proposal/status; a distinct proposal generation is not required merely to distinguish identical results. The source checks the complete current Context/Snapshot and session match before query/page/status changes, consumes current terminal attempts once, and executes through Document only after policy checks.
The six tests use actual App messages and independently authored complete Project/source/history outcomes. They check changed commit across Saved/Derived, one-step exact Undo/Redo, stale packets against a newer session, different-slot queued Apply, no-op preservation of Redo, generation-only primary ABA, busy cancellation, temporal refusal retirement and a source-size-limit failure intended to exercise real source-write atomicity. The source-limit fixture's formatting assumption requires the pending runtime gate; this review does not presume it passes.
Additional concrete integration/UX findings sent to the parent while wiring was still being written:
- Early Scenario spacing dispatch returns before ordinary reorder reconciliation. Without an explicit owner rule in that path, a fresh body drag can start spacing while an old chooser remains active. The eventual fix must leave stale packets inert and avoid advancing an epoch after capturing the new spacing session, which would invalidate it immediately. Current selection changes already cancel reorder explicitly.
- Clearing the proposal after a successful commit and showing only generic “Semantic order updated” is insufficient observable success when preserved saved geometry remains visually unchanged. Retain a bounded result summary naming exact sequence/destination/result neighborhood, with Undo. Bind the summary to document/revision/view so later navigation or Undo does not present old order as current.
- The six initial adapter tests do not constrain the new allowed-Fallback or blocked-Unavailable/hidden-selection policy branches. Add actual Fallback admission/commit coverage and direct guard coverage before claiming that policy verified; synthetic Unavailable/hidden candidate injection may test guard behavior if explicitly distinguished from a real geometry transition.
The parent is addressing final wiring/UI and additional coverage. No final App/UX acceptance or passing runtime result is claimed at this handoff stage.
## First UI source findings (before compile checkpoint)
**Material input interference:** the chooser overlay is currently a child of `canvas_workspace::Viewport`. That wrapper handles wheel and Space/Tab/arrows/Escape before forwarding events to children (`canvas_workspace/viewport.rs:258-350`). Clicking the search field gives the viewport focus; a subsequent space can publish `CancelGesture`, arrows can pan, wheel can move the canvas instead of scrolling the chooser, and captured Escape can publish camera Leave instead of the advertised chooser cancel. `opaque(card)` only handles child routing and cannot prevent this parent pre-handler. Move the chooser outside the Viewport/sensor or implement explicit child-first ownership, preserving the raw canvas widget tree. Verify mounted typing with spaces/arrows, chooser scroll and Escape; App message tests do not cover this widget-routing defect.
Additional UI findings sent to the parent:
- `reorder_view::panel` searches the displayed title after `short(name, 38)`. A distinctive full-name suffix is absent from that title, so searching by that suffix falsely reports no destination. Search full model names/aliases/position independently of display truncation.
- The selected destination and Fallback warning are in the scrolling body while Apply is fixed below it. With a long order comparison they can be outside the viewport when Apply is enabled. Keep the exact chosen destination and relevant policy warning adjacent to Apply in a fixed footer, so explicit Apply approves a visible consequence.
- `workspace` computes chooser-aware `coordinate_input` but assigns `scene.coordinate_input` directly from capabilities. A singleton Derived body/handle can still begin a legacy coordinate reorder under the chooser. Use the chooser-aware permission for the actual scene; deliberate selection changes may remain available to cancel the operation.
- The new context-bound summary improves persistence but initially names only count/destination/sequence. Include a bounded resulting semantic neighborhood/block in semantic order (for example B -> [A,C] -> D); count-only feedback does not resolve the select-C-then-A versus semantic-A/C question after the preview disappears.
- Context-menu reorder is currently always disabled because its Begin eligibility transitively rejects an open model menu. The header entry remains available. This may be an explicit bounded limitation, but do not claim contextual access or display a misleading dead action without explanation.
These findings are static observations of current code during concurrent implementation, not final findings against a frozen compiled source. They require reinspection after the parent's changes. No native workflow has been accepted.
## Reinspection of the revised adapter/UI
The parent addressed the concrete findings above. The chooser is now an outer sibling layer above the sensor/Viewport rather than its child, with underlying canvas keyboard and coordinate authoring disabled while the session owns input. The normal canvas tree remains stable. The early spacing handler is inert during reorder, and real selection changes explicitly cancel it. Full model names/aliases are searched independently of truncated display labels. Exact chosen destination and policy feedback now occupy a fixed footer beside Apply. The fallback notice distinguishes coordinate editing from explicit semantic reorder; the context menu honestly directs users to the header entry instead of presenting an unusable action.
The persistent result is tied to the current Scenario Context and cleared on stale context or a new operation. It now derives a compact neighborhood from actual committed sequence order, with positions, up to three selected names, an explicit omitted-member count and immediate neighbors. It therefore no longer repeats click order or merely reports a count. The original full selection remains available, and the UI points to Undo without adding another approval step.
The additional real baseline-Fallback test authors reversed saved call/reply coordinates, asserts actual Fallback, commits the semantic operation and retains the requested Saved identity, complete selected set and authored Project records. The Unavailable and hidden-selection tests deliberately inject preview outcomes to exercise App refusal/terminal atomicity. Their comments correctly avoid claiming natural geometry transitions. No Ready-to-Unavailable transition is inferred from synthetic guard coverage.
**No new blocking static issue found in this revised adapter/UI source.** The resolved wrapper defect still requires the planned mounted input regression and native exercise. Actual compact footer layout with long aliases, search/scroll focus, destination reachability, repeated names, intermediate feedback, and keyboard activation/discoverability remain empirical questions. The chooser is a concrete candidate implementation, not acceptance of the entire requested graphical authoring workflow. Pending compilation/test/native results are not assumed by this review.
## Frozen source and evaluator review at f3ed6e97
The parent froze `f3ed6e97dd3caf06046711cf74d268c7274bc780` for the next gate. Reinspected the final source and nine App test functions. Destination-title construction now enumerates positions once, preserving full-name/alias search without a repeated linear position lookup per row. Result neighborhoods use actual semantic positions and aliases, distinguishing repeated display names; final display sizing still needs native inspection.
The new mounted evaluator constructs the real `app.view()` through the installed Iced UserInterface and headless WGPU renderer, settles layout, finds the actual identified query widget and clicks/focuses it. It injects raw Space and requires an emitted `ScenarioReorder(Query(" "))`, then checks actual query state. It injects arrow and wheel events while requiring the camera and live session token remain unchanged. Finally it injects raw Escape and requires the root bridge's captured `ScenarioReorder(Cancel)` before checking exact model/source, selected targets/primary and no history. This meaningfully detects the earlier parent-Viewport pre-handler defect; it is not merely direct App message dispatch. The new root escape capture remains within the existing wrapper, preserving widget state and overlay precedence.
Evaluator limits: arrow checks establish noninterference, not precise caret motion; the wheel check establishes no camera/session disturbance, not successful scrolling through overflowing destinations. The short mounted fixture does not establish twenty-sibling navigation, compact footer clipping, keyboard traversal/activation, or native accessibility. Those remain explicit follow-up observations, not reasons to mislabel this mounted regression as comprehensive UX acceptance.
Read the preserved first gate: `reorder-app-test-1` at `61099ed4742eaa51c3bd81129bc072d8321961b7` closed exit 101 with all 817 inputs unchanged and no executable records. Its raw Cargo stream contains six compile errors: five E0659 ambiguous `column` uses and one E0603 private test-helper `occurrence` import. No tests executed in that failed attempt. It must remain a compilation failure, not be relabelled by subsequent source corrections. The second gate at f3ed6e97 was running at this review point.
**Scoped final source assessment: no unresolved material static defect found after the recorded fixes.** Runtime/native results are pending. This finding accepts the source for its bounded verification step, not the chooser's complete user experience or issue #29 completion.
## First corrected-source execution: filter limitation
Independently read `reorder-app-test-2` at f3ed6e97: exit 0, 817 unchanged inputs, **23 passed / 0 failed / 0 ignored / 1,581 filtered**. Raw stream/map/archive hashes and source-proof/result bindings agree. Exactly one new App test ran: `real_baseline_fallback_allows_explicit_semantic_reorder_and_retains_saved_view`. The `reorder_` name filter matches the earlier session/slot tests, but not the module name `scenario_reorder::` itself; the remaining eight new App tests were filtered out. This result therefore does not verify all nine App tests or the mounted evaluator. The parent detected that coverage gap and started the broader `scenario` filter at the same frozen source; its result is pending.
## Broader gate exposes fixture failures
Read the closed `reorder-app-scenario-1` output at f3ed6e97: **301 passed, 6 failed, 1 ignored, 1,296 filtered**. Its source proof records exact comparison of all 817 captured inputs with that source. The mounted query test, real Fallback case and synthetic presentation guards passed. Five failures panic in shared Derived setup at `scenario_context().unwrap()` before the intended operation; the fixture selected the owner without entering the Behavior page. The sixth expected a source-budget failure, but its observed status is successful semantic update: the current fixture did not actually force source growth/refusal. These failures are retained and must not be described as an all-green adapter gate. Correcting setup and constructing a real source-write refusal remain necessary; the current evidence does not yet establish all nine App tests pass.
## Review of the six failed-test corrections
Independently inspected the source writer's `SyntaxUpdate::list` (`oa-core/src/source_project.rs:1516-1655`). A same-parent permutation maps each existing reference chunk once, preserves its prefix/suffix trivia and uses the same comma count. It does not necessarily rewrite the compact list into longer canonical spacing. The previous budget-failure expectation was false for this operation.
The corrected test now requires successful permutation at the exact existing source-byte budget, an independently specified complete Project, retained target order/primary/camera, and exact original model/source after Undo; dirty Properties must still reject Begin. The five Derived setup failures are repaired by entering `Page::Behavior` before capturing a Scenario context. Neither correction changes production code or hides a demonstrated production defect. The attempted error-injection test is not silently repurposed as error-branch evidence: a real App `Document::execute` failure during this semantic permutation remains an explicit runtime coverage gap. Static inspection still shows the error branch changes only status after retiring the operation; model/source/history atomicity relies on Document's separate contract and tests. A new gate is required for the corrected evaluators.
## Keyboard workflow gap and proposed correction
The parent inspected installed Iced buttons and found ordinary chooser buttons do not provide Tab/KeyPressed activation. Existing tests establish search input and Escape, not a complete keyboard reorder workflow. This is a real remaining interaction gap, not a passing-test acceptance inference.
Recommended bounded path: reuse the established keyboard-aware Control for the header entry, focus the query after admitted Begin, let plain Enter preview only a unique exact filtered destination, and use an explicitly labelled **Ctrl+Enter** to Apply the displayed eligible proposal. Ctrl+Enter must capture its exact Slot, reject repeats, and be inert without an eligible proposal. Plain Enter must never commit. Rejected the proposed 'Enter again applies' phase switch: key repeat or queued Enter events can make a newly chosen warning-bearing proposal execute before its consequence has been displayed. A distinct Apply shortcut is easier to state and verify without adding another mode or modal. Actual F6/Tab entry, typing, Enter preview, Ctrl+Enter Apply and Escape still require mounted/native verification once implemented; no implementation result is assumed here.
## Corrected Scenario gate and subsequent keyboard source review
Independently audited closed `reorder-app-scenario-2` at `c9f6a3da40e288e9f993d9cacf516142c0017cf3`: **307 named passes, 0 failures, 1 ignored, 1,296 filtered**, including all nine new App tests. Exit 0, all 817 captured inputs unchanged, raw stdout/stderr/map/archive hashes and source-proof/result bindings agree. This establishes the corrected tests, including actual mounted query ownership, at that source. It does not include the subsequent keyboard workflow changes.
The next keyboard code uses a token-specific query widget ID and focus task, the existing keyboard-aware header Control, plain Enter for a unique exact destination preview, and Ctrl+Enter for captured exact-Slot Apply. Repeated Ctrl+Enter is ignored, and an invalid active Ctrl+Enter is captured rather than falling through to query submission. Those choices address the earlier phase-switch concern.
One additional source finding was sent before the keyboard gate: the new root Ctrl+Enter handler precedes current-overlay preflight. A picker opened within the same Iced batch can be widget-local before any App context changes, leaving the cached Apply action live behind that picker. Give current overlays precedence for Ctrl+Enter as already done for Escape, or consume it without Apply while an overlay exists. Verify picker-open plus Ctrl+Enter in the same batch; an App-modal predicate alone does not prove this case. Keyboard/native acceptance remains pending that revision and its tests.
## Additional keyboard lifetime finding
The parent raised a stale focus-task concern, confirmed independently against installed `iced_core-0.14.0/src/widget/operation/focusable.rs:29-49`: the generic target-focus operation unfocuses every nonmatching focusable even when its target ID is absent. Token-specific IDs prevent focusing a newer query, but do not prevent an old task from blurring it. The initial evaluator runs the old focus task before focusing the current query, so it does not detect this disturbance.
Required correction: a read-only target-existence/owner check before chaining any focus-mutating operation; no matching current target must mean no focus changes. Verify by focusing the newer query first, replaying the old task, and requiring that current focus and actual typing remain intact. This is a concrete lifetime defect in the initial generic-focus implementation, separate from proposal/model freshness. The root Ctrl+Enter overlay-preflight correction was re-read and is sound; its current overlay gets precedence and cannot fall through to cached Apply.
## Keyboard lifetime and overlay corrections rechecked
Re-read the final guarded `reorder_view::focus_query`: its first operation only discovers the exact token-specific focusable; only a present target chains the focus mutation. An absent old token therefore leaves the newer query's focus unchanged. The strengthened mounted evaluator first focuses the current query, then replays the older task, requires current focus to remain, and sends a raw `x` key that must publish and apply `Query("x")`. This directly addresses the previously missing ordering and observable typing behavior.
The root bridge now offers Escape to the current overlay first; if no overlay captures it, an active reorder emits the captured, context-bound Cancel and captures the event regardless of underlying child handling. This closes the ignored-child/global-subscription gap after a picker has closed. Ctrl+Enter still gives the current overlay precedence before the cached exact-Slot Apply. No additional material static defect found in this bounded revision. These changes and new evaluators await their own execution gate; the earlier c9f6a3da result remains evidence for its earlier source only. Native keyboard and full chooser usability remain unaccepted here.
## Executed keyboard gate independently audited
Closed `reorder-app-scenario-5` at `04485e001798430fb1b2e8d1347e6bde51e6e7a1` records exit 0 and **310 passed / 0 failed / 1 ignored / 1,296 filtered**. Independently counted all 310 named passes and all 12 App adapter tests, including the keyboard preview/Apply sequence, same-batch arrangement picker ownership, and old focus task replay after current focus with actual typing. Raw stdout/stderr, input map/archive and source-proof result/map hashes match. All 817 archive members match their inventory pins; independently read all 817 corresponding Git blobs at that exact commit and verified their sizes/SHA-256 against the captured inventory. The receipt records unchanged inputs.
This accepts bounded runtime evidence for the exact keyboard, envelope, selection, source/history and presentation cases those tests exercise. It does not establish native focus behavior, visual layout, long-list usability, or complete chooser UX acceptance. The real App source-write failure branch remains the earlier disclosed runtime fixture gap. Strict Clippy was still in progress at this review checkpoint.
The proposed replacement of local `short_label` with existing `crate::views::short(..., 24)` is appropriate for display-only owner labels: it avoids splitting grapheme clusters and removes duplicate truncation logic. Its intentional display differences are whitespace normalization and counting the ellipsis within the limit (rather than appending it after 24 Unicode scalars). Full identity and semantic destination remain independently captured; search uses full strings elsewhere. Any such later edit requires its own source attribution and suitable verification, and is not silently included in the 04485e00 test result above.
## Final helper-only source and repeated gate
Independently compared `04485e001798430fb1b2e8d1347e6bde51e6e7a1` with `14df924b98d74144c1e40fbe7098994ff5eb2e94`: the entire commit difference is the previously reviewed `short_label` body delegating to `crate::views::short(value, 24)` (one file, one insertion, six deletions). No session, input, policy or test changes accompany it.
At final source `14df924b98d74144c1e40fbe7098994ff5eb2e94`, independently audited `reorder-app-scenario-6`: **310 named passes / 0 failed / 1 ignored / 1,296 filtered**, including all 12 App adapter tests; and `reorder-app-format-1`: `cargo fmt --all -- --check`, exit 0. Both receipts record 817 unchanged inputs and exact source proofs. Verified their raw stream/map/archive/result pins and every archived member. The inventories differ from the previously independently Git-checked 04485e00 inventory only at the adapter file; that changed entry independently matches its exact 14df924b Git blob. Thus the final helper-only source has its own repeated runtime evidence rather than relying only on predecessor tests. No material issue found. Final strict Clippy/build and native visual/interaction acceptance remain pending at this checkpoint.
## Native preview clipping finding (14df924b, run 1)
Inspected the actual 1605×872 capture `.local/scenario-reorder-app-native/run-1/24-preview-c-1.jpg` (the supplied PNG spelling was resolved to the retained JPG). The chooser's After text is occluded at the right edge, and the input and destination button crowd the same scrollbar. The intended after-order B, A, D, C can still be recovered from the wrapped aliases, but this is a real preview readability defect; passing mounted input tests did not detect it. The fixed destination/warning/Apply footer remains visible in this capture.
Concrete cause: `reorder_view.rs` uses `scrollable(body).height(Fill)` around two Fill comparison columns. Installed `iced_widget-0.14.2/src/scrollable.rs` defaults to a floating 10-pixel scrollbar over content. Its documented `.spacing(...)` method embeds the scrollbar and reserves its width plus spacing in layout. Recommend embedding it with a modest gap (for example `.width(Fill).spacing(8)`), keeping the body/comparison/text constrained to available width and retaining wrapping for long names/aliases. Horizontal scrolling would add unnecessary friction here. Recheck the same repeated-name preview and both columns at native size after the narrow fix; explicit Fill constraints alone do not establish that the scrollbar no longer covers text. No production file was edited by this reviewer. The parent continues this old-source trial for functional evidence, not final layout acceptance.
## Native result-summary lifetime fix (implementation handoff)
The parent observed the post-Apply summary disappear when Saved spacing diagnostics changed viewport height. Source tracing confirms the accepted `CanvasEvent::Viewport` handler increments `canvas_epoch`; the old summary reconciler compared the whole Context and incorrectly treated that passive resize as loss of the completed result.
At the parent's explicit request this reviewer implemented the bounded correction in `app/scenario_reorder.rs` plus new `app/scenario_reorder/summary_tests.rs` (no other production/test files). A completed summary now ignores only input epoch, while preserving document-instance, Scenario owner, representation, visit and document revision matching. It additionally captures the post-commit full selection Snapshot and requires the same generation, targets and primary; selection ABA cannot masquerade as a camera-only change. New Begin/cancel clears both summary and capture. Live operation/event admission remains exact and unchanged.
Three new regressions drive a real 40-pixel viewport reduction followed by Camera Pan and exact-source Undo; real Saved-to-Derived navigation, selection collapse and new Begin/Cancel; and primary-change/restore ABA. Only the owned files were formatted with standalone rustfmt and `skip_children=true`. No Cargo, native or Git operation was run for this implementation; execution and native confirmation await the parent. This paragraph records an implementation handoff, not an independent review of this reviewer's own fix.
## Summary test compile correction and spacing terminal integration
The parent reported the first correction gate at `20109779` closed with E0425: this reviewer's new fixture referred to `oa_core::SourceBundle`, which is not a root export. Corrected the return type to `oa_core::source_project::SourceBundle`; this is a test compile repair, not a passing execution claim.
A separate early-return integration gap was identified: admitted spacing Finish bypasses App's common reconciliation. Added `scenario_reorder_reconcile()` immediately after its existing terminal `reconcile_multiselect()`, leaving all stale-envelope and session early rejections untouched. A fourth bounded summary test reuses the successful-reorder fixture and existing real spacing packet helper, sends Begin/Move/Finish, requires an actual spacing source edit with unchanged semantic order/selection, observes immediate summary retirement before another event, and verifies exact reordered source after Undo. The two authorized files were formatted and frozen for parent execution; no Cargo/Git/native action was run by this reviewer.
@@ -0,0 +1,49 @@
# Scenario semantic reorder — final bounded delivery audit
Source under review: `1c4099a9ef76dd28d17ef892e95edf89e860569f`. Reviewed the checks/native packages, final report, policy successor and root evidence index. No Cargo, Git, network, native application or GUI action was run in this audit. Only this local review file was written.
**Result: no material unresolved packaging, source-attribution, report-consistency or reviewed layout finding.** This is bounded Windows branch evidence, not default-branch integration, release acceptance or full issue-29 completion. Issue 37 remains outside this increment.
## Independence
I independently reviewed the chooser layout correction, diagnostic copy, evidence packaging and claims. I previously authored the summary lifetime fix, its tests and the spacing-terminal reconciliation addition; this audit must not be presented as an independent-author review of those changes. I did independently inspect their captured execution results and native output. Earlier development findings and failed attempts remain in the development review and packages.
## Checks package
Ran the standalone `checks/verify.py` using Python with `-B`: PASS, **17 runs, five recorded failures, 139 logical files, 123 stored members, nine source capsule pairs and 17 source proofs**. Verified all **136** logical Cargo-run files against the original `.local/scenario-group-gates` bytes. The three remaining logical records are packaged helpers/comparator data. Failed history is preserved: test-1 and scenario-1/3/4/7 remain failed, including the bad SourceBundle test path I introduced and subsequently corrected.
Archive: **29,229,448 bytes**, SHA-256 `80406d81e0a5d47bea2ef284bc50a079713d828e8ea291cb96cfcedfeaa16235`.
Final-source scenario-8 records **315 named passes, zero failures, one ignored, 1,296 filtered**, including all **17** App reorder tests (13 adapter/keyboard/layout and four summary-lifetime tests). Final clippy-3, format-2 and build-2 record exit 0, unchanged inputs and matching exact-source proof receipts at 1c4099a9; each inventory has **818** inputs. Commands match the report: Scenario-filter desktop tests, all-target desktop strict Clippy, all-project format check and desktop/CLI build. This is not the full desktop test suite.
The package verifier validates input archives and proof/receipt bindings, not Git itself. Under this audit's no-Git constraint I did not independently repeat the final commit's blob comparison. Earlier review independently compared the predecessor's Git inputs; this audit compared the captured 14df924b and 1c4099a9 source capsules and final proof identities.
## Final source changes
The two captured source inventories differ at exactly six paths: `app/scenario_reorder.rs`, its new `summary_tests.rs`, its existing `tests.rs`, `app/scenario_spacing.rs`, `behavior/scenario/reorder_view.rs` and `behavior/scenario/workspace.rs`.
Independent layout review confirms an embedded scrollbar gutter (`spacing(8)`), explicit available-width constraints and WordOrGlyph wrapping for long aliases. The mounted regression exercises repeated long unbroken aliases, equal allocated columns, right-edge clearance, query containment and multiline height at two scroll offsets. It does not alone establish native readability; the screenshots below supply that separate evidence. The diagnostic copy now states that authored positions disagree with execution order and identifies aliases, avoiding the former misleading claim that semantic order remained unchanged after Apply.
The remaining delta comprises the disclosed summary lifetime/cancel feedback, four summary tests, corrected SourceBundle module path and spacing-terminal reconciliation. Their live event/session exact-envelope checks were not relaxed. Because I authored these, their source assessment here is a scope/accounting statement, not an independent review claim.
## Native package and fidelity
Ran `native/verify.py native-directory`: PASS for its offline archive/source/receipt checks. It reports run-1 as **unaccepted**, with the original snapshot/oracle failure, and runs 2/3 as accepted with passing checks. Accepted flags come from the explicit review configuration; verifier success does not manufacture usability acceptance.
Archive: **12,792,711 bytes**, SHA-256 `0686d691a6ecea80310c5ee31056de36a7389d89a41ca501e6db9427f1ba4a82`, **535 members**. Compared all **534 original-derived members** byte-for-byte against local retained files; the remaining member is generated `review-config.json`, whose contents the verifier checks against manifest declarations. Independently rehashed all **10 omitted executable/DLL entries** against their local retained bytes and manifest pins. These omitted binaries remain unavailable to an offline recipient; the archive does not claim to be a runnable release.
The verifier checks closed process identities, build-result/source-proof/input-map relationships, captured executable/runtime pins, immutable inventories, captured image references and timestamps, exact source sidecars and separately pinned oracle revisions. The v2 oracle restricts the complete-file difference to the literal expected permutation of existing reference chunks, preserving their whitespace trivia; it does not normalize arbitrary source differences. The v1 failure is not relabeled.
Runs 2/3 closed normally at `2026-09-25T01:12:35.077492+00:00` and `2026-09-25T01:15:48.854403+00:00`, with exit 0 and independently empty stdout/stderr. Final-source Studio pin is 119,900,672 bytes, SHA-256 `123e5bebda06c8446cb86c3e071599feea318e69953a949f64b29ec3010d2717`. The captured CLI preflight belongs to the same source and v2 fixture. Run-2 snapshot 76, run-3 snapshot 15, run-3 final source and v2 before-C expectation are exactly equal: **12,764 bytes**, SHA-256 `f48147dbc5101d8dd0386f72ef769d8684935a410d7e60b85d420033d5243f06`.
## Bounded visual and report review
Inspected original run-2 captures 25/26 (1605×872), 60/75 (1104×732), and run-3 capture 15 (1605×872). Before/After text now wraps before the scrollbar with a visible gutter. The compact body needs scrolling; destination and Apply/Cancel remain visible. The committed summary remains visible after the alias-based Saved-order diagnostics increase header height, at ordinary and compact sizes. The fresh-process capture shows the persisted semantic ordinals and zero transient selection. No new material visual issue found in these specific captures.
Read the final report, policy and root index after the native archive pin was filled. Their source versions, test counts, failure list, package pins, corrected-versus-historical native runs and source persistence claims agree with the inspected evidence. The development review's older pending statements are explicitly historical. Both documented verifier commands work when invoked as shown in the root index.
Limitations remain explicit: no native Shift-click claim (selection used contextual Add), no native source-write-failure/temporal-refusal/fallback coverage claim, no arbitrary-window-size or complete screen-reader acceptance, no Linux execution, and no release/default-branch integration assertion. The lengthy F6/reverse-Tab keyboard entry route remains a discoverability limitation. The real App source-write failure branch is still a runtime fixture gap. No broad acceptance is inferred from the package consistency PASS.
This review file is stable for the parent's delivery copy. Publication and remote availability were not performed or verified here.
Delivery-note attribution: the parent reports its first staged-byte check found LF normalization differences in three external text records (report, native manifest, development review), normalized those records, and then passed all 13 staged-file byte checks. ZIP/raw members and archive hashes were unchanged. I did not run Git or independently inspect the index; this is a reported packaging correction, not a product change or a staged-byte verification claim by this reviewer.