11 KiB
Process group adapter candidate
Read-only Astra investigation against the State follow-up working tree above 7e348d967d1787c052a145b7448636613a6a7054. This is a proposed next adapter, not implementation, accepted semantics, or verification. Live ownership and priorities remain in Gitea #29. No source, build or GUI change accompanied the investigation.
Representation facts
diagram_usage.rs already defines Surface::Process(owner), exact ProcessOccurrence(OccurrenceEndpoint { references, occurrence }), local ProcessLink, and qualified ProcessPreviewLink targets. Local cards are semantic occurrences in owner steps; they reference reusable definitions and are not saved diagram placements. Different reference paths to the same defining occurrence are different selected targets. Legacy derived OrderedPath arrows lack relation identities: do not fabricate editable IDs or substitute endpoints.
topology/usages.rs::Graph::usage_bounds provides exact displayed-target visibility, including bounded qualified previews. Hidden preview tiles do not fall back to their outer reference. Its approximate reveal rectangles are not adequate edge hit tests. Qualified preview content stays read-only until its definition is explicitly opened.
Movement candidates
| Candidate | Assessment |
|---|---|
| Persist arbitrary XY | Conflicts with derived process topology and needs new schema; reject for this adapter. |
| Sequential singleton reorder | Produces click-order-dependent layouts and does not define a simultaneous operation; reject. |
| Stable block within one original column | Candidate: preserves existing topology and uses one existing SetSteps command. |
| Rewire links during a cross-column drag | Alters process execution meaning; requires a separate capability and explicit interaction. |
Existing topology/direct.rs::reorder verifies local contributions and equal original graph X-columns, then validates SetSteps. Graph::expanded_qualified derives ranks from sequence links and legacy order, with steps supplying vertical order; cyclic fallback can depend on enumeration order.
The proposed pure planner admits the whole nonempty set only if every target is a visible local occurrence with an empty reference path and belongs to this owner. Selected IDs and the destination must share one original column. Build the block in original steps order, then use the column-slot permutation below: preserve other-column indices and unselected order within this column. Object-anchored drops on selected items are no-op; a raw gap is a separate API. Check the complete rank map remains unchanged, especially cycle fallback. Distinguish no-op from a command so it creates no source/history entry. Preview and commit must consume this same planned order; do not freely translate cards.
Before-card only could reuse existing behavior but makes moving to the end awkward. Before/after slots are the preferred candidate, subject to independent review and actual interaction testing. Participation of each occurrence-body type also needs a precise decision.
Hide and removal
Process has no saved placements and therefore no existing Hide operation. Explain that limitation; do not silently substitute semantic deletion or add persisted hidden cards without a separate design decision.
Homogeneous local-occurrence removal should present one aggregate impact review and apply one Batch(Delete(...)). Core deferred deletion already supports union cleanup. Preserve referenced work, exchanges, reused process definitions and opposite-layer counterparts. Initially refuse qualified or mixed sets in full; local-link-only deletion can be a separate extension. Never invoke singleton deletion once per member. Capture document, revision, surface and selection generation through confirmation, revalidate the whole set, and preserve pending property/source/forms.
Implementation boundaries and falsifiers
Extend app/multiselect.rs with Process dispatch and exact primary paths, avoiding the assumption that every context is a saved diagram. Use app/process_canvas.rs for captured adapter commands. The input and reorder planner belong in behavior/topology/direct.rs; graph/render changes in topology.rs; exact visibility in topology/usages.rs; stable controls in topology/view.rs. Process currently lacks the needed canvas right-click branch, so contextual Add/Remove needs explicit transport into model_menu.rs. Aggregate confirmation belongs at app/diagram_removal.rs and its view. Reject stale and legacy singleton commands before App's shared side effects.
The current shared group gesture requires saved placements and an XY anchor; reuse its lifecycle concepts, not that constructor unchanged. Compare a small shared threshold/cancellation component with a Process order-specific gesture before introducing abstraction.
First useful outcome: exact local/qualified/link selection with whole-set refusals, plus one atomic same-column local-occurrence reorder and one Undo/Redo. Aggregate removal remains separate acceptance if omitted from that outcome.
Tests must independently assert source-order blocks from noncontiguous reverse-click selections; unchanged other-column indices and unselected order within the affected column, relations and reusable definitions; identical referenced work represented by distinct occurrences; distinct qualified paths and collapse visibility; full refusal of cross-column/mixed/stale sets; no-op history; ordered pointer/focus/Shift/cancellation/camera behavior; no primary-only reconnect bypass; OA and SA, legacy exchange order, explicit branches and cyclic fallback. Native slot feedback, stable canvas/camera, source save/reopen and one-step history are required beyond compilation.
Independent critique: revise before implementation
A fresh read-only Astra review found a concrete defect in global block splicing. Given steps [a,u,b,v,c], one displayed column [a,b,c], and selected {b,c}, dropping after a is visually a no-op. The proposed global splice produces [a,b,c,u,v], changing source/history without a visible change. Equivalent before/after positions in the same displayed gap must have one interpretation.
The revised candidate is a column-slot permutation: extract this column's order from original steps, remove the selected members, normalize the drop to a gap in the remainder, insert the original-order selected block, then write the resulting column order back into this column's original steps indices. Other-column indices remain exact; unselected relative order within the affected column is preserved. This deliberately replaces the earlier all-unselected-global-order condition. Return no command when column order is unchanged, and verify the complete ID-to-rank map remains unchanged before accepting SetSteps. Local Action, Exchange, Control and SequenceReference occurrences are proposed participants; qualified descendants and links are whole-set refusals. This revision still requires an independent pure experiment before UI implementation.
Scope correction: legacy ordered-path nodes have successive ranks, and cycle-blocked nodes receive distinct fallback ranks (topology.rs rank computation). A multiple selection of those nodes cannot satisfy same-column admission. Test refusal and unchanged execution meaning rather than claiming useful reordering of those sets. A graph containing a cycle can still admit a separate acyclic peer group.
Removal has an additional semantic consequence: behavior.rs derives explicit-versus-legacy interpretation from remaining occurrence kinds and SequenceLinks. Deleting action/control from [action,exchange1,control,exchange2] without links leaves an exchange-only sequence with implicit ordered-linear meaning. Aggregate review must expose this transition or initially refuse it. Include caller-owned ContextualLinks targeting removed occurrences in the impact union (references.rs cleanup), not just local links. See the presentation-versus-legacy distinction in docs/language.rst.
Smallest production experiment: independent OA/SA fixtures with interleaved steps and different card heights; reverse-click selection; before-first/after-last and equivalent gaps; already-positioned no-ops; literal expected steps; complete Project equality outside steps; unchanged ranks; exact source roundtrip and one Undo/Redo. Add legacy and cycle refusal plus acyclic peers beside a cycle. Separately demonstrate deletion-induced mode switching before designing confirmation. These Rust/application checks have not run yet.
Bounded permutation experiment
Executable exploratory model and results isolate the order transformation from production architecture. An independent Astra investigator implemented it; the parent read both scripts and reran them successfully. The experiment covers 214,990 column cases and 861,096 plans against a four-node graph rank model, with no invariant failures. Its modeled ranks and sentinel serialization do not execute the Rust layout, source writer or history.
An object-anchored Before/After interface can keep selected-target no-op without losing changed destinations: all remainder gaps were reachable using unselected anchors in 2,036 bounded subsets. Raw-gap normalization is different: in [a,b,c,d], selecting {b,d} and normalizing Before d gives [a,c,b,d]; selected-target no-op keeps the original, while After unselected c reaches the changed order. This supports the simpler selected-target no-op interaction. Block contiguity applies to an admitted planned move, not to that no-op. Actual pointer feedback, production graph admission, serialization and history remain unverified.
An independent critic matched the experiment's rank algorithm to Rust and found no counterexample under the stated valid-input assumptions. The review prompted an explicit five-node changed group beside a cycle; four-node enumeration could only cover singleton movement or unchanged whole-peer blocks there. It also identified a compatibility choice: current singleton direct::reorder globally splices, so moving b before a in [a,u,b,v,c] writes [b,a,u,v,c], while this candidate writes [b,u,a,v,c] with the same display. Prefer one column-slot planner for both singleton and group reorder, preserving unrelated column indices consistently. This would intentionally revise singleton source ordering and requires production regression/roundtrip/history checks; no such migration is implemented here. Retaining global singleton splice was rejected as two source transformation rules for the same visible operation. Native anchor reachability and selected-target guard execution remain separate checks.