From f9c5165cb9fd0f219797ebcd21bf24fd1e0b941b Mon Sep 17 00:00:00 2001 From: "sorokin.oleg.edu" Date: Wed, 23 Sep 2026 01:06:34 -0700 Subject: [PATCH] Record reviewed mixed syntax boundary and preserve Scenario contracts --- harness/DECISIONS.md | 26 +++ ...analysis-mixed-parser-proposal-20260923.md | 91 +++++++++ .../analysis-mixed-parser-review-20260923.md | 35 ++++ harness/scenario-arrangement-selection.md | 11 ++ harness/scenario-layout-contract-candidate.md | 185 ++++++++++++++++++ harness/scenario-layout-design.md | 110 +++++++++++ 6 files changed, 458 insertions(+) create mode 100644 harness/analysis-mixed-parser-proposal-20260923.md create mode 100644 harness/analysis-mixed-parser-review-20260923.md create mode 100644 harness/scenario-arrangement-selection.md create mode 100644 harness/scenario-layout-contract-candidate.md create mode 100644 harness/scenario-layout-design.md diff --git a/harness/DECISIONS.md b/harness/DECISIONS.md index 498cbce8..dbaf2e4d 100644 --- a/harness/DECISIONS.md +++ b/harness/DECISIONS.md @@ -1,5 +1,31 @@ # Architectural and product decisions +## Private mixed syntax boundary — 2026-09-23 + +Proceed with the [reviewed syntax-only slice](analysis-mixed-parser-review-20260923.md) +on tested private source `10d7f334`, retaining current root `195ddbb` as an +ordinary-compatibility reference. Direct comparison found the relevant ordinary +syntax/include machinery equal or equivalent; whole-file drift chiefly concerns +semantic/editor behavior. A full root merge is not a prerequisite for this +private experiment, and neither whole language/updater file may replace the +other during eventual integration. + +One opaque complete-bundle result borrows the actual original files and owns +the shared budget, canonical file table, ordinary occurrence positions and typed +unresolved syntax. It supplies no admitted Project, Index or edit authority. +Explicit IDs are a staging restriction; missing IDs reject before generation. +Retain duplicate syntax occurrences until semantic uniqueness is checked. +Ordinary signed numbers require byte adjacency and complete value spans; +typed subtraction retains its separate grammar. Bound aggregate syntax storage +without silently reinterpreting caller model-record or ordered-step limits. +Propagate phase-check failures even where the Budget does not latch them. + +The [proposal](analysis-mixed-parser-proposal-20260923.md) and review define the +independent fixtures and rejected shortcuts. Same-pass unresolved syntax is a +dependency of later mixed resolution/index/composition, not public source8 +activation or a substitute for whole-output admission. Source implementation, +fresh review and runtime checks remain required. + ## Private source composition decision — 2026-09-23 Adopt the opaque validated original-span rename batch as the next private diff --git a/harness/analysis-mixed-parser-proposal-20260923.md b/harness/analysis-mixed-parser-proposal-20260923.md new file mode 100644 index 00000000..eac1d8bc --- /dev/null +++ b/harness/analysis-mixed-parser-proposal-20260923.md @@ -0,0 +1,91 @@ +# Next private mixed-parser slice + +**Original proposal, subsequently narrowed by the [independent review](analysis-mixed-parser-review-20260923.md).** The parent accepted the private syntax-only direction with that review's corrections; implementation and runtime acceptance remain open. In particular, the review resolves the base to A and corrects this proposal's inference of ordinary grammar drift from whole-file statistics. The following inspection is retained as its original reasoning, not a public source8 claim. + +Read-only inspection, 2026-09-23. Private source pin A=`10d7f3340d5cd61a656dc0bcf7c143f8897c5551`; current ordinary/public pin R=`195ddbbba5b352af09bca385a6c3e4dd1c77f8c8`. Both pins checked before and after inspection. No compiler, source edits, GUI or Gitea operations. Parent reports A passed Windows 173 listing/65 typed/strict; those gates do not exercise mixed parsing. + +Read the published `harness/analysis-original-span-proposal-20260922.md` and `harness/analysis-original-span-review-20260923.md` at R, plus A's `harness/analysis-source8-20260913/analysis-source8-repair-design-r2-20260913.md`, especially “Source pipeline and exact editing” and the resource/older-version contracts. This note narrows their next parser dependency; it does not replace them. + +## Recommendation and exact deliverable + +Implement **one private complete-bundle syntax parse**, producing an opaque `ParsedMixedSyntax` witness. It retains ordinary unresolved syntax and ordinary edit positions alongside typed unresolved declarations, from one significant-token stream per original file and one inherited budget for the complete pass. Start with explicit stable IDs only, source8 entry, existing ordinary grammar, all existing typed declaration grammar, and normal include/path rules. It returns no Project, Index, rename authority, output text or installed document. A complete semantic/session witness is a dependent slice, not an alternative name for this syntax result. + +This resolves actual mixed-file dispatch, full-file coordinates, lexical ownership, aggregate scanning and same-parse ordinary edit provenance before undertaking cross-domain lowering or production composition. Root public dispatch remains closed; a private constructor selects source8 policy before scanning and verifies that the actual entry says 8. No schema constant, public parser acceptance, save route or model change belongs in this patch. + +## Existing source seams + +Paths below are repository-relative; line numbers belong to their indicated pin. + +| Existing site | Consequence for the slice | +| --- | --- | +| R `language.rs:1066` `parse_unit`; `:1272` Parser; `:1489` unit | `strict_tokens` owns a separate token Vec; unit mixes entry/header/includes, iterative ordinary declaration nesting and fields. Add a private mixed entry through factored grammar operations, retaining the iterative declaration-owner stack. Public versions currently stop at 7. A has the corresponding unit at `:1332`. | +| R `language.rs:1155–1270` `edit_declarations`/`edit_positions` | `edit_declarations` reparses and `edit_positions` rescans, derives delimiter ends and assumes token shapes. A mixed caller cannot invoke these helpers on the original mixed file. Factor a positions projection over the already parsed ordinary AST and retained token/span metadata. Keep the legacy wrappers' observable behavior. | +| R `language.rs:1392` ordinary `value_inner` | Ordinary numbers remain finite JSON values; they are not Exact. Raw `-` + number must be consumed as one ordinary signed value with its complete span; typed `1-2` is subtraction. Preserve ordinary rejects such as `+1`, `1e`, `1_0`, `0x1` and nonfinite JSON numbers. | +| A `language/raw_tokens.rs` Scanner and legacy adapter; `analysis_source/lex.rs:23` tokens | Scanner already preserves raw full-buffer spans and separates typed operators. Legacy adaptation greedily groups adjacent numeric parts and performs JSON classification. Do not use that whole-file legacy adapter for mixed source; typed lex currently charges bytes/raw tokens, including trivia, before retaining significant tokens. | +| A `analysis_source/cursor.rs:5` Cursor; `declarations.rs:243` parse | Typed parse already consumes a borrowed significant cursor, checks inherited version=8, rejects lexical owners, and returns unresolved full-buffer declaration/field/reference/literal spans. This is the useful dispatch seam; `analysis_source::parse` is an expression-only whole-input wrapper. | +| R `source_project.rs:303–605` compile_once | Existing iterative include visitor owns path normalization, cycle/depth/edge/visited checks, aggregate ordinary counts, unreachable-file rejection and located errors. Reuse/factor its traversal policy for private syntax collection; do not call compile_once and discard its model. Its `:429` parse_unit call is the later production substitution point. | +| A `analysis_source/index.rs:147–195` parse/build | Current parse scans typed-only numeric-keyed files and accepts a separately supplied ordinary Project. Calling it on mixed buffers fails; calling it on extracted typed text invents provenance. Keep build private. This slice does not manufacture an Index. | +| A `analysis_source/lower.rs:269` lower | Accepts ordinary skeleton plus all typed units; collects all typed globals/signatures before bodies; deliberately does not admit the skeleton. Needed in the next semantic slice after the shared syntax witness exists. | +| R `source_project.rs:895`, `:918`, `:984`, `:1050–1071` update path | Actual-file ordinary edit ASTs, formatted comparison ASTs and local project-header spans have different roles. Later production editing uses retained actual-file positions; retain CompleteForEdit/Compact formatting and their comparison semantics. Scalar application, structural second pass and full candidate equality remain outside this parser patch. | + +R and A's ordinary files are materially different (427 insertions/81 deletions across language.rs/source_project.rs in the inspected comparison). R also contains current CompleteForEdit/Compact work. Do not copy A's whole language/source_project files over R or overwrite the parent's Scenario integration. Pin the combined implementation base and agree ownership of the shared grammar hooks before coding. + +## Minimal private interfaces and ownership + +Names are illustrative, not a request for a public framework: + +```rust +parse_mixed_syntax(bundle: &SourceBundle, limits: ProjectLimits, + test_profile: /* optional tighter private profile */) + -> Result, Vec>; +``` + +The result privately borrows the **actual complete SourceBundle**, owns the one finished Budget, canonical file table, parsed units and retained significant tokens/ordinary position metadata. It retains entry, every canonical path and original bytes through that borrow. File keys are minted once from canonical bundle keys before traversal; the include visitor visits each reachable file once. A FileKey is meaningful only through its owning result, never an independently accepted `(usize, path)` mapping. Store paths/source references into the borrowed bundle rather than a self-referential owned Index-plus-source-map structure. Constructors are private; expose read-only inspection only. This establishes syntax provenance, not semantic validity or mutable-current freshness. + +Each file result contains its source reference, entry/fragment role, include spans, ordinary declarations with lexical owners, typed declarations, and ordinary edit positions. Positions remain half-open **full original file UTF-8 byte offsets**, even after Unicode comments, the project header, includes or preceding declarations. No header/include offset is added to typed spans. Nested ordinary declaration spans legitimately contain descendant declarations; declaration ranges are descriptive ownership, not automatically disjoint replacement authority. + +Use one shared significant-token cursor state. Ordinary grammar methods may have a domain-specific borrowed view; they must advance the same token position used by typed `declarations::parse`, without copying/rescanning a declaration or replaying a speculative parse. Preserve legacy grammar through factoring, not by cloning a second independently maintained ordinary parser. Keep token access/classification adapters small and local; no general parser trait framework is required. + +At document scope, dispatch exact typed declaration words before generic ordinary `declaration_kind`. Inside an ordinary element's open body, recognize a typed header only to deliver the existing “must be roots” error; do not reinterpret it as an ordinary field. Contextual words such as `unit`/`calculation` must remain legal aliases where already allowed. Entry descriptions/includes keep current placement rules. Generic derived long analysis kind names must not become an alternative accepted syntax. + +For ordinary edit positions, a raw numeric value may cover several significant tokens (`-12.5`). The current token-end heuristic would cover only `-`. Record ordinary value end spans as grammar consumes values (a small per-file side table keyed by the existing AST start offset is sufficient), then project EditValue from that AST plus spans. Keep the shared legacy/migration Ast representation unless a demonstrated need justifies changing it. Record ordinary header token roles from actual parsing as well; do not obtain them with another `edit_header` scan. Typed declaration spans/expressions never enter ordinary EditKind::Record recursion. + +**Stable-ID scope:** reject omitted project, ordinary global, typed global or parameter IDs in this first private entry before returning a witness. The ordinary `optional_id` path currently creates UUIDs, so the private mode must reject before that generation; typed IdentitySyntax already retains missing identity/insertion information. This intentionally postpones stabilization instead of assigning hidden IDs or granting edits against pre-insertion offsets. Later accept missing IDs only through bounded insertion into the returned full documents and a new complete parse of those actual bytes. + +## Budget and parser invariants + +Create one Budget at the private complete-parse boundary from source8 hard ceilings intersected with caller restrictions and any tighter test profile. Own it in the returned witness; lower/index/compose later obtain it from that witness, with no ambient replacement/reset API. Creating a Budget for each include or switching token policy after seeing local fragment syntax is invalid. Selecting explicit private source8 mode before lexing avoids a public version-probe implementation in this slice; eventual public dispatch needs a bounded header read with unambiguous accounting. + +Precheck aggregate file/UTF-8 byte size before broad token/String allocations. Charge each file's original bytes once in scanning; a prior noncharging aggregate limit check is not another charge. Charge every raw token including trivia once, before storing; significant filtering and ordinary legacy-compatible numeric consumption do not recharge tokens. EOF carries no token charge. Do not scan or convert typed exact atoms again to derive positions. JSON ordinary values keep their finite numeric domain, and exact numeric WorkMeter use belongs only to typed numeric consumption. + +The mixed parser must also bound ordinary temporary containers/references before allocation; existing per-unit graph counts and final `check_model` alone are insufficient. Specify the charge table in the patch: ordinary declaration/field/value/list-entry allocations join the private syntax-storage ceiling; retain caller graph/record accounting separately; ordinary reference storage is bounded before copying, while caller ordered-step/reference semantics remain explicit rather than silently relabeling every scalar reference a model step. Typed existing entry/reference charges stay intact. Count aggregate phase metadata (file table, positions, catalogs later) before reserving; the existing typed budget phase checks are reusable but do not magically bound ordinary additions. Preserve ordinary value-depth64 and separate typed frame256/logical-depth128 semantics and safe failure cleanup. Tests must discriminate which bound fails. + +## What this does not yet solve + +The dependent **ResolvedMixedBundle** must consume this syntax witness, collect one global alias/identity/category catalog including typed declarations, build the ordinary skeleton against it without premature complete-model admission, lower typed units once, merge them, admit the whole Project, and construct Index internally from the same tokens/units/lowerer result. Only that result can bind complete Project, Index, file table, original bundle and inherited Budget for composition. Current A Index borrows `BTreeMap`; adapting its private source accessor to witness-owned file references is justified there. Exposing `build(Lowered, spans)` to arbitrary callers is not. + +R `language::resolve_declarations` combines ordinary construction, version migration and final limits; A additionally migrates source7 through `migrate_v7`. Neither is an appropriate “parse ordinary and admit first” shortcut: forward ordinary references may target typed records, and typed subjects/types/calls may target later files. The semantic slice needs a narrowly extracted non-admitting ordinary construction step, complete catalog, and one final model admission. Syntax witness tests cannot prove these relationships or satisfy intended-Project equality. + +Coordinated version7→8 blockers for production are: reconcile root schema7 with private schema8 definitions/analysis and Scenario payload; preserve frozen older DTO/source gates and the source3 old-envelope boundary; choose the one public dispatch/migration change; stabilize missing global/parameter IDs and reindex actual returned bytes; retain required categories and ordinary complete/compact edit behavior; supply complete mixed lowering/index provenance and supported-edit diff gate; compose original edits once and recompile/admit/compare the entire actual output; pass migration/history/checked-save and resource calibration gates. None requires a new metamodel or blocks this private explicit-ID syntax slice. Root should coordinate them, not accept `arcadia 8` early to make a fixture pass. + +## Rejected shortcuts and cost comparison + +| Approach | Decision | +| --- | --- | +| Shared scanner/cursor + existing grammar extraction + same-parse ordinary positions | Recommended: moderate localized factoring; directly tests mixed boundaries and retains ownership. Limit deliverable to syntax until semantic construction is ready. | +| Parse ordinary and typed projections independently, then combine models/indexes | Reject: masking preserves numeric offsets at best but loses actual-source token/ownership proof; substring/concatenation creates local offsets; separate parses reset or double-charge resources and cannot establish cross-domain global resolution. A clever remap does not repair these invariants. | + +Also reject whole-file legacy tokenization (typed punctuation fails/typed number domain changes), silent retries with larger budgets, counter subtraction after rescanning, caller-supplied numeric file remapping, and treating equal bytes/shared lifetimes as proof of the same semantic parse. A full replacement edit AST is unnecessary for this step. + +## Six observable first-slice fixtures + +All are proposed, unrun. Use independently authored source literals and expected span/substring tables rather than expectations extracted from the result itself. + +1. **Interleaved CRLF/Unicode:** entry description/comment, ordinary nested element, typed calculation with `1-2` and `1e-2`, ordinary record with negative coordinates after it. Verify exact original substring at every selected ordinary/typed/header/value span, lexical owners, and byte-identical complete input. Explicit `-12.5` ordinary span must include the minus and full atom. No output Project claim. +2. **Complete include binding:** root + nested-path module + shared dependency reached twice; mixed declarations after include prefixes in two files with identical local offsets/spellings. Check unique scan count, fixed FileKey/path mapping, exact include spans; cycle, missing, escaping and unreachable-file negatives return no complete witness. Entry/path/map replacement is not an accepted constructor operation. +3. **Dispatch and grammar separation:** `unit`/`calculation` used as allowed ordinary aliases, all short typed declaration kinds, typed roots between nested ordinary blocks. Reject typed lexical nesting, long derived analysis names, fragment version headers and source7 at this private source8 entry. Existing public source3–7 and public source8 rejection remain unchanged. +4. **Number/position compatibility:** ordinary signed/exponent JSON values and typed exact ratio/scientific expressions, with comments between legal typed tokens. Ordinary `+1`, split-sign forms not admitted by the old grammar, malformed/nonfinite JSON values reject. Typed values beyond JSON precision retain exact values/literal spans. Existing ordinary token compatibility tests plus independently stated old outcomes prevent broadening by accident. +5. **Aggregate budget and failure cleanup:** one-file and split-file variants with exact byte/token/ordinary-storage/reference/numeric ceilings and plus-one failures; include trivia; add an earlier ordinary allocation so a later typed declaration crosses the shared ceiling, and reverse producer order. Previously latched failure returns no witness. Test-only scanner visitation/Exact conversion counters demonstrate one scan/one conversion; unchanged counters alone do not. Run retained 128-KiB typed depth/rejection cleanup controls when parser ownership changes warrant them. +6. **Opaque syntax scope:** explicit-ID positive across all declaration/parameter kinds; remove one ID in each domain and require refusal with original bundle unchanged. Read-only ordinary EditValue and typed occurrence syntax inspect the same witness; no external AST/Lowered/FileKey-map constructor exists. Unresolved forward ordinary/typed references can be retained syntactically, but do not assert they resolve. A following semantic slice must add reordered cross-file forward references, repeated/reordered calls, reused parameter UUIDs, catalog collisions, wrong-session batch rejection and independent whole-Project equality. + +First patch completion means these syntax/ownership/resource fixtures and unchanged ordinary compatibility tests pass on an immutable Windows source pin with fresh review. It does not mean mixed renames, source8 save, full S3/S4, public schema activation, or all semantic references work. diff --git a/harness/analysis-mixed-parser-review-20260923.md b/harness/analysis-mixed-parser-review-20260923.md new file mode 100644 index 00000000..a81ed3bf --- /dev/null +++ b/harness/analysis-mixed-parser-review-20260923.md @@ -0,0 +1,35 @@ +# Private mixed syntax proposal: independent review + +**Disposition: proceed with a private syntax-only implementation on A=`10d7f3340d5cd61a656dc0bcf7c143f8897c5551`, with the bounded corrections below.** Do not first merge the full current root or copy either side's complete language/updater files. The proposed single-buffer cursor, original coordinates, complete-bundle borrow and inherited budget address the real next dependency. A semantic witness, compositor, ID stabilization and public activation remain separate dependent work. + +Reviewed `.local/analysis-mixed-parser-next-slice-20260923.md`, the published original-span proposal/review at R=`195ddbbba5b352af09bca385a6c3e4dd1c77f8c8`, the private r2 design, and actual A/R source. Source/design review only: no tests, compiler, GUI, source/worktree edits or Gitea operations. Parent's reported A gates are export/typed evidence, not mixed-parser evidence. Line references below are pinned to A or R; `analysis_source/*` means `crates/oa-core/src/language/analysis_source/*`. + +## Resolve the implementation base now + +The proposal's 427/81 whole-file difference is real but does **not** demonstrate materially different ordinary syntax. Direct Git extraction established: + +- `source_project.rs` is byte-identical from the file start through the entire include/compiler/edit-application section before `format_bundle`. Thus the traversal policy at R/A `:303–605` has no R/A drift. +- `parse_unit` and the edit-header/declaration/position section are byte-identical (A `language.rs:905–1109`, R `:1066–1270`). Parser `fields` through `value_inner` is byte-identical (A `:1179–1293`, R `:1336–1450`). The iterative `unit` implementation differs only in A initializing its additional empty `Project.definitions` member. UUID optional-ID behavior is equivalent; R factors the existing shape check into `has_uuid_header_shape`. +- Real differences requiring later integration include raw-token versus current bounded tolerant-outline tokenization, A's analysis model/migration/source3 bridge, and R's ordinary defaults plus complete/compact formatter/updater. R `language.rs:1757` and `source_project.rs:853` are semantic/edit behavior, not prerequisites for a syntax-only result. A's generic `declaration_kind` also sees a larger `Kind::ALL`; equal grammar function bodies do not imply equal recognized kind sets. + +**Concrete base:** keep A's tested private analysis/numeric/export dependency closure and existing module isolation; factor its ordinary syntax/position code in place, using R's pinned ordinary behavior as a compatibility oracle. Implement the mixed unit/bundle owner privately, sharing the factored ordinary grammar and include policy with existing A paths. Do not port R's whole updater, Text outline, Scenario payload or schema constants for this experiment. Keep a narrow compatibility note identifying the equal syntax seams and intentionally deferred semantic/editor differences. Recheck those seams against the parent's eventual integrated pin before proposing production composition. This avoids an unrelated model/GUI integration prerequisite and does not claim A already contains root ordinary default/update behavior. + +## Corrections and acceptance conditions + +1. **Define ordinary numeric consumption precisely.** A `raw_tokens.rs:158–181` preserves the legacy greedy, *byte-adjacent* numeric alphabet; the mixed significant adapter (`lex.rs:19–51`) discards trivia. A two-token `-` plus Number rule without adjacency would newly admit `- 12.5` and `- //comment\n12.5`. Require contiguous original spans, complete ordinary numeric spelling, finite JSON classification, and the original complete value end. Keep `+1`, `.5`, `1e`, `1_0`, `0x1`, `1-2` invalid as ordinary values; typed `1-2` and exponent `1e-2` retain their different meaning. This belongs in a small ordinary-consumer view over the same cursor, not a second lexer or substring parse. Full field/value spans must include semicolon/delimiters correctly after multi-token negatives. Check nested records/lists and `@ /*not supported*/`-style malformed trivia as well as top-level coordinates. Only `//` comments are supported by the current scanner. + +2. **Preserve occurrence ownership before semantic uniqueness.** Explicit IDs are a reasonable first-slice restriction because the ordinary AST and lexical owners currently require `Id`, and edit positions refuse unstabilized declarations (R `language.rs:1232–1240`). Reject missing ordinary/project IDs before `optional_id` generates UUIDs (`:1316–1319`); inspect typed globals and every parameter's existing `IdentitySyntax` (`A declarations.rs:34–42,406–434`). This is staging policy, not proof syntax intrinsically requires explicit IDs. Do not add stabilization here. Conversely, do not key syntax/position storage solely by UUID or alias: ordinary `edit_declarations` explicitly preserves occurrences through temporarily duplicate identities (R `:1151–1154`), and global uniqueness is deferred to resolution. Preserve ordered declaration occurrences and lexical owner occurrence information; either retain duplicate IDs without collapsing nodes, or explicitly label any early uniqueness rejection as additional syntax-slice policy. Reused parameter UUIDs across calculations remain legal. The side table keyed by actual AST start is suitable. + +3. **Make the storage table concrete without relabeling model limits.** A `budget.rs:16–24` currently derives syntax entries from caller `max_records` and references from `max_step_references`. Counting every ordinary declaration, field, value and list slot against that same limit can reject a one-project/one-element input under `max_records=2` solely because it has a description field, although the ordinary model has two records. Similarly `parent @x` is not automatically an ordered model step. Keep bounded syntax storage and aggregate ordinary model counts distinct and document which bound each fixture targets. If retaining the existing candidate source8 syntax ceiling is deliberately stricter, state that private policy; do not claim preservation of all caller-limit behavior. Preserve public source3–7 accounting. Tokens/metadata/position copies need an aggregate storage bound, not a fresh per-file check or repeated independent allowance. Do not charge the same AST record again merely because a span references it. A `lowering_entries/index_bytes/lowering_occurrences` are noncharging **phase checks** (`:137–160`) and do not latch failure; all their errors must propagate immediately. `Budget::active` alone is not proof those phase failures were retained. + +4. **Keep factoring localized and dispatch contextual.** Share `fields/value/nesting/header` operations; retain the iterative declaration stack. The ordinary parse wrapper can continue selecting its legacy view and the private mixed wrapper its raw-token view, while both call one grammar implementation. No generic parser trait framework or second independently maintained ordinary parser is needed. Inside an ordinary body, reject a *typed declaration header*, not every field whose word happens to be `unit` or `calculation`; ordinary syntax retains generic field names before semantic validation. At document scope, short typed words dispatch first. Explicitly exclude long analysis-derived ordinary kinds on A: `language.rs:236–259` builds names from the expanded `Kind::ALL`, so dispatching short words first alone does not close that alternative syntax. + +5. **Provenance is the whole constructor, not token retention alone.** Borrow the actual `SourceBundle`, including entry and all files, validate canonical/case-colliding paths and complete reachability before returning, and mint the path table internally. Maintain one shared cursor index and Budget. Temporary borrowing of the owned token vectors is sufficient; do not create a self-referential stored Cursor. Retaining tokens is justified for the later Index's token witnesses (`A index.rs:185–195`), but there is no need to clone a second token stream or expose a public profile/configuration framework. A test-only tighter-profile constructor or fixed private helper suffices. A result may privately reuse the existing header container with its empty Project shell, but must not expose it as an admitted ordinary model. The distinction between `ParsedMixedSyntax` and a later resolved/admitted witness is sound. Keep construction of the latter internal, with ordinary construction against the full catalog, lower-once, final admission and same-parse Index creation; the current typed-only `Index::parse(ordinary, numeric_files, budget)` is not that authority. + +## Bounded first-patch gates + +The six proposed fixtures are a useful sufficient scope with these additions: signed-value adjacency and nested value/field ends; a contextual typed word used as an ordinary field/alias; long derived analysis-kind refusal on A; duplicate ordinary identities without position collapse; reused scoped parameter UUIDs; ordinary model-record versus syntax-storage boundaries; shared dependency scanned once; and exact Unicode/CRLF source substrings independently specified. Missing-ID failures must leave input unchanged and never call UUID generation. A deliberate phase-bound failure must return no witness, even though that check does not latch the Budget. + +Require compatibility tests for the public legacy token/parse paths actually touched by factoring, including the existing `raw_tokens::tests::legacy_adapter_retains_authored_numeric_operator_and_trivia_tokens`. Retain ordinary depth 64, typed frame 256/logical depth 128, and the applicable small-stack cleanup controls. These are future acceptance tests, not executed results. Do not require unrelated source updater/GUI integration gates to approve a syntax-only private patch; require those when its code is composed into the corresponding production path. + +The broader rejection of projection/masking and fabricated `build(Lowered, spans)` provenance is justified. No alternate architecture is needed. The next useful action is this bounded private implementation with the charge table and ordinary numeric adapter specified in its patch, followed by fresh source review and appropriate parser gates. diff --git a/harness/scenario-arrangement-selection.md b/harness/scenario-arrangement-selection.md new file mode 100644 index 00000000..7251979c --- /dev/null +++ b/harness/scenario-arrangement-selection.md @@ -0,0 +1,11 @@ +> Preserved from Scenario source `14e7e6aa46f59346c7a9a478fc9498fd0b496aaf`. This records its original design or selection contract. Combined implementation candidate `015273ac` and its review are tracked in Gitea issue27; public version adoption and combined acceptance remain open. Original proposal status below is historical and does not claim current runtime results. + +# Scenario arrangement selection + +An explicit arrangement change follows an inspector that is showing the current Saved Diagram record. Switching from Saved A to Saved B selects B and refreshes its Properties draft. Switching that view inspection to Automatic selects the Scenario owner, since Automatic has no Diagram record. An occurrence, lifeline, Scenario owner or independently selected foreign view keeps its selection. Returning from Automatic to a Saved view therefore preserves an already selected Scenario owner. + +The follow intention is captured before the existing property Apply. The destination must pass the existing owner/context checks; a rejected draft or stale event cannot change selection. A same-view UUID edit follows the resulting Diagram identity. Successful entry refreshes the selected view's draft without a second Apply or a new document transaction. Passive page navigation and Back retain their existing behavior. + +This corrects the actual Scenario picker (`CanvasEvent::Representation`). Previously, selecting A's whole-view usage and then choosing B left A selected, so the exact-current-view Details guard disabled Properties. Preserving that foreign view selection would make the inspector disagree with an explicit view change. Broadly selecting B after every arrangement change was rejected because it would discard an engineer's independent model-element inspection. The separate `Message::Diagram` handler already follows the current view, but its global UI picker excludes Scenario diagrams and cannot substitute for this workflow. + +The regression module `app::scenario_details_tests` exercises the real picker overlay and Properties button, independent selections, Automatic, valid draft application and exact Undo/Redo, same-view UUID edits, and invalid/stale refusals. A container ID exposes the unchanged picker's bounds to the mounted evaluator. Native acceptance must retain the original A-record → Scenario arrangement B → Details → Properties workflow. Compilation and actual execution status belong to the linked review and [Gitea issue #24](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/24). diff --git a/harness/scenario-layout-contract-candidate.md b/harness/scenario-layout-contract-candidate.md new file mode 100644 index 00000000..5d205d89 --- /dev/null +++ b/harness/scenario-layout-contract-candidate.md @@ -0,0 +1,185 @@ +> Preserved from Scenario source `14e7e6aa46f59346c7a9a478fc9498fd0b496aaf`. This records its original design or selection contract. Combined implementation candidate `015273ac` and its review are tracked in Gitea issue27; public version adoption and combined acceptance remain open. Original proposal status below is historical and does not claim current runtime results. + +# Scenario layout contract candidate + +Status: proposal for peer coordination; no public spelling, version, migration or gesture policy is adopted here. Scope: Scenario only; two independent saved views, lifeline x and direct message send y. This document elaborates [the selected storage direction](scenario-layout-design.md). It is not a replacement for that direction or the user specification. No core implementation or runtime verification accompanies this candidate. + +## Existing facts and scope + +The working baseline uses schema/source 7. Diagram already owns a representation UUID/alias and architecture placements/routes; StateMachine is an owner-bound projection precedent. Current Scenario rendering derives geometry from a semantic owner without saved lane positions. A Scenario occurrence is independently identified from its represented Exchange; a Lifeline is independently identified from its represented performer. Existing OccurrenceEndpoint contains explicit reference-occurrence IDs and an occurrence ID. + +The first slice edits occurrences belonging to the chosen Scenario's own sequence tree, including its nested Fragment/Branch sequences. Here **direct** means no traversal through ScenarioUse or SequenceReference: it does not mean only top-level steps. Expanded called-scenario appearances, process topology, action/state/ref-box placement, independent receive positioning, routes, labels and resize remain outside this payload's first implementation. Their omission is not completion of #20. + +## Candidate Rust shape + +Names below are proposed. Preserve existing architecture JSON/source fields and defaults; do not migrate them into a new universal payload. + +~~~rust +// Additional ProjectionKind variant; existing variants unchanged. +Scenario { scenario: Id } + +// Additional Diagram field. +#[serde(default, skip_serializing_if = "Option::is_none")] +layout: Option, + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +enum DiagramLayout { + Scenario(ScenarioLayout), +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)] +#[serde(deny_unknown_fields)] +struct ScenarioLayout { + #[serde(default)] + lanes: Vec, + #[serde(default)] + messages: Vec, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +struct ScenarioLanePosition { + lifeline: Id, + x: f32, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +struct ScenarioMessagePosition { + address: OccurrenceEndpoint, + send_y: f32, +} +~~~ + +There are no new row UUIDs, aliases or UUID-valued map keys. Lane row identity is its lifeline reference; message row identity is the complete address. The source declaration identity remains the Diagram UUID. Collections preserve authored order, but their order has no geometric or semantic ordering meaning. + +A Scenario projection requires an existing Scenario in the Diagram's layer. It accepts layout absent/none (fully automatic), or the Scenario payload. A present empty payload is valid and distinguishable in the stored model from absence; editing must not gratuitously normalize one to the other. Other projections reject a nonempty Option regardless of whether its contained lists are empty. Scenario diagrams require empty architecture nodes and routes. Existing view_options remain governed by their existing contract; this slice neither invents scenario filter semantics nor silently applies architecture options. + +Only one payload field is introduced. Future geometry should extend an appropriate typed payload, not add unrelated optional lane/message/process bags to Diagram. Existing source 7 readers must not accept the new projection or new layout field, including explicit none; the eventual version gate is a coordinated change, not an implication of serde defaulting. + +## Exact address and value admission + +1. A lane reference must name a Lifeline directly owned by the projected Scenario. Two Lifelines representing the same performer are distinct valid keys. +2. A message address must have references: [] and name an Occurrence whose body is Exchange. Reject any nonempty references list with an explicit unsupported-address diagnostic. Do not resolve it to its terminal occurrence or truncate it. Reusing OccurrenceEndpoint reserves the identity vocabulary, not expanded-reference support. +3. Membership follows the Scenario's actual steps and recursively its own fragment operands/branch steps, consistent with valid parent/step membership. Do not use arbitrary transitive element descendants, represented Exchange identity, or name matching. An unrelated occurrence is invalid even when it represents the same exchange. A Fragment, Action, State, ScenarioUse or SequenceReference occurrence is not a message-position key. +4. Missing sender/receiver/exchange references that are already admitted as unfinished semantic content do not themselves invalidate a correctly owned message-position row. Its authored intent may remain latent until an arrow can be rendered. The renderer must not fabricate endpoints; direct manipulation can begin only on actual geometry. Deleting the message occurrence is different from temporarily removing its endpoint assignment. +5. Reject duplicate lifeline IDs and duplicate complete message addresses after alias resolution, even when values are equal. The same address in two different Diagrams is valid. Unknown fields, missing required lifeline/address/send_y/x, malformed UUIDs and invalid nested records reject the entire candidate. +6. x and send_y are finite binary32 values with absolute value at most existing MAX_COORDINATE (1,000,000 at this baseline). Negative values and signed zero follow the same numeric admission; there is no new positive-only minimum or automatic clamp. Structural admission does not promise a feasible rendered chronology. The separately specified projection must report unsupported geometry and preserve authored intent rather than silently edit semantics or coordinates. Whether the first release refuses such an edit before commit is a separate projection/gesture integration decision. +7. Count one present payload and every lane/message entry against ParseLimits.max_records; these introduce no semantic graph objects. Reference paths are empty in this slice. Enforce shared byte/depth limits before generic allocation, then collection budgets before building membership or duplicate indexes. Validate with bounded traversal/visited identity sets and indexed membership, not one full scene traversal per entry. This counting proposal must be reconciled with #7's checked codec once; it is not a second admission system. + +send_y always means the actual message's send endpoint in diagram coordinates. Normal and self messages preserve their renderer-defined send-to-receive offset for whole-message placement. In particular, a self Create/Delete currently stores a receive-oriented row: converting send_y to that row is the renderer bridge's responsibility. Store neither that internal row convention nor activation/capsule coordinates. This contract does not reorder steps, flatten parallel/alternative operands, or prescribe how a user's drag crosses another event. + +## JSON and source examples + +The following JSON is a complete **candidate Diagram value**, assuming the referenced Scenario/lifeline/message exist with compatible ownership and layer. Version headers belong to the containing project and are deliberately not assigned here. + +~~~json +{ + "id": "10000000-0000-4000-8000-000000000001", + "alias": "nominal_view", + "name": "Nominal spacing", + "description": "", + "layer": "Oa", + "projection": { "Scenario": { "scenario": "20000000-0000-4000-8000-000000000001" } }, + "nodes": {}, + "routes": [], + "layout": { "Scenario": { + "lanes": [ { "lifeline": "30000000-0000-4000-8000-000000000001", "x": 420.0 } ], + "messages": [ { + "address": { "references": [], "occurrence": "40000000-0000-4000-8000-000000000001" }, + "send_y": 200.0 + } ] + } } +} +~~~ + +Equivalent proposed declarations in a containing source project whose aliases resolve to those identities: + +~~~text +diagram nominal_view "Nominal spacing" id "10000000-0000-4000-8000-000000000001" { + layer Oa; + projection { Scenario { scenario @nominal; }; }; + layout { Scenario { + lanes [{ lifeline @controller_lane; x 420; }]; + messages [{ + address { references []; occurrence @delivery_first; }; + send_y 200; + }]; + }; }; +} +diagram review_view "Review spacing" id "10000000-0000-4000-8000-000000000002" { + layer Oa; + projection { Scenario { scenario @nominal; }; }; + layout { Scenario { + lanes [{ lifeline @controller_lane; x 680; }]; + messages [{ address { references []; occurrence @delivery_first; }; send_y 240; }]; + }; }; +} +~~~ + +These are candidate syntax examples, not claims that the current parser accepts them. Source uses @alias in every reference field; UUID string literals remain JSON references and declaration IDs, not a source-reference shortcut. + +Invalid variations: repeat controller_lane in one lanes list; repeat the same message address with another send_y; use the represented performer as lifeline; use an Exchange definition as occurrence; use another Scenario's message; use references [@scenario_use]; attach this payload to Overview; add an architecture node or EdgeRoute to this Scenario view; supply NaN/infinity or x beyond the shared bound. Each refusal preserves the entire accepted model/source/history. Equal coordinates for distinct valid lifelines are not a duplicate-key structural error; any graphical overlap feedback belongs to projection policy. + +## Commands, sparse values and no-op behavior + +CreateDiagram/EditDiagram remain complete-record operations. Candidate focused command names are: + +~~~rust +SetScenarioLanePosition { diagram: Id, position: ScenarioLanePosition } +RemoveScenarioLanePosition { diagram: Id, lifeline: Id } +SetScenarioMessagePosition { diagram: Id, position: ScenarioMessagePosition } +RemoveScenarioMessagePosition { diagram: Id, address: OccurrenceEndpoint } +~~~ + +A Set validates the Scenario context/address, creates its compatible empty payload if absent, replaces an existing row in place or appends a new row, and retains unrelated rows and order. Setting an existing numerically equal value preserves the original record, including signed-zero representation; do not replace -0 with +0 during an otherwise changing batch. Explicitly setting an absent override is an authored change even if it equals today's automatic coordinate. Remove validates the existing diagram and valid semantic address before removing; removing an absent override is a no-op. Removing the final row retains a present empty payload. Explicit EditDiagram can clear it to None. + +A gesture with zero actual motion never synthesizes a Set from projected coordinates. Its captured authored value, representation/document/revision/input identity and actual delta govern preview; stale/cancel/no-motion produces no write and no new Diagram. The first actual edit of a derived view prepares a fresh Diagram identity and initial override in one checked transaction; allocation during preview alone must not become a persisted record. Undo returns to the exact prior model/source absence; Redo restores the same created identity. + +All command paths use existing prepare_command/execute_batch and checked source writeback. Validate the final batch; reject atomically on structural/source failure. Desktop history captures the complete compiled source snapshot. REST uses its existing If-Match, dry-run and changed:false contract. No new transaction or layout history is introduced. Only the final model/source pair decides no-op: numeric equality must not justify erasing different record provenance or source text. + +## Delete, copy, retarget and identity lifecycle + +| Operation | Candidate required result | +| --- | --- | +| Delete a saved Diagram | Remove that representation and its inline layout; retain its Scenario, lifelines, occurrences and other views. Existing diagram-owned artifact cleanup still applies. | +| Delete a Scenario | Include all its Scenario-projection Diagrams in the existing deletion closure. No ownerless saved view survives. | +| Delete a Lifeline | Remove its lane entries from all surviving views; existing semantic endpoint cleanup continues. Do not delete message positions merely because those messages become incomplete. | +| Delete an Occurrence, or delete a fragment/branch containing it | Prune entries for the actual deleted message IDs from all surviving views. Preserve unrelated rows. Deleting and recreating a UUID is not a rename: deleted appearance layout is not inherited by the replacement. | +| Hide/fold, change names, change represented performer/exchange | Retain authored layout keyed to the surviving appearance; visibility is not deletion. | +| Reidentify | Rewrite projection owner, lane and occurrence references (and all address components when supported) using the checked whole-project identity map; retain values, row order and source comment ownership. Preflight collisions and final context before publishing mutations. | +| Reparent within the same Scenario sequence tree | Retain position if the final model/address remains valid. Semantic step/ownership validation still applies; geometry feasibility is separately evaluated. | +| Reparent outside the Scenario, or change Exchange occurrence to a non-message body | Reject while incompatible layout remains; an explicit same-batch removal repairs it. No implicit transfer to another view or definition. | +| Retarget Scenario projection | Ordinary EditDiagram may retain only final-compatible rows. In practice a different owner requires clearing old rows explicitly in the supplied replacement; there is no hidden clearing or coordinate reassignment. Layer must also match. | +| Change Scenario projection to architecture | Explicitly remove the Scenario payload and supply valid architecture content in the same transaction. Reverse conversion explicitly removes incompatible architecture nodes/routes, including their identity/provenance handling. | +| Duplicate only a view | Create a fresh Diagram UUID and unique alias; copy payload/order/values and keep all semantic reference IDs unchanged. Do not duplicate semantic elements or externally attached artifacts implicitly. Source creates a new declaration; original comments remain with the original declaration unless a separate copy-source operation promises more. | +| Copy semantic model plus view | An explicit copy map remaps the owner and every copied appearance reference into the copied closure before final validation. Missing/incompatible mappings reject; this is not the view-only duplicate command. No new semantic-copy implementation is claimed. | + +Delete/source synchronization must preserve the difference between command deletion and a malformed source edit: source that simply removes a referenced declaration while leaving stale layout is rejected. A deliberate source edit removing both is accepted atomically. Existing source identity correspondence must carry deletion/reuse and UUID swaps; never infer correspondence solely from matching final UUIDs. + +## Source lifecycle and exact integration seams + +At this worktree baseline: + +- oa-core/model.rs:537 (OccurrenceEndpoint), 1431 (ProjectionKind), 1485 (Diagram): add only the Scenario projection and optional tagged payload; preserve existing architecture fields. +- oa-core/session.rs:24-45, 474-489: reuse checked Create/EditDiagram and add focused commands. Audit projection matches, layout and node relocation: no architecture operation may accidentally accept this new view through a wildcard. +- oa-core/language.rs:410-459 already classifies scenario, lifeline, references and occurrence as explicit references. The proposed address object nests existing reference fields; no new UUID map parser is needed. Diagram parser defaults/version gating at1817-1833 and writer at704-724 must cover layout, preserve legacy output when None, and reject the feature under old headers. +- oa-core/source_project.rs:1486 item_key currently recognizes a limited set of nested row reference keys. Extend with schema-aware lane key lifeline and message key full address, resolved through aliases and the original-to-candidate identity map. Do not key by ordinal, x/y, terminal occurrence alone or serialized text. A coordinate edit must preserve unrelated row comments, order, includes and declaration file ownership. It must not turn a source UUID rename into row deletion/reinsertion. update_bundle recompiles and checks the exact requested Project at1017-1025; retain that oracle. +- oa-core/language.rs:59-101 record limits; persistence.rs header admission/migration; validation.rs diagram checks; references.rs remap/deletion closure: integrate all new references and bounded records together. +- oa-desktop/document.rs:315-327 and366-410: unchanged checked source commit/Undo/Redo boundary. app navigation, behavior camera/view state and diagram_usage::Surface must carry saved Diagram identity separately from the semantic Scenario owner; two saved views must not alias one owner-scoped state. +- docs/language.rst Diagram/route lifecycle and docs/api.rst transaction/OpenAPI contract need coordinated normative updates only after adoption. Server may reuse generic commands, but tests must verify serialization, conditional admission, dry-run and exact no-op rather than assume automatic parity. + +The future source updater should identify lane/message rows contextually inside this payload, not globally declare every arbitrary record containing a lifeline or occurrence field to be the same row type. Unknown future payload fields remain errors. Reset uses explicit removal, not magical null coordinates. + +## #7 coordination and open decisions + +Peer issue7 candidate847b1caa7e75bb82f6ce5193c45bcfc45973ad1a already proposes schema8 (model.rs:9), Project.definitions (1661), checked remap preflight (references.rs:214-217), and unfinished analysis source authoring (language.rs:1652-1653). Its remap function returns Result and preflights analysis before mutation. The scenario payload must join that fallible preflight, including duplicate/context validation, rather than restore an infallible signature or add a separately committing remap pass. + +Coordinate one version gate/migration, generic Value admission, aggregate record/depth accounting, source nested-row identity/origin handling, reference walking and delete closure. Exact overlap files are model.rs, language.rs, source_project.rs, persistence.rs, references.rs, validation.rs and session.rs, plus their normative docs/API schema. Neither version8 nor these candidate field names are reserved by this document. + +Open integration decisions: final public names and version; placement of new source row-key logic alongside peer semantic keys; migration representation of layout absence without rewriting old architecture source; the geometry feasibility contract and selected release gesture; how existing view_options are presented for Scenario views. No option here grants a new movement policy. Later expanded-reference support requires a qualified resolver, render/edit capability, path lifecycle and separate acceptance; accepting its paths now would create unsupported persisted intent. + +## Required first-slice evaluators + +Before claiming the contract implemented: parse/JSON/source round trips with two distinct views; same performer/exchange repeated under distinct lifeline/occurrence IDs; nested direct message admission and expanded-ref refusal; duplicate aliases resolving to identical address refusal; source comment/include preservation under coordinate edits and identity swaps; deletion/reuse, retarget/reparent repair and view-only duplication; negative/boundary coordinates without silent mutation; zero-motion signed-zero and latent projected values; first edit one-history-entry/Undo-to-absence/Redo-same-ID; stale REST and unchanged dry-run; exact send/receive and typed lifetime/activation geometry. Check original source bytes, accepted revision, undo/redo availability and other-view values on every rejected/no-op path. Pure serialization checks cannot establish gesture or native usability. diff --git a/harness/scenario-layout-design.md b/harness/scenario-layout-design.md new file mode 100644 index 00000000..6f1689a8 --- /dev/null +++ b/harness/scenario-layout-design.md @@ -0,0 +1,110 @@ +> Preserved from Scenario source `14e7e6aa46f59346c7a9a478fc9498fd0b496aaf`. This records its original design or selection contract. Combined implementation candidate `015273ac` and its review are tracked in Gitea issue27; public version adoption and combined acceptance remain open. Original proposal status below is historical and does not claim current runtime results. + +# Persisted scenario editing: implementation direction + +Status: selected storage direction after independent source comparison and critique; implementation and acceptance remain open. This note does not adopt a new model/source version or public field spelling. Shared schema, source and reference changes are coordinated in [issue 7 comment 756](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/7#issuecomment-756). + +The user requires ordinary direct scenario editing, including spreading lifelines, moving arrows and resizing diagram content, with graphical/text/API parity. [Issue 20](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/20) is the live outcome record; `PROJECT_GOAL.md` retains the full application requirement. Lane and whole-message spacing are the first persisted increment, not completion of that outcome. Process topology, frame/box resizing and route editing remain required work with their own geometry contracts. + +## Evidence and choice + +Use the existing **Diagram identity namespace**, adding an owner-bound Scenario projection and a typed scenario-layout payload. Preserve current architecture serialization initially. Do not convert every existing diagram to a new generic representation merely to add this capability. + +An owner-keyed presentation map is smaller only if there is exactly one arrangement per semantic scenario. That product restriction is not established. Adding view IDs, aliases, naming, duplication, source declarations, deletion and history to that alternative would recreate a second Diagram subsystem. Existing Diagram IDs and the owner-bound StateMachine projection supply useful precedents, while checked Diagram commands and source transactions already exist. + +This choice does not make integration automatic. Current behavior navigation, camera scopes and gesture contexts identify semantic owners. Saved views need representation identity throughout those paths. Current non-state saved-diagram dispatch can also fall through to architecture rendering. These are required parts of the first increment, not optional cleanup. + +The first projection is **Scenario only**. Process and FunctionalChain currently use topology rendering, while the row-anchor experiment concerns `Scene::sequence`. An unused Process projection with a sequence payload would claim a capability it does not supply. Later process-layout persistence may extend the same Diagram namespace with its appropriate typed payload. + +Reviewed source bases: + +- [208268c8](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/commit/208268c8aa7f6bc3c2bab6a3c0657358f3f7dc23): prepared navigation/rename union, not yet compiled or accepted together. +- [4b782a71 experiment](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/4b782a71fc011defd39331d3d6d5b73c1506275c/harness/experiments/behavior-anchor-plan-20260912/README.md): complete-anchor bridge, with explicit frame/lifecycle/scope falsifiers. Windows compilation check passed; runtime result was pending when this note was prepared. Use its subsequent evidence record for current results. +- [aadc6396 renderer](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/src/commit/aadc6396d39ff336d05381d58d545093d3f37a73/crates/oa-desktop/src/behavior.rs): peer typed activation/lifecycle integration. Reported 51 targeted checks do not establish full/native acceptance or this layout integration. +- [847b1caa analysis candidate](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/commit/847b1caa7e75bb82f6ce5193c45bcfc45973ad1a): prospective schema 8, analysis definitions and fallible remapping. Its version and persistence boundary must be reconciled, not overwritten. + +## Identity and logical data contract + +The following names describe meaning; source/JSON spellings remain subject to the shared schema design. + +| Identity/value | Meaning and invariant | +| --- | --- | +| Diagram ID | One saved representation. Two diagrams of one scenario may carry different layouts. It is distinct from the scenario owner ID. | +| Scenario owner ID | The semantic Scenario rendered by that representation; its layer must match the Diagram. | +| Lane identity | The Scenario's Lifeline ID, not its represented performer ID. Two lifelines representing the same performer remain independently addressable. | +| Message appearance | Its occurrence identity plus any reference-occurrence path. Never key by the represented Exchange definition. `OccurrenceEndpoint` is the existing path concept. | +| Lane x override | Authored horizontal center in diagram coordinates. Absence retains automatic placement. | +| Whole-message send-y override | Authored send endpoint height. The receive endpoint and current self-message offset remain derived for a whole-arrow move. A renderer row that denotes receive height must be converted explicitly; row storage conventions must not leak into the public meaning. | + +Use typed records with explicit reference-valued fields and reject duplicate addresses. Arbitrary UUID-valued JSON object keys bypass existing source alias/reference handling and are not a suitable shortcut. Direct appearances use an empty reference path. This first increment must not claim expanded-reference editing before its resolver and renderer are implemented and tested; unsupported addresses need explicit admission behavior, not accidental fallback to a definition-level placement. + +Coordinate admission reuses the project's finite coordinate bounds. Negative coordinates, large gaps and the resulting viewport extents require actual projection tests; a positive-only fixture does not establish them. Stored values represent authored intent, not a copy of every generated endpoint, label, activation or box bound. + +A Scenario projection accepts only its compatible typed layout. Architecture projections reject that payload. Scenario views reject incompatible architecture node/route payloads. Every projection dispatch, selector and usage query must classify the projection explicitly; `state_machine().is_none()` is not an architecture classifier. + +Structural validity is separate from the unsettled vertical movement policy. This note does not authorize semantic chronology contradictions, automatic reparenting, unexplained clamping or a new blanket spacing rule. + +## Projection and editing lifecycle + +1. Opening an old Scenario retains its derived unsaved view. It creates neither a Diagram nor a history entry and does not dirty source. +2. An explicit create/save-view action, or the first real geometry edit, may create a saved Diagram. Creation plus its initial authored override is one checked transaction. Undo restores the prior absence exactly. +3. Resolve absent positions automatically without persisting them. Preserve sparse authored values through folding, hiding, preview and passive layout. A zero-motion drag, including signed zero, must not materialize positions or erase latent values merely because a constraint displaced their displayed geometry. +4. Preview state lives outside the Document. Capture accepted source/document identity, an explicit derived-versus-saved representation identity, semantic owner and the current view-visit/input context when a gesture starts. A derived view has no saved Diagram ID; allocate that ID only inside an accepted creation/edit transaction. Switching between two views of the same Scenario, or leaving and returning to one without an intermediate frame, must invalidate old gesture/navigation envelopes. Cancellation and zero motion retain the derived view without creating a Diagram. +5. Commit one validated transaction on accepted release. Escape, stale context, invalid input and no-op release preserve model, exact source bytes, revision and redo history. Reuse the Document's checked source writeback boundary; do not maintain a parallel layout history. +6. Source export/import, JSON/REST transactions, native Save/reopen and model Undo/Redo must represent the same layout. Existing transaction no-op/ETag behavior remains applicable. Preview geometry alone is not persistence parity. + +The first prototype must exercise two separately arranged diagrams of the same Scenario. This exposes representation/owner confusion early, before substantial UI work depends on it. + +## References, transformations and limits + +Visit the Scenario owner, lifeline IDs, occurrence IDs and every reference-path component in validation, rename/reidentification, deletion and checked remapping. Integrate with the peer's fallible remapping/preflight contract instead of adding an infallible competing walker. + +Duplicating a saved view creates a new Diagram identity and copies authored layout values while retaining its semantic owner, lifeline, occurrence and reference-path identities. Duplicating a representation does not reidentify or duplicate its semantic objects. A separate semantic-model copy operation may remap those references according to its explicit copy map; these operations must not share an ambiguous blanket reidentification rule. + +Deleting an owner removes its saved Scenario views. Removing an appearance prunes its authored layout according to an explicit, tested rule while preserving unrelated semantic elements and other views. Retargeting a view or reparenting an appearance must reject or explicitly clear incompatible layout; it must not silently apply coordinates to another appearance. Hiding or folding is not deletion and retains authored data. + +Nested source records need stable identities and reference handling so a coordinate edit does not rewrite unrelated comments or records. Enforce duplicate-address and collection bounds before unbounded work. Determine these limits through the same checked persistence boundary as other model data; do not invent a second codec admission policy. + +## Movement policy still to evaluate + +Current ordinary scenario dragging already performs semantic reorder through a validated `SetSteps` command within the same parent sequence. The semantic model orders whole occurrences, not independently ordered send and receive events. Parallel and alternative operands also cannot be treated as one flattened chronology. + +Compare these two user gestures before selecting the release behavior: + +- Spacing drag preserves semantic order and shows its feasible boundary; an explicit Reorder action changes steps. +- Continuous drag adds spacing and previews a semantic reorder when crossing an event, extending the existing gesture. Release commits the layout and validated reorder atomically when applicable. + +Evaluate ordinary spacing, intentional and accidental crossings, Call/Reply and Create/Delete validity, same-owner view switches, discoverability, cancellation and one-step Undo. Both candidates must preserve operand membership unless the user invokes an explicit structural move. A persistence-home choice does not settle this gesture choice. + +The next bounded workflow prototype will evaluate **spacing through the arrow or label, with explicitly named Reorder available at the selection**. This is a candidate for runtime evaluation, not release acceptance. Spacing has a view-local purpose; reordering changes the shared Scenario and therefore affects its other representations. Inferring that shared semantic instruction merely from pointer travel is the principal reason to try separate actions first. Continuous spacing/reorder retains today's motor behavior and remains the alternative if the explicit action proves difficult to discover or use. + +This deliberately changes the current body-drag behavior: both an occurrence hit and the selected handle currently capture Reorder, with a three-screen-pixel movement threshold. Retaining only the existing handle is insufficient. Its world rectangle at x6..28 becomes 1.1 screen pixels wide at 0.05 zoom and can pan offscreen while the selected message remains visible. The named action must remain reachable at the current selection and camera position. + +The prototype must distinguish arrow/label, activation shoulder, lifecycle marker and reorder-handle hit roles; a shared occurrence UUID does not imply a shared drag action. It must preserve exact authored values, source, revision and redo on cancellation, stale view-visit context or return to the starting position. Geometry diagnostics are inputs to explicit preview feedback, not permission to rewrite steps, clamp stored values or manufacture missing arrows. The complete resolver's acceptance of source-admitted crossings does not itself select the gesture's crossing policy. + +Acceptance needs one independent native workflow: make two close messages easier to read, then deliberately swap them without being taught the handle. Include negative/far-right selections, Fit zoom, self Call/Reply and Delete, activation-shoulder input, and two saved views of one owner. Compare complete steps, both layouts, source and one-step Undo. Failure to discover Reorder or understand a refused spacing preview requires revising the interaction before adoption. No full implementation of both candidates is required merely to compare their risks; this first experiment does not replace the broader direct-editing acceptance matrix below. + +## Labels are part of the spacing outcome + +Both reviewed renderers shorten each complete message label to 32 graphemes independently of lane spacing. Their 225-unit backplate estimate is not a matching text clip. Existing release1 call/reply names already expose this truncation. The navigation membership helper independently assumes the same shortened label; changing paint alone would make its visibility claims wrong. + +The next bounded label candidate measures the same single-line text the canvas paints, resolving one displayed text/prefix/bounds result for paint, backplate, hit testing and visible-field navigation. Wider usable space must reveal a full known label when it fits. Measurement must account for the actual canvas zoom, font, shaping and font-system revision. Layout advances are not proof of pixel-ink bounds for overhanging glyphs. + +Resolve the corridor after lifecycle/activation endpoint alignment. Reversed and self messages need explicit corridor choices; a zero sender/receiver gap is not a valid self-message policy. The label helper should accept a corridor rather than hide those choices. Wrapping is a separate row-height/collision decision. Preserve the peer's backplate → activation → arrow/text paint order and precise shoulder-hit behavior. + +## Required evidence before adoption + +| Check | Observable success | +| --- | --- | +| Legacy open / zero motion | No new Diagram, coordinate entries, source changes, revision or history changes. | +| Two views of one Scenario | Independent layouts and camera/input contexts survive switching, export, REST, reopen and Undo. Delayed input from the first cannot edit the second. | +| Repeated Exchange / performer | Moving one appearance changes only its intended authored layout records; other appearance records and semantic identities remain intact. Dependent rendered geometry follows the separately selected movement policy. | +| Whole-message motion | Exact send/receive geometry, marker and activation alignment, with source semantics preserved for spacing and changed only by an explicit accepted reorder transaction. | +| Lifetime and self-call | Delete clipping and unanswered-call cues stay truthful; self-call execution begins at the actual receive endpoint, not its send row. | +| References / copy / deletion | All qualified identities transform consistently; unrelated layouts, comments and semantics remain intact. | +| Label readability | Full known names and distinguishing suffixes appear at sufficient width; actual font/render checks cover CJK, combining text, reversed/self calls, hits and nested bar continuity. | +| Projection extents | Negative coordinates, wide gaps and label extents remain reachable without changing authored values to fit the viewport. | +| Persistence transaction | One real drag yields one source/model history entry; invalid/stale/no-op paths leave source, disk and ETag unchanged as appropriate. | +| Real workflow | A matching Windows build supports direct selection, drag, cancel, next keyboard edit, navigation, Save and reopen on small and representative large models. | + +The old floor and complete-plan probes are evidence about integration seams, not an adoptable free-editing architecture. In a later typed-activation union, update their bar/cue representations and compare the full activation vector; preserve nonempty/count and complete source/history assertions. Independent source review alone does not satisfy any runtime row in this table.