665 lines
34 KiB
ReStructuredText
665 lines
34 KiB
ReStructuredText
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 and current schema-5 JSON. Source import uses the shared language parser
|
||
and its supported migrations. Export uses schema 5 / arcadia 5. 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 5; 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 source5; source3/4 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":"<port UUID>","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":"<diagram UUID>","node":"<placement UUID>",
|
||
"anchor":{"port":"<port UUID>","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":"<work UUID>","lifeline":null}}
|
||
{"Control":{"kind":"Choice"}}
|
||
{"SequenceReference":{"sequence":"<process or chain UUID>"}}
|
||
|
||
``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.
|
||
|
||
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 schema5/source5. 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 5; 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.
|
||
|
||
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 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.
|
||
|
||
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
|
||
<language.html#typed-semantic-review-facts>`_ 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 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``.
|