feat: preserve nested source projects across desktop and REST

This commit is contained in:
2026-09-06 00:17:20 +03:00
parent d364d3c058
commit 4e8575bd11
32 changed files with 4283 additions and 417 deletions
+9 -7
View File
@@ -8,9 +8,9 @@ The normative contract is [language.rst](language.rst); [scope.md](scope.md) exp
|---|---|---|
| `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 current-model storage | Iced or a desktop session |
| `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. Canonical source/JSON import/export is the explicit integration path.
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
@@ -26,7 +26,7 @@ Element kind and layer derive from closed OA/SA bodies. Shared typed bodies repr
`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.
The desktop retains up to 100 full-model history snapshots and compares against a saved snapshot to compute dirty state. This favors straightforward correctness for modest models. The cost is proportional to model size; indexed validation, persistent collections or delta history should follow profiling, not speculative infrastructure.
`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
@@ -44,17 +44,19 @@ Keep domain mapping choices in the core or derive UI choices from its queries. I
## Text and draft state
`language.rs` provides a lexer/parser, deterministic formatter, tolerant source analysis and explicit V1 adapters. It collects declaration aliases before resolving UUID references, accepts forward references, rejects unknown/duplicate fields and typed-constructor errors, and validates the complete candidate. Canonical `arcadia 2` text preserves every persistent field, alias, UUID and ordered occurrence. Comments/whitespace are lexical trivia and normalize on Apply. V1 migration preserves existing identities and derives new placement/occurrence IDs deterministically.
`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 Session, selection, draft, source buffer/history, 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. Source lint runs after a short debounce and ignores obsolete results. Valid Apply commits once; rejected text stays editable with located diagnostics. Text-buffer history is distinct from committed-model history.
`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 persistence detects JSON by content and otherwise parses Arcadia text. `.arcadia` saves canonical text; other suffixes save strict JSON. A validated snapshot is written to a sibling temporary file, flushed and atomically installed. Normal desktop saves compare the previously read bytes to detect external changes before replacement. This is an optimistic local-file check, not a guarantee against every concurrent writer or power-loss scenario. File tasks run on blocking workers; the desktop preserves drafts and pending New/Open/Close continuations on failure or cancellation.
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}` envelope per current hosted project. Service identity is immutable and independent of editable model identity. A directory lock enforces one local owner; a store mutex serializes revision checks and writes. Disk replacement precedes in-memory adoption. Authentication, body/admission limits, object/query limits and total store capacity are explicit. No distributed database, retained history, idempotency ledger or automatic artifact fetching is hidden behind this interface. See [server.md](server.md) and [api.rst](api.rst) for deployment, error and concurrency behavior.
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