Migrate schema 2 ports through frozen readers and expose schema 3 source API
Rust checks / check (ubuntu-latest) (push) Canceled after 0s
Rust checks / check (windows-latest) (push) Canceled after 0s

This commit is contained in:
2026-09-05 18:23:33 +03:00
parent 0d14438b7b
commit b9f88ce1f3
21 changed files with 7513 additions and 152 deletions
+121 -32
View File
@@ -1,7 +1,7 @@
Arcadia Studio OA / SA Language and Editing Contract
====================================================
:Version: 2
:Version: 3
:Status: Normative current implementation contract; first-release integration
:Core implementation: ``crates/oa-core``
:Text suffix: ``.arcadia``
@@ -11,17 +11,15 @@ Arcadia Studio OA / SA Language and Editing Contract
This specification defines the shared Operational Analysis (OA) and System
Analysis (SA) model, its textual language, graphical editing obligations,
validation, persistence, and explicit migration from version 1. MUST, MUST NOT,
validation, persistence, and explicit migration from versions 1 and 2. MUST, MUST NOT,
and MAY indicate requirements, prohibitions, and permitted choices.
The first-release capability/mission, contextual process/chain, typed scenario
and state/event additions
are temporarily integrated under schema 2. This does not declare the first
release complete or waive its remaining scenario, state, data, transition and
usability requirements. A distinct release schema and explicit V2 migration
will be specified after those interfaces are frozen. This document describes
the current implemented records, rather than inventing compatibility rules for
that future schema.
Schema 3 introduces typed function and component ports, required functional
exchange endpoints, independently oriented boundary exchanges, and explicit
PortAllocation relations. First-release scenario/state additions remain in
scope; this schema change does not declare native acceptance or the wider
release complete. The preserved schema-2 reader validates the original
contract before migration.
OA describes stakeholders, operational work and needs. SA describes the
selected system boundary, external actors, functions, services and expected
@@ -42,7 +40,7 @@ Actual verification evidence is separate from this contract.
2. One authoritative model
--------------------------
A Project stores ``schema_version`` (2), ``id``, ``alias``, ``name``,
A Project stores ``schema_version`` (3), ``id``, ``alias``, ``name``,
``description``, and maps named ``elements``, ``relations``, ``diagrams``,
``artifact_links``, and ``traces``. Each map is keyed by the UUID contained in
its record. Duplicate map keys and mismatching keys/identities are errors.
@@ -108,8 +106,8 @@ lists all additional fields. ``ref`` means ``@alias``; ``ref?`` also accepts
- ``items``: exchange-item refs
- ``[]``
* - ``oa_port``, ``sa_port``
- ``direction``: In, Out, InOut; ``interface``: ref?
- InOut; none
- ``contract``: required PortContract; ``legacy``: optional LegacyPortContract
- No implicit contract; ``legacy`` defaults none. OA admits Legacy only.
* - ``oa_scenario``, ``sa_scenario``
- ``viewpoint``: ScenarioViewpoint; ``context``: ref?; ``precondition``, ``postcondition``: strings; ``steps``: occurrence refs
- MixedLegacy for omitted schema-2 source; none; ``""``; ``""``; ``[]``
@@ -205,7 +203,7 @@ contain activities; functions contain functions. Capability grouping uses
same-layer capability parents; it does not mean inheritance or inclusion.
Operational and system missions are root semantic records; they do not own
capabilities by containment. MissionCapability expresses that association.
DataFields belong to ExchangeItems or Record DataTypes. Ports belong to
DataFields belong to ExchangeItems or Record DataTypes. Preserved generic ports belong to
participants or work. Lifelines belong to scenarios. State-machine ownership
uses participant → machine → region → state/mode; a state or mode can contain
a nested region. All other state vertices belong to Regions as well. Events
@@ -235,10 +233,13 @@ references. Their kind is the declaration keyword:
- ``items`` refs / []
* - ``functional_exchange``
- SA function → SA function
- ``source_port``, ``target_port`` / none; ``items`` / []
- Required ``source_port``, ``target_port`` refs; ``items`` / []
* - ``boundary_exchange``
- Participant-owned output-compatible port → input-compatible port
- ``items`` refs / []
- Different participant owners; typed component ports have matching kinds
- ``oriented`` bool / true; ``items`` refs / []
* - ``port_allocation``
- SA Component port → SA FunctionInput/FunctionOutput port
- Requires the function's actual work Allocation to that component
* - ``capability_involvement``
- Participant, activity/function, or OA role → capability
- None
@@ -297,12 +298,75 @@ imply a unique performer.
Allocation of a non-leaf work element is invalid. A computed graphical summary
of its allocated leaves MUST NOT create an extra semantic allocation.
Functional ports, when selected, belong to the corresponding endpoint function
and have compatible direction. Boundary ports belong to participants and have
compatible direction. An interface groups ExchangeItems; an exchange using
that port interface must carry items supported by it. Studio's OA boundary
exchange is a simplified representation of operational communication; it is
not a claim of complete Capella CommunicationMean equivalence.
Typed function ports belong directly to SA Functions. ``FunctionOutput``
declares ``outgoing_items``; ``FunctionInput`` declares ``incoming_items``.
The lists contain distinct same-layer ExchangeItem references. A functional
exchange MUST reference output/input ports owned by its respective functions,
and each carried item MUST fit both declarations. Empty declarations accept
no items. Item compatibility is identity equality; future specialization is
not inferred from names. Port declarations remain independent of incident
exchanges after creation.
A ``Component`` contract belongs to an SA System or SystemActor and stores
``kind`` (Standard or Flow) and ``orientation`` (Unset, In, Out, InOut).
Standard requires Unset. Flow Unset is an incomplete draft, not InOut. Typed
component connections require matching kinds: Standard/Flow mismatch is an
error. Standard connections normally use ``oriented false``; directional Flow
connections use true. Boundary orientation is separate from endpoint kind and
orientation. Oriented Flow endpoints permit Out at source and In at target;
unoriented Flow endpoints must permit at least one communication direction.
Provided/required interfaces are separate identified relations. A Standard
partner satisfies a requirement by providing the identical interface; stored
source/target order does not infer service roles. Component carried items must
fit the declared interface-item union when explicit declarations exist. An
explicitly empty interface is not a wildcard. Missing declarations and
unsatisfied required interfaces produce located completeness warnings.
``PortAllocation`` relates a Component port to a typed function port only when
that function has an actual Allocation to the component owner. Standard may
allocate either function direction; Flow directions must agree. A typed
ExchangeAllocation requires both corresponding PortAllocations and compatible
carried items. Unoriented boundary exchanges allow reversed correspondence.
Visual allocation nesting is never evidence of a stored allocation relation.
``Legacy`` requires ``legacy { direction ...; interface ...; }``. It preserves
generic direction/interface data and emits a located compatibility warning.
It is an explicit compatibility constructor in JSON/source; ordinary creation
pickers do not offer it. Resolution to a typed SA contract retains this record
without treating it as another active constraint. OA generic ports remain
Legacy; OA Interactions stay activity-to-activity without function ports.
Deleting a referenced legacy interface clears that optional live reference.
A source-3 functional exchange MUST specify both port aliases; the parser does
not create endpoints. Graphical/command FE creation plans ports atomically,
using unique compatible typed-port reuse or deterministic new endpoints.
Port deletion cascades to incident FEs; FE deletion retains independent ports.
For example::
arcadia 3;
project ports_example "Typed function contract" {
sa_function send "Send" {}
sa_function receive "Receive" {}
sa_exchange_item payload "Payload" {}
sa_interface old_service "Preserved service" { items [@payload]; }
sa_port output "Output" {
parent @send;
contract { FunctionOutput { outgoing_items [@payload]; }; };
}
sa_port input "Input" {
parent @receive;
contract { FunctionInput { incoming_items [@payload]; }; };
}
functional_exchange message "Message" {
source @send; target @receive;
source_port @output; target_port @input; items [@payload];
}
sa_port preserved "Unresolved original" {
parent @send; contract Legacy;
legacy { direction InOut; interface @old_service; };
}
An exclusive region has at most one initial state. Missing initial state is
a completeness warning. Initial states have no incoming transitions and at
@@ -814,16 +878,16 @@ exchanges it references. Cross-layer counterparts are not owned descendants.
Text edits describe a complete candidate and must remove or repair dependencies
explicitly before Apply succeeds.
9. Persistence and V1 migration
-------------------------------
9. Persistence and explicit migration
-------------------------------------
Loading detects JSON from its first non-whitespace ``{``; other input is parsed
as Arcadia source regardless of filename. Saving an ``.arcadia`` suffix uses
canonical V2 text; other suffixes use V2 JSON. Both forms preserve the same
canonical V3 text (``arcadia 3``); other suffixes use V3 JSON. Both forms preserve the same
complete model. JSON rejects unknown fields throughout typed payloads,
duplicate maps, unsupported versions, and structural errors.
During first-release schema-2 integration, old Scenario bodies without a
The frozen schema-2 reader retains staged compatibility defaults. Old Scenario bodies without a
``viewpoint`` retain MixedLegacy, and old Exchange occurrence bodies without
``message_kind``, ``reply_to`` or ``values`` retain Asynchronous, none and [].
Old StateTransition bodies without ``transition_kind``, ``triggers`` or
@@ -836,8 +900,33 @@ defaults without changing any prior identity, name, reference, order, geometry,
artifact or trace field. The original V2 golden source/JSON in
``crates/oa-core/tests/fixtures`` MUST NOT be regenerated from the newer demo;
they verify that every old persistent field survives. Canonical output writes
the added defaults. A future schema-3 adapter remains a separate required
migration and is not implied by this temporary compatibility behavior.
the added defaults through the explicit schema-3 migration.
The V2 adapter preserves every original identity, alias, prose, parent,
placement, trace and artifact. Generic ports become Legacy with their original
direction/interface record. Existing FE endpoint IDs remain unchanged. For
only a missing endpoint it creates an item-bearing FunctionOutput/Input owned
by the already specified function, using UUID v5 in the project namespace
with ``v2-fe-port:<fe-id>:source`` or ``v2-fe-port:<fe-id>:target``. Every
identity category is checked for collision; collisions are located errors,
never overwrites. New aliases follow the deterministic collision-free alias
convention. Every old boundary exchange receives ``oriented true``; no
PortAllocation is inferred.
``decode_with_report``, ``load_with_report`` and their limited/source variants
return the model plus a migration report containing original unresolved port
IDs, required resolutions, generated endpoint IDs/aliases/owners, and boundary
orientation defaults. REST import, replacement, candidate validation and
project snapshots surface the same report. Opening an old server envelope
preserves its resource ID/revision and bytes; the next explicit edit writes
schema 3. Model/source exports contain only the canonical model. Migration
reports are transient response metadata, not persisted model facts.
Admission checks account for generated objects and their references before
construction. Both the old V2 contract and the resulting V3 graph are
validated. Migration itself does not save or increase a stored revision.
Canonical second saves are stable. V1 normalization produces the frozen V2
model and then uses this same V2-to-3 stage.
Save validates a snapshot, writes a sibling temporary file, flushes it, and
atomically replaces the destination. Failed serialization or validation must
@@ -856,7 +945,7 @@ step becomes a distinct occurrence element owned by its process. Generated
diagram, node, and occurrence identities use UUID v5 with the old Project ID
as namespace and deterministic role/index names. If such an identity collides,
a deterministic suffix is tried. Reimporting the same fully identified V1
input therefore yields the same V2 result, including repeated occurrences.
input therefore yields the same V3 result, including repeated occurrences.
No System or SA content is invented during an OA-only migration.
V1 source aliases are retained when valid in V2. JSON imports generate the old
@@ -864,7 +953,7 @@ canonical aliases deterministically. Any alias newly reserved in V2 is changed
by a deterministic suffix; aliases were not persistent V1 semantic data.
A project alias and aliases for new records are generated without colliding
with retained aliases. The existing bundled V1 text and JSON migrate to equal
V2 projects. Future versions remain errors until a separate migration exists.
V3 projects. Future versions remain errors until a separate migration exists.
10. Complete authoring example
------------------------------
@@ -874,7 +963,7 @@ the assigned UUIDs explicitly.
.. code-block:: text
arcadia 2;
arcadia 3;
project harbor "Harbor assistance" {
oa_entity control "Harbor control" {}
oa_activity assess "Assess assistance" {}