Prepare semantic commands before atomic source adoption

This commit is contained in:
2026-09-05 21:39:25 +03:00
parent 366ce4480d
commit 41d7963d89
3 changed files with 116 additions and 5 deletions
+29 -5
View File
@@ -85,6 +85,31 @@ pub struct Session {
saved: Project,
revision: u64,
}
/// One validated command result, ready for an owning editor or service to adopt.
/// Preparation never mutates the input and allocates creation identities once.
/// A source editor can validate its corresponding document edits before either
/// representation becomes visible.
pub struct PreparedCommand {
pub project: Project,
pub selected: Option<Id>,
}
pub fn prepare_command(
project: &Project,
command: &Command,
) -> Result<PreparedCommand, ModelError> {
let mut candidate = project.clone();
let mut pending_deletions = BTreeSet::new();
let selected = apply_command(&mut candidate, command, 0, &mut pending_deletions)?;
crate::references::finish_deletions(&mut candidate, &pending_deletions);
validate_candidate(&candidate)?;
Ok(PreparedCommand {
project: candidate,
selected,
})
}
impl Session {
pub fn try_new(project: Project) -> Result<Self, ModelError> {
validate_candidate(&project)?;
@@ -143,11 +168,10 @@ impl Session {
Ok(())
}
pub fn execute(&mut self, command: Command) -> Result<Option<Id>, ModelError> {
let mut candidate = self.project.clone();
let mut pending_deletions = BTreeSet::new();
let selected = apply_command(&mut candidate, &command, 0, &mut pending_deletions)?;
crate::references::finish_deletions(&mut candidate, &pending_deletions);
validate_candidate(&candidate)?;
let PreparedCommand {
project: candidate,
selected,
} = prepare_command(&self.project, &command)?;
if candidate != self.project {
self.past
.push(std::mem::replace(&mut self.project, candidate));
+1
View File
@@ -29,3 +29,4 @@
- Source/schema3 is now implemented. The original V2 comment-normalization decision is superseded for the first-release source-project work: validated bundle updates preserve concrete tokens/comments/whitespace, while explicit canonical export remains available. Desktop bundle editing and experimental nested syntax are separate acceptance gates; neither is implied by the pure-core updater.
- Connection routing is per diagram, keyed by an existing relationship/trace ID. Store ordered pinned points and relative label placement; derive orthogonal elbows in a pure Rust core shared by canvas, picking, Fit and SVG. Typed port anchors never move to improve a route. Bounded automatic routing provides an initial path; manual pins express engineering layout intent. Collapse temporarily suspends authored routing when endpoints are promoted, preserving it for expansion. One pointer gesture commits one atomic command; stale/invalid-draft gestures are rejected.
- Source workspace integration uses one accepted history of compiled source/model snapshots. The existing semantic Session remains for model-only consumers; a shared `prepare_command` supplies validated candidates and creation selection without committing or generating IDs twice. Desktop source writeback must succeed before adoption. Comment-only accepted edits are real history entries. Drafts and disk baselines stay separate; see release-source-integration.md for the implementation and acceptance contract.
+86
View File
@@ -0,0 +1,86 @@
# Source workspace integration contract
Status: implementation in progress after the accepted routing checkpoint. This
is the next vertical slice of the first release, not release completion.
## Observable outcome
A system engineer opens an entry `.arcadia` file and edits its included files
independently. Switching files retains invalid drafts and cursor positions.
Located project diagnostics navigate across files. Apply adopts the entire
validated source/model pair atomically. Graphical edits preserve comments and
file ownership. Undo/Redo restores exact accepted source, including comment-only
edits. Save All writes the project with conflict detection and recoverable disk
failure handling; reopen reproduces the accepted model and source.
## Architecture and sequence
1. Add `prepare_command(project, command)` to the shared semantic command engine.
It returns a validated candidate and selected identity without mutating input
or executing creation twice. Existing semantic Session uses the same helper.
2. Desktop `Document` owns one history of accepted `CompiledSourceProject`
snapshots. Command preparation followed by `update_bundle` succeeds before
adoption. Source-only accepted edits advance revision and history. Separate
draft history remains an editor concern; do not synchronize two accepted
model/source undo stacks.
3. Keep filesystem code outside pure `source_project`. Discover includes with
`inspect_includes`, enforce aggregate budgets and portable/contained physical
paths, retain exact original disk bytes before identity stabilization.
4. Integrate file navigation, full-bundle asynchronous lint, Apply, Open and Save
into the existing Iced application. Results carry document identity and draft
generation. The active text control renders one file; inactive drafts persist.
5. Extend production syntax through the same compiler/index/updater, separately
from this integration. Never copy the experimental lowering/writer wholesale.
6. Verify real native two-file editing, failure repair, graphical rename, exact
Undo, Save All and reopen; obtain independent correctness and UX review.
## Failure and persistence decisions
- Dirty text in any file blocks graphical mutation until explicitly applied or
reverted. A failed compile/writeback leaves model, source, revision and history
unchanged. Diagnostics retain original per-file spans and related locations.
- Successful lint is advisory: only explicit Apply adopts inserted identities.
- Syntax/missing-include errors retain loaded editable documents. Removing an
include detaches its buffer; it does not delete a file. Compile reachable files
while retaining detached dirty content visibly and guarding close/discard.
- Check all dependency baselines before saving, including unchanged files.
Stage exact bytes, keep recovery information, replace the entry last and roll
back ordinary partial failure. Interrupted recovery must not overwrite a newly
observed external edit. This is recoverability, not filesystem-wide atomic
visibility or compare-and-swap with other editors.
- Source Save As retains relative file layout and reviews destination collisions.
JSON remains whole-model interchange and cannot erase source layout/history.
## Production syntax direction
Retain flat syntax. Nested elements express semantic parent only; allocation
stays explicit. Contextual input/output shorthand creates real SA function ports,
with item lists and an optional ordinary field body. FE shorthand references real
ports and infers redundant function endpoints after resolution. Ordered steps
blocks cover existing scenario/process/chain/Branch semantics. Typed value bodies
remain ordinary fields; includes stay document-level. No new global reserved
aliases. The parser must expose real spans and lexical ownership, never fake
spans for inferred values. Structural edits compose around the existing
UUID-aware scalar/list updater.
Contiguous leading and same-line trailing comments travel with their declaration;
blank-separated comments stay in the containing gap. Deleted syntax leaves its
comments in the old body with separation so they cannot become the next record's
documentation. Preserve authored flat placement; prefer owner-local placement
for new children. Equal explicit parent and nesting may coexist; contradictions
fail. Shorthand-derived contracts/endpoints have one definition. Valid edits that
outgrow shorthand expand that declaration locally instead of rejecting the edit.
## Acceptance evidence required
- Creation selects the same UUID persisted in source; rejection is fully atomic.
- Comment-only Apply/Undo/Redo and history branching restore exact bytes.
- Two-file errors and stale lint/discovery cannot change newer drafts or models.
- IDs stabilize once while disk conflict baselines retain original bytes.
- Item rationale comments follow UUIDs through reorder and alias swaps.
- Nested create/delete/reparent and occurrence reorder/move preserve identity,
comments, allocations and unrelated files; empty steps blocks remain editable.
- External edits/deletions/new-file collisions reject Save All before loss;
injected partial failures and interrupted recovery preserve coherent content.
- Default/minimum-size native editing and save/reopen are observed, not inferred
from compilation. Windows/Linux builds and focused regressions pass.