Replace the oversized header and reference rail with stable editor slots and a retained supporting drawer. Bind diagnostic, result and menu actions to their original publication and visit; preserve effective selections on navigation and dismiss Actions, Find and the drawer one surface per Escape. Retain exact Windows source captures, eight final gates (871 desktop passes), independent reviews, native selection/rename/recovery trials and the original failures. All 526 tested inputs and staged evidence were byte-checked before commit. Combined preview integration and packaging remain with issue 27; Linux remains paused.
8.6 KiB
Native trial 2: Escape and text Undo review
Read-only source and evidence review by Codex-9e8r6t /root/diagnostic_input, 2026-09-13. Parent owns the live GUI, source integration and execution. This note is the only new artifact; no source edits, build, test, Git or GUI operation was performed for this review. Source references below are relative to C:/ar-text-9e8r6t at the hashes recorded below. Trial evidence is under main .local/text-workspace-native-20260912/trial-text-2.
Escape: one legacy action, not duplicate dispatch
Screenshots 050 and 051 were independently inspected. 050 shows the menu dismissed with Find and References still open. 051 shows both Find and the drawer closed. Its filename says “keeps-drawer”; that label is incorrect and must not override the pixels.
The mechanism is direct: app.rs:1996 computes whether to restore source focus, then unconditionally sets source_navigation.open = false and calls text_workspace.show_drawer(None) before guarded focus restoration. The captured bridge (behavior/creation.rs:15,23) emits only for Captured Escape. The ordinary subscription (app.rs:1128–1142) explicitly ignores Captured Escape. The bridge is disabled while the Text popup is open (app.rs:1117). There is no evidence of two App Escape messages from one key. The actual-subscription test at app/source_symbols/tests.rs:1916 already asserts one message after popup dismissal and then explicitly expects both surfaces closed; the modal matrix at line 1099 also encodes the simultaneous dismissal.
Frozen CBC main/crates/oa-desktop/src/app.rs:1911 performed the same simultaneous dismissal, additionally clearing old results. This is inherited behavior, not a new subscription race. Current interaction contract line 53 requires only menu-first dismissal, which trial 2 passes. Earlier private design.md:50 says “Escape closes only the focused transient surface”; that stronger scoped-dismissal intent was omitted from the handler/test expectations. Parent now accepts a one-surface-per-Escape correction after the native trial closes. This is a bounded usability defect, with no observed source/model data loss; retained query data already survives Hide.
Small correction and evaluator
Keep the existing popup and modal dispatch layers. In the ordinary Text Escape path, dismiss Find if it is open; otherwise hide the supporting drawer. Use the existing focus-only restoration for Find, preserving its actual selected bytes and scroll. Do not introduce another subscription or focused-widget engine. The accepted priority is explicitly menu → Find → drawer, including the case where clicking Actions had unfocused the Find input.
Extend the actual subscription regression: start with current References data, grouping and nonzero saved scroll, open Find, then Actions. Popup Escape yields its tokened dismissal and no bridge message. The next actual captured/ignored Escape yields exactly one App message, closes Find only, retains drawer visit/groups/results/scroll, and leaves the live word/line selection intact after guarded focus. The next Escape closes only the drawer and retains its data. Check accepted source/model/history unchanged; pending matching query completion may store data without jumping/reopening. Update the two legacy simultaneous-dismissal expectations rather than merely adding a new test that contradicts them. Native replay must inspect each resulting surface separately.
Higher-priority risks: do not move the Text branch before menu handling (app.rs:1232), architecture cancellation (1287), model-menu dismissal (1324), hosted/workflow/file/delete/pending dialogs (1392), or rename cancellation (1454). Existing modal Escape tests must still leave underlying Find/drawer intact and must not queue editor focus. Generic source interaction invalidation precedes ordinary dispatch; retain that cancellation and queue focus only after the chosen current surface closes. Preserve source_navigation_available guards (app/source_symbols.rs:91) and the raw-input/ticket guards on asynchronous focus. Do not inadvertently extend this Text priority to behavior-source back/cancel or active connection cancellation in the same ordinary handler.
Text Undo: separate existing history limitation
source_workspace.rs:83 stores past/future: Vec<String> plus one current cursor, with no per-history cursor, selection or scroll. app.rs:2982 applies the edit and sends the post-edit cursor into Workspace::edit (233), which overwrites buffer.cursor. Workspace::undo (302) swaps text/history and advances generation but leaves that cursor unchanged. app.rs:3156 then calls show_source_file(true); its default path (app.rs:700–734) reconstructs Content with text, losing internal scroll, and queues the retained post-edit coordinate.
If that coordinate is invalid in the restored shorter text, the existing exact-cursor guard refuses the reveal, leaving the fresh editor at its default top/caret. If it remains valid, restoration can use that post-edit coordinate instead of the earlier pre-edit selection. These primary-source mechanisms explain the parent's reported scroll-to-top and occasional prior post-edit caret. Workspace bytes are unchanged from frozen CBC and CBC has the same SourceUndo reconstruction route. A targeted note search found no earlier explicit tracked Undo-scroll defect: describe this as a newly observed native limitation of pre-existing text-only history, not as already accepted exact cursor/viewport Undo behavior.
Screenshot 011 was inspected: it shows the original alias, the viewport at the file start, and “All changes saved” after the typing probe's Undo. The parent reports analogous baseline restorations during the other selection probes. This is limited evidence of visible text restoration and clean-state feedback, not proof of exact Undo caret/selection/scroll restoration or all unsaved buffers. Saved-disk oracle results inspect disk only; they cannot establish a live unsaved editor's cursor or viewport. Model/rename Undo evidence is a separate action and must not be used as text-Undo evidence.
Keep exact text-Undo cursor/selection/viewport semantics as a separate follow-up: decide the edit grouping and before/after selection/viewport history policy, then evaluate real replacement → Undo → Redo with Unicode, multiline CRLF, caret movement after edit, and exact source/selection/scroll assertions. Navigation design line 43 explicitly keeps existing text/model history untouched. The current Escape correction should not redesign histories.
Exact reviewed hashes
Trial launch manifest binds source archive 83ff861fc27b7aead159fde12e6fd881ba6c3c02b29e7bf10bbc12c60b7e6067; its native scope was still pending at launch. Hashes below bind this review, not later fixes.
| Artifact | SHA-256 |
|---|---|
| crates/oa-desktop/src/app.rs | 75ef46ef2789b32c5837ee33dfdc303eaba013ba75767138e4a19ba5113bc6ba |
| crates/oa-desktop/src/app/source_symbols.rs | d81914a553114d85452d973a1edb175843d27154b3f9b9fc4cbc5049d423abe4 |
| crates/oa-desktop/src/app/source_symbols/tests.rs | 00cbacdd0af98858b5e74608720bd8251719c9926569a65a0ad777a40f1744c9 |
| crates/oa-desktop/src/behavior/creation.rs | 438a245ead397060767c790c51a8f21cd5021342627999deb4695cf3bd22091a |
| crates/oa-desktop/src/source_workspace.rs | 388c71f63829c0c76526a1700ebf5f240c86c467a65aae4fca4cd6c6a88c468b |
| harness/text-workspace-interaction-contract-20260912.md | 87d83bcedc808bf78bb3f9d0bb4b09884f627c010fbc339c86e11d00f696646b |
| harness/release-text-navigation-design-20260911.md | adaaf60fa0711677997f62c49ec899b8d412a0a0896897b2f1bb53d0ecdbeb75 |
| main private design.md | 73c6aa75980ce0ceeb132ef8a89f73a906a2ed6c4a7cc1f2ff5745ab0d0b66fa |
| frozen CBC main app.rs | d2e13b4527eec6c0920668d312d647806c762ed0a2f3ad9595a1243d9993fc14 |
| trial2 launch-manifest.json | f4bc04c2f6669f7e2cb28d12cc65efe4c89917396c3d871a189960dea7dee1ee |
| trial2 screenshots/050-escape-closes-only-actions.json | 3bb686f78988b6d7a321fa4c7c7f62f7ffe159023fb38146b8fb6baa73d924bf |
| trial2 screenshots/050-escape-closes-only-actions-0.jpg | d414906bcb1e55e881128a388c223e9f139b5c5097083bb51f35cad133632fdc |
| trial2 screenshots/051-second-escape-closes-find-keeps-drawer.json | 942ccb4b8cb87de4a2b1d02fe5daa98ccf8db26723c2d55ab946570b59c5e10e |
| trial2 screenshots/051-second-escape-closes-find-keeps-drawer-0.jpg | 988dc77f7844cbae0bf3156e27065a20f5198e7a081ecb7b031d95f15f04b29a |
| trial2 screenshots/011-word-find-close-undo-baseline.json | cfdf9fb5fe821e269e2288acc9d3e69bce7d2601b0dc1f528044755eff390658 |
| trial2 screenshots/011-word-find-close-undo-baseline-0.jpg | ddb8488cfefad22260bf9aded45ca46a7c77cdf2e35ec413c1e66d605f01ece5 |