Files
ARCADIA-Studio/harness/scenario-analysis-version-integration-review-20260913.md
T

13 KiB

Scenario / analysis schema8 integration audit

Decision boundary: optional Scenario presentation can share the pending schema8 model, but aed07176 is not a version-adoption patch. Four integration obligations remain: old-schema field-presence rejection, combined resource accounting, atomic composition of reference preflights, and preservation of typed source-update contexts. They are root codec/integration work, not defects claimed against the peer's explicitly isolated contribution. Do not implement them in the frozen S2 worktree before the typed-adapter phase handoff.

Inspected exact Scenario source aed07176ab453b981d5f9c76e504c531f6dd7f42 and clean analysis worktree 6216cff4cfeb1502b8453b40547aacb74941f2b2. The Scenario object was missing locally; a scoped git fetch --no-tags --no-write-fetch-head gitea <exact SHA> populated objects without changing the root checkout/branch or frozen worktree. Input manifest, SHA256 c72d6d140579dcbf910f81505ced83a3cd6fa09bae813469be59da635033cbb2, pins 22 actual source blobs. Accepted r2 typed-definition grammar was read from the analysis worktree's harness/analysis-source8-20260913/analysis-source8-repair-design-r2-20260913.md.

Read Gitea #7 through 843, #20 through 845, and the published aed gate README at e7ceff11. It records 26 focused cases overlapping 471 executed core passes, one ignored probe, strict pass and preserved earlier failures. This audit did not rerun/independently validate those receipts. A newer renderer candidate68a81c3 is reported in845, but its source/runtime is outside this aed codec audit. No gesture/rendering import is proposed.

Exact seams and mandatory failure cases

1. Freeze old Diagram contracts before adopting the new current field. Peer model.rs:1523 adds layout: Option<DiagramLayout> with serde-default None and omitted serialization of None. scenario_layout.rs:10-35 defines Scenario payload, lane rows and message rows; message addresses retain explicit reference paths. None and Some(empty) intentionally differ. Analysis is schema8; the peer stays schema7 experimentally. Keep root's version decision; do not import the peer's SCHEMA_VERSION=7 over analysis.

Analysis migration_v7.rs:10-25 freezes only the top-level Project envelope and reuses current Diagram. migration_v3/mod.rs:23 and migration_v4.rs:59 also share Diagram. Adding a current field therefore makes typed older envelopes accept it unless separately rejected. Existing persistence.rs:163-166 inspects raw JSON only for versions<=6, and check_legacy_header:225 catches unknown Diagram fields only for pre6. Neither protects schema7; schema6 also lacks a layout-presence check. The actual JSON boundary has no version-aware nested Diagram visitor: json_codec.rs:276-297 delegates current decoding to Project::deserialize and legacy decoding to generic serde_json::from_slice::; the derived current Diagram accepts its newly known layout field even when the frozen top-level DTO denies unknown fields. reject_pre8_project:479 currently checks definitions/analysis kinds only. Testing layout.is_some() after serde is inadequate: explicit old layout:null has already become None.

Minimal compatible repair: a context-specific raw Diagram-field presence rejection (at diagrams..layout, not a recursive blacklist for every key named layout) for schemas<8 before deserializing current Diagram, and a corresponding source check in language.rs:1757 before defaults/merge/from_value. Reject explicit layout even null/none/empty payload. Do not simply extend the existing call to check_legacy_header to version7: it unconditionally invokes reject_source7_fields, which would wrongly reject legitimate schema7 Operation/contextual-link fields. Keep the <=6 source7 restriction separate from the new <=7 layout restriction. Frozen nested Diagram DTOs are a stronger alternative, but require more migration adapters; either approach must retain old field-presence semantics.

Also protect typed internal migration entrances: reject_pre8_project should reject any non-None current layout, and language/source3_bridge.rs:13-47 must not blindly forward a scratch Diagram carrying a new payload. Its exhaustive Project destructure does not detect additions inside the shared Diagram type. Never strip a supplied payload or serialize a current record back into an older contract as a workaround.

Required public negative matrix: real legal schema3/4/5/6/7 projects with one diagram, inject layout:null, empty Scenario, and nonempty Scenario; all reject without writes. Source6/7 layout none; and layout { Scenario { lanes []; messages []; }; }; must reject, including included modules. Keep legal schema7 Operation/contextual-link positives to catch overbroad rejection. Legitimate old payloads without layout migrate to current None and an empty analysis catalog, with exact semantic IDs/geometry retained. Current schema8 absent/None/Some(empty)/sparse layout round trips must preserve their intended distinctions. Standalone serde_json::<Diagram> success is not public version admission.

2. Wire both semantic row and ordered-reference accounting. Peer scenario_layout.rs:61 deliberately exposes only a contribution: None=0, Some=1 + lanes.len + messages.len, no graph objects. Its reference_visitor_and_record_count_cover_explicit_rows test proves 0 and3 for one lane/one message, not integration into public limits. Analysis language.rs:62-108 currently counts graph+definitions, ordinary diagrams/nodes/routes/anchors and analysis::nested_record_count, but never Scenario payloads. Add every diagram's contribution using bounded/saturating accumulation; do not replace the existing analysis contribution or count only the active view. Hidden/filtered/inactive diagrams and structurally invalid or disabled-looking payloads still consume stored-record/reference budgets; visibility and renderer support are not admission exemptions.

