diff --git a/docs/JOURNAL.md b/docs/JOURNAL.md index b5928de..8e6c11b 100644 --- a/docs/JOURNAL.md +++ b/docs/JOURNAL.md @@ -12652,3 +12652,110 @@ content-not-grep issue caught by quality review). The Sweep 1 lesson held. One plan-vs-actual phrasing variance ("a later iter" vs "a future iteration") was caught by the implementer at edit time and applied correctly without a fixup. + +## 2026-05-10 — Iteration design-md-consolidation 3: schema SoT inversion + data-model hardening + +Third iteration of the milestone defined in +`docs/specs/2026-05-10-design-md-consolidation.md`. Sweep 3 +inverts the schema source-of-truth between `docs/DESIGN.md` +§"Data model" and `crates/ailang-core/src/ast.rs`: DESIGN.md is +canonical, `ast.rs` is the projection, and a new drift test +catches divergence. + +Three substantive changes plus one new test: + +- **Two Rust code blocks removed from Decision 10.** The + `Type::Fn` + `ParamMode` block (around line 1027 at iter + start) and the `Suppress` struct block (around line 1132) are + replaced by prose pointers to §"Data model". Decision 10's + prose argument (per-position metadata vs `Type::Borrow` + variant) reads cleanly without the inline Rust. +- **§"Data model" SoT inversion.** The opener now reads "**This + section is the canonical schema.**" The Rust types in `ast.rs` + are framed as the in-memory projection, not the source. The + drift test is named as the enforcement mechanism in the + opener. +- **`ast.rs` module doc-comment.** The file-level `//!` block + bold-emphasises that DESIGN.md §"Data model" is canonical; + names the drift test as the enforcement; preserves the + serde-attribute description and the entry-type pointer. +- **`crates/ailang-core/tests/design_schema_drift.rs`** is the + new drift test (369 lines). Pattern follows the existing + `spec_drift.rs`: exhaustive `match` per enum (`Term`, + `Pattern`, `Type`, `Def`, `Literal`, `ParamMode`) ensures + adding a variant without a DESIGN.md anchor fails compilation; + the test asserts each anchor literally appears in DESIGN.md. + 7 tests total. All GREEN on first run after the schema-tag + alignment described below. + +**Real schema-vs-doc drift surfaced and closed inside the iter.** +The drift test exposed a pre-existing bug: `ast.rs`'s `Def` enum +uses `#[serde(tag = "kind", rename_all = "lowercase")]`, so +shipped `.ail.json` examples emit `"kind": "class"` / +`"kind": "instance"`. But Decision 11 §"Form-A schema" in +DESIGN.md said `"kind": "ClassDef"` / `"kind": "InstanceDef"`. +Confirmed by grepping `examples/test_22b1_*.ail.json` — every +shipped example uses lowercase tags, matching the serde output. +Per Sweep 3's commitment ("DESIGN.md is the canonical schema"), +DESIGN.md was wrong; closed with fixup `934a6e1`: Decision 11 +JSON code blocks now use lowercase tags, drift test anchors +updated to match. Prose references to the Rust type names +`ClassDef` / `InstanceDef` (e.g. line 1382's +"`**ClassDef**` — top-level definition kind, declares a class:") +are fine — those reference the Rust struct names, not the JSON +tag values. + +Quality-review nit closed inline: the test's file-level +doc-comment originally opened with `Sweep 3 / Task 4:` (a +task-reference prefix per CLAUDE.md comment policy is noise +once the iteration is closed). Doc-comment trimmed; def-kind +description list updated from PascalCase +(`ClassDef`/`InstanceDef`) to lowercase (`class`/`instance`) +to match the post-fixup anchors. + +Acceptance: + +- `grep -nE '^\s*(struct |enum |pub (struct|enum|fn))' docs/DESIGN.md` → empty. +- `grep -n 'whenever the two disagree\|ast.rs is the source of truth' docs/DESIGN.md` → empty. +- `grep -n 'This section is the canonical schema' docs/DESIGN.md` → 1 line (1708). +- `grep -n 'design_schema_drift' docs/DESIGN.md crates/ailang-core/src/ast.rs` → 1 match in each file. +- `cargo test -p ailang-core --test design_schema_drift` → 7 tests pass. +- `cargo test --workspace` → 0 FAILED. +- `bench/check.py` 0 regressed (63 metrics; 3 improved beyond + tolerance, 60 stable). `bench/compile_check.py` 0 regressed + (24 metrics, 24 stable). +- Sweep-1 + Sweep-2 invariants stay empty (no regression). +- DESIGN.md size: 2155 → 2139 lines (−16 this sweep, −123 + cumulatively from 2262 at milestone start). + +Tasks (commit subjects): + +- design-md-consolidation 3.1: remove 2 Rust code blocks from Decision 10 +- design-md-consolidation 3.2: invert §Data-model SoT — DESIGN.md canonical, ast.rs projection, drift test enforces +- design-md-consolidation 3.3: ast.rs doc-comment names DESIGN.md §Data-model as canonical schema, drift test as enforcement +- design-md-consolidation 3.4: add design_schema_drift.rs — exhaustive-match drift test for ast.rs vs DESIGN.md §Data-model +- design-md-consolidation 3.4 fixup: align DESIGN.md ClassDef/InstanceDef JSON tags with ast.rs lowercase serde rename +- design-md-consolidation 3.4 nit: drop task-ref doc-comment prefix + align def-kind list with lowercase tags + +Carried into sweep 4: workflow / cross-reference cleanup. +"Project ecosystem" `agents/` path correction; "Verification and +correctness" workflow detail; "What is not (yet) supported" +§"Recently lifted gates" removal; cross-reference audit. + +Process notes: +- The plan predicted "GREEN on first run — DESIGN.md already + aligned" for the drift test. Reality matched in the sense + that the test's grep-presence checks all passed on first run + — but the schema-vs-emit drift between DESIGN.md and ast.rs + was a different bug class that the grep-presence test wasn't + designed to catch. Surfacing happened anyway because the + implementer flagged it as known debt; the orchestrator + promoted it to in-scope and closed it. +- Open question for follow-up sweeps: the current drift test + guards DESIGN.md text presence, not serde-roundtrip fidelity. + A future hardening would round-trip a constructed `Def` value + through `serde_json::to_value` and assert the emitted JSON + matches one of DESIGN.md's anchors literally — that catches + the ClassDef/class class of bug structurally rather than + through grep-presence + spot inspection. Out of scope for + iter 3; queued. diff --git a/docs/roadmap.md b/docs/roadmap.md index c5dec2f..c371b73 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -41,7 +41,7 @@ work progresses. - sub-entries: - [x] Sweep 1 — remove history anchors - [x] Sweep 2 — REVERTED + migration plans out - - [ ] Sweep 3 — schema SoT inversion + data-model hardening + - [x] Sweep 3 — schema SoT inversion + data-model hardening - [ ] Sweep 4 — workflow / cross-reference cleanup ## P1 — Next