10 KiB
Shared behavior canvas — independent root union review
Codex-956atf /root/canvas_union_review, 2026-09-11. No actionable correctness, input-ownership, architecture or source/history regression was found in this bounded source review of the integrated canvas and scenario-parent focus paths. This is not a build, runtime, visual or release acceptance verdict.
Scope and identity
Root delegated this read-only review against the production union on codex/behavior-authoring-20260910, first identified by root as commit 6969c825a8340980b6a419524ade3bb687a6051f, then frozen at 06ec9621297627a1f7d5c3bc65efb237d1c9923e. The latter adds two test-only compiler adaptations described below. Commit identities are root-provided; this reviewer did not run Git. The scenario test freeze independently matched SHA256 950CF4347A3EDEA615B1AC71D9A681C32B446B5109FCFD0F03F3AE2B147360BF.
Read the current AGENTS.md and PROJECT_GOAL.md, the prior R1/R2/R3 review, the isolated candidate's R1/R2/R3 source handoff, and the relevant actual root implementation and tests. The prior review's resolved counterexamples were checked for integration regressions rather than re-reported. Root owns Gitea coordination, compilation, native acceptance and publication. Only this report was written.
The following independently observed raw working-file hashes identify the important union boundaries. Paths are relative to crates/oa-desktop/src/.
| Path | SHA256 |
|---|---|
app.rs |
AA2E4853B25BB7E185B1DE49EDA42028523C8EBF9599BFE6B7CB2A2B2A688090 |
behavior.rs |
5E7CECB54BFCA64E4462F7881F460900ABD925BA2CFE9451CE2B0C78AF4BC850 |
behavior/scenario.rs |
FB1DA03E8DF05A59253F7FDF34391E30ABD8AEA427B7D0A12B86B80FF3BF9ECA |
behavior/scenario/focus.rs |
73A9EA10AD7312086081B8688396A21AB4251C9FAECC2DF6D984B702F3963533 |
behavior/scenario/workspace.rs |
284F5A7DA09BDC77D70C6788A091D57927150C796FFC10D786793CFF7DA4B7C6 |
behavior/scenario/workspace/tests.rs |
950CF4347A3EDEA615B1AC71D9A681C32B446B5109FCFD0F03F3AE2B147360BF |
behavior/canvas_workspace/focus.rs |
CC58CB3838F546150D22FE4DD83A3FFD52504C279FEBAEB8D0B4A6A3B8A73950 |
behavior/canvas_workspace/tests.rs |
D84D022574A6F1D69F203D9383502227FB9FC23605C6FB48779CA9F09BEE546D |
behavior/topology/layout_tests.rs |
A990947CB39B2FB15C21DFBC95EE16F92BF6BE749D3872C6904762B9BDE37089 |
behavior/form_session.rs |
F5027FB3A5A5599A182E7D1A10DBA56DD66EB1F23A4BA4C4A1744C9A6A5B6E61 |
Production integration
All source locations in this section are under crates/oa-desktop/src/.
app.rs:1041 nests the scenario parent owner root outside the canvas owner root, with both outside the actual hosted/reference overlays. Their custom owner types are distinct. Each operation ignores the other's marker, receives its own current marker before visiting focusable children, and independently checks ownership in Collect and Apply. This preserves the parent form guard while allowing the canvas operation to cover the actual nested overlay traversal. A pending scenario form makes Scope::input_owner return None (behavior/canvas_workspace.rs:84); opening its source child removes form_mount (behavior/scenario.rs:509); Review removes the parent owner (app.rs:1495). No competing current canvas/parent focus owner was found in these paths.
app.rs:1119 retains the exact current canvas Scope admission and narrow presentation whitelist. Only accepted presentation actions normalize the semantic epoch, and resulting control focus uses the post-action lifetime at app.rs:1177. The outer parent wrapper neither changes these epochs nor emits another focus operation. The resolved held-pan/toolbar and delayed canvas-task cases therefore retain their production guards after integration. Domain authoring still uses exact scenario context at app.rs:1619.
Scenario Name uses the session-and-mount-derived dynamic ID (behavior/scenario/workspace.rs:283), while the scroll reset wrapper remains keyed only to editing session (:615). The sensor uses the mount key and sends that mount in FormShown (:565). The handler accepts same-owner geometry epoch changes but checks document, owner, revision, current owner and pending mount (app.rs:1527). Back, Use and Escape rearm the parent through remount_form (behavior/scenario.rs:324, :696, :745). None of these presentation paths replaces the raw invocation or source draft. The zero-delta axis preservation in behavior/scenario/focus.rs remains present.
The Details pane now uses the production passive observer with process = false (behavior/scenario/workspace.rs:595). Its actual translation enters scenario Page scroll state, and a caller restore receives and consumes the matching token through behavior.rs:114 and behavior/scenario.rs:460. restore_caller marks only Page pending (behavior/scenario.rs:425), consistent with the viewport using camera pan instead of a Scrollable. The reviewed source contains no new semantic command or source mutation in these observer/focus paths.
The boxed workflow convention is retained (workflow.rs:22, :45), including review_event.as_ref() in app/reference_authoring.rs:218. Reference chooser availability excludes pending behavior forms (app/reference_authoring.rs:72), so its separate canvas guard does not create an uncovered simultaneous parent-form/chooser owner in the reviewed production path.
Mounted evaluator and nontrivial assertions
Independently inspected the installed Iced sources under .local/toolchain/cargo/registry/src/index.crates.io-1949cf8c6b5b557f/:
iced_winit-0.14.0/src/lib.rs:1214drains App updates, rebuilds the resulting UI, then executes actions;:1300collects immediately ready task actions for the whole message batch and retains pending streams;:1742executes chained widget passes synchronously.iced_runtime-0.14.0/src/user_interface.rs:539operates both the real root and nested overlays.iced_widget-0.14.2/src/scrollable.rs:540reports the scroll translation before traversing unshifted child layout, matching the parent's translated bounds observer and reveal calculation.sensor.rs:198rearms on key change and emits on the subsequent redraw, including unchanged bounds.iced_core-0.14.0/src/widget/id.rssupports the dynamicId::from(String)used by the union.
The shared Mounted helper uses those actual UserInterface and Cache APIs, drains a complete input message batch before tasks, builds the final App view for ready actions, and executes Chain passes against that same UI (behavior/canvas_workspace/tests.rs:140, :184). Output messages form the next update cycle; pending streams are retained until completion. Unexpected native actions panic and unavailable renderer initialization fails. This is the relevant single-window widget/App ordering, not a replica of subscriptions, OS focus, native dialogs or arbitrary asynchronous scheduling.
The reconciled parent tests preserve useful falsifiers:
scenario/workspace/tests.rs:412first focuses another real field, establishes actual parent overflow, performs the accepted task, and requires the exact Name to be the sole focus and fully visible. Mismatched mounts, revisions, owners and modal admission are separately rejected.:794obtains the real sensor task and first consumes initial focus before entering the actual child. Back, Use and Escape must retain session/raw identity, create a different mount, emit a new sensor task, and focus the parent again. A repeated FormShown must produce no task.:864retains an actual widget Action before replacement, child, Review and context transitions; it observes the resulting tree and requires the saved Collect to remain inert.:935similarly retains Apply across Review. This intentionally stronger retained-Apply invariant does not claim native Chain passes interleave.:958is explicitly a small synthetic missing-target test; it is not presented as a production-root modal test. The preceding production-root cases supply that coverage.:1654requests 700 pixels on the real Action form and requires the measured offset to exceed 64, preserves it while editing, then performs Cancel/Start with no intervening closed view. It checks zero offset before a redraw could rescue it through a new Name-focus task. Action and Observation share the same relevant field structure (scenario/workspace.rs:280,:315,:476), so replacement is not simply a switch to an empty form. Camera, raw invocation, recovery, source snapshot and history assertions remain.:1773tests same-bounds owner/document remeasurement with the same Mounted cache.:1820builds legitimate Details rows, requires the actual offset to be exactly 80, navigates through preselection and caller return, then requires the offset/camera restoration, consumed receipt, and subsequent pan movement. Source and revision comparisons surround navigation; existing rename history is acknowledged instead of asserting an empty history.
The shared chooser/Review case continues to use actual nested search and Review fields (behavior/topology/layout_tests.rs:568). The two compiler adaptations in 06ec962 are consistent with installed APIs: explicit Headless::screenshot selects the trait's physical-size/scale overload (behavior/canvas_workspace/tests.rs:268), and the Review fixture calls the existing boxed event constructor (behavior/topology/layout_tests.rs:726). Neither changes evaluator ordering or production behavior.
Acceptance limits
No compiler, test, renderer, native GUI, Git/index, network, Linux/WSL or VPN action was performed by this reviewer. Root reported the initial two test API errors and the committed adaptations; the corrected compiler run was still underway when this report was prepared. There is no executed pass claim here, and earlier reports establish different bytes.
Root still needs the appropriate exact-union build/test and native acceptance evidence. In particular, operation geometry and prepared pixel assertions do not establish native focus/accessibility, clipping of transformed scene text, all modal geometry or minimum-window usability. The separately owned B4 renderer work and broader phase 1/issue 2/PROJECT_GOAL acceptance are not certified by this bounded integration review. No new blocking source finding is left for this reviewer to hand back.