Files
ARCADIA-Studio/docs/v2-interface.md
T

12 KiB

V2 integration interface — frozen core skeleton

crates/oa-core/src/model.rs now contains the exact public schema-2 declarations. This file records integration contracts; Rust declarations are authoritative. All new model fields are required in schema-2 JSON; schema-1 migration constructs them explicitly.

  • Project {schema_version,id,alias,name,description,elements,relations,diagrams,artifact_links,traces}. Project::empty() gives empty maps and no invented SA system. SCHEMA_VERSION = 2.
  • One global UUID and alias namespace includes project, elements, relations, diagrams, diagram nodes, artifact links and traces. Helpers: valid_alias, reserved_alias, Project::identities, contains, fresh_alias(name,fallback,id).
  • Element {id,alias,name,description,parent:Option<Id>,body:ElementBody}. ElementBody::Oa(OaBody) | Sa(SaBody). Kind/layer are derived through .kind() / .layer(); no .kind or .position fields remain.
  • OaBody: Entity, Actor, Role, Activity, Capability, Process{steps}, Shared(SharedBody). SaBody: System, Actor, Function, Capability, Mission, FunctionalChain{steps}, Shared(SharedBody).
  • SharedBody: ExchangeItem, DataType, DataField, Interface, Port, Scenario, Lifeline, Occurrence, StateMachine, Region, State (kind distinguishes State/Mode/Initial/Final), Constraint. Payloads and enum spelling are in model.rs. Common .shared()/.shared_mut() and .steps()/.steps_mut() accessors support property forms.
  • steps contain occurrence ELEMENT IDs, never relation IDs. An occurrence is parented by its process/chain/scenario/branch. Its Exchange payload references a relation. Lifelines are elements parented by a scenario. StateMachine -> Region -> State/Mode/Initial/Final uses parent ownership, with optional nested regions under state/mode.
  • Relation {id,alias,name,description,body:RelationBody} exposes .kind(), .source(), .target(). Body exposes .endpoints(), .set_endpoints(a,b), .items(). RelationBody::new(kind,source,target) creates empty/default payload fields.
  • V1 Contribution maps to CapabilityInvolvement{source,target}; V1 Realization to ChainInvolvement{source,target}. Allocation/Interaction retain spelling; Interaction includes an items: Vec<Id> field.
  • Diagram {id,alias,name,description,layer,projection,nodes}; ProjectionKind: Overview, Decomposition, Allocation, Traceability. Traceability accepts both layers; other views are layer-filtered. NodePlacement {id,alias,element,position,size,collapsed} has no description or parent. Absolute coordinates, positive finite size. At most one placement per element per diagram.
  • ArtifactLink {id,alias,name,description,owner,relation,uri,revision:Option<String>,fragment:Option<String>}; owner is any existing model object. Preserve URI/revision verbatim; never fetch during validation.
  • Trace {id,alias,name,description,oa,sa,kind,baseline:Option<TraceBaseline>}. Canonical OA and SA endpoints can reference elements or relations. Baseline contains oa and sa TracedProperties{name,description} only, no live UUID references.

Reference-valued fields

  • Element.parent; process/chain/scenario.steps; occurrence Branch.occurrences; Fragment.branches.
  • DataField.type_ref only when TypeRef::Named(Id).
  • Interface.items; Port.interface; Scenario.context; Lifeline.represented.
  • Occurrence Exchange.exchange/sender/receiver; Action.action/lifeline; State.state/lifeline.
  • Constraint.constrained.
  • All RelationBody.source/target; exchange variants.items.
  • NodePlacement.element; ArtifactLink.owner; Trace.oa/sa.
  • Map keys, all record id fields and diagram-node IDs are identity fields, not ordinary references.

Option<Id> uses None for incomplete drafts; warnings explain missing references. Existing-but-wrong-kind or dangling Some values are structural errors. Ordered vectors preserve order and repeated use through distinct occurrence IDs. No dual ownership fields exist.

Command/session API

Commands derive Clone/Serialize/Deserialize. Public execute_batch(&Project, &[Command]) -> Result<Project, ModelError> clones, applies all operations, validates once, and returns the accepted candidate without mutating input.

Core mutation commands: Replace(Project), CreateElement(Element), EditElement(Id,Element), CreateRelation(Relation), EditRelation(Id,Relation), CreateDiagram(Diagram), EditDiagram(Id,Diagram), CreateArtifact(ArtifactLink), EditArtifact(Id,ArtifactLink), CreateTrace(Trace), EditTrace(Id,Trace), CreateNode{diagram,node}, EditNode{diagram,original,node}, RelocateNode{node,diagram}, EditProject{id,alias,name,description}, Reparent{element,parent}, Reidentify(Id,Id), Rename(Id,String), Describe(Id,String), SetAlias(Id,String), Delete(Id), Batch(Vec).

RelocateNode { node: Id, diagram: Id } moves the existing placement between diagrams without deleting it or pruning references. Identity, alias, geometry, collapse state and attached artifacts survive. The transaction rejects duplicate element placement or incompatible target layer. Relocation into the same diagram is a no-op. Reparent to the same parent is also a no-op, preserving ordered occurrence/branch membership and history.

Convenience commands: Add(Kind), AddElement{kind,layer,name,parent}, Connect(RelationKind,String,Id,Id), AddStep(sequence,exchange), RemoveStep(sequence,index), MoveStep(sequence,from,to), SetSteps(sequence,Vec), MoveNode{diagram,node,position,with_descendants}, Layout(diagram).

