Files
ARCADIA-Studio/harness/saved-group-removal-evidence-20260925/semantic-review.md
T

16 KiB

Saved Architecture / State aggregate model-removal semantic review

Read-only critique of afcea12cd96dcc55c42006e65a5ab5a6212c54b7 in C:/ar-scenario-9e8r6t, 2026-09-24. Scope: issue 29 saved-view aggregate Delete-from-model, with group Hide retaining its existing placement-only meaning. This is design/source evidence, not test or native acceptance. Initial critique was read-only. Parent subsequently authorized only diagram/group_removal/conditional_tests.rs; three independent conditional-support and validity falsifiers were written there. No Cargo/GUI, commits, or Gitea operations were performed.

Use an explicit Delete selected from model… action with one aggregate review; Shift+Delete can invoke the same captured action. Keep unmodified Delete and Hide selected placements as placement-only removal. Never switch unmodified Delete from Hide to model deletion merely because an edge/row/port is added to the selection. This follows the current contract (harness/multiselect-contract-20260923.md, Related group actions), avoids surprising meaning changes, and fits the existing singleton distinction. Current architecture interception is diagram/multiselect.rs:179; State interception is behavior/state_canvas.rs:878; the existing group menu placeholder is model_menu.rs:512.

Admit every original exact visual target against one accepted-model projection and one captured selection before reducing the set:

Exact target Semantic Delete ID Required evidence
Placement(id) Saved diagram node.element Exact node ID is present in the specified diagram and its final visible projected nodes; element exists. Never delete the placement ID for this action.
Port { port, placement } port Exact projected port+owner-placement pair exists; stored element is a Port owned by that placement's element. Never promote the port to its owner.
Edge(id) id Exact projected edge exists AND ID is an actual stored relation or trace. A TraceLink is legitimate: Traceability projection emits trace IDs, not relation IDs.
StateRow { placement, relation } relation visible_row_target confirms the exact row occurrence; stored relation is StateAction or internal StateTransition. Delete the maintained relation, never its referenced activity/function.
Whole, AllocationGrouping, Process/Scenario targets Refuse complete operation These are not admitted saved-selection action targets at this source. Do not silently discard them or translate navigation highlight identities.

app/multiselect.rs:67-88 is the authoritative existing final-projection visibility mapping. diagram_usage.rs:112 defines the richer navigation Target union; union membership is not action permission. AllocationGrouping is currently navigation-only (visible() rejects it); a future explicit unallocate action must establish exact selected grouping admission independently. Allocation work placement deletion still means deleting the work model element, including when its visible parent is a derived allocation summary: it does not mean deleting the performer or a manufactured aggregate Allocation relation.

Saved projection.rs:397-479 constructs relationship edges from stored relation records, and :487-520 constructs trace edges from stored trace records. There is no synthetic edge deletion identity in this saved projection path. Reject missing identities defensively. Expanded Process preview/contextual targets have their own adapters and must not be inferred from generic Edge IDs. A stored ContextualLink that actually appears as a saved edge is a maintained relation, not an ephemeral preview identity.

behavior/state_canvas.rs:483-594 defines row semantics, including exact-placement validation and current relation source matching. Dedicated State projection has no component/function ports (oa-core/src/projection.rs:526); a forged State Port target must therefore fail visibility even when the stored port exists elsewhere.

Normalize semantic identities only after full admission

Preserve all exact visual targets in the captured Snapshot and deduplicate only semantic delete IDs. Current core validation rejects duplicate same-element placements within one diagram (validation.rs:795, duplicate_placement); never weaken that invariant to demonstrate deduplication. The same element can be placed in different views, and deletion affects all of those placements. Reject repeated exact typed targets before mapping. A review can accurately distinguish selected diagram objects from model subjects; use unique IDs when marking selected impact records.

Ancestry-only normalization is insufficient. Core deletion also removes incident relations, port-bound functional exchanges, exchange occurrences, port/exchange allocations, trace links, artifact links, diagram-owned placements, and diagrams tied to a deleted State machine or Scenario (oa-core/src/references.rs:322-423). Selecting owner+port+edge, state+action-row, or traced object+trace must not send an invalid second Delete after the first cascade removed its ID. Command::Delete explicitly errors for missing identities (session.rs:674-683).

