Files
ARCADIA-Studio/harness/release-activity-allocation-drag-design-20260911.md
T

105 lines
19 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.
# Activity/function allocation drag proposal — 2026-09-11
Codex-956atf `/root/capella_process_gap`, advisory diagnosis/design for [issue 3](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/3), under [root scope 432](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/3#issuecomment-432).
The user wants existing activities to move from the canvas root into entities/actors and back out by dragging. The proposal below also covers SA functions/system actors. It changes allocation and placement, never work decomposition. This is a proposal for root review, not ratified specification, implementation or native acceptance.
Read current AGENTS/PROJECT_GOAL, issue 3/4 and current diagram, App, projection, validation, command and reference-deletion source. Baseline anchors identify **638d06c4e33a1f54203b234d0b49c3ecf551d27d**. Root's canvas integration currently has local staged/unstaged changes and merge conflicts; none was modified. [Issue 4 comment 431](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/4#issuecomment-431) assigns the child-work correction to ytr83r: first-child creation transfers the existing leaf allocation to the child, preserving identity/metadata. This report does not acquire that implementation, B4/header or source-navigation work. Only this report was created; no compiler/test/native execution, Git/index/Wiki mutation, agents, Linux/WSL or VPN activity.
## Exact cause of the current interaction
1. [Diagram drag state][S1] stores placement ID, pointer origin and original position. Press starts a placement drag; release emits only `Message::MoveNode(id, position)`. There is no performer destination or allocation intent.
2. [App's MoveNode handler][S2] applies pending properties and executes `Command::MoveNode { with_descendants: true }`. [Core movement][S3] updates node positions and eligible route waypoints. It never adds, edits or removes Allocation.
3. In an allocation diagram, [projection parent computation][S4] groups work under its computed performer, or under a visible work ancestor with the same performer. Parentage comes from semantic records, not geometric overlap.
4. [Enclosure][S5] expands/moves a projected parent to surround its projected children. The [drag preview][S6] retains the accepted Project's allocation relationships, so dragging work outward keeps it inside the same expanding enclosure.
Thus incoming drag cannot create allocation; outgoing drag cannot remove it. The continued enclosure is expected projection behavior, not a coordinate-clamping defect. Fixing coordinates, weakening enclosure, or enabling arbitrary `Reparent` would address the wrong layer. This diagnosis follows executed source paths; it is not a fresh observation of the native binary.
## Required meaning and less obvious cases
The existing [language contract][S7] distinguishes Activity → Activity / Function → Function decomposition from participant → leaf-work Allocation. Non-leaf Allocation is invalid; each leaf has at most one direct performer. Actor graphical containment must therefore not become `Element.parent = actor`. [The earlier native Capella benchmark](release-capella-basic-editing-20260907.md) independently found an activity visually inside an entity while the activity remained in its work hierarchy with a separate allocation. Capella also separates [allocation management](https://github.com/eclipse-capella/capella/blob/5537297b071fff809285bc63989f5067d675bc52/doc/plugins/org.polarsys.capella.ui.doc/html/07.%20Modelling%20Wizards%20and%20Accelerators/7.2.%20Contextual%20Allocations.mediawiki) from [layout-only work](https://github.com/eclipse-capella/capella/blob/5537297b071fff809285bc63989f5067d675bc52/doc/plugins/org.polarsys.capella.ui.doc/html/04.%20User%20Interface/4.05.%20Diagram%20Editor.mediawiki#L84-L105).
Two existing semantics prevent treating every outward drag as “delete one relation”:
- [`effective_performer`][S8] falls back from direct Allocation to RoleAssignment/RoleRealization when that resolves to one performer. Removing a direct allocation can leave the same grouping, reveal another role-derived performer, or leave ambiguity. `allocation_summary == None` can mean mixed/unallocated leaves; it does not identify a unique old performer.
- [Allocation deletion impact][S9] can remove dependent SA PortAllocations and then ExchangeAllocations. Other references such as trace/artifact ownership may also be affected. Editing an Allocation's source preserves its identity but can invalidate existing mappings or participant scenarios. Validate the entire candidate and show real impact; never hide collateral deletion behind a successful drop.
“Out to root” means outside a performer for this task. Source-root work with no effective performer becomes diagram-root work. A decomposed child can still remain inside its work parent. Label that destination **Unallocated — decomposition retained**, and preview actual resulting groups. Moving a child out of its semantic decomposition is a separate explicit action.
## Interaction candidates
Criteria: perform the user's ordinary move directly, preserve domain meaning, make consequences visible before commitment, and use one existing source/history transaction.
| Candidate | Benefits | Tradeoffs |
| --- | --- | --- |
| Dedicated “Assign performer” tool or relationship editor; ordinary drag stays layout-only | Clear mode, straightforward target validation | Adds a mode/menu before the exact gesture the user requested; it leaves ordinary incoming/outgoing drag apparently ineffective. Keep as a keyboard/accessibility alternative, not the primary workflow. |
| **Context-sensitive body drag in Allocation views** | Incoming, between-performer and outgoing movement use one familiar gesture; same-performer movement remains arrangement | Needs stable target hit-testing, explicit preview and ambiguity handling. Recommended. |
| Geometric nesting becomes semantic containment | Superficially simple implementation | Violates work/performer ownership rules, destroys decomposition, and confuses allocation with containment. Reject. |
| Allow composite-parent Allocation directly | Makes bulk dragging appear cheap | Contradicts current source/core semantics and peer issue 4's correction. Reject. |
### Recommended gesture
Ordinary work-body drag in **ProjectionKind::Allocation** selects a semantic destination while moving a ghost. Other projections retain their established layout movement; an explicit Assign/Unassign action can enter the same operation when needed. Provide a discoverable **Arrange only** affordance, also keyboard accessible, so review-layout movement cannot accidentally change allocation.
Capture the accepted document, revision, diagram, canvas epoch, placement/work ID, original geometry, selected leaf set and direct-allocation identities at press. Respect the existing screen-space threshold. Use the press-time projected performer rectangles for hit-testing, excluding the dragged work and its moving subtree: the preview's expanded old enclosure must not chase the pointer and make exit impossible.
A compatible performer header or exposed body highlights with **Assign to Rescue team**, **Move from A to B**, or **Assign 4 leaf activities to B**. Same performer says **Arrange within B**. Exposed blank canvas outside all performer groups is the outgoing destination. A drop over an incompatible object, outside the viewport, or over unrelated overlapping performer rectangles is not an implicit root drop. Nested performers resolve to the most specific unambiguous visible performer; arbitrary paint order must not choose between overlapping peers. The pointer is the destination anchor; show the chosen destination before release, rather than infer it from how much of the dragged box overlaps.
Hovering a work card does not reparent into that work. Ports, links, other-layer performers and hidden objects are not allocation targets. A collapsed performer may be targeted via its visible header; successful drop expands that one target in the same presentation transaction so the work does not disappear. Cancellation preserves the prior fold state.
The preview must show **the candidate semantic grouping**, including any affected composite ancestors. For a single leaf changing allocation, do not relocate an entire target performer's existing contents. Pointer motion changes no accepted data. A valid ordinary release commits one prepared Batch; Escape, hidden/outside release, unfocus or invalid target commits none. Same allocation with changed coordinates is one layout operation; a true no-op adds no history.
## Allocation command semantics
Compute scope from the selected work definition's current same-kind descendant leaves. Do not use visual descendants as the semantic leaf list: folding, unplaced children and mixed performer groups can hide relevant leaves. Preserve every work parent, ID, name, alias, description, work exchange, role assignment, trace, scenario use and unrelated allocation unless a separately shown dependency repair explicitly changes it.
| Starting state | Drop onto performer B | Drop outside performer grouping |
| --- | --- | --- |
| Leaf, no direct allocation | Create one Allocation B → leaf with a fresh stable ID allocated once during preparation. If role-derived responsibility exists, show it; B is an explicit user choice, not inferred responsibility. | No direct allocation to remove. If role-derived grouping remains, show that exact reason and offer its existing role-assignment editing path; do not pretend the work became unallocated. |
| Leaf, direct A → leaf | Edit the existing relation's source to B, retaining relation ID, alias/name/description and target. If A=B, only layout changes. | Delete that exact Allocation after impact analysis. The predicted root/group result must be truthful about any remaining role-derived responsibility. |
| Composite with all current leaves unallocated, or all with one unambiguous direct performer | Apply the preceding leaf rules to **all current leaves** in one Batch. Preview leaf count; keep the composite without direct Allocation. | Remove direct allocations across that leaf set in one Batch, subject to role and dependency checks. Do not delete the work or its decomposition. |
| Composite with mixed performers, partly assigned leaves, or role-derived responsibility | Retain a bounded local impact draft after release: show counts grouped by old performer/unallocated/role-derived status and exact destination. Explicit Apply means assign the displayed leaf set to B. | Retain a bounded draft naming which direct allocations will be removed and which role-derived responsibilities remain. Do not select an arbitrary performer or silently clear role relations. |
Mixed context is not an invalid model, and an explicit destination can resolve it. A source draft containing duplicate direct allocations is different: it must not be accepted as a valid canvas baseline, and a stale drop must not repair it opportunistically.
For direct moves without extra impact, no extra confirmation is needed. If standard Delete would remove IDs beyond the intended Allocation set, or a source change invalidates port/exchange/scenario dependencies, retain a local impact/refusal state with named reasons and a route to the existing repair editors. Never silently delete these dependents or invent replacement ports/channels. Root can later extend that draft to support an explicitly reviewed repair Batch. A role warning allowed by current validation remains advisory; do not turn it into a new metamodel prohibition.
Prepare the entire semantic-plus-placement candidate before acceptance. Compute explicit moved-placement IDs and route deltas from the captured work subtree; do not issue `MoveNode(with_descendants=true)` blindly *after* allocation changes, since its newly computed visual descendants can differ. Preserve hidden subtree placement offsets where applicable. Project the candidate and use existing bounded [insertion adjustment][S11] behavior only for affected collisions; include any resulting node/route/fold edits in the same Batch. If the result still produces an unreadable giant enclosure, the preview fails acceptance and requires local arrangement work, not a misleading success message.
Use existing CreateRelation/EditRelation/Delete/EditNode/SetEdgeRoute/Batch commands and `document.execute`; no schema change or persisted desktop-only grouping map is needed. Creation IDs are reused by retry/Redo. Exact source and Project Undo/Redo must include relations, layout, fold state and authorized impact together. API/text users retain the same semantic operations.
## Production seams and ownership
- **New bounded planner module**, preferably `crates/oa-desktop/src/allocation_drag.rs`: request/destination types, leaf traversal, direct-versus-role provenance, candidate/impact computation and command composition using existing core validators. Keep it independent of Iced input so behavior can be checked directly. This is UI proposal composition; existing core remains authoritative.
- **`diagram.rs`**: replace the bare movement tuple for allocation-capable work with stamped gesture state; stable destination hits, candidate projection, ghost/highlight/text and release intent. Preserve ports, connections, pan and ordinary route editing. Current [release event][S1] has no captured context.
- **Root-owned `app.rs` dispatch**, ideally a small new `app/allocation_drag.rs` handler: admit only the current clean Diagram owner, recheck captured context and exact identities, recompute the candidate against current data, then execute once. The current [MoveNode handler][S2] calls `apply()`; the new semantic drop must **not** auto-apply unrelated dirty properties or source. Reuse the [route context shape][S10], but add view/bounds/camera-lifetime invalidation where needed.
- Existing `projection.rs`, `validation.rs`, `references.rs` and `session.rs` supply semantics and geometry. No planned change to leaf validation or allocation summary. Add focused language/help wording only after root accepts the interaction.
- Coordinate any palette/menu placement with root. `model_menu.rs` dispatches Create child work through `Message::CreateContextElement(work, true)`; leave that peer-owned issue 4 correction and any helpers it introduces alone. `architecture_authoring.rs` separately handles performer-context allocated creation and does not need changes for dragging existing work. Root must keep the new App drag dispatch separate from the peer creation branch when integrating. In particular, transfer of an allocation to the first child must invalidate a previously captured leaf drag. No syntax/source-navigation ownership is acquired.
A source refusal or stale drop retains the accepted model/source/history. A retryable impact/source failure may retain its bounded draft; after revision change, require recomputation and a renewed visible result rather than replaying old commands. Canvas errors must remain visible near the destination and in status, not depend on an offscreen Inspector.
## OA/SA user acceptance
Run the same fixture pattern with OA Entity/Actor + Activity and SA System/SystemActor + Function, at 1100×700 client and a wider window. These are proposed checks, not passing tests.
1. **Incoming/outgoing leaf.** Drag a source-root unallocated leaf into A; see the exact target highlight and nested result. Save/reopen. Drag it out to blank canvas; see A release its enclosure and the leaf remain. Verify decomposition unchanged, one Allocation created then removed, and exact source/model Undo/Redo for each operation.
2. **Reassign and arrange.** Drag A's leaf into B; original Allocation UUID and metadata survive with source B. Move within B and use Arrange only across a group boundary; allocation remains unchanged. Check all other performers, work uses, routes and sibling positions. A stationary click and release on an invalid object add no history.
3. **Decompose then move.** After peer issue 4 creates first/second/grandchild work, move the uniformly allocated composite A → B. Only leaf allocations change; parent allocation remains absent, decomposition and all UUIDs survive. Move one child out: preview and final result must agree about changed ancestor summaries. A semantically nested child is not falsely advertised as source-root.
4. **Mixed and role-derived work.** Drag a composite containing A/B/unallocated leaves; the bounded impact draft shows all three categories. Cancel changes nothing; Apply to a chosen performer affects the exact displayed set. Remove direct allocation from a role-assigned leaf and verify the residual role grouping is explained. Ambiguous roles never select a performer automatically.
5. **SA technical and OA communication dependencies.** Include SA PortAllocation/ExchangeAllocation and participant-bound scenarios, plus OA exchange allocation/role cases. Retarget/remove only when the whole candidate is valid. Extra cascade or invalidated mapping is visible and retained for repair; there is no hidden dependent loss. Exact cancellation preserves every source byte.
6. **Stale and source refusal.** Press, then change owner/view/revision, resize/Fit, open an editor/dialog, begin save or create the child that retires the captured leaf allocation; deliver the old release. No mutation. Inject a source-edit/write refusal; no model/layout/history partial commit, pending unrelated edits survive, and retry uses a freshly validated candidate. Exercise Escape, unfocus and release outside the viewport with actual input.
Native acceptance must verify target visibility, no enclosure chasing, readability, focus and correct recovery in the actual packaged build. Preserve the broader OA/SA goal; closing this specific interaction does not establish complete architecture usability or issue 2 completion.
[S1]: http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/638d06c4e33a1f54203b234d0b49c3ecf551d27d/crates/oa-desktop/src/diagram.rs#L936
[S2]: http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/638d06c4e33a1f54203b234d0b49c3ecf551d27d/crates/oa-desktop/src/app.rs#L2780
[S3]: http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/638d06c4e33a1f54203b234d0b49c3ecf551d27d/crates/oa-core/src/session.rs#L771
[S4]: http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/638d06c4e33a1f54203b234d0b49c3ecf551d27d/crates/oa-core/src/projection.rs#L81
[S5]: http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/638d06c4e33a1f54203b234d0b49c3ecf551d27d/crates/oa-core/src/projection.rs#L541
[S6]: http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/638d06c4e33a1f54203b234d0b49c3ecf551d27d/crates/oa-desktop/src/diagram.rs#L410
[S7]: http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/638d06c4e33a1f54203b234d0b49c3ecf551d27d/docs/language.rst#L424
[S8]: http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/638d06c4e33a1f54203b234d0b49c3ecf551d27d/crates/oa-core/src/validation.rs#L2850
[S9]: http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/638d06c4e33a1f54203b234d0b49c3ecf551d27d/crates/oa-core/src/references.rs#L270
[S10]: http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/638d06c4e33a1f54203b234d0b49c3ecf551d27d/crates/oa-desktop/src/route_edit.rs#L6
[S11]: http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/638d06c4e33a1f54203b234d0b49c3ecf551d27d/crates/oa-desktop/src/diagram.rs#L79