Files

71 lines
11 KiB
Markdown

# Architecture and extension guide
The normative contract is [language.rst](language.rst); [scope.md](scope.md) explains deliberate differences from the complete Arcadia/Capella ecosystem. V2 uses one typed model and one validated mutation boundary across the desktop, text editor and REST service.
## Crate boundaries
| Crate | Responsibility | Does not depend on |
|---|---|---|
| `oa-core` | Model, structural/completeness rules, commands/history, reference maintenance, diagram projection, OA/SA transitions, text and file persistence | Iced, renderer, HTTP or native UI |
| `oa-desktop` | Iced events/state, property and source drafts, graphical views, file interactions | Server availability or an account |
| `oa-server` | HTTP contract, authentication/admission, resource revisions and atomic model/source storage | Iced or a desktop session |
The server reuses the same core library as the desktop. A new automation endpoint must produce a core command/candidate rather than implement a second version of domain rules. Desktop and server are separate storage clients: there is currently no desktop HTTP adapter. Explicit transfer supports canonical model interchange and authored source bundles.
## Model, identity and references
`model.rs` defines Project maps for typed Elements, Relations, Diagrams, Traces and ArtifactLinks. Each diagram owns NodePlacements. All records share one UUID/alias namespace. UUIDs are durable reference identity; stored aliases are stable text labels; display names can change independently or repeat.
Element kind and layer derive from closed OA/SA bodies. Shared typed bodies represent data, interfaces, scenarios, state machines and constraints; payload variants cannot disagree with an independent kind tag. Relations are separate typed records, including relation-to-relation exchange allocation. Sequence occurrences have their own element identity; repeating an exchange uses distinct occurrences. Semantic parent, performer allocation and diagram placement are independent.
`references.rs` visits stored references for reidentification, deletion cleanup and transition mapping. New reference fields must join these visitors and their regression cases. Reidentification updates map keys, owned records, endpoints, occurrence lists, placement targets, traces and artifact owners atomically. Deleting a sequence does not delete its referenced semantic exchanges. Deleting an OA/SA element does not own or delete its cross-layer counterpart.
## Validated transactions and history
`session.rs` clones a candidate, applies a command or batch, validates the complete result, and adopts it only when valid and changed. `Replace(Project)` supports full source replacement. Record edits apply drafted properties together; typed operations handle reparenting, placement relocation, grouped movement, ordering and layout. A rejected batch leaves accepted state and history intact. Public builders construct candidates and fixtures; they are not a substitute for final validation.
`validation.rs` separates structural errors from incomplete-model warnings. Dangling references, wrong kinds/layers, ownership cycles, incompatible ports and invalid uniqueness reject a candidate. Missing allocations, incomplete references and coverage gaps allow continued authoring. Small predicates support parent/relationship choices; they must agree with the committed-model policy.
`prepare_command` returns a validated candidate, selection and original-record identity map without committing. Desktop `document.rs` then updates the accepted source through the shared writer before adopting one compiled model/source snapshot. It retains up to 100 accepted changes within an estimated 32 MiB history budget and compares the complete source bundle with its saved baseline. Comment-only changes have history; invalid updates retain the current snapshot. Exact snapshots preserve authored omissions and comments through Undo/Redo. Persistent collections or delta history should follow profiling, not speculative infrastructure.
## Nesting and graphical views
`projection.rs` derives visible nodes, visual parents and edges from a stored diagram's projection. Decomposition uses semantic ownership; allocation uses direct/effective leaf performers and computed parent summaries. Node positions/sizes/collapse belong to each view, so multiple diagrams can represent the same semantic element independently.
`diagram.rs` uses the shared projection for drawing, hit testing, Fit, grouped movement and SVG. A placement move never implicitly reparents or reallocates an element. `RelocateNode` moves a placement between diagrams while retaining its UUID, alias, geometry, collapse and references; validation rejects an incompatible destination or duplicate placement. `behavior.rs` presents sequence/scenario and state-machine content from the same typed records. UI acceptance is recorded separately from these implementation boundaries.
## Counterpart planning
`transitions.rs` builds a candidate plan from source IDs, direction, dependency scope, explicit mappings and reviewed field decisions. Participant/system-boundary choices remain explicit. Shared content and ownership references map when creating counterparts; ambiguous or incompatible mappings produce conflicts. OA-to-SA traces retain canonical endpoints regardless of which perspective starts the operation.
Existing counterparts receive reviewed name/description changes, not structural synchronization. Per-trace baselines record those reviewed values, including intentional divergence. Ordinary editing never propagates automatically. Apply rejects a stale project fingerprint or unresolved conflict, then uses the same batch validator. Desktop application creates one history entry; the service additionally checks resource revision/ETag before committing. The fingerprint is a deterministic change token, not a security signature.
Keep domain mapping choices in the core or derive UI choices from its queries. Independent desktop match tables can drift from accepted semantics; the V2 review found and corrected this kind of mismatch for fragment construction and capability/mission transition options.
## Text and draft state
`language.rs` provides the shared lexer/parser, deterministic formatter, tolerant source analysis and explicit V1/V2 migration readers. It collects global declaration aliases before resolving UUID references, rejects unknown/duplicate fields and typed-constructor errors, and validates the complete candidate. Source3 elements may nest to express semantic parenthood; iterative parsing retains real lexical-owner/body/own-field spans. Canonical flat output remains available and preserves every model field, alias, UUID and ordered occurrence.
`source_project.rs` compiles an explicit virtual bundle with relative includes, global identity and per-file diagnostics. It never reads a filesystem or network. The accepted bundle inserts missing identities while preserving authored bytes. The shared updater changes individual tokens and keyed list entries, then `source_project/source_structure.rs` composes structural moves from original declaration provenance. Nested reparenting moves attached comments and children across files; flat source organization stays flat. Recompilation and full model equality are mandatory before adoption. Canonical export alone normalizes comments/formatting.
`forms.rs` is a closed adapter over typed records. JSON values are temporary form structure; incomplete numbers, references and escaped strings stay in drafts until decoding a typed Command. This is not an extensible runtime schema or an alternate persisted metamodel. Every added field needs a usable control and meaningful authoring coverage; a no-op serialization test alone cannot establish graphical reachability.
`app.rs` coordinates the accepted Document, selection, property draft, per-file source workspace, active view/camera, workflow dialogs and file state. `views.rs` renders task navigation and inspectors; `workflow.rs` handles explicit relationship/manual-trace/counterpart choices. `highlight.rs` translates tolerant core tokens to source coloring. Lint runs on a worker after a short debounce and ignores obsolete results. Valid Apply commits all reachable files once; invalid or inactive-file drafts retain located diagnostics. Per-buffer history is distinct from accepted model/source history.
## File and service persistence
Core model persistence detects JSON by content and otherwise parses standalone Arcadia text; its model export uses canonical source or strict JSON. Native source-project loading/save uses explicit file receipts, validates physical path ownership and preserves comments across all included files. Save All compares previously read bytes, stages replacements and records an interrupted-save journal. Each replacement is atomic; multi-file visibility is not. Recovery is explicit and survives invalid drafts or missing entry files. File tasks run on blocking workers and failures preserve accepted models, drafts and pending continuations.
The service stores one `{resource_id, revision, model, source_project}` envelope per current hosted project. One ETag protects both representations, including comment-only edits. Every command/transition uses shared source writeback and identity provenance before commit. Old model-only envelopes gain deterministic source in memory without changing disk or revision; inconsistent paired envelopes reject startup. Service identity stays independent of model identity. A directory lock enforces one local owner; a mutex rechecks the ETag and writes the complete envelope before in-memory adoption. Admission charges both model and source. See [server.md](server.md) and [api.rst](api.rst) for limits, errors and deployment.
## Extending a supported concept
1. Define the semantics, field types, references and both editing obligations in `language.rst`; choose migration behavior if the stored schema changes.
2. Update the closed core model, reference visitors, validation and applicable command/transition/projection behavior.
3. Extend parser and formatter together; verify exact round-trip, invalid-input preservation and identity/reference maintenance.
4. Expose graphical creation/editing for each field/variant, including optional values and ordering. Keep draft and modal failure paths intact.
5. Update the REST/OpenAPI contract for new command or data variants; exercise actual HTTP candidate acceptance/rejection and persistence.
6. Run focused domain/interaction tests, strict workspace checks, and native Windows/Linux workflows with visual inspection at supported sizes. Update acceptance evidence only after observing the result.
No runtime plugin ABI, general extension framework or later-layer infrastructure is present. The documented core and REST boundaries provide practical development seams without requiring speculative abstractions.