Chosen bounded strategy (reviewed in new planner source): validate/admit all targets on the original project; calculate each deduplicated semantic ID's original full deletion_impact; repeatedly choose the remaining ID covering the largest number of remaining selected IDs (stable ID tie-break), append one Delete, and subtract covered selected IDs. Execute the collected single Batch against the original project using the actual core pipeline. Never singleton-validate intermediate candidates. Assert every selected semantic ID is absent and all resulting identities existed originally.

I support this strategy for current pure-delete semantics. Ordinary cascades are monotone reachability through the original dependency structure. Surviving-reference clearing does not add cascade dependencies. The only support-sensitive deletion condition is ExchangeAllocation endpoint-allocation coverage; core explicitly defers that cleanup until batch finalization (references.rs:430-467). Consequently that combined loss cannot unexpectedly delete an upcoming selected command before its turn. Original full-impact coverage may safely omit individually covered conditional dependents because a pure-delete batch creates no replacement facts. This argument does not extend to batches with replacement/rewiring commands; revisit normalization if the operation gains those commands.

Do not treat the union of original singleton impacts as final review impact. Final execute_batch performs inheritance pruning and reference/view cleanup, so its actual candidate is authoritative. An attempted stronger alternate-pairing counterexample was falsified by existing validity constraints: validation.rs:2932 requires different BoundaryExchange participant owners, ports::actual_performer resolves one performer per function, and duplicate same-endpoint PortAllocations are forbidden. Therefore two simultaneous complete direct/reverse mappings cannot coexist in a valid model; do not relax validation to make a hypothetical example pass.

The independent conditional_tests.rs valid fixture instead uses two actual performers and selects both endpoint PortAllocations, whose cascades overlap on the same deferred ExchangeAllocation. It compares the complete result to a literal independently edited Project, varies IDs and click order, and preserves unrelated authored route metadata. A second test also selects the visible functional exchange, combining direct and deferred removal of that dependent. A third asserts rejection of the invalid dual-mapping fixture. ExchangeAllocation itself has relation endpoints, so it is not a visible selectable saved edge in this fixture; do not fabricate a selectable Edge target for it.

Review actual records and preserve transaction lifetime

Compute removed IDs as original identities minus final candidate identities. Project::identities includes placements, diagrams, artifact links and traces (model.rs:1787-1804). Compute changed IDs only for surviving unequal records across elements, relations, diagrams, artifact links and traces; additionally compare surviving embedded diagram nodes. Parent diagram and changed embedded placement are distinct record rows, so describe counts as records rather than semantic elements. Keep removed and changed sets disjoint. Diagram route/filter/anchor changes are represented by changed diagram records because they have no independent model identity.

Deleted StateAction/internal-transition rows preserve referenced work and states unless those are separately selected or removed by another selected ancestor. Removing a State clears/revises references in surviving Scenario state occurrences rather than claiming all references are removed. The core clears many surviving references and transition trigger/effect lists (references.rs:487-618), may leave a “Removed trigger…” replacement marker, and prunes contextual payload values. Review these actual changed records; a list of only deleted objects is materially incomplete.

Deleting a trace removes only that trace. Deleting one traced counterpart removes its trace links but preserves the opposite-layer counterpart under established core semantics (references.rs:322, :401-408). Do not promise every opposite-layer object is preserved if the user explicitly selected both counterparts. Suggested disclosure: “Traced counterparts are preserved unless selected or owned by another selected object.”

Retain the original document-instance, revision, surface, canvas epoch, selection generation/ordered targets/primary, gesture/input lifetime, and modal token. Admit before any source interaction, selection reconciliation, editor cancellation or modal-state mutation; revalidate when confirming. Check raw source/property drafts, active rename/editor/gesture/pending behavior, and action tool mode. Existing diagram_removal::enabled, Selection::matches and Process/Scenario captured-removal adapters are useful patterns, not justification to omit saved-view gesture checks. Changing primary away and back, selection remove/re-add, model undo/reapply, or active view switch must not revive an old request.