Session::try_new(Project)->Result<Session,ModelError>, Session::new(Project)->Session (validated convenience, panics on invalid input), project()->&Project, revision()->u64, execute(Command)->Result<Option<Id>,ModelError>, execute_many(&[Command])->Result<(),ModelError>, undo/redo/dirty/mark_saved/can_undo/can_redo. Snapshot history remains bounded. Every changed accepted mutation/undo/redo increments revision; no-op or failed command does not.

Transition types/functions are documented below. No request receipts, transport versions, or server infrastructure belong in core.

P1 extension to frozen relation interface: FunctionalExchange now has source_port: Option<Id>, target_port: Option<Id> in addition to source/target FUNCTION IDs and items. RelationBody adds ExchangeAllocation{source,target} (boundary-exchange relation → same-layer interaction/functional-exchange relation), InterfaceProvision{source,target} and InterfaceRequirement{source,target} (participant/port → Interface), and StateAction{source,target,phase:StateActionKind} (State/Mode → Activity/Function; Entry/Do/Exit). These fields participate in reference maintenance. .permits(Kind,Kind) is a convenience only; ExchangeAllocation requires relation-ID-aware validation/candidate queries.

Transition API (implemented)

transitions::plan_transition(&Project, &TransitionRequest) -> Result<TransitionPlan, ModelError>; apply_transition(&Project, &TransitionPlan) -> Result<Project, ModelError>; trace_drift(&Project,&Trace)->Drift; project_fingerprint(&Project)->String.

transitions::counterpart_kinds(source: Kind, direction: TransitionDirection) -> Vec<Kind> is the shared choice policy for UI and other clients. It returns supported explicit element counterpart kinds in stable Kind::ALL order using the same compatibility predicate as transition validation; an empty list means no automatic element mapping.

TransitionRequest {direction:OaToSa|SaToOa, sources:Vec<Id>, scope:SelectedOnly|Required|Subtree, mappings:Vec<TransitionMapping>, fields:Vec<TransitionField>, resolutions:Vec<FieldResolution>, destination_diagram:Option<Id>}. TransitionRequest::new(direction,sources) defaults to selected-only and name/description fields. TransitionMapping {source,target:Option<Id>,target_kind:Option<Kind>} selects reuse or explicit creation kind. An explicit mapping with target=None means create a new counterpart even if another trace exists. Without mapping, one existing trace is reused; multiple traces require selection.

FieldResolution {source,field:Name|Description,decision:TakeSource|KeepTarget|Value(String)}. TransitionPlan {base_fingerprint,request,changes,conflicts,warnings,commands}. Changes carry source/target IDs, Create/Update/Reuse and before/after field changes. Conflicts have optional source/target/field and message. Conflicts prevent apply. The deterministic fingerprint guards stale plans, is not a security hash, and does not introduce persistent project revision fields. Planned IDs and aliases remain unchanged during apply. Server owns request idempotency/revision storage. Apply is one candidate transaction; Session adoption can use Command::Replace(candidate) for one Undo.

OA Capability defaults to SA SystemCapability; explicit OA Capability to SA Mission is supported with TraceKind::Manual, and SA Mission defaults to OA Capability. Repeated previews preserve reviewed divergent name/description values when the source has not changed. Source-only changes propose an update; different edits on both sides require review. An explicit decision records both accepted values. Target-only edits do not advance the skipped field's baseline, preserving reverse propagation.

Projection API (implemented)

projection::project_view(&Project,diagram_id)->ProjectedView {nodes,edges}. ProjectedNode {id,element,position,size,visual_parent:Option<Id>,depth,collapsed}; id/visual_parent are placement IDs. ProjectedEdge {id,source,target,trace} uses placement endpoint IDs. descendant_nodes(&Project,diagram,node)->Vec<Id> includes collapsed descendant placements, so moving a container also keeps their future expanded positions consistent.

Final integration notes

  • validation::can_parent(project,kind,layer,parent), can_connect(project,kind,source,target), effective_performer(project,work), and allocation_summary(project,work) are public. The latter two derive information and never materialize allocations. Shared roles are valid; ambiguity and role/direct-allocation mismatch are warnings. One direct performer per leaf is structural.
  • Owned state machines require participant owners; an unowned state machine is valid incomplete work with a warning, admitted by can_parent. Functional port ownership/direction, scenario lifeline contexts, state/action ownership, interface item contracts and boundary/work exchange allocations share core validation.
  • Projection expands container bounds around descendants using 24-unit side/bottom padding and 44-unit header space. Persisted positions/sizes remain editable requested anchors/minima. Layout recursively places descendants and resizes their containers. Allocation projection suppresses the redundant allocation edge.
  • mark_saved(snapshot: Project) keeps the explicit snapshot signature. Core accepted project state is private.
  • Existing counterpart updates are intentionally scoped to reviewed name/description fields. New selected objects/dependencies copy mapped typed bodies. Existing structural bodies are not automatically overwritten; they remain editable using ordinary commands/source. Trace drift warnings use the same name/description baselines. Many-to-many trace records are supported, while ambiguous counterpart or conflicting merge choices require explicit transition selections.
  • Project::demo() now supplies 39 semantic elements, three focused diagrams (OA allocation, SA allocation, SA decomposition), ten reviewed traces, and two external code/CAD artifact links. It covers information/material/energy items, typed fields, interfaces/ports, repeated scenario messages, a process/chain, normal/degraded modes, guarded transitions, availability, a typed state entry action, and a constraint. Its validator output is empty.