77 lines
12 KiB
Markdown
77 lines
12 KiB
Markdown
# S2c typed canonical writer checkpoint
|
|
|
|
2026-09-13. Delegated owner: `/root/source8_lowering_plan`; integration, executable gates and publication: `/root`. This is a **source-only, private staged implementation**. All ten newly authored writer tests are **UNRUN**. No Cargo, compiler, GUI or Gitea operation was performed by this contribution.
|
|
|
|
## Frozen source and checks
|
|
|
|
- Worktree: `.local/as2-20260913`, branch `codex/analysis-s2-956atf-20260913`, clean after commit.
|
|
- Commit: **`f1d79df4979121335ed7b4ce4da84b2fca8a9ef4`**, `Stage bounded typed source8 canonical and subtree writers`.
|
|
- Parent: **`bed5b0e8320bfc106b1f5f62e42339ca23b900cd`**, accepted versioned Negate guidance addendum. That parent follows the corrected S2b pin `a2a28f8d23a46ba1696b6a8410d4d3b5c1808f49`.
|
|
- Six files, 1,863 insertions and two deletions. No edits to public `language.rs`, source_project, model, semantic admission, parser/Budget, source3 bridge, header dispatch, ordinary writers, or user-owned specification.
|
|
- Rustfmt completed and subsequent `rustfmt --check --edition 2024 --config skip_children=true` passed for the six affected Rust paths using the root `.local/toolchain` environment. Staged `git diff --check` passed. These checks are not compilation or behavioral evidence.
|
|
- The oracle was moved byte-for-byte from `analysis_source/lower/oracle.rs` to `analysis_source/model_oracle.rs`; both Git blobs are `7acca881a5f5b1243a8df760b230f57619212eef`. Lowerer tests change only their module import. No oracle values or constructors changed.
|
|
- Parent-reported prior a2 executable evidence: listing 142 admitted, typed 34 passed, raw_tokens one passed, full 126 passed / 16 existing unsupported-header failures, strict all targets passed at 07:09:57Z, with 531 unchanged inputs. **None of this is evidence that S2c compiles or passes.** Original analysis-core a2 and root 440 checkouts remain untouched.
|
|
|
|
## File partition
|
|
|
|
Paths below are relative to `crates/oa-core/src/language/`.
|
|
|
|
| File | Change |
|
|
| --- | --- |
|
|
| `analysis_source.rs` | Registers private writer and shared test oracle. Existing staged module admission remains unchanged. |
|
|
| `analysis_source/lower/tests.rs` | Uses the shared oracle instead of its former local module. |
|
|
| `analysis_source/model_oracle.rs` | Mechanical 100% rename of the independently authored complete Rust Project oracle. |
|
|
| `analysis_source/write.rs` | 664 lines: bounded output sink, lookup/scope tables, declaration/type/binding/item formatting and fallible fragment interfaces. |
|
|
| `analysis_source/write/expression.rs` | 284 lines: iterative expression task stack, all 13 Expr variants, precedence-aware parent context. |
|
|
| `analysis_source/write/tests.rs` | 910 lines: ten authored tests and local staged parse/lower helpers. |
|
|
|
|
## Private interfaces
|
|
|
|
All interfaces remain inside the existing private staged `analysis_source` module; there is no new public test API or production entry point.
|
|
|
|
- `Limits { bytes, entries }`, constructed with `Limits::source8(ParseLimits)` using the existing candidate source8 hard limits. `Writer::new` rejects caller limits above the hard ceilings.
|
|
- `Writer::new(&Project, Limits) -> Result<Writer, Error>` borrows the complete model, collects calculation parameter scopes once, and rejects duplicate IDs/names within a calculation. Reused parameter IDs across owners or between a parameter and a global object remain allowed.
|
|
- `Usage { bytes, entries }` is available through `usage()`. Work and output counters aggregate across successful fragment calls; they do not restart for each declaration or subtree.
|
|
- `Error { owner: Option<Id>, field: &'static str, message: String }` reports model context, without inventing source spans.
|
|
- `definition(Id)`, `analysis_element(Id)` return a complete typed declaration; `typed_declarations()` returns `Vec<(Id, String)>` in definitions-by-ID then analysis-elements-by-ID order, including unused definitions and unbound declarations.
|
|
- `value_type(owner, &AnalysisType)` emits a type value. `binding(owner, lower::Field)` emits the actual model binding and validates its owner/field context.
|
|
- `expression(owner, Field, &Expr, Parent)` emits a supplied expression, retaining owner/field parameter scope. `Parent` is `Root`, `Binary(BinaryOp, Side)` or `Negate`; `Side` is Left/Right. This is the explicit S3 replacement boundary: a retained binary/unary parent can request the grouping needed to preserve topology.
|
|
- `parameter(calculation, ParameterId)` emits a complete `input ...;` item with explicit scoped ID. `override_entry(case, property)` emits a complete `@property = binding;` entry and fails if absent. Other fragment APIs emit values without field keywords or semicolons.
|
|
|
|
The byte sink checks remaining capacity before growth and uses `serde_json::to_writer` directly for quoted strings, matching existing `language::quote`. Raw alias and quoted-string size checks precede their variable-size work. Exact values use existing `Exact::canonical_literal()`; its scratch is bounded by the model's two 4096-bit components. No float conversion, recursive child-string construction, JSON payload transport, or reparsing/normalization of Exact values is introduced.
|
|
|
|
Entry work is charged before scope-table insertion, structural visits and expression scheduling; stack growth has a pending-entry bound. The first failed output call latches its error, discards its unfinished fragment and prevents later calls from returning output. Completed fragments consume the same aggregate quota. No parser Budget reference/literal recharge or semantic admission occurs inside the writer.
|
|
|
|
## Formatting contract
|
|
|
|
Declarations use LF, four-space declaration indentation, eight-space fields, description first, short typed words and explicit required fields. Definitions retain ID order; parameters and call labels use the callee's parameter vector order; overrides use property ID order. Dimension axes follow the fixed seven-axis order. Empty dimension and override bodies remain explicit `{}`. Units retain exact scale/offset; display-unit none, documented-constraint none, base ModelBaseline and unbound values remain explicit. Headers emit all IDs and display names. Analysis parent must remain none.
|
|
|
|
The expression writer handles all 13 model variants iteratively. Binary grouping preserves lower precedence, equal-precedence right children, and comparison nesting on either side. Negate emits `- ` and groups only a binary operand. Negative literal nodes remain `ratio(-1, 1)`, distinct from unary `- 1`. Parameter and global references use typed lookups and owner scope; calls require the exact callee parameter-ID set, emit labels in declaration order, and do not expand the call graph. Depth 128, list width 1024 and exponent bounds remain unchanged.
|
|
|
|
The accepted Negate addendum is implemented without parser-limit changes. A source-derived case override with 127 Negates around Number(-1) consumes 130 staged frames; the calculation control consumes 129. The obsolete mandatory-grouping spelling consumes 257 in the case and 256 in the calculation, showing why the calculation-only control was insufficient. Replacing the entire grouped operand in `-(1)` with a binary expression requests `Parent::Negate` and restores required grouping.
|
|
|
|
## Authored tests — all UNRUN
|
|
|
|
Full prefix: `language::analysis_source::write::tests::`.
|
|
|
|
1. `typed_oa_sa_canonical_roundtrips_match_independent_projects`: complete independent OA/SA model equality through typed canonical parse/lower, 14 display-name assertions, one existing semantic admission per candidate, canonical stability and public8 rejection.
|
|
2. `typed_declaration_order_and_required_empty_values_are_canonical`: independent model additions for empty dimensions, affine algebra, negative unit offset, Unicode symbol, unused zero-input/list-result unbound calculation, explicit none/empty values and sorted overrides; complete model roundtrip/admission/stability and absent-override failure.
|
|
3. `all_expr_variants_and_precedence_preserve_exact_trees`: independent actual Expr and golden source for all 13 variants, including the corrected semantically valid AsKind; structural roundtrip plus admission in the complete candidate; additional unary, negative-literal, binary, comparison and empty-list topology controls.
|
|
4. `canonical_calls_use_callee_parameter_order_and_qualified_names`: reversed parameter vectors, map-order independence, reused IDs across scopes and a global ID, caller parameter names versus callee argument labels, complete parameter items and model roundtrip/admission.
|
|
5. `subtree_output_respects_parent_context_and_retained_delimiters`: replaces the whole `(1)` operand span in `-(1)` with binary, negative literal and unary trees, verifying retained-parent topology; right subtraction child, type fragment and complete override item controls.
|
|
6. `canonical_strings_and_exact_literals_use_existing_encodings`: quotes/backslash/control characters/NUL/Unicode equality with existing quote encoding, exact literal canonical forms, and typed model roundtrip.
|
|
7. `writer_limits_are_aggregate_exact_and_latched_without_partial_results`: exact and adjacent byte/entry limits, cross-fragment charging, latched errors, escaped Unicode byte controls and hard-limit rejection.
|
|
8. `writer_lookup_scope_shape_and_depth_failures_are_model_located`: wrong domains/unknown IDs, out-of-scope parameters, call argument-set mismatch, bad power/list/depth bounds, invalid owner/field contexts and contextual errors.
|
|
9. `negate_override_roundtrip_preserves_depth128_within_frame256`: source-derived whole-case depth-128 AST, prefix 130/129 and obsolete grouped 257/256 controls, exact 127-unary/negative-literal tree, complete model equality and stable canonical output.
|
|
10. `iterative_writer_preserves_width1024_and_empty_call_topology`: exact list-1024 and zero-argument-call structural roundtrips.
|
|
|
|
## Review and remaining work
|
|
|
|
Fresh independent source review and parent-owned compilation/executable gates are next. The writer's model precondition is complete semantic admission by its caller; writer lookup/shape failures do not replace semantic validation. The all-13 tests run the existing admission once per complete candidate. The helper used to inspect a bare expression wraps it in a private probe calculation for structural parsing/lowering; that helper's placeholder result type is not claimed as a semantic oracle.
|
|
|
|
OA/SA tests combine a separately authored ordinary source7 skeleton with typed declaration output and the existing staged lowerer. Complete Project equality here is **not public whole-source8 parsing, include admission, save admission or migration evidence**. The string-encoding test checks encoding and structure; it does not claim semantic admission of its modified control-character names/symbols. The width/empty-call test checks topology.
|
|
|
|
S3 still owns source-qualified indexing, deriving replacement context from existing expression sites, original span selection, comment/ownership-preserving edits, stabilization of missing parameter IDs, and cursor/update behavior. S4 still owns complete ordinary/typed production composition, envelope/include aggregate limits and inherited frames, version/migration/export/save integration, and eventual public8 activation. The writer's aggregate quota currently covers typed output only. `value_type` accepts its owner as error context; binding/expression methods validate model owner/field context. No production-wide writer or public formatter signature changes are included.
|
|
|
|
The local accepted implementation plan is `.local/analysis-source8-writer-plan-20260913.md` (SHA256 `e6ef6108792896cfb65e825cd19e984bf1c1729cff242653ed7947b4c6e9a803`). The versioned Negate addendum is `harness/analysis-source8-20260913/writer-canonical-negate-20260913.md` in the bed5 ancestor. Source stays frozen pending parent direction.
|