Commit through exactly one Document::execute(Batch); its source update can still fail after a valid core preview (document.rs:322-334). On failure preserve accepted model, source bundle, selection, revision and Undo/Redo history; do not clear the group until successful commit. Cancel preserves the selected set and source. Successful delete reconciles to a surviving safe owner/view and supports one-step Undo/Redo. The review should not promise automatic restoration of transient selection unless implemented and tested.

Falsifier cases to prioritize

  1. Invalid same-element duplicate placements refuse as duplicate_placement; valid different selected elements with additional placements in other views delete every placement of the selected semantic objects. Group Hide still removes only selected placement records and retains model identities.
  2. Selected semantic ancestor+descendant with IDs in both traversal orders; owner+its port+incident functional exchange; State+its action/internal-transition row; element+incident trace. No double-delete failure or silent partial operation. Add an independent valid member to each.
  3. Edge-only and mixed node+trace selections in Traceability. Trace-only deletion preserves both counterparts; deletion of one counterpart preserves the unselected other; selection of both deliberately removes both.
  4. State action/internal transition rows referencing work used elsewhere. Row-only model deletion preserves referenced work, states, other rows and views; row+state union deletes all actually covered rows once. Folded/reparented/changed-source rows and a forged placement pair refuse before mutation.
  5. Exact Port owner mismatch; stale hidden edge; missing semantic ID; AllocationGrouping/navigation focus; Whole and foreign Process/Scenario target mixed with a valid saved placement: every case refuses the complete set, preserving histories and drafts.
  6. Allocation work nested visually under a performer (including summary parent) removes work, not performer or fabricated allocation. Removing selected work/ports includes actual allocation-dependent cascades. Select both required port allocations whose conditional cascades overlap on one ExchangeAllocation; add the visible functional exchange as an explicit direct cause and vary ID order. Do not fabricate an invisible ExchangeAllocation edge.
  7. Two individually problematic deletions that form a valid union, and a union that violates a remaining invariant: only final candidate semantic validation, all-or-nothing source/document transaction. Coverage planning must never commit or per-singleton-validate.
  8. Updated survivors: Scenario lifeline/action/state references, State transition trigger/effect records, process step order, diagram routes/filters/port anchors, artifact links, source layouts. Independent before/after expected records confirm removed and changed review sets; do not just compare planner to its own output.
  9. Mixed target group plain Delete remains safe/refuses Hide; explicit Delete-from-model opens aggregate review. Right-click an unselected object must not accidentally delete only that object or substitute it into a captured group.
  10. Cancel, stale Begin, stale Confirm, duplicate Confirm, primary ABA, selection ABA, view/document switch, raw source/property draft, inline editor, live drag/pan/route/port edit, source rename and busy I/O. Assert zero source/history/selection changes on rejection; no action through a newer modal token.
  11. Successful real source save/reopen and single Undo/Redo recover the entire model/source bundle, including other views and opposite-layer records. Force a source writeback/update failure after valid semantic preview and verify atomic preservation.
  12. Native review at ordinary window size with enough removed/changed records for paging/search, long labels, duplicate names and other-view placements. The total count stays aggregate under filtering; every effect is reachable; confirm/cancel remain visible; the action clearly says model deletion rather than Hide.

Saved deletion can change Process/Scenario definition interpretation indirectly by deleting exchange occurrences or links. Actual record review must disclose those owner changes. A stronger derived-effects/caller review can reuse the Process removal concept, but should not claim complete propagation or semantic stability from unchanged stored caller records.

Decision

Prefer the explicit aggregate model-delete action. Reuse core deletion and one prepared Batch; add no new wire command or independent cascade rules. The principal implementation risks are collapsing visual and semantic identities too early, admitting a valid subset, ancestry-only normalization, excluding legitimate trace edges, understating changed survivors, and expiring or executing requests against the wrong input lifetime. The source supports this direction; runtime acceptance remains for the parent to establish.

Reviewed follow-up policy: harness/saved-group-removal-policy-20260925.md and docs/language.rst section 8.1 agree with this recommendation, including duplicate-placement validity and atomic source synchronization. One concrete planner mismatch found during review was absent rejection of exact duplicate Target entries; reported to implementer before testing. The planner otherwise matched the inspected admission and impact semantics. Test source is unexecuted pending parent validation.