diff --git a/crates/oa-desktop/src/app.rs b/crates/oa-desktop/src/app.rs index ceba0099..f08e7f3a 100644 --- a/crates/oa-desktop/src/app.rs +++ b/crates/oa-desktop/src/app.rs @@ -653,7 +653,15 @@ impl App { } Message::SelectProject => self.select(self.project().id), Message::SelectNode(id) => { - if self.selected_node == Some(id) || self.selected == id { + if (self.selected_node == Some(id) + && self.active_diagram + .and_then(|diagram| self.project().diagrams.get(&diagram)) + .and_then(|diagram| diagram.nodes.get(&id)) + .is_some_and(|node| self.selected == node.element)) + // Defer a placement draft until release: it may change the + // identity captured by the just-started canvas gesture. + || (self.selected == id && self.draft.as_ref().is_some_and(Draft::dirty)) + { return Task::none(); } let original = self.selected; @@ -1107,12 +1115,19 @@ impl App { } else { node }; - self.execute(Command::MoveNode { + if self.execute(Command::MoveNode { diagram, node, position, with_descendants: true, - }); + }) && let Some(placement) = + self.project().diagrams[&diagram].nodes.get(&node) + { + // A drag edits a placement, but the canvas still selects + // the engineering element represented by that placement. + self.selected = placement.element; + self.refresh_draft(); + } } } Message::Zoom(factor) => { diff --git a/crates/oa-desktop/src/tests.rs b/crates/oa-desktop/src/tests.rs index e19cedb5..3cd3c541 100644 --- a/crates/oa-desktop/src/tests.rs +++ b/crates/oa-desktop/src/tests.rs @@ -564,6 +564,62 @@ fn selecting_current_constructors_preserves_payloads() { send(&mut app, Message::Apply); assert_eq!(*app.project(), accepted); } +#[test] +fn dragging_keeps_semantic_selection_and_same_node_remains_editable() { + let mut app = App::with_project(fixture()); + let diagram = app.active_diagram.unwrap(); + let placement = app.project().diagrams[&diagram] + .nodes + .values() + .next() + .unwrap() + .clone(); + let semantic = placement.element; + send(&mut app, Message::SelectNode(placement.id)); + let before = app.project().clone(); + for distance in [40., 80.] { + send( + &mut app, + Message::MoveNode( + placement.id, + Position { + x: placement.position.x + distance, + y: placement.position.y + distance, + }, + ), + ); + assert_eq!(app.selected, semantic); + assert_eq!(app.selected_node, Some(placement.id)); + assert_eq!( + app.draft.as_ref().unwrap().kind, + crate::forms::RecordKind::Element + ); + send(&mut app, Message::SelectNode(placement.id)); + assert_eq!(app.selected, semantic); + } + send(&mut app, Message::Undo); + send(&mut app, Message::Undo); + assert_eq!(app.project(), &before); + // Explicit placement inspection must not make its canvas card unselectable. + send(&mut app, Message::Select(placement.id)); + send(&mut app, Message::SelectNode(placement.id)); + assert_eq!(app.selected, semantic); + send( + &mut app, + Message::Field("/name".into(), "Still editable after dragging".into()), + ); + send(&mut app, Message::SelectNode(placement.id)); + assert_eq!( + app.draft.as_ref().unwrap().inputs["/name"].raw, + "Still editable after dragging" + ); + send(&mut app, Message::Apply); + assert_eq!( + app.project().elements[&semantic].name, + "Still editable after dragging" + ); +} + #[test] fn placement_identity_edit_then_drag_and_diagram_identity_then_arrange() { let mut app = App::with_project(fixture()); diff --git a/harness/PLAN.md b/harness/PLAN.md index 6311977c..e297b325 100644 --- a/harness/PLAN.md +++ b/harness/PLAN.md @@ -4,7 +4,7 @@ Deliver the first release of Arcadia Studio for system engineers: complete Operational Analysis and System Analysis/System Architecture workflows, equivalent graphical and textual models, clear artifact traceability and a deployable/programmatically accessible Rust service. Logical/Physical Architecture and later Arcadia layers are future releases, as the new objective explicitly states. -The authoritative objective is the attachment ending 81e84f53-2b51-4151-9e34-59414bda8b2d/goal-objective.md. The accepted 0.2.0 prototype is the baseline, not proof of this release's completeness. Its source is preserved at D:/CodexBuilds/Capella2-release1-01a06e2e/v2-source-baseline.zip and its existing binary archives remain in dist until replacement passes acceptance. +The authoritative objective is the updated attachment ending 20fca018-f8ce-4cc0-86e7-8ead5d325630/goal-objective.md. It retains the first-release scope and adds explicit modular source/include, drag-selection and directly editable behavior-diagram requirements. The accepted 0.2.0 prototype is the baseline, not proof of this release's completeness. Its source is preserved at D:/CodexBuilds/Capella2-release1-01a06e2e/v2-source-baseline.zip and its existing binary archives remain in dist until replacement passes acceptance. ## Existing architecture and retained decisions @@ -16,6 +16,8 @@ The current forms are a closed typed-record adapter, not a second metamodel. Exp Current priority within milestone2: address the user's diagram/port correction using `release-diagram-port-correction.md`. Separate engineering views, actual owner-bound port geometry and full functional/component-port semantics precede further breadth. Existing R5 state authoring is preserved; it still needs native verification. +Updated priority: fix drag selection and repeated selection immediately; complete the active isolated port/schema3 implementation. Then make behavior diagrams directly editable using shared persisted geometry and ordinary commands, and replace the single huge source editing experience with a modular project/include workflow. These are release requirements, not future limitations. Source projects must preserve identity, precise per-file diagnostics, Git-friendly ownership of declarations, cycle/missing/duplicate include failures, safe local include resolution and GUI/API parity. Behavior acceptance requires actual canvas movement and contextual creation/editing, not only selection plus external menus. Freeze concrete interfaces after read-only exploration before changing the shared schema. + 1. **Release coverage audit and interfaces.** Compare actual core/UI/API with official Capella OA/SA semantics and the new objective. Freeze a coverage table and concrete variant/reference/transition contracts before editing shared interfaces. Distinguish unsupported later layers from missing OA/SA workflows; V2 exclusions are reconsidered. Native audit exercises onboarding/help/authoring at supported sizes. Independent audits have separate file ownership. 2. **Complete engineering semantics.** Fill verified gaps in capability relationships and mission involvement; operational process/functional-chain function/control topology; scenario/state/data constructs needed by OA/SA engineers. Add typed semantic-content drift and reviewed existing-counterpart reconciliation, including reference mapping and explicit dependency/ownership decisions. Every addition has a usable graphical authoring workflow, equivalent source/API representation, meaningful reject/undo/delete/reidentify/transition tests and a worked example. Exact additions and invariants are recorded in the coverage/interface artifact from milestone1, avoiding speculative LA/PA concepts. 3. **Approachable authoring and help.** Replace static help with searchable topic navigation, concise concepts, numbered OA→SA tutorials, related topics and direct workspace actions. Add a focused starting workspace, recent models and practical creation guidance. Improve source authoring with asynchronous versioned lint, semantic warnings, diagnostic navigation and find/go-to tools. Make selection/navigation and hidden/placed model distinctions clear. Add recoverable local checkpoints for unsaved accepted models and drafts; preserve explicit file-save/conflict behavior. diff --git a/harness/STATE.md b/harness/STATE.md index b0fa2ef8..877652e5 100644 --- a/harness/STATE.md +++ b/harness/STATE.md @@ -2,7 +2,7 @@ ## Objective and evidence -Active first-release goal: complete OA + SA/System Architecture, Rust/Iced Windows/Linux, equivalent graphical/source editing, reST contract, traceability, REST and built-in guidance. Objective attachment81e84f53-2b51-4151-9e34-59414bda8b2d. V2 is the preserved baseline, not release acceptance. PLAN.md and release-semantics-audit.md retain the full scope. +Active first-release goal: complete OA + SA/System Architecture, Rust/Iced Windows/Linux, equivalent graphical/source editing, reST contract, traceability, REST and built-in guidance. Objective attachment20fca018-f8ce-4cc0-86e7-8ead5d325630, read fully. V2 is the preserved baseline, not release acceptance. PLAN.md and release-semantics-audit.md retain the full scope. User prioritizes Capella-like hierarchical architecture and correct ports. release-diagram-port-correction.md records the correction; release-port-contract.md is being finalized before implementation. No release completion claim. @@ -53,3 +53,17 @@ Hierarchy worker released app.rs/diagram.rs/tests.rs after fixing semantic selec Latest native checkpoint ready: D:/CodexBuilds/Capella2-release1-01a06e2e/ui-hierarchy-reviewed/arcadia-studio.exe SHA2563603AC957B6E16B4321F7FB7E759B3A2265357679DB8F27DD9ED5642B7E02179. Not launched yet. Old Studio window723086 has dirty marker, so inspect and preserve any unsaved changes before closing (do not infer it is safe from the earlier no-edit state). Typed-port work isolated at D:/CodexWorktrees/Capella2-typed-ports, branch codex/typed-port-contracts, from c20a207. port_contract_design owns core model/ports/validation/references/session/transitions/demo/projection + non-language tests; capella_startup_diagnosis now owns persistence/migration/language/server/API/reST + source/migration tests. They coordinate shared schema but never edit the same files. Root main remains buildable during their implementation. Temporary model-capacity errors were retried on the same agents; both resumed. Full core port/schema3 acceptance pending. + +## Updated objective and drag bug + +Authoritative objective is now attachment20fca018-f8ce-4cc0-86e7-8ead5d325630 (read fully). It retains first-release scope and adds modular source projects/includes, stable drag/reselection, and directly editable behavior/scenario diagrams. Root fixes drag; hierarchy_port_review is read-only mapping direct behavior manipulation/persisted geometry interfaces. Active port work remains aligned. + +Root verified drag bug: MoveNode returned a placement identity, dropping semantic highlight; SelectNode returned early for that same placement. Handler now selects the moved semantic element and restores its property draft; same-card click from a clean placement inspector restores semantic selection. Dirty placement identity edits defer to gesture release so existing remap behavior survives. Focused repeated drag/reselection/property-edit/undo regression and existing placement-identity regression pass. Native build ui-hierarchy-reviewed replaced before first launch, current SHA25630FA95CA9C606B20EAA5B4FA08AE04EB47CCB1A2498C05C0C26F2B049F006BE5; native checking now. + +Original Capella: created component exchange C1 between Aircraft and IFE System; it automatically made ComponentPorts. Source CP1 properties explicitly show provided/required interfaces, allocated/realized ports, Standard/Flow kind and Unset/In/Out/InOut direction; generated source is Flow/Out. Opened its allocated-port chooser, containing function ports under Aircraft-assigned functions. No port allocation committed yet; chooser remains open. Component Exchange tooltip requires same port kind; main contract amended to reject typed Standard/Flow mismatch, both workers notified. Unknown screenshot/foreground mismatch interrupted picker selection; no unchecked retry or guessed input. Capella later restored at1008×762 with modal partly outside main window; use full dialog screenshot only after fresh valid observation. + +## Drag selection verified; typed-port integration next + +Root full desktop71 tests and strict desktop all-targets Clippy passed (session60951). Reopened current SHA30FA95CA checkpoint through native CUA, fresh window527250. Dragged an initially unselected Report distress activity, clicked the same moved card, edited its name to Report distress at sea and applied: semantic highlight and properties remained correct throughout; containing participant expanded. Save As is pending, not verified: the helper targets a16×16 primary capture for modal1706878 alongside a1186×713 related screenshot and failed UIA set_value/coordinate operations; a later refresh detected user input. Do not claim the fixture exists, overwrite or discard unsaved changes. Both prior Studio windows were absent on fresh inventory, so old unsaved geometry is not assumed recoverable. Current default native layout verified; current minimum resize still pending. + +Port core0d14438 and migration/source/APIb9f88ce are committed on codex/typed-port-contracts, isolated worktree clean. Integrate together, retaining main hierarchy reflow/allocation_summary changes. Handoffs release-port-core.md and release-port-migration.md record actual tests and APIs. Core worker reported125 total core tests including9focused port tests; migration worker31focused core+20server tests and strict Clippy. Root integration checks, desktop typed controls/glyphs and native port acceptance remain pending. Migration worker now independently reviews core ports; hierarchy reviewer designs modular source projects. Direct behavior editing design reuses contextual Diagram placements; interface adoption/implementation remains ahead. diff --git a/harness/release-capella-workflow-benchmark.md b/harness/release-capella-workflow-benchmark.md index beb1505c..e2ba98e3 100644 --- a/harness/release-capella-workflow-benchmark.md +++ b/harness/release-capella-workflow-benchmark.md @@ -97,3 +97,13 @@ Pressed **F9** on the newly created exchange-item allocation. Semantic Browser o This pass materially advanced all five engineering feature comparisons with actual creation/editing, and exercised a subset of navigation; it is still **not** a completed six-area benchmark. Remaining direct comparisons include participant/include/extend variants; complete AND/OR/iterate branch topology; OA process equivalents; scenario operands/context/correspondences; state transition edge cases; data properties and categories; show/hide/selection productivity; and a current transition-preview round trip. Controls merely seen in a palette are distinguished from successfully operated controls above. No conclusions about Studio passing these acceptance workflows are implied. CUA handed back to the lead for Studio verification. Original Capella remains open, window **524804**, launch exec session **55359**, maximized at 2560x1392. The active tab is the CDB with the allocation selected and Semantic Browser visible; other edited benchmark diagrams remain open. Changes are **unsaved** in the disposable sample. Re-inventory windows before future input; these are continuation hints, not durable identities. All screenshots were captured and inspected through the native Computer Use tool; no screenshot files were saved. No Studio code or build was changed by this benchmark agent. + +### System architecture and actual port authoring (lead, 2026-09-05) + +Reopened the SA workflow and **[SAB] High Level System Overview with some FCs**. Aircraft, IFE System, Passenger and Cabin Crew are nested participant containers; allocated green functions sit inside them, and italic parent functions summarize their allocated descendants. Functional exchanges attach to small function-boundary ports. This reinforced the distinction between direct work allocation and inferred summary nesting. + +Opened Send Audio Announcement's **FunctionOutputPort FOP5** properties: Outgoing Exchange Items and Realized Function Output Ports are explicit fields; it has no generic InOut/function-interface contract. Created **FunctionalExchange38** by choosing the palette tool then Provide Navigation Data and Determine Operating Profiles. Capella created source **FOP1** and target **FIP3** automatically; Semantic Browser identified their actual function owners and FE endpoint references. Modeling Accelerators separately offers Propagate Port Realizations, Propagate Exchange Items to Function Ports and Synchronize Exchange Items and Function Ports. Those accelerators were observed, not run. Allocation Management opened an empty component-exchange chooser and was cancelled. + +Created **C1** with Component Exchange between Aircraft and IFE System. Capella automatically created their ComponentPorts. The tool's tooltip requires matching port kinds and complementary Flow orientations. Source **CP1** properties show **Standard/Flow**, **Unset/In/Out/InOut**, Provided Interfaces, Required Interfaces, Allocated Ports and Realized Ports. The generated source is Flow/Out. Opened its Allocated Ports picker: available function ports belong to functions assigned to Aircraft (including the newly created Provide Navigation Data FOP1). No allocation was committed; the picker remains pending. Screenshot identity/foreground errors interrupted further input, so component-exchange generation accelerators and allocation completion are not claimed. + +The adopted Studio port contract uses separate typed function and component variants, mandatory FE endpoints, independently oriented component exchanges, explicit port allocations and preserved Legacy migration. A typed Standard/Flow mismatch is rejected following the observed native restriction. This evidence does not itself establish Studio acceptance. Original sample changes remain unsaved in the disposable workspace; fresh inventory is required before continuing. diff --git a/harness/release-port-contract.md b/harness/release-port-contract.md index 088a2fd5..11d80ba1 100644 --- a/harness/release-port-contract.md +++ b/harness/release-port-contract.md @@ -71,7 +71,7 @@ RelationBody::PortAllocation { - Provided interfaces, required interfaces, function item contracts, component kind, and component orientation are separate facts. Keep provision/requirement roles visible and independently editable. Their union may describe potential carried items, but cannot prove role matching. New port-level provision/requirement relations use Component ports; participant-level relations retain their current meaning. Preserved relations on Legacy ports, or resolved function ports retaining `legacy`, remain visible compatibility declarations with warnings and do not replace function item contracts. Ordinary creation does not offer interface roles on function ports. - For a Standard connection, stored endpoint order does not establish provider/consumer roles. A required interface is satisfied by a partner-provided identical interface; R6 may also use its explicitly compatible interface specialization. Unsatisfied requirements are located completeness warnings. Never infer that Out provides or In requires: Operation call/reply direction is independent of those roles. Participant interface declarations are not silently inherited by every owned port. - At a component port with explicit provided/required interface declarations, carried items must fit their effective interface-item union using `item_satisfies`. Absence of declarations means unspecified compatibility and may warn; an explicitly empty interface does not accept arbitrary items. Do not manufacture interface relations to make a connection pass. Legacy uses its preserved interface association and the old item checks until resolved; after resolution that association is displayed as preserved/unclassified data and is not another active typed constraint. -- `BoundaryExchange.oriented` is independent of port kind/orientation. New Standard connections default false; directional Flow connections default true. For oriented Flow endpoints, source must permit Out and target In. A known contradictory direction is an error; Unset warns. For an unoriented connection between Flow ports, at least one communication direction must be possible: In-only/In-only or Out-only/Out-only conflicts. Standard has no Flow direction. Mixed Standard/Flow connections warn that transport compatibility is unspecified; they do not assert an adapter. +- `BoundaryExchange.oriented` is independent of port kind/orientation. New Standard connections default false; directional Flow connections default true. For oriented Flow endpoints, source must permit Out and target In. A known contradictory direction is an error; Unset warns. For an unoriented connection between Flow ports, at least one communication direction must be possible: In-only/In-only or Out-only/Out-only conflicts. Standard has no Flow direction. Typed Standard/Flow endpoints must have the same kind; mixed connections are structural errors. Preserved Legacy endpoints retain their explicit compatibility warnings. This follows the native Capella Component Exchange tool, which requires matching kinds; do not assert an implicit adapter. - A BoundaryExchange connects different participant owners. Typed component endpoints are SA-only. Preserved OA boundary exchanges retain Legacy participant endpoints and an explanatory compatibility warning. - PortAllocation is same-layer Component-to-typed-FunctionPort, unique per pair. Its function must have an actual work Allocation to the component owning the allocating port. A missing/contradictory allocation is an error for this new relation; the authoring action must resolve that work allocation first. Do not use computed allocation-summary nesting as evidence. Flow In permits input, Out output, InOut either, and Unset warns. Standard may allocate either direction. Multiple allocations are allowed when these invariants hold; no unsupported one-to-one cardinality is imposed. - A typed SA ExchangeAllocation requires both boundary endpoints to allocate the corresponding FE ports through explicit PortAllocation relations. An unoriented boundary can correspond in either stored order; an oriented boundary must correspond in its direction. The boundary item set must cover the allocated FE items using the same compatibility helper. Legacy exchange allocations retain prior owner/item checks and a warning that typed port allocation remains unresolved.