Arcadia Studio model REST API ============================= This is the HTTP contract for ``oa-server``. The normative engineering model and source language belong to ``language.rst``. ``openapi.json`` describes the JSON records and closed command vocabulary. The server uses the same Rust ``Project``, ``Command``, parser/printer and validation implementation as the desktop. Identity, revision and writes ----------------------------- All model routes begin with ``/api/v1``. A hosted project's immutable service ``resource_id`` is different from its editable ``model.id``. Each stored file contains ``{resource_id, revision, model, source_project}``. ``source_project`` is the accepted entry filename and map of authored source files; compiling it must reproduce ``model``. The revision starts at 1, increments once per changed accepted model/source pair, and does not change for an exact no-op. Comment-only edits and file/entry changes count as changes even when the model is unchanged. Existing-project writes require the exact quoted ETag returned by a project read, for example:: If-Match: "p-6f7162cc-094c-4f30-9b70-3f6f355f0c7f-r1" Missing preconditions return 428; stale preconditions return 412. Weak ETags, wildcards and lists are not accepted on writes. GET of the envelope, model and source/source-project supports ``If-None-Match`` and returns an empty 304 when unchanged. Use ETags as opaque strings; revisions are unsigned integer counters in JSON. Every accepted changed write is persisted before the response. A worker captures a revision-qualified snapshot, then parses and validates its candidate outside the catalog lock. Commit rechecks the exact ETag and atomically installs the envelope under the lock. Another accepted edit during preparation therefore returns 412 even when the original snapshot passed its initial revision check. Malformed or rejected inputs preserve the accepted model. Incomplete-model warnings permit work and are returned in ``issues``. There is no retained revision history, idempotency receipt, tombstone or server undo. DELETE permanently removes the hosted envelope. Source/JSON interchange exports contain the current model only; source-project export also preserves the authored file layout and comments. They preserve persistent aliases, diagrams, artifact references and OA/SA trace data. Artifact revision strings refer to external artifacts, not past server snapshots. A lost connection or 504 can occur after an admitted write has begun. That write may still complete. Read current state before choosing a new action. Do not automatically retry POST create/import or regenerate random IDs and assume the original request failed. Routes ------ Health and schema routes are public. All model routes require the configured bearer token, if any. Non-loopback binding requires a configured token. .. list-table:: Endpoints :header-rows: 1 :widths: 12 41 47 * - Method - Path - Behavior * - GET - ``/health``, ``/health/live``, ``/health/ready`` - Responding process with successfully opened store. * - GET - ``/openapi.json``, ``/api/v1/openapi.json`` - OpenAPI 3.1 contract. * - POST - ``/api/v1/projects`` - Create from ``{"name":"..."}``; 201 + Location/ETag. * - GET - ``/api/v1/projects`` - Summaries; ``limit``, ``after``, name substring ``q``. * - GET - ``/api/v1/projects/{id}`` - Complete current stored envelope. * - PATCH - ``/api/v1/projects/{id}`` - Conditional rename using ``{"name":"..."}``. * - DELETE - ``/api/v1/projects/{id}`` - Conditional permanent removal; 204. * - POST - ``/api/v1/projects/import`` - Raw model JSON or Arcadia source; new service ID. * - POST - ``/api/v1/projects/import-source-project`` - Complete source bundle as JSON; stabilize missing IDs and create a resource. * - GET / PUT - ``/api/v1/projects/{id}/model`` - Export or conditionally replace native model JSON. * - GET / PUT - ``/api/v1/projects/{id}/source`` - Export or conditionally replace canonical UTF-8 source. * - GET / PUT - ``/api/v1/projects/{id}/source-project`` - Export exact authored files or conditionally replace the complete bundle. * - GET - ``/api/v1/projects/{id}/elements`` - Filter by ``kind``, ``layer``, ``alias``, name ``q``. * - GET - ``/api/v1/projects/{id}/relations`` - Filter by ``kind``, ``source``, ``target``, ``incident_to``. * - GET - ``/api/v1/projects/{id}/artifact-links`` - Artifact links; optional owner ``object`` filter. * - GET - ``/api/v1/projects/{id}/traces`` - OA/SA traces; optional endpoint ``object`` filter. * - POST - ``/api/v1/projects/{id}/query`` - Bounded directed neighborhood, no mutation. * - GET / POST - ``/api/v1/projects/{id}/validation`` - Validate current model or a submitted candidate. * - POST - ``/api/v1/projects/{id}/transactions`` - Conditional typed command batch, optional dry run. * - POST - ``/api/v1/projects/{id}/transitions/preview`` - Preview a core transition against If-Match; return plan/base_revision. * - POST - ``/api/v1/projects/{id}/transitions/apply`` - Conditionally apply that client-held plan and base_revision. * - POST - ``/api/v1/projects/{id}/semantic-transitions/query`` - Read selected traces' typed facts, own drift and linked impacts. * - POST - ``/api/v1/projects/{id}/semantic-transitions/preview`` - Prepare typed semantic decisions and source writeback without writing. * - POST - ``/api/v1/projects/{id}/semantic-transitions/apply`` - Apply that prepared candidate under its original shared revision/ETag. ``Content-Type: application/json`` is required for JSON requests. ``text/plain; charset=utf-8`` is used for Arcadia source. The service does not guess formats from a filename. Unknown DTO fields, invalid UUIDs/enums, duplicate model map keys and unsupported schemas are rejected. Maximum body size is 8 MiB. Accepted serialized model JSON and serialized source-bundle JSON each have an 8 MiB cap, including IDs inserted during compilation. The stored envelope allows both bounded representations plus small framing overhead. Compressed or encoded request bodies and browser Origin requests are not supported. Model admission permits at most 5,000 elements plus relations, 20,000 total persistent records (including the project, views, placements, routes and manual port anchors), and 50,000 ordered step references. Source declaration counts and decoded JSON record counts are checked before structural validation. Legacy import counts the occurrences and placements migration will generate before validating or migrating that model. Exceeding these budgets returns ``422 model_limit``; candidate validation reports the same diagnostic in its 200 response. Parsing, validation and query processing use snapshot workers, so this work does not hold the catalog lock or serialize unrelated model preparation. Import accepts schema-1 JSON through the shared explicit migration adapter, as well as schema-2, schema-3, schema-4, schema-5, schema-6 and current schema-7 JSON. Source import uses the shared language parser and its supported migrations. Export uses schema 7 / arcadia 7. Native JSON replacement accepts supported older schemas through the same explicit migration. Only documented query parameters are accepted. In particular, appending ``?revision=...`` to model/source export is an error, not historical retrieval. Authored source projects ------------------------ A source bundle contains ``entry`` and a map of ``files``. For example:: { "entry": "rescue.arcadia", "files": { "rescue.arcadia": "arcadia 7; project rescue \"Rescue\" { include \"oa/work.arcadia\"; }\n", "oa/work.arcadia": "// Engineering rationale\noa_activity assess \"Assess assistance\" {}\n" } } The entry is a root filename. All keys are canonical, portable, slash-separated relative paths ending in ``.arcadia``. Includes resolve only against these submitted strings. They never read the service filesystem, URLs, artifact targets or another hosted resource. All submitted files must be reachable; missing files, cycles, duplicate keys, case collisions and escaping paths are rejected. The bundle permits at most 256 files, 32 include edges along a path, and 1,024 include edges in total. Model and source-byte budgets apply across the complete bundle, not separately per file. Current bundle syntax is source7; source3/4/5/6 bundles migrate explicitly while preserving their files/includes/comments. V1/V2 single-file migration remains available through interchange import. Compilation inserts UUIDs into headers that omit them. Import returns 201 with Location/ETag; GET source-project retrieves the stabilized accepted bundle. PUT returns ``revision``, ``changed``, located ``issues`` and that accepted ``source_project``. Preserve the returned IDs before subsequent editing. With explicit IDs, untouched text, comments, line endings, entry name and module ownership are preserved exactly. Re-submitting the same accepted bundle is a no-op. Removing a file means submitting a complete valid bundle without that file and its includes; no files are created or deleted on the service host. All typed command, transition, rename and model-interchange writes update this same accepted source project. Existing declarations and reference comments follow command identity correspondence, including UUID swaps. Full-model replacement uses common UUIDs as its correspondence boundary. It preserves the accepted source layout; canonical interchange formatting/comments are not adopted as a replacement authored workspace. Use source-project PUT for authoring file layout and comments. A failed source writeback rejects the whole write and never falls back to discarding authored files. Old model-only envelopes are migrated to a deterministic source bundle in memory when opened. Reading or an exact no-op does not rewrite their files or advance revisions. Their next changed write persists both representations. Startup rejects already-coupled envelopes whose source/model disagree or whose source lacks stable IDs. The 256 MiB store budget charges complete accepted envelopes, including the generated source of old envelopes before their next save; an over-capacity old store is reported rather than silently pruned. Queries and pagination ---------------------- List filters combine using AND. Enum spelling is case-sensitive and comes from the shared schema: examples include ``kind=Activity`` and ``layer=Oa``. Aliases match exactly; ``q`` is a Unicode-lowercase substring match on the display name. Empty or invalid enum values are request errors. Lists are ordered by UUID. ``limit`` defaults to 100 and accepts 1 through 1000. ``after`` is an exclusive last UUID. ``next_after`` is null at the end. Project-scoped lists return a revision. Include that revision on following pages to detect a changed model; 409 ``snapshot_changed`` means restart the query. Supplying a past revision does not retrieve history. The project catalog is a live list and does not have a multi-page snapshot guarantee. A neighborhood request is:: { "roots": ["1b37b9d7-9a95-4a51-8707-010878a82419"], "direction": "both", "relation_kinds": ["Allocation", "Interaction"], "max_depth": 2, "max_objects": 200, "revision": 3 } Roots may identify elements or relations. The service traverses relation source/target adjacency in the selected direction (incoming/outgoing/both), preserves distinct parallel relations, and returns ``elements``, ``relations``, ``revision`` and ``truncated``. Empty kind filters permit all relation kinds. Every returned relation includes its endpoint closure, including the endpoints of a referenced relation. Closure records count against the object bound but do not add traversal depth. Model ownership, process occurrence order and non-endpoint references remain available in the returned records and complete model; they are not silently treated as additional graph edges. Use 1–100 roots, depth 0–4, and 1–1000 total returned objects. The cap must fit the roots and their endpoint closure. A root closure that cannot fit is an error; further omitted edges set ``truncated: true``. A missing root is 422. Deterministic UUID iteration makes repeated queries of one snapshot stable. Transactions ------------ The ``commands`` array contains the shared externally tagged Serde command representation. It is not RFC 6902 JSON Patch. For example:: { "commands": [ {"Rename": ["1b37b9d7-9a95-4a51-8707-010878a82419", "Assess assistance"]}, {"Describe": ["1b37b9d7-9a95-4a51-8707-010878a82419", "Review the request."]} ], "dry_run": true } One-field variants use ``{"Delete":"uuid"}``; tuple variants use arrays; named-field variants use objects. For a new typed OA activity:: { "CreateElement": { "id": "1b37b9d7-9a95-4a51-8707-010878a82419", "alias": "assess", "name": "Assess assistance", "description": "Review the request.", "parent": null, "body": {"Oa": "Activity"} } } ``CreateArtifact``/``EditArtifact`` and ``CreateTrace``/``EditTrace`` use the same transaction boundary as engineering edits. Artifact URI, revision and fragment strings are opaque references. No URI is fetched or verified by the service. Model references and alias uniqueness are checked by the core. At most 200 commands are allowed, counting nested Batch wrappers. Explicit creation identities allow later commands in the batch to reference earlier creations. The shared ``execute_batch`` applies all operations to one candidate and validates the final state. A rejected operation or final structural error rejects the whole request. Reference rewrites/deletion cleanup follow the same core logic as desktop editing. Command preparation retains original-to-candidate identity correspondence through UUID edits, swaps, deletion and reuse. Source writeback uses that correspondence to preserve declaration ownership and comments. Dry run still requires ``If-Match``. Its response includes ``revision``, ``dry_run``, ``changed``, ``issues`` and the proposed ``model`` and ``source_project``. It validates source writeback as well as semantics and neither writes nor reserves IDs. A committed response omits the proposed model and source project. Commit must check the revision again. A no-op is successful with ``changed: false`` and the original ETag. Diagram port positions ---------------------- ``NodePlacement.port_anchors`` is an optional list of ``{"port":"","side":"Top","offset":0.25}`` records. Side is Left, Right, Top, or Bottom; offset is a finite fraction from 0 through 1, measured from top on vertical edges and from left on horizontal edges. The port must be a direct child of the placement's semantic element and occur at most once in its anchor list. Placement is presentation state; it changes neither semantic ownership nor port direction. Other diagrams are independent. The existing transaction endpoint accepts:: {"commands":[{"SetPortAnchor":{ "diagram":"","node":"", "anchor":{"port":"","side":"Top","offset":0.25} }}]} ``SetPortAnchor`` upserts by port UUID. ``RemovePortAnchor`` takes ``{diagram,node,port}`` and restores automatic positioning. Repeating a reset is a no-op only while the referenced port still belongs to that placement's element; missing or stale owners are rejected. Remove old anchors before reparenting in the same atomic batch. Both commands support ordinary dry run, ETag checks and source-project writeback. Rejected batches preserve the model, authored files and revision. JSON/source imports may omit ``port_anchors``; it defaults to ``[]`` and empty lists are omitted on export. The normative diagram semantics and source spelling are in ``language.rst`` section 5. Contextual process and chain topology ------------------------------------- Operational processes and system functional chains can combine work contributions, exchange contributions, explicit controls and references to reusable sequences. Each contribution is an ordinary ``Occurrence`` element owned directly by the process/chain, with its stable ID in that owner's ``steps`` list. ``OccurrenceBody`` includes, for example:: {"Action":{"action":"","lifeline":null}} {"Control":{"kind":"Choice"}} {"SequenceReference":{"sequence":""}} ``ControlKind`` is ``Choice``, ``Merge``, ``Fork``, ``Join`` or ``Loop``. ``RelationBody.SequenceLink`` connects contribution IDs in one owner and contains ``source``, ``target`` and a string ``guard``. Conditions belong to choice/loop paths; an explicit ``else`` guard can describe the other path. The readable order of the ``steps`` list remains persistent, while links express the explicit alternative, parallel and loop topology. The core checks owner context, work/exchange endpoint agreement and recursive sequence reuse; engineering diagnostics identify incomplete branch cardinality or paths. Old exchange-only sequences without explicit links retain their linear meaning. These records use the same create/edit transaction commands and source/model replacement routes as other engineering records. For example, ``GET /api/v1/projects/{id}/relations?kind=SequenceLink`` queries the links. The source representation uses ``sequence @alias`` references. The service does not execute conditions or simulate a process. Caller-qualified process and chain links ---------------------------------------- Schema 7 adds the closed ``RelationBody.ContextualLink`` payload:: { "ContextualLink": { "owner": "", "source": {"references": [], "occurrence": ""}, "target": {"references": [""], "occurrence": ""}, "purpose": {"Precedence": {"guard": "check accepted"}} } } ``references`` is an ordered path of reference-occurrence IDs, never sequence definition IDs; at most 64entries per endpoint. The explicit owner determines context and source placement. ``purpose`` is exactly Precedence with string guard, Exchange with work-exchange UUID, or CommonWork with work UUID. Only Precedence contributes ordering; the other purposes preserve assembly incidence. Both paths empty with Precedence must use the existing SequenceLink constructor. Query these records with ``relations?kind=ContextualLink``. Ordinary create/edit, source replacement and JSON replacement share the same owner/path/purpose checks. R1.B and R2.B remain separate caller contributions even if B has one definition UUID. Deleting a typed path/leaf/owner/purpose dependency removes the whole link; retargeting an invalid surviving link requires explicit repair. No path shortening, implicit work duplication or fallback to a whole reference is permitted. Authored path entries count toward the 50,000 ordered-reference budget. Resolver cache state does not change validity. Contextual analysis has separate 50,000 node/100,000 edge limits and explicitly reports incomplete expansion. See language.rst4.2.1 for caller-qualified diagnostics and synthetic-boundary rules. Typed scenarios and message values ---------------------------------- Scenario bodies store an explicit ``viewpoint``. Occurrence Exchange bodies store ``message_kind``, optional correlated-call ``reply_to`` and contextual ``values``. Message kinds are Asynchronous, Call, Reply, Create, Delete, or ``{"Timer":{"expression":"after 5 s"}}``. Each value record contains a carried DataField UUID in ``field``, enclosing field UUID list ``path`` (default []) and textual ``expression``. Identity is (path, field), allowing repeated uses of a Record. Operation Call/Reply direction checks use the direct parameter; Reference storage stops nested payload traversal. Expressions do not change the shared exchange item's type or evaluate server-side. ``ScenarioUse`` contains a referenced ``scenario`` and one-to-one lifeline ``bindings`` records with ``referenced`` and ``local`` UUIDs. The core validates viewpoint/layer compatibility, call/reply order and reversal, lifetime order, carried fields, binding identity and recursive reuse through the same candidate boundary used by the desktop. The normative details are in ``language.rst``. Existing schema-2 files may omit the new fields: missing viewpoint maps to MixedLegacy and missing message fields to Asynchronous, null and []. Source exports make those compatibility defaults explicit. This preserves original V2 models while the release schema is being integrated; it does not silently reinterpret old mixed lifelines as a strict new viewpoint. Data and interface contracts ---------------------------- Schema4 uses typed bounded DataTypeDefinition and DataValue constructors, field storage/defaults/directions, and single specialization. Exact JSON shapes are in ``openapi.json`` and semantic rules and runnable source in ``language.rst`` section 4.5. Interface membership is an identified InterfaceItemAllocation relation with independent order/transmission/acquisition. DataAssociation relates Record types with named, navigable, multiplicity-bearing ends; it does not add carried fields. Use ordinary relation queries, transactions and artifact links, for example ``GET /api/v1/projects/{id}/relations?kind=InterfaceItemAllocation``. The service and desktop use the same inheritance/path/default validation. Invalid bounds, defaults, directions, cycles or contract-breaking deletions reject atomically, preserving the accepted source/model, revision and stored bytes. Correct a related contract in the same transaction when removing a used interface allocation. Explicit schema1/2/3 migration preserves prior identities and typed ports. Reports add semantic defaults, generated interface allocations and unresolved message values. Old source3 bundles retain files/includes/comments during upgrade; all current exports use schema7/source7. Reading an old envelope does not write it or advance its ETag. Canonical exports omit transient migration reports. Validation ---------- GET returns current-model diagnostics. POST accepts either:: {"format":"json", "model": {"...":"complete native Project record"}} or:: {"format":"arcadia", "source":"complete source document"} or:: {"format":"source-project", "source_project":{"entry":"rescue.arcadia", "files":{"rescue.arcadia":"arcadia 7; project rescue \"Rescue\" {}"}}} A well-formed validation request returns 200 with ``valid`` and ``issues`` even if its candidate is invalid, including a model record that fails typed decoding. Malformed request JSON or an invalid format/payload envelope is a 400. Source diagnostics include one-based line and column according to the shared language parser. Candidate validation does not replace current state. Source-project validation locations refer to the submitted bytes before UUID insertion. Successful source-project PUT diagnostics refer to the returned accepted bundle. Missing IDs are not saved or adopted by validation. Typed state machines and events ------------------------------- OA and SA Event records use the same ``SharedBody::Event`` and ``EventBody`` contract as source and graphical editing. Signal carries same-layer item references; Time specifies After/At and an expression; Change specifies a condition expression. State vertices include Choice, Junction, Fork, Join, ShallowHistory, DeepHistory, EntryPoint, ExitPoint and Terminate, as well as State, Mode, Initial and Final. Query these through the ordinary ``kind`` filters. No timer or executable state-machine service is implied. StateTransition keeps ``trigger``, ``guard`` and ``effect`` prose and adds ``transition_kind`` (External/Local/Internal), ``triggers`` (Event or work UUIDs) and ``effects`` (work UUIDs). The reference lists use UUIDs in JSON and aliases in source. Missing new properties in staged schema-2 input hydrate as External/[]/[] without changing prior text. These defaults are compatibility behavior pending the distinct release schema, not a versionless expansion of every future input contract. Use one ordinary transaction to create an event and edit its referring transition. Reidentification updates references, and deletion prunes signal items and effect references. Removing the last typed trigger with no prior trigger prose leaves a descriptive replacement reminder; it does not silently introduce a completion transition. Invalid typed references reject the whole candidate and preserve revision/ETag. All writes retain the same conditional commit and disk persistence contract as other semantic records. State diagram representation ---------------------------- ``Diagram.projection`` keeps the existing string values ``Overview``, ``Decomposition``, ``Allocation``, ``Traceability``, ``FunctionalDataflow`` and ``Capabilities``. A dedicated state view instead uses the required payload:: {"StateMachine":{"machine":"11111111-1111-4111-8111-111111111111"}} The UUID MUST identify an existing StateMachine in the diagram's layer. Only that machine, its Regions and its state vertices may be placed, including nested members. Empty and partial views are valid. No machine, Region, vertex or placement is synthesized by accepting or reading a diagram. Source uses ``projection { StateMachine { machine @modes; }; };`` with the same reference. Use the ordinary ``CreateDiagram`` or ``EditDiagram`` transaction commands, JSON model import/replacement, or source/source-project writes. A bare ``"StateMachine"``, missing or null ``machine``, malformed UUID, or additional payload field is malformed JSON model data (400). A missing, wrong-kind or cross-layer machine produces the semantic issue ``state_diagram_context``; an incompatible placement produces ``state_diagram_member``. These reject writes with 422. Transaction rejections use the ``command_rejected`` problem code and include the first core failure in ``detail``; candidate validation provides the structured ``issues`` collection. Source syntax errors use the source rejection response (422) with locations. The validation endpoint returns 200 with ``valid:false`` for a well-formed invalid candidate, as described above. When changing a diagram's machine or selecting StateMachine for an existing diagram, remove or relocate incompatible placements in the same transaction. Other projections continue to preserve hidden placements. Rejected writes retain the accepted model, source bundle, revision and ETag. Reading a state view has no semantic or persistence side effects. Source-6 communication and saved views -------------------------------------- The same import, replacement and command endpoints admit OA ``CommunicationMean { source, target, oriented, items }`` and root-level ``ExchangeCategory { family, exchanges }`` records. Communication means join distinct OA entities/actors. Categories group same-layer exchanges as ``Work`` or ``Participant`` without owning them. Existing legacy OA boundary exchanges retain their identities and contracts; migration does not silently replace them. ``Diagram.view_options`` is an optional closed object with defaults: empty ``hidden_edges``, ``All`` for ``relation_kinds``, both category selections, ``coverage`` and ``work_contexts``, and ``Name`` for ``exchange_labels``. ``{"Only":[]}`` hides all relation and trace lines; ``{"Any":[]}`` preserves an explicit empty category/context selection. Category members union within each family, and independent filters intersect. ``Traceability`` permits references from both layers; ordinary projections require the diagram's layer. These presentation choices preserve semantic records, routes, placements and the automatic port positions derived from unfiltered eligible exchanges. Schema/source versions 1–5 reject the new constructors, category review facts and explicit ``view_options`` field, including an empty object. Their frozen readers migrate accepted content to schema/source 7 with default view options. The OpenAPI document describes current records; it is not a permissive union of historical input formats. Source-7 integration and release acceptance are tracked separately in the release coverage audit. Explicit interface-operation identity ------------------------------------- ``OccurrenceBody.Exchange.operation`` is optional. Absent/null retains ordinary channel semantics and is omitted in canonical output. ``{"allocation":null}`` (or an empty object) retains explicit unresolved operation intent. A selected ``{"allocation":""}`` identifies that exact allocation, including for parameterless operations sharing one channel. These records are closed; unknown fields are rejected. Earlier schema/source versions reject the operation field even when explicitly null and reject ContextualLink and their new semantic facets. Migration never guesses an operation from names, message values or a channel's item set. Selection is valid only for SA BoundaryInterface Call/Asynchronous messages. Core proves actual Standard component-port Requires/Provides roles, compatible interfaces exposing the same allocation, actual channel direction and allowed transmission protocol. Reply stores no operation and derives it from its exact Call; a separate return channel still needs its own valid carried-item/endpoint contract, including a void return. Selected message values use the exact operation signature. Unresolved intent preserves live expressions and checks their paths with an incomplete-signature warning; it does not substitute the channel union. Allocation deletion clears selection to unresolved only within an otherwise valid whole candidate. Removing the sole allocation can refuse atomically while a channel still carries its now-unadmitted item; repair every affected channel explicitly in the same batch. A surviving same-item allocation may keep a channel valid, but is never silently selected. Reselection validates retained values without pruning them. The service uses the same source/history boundary as graphical editing. See language.rst4.3.1 for the complete contract. Cross-layer transitions ----------------------- Preview accepts the shared ``TransitionRequest`` record, including direction (``OaToSa`` or ``SaToOa``), sources, dependency scope, mappings, selected fields, conflict resolutions and optional destination diagram. All fields are explicit in OpenAPI. At most 100 sources, 200 mappings, 200 communication endpoint decisions, 200 operation omissions and 400 field resolutions are accepted. A conflict-free plan must fit the same 200-command transaction limit and model/source-capacity limits. A conflict-free preview also checks source writeback, so its commands can update the same accepted authored workspace. SA→OA abstraction of explicit operation intent requires ``operation_omissions`` (omitted means empty). Each closed record contains the selected invocation's ``source`` UUID and a nonempty ``rationale`` string. Missing, duplicate, irrelevant or wrong-direction omissions reject. Reply derives its Call's abstraction and has no second writable operation choice. Source operation identity/values remain intact; target facts are mapped and validated. Preview and Apply enforce the same 200 omission limit for ordinary and semantic transitions. OA ``CommunicationMean`` maps to an SA ``BoundaryExchange`` through an explicit ``communication_endpoints`` array (omitted means empty). Each decision identifies the source communication means and both ``source_port`` and ``target_port``. Each port choice is either ``{"Reuse":{"port":"port-uuid"}}`` or ``{"Create":{"id":"new-port-uuid","alias":"radio_port","name":"Radio port", "description":"","kind":"Standard","orientation":"Unset"}}``. Created or reused SA component ports must belong to the explicitly mapped participants. These per-exchange choices do not replace participant correspondence with port IDs. Missing or incompatible choices remain preview conflicts. Interface and functional-port allocations use their existing explicit workflows; an engineer may omit an unresolved allocation from this transition. Reverse transition maps boundary ports through their owners to OA participants. ``ExchangeCategory`` transitions preserve their family and map only explicitly corresponding member exchanges. Missing member mappings are conflicts, not new fabricated exchanges. Typed review exposes ``Category.Family`` and the ``CategoryExchanges`` member collection; historical review facts remain exact. The preview response is ``{"base_revision":1,"plan":{...}}``. It contains planned changes, conflicts, warnings and exact commands/IDs. It does not write the model or persist a server-side plan. Apply accepts that entire response and requires the original ETag in ``If-Match``. It checks both base_revision and the core's snapshot fingerprint before executing the shared transition validator. Stale revisions fail with 412 and unresolved conflicts with 422. Successful apply increments the revision once, preserving the planned identities. A supplied plan is a client-owned command proposal. It is not cryptographically authenticated as an untouched server preview; the same authenticated client can submit ordinary typed commands. The core fingerprint is a change detector, not a security digest. There is no plan token, expiration store or receipt. Typed semantic transition review -------------------------------- The sibling ``semantic-transitions`` routes use the `typed review semantics `_ in ``language.rst`` sections 5.1–5.5. The original prose transition routes keep their existing contract. All new routes use JSON and the existing authentication, capacity, worker and error boundaries. Query accepts ``{"traces":["trace-uuid"],"references":{},"revision":1}``. ``references`` is an optional map of canonical OA UUIDs to SA UUIDs, including historical deleted identities. It never guesses correspondences from names. ``revision`` is optional; a mismatch returns 409. Select 1–100 unique existing trace IDs; an empty or duplicate selection returns 400 and a missing trace returns 404. The response includes the current revision and items containing ``trace``, ``oa``, ``sa``, typed ``facets``, ``drift`` and ``linked_impacts``. Own and linked drift and their unreviewed flags remain distinct. Query reads one immutable snapshot, does not refresh baselines, and does not fetch artifact URIs. Preview accepts ``SemanticTransitionRequest``:: { "transition": { "direction": "OaToSa", "sources": ["40000000-0000-4000-8000-000000000002"], "scope": "SelectedOnly", "mappings": [{ "source": "40000000-0000-4000-8000-000000000002", "target": "40000000-0000-4000-8000-000000000003", "target_kind": null }], "fields": [], "resolutions": [], "destination_diagram": null }, "traces": {}, "references": {}, "reviews": [{ "source": "40000000-0000-4000-8000-000000000002", "resolutions": [ {"facet":{"Header":"Name"}, "decision":"TakeSource"}, {"facet":{"Data":"Unit"}, "decision":"KeepTarget"} ], "reset": [] }], "candidates": [], "accepted_impacts": [] } The example maps an existing OA data type to its traced SA counterpart, takes only its name and acknowledges intentionally different units. Other facets stay unreviewed or retain their earlier drift. Select an explicit trace through the ``traces`` map (source UUID to trace UUID) when multiple trace kinds connect the pair. ``reset`` deliberately invalidates exact old selectors after changed correspondence. The optional collections default to empty. Semantic header decisions use typed facets; leave legacy ``transition.fields`` and ``transition.resolutions`` empty. Facet selectors are closed enums, for example ``{"Data":"IntegerMinimum"}`` or ``{"Member":{"collection":"SignalItems","keys":{"oa":"oa-uuid","sa":"sa-uuid"}}}``. Annotation keys contain the entire path and field; enum literal keys are exact strings. ``KeepTarget``, ``TakeSource`` and ``Candidate`` operate on independently selected facts. Candidate records use existing Element/Relation/ArtifactLink types, must preserve identity/alias, and must equal precisely the result of the selected facets. Constructor review covers its coupled introduced/removed fields. Membership review does not silently acknowledge order; target-only members remain independent. OpenAPI defines every selector and typed payload. Preview requires ``If-Match`` and returns ``{"base_revision":1,"plan":{...}}``. The plan contains the original typed request, mapping plan, review facts, acknowledged/retired selectors, linked impacts, exact prepared impacts, conflicts, commands, and base/prepared fingerprints. A conflict-free preview also prepares the complete authored source bundle and checks its model equivalence and capacity. No preview changes the model, source, revision or stored bytes. If ordinary preparation induces additional cleanup, the plan reports exact typed before/after impacts and a conflict. Review those impacts, place the accepted records in ``accepted_impacts``, and request another preview. Acceptance cannot override a contradictory selected facet. Missing mappings, ambiguous order, duplicate decisions, invalid candidates or unresolved impacts cannot be applied. This is the shared core planner and command preparation, with no server-specific semantic mutation engine. Apply accepts the entire preview envelope under the same ``If-Match``. It checks ``base_revision``, the model fingerprint, unresolved conflicts, the prepared candidate fingerprint, ordinary model validation and coupled source preparation, then atomically stores one accepted model/source revision. The final store check also catches a concurrent edit during preparation. Source-only edits invalidate the preview through the shared ETag even when the model fingerprint is unchanged. Stale ETag/revision returns 412; semantic rejection returns 422 with code ``semantic_transition_rejected``. Exact no-op candidates preserve revision. Read and preview again after a successful changed apply before reviewing further. A supplied plan remains a client-owned candidate. Fingerprints detect stale or inconsistent proposals; they are not tamper-proof signatures, authentication receipts or proof of original review authorship. Apply preserves preview-generated identities and does not rerun the planner with fresh random IDs. Authenticated clients already have ordinary model/source editing privileges. The server does not persist plans, tokens or review sessions. Requests allow 100 sources, trace choices and reviews; 200 mappings, candidates and accepted impacts; 5,000 canonical reference mappings; and 5,000 facet resolutions plus resets across all reviews. The legacy 400 prose-resolution limit, 200 communication endpoint decisions, 200 operation omissions and 200-command transaction limit still apply. Query has the same 5,000 reference-map limit. Core bounded linked traversal errors remain observable as semantic rejection; no truncated result silently claims complete review. Schema/source 5 adds ``TraceBaseline.semantic``. Absence or null is Unreviewed; migrating older prose baselines does not fabricate semantic history. The persisted baseline contains only closed typed ``FacetReview`` facts, not whole candidate records or a generic JSON value tree. Historical UUIDs remain historical, including after deletion, and source uses explicit ``uuid`` tokens for them. Error contract -------------- All errors have ``Content-Type: application/problem+json``. Example:: { "type":"urn:arcadia:problem:revision_conflict", "title":"Precondition Failed", "status":412, "code":"revision_conflict", "detail":"Project changed. Reload and review the current model before retrying.", "current_revision":3 } ``issues`` contain severity, code and message, and may include field, object_id, line, column, source ``path``, half-open UTF-8 byte ``span`` (``start``, ``end``), and ``related`` source locations (path/span). Lines and columns are one-based; columns count Unicode scalars. Use ``code`` for client decisions, not the English message. ``X-Request-ID`` is a response correlation UUID. This is not an idempotency key or receipt address. * 400: malformed JSON/envelope/query/UUID or unsupported ETag form. * 401: missing or incorrect configured bearer token; includes WWW-Authenticate. * 403: browser Origin is unsupported, or unauthenticated Host is not loopback. * 404: missing project or route. * 405: unsupported HTTP method. * 409: requested query revision changed or revision counter exhausted. * 412: stale write precondition. * 413: body, serialized model, stabilized source bundle or envelope exceeds its size limit. * 415: unsupported Content-Type or Content-Encoding. * 422: rejected source/model/command, model count limit, or missing graph root. * 428: missing If-Match. * 503: work slots full or filesystem/storage unavailable; Retry-After is present. * 504: request deadline; an admitted write outcome may be unknown. * 507: fixed store cap of 128 models or 256 MiB serialized envelopes reached. * 500: unexpected server/worker failure. Deployment and persistence limitations are documented in ``server.md``.