8.9 KiB
Scenario semantic destination reachability experiment
2026-09-24; production base 53817298 plus parent-owned test-only session and this test module, tested together at cae7a22297. Only crates/oa-desktop/src/behavior/scenario/reorder_slot_experiments.rs and this local note are owned by this subagent. No production input change, Cargo, GUI or publication performed by this subagent. Parent ran the captured test gate; executed findings and independently inspected records are appended below. The four tests remain frozen without fixture correction.
Question, method and literal expectations
Does the existing nearest-Y picker give every exact same-parent semantic destination a usable pointer target when Saved geometry differs from semantic order? The test module uses actual presentation::present, Scene::slot_at, group_reorder::Prepared and core command execution. Every fixture must be core error-free and actual requested Saved presentation Ready. Four independent asynchronous messages have semantic order [A,B,C,D]. Expected candidate Projects are constructed by changing only the literal parent step vector in a clone, then compared in full; format/parse is also checked. The fixture is deliberately uncomplicated: it isolates destination identity, not lifecycle admission or user comprehension.
| Case | Authored send Y | Literal expectation |
|---|---|---|
| Crossed | 200,500,300,400 | Before-slot Y 158,458,258,358; physical order A,C,D,B; each exact anchor still reachable at its own Y. C-then-A selection before D gives [B,A,C,D]. |
| Equal | 200,300,300,500 | B/C share slot Y258. B precedes C in the slot vector and wins every tie. Exact chooser before C gives [B,A,D,C] for D-then-A selection; nearest at Y258 chooses before B and gives [A,D,B,C]. |
| Close | 200,300,300.125,300.25 | C slot258.125 is continuously reachable, but its open nearest-Y interval (258.0625,258.1875) contains no integer pixel at scale1/pan0. |
| Offscreen | 200,300,400,2000 | D slot1958 is reachable there; its boundary against C is Y1158, outside a fixed world viewport Y0..600. Exact chooser before D remains valid. |
The equal case has a mathematical identity argument in addition to a sampled execution check: two slots with equal Y have equal distance for every finite pointer Y, and Iterator::min_by keeps the earlier equal minimum. Sampling is not represented as exhaustive proof. Close and offscreen cases are deliberately weaker: there is no claim that Windows quantizes all input to integer pixels, or that a destination remains offscreen after pan/zoom. A fixed-camera handle with camera-change cancellation cannot silently rely on pan to make that case work.
Source anchors: behavior.rs:1621-1632 seeds before-slots at each resolved anchor Y minus42; behavior.rs:1855-1860 minimizes distance before filtering parent, ignores X, and has no tie disambiguator; behavior.rs:2179-2180 maps screen coordinates using pan/scale. The same-parent root fixture intentionally avoids wrong-parent nearest-slot filtering. Existing policy still requires the drag to expose that refusal instead of searching farther.
Design implication, conditional on the gate
An unchanged nearest-Y handle cannot establish equivalent destination coverage to an exact Slot chooser if the equal case passes its actual Ready assertion. A better hover label does not create C's missing hit region. Candidate remedies are a temporary semantic-order destination strip, an explicit tie chooser, or keyboard cycling through exact slots. Each adds a nonspatial identity mechanism; do not pretend a source-order tie-break alone makes both tied anchors reachable. Crossed coordinates alone do not falsify the handle: they test user comprehension. Close coordinates establish target-size sensitivity, not total continuous unreachability. Offscreen coordinates establish the need for a deliberate camera or alternate destination policy.
Minimal shared operation boundary
The parent-owned scenario/reorder_session.rs is consistent with the useful minimum: immutable Arc<Project>, exact full Scenario Context, complete Snapshot, fresh nonnil operation token; one admitted Prepared; no initially chosen destination; a single cached current Preview{slot,before,after,outcome,presentation,private command}; consuming finish returns the cached command plus selection/requested representation. Do not store a scene for every sibling or every pointer sample. Do not add a global gesture abstraction for this experiment.
Both inputs should feed the same exact preview(Slot). The chooser supplies identity directly. A drag first resolves the actual global nearest displayed slot, then submits that exact identity to the planner; None from parent filtering is refusal, never a redirect to the closest legal slot. Repeated current Slot should reuse the candidate. Candidate Ready, Fallback and Unavailable remain separate from semantic Change/Noop/Refused, and requested representation stays Saved even when actual display falls back. Baseline fallback admission is a separate decision: a chooser may use identities visible in the fallback scene, but coordinate input cannot gain permission just because the semantic planner is valid.
The pure session cannot own the whole input lifetime. The App must compare full context/snapshot/token before taking or mutating the active session. Cancel matches the current token; old Cancel must not discard a newer operation. Every admitted terminal event, including no-op, refusal, failed begin and failed source commit, retires the operation generation so a replayed Begin cannot reopen it on an identical selection. A pointer adapter additionally freezes camera/bounds and defines threshold/outside release/out-and-back; a stationary press/release on a fixed handle must not accidentally select its incidental nearest slot. A chooser can permit passive scrolling only if exact destination identity is stable. Source/Properties dirty state, draft insertion, menu capture, ownership and document-instance/representation-visit ABA admission remain App responsibilities.
No universal commit policy for candidate Fallback/Unavailable is inferred from a returned valid command. The prototype must show that status and make the product decision explicit before enabling a user path. No GUI/accessibility/comprehension claim follows from these source-level tests. Existing selected body/header group spacing retains its meaning, aggregate removal remains separate, and issue29 is incomplete.
Executed findings and negative design decision
Read back .local/scenario-group-gates/reorder-interaction-test-1/result.json, source-proof.json and the executed test names/result in stdout.log. The parent-run command was cargo test -p oa-desktop reorder_ --message-format=json -- --nocapture, with exit0, unchanged inputs, and 22 passed / 0 failed / 0 ignored at commit cae7a22297. The source-proof record reports all 814 captured inputs matching that commit's exact Git blob bytes. This subagent inspected those records; it did not rerun Cargo or the source-proof helper.
All four named slot experiments and all five new session tests executed successfully. The unmodified equal/coincident fixture passed both core admission and actual requested Saved Ready presentation. Thus the missing BeforeC target is a real production geometry/picker combination, not an invalid-coordinate or fallback artifact. The full-model chooser BeforeC and nearest BeforeB changes passed their distinct literal expected orders. Crossed slot ordering, close continuous reachability versus integer-pixel samples, and the explicitly fixed-viewport offscreen result also matched the table above. No fixture corrections were needed.
Reject an unmodified nearest-Y fixed handle as the sole exact-destination method. In the admitted equal-Y case, BeforeB and BeforeC have identical distance functions; the current stable tie winner makes BeforeC unreachable. Reversing that winner would merely make BeforeB unreachable instead. Pan, uniform zoom, a clearer hover label, or a different fixed tie-break cannot distinguish identical coordinates. Recovering both choices requires explicit identity disambiguation, a semantic destination strip with distinct targets, or another mechanism that introduces a choice beyond nearest original Y. This rejects equivalence of that particular sole-input method, not every possible canvas drag design.
An exact identity chooser remains the recommended next comparator, not accepted UX. These tests do not establish discoverability, direct graphical editing quality, keyboard behavior, result comprehension, nested/offscreen navigation policy, full App lifetime admission or native usability. They also do not claim every root append slot or nested wrong-parent case was covered. The bounded reachability question is resolved without broadening tests; the shared session and a concrete chooser/strip prototype still require their own integration and user-workflow evaluation.