diff --git a/harness/experiments/scenario-workspace-preparation-20260913/.gitattributes b/harness/experiments/scenario-workspace-preparation-20260913/.gitattributes new file mode 100644 index 00000000..bd2de00c --- /dev/null +++ b/harness/experiments/scenario-workspace-preparation-20260913/.gitattributes @@ -0,0 +1 @@ +* -text -whitespace diff --git a/harness/experiments/scenario-workspace-preparation-20260913/README.md b/harness/experiments/scenario-workspace-preparation-20260913/README.md new file mode 100644 index 00000000..81bd81d3 --- /dev/null +++ b/harness/experiments/scenario-workspace-preparation-20260913/README.md @@ -0,0 +1,10 @@ +# Saved Scenario workspace preparation — 2026-09-13 + +Read-only preparation for the next workspace increment, based on frozen [renderer68a81c3](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/commit/68a81c3f50d846e34cae96090979543878514c1e) and the [selected display policy at920b718](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/920b718f62c20ba3c58f664dae3c5ec6b0e65ce6/harness/scenario-renderer-bridge.md#next-display-policy). Neither note implements or executes the proposed integration. + +- [Acceptance matrix](acceptance.md): actual Scene/Project/source/history guards, saved-view isolation, fallback/error behavior, full-origin Fit and zoom controls, deferred reveal, held events and a later native workflow. +- [Independent identity critique](identity-review.md): verified entry, context, active-diagram, Back, semantic-form and usage/reveal call paths; Page::Behavior remains the simplest route provided representation and semantic ownership stay distinct. + +[Manifest](manifest.json) binds the two original notes by exact byte count and SHA256. Both archives preserve original bytes and line references; source references mean68a81c3 unless stated otherwise. Their historical planning language is not execution evidence, and any referenced prospective test count requires its own actual gate receipt. Original notes are preserved with `-text` attributes. + +The [bridge note](../../scenario-renderer-bridge.md#next-display-policy) holds the selected next-display policy and its short implementation constraints. This archive adds preparation evidence, not a new schema, gesture policy, feature completion or runtime acceptance claim. diff --git a/harness/experiments/scenario-workspace-preparation-20260913/acceptance.md b/harness/experiments/scenario-workspace-preparation-20260913/acceptance.md new file mode 100644 index 00000000..08086798 --- /dev/null +++ b/harness/experiments/scenario-workspace-preparation-20260913/acceptance.md @@ -0,0 +1,38 @@ +# Saved Scenario workspace: adversarial acceptance preparation + +Prepared read-only against frozen renderer `68a81c3f50d846e34cae96090979543878514c1e`. Authority: [selected next-display policy at plan 920b718](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/920b718/harness/scenario-renderer-bridge.md), section “Next display policy”. This is an unexecuted matrix for the next increment, not acceptance of current workspace wiring. The 87 focused foundation results belong to their eventual run receipt; none is claimed here. + +## Common observable guards + +Before each passive navigation/display action capture full accepted Project, accepted SourceBundle, editable draft bundle, document revision, dirty flags and actual Undo/Redo behavior. Reuse `app/diagram_usages/tests.rs:35-60` AuthoredState; its `can_undo/can_redo` booleans alone cannot prove unchanged stack contents. Add one known prior authored edit and exercise exactly one Undo/Redo after the passive sequence, as the existing navigation test does. Do not compare only saved layout fields. Selection, camera and status are expected presentation changes; raw drafts are not. + +Use one owner with views A/B and an explicit derived entry. Existing resolver fixture `behavior/scenario_layout/tests.rs:339` provides A `(first,second)=(148,200)` and B `(1000,240)`, sharing the exchange but preserving occurrence identity. B resolves successfully with a source-order diagnostic. The lane fixture at line390 provides centers `(requester,provider)=(900,-500)`, a provider header x=-602 and full bounds x=-660..1140. These numeric controls distinguish actual displayed geometry from a correctly labelled but wrong owner-only Scene. + +## Discriminating matrix + +| Probe | Required observable outcome | Existing evaluator to extend | +| --- | --- | --- | +| A → B → derived → A, same owner, including A→B without rendering an intermediate frame | Header/selector identifies the actual saved view; A shows 148/200, B shows 1000/240, derived uses the automatic positions. Whole-view and occurrence chooser results retain Saved(A), Saved(B), Derived(owner) separately. Selecting the repeated message reveals that exact occurrence in the chosen view. All common authored guards hold. | `app/diagram_usages/tests.rs::repeated_scenario_messages_select_the_exact_occurrence_and_move_camera` (908); `app/diagram_selection_tests.rs::diagram_switch_preserves_an_independent_semantic_inspection` (122). | +| Ready reveal for A; switch to B; deliver A's retained viewport/control task; deliver B's real smaller viewport | No A camera, focus or target leaks into B. B's highlighted target is visible and centered after its first actual viewport, once. Manual pan after reveal cancels any delayed snap. Use old/new documents, revisions and visit epochs independently, including identical sizes. | `app/diagram_reveal/tests.rs` tests at230,273,316,347: all surfaces recenter once; malformed stamps; resize before measurement; user cancellation. | +| B's admitted async source-order crossing versus a saved view with `self_reply=600` | B stays authored at1000/240 with an explanatory notice. The latter produces the named typed hard failure and a COMPLETE automatic display, retaining the requested saved-view identity and its authored600. Compare normal messages, frames, lifecycle markers and nonempty typed activations against an independently captured automatic control; do not compare only one arrow or a success flag. | Resolver source controls at339 and572; new presentation-adapter child tests plus mounted workspace. Keep hard failure separate from successful diagnostics. | +| Hard failure plus a conspicuous valid lane override | Fallback uses automatic lanes AND automatic messages/scopes/activations. No surviving authored lane is mixed into fallback. Persistent banner names the saved view and says saved positions are preserved. Selection, source navigation and Fit work; geometry-dependent controls and injected mutation events are refused. Two fallback saved views remain distinct destinations even if their pictures match. | New adapter outcome assertions, actual `workspace::view`, existing Mounted input/pixels. `scenario/usage.rs:25,156,167` must consume the displayed geometry rather than recomputing an authored-only result. | +| Invalid raw source or invalid property/behavior draft while a fallback view is already displayed | Scene continues to represent the accepted model; draft text does not silently become accepted geometry. Existing navigation/admission guards retain raw input and focus. Passive viewport, banner rendering and Fit neither apply nor cancel anything. Repair actions obey existing draft guards. Successful explicit repair changes accepted state once; Undo restores exact unsupported values and fallback deterministically. | `pending_source_behavior_and_modal_inputs_block_open_and_choose_without_loss` (usage tests532); `scenario_workspace_viewport_events_are_passive_guarded_and_do_not_apply_raw_forms` (workspace tests996); `scenario_workspace_choosing_tools_preserves_valid_and_invalid_pending_editors` (1042). | +| Pointer press in fallback, then source repair or view switch before release; separately replay captured Begin/Reorder events | No geometry or semantic sequence write comes from the stale pointer sequence. Clean fallback still permits semantic inspection. Merely hiding/greying controls is insufficient: directly delivered old events must be rejected. A fresh valid gesture remains a separate future acceptance gate; do not claim layout-drag support in this display increment. | `canvas_workspace/tests.rs::Mounted::input/batch` (140/155), captured toolbar helpers (742), Scene pointer tests and full authored guards. Requires explicit per-display capability/gesture identity to be observable through emitted events, not a test-only permission bypass. | +| Negative-origin or very wide saved geometry; Fit with actual measured viewport and visible fallback banner | All intended structural bounds fit inside the measured canvas gutter; leftmost negative header, Create marker and activation are reachable. Assert transformed known points against real widget bounds, then click one and verify exact selection. Width alone and an origin-zero camera are wrong. A zoom minimum must not silently defeat Fit. | `scenario_workspace_fit_uses_measured_inner_viewport_and_rejects_nonfinite_inputs` (1749), `production_scenario_canvas_keeps_bounds_draft_identity_and_camera_through_editing` (6), `scenario_workspace_scaled_and_panned_scene_keeps_clicked_slots_and_message_endpoints` (1147). | +| Delete/reidentify saved view or change owner before queued choose/Back; automatic resolution also fails; unfinished messages with latent positions | Stale identity is refusal, never automatic fallback to another owner. A valid saved view whose automatic resolution also fails shows unavailable state with inspection/source actions. Unfinished messages retain authored positions and semantic notices without invented arrows or spurious hard-failure banners. Opaque-use Back restores the original saved identity, not an arbitrary view of its owner. | `revision_retarget_and_document_change_make_old_destinations_inert` (usage tests461), `old_panel_tokens_and_forged_targets_cannot_redirect_selection` (438), existing Scenario open-use/Back tests; latent source controls at628/762. | + +## Minimal new test seams + +Camera falsifier supplied and source-checked by the parent: with a 700x500 viewport and bounds x=-1,000,160, width=2,000,400 (height not the limiting dimension), an eight-pixel horizontal gutter requires zoom approximately 0.00034193 and pan-x 349.986; projected left/right are 8/692. The existing 0.05 floor produces 100,020 pixels of width. Assert these independently calculated endpoints after the actual Fit event, after a subsequent viewport measurement and across Fit→ZoomIn→ZoomOut. The anchor under the zoom center must remain fixed, and zoom must not jump back to 0.05. This probes the full path: `Scenario::camera_zoom(None)` currently passes the computed scale through `zoom(Some(fitted))`, clears Fit and zeros pan; shared `canvas_workspace::change` independently clamps 0.05. Removing only the `fit_scale` clamp cannot satisfy it. The toolbar must display a meaningful nonzero tiny scale (for example 0.034%, with accessible equivalent), not rounded 0%. Exact label formatting is a product choice; truthful scale and usable zoom transitions are acceptance requirements. + +1. The production presentation adapter itself is the necessary new seam: read-only access to requested representation, actual Scene/bounds, authored/fallback/unavailable status and diagnostics. Child tests can access its private result. Do not create a separate test renderer, fake fallback or public cache API. Test a deterministic automatic-resolution error if a real admitted fixture is available; otherwise label that branch as an unexecuted defensive condition instead of injecting a falsely representative fixture. +2. Extend the existing mounted harness; it already supplies real widget layout, input batches, task execution, clicks and pixels (`behavior/canvas_workspace/tests.rs:90-300`). A stable semantic widget ID for the persistent notice/source action can make geometry/focus checks practical; it is not a substitute for native reading and keyboard activation. +3. Extend the reveal fixture's surface cases to saved Scenarios. Preserve the actual `App::update` viewport path, rather than directly calling the new camera setter. Keep lookup completion helpers for deterministic async tests, with a later real chooser native check. + +Current ownership hazards to change together: `app.rs:1725,1757` Scenario context/admission; `scenario.rs:71,329,350` owner-only Context/enter/Fit; `scenario/workspace.rs:14,72-102` presentation and sensor identity; `canvas_workspace.rs:58-87` Scope; `app/diagram_reveal.rs:25-69` viewport→Surface mapping; `scenario/usage.rs:25,156-201` derived-only usages/reveal. Resolver `scenario_layout.rs:477-499` already distinguishes requested Representation and resolved owner; success diagnostics are currently retained in the plan, not a display policy. Line numbers are exact to 68a81c3 and should be re-resolved after integration. + +## Small native acceptance sequence after controller/mounted checks + +At one ordinary and one narrow window size: open A/B from real diagram navigation; inspect view names and two usages of one message; Fit the negative-origin view and click its far-left marker. Open the hard-failure view, read its banner with panels shown and Focus enabled, select an element and navigate to source. Leave invalid raw source, confirm no implicit apply/loss, repair explicitly, then Undo/Redo and save/reopen. Attempt a real fallback drag and verify no source/history change. Record the failed/refused actions as well as successful ones. Native timing cannot reliably replace held-task tests, and screenshots alone cannot establish source or history preservation. + +Do not broaden this increment into unrestricted movement, route editing, activation redesign, export support or generic codec acceptance. No compiler, server, GUI or source mutation was performed to prepare this note. diff --git a/harness/experiments/scenario-workspace-preparation-20260913/identity-review.md b/harness/experiments/scenario-workspace-preparation-20260913/identity-review.md new file mode 100644 index 00000000..e9b05f37 --- /dev/null +++ b/harness/experiments/scenario-workspace-preparation-20260913/identity-review.md @@ -0,0 +1,25 @@ +# 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. diff --git a/harness/experiments/scenario-workspace-preparation-20260913/manifest.json b/harness/experiments/scenario-workspace-preparation-20260913/manifest.json new file mode 100644 index 00000000..315db2e5 --- /dev/null +++ b/harness/experiments/scenario-workspace-preparation-20260913/manifest.json @@ -0,0 +1,21 @@ +{ + "status": "unimplemented, unexecuted next-workspace preparation; read-only source review and acceptance design", + "frozen_source": "68a81c3f50d846e34cae96090979543878514c1e", + "policy_source": "920b718f62c20ba3c58f664dae3c5ec6b0e65ce6", + "originals": [ + { + "original_name": "scenario-workspace-acceptance-20260913.md", + "archived_path": "acceptance.md", + "bytes": 11244, + "sha256": "37a4e55aec080b90760e8575e40466b669e715506e4bedb2c1dd592fd31cdec1", + "exact_original_bytes": true + }, + { + "original_name": "saved-scenario-identity-adversarial-review-20260913.md", + "archived_path": "identity-review.md", + "bytes": 9862, + "sha256": "9b3d17e0442db2c99a36188bf5ba36095bba7e8cd2e38c61e79eb81f7d0ba466", + "exact_original_bytes": true + } + ] +} \ No newline at end of file diff --git a/harness/scenario-renderer-bridge.md b/harness/scenario-renderer-bridge.md index f219592d..93d84568 100644 --- a/harness/scenario-renderer-bridge.md +++ b/harness/scenario-renderer-bridge.md @@ -53,3 +53,5 @@ The [portable source review](experiments/scenario-resolver-review-20260913/READM For the next workspace increment, use one complete automatic fallback only when a structurally accepted saved representation has a hard geometry failure and its automatic resolution succeeds. Keep requested Saved identity distinct from the Derived geometry provenance, preserve all authored values and show a persistent accessible explanation. Invalid/stale identity or failure of both projections yields an unavailable canvas with inspection/source actions, never an arbitrary owner or unchecked partial renderer. Successful authored geometry with source-order/frame-overlap diagnostics stays authored and receives explanatory notices. Latent messages and semantic completeness warnings remain distinct. One presentation adapter must supply the actual Scene, origin-bearing bounds, identity and status to paint, hit-testing, usage and reveal. App owns document/revision/view-visit freshness; existing Scenario state owns presentation. Inspection, navigation and guarded semantic/source repair remain available. Coordinate-dependent input is refused in fallback at both controls and event admission, including a held drag released after repair. An explicit repair must never save fallback coordinates implicitly. This is a selected reversible display policy for the next implementation; native feedback, focus, stale input and persistence acceptance remain required. + +The [workspace acceptance preparation and independent identity review](experiments/scenario-workspace-preparation-20260913/README.md) define the next integration checks. Route saved Scenarios through Page::Behavior with explicit representation, semantic owner and a stable view-visit stamp across controls, passive callbacks and Back; restoring a caller restores presentation into a fresh visit. Fit and every zoom transition must use full origin-bearing bounds without a conflicting minimum-scale clamp. Do not enable a saved chooser destination until paint, query and reveal consume the same resolved Scene and representation. These are implementation constraints for the next increment, not implemented or executed workspace support.