Files
ARCADIA-Studio/harness/experiments/scenario-workspace-preparation-20260913/identity-review.md
T

26 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Saved Scenario identity routing: independent source critique
Read-only review of frozen renderer68a81c3f50d846e34cae96090979543878514c1e and plan920b718f62c20ba3c58f664dae3c5ec6b0e65ce6 (`harness/scenario-renderer-bridge.md`). No source changes, compilation or native evidence. Line references below are relative to `crates/oa-desktop/src/` at68a81c3. These are next-integration hazards, not claims that the still-disabled saved workspace currently admits them.
**Recommendation:** Page::Behavior is the smallest reasonable routing candidate, following the existing saved-state adapter. Explicit Representation must be authoritative across entry, events, Back, presentation and usages; changing only canvas_workspace::Scope is insufficient. Retain semantic owner and selected IDs independently of saved Diagram identity. A new page does not remove these shared assumptions and would duplicate form/canvas dispatch, so no materially better page-level alternative is established.
## Concrete unsafe assumptions and minimum changes
1. **Entry is not a single setter.** `app.rs:1757–1791` currently refuses saved pick/reveal before Apply. Removing that check alone reaches Diagram choice (`3093–3119`), which sets active_diagram and calls the architecture fit, without routing to Behavior. `app/state_diagram.rs:12–42` only recognizes StateMachine. `behavior.rs:1041–1051` resolves pending owner, active owner, selection ancestry, then the first behavior; a selected Diagram UUID has no semantic ancestry (`1078–1107`). `Page(Behavior)` can preselect an owner (`app.rs:2454–2462`). Add one guarded saved-Scenario entry/reconciliation adapter: validate Diagram→Scenario/layer, set Representation::Saved, matching active_diagram and active_owner atomically, then retire canvas/input lifetime and render the resolved scene. Never let a missing/retargeted saved view fall through to the first Scenario. Keep architecture mutation/export refusal independently scoped; enabling rendering does not authorize those operations.
2. **Same-owner views alias at several retained and passive boundaries.** Context has document/scenario/revision/epoch only (`behavior/scenario.rs:71–76`). Presentation identity and enter use(document,owner) (`329–339`); workspace sensor key also omits view (`scenario/workspace.rs:75–127`). Shared Scope and control IDs omit view (`behavior/canvas_workspace.rs:60–100`); toolbar validation explicitly assumes scope.owner==context.scenario (`app.rs:1284–1288`). Do not put Diagram UUID into Scope.owner as a shortcut. Add representation identity alongside semantic owner and propagate it through Scope::current, Intent validation, widget IDs, sensor keys, Context and camera boundary (`app.rs:1341–1355`). In particular, Viewport/Scrolled/FormShown accept owner/revision while intentionally ignoring epoch (`1810–1857`), and Restored relaxes revision too. They must check representation. A stable navigation-visit token is also needed for A→B→A without an intervening rendered frame; keying sensors by canvas_epoch would cause feedback because viewport/pan themselves change that epoch. Keep existing epoch relaxation within the same valid visit.
3. **Back stores the caller owner, not its representation or active diagram.** Caller/DetailsRestore (`scenario.rs:218–239`) and open_use/valid_caller/back/restore (`377–451`) currently carry owner, occurrence, target, camera and scroll. App OpenUse/Back (`1921–1971`) forcibly restore active_owner before select to defeat its same-UUID fast path; keep that fix. Capture caller Representation and destination visit plus any active_diagram value that the saved transition replaces. Opening a definition should deliberately enter Derived(callee) unless the user explicitly chooses a saved callee view; do not guess among saved views. Back must validate that the captured saved Diagram still exists and projects the captured owner, as well as the existing ScenarioUse target predicate. Retarget/deletion must refuse/skip that caller frame with the existing unavailable feedback, not silently restore automatic geometry. Rename with stable identity can still return. Restore page/representation/active_diagram/owner independently of whether selection already equals the occurrence. Back restores presentation values into a fresh visit; it must never revive the caller's old event token. Scroll observer identity (`behavior.rs:38–205`) and delayed form focus Stamp (`scenario/focus.rs:11–37`) need the same destination check when they can survive navigation.
4. **active_diagram is also remembered architecture state, not a reliable Behavior selector.** Current derived Scenario reveal/OpenUse leave active_diagram untouched (`app/diagram_usages.rs:381–393`, `app.rs:1921–1961`). Page(Diagram) deliberately replaces non-architecture views with an architecture default (`2435–2452`). sync only checks active diagram existence/layer (`792–805`); Apply's UUID-following updates active_diagram/active_owner/state diagram but knows no new Representation (`853–925`). Introduce an explicit consistency rule: visible Saved(d) implies active_diagram==d and projection owner matches; visible Derived must not retain an unrelated saved Scenario as its apparent current view. Preserve remembered architecture where useful, but never infer Saved solely from a lingering active_diagram. Reconcile after property UUID edits, source adoption, Undo/Redo, deletion, projection-owner retarget, duplication and layer changes. Any identity change must invalidate pending gestures/measurements even when owner or selected UUID remains equal. A shared accessor returning validated(owner,representation) is smaller and safer than independently rebuilding that pair in each caller.
5. **Passive routing must preserve pending semantics and selection.** apply (`app.rs:853–863`) refuses source drafts and pending behavior forms, but can commit valid property drafts. select (`1062–1093`) calls Apply and can change active_owner; its equal-ID path returns early. A new entry helper must not use select/Apply merely to display a view or recover an owner. Keep explicit choice's established property-Apply policy separate from the passive routing postlude; validate a stale destination before any Apply, and preserve both valid/invalid source-child/parent form buffers on rejected navigation. Existing usage navigation requires every modal/source/property/behavior guard to be clean (`app/diagram_usages.rs:16–29`), and OpenUse/Back explicitly do so. Reuse those predicates for equivalent new paths. Saved-view selection remains either a semantic object or an explicitly inspected Diagram; do not convert a message/lifeline selection into the saved Diagram just to retain workspace identity. Semantic form commands continue to address owner/occurrence IDs; view-only lane/send edits address the captured Diagram. Merely entering Saved must not change the existing Select/reorder tool into spacing-drag semantics.
6. **The current usage/reveal contract is owner-only and automatic.** Scenario usage builds Scene::sequence separately, emits Surface::Scenario(owner), and Whole uses origin-zero Size (`scenario/usage.rs:25–40,140–165`); reveal requeries that automatic surface (`167–204`). collect deduplicates by subject/surface/target (`diagram_usage.rs:180–207`), so saved views must remain distinct surfaces. Current Surface::Saved is categorized/routed as architecture or state, and saved Scenario is explicitly refused (`app/diagram_usages.rs:293–299,335–365,434–445`). Introduce a typed surface→representation mapping (existing Saved(d) can remain the saved identity if every category/query/router discriminates its projection). Use the same resolved representation and full bounds for paint, query, Choose revalidation, focus and camera. Scenario viewport→surface currently hardcodes Scenario(owner) (`app/diagram_reveal.rs:49–54`); it must report the selected Saved(d), and final deferred reveal must verify current representation plus visit before consuming a measurement. Otherwise A/B with the same owner can jump using automatic/A bounds or satisfy the wrong first-layout completion. Keep one-surface Choose revalidation and existing async token/revision release rules. Measured-label/operation visibility remains the separately documented dependency, not something identity wiring alone solves.
## Ordered narrow integration and discriminating controls
First establish validated representation/owner access, entry/reconciliation and all context/retained-widget stamps, while preserving existing semantic forms and architecture refusal. Then carry complete caller representation through OpenUse/Back and shared scroll/focus ownership. Finally wire the resolved Scene and explicit surface into paint/query/deferred reveal together; never enable a Saved chooser row whose actual reveal still rebuilds automatic geometry. Full bounds/fit changes remain necessary at that last step; the current0.05 floor/origin-zero fit is already recorded in the bridge note.
Critical controls for the parallel acceptance matrix: two saved views of one owner with equal viewport size; A→B→A before a render with held Viewport/Scrolled/toolbar/FormShown; SavedA→DerivedC→Back while an edit has already selected the caller UUID; saved caller deleted or retargeted during the visit; valid/invalid pending source-child and property buffers when selecting another view; semantic occurrence rename/UUID edit and saved Diagram UUID edit followed by Undo/Redo; asynchronous Choose for SavedA while SavedB/Derived is displayed; negative-origin Saved Whole reveal after the first exact measurement. All refused/passive cases need whole Project/source/history equality and retained raw draft checks. A separate page would still require all these checks.