The variable-length message.address.references is a separate ordered-reference budget hook. Count its actual length across all rows/diagrams together with existing element steps and ContextualLink endpoint paths, including malformed/unsupported candidates. Peer scenario_layout.rs:226 rejects nonempty paths semantically, but that is not a resource meter. It still receives already allocated vectors. Lane/occurrence singleton references are bounded by row counts; this does not require redefining the existing budget as every global reference.

Retain JSON physical preflight (persistence/json_codec.rs:87, byte/token/aggregate-entry/container/string ceilings) before serde and final ParseLimits::check_model before structural validation (persistence.rs:213). Source language.rs:1544 and bundle source_project.rs:503 currently meter declaration counts, not these nested rows. The root typed-source resource phase must charge layout rows/reference entries under the same whole-document/bundle budget before potentially large collection/resolution work; do not reset per included file, diagram or list and do not route Scenario coordinates through Exact/analysis-expression node accounting. Do not turn on DEPTH_128_VALIDATED (json_codec.rs:22) for this shallow optional payload.

Minimal failures: budget B accepts exact combined ordinary+analysis+Scenario count, B-1 rejects; two views in different includes exceed a shared limit though each fits; Some(empty) consumes its payload record; a single rejected message with an oversized explicit reference path is charged; existing ContextualLink paths plus Scenario paths share the ordered-reference ceiling. Exercise public JSON/source and programmatic Session/prepare boundaries, with a no-mutation sentinel. Physical preflight alone does not prove the configured semantic max_records limit.

3. Compose both fallible remap domains before any identity/reference mutation. Peer references.rs:207-323 adds diagram visitors, Scenario projection owner remapping and affected-row collision preflight; session.rs:917 runs it before reidentifying. Analysis already has a different preflight at references.rs:214-217 and session.rs:941, plus analysis::references::remap_project, definitions and scoped ParameterIds. A blind replacement would lose one domain. Worse, adding peer checks only inside the final remap call lets root session::reidentify change object identity before a Scenario collision rejects.

Use one composed check entry point called before mutation by both public references::remap_references and session::reidentify; it must run analysis key/call-map checks and Scenario lane/address collision checks first. Then retain typed analysis remapping and peer diagram visitor/deletion pruning, including Scenario owner-view cascade. Parameter IDs remain scoped: a ParameterId equal to the remapped global UUID must not be rewritten merely by equality. Preserve the peer's repair-batch tolerance: unrelated already-invalid duplicate rows do not become a new global admission requirement for an unaffected remap.

Required union negatives/positives: direct public remap and Reidentify each leave the complete Project unchanged on a Scenario lane/message collision; analysis override/call-argument collision remains atomic with Scenario present; successful remap updates layout/Scenario owner/global analysis subject refs while preserving equal-valued scoped ParameterIds; delete only the actual closure, retaining unrelated view overrides and incomplete-message positions. These are additional union tests, not a replacement for the peer's26 cases or root analysis tests.

4. Preserve source8 typed field dispatch and peer row provenance. Peer source_project.rs:1136-1154 adds explicit EditContext path Diagram -> layout -> Scenario -> lanes/messages; :1544-1594 uses lifeline identity or full occurrence-address identity only in that context. This must compose with the root's future typed definition/parameter/call-site/override paths, not become a generic field-name heuristic. A calculation parameter or ordinary record named messages, lanes, layout, etc. must not acquire Scenario row identity. Diagram coordinates remain the existing finite f32 numeric grammar; new analysis literals/operators must not silently broaden it to expressions/ratios.

Retain context arguments at both update entry (peer source_project.rs:934) and migration entry (peer source_project/source_migration.rs:72); the first omitted migration argument caused a real retained compile failure. Keep the peer's authored layout none preservation rule (source_project.rs:1346) for an unrelated edit, while a real Some->None clear removes payload syntax. Retain current SourceIndex declaration/top-level field meanings and the root's distinct Definition record category; no Scenario data should be classified as a new global definition or graph object.

Reuse peer scenario_layout/tests/source_lifecycle.rs controls for reordered rows with identity-following comments, untouched 4.20e2/2.00e2 spellings, alias changes, identity swaps, one-Undo command batches, explicit none, clear, invalid-source nonmutation and unchanged file ownership. Add one mixed schema8 bundle with neutral definitions + analysis Expr/call parameters + Scenario layout: alias/parameter rename affects only typed uses, row reordering leaves analysis source byte-exact, analysis edits leave layout/comment/number spelling byte-exact, and full Project equals recompiled source. Old source migration must retain includes/trivia, never synthesize authored layout; current canonical/source updates must publicly reopen exactly before checked save may stage/replace.

Ownership / order

Root owns public version8 adoption, older wire/source rejection, shared counts/resource policy, source8 typed-adapter composition and save-before-replace safety. The peer owns scenario_layout semantics, sparse commands, scoped source-row provenance and renderer/gesture progress. Import reviewed peer mechanisms after the S2 declaration/lowering boundaries stabilize; compose shared model/language/source_project/references/session/persistence changes deliberately. No change to peer gesture policy, automatic fallback policy, activation rendering or new schema number is needed for these codec hooks.

The original checked-save regression must remain red until public source8 is complete; keep the S0 public-decode/full-equality guard. Peer source7 experimental tests should be ported to the final current schema fixtures at integration, while explicit old-schema layout tests remain negative. Passing either isolated suite does not waive combined admission, native or API lifecycle gates. This audit changed no production source, ran no compiler/GUI and posted nothing to Gitea.