diff --git a/bench/architect_sweeps.sh b/bench/architect_sweeps.sh index cd6985e..66e87c8 100755 --- a/bench/architect_sweeps.sh +++ b/bench/architect_sweeps.sh @@ -2,7 +2,8 @@ # bench/architect_sweeps.sh # # Run the five honesty/anchor sweep-invariant greps against the -# design/ prose set (design/contracts + design/models); the spine is +# design/contracts (the honesty-bound contract surface; design/models +# is the narrative tier, out of honesty-sweep scope); the spine is # design/INDEX.md. Output: matched lines, prefixed by sweep name. # Exit 0 if all five sweeps are clean, 1 if any anchor was found, # 2 if the spine (design/INDEX.md) is not found. Sweeps 1-4 are the @@ -22,7 +23,7 @@ set -u INDEX="design/INDEX.md" -DESIGN_GLOB="design/contracts design/models" +DESIGN_GLOB="design/contracts" # contracts only — design/models is the narrative tier; "as of milestone N" context is legitimate there HITS=0 if [[ ! -f "$INDEX" ]]; then diff --git a/bench/orchestrator-stats/2026-05-19-iter-design-md-rolesplit.tidy.json b/bench/orchestrator-stats/2026-05-19-iter-design-md-rolesplit.tidy.json new file mode 100644 index 0000000..2c5588e --- /dev/null +++ b/bench/orchestrator-stats/2026-05-19-iter-design-md-rolesplit.tidy.json @@ -0,0 +1,13 @@ +{ + "iter_id": "design-md-rolesplit.tidy", + "date": "2026-05-19", + "mode": "standard", + "outcome": "DONE", + "tasks_total": 7, + "tasks_completed": 7, + "reloops_per_task": { "1": 0, "2": 0, "3": 0, "4": 0, "5": 0, "5b": 0, "6": 0, "7": 0 }, + "review_loops_spec": 0, + "review_loops_quality": 0, + "blocked_reason": null, + "notes": "Re-dispatch after Boss plan re-derivation; the corrected plan ran first-shot clean across all tasks with zero spec/quality re-loops. Task 1 RED verified against un-stripped tree before strips; clause-3 flipped RED->GREEN at Task 7. One Edit retry on roundtrip-invariant.md:73 due to a soft-wrap boundary in the match string (tool-level, not a review re-loop)." +} diff --git a/crates/ailang-core/tests/design_index_pin.rs b/crates/ailang-core/tests/design_index_pin.rs index 6bb0361..7044351 100644 --- a/crates/ailang-core/tests/design_index_pin.rs +++ b/crates/ailang-core/tests/design_index_pin.rs @@ -129,29 +129,124 @@ fn every_contract_names_a_resolvable_ratifying_test() { #[test] fn contracts_carry_no_decision_record_prose() { - // clause 3 — the conflation tripwire. + // clause 3 — the conflation tripwire, widened (design-md-rolesplit.tidy, + // audit Resolution-4) to a FAITHFUL SUPERSET of + // bench/architect_sweeps.sh Sweep-1's history-anchor regex over the + // design/contracts/ scope, PLUS the audit-named decision-record + // phrases (the deliberate widening that closes the case-variance + // dodge the 6 literal markers left open). + // + // Invariant: clause-3 GREEN ⟹ Sweep-1 finds nothing in design/contracts/. + // + // Sweep-1 = 'Iter [0-9]+[a-z]?(\.[0-9]+)?|Family [0-9]+ + // |^[^/]*2026-[0-9]{2}-[0-9]{2}|\*\*Status: |pre-[0-9]+[a-z]? + // |[0-9]+[a-z]? sketch|21\.g' + // Faithfulness, per Sweep-1 alternative: + // - Iter / Family / pre- / sketch / 21.g / **Status: + // → sweep1_line_anchor() reproduces each verbatim, + // case-SENSITIVE (grep -E, no -i) — exactly Sweep-1 here, + // never narrower. + // - ^[^/]*2026-NN-NN → date_anchor() reproduces Sweep-1's + // ^[^/]* PATH-EXCLUSION (only the line prefix before the + // first '/' is scanned) and generalises 2026→20NN + // (⊇ Sweep-1, never narrower). A `docs/specs/2026-..` + // citation has '/' before the date ⇒ NOT flagged — faithful + // to Sweep-1, no over-fire on legit present-tense spec + // cross-refs (the iter-.1 plan defect this repairs). + // - PHRASES: literal decision-record idioms (case-insensitive) — + // the deliberate widening that closes the capital-variance + // dodge ("An earlier draft" vs "an earlier draft"). + // + // A blanket case-insensitive iter/milestone detector was evaluated + // and REJECTED (audit Resolution-4 corrected): it conflates the + // memory-model rule-names "Iter A"/"Iter B", and ordinary words + // "pre-existing"/"pre-set"/"pre-Boehm"/"pre-tail-call", with + // provenance stamps — unworkable. faithful-Sweep-1 (the capital-I, + // digit-anchored form) already excludes those by construction and + // is confirmed ZERO across every contract file; lowercase + // `(iter )` provenance is removed by the strip tasks, not by + // a fragile hard-gate regex. The load-bearing invariant + // (clause-3 GREEN ⟹ Sweep-1 clean in contracts/) holds with + // sweep1_line_anchor + date_anchor + PHRASES alone. let dir = root().join("design/contracts"); - let markers = [ - "we rejected", - "an earlier draft", - "Why not other", - "was retired in iter", - "rollback plan", - "previously all", + + const PHRASES: &[&str] = &[ + "we rejected", "an earlier draft", "earlier draft committed", + "why not other", "was retired", "were retired", "rollback plan", + "previously all", "deliberately deferred", "new-baseline decision", + "amends the above", "out of scope per", + "the journal records when", "unchanged from the original draft", ]; + + // Sweep-1's non-date alternatives, hand-rolled verbatim, case-SENSITIVE + // (grep -E without -i), on the raw physical line. + fn sweep1_line_anchor(line: &str) -> Option<&'static str> { + let kw_digit = |kw: &str| -> bool { + let mut from = 0; + while let Some(i) = line[from..].find(kw) { + let p = from + i + kw.len(); + if line[p..].chars().next().map_or(false, |c| c.is_ascii_digit()) { + return true; + } + from = p; + } + false + }; + if kw_digit("Iter ") { return Some("Iter "); } + if kw_digit("Family ") { return Some("Family "); } + if kw_digit("pre-") { return Some("pre-"); } + if line.contains("**Status: ") { return Some("**Status:"); } + if line.contains("21.g") { return Some("21.g"); } + if let Some(s) = line.find(" sketch") { + let pre = line[..s].as_bytes(); + if pre.last().map_or(false, u8::is_ascii_alphanumeric) + && pre.iter().rev() + .take_while(|c| c.is_ascii_alphanumeric()) + .any(u8::is_ascii_digit) + { + return Some(" sketch"); + } + } + None + } + + // Sweep-1's `^[^/]*2026-NN-NN`, generalised to 20NN-NN-NN, + // PATH-EXCLUDED: scan only the line prefix BEFORE the first '/'. + fn date_anchor(line: &str) -> Option { + let prefix = line.split('/').next().unwrap_or(line).as_bytes(); + for w in prefix.windows(10) { + if w[0] == b'2' && w[1] == b'0' + && w[2].is_ascii_digit() && w[3].is_ascii_digit() + && w[4] == b'-' && w[5].is_ascii_digit() && w[6].is_ascii_digit() + && w[7] == b'-' && w[8].is_ascii_digit() && w[9].is_ascii_digit() + { + return Some(String::from_utf8_lossy(w).into_owned()); + } + } + None + } + for entry in fs::read_dir(&dir).expect("design/contracts/ exists") { let p = entry.unwrap().path(); if p.extension().and_then(|e| e.to_str()) != Some("md") { continue; } - let body = norm(&fs::read_to_string(&p).unwrap()); - for m in &markers { + let raw = fs::read_to_string(&p).unwrap(); + let fname = p.file_name().unwrap().to_string_lossy().into_owned(); + let low = norm(&raw).to_lowercase(); + for ph in PHRASES { assert!( - !body.contains(m), - "decision-record marker {:?} found in contract {:?} — re-conflation", - m, - p.file_name().unwrap() + !low.contains(ph), + "clause-3: history phrase {ph:?} in contract {fname:?}" ); } + for line in raw.lines() { + if let Some(a) = sweep1_line_anchor(line) { + panic!("clause-3: Sweep-1 anchor {a:?} in contract {fname:?}: {line:?}"); + } + if let Some(d) = date_anchor(line) { + panic!("clause-3: history date {d:?} in contract {fname:?}: {line:?}"); + } + } } } diff --git a/design/contracts/data-model.md b/design/contracts/data-model.md index 1a271b9..82169b2 100644 --- a/design/contracts/data-model.md +++ b/design/contracts/data-model.md @@ -146,7 +146,7 @@ are real surface forms. // lowers as in-place rewrite under `--alloc=rc`. { "t": "reuse-as", "source": Term, "body": Term } -// loop-recur iter 1: strict iteration block. `binders` declares +// loop: strict iteration block. `binders` declares // one or more loop parameters (name, type, init), evaluated in // order on loop entry; `body` is in scope of all binders. The // loop's value is `body`'s value on the iteration that exits via a @@ -158,7 +158,7 @@ are real surface forms. "binders": [ { "name": "", "type": Type, "init": Term }, ... ], "body": Term } -// loop-recur iter 1: re-enter the lexically innermost enclosing +// recur: re-enter the lexically innermost enclosing // `loop`, rebinding its binders positionally to `args`. Transfers // control (no fall-through); valid only in tail position of its // enclosing loop (enforced at typecheck, `recur-not-in-tail-position`). diff --git a/design/contracts/float-semantics.md b/design/contracts/float-semantics.md index 0a9b8b6..b9bce20 100644 --- a/design/contracts/float-semantics.md +++ b/design/contracts/float-semantics.md @@ -97,8 +97,8 @@ LLM-author wants. Use ordering operators (`<`, `>`, ...) and `float_to_str` (Float → Str) and `int_to_str` (Int → Str) are fully wired through checker, codegen, and runtime. Both allocate -a fresh heap-Str slab at the call site (see "Str ABI" below for -the dual realisation) and carry `ret_mode: Own` so the let-binder +a fresh heap-Str slab at the call site (see design/contracts/str-abi.md +for the dual realisation) and carry `ret_mode: Own` so the let-binder for the call result is RC-tracked and the slab is freed at scope close. diff --git a/design/contracts/roundtrip-invariant.md b/design/contracts/roundtrip-invariant.md index be52989..f78dabd 100644 --- a/design/contracts/roundtrip-invariant.md +++ b/design/contracts/roundtrip-invariant.md @@ -69,8 +69,7 @@ inherit the gate automatically): Pins drift internal tests cannot see. - `crates/ailang-core/tests/schema_coverage.rs::every_ast_variant_is_observed_in_the_fixture_corpus` — every variant of `Def`, `Term`, `Pattern`, `Literal`, `Type`, - and `ParamMode` appears in at least one `.ail` fixture (corpus - flipped from `.ail.json` to `.ail` at iter form-a.1). New AST + and `ParamMode` appears in at least one `.ail` fixture. New AST variants fail compile until the visitor and corpus are extended in lockstep. - `crates/ailang-core/tests/carve_out_inventory.rs::examples_ail_json_inventory_matches_carve_outs` diff --git a/design/contracts/scope-boundaries.md b/design/contracts/scope-boundaries.md index 795ad65..8d031ca 100644 --- a/design/contracts/scope-boundaries.md +++ b/design/contracts/scope-boundaries.md @@ -2,8 +2,7 @@ ## What is not (yet) supported -Snapshot of the current boundary. Items move out of this list -as iterations land; the JOURNAL records when. +Snapshot of the current boundary. - No effect handlers — only the built-in `IO` op (`io/print_str`). `Diverge` is a reserved effect name with no op and no codegen. @@ -13,8 +12,7 @@ as iterations land; the JOURNAL records when. a body, lambdas check monomorphically against their declared type. - Polymorphic fns must be **directly called** at the use site. Passing a polymorphic fn as a value (`let f = id in f(42)`) is - not yet supported — it would need one closure-pair global per - instantiation, deferred. + not yet supported. - No higher-rank polymorphism. Passing a polymorphic fn to another polymorphic fn (`apply(id, 42)`) is not supported. - No recursive `let` for non-fn values. Plain `let x = … in …` only @@ -32,10 +30,8 @@ What **is** supported (and used as the smoke test for the pipeline): - Int, Bool, Unit, **Str**, **Float** as primitive types. - `if`, `let`, function calls, recursion. - Effects on function signatures, with `do op(args)` for direct effect - ops (`io/print_str`). The per-type print ops - `io/print_int`, `io/print_bool`, `io/print_float` were retired in - iter rpe.1; the polymorphic `print` (§"Polymorphic print") is the - canonical output path for non-Str values. + ops (`io/print_str`). The polymorphic `print` (§"Polymorphic print") + is the canonical output path for non-Str values. - **Builtins.** Arithmetic operators (`+`, `-`, `*`, `/`) of type `forall a. (a, a) -> a` (codegen-restricted to `{Int, Float}`); `%` of type `(Int, Int) -> Int` (Int-only — `fmod` semantics for diff --git a/design/contracts/str-abi.md b/design/contracts/str-abi.md index 4754b09..2623f01 100644 --- a/design/contracts/str-abi.md +++ b/design/contracts/str-abi.md @@ -11,16 +11,16 @@ and return an owned `Str`. Each is registered as a builtin in `crates/ailang-codegen/src/lib.rs::lower_app` to a `call ptr @ailang_`, and backed by a `runtime/str.c` C helper. -- `int_to_str : (borrow Int) -> Str` (iter 24.1) — decimal rendering +- `int_to_str : (borrow Int) -> Str` — decimal rendering of an `Int`. Backs `Show Int` in the prelude. -- `bool_to_str : (borrow Bool) -> Str` (iter 24.1) — `"true"`/`"false"`. +- `bool_to_str : (borrow Bool) -> Str` — `"true"`/`"false"`. Backs `Show Bool` in the prelude. -- `float_to_str : (borrow Float) -> Str` (iter 24.1) — +- `float_to_str : (borrow Float) -> Str` — type-installed; codegen is reserved and not yet shipped. -- `str_clone : (borrow Str) -> Str` (iter 24.1) — allocates a fresh +- `str_clone : (borrow Str) -> Str` — allocates a fresh heap-Str copy of the input's bytes. Backs `Show Str` in the prelude. -- `str_concat : (borrow Str, borrow Str) -> Str` (iter str-concat, - 2026-05-13) — combines two `Str` values into a single owned `Str`. +- `str_concat : (borrow Str, borrow Str) -> Str` — combines two `Str` + values into a single owned `Str`. General-purpose; commonly used in Show bodies for labelled output (`(app str_concat "label=" (app int_to_str x))`). @@ -35,16 +35,12 @@ directly; values of other primitive types route through the polymorphic `print` helper (§"Polymorphic print"), which feeds the heap-Str result of `show x` into `io/print_str`. -`==`, `<`, `<=`, `>`, `>=` REMAIN primitive operators (unchanged -from the original draft). Class methods are accessed by name (`eq x y`, -`lt x y`, …), not via these operators. Routing operators through -classes is deliberately deferred — it would require migrating every -existing fixture and would re-baseline the bench corpus, which is a -new-baseline decision rather than an iter detail. +`==`, `<`, `<=`, `>`, `>=` REMAIN primitive operators. Class methods +are accessed by name (`eq x y`, `lt x y`, …), not via these +operators. -`Num` is NOT in milestone 22. Arithmetic operators (`+`, `-`, `*`, -`/`) stay primitive and per-type. Class-based numeric overloading -would invoke literal-defaulting which axis-7 already excluded. +Arithmetic operators (`+`, `-`, `*`, `/`) stay primitive and +per-type. **Str ABI.** A `Str` is a pointer to a structure with `i64 len` at offset 0 followed by `len` bytes plus a trailing `NUL` at offset 8. @@ -71,7 +67,7 @@ the previous global in `.rodata` and reading them is undefined. **The static-Str non-RC invariant is enforced at codegen.** Two mechanisms keep static-Str pointers out of `ailang_rc_dec` along every shipping execution path: (1) the non-escape lowering pass -(iter 18b) and the move-tracking partial-drop logic (iter 18d.3) +and the move-tracking partial-drop logic prevent let-binders or pattern-binders for static-Str literals from reaching scope-close drop emission; (2) the `Type::Con { name: "Str" }` carve-outs in `field_drop_call` and in the `Term::App` arm of diff --git a/design/contracts/typeclasses.md b/design/contracts/typeclasses.md index 39817e1..e6f8607 100644 --- a/design/contracts/typeclasses.md +++ b/design/contracts/typeclasses.md @@ -74,8 +74,7 @@ user-ADT call site `print (MkIntBox 7)` causes synthesis of user-defining module per Decision 11 coherence). The synthesised body crosses a module boundary the source template did not. -Three invariants make this work, all installed in milestone 24's iter -24.3 and worth keeping load-bearing: +Three invariants make this work: 1. **`MonoTarget::FreeFn::type_args` carries canonical types post-collection.** At every site where `subst.apply(m)` produces a @@ -179,11 +178,10 @@ wording is fixed; the categories and their triggers are: - `OverridingNonExistentMethod` — instance specifies a method not in the class. -(`MethodNameCollision` was retired at iter mq.3. Cross-class method -sharing is now structurally legal; ambiguity surfaces at the call -site via `AmbiguousMethodResolution` or, for class-fn name overlap, -via the `class-method-shadowed-by-fn` warning. See §"Method -dispatch" below.) +Cross-class method sharing is structurally legal; ambiguity surfaces +at the call site via `AmbiguousMethodResolution` or, for class-fn +name overlap, via the `class-method-shadowed-by-fn` warning. See +§"Method dispatch" below. **Class-schema diagnostics** (validation of class declarations): @@ -196,8 +194,7 @@ A class param appearing in applied position (e.g., `f a` where `f` is the class param) is rejected earlier by the canonical-form validator as `BareCrossModuleTypeRef` — `f` is a bare, non-primitive name not declared as a `TypeDef` in the owning -module — so the dedicated `KindMismatch` diagnostic was retired -at iter ctt.3. +module. **Typecheck diagnostics** (per function body): @@ -276,40 +273,23 @@ warning surfaces the shadow. ## Prelude (built-in) classes -Milestone 22 ships **no built-in Prelude classes**. -An earlier draft committed to a fixed Prelude (Show / Eq / Ord on the -primitives), but the implementation work to wire `int_to_str` as a -heap-allocated-string runtime primitive proved substantively -separable from the typeclass machinery itself, and the LLM-utility -case for primitive `Show` is weak (LLM-natural form is `int_to_str -x`, not `show x` through a single-instance class). The user-class -end-to-end path is the milestone's typeclass acceptance gate -(the user-defined-class fixture: `class Foo a` + `data IntBox` + -`instance Foo IntBox`); see `docs/specs/2026-05-09-22-typeclasses.md` -"Amendments" for the substantive rationale. +The prelude ships the `Ordering` ADT, the `Eq` and `Ord` classes, +primitive `Eq Int/Bool/Str` and `Ord Int/Bool/Str` instances, and +the five polymorphic free-fn helpers `ne`/`lt`/`le`/`gt`/`ge`. Float +has neither `Eq` nor `Ord` instance per §"Float semantics"; a +polymorphic helper invoked at Float fires `NoInstance` at typecheck +with a Float-aware diagnostic cross-referencing this section. -Milestone 23 amends the above: the prelude now ships the `Ordering` -ADT, the `Eq` and `Ord` classes, primitive `Eq Int/Bool/Str` and -`Ord Int/Bool/Str` instances, and the five polymorphic free-fn helpers -`ne` / `lt` / `le` / `gt` / `ge`. Operator routing through `Eq`/`Ord` -and `print`-rewire remain out of scope per their original substantive -reasons (bench rebaseline, milestone-24 dependency on the post-mq -dispatcher); `Show` itself ships in milestone 24. Float has neither -`Eq` nor `Ord` instance per §"Float semantics"; a polymorphic helper -invoked at Float fires `NoInstance` at typecheck with a Float-aware -diagnostic cross-referencing this section. - -Milestone 24 amends the above further: the prelude ships `class Show -a where show : (a borrow) -> Str` and primitive `Show Int`, -`Show Bool`, `Show Str`, `Show Float` instances (iter 24.2). Float -**is** included in Show (unlike Eq/Ord) — IEEE-754 makes structural -equality and total ordering semantically dubious, but textual -representation of a Float is well-defined modulo the NaN-spelling -caveat in §"Float semantics". Each `Show ` instance body is a -single-application lambda invoking the corresponding runtime primitive -(`int_to_str`, `bool_to_str`, `str_clone`, `float_to_str`); no codegen -intercept is required. The polymorphic helper `print : forall a. Show -a => a -> () !IO` shipped in iter 24.3 with body +The prelude ships `class Show a where show : (a borrow) -> Str` and +primitive `Show Int`, `Show Bool`, `Show Str`, `Show Float` +instances. Float **is** included in Show (unlike Eq/Ord) — IEEE-754 +makes structural equality and total ordering semantically dubious, +but textual representation of a Float is well-defined modulo the +NaN-spelling caveat in §"Float semantics". Each `Show ` instance +body is a single-application lambda invoking the corresponding +runtime primitive (`int_to_str`, `bool_to_str`, `str_clone`, +`float_to_str`); no codegen intercept is required. The polymorphic +helper `print : forall a. Show a => a -> () !IO` has body `\x -> let s = show x in do io/print_str s` (explicit let-binder for heap-Str RC discipline per eob.1 Str carve-out). The let-binder is structurally pinned by `crates/ail/tests/print_mono_body_shape.rs`. diff --git a/docs/journals/2026-05-19-design-decision-records.md b/docs/journals/2026-05-19-design-decision-records.md index e2865e4..4b22652 100644 --- a/docs/journals/2026-05-19-design-decision-records.md +++ b/docs/journals/2026-05-19-design-decision-records.md @@ -429,3 +429,51 @@ post-ct.2.2 — a different consumer story, hence a different overlay shape. The asymmetry between the check side and the mono side is by design and is pinned by `crates/ailang-check/tests/duplicate_ctor_pin.rs`. + +## Migrated from design/contracts/ at design-md-rolesplit.tidy (2026-05-19) + +History/decision-record prose extracted from contract files by the +post-audit tidy (the `###`-whole relocation in iter .1 dragged these +into contracts; they are relitigation-guard content, not contract). + +### typeclasses.md — Prelude-classes evolution + +An earlier draft committed to a fixed Prelude (Show/Eq/Ord on the +primitives), but the implementation work to wire `int_to_str` as a +heap-allocated-string runtime primitive proved substantively +separable from the typeclass machinery itself, and the LLM-utility +case for primitive `Show` is weak (LLM-natural form is `int_to_str +x`, not `show x`). Milestone 23 added `Ordering`/`Eq`/`Ord` + +primitive instances + the five helpers; operator routing through +`Eq`/`Ord` and `print`-rewire were held out for bench-rebaseline / +post-mq-dispatcher reasons; `Show` shipped in milestone 24 (iters +24.2/24.3). `MethodNameCollision` was retired at iter mq.3 +(cross-class method sharing became structurally legal). The +dedicated `KindMismatch` diagnostic was retired at iter ctt.3 +(`BareCrossModuleTypeRef` subsumes it). + +### str-abi.md — heap-Str builtin provenance + deferred-operator rationale + +Builtin iter provenance: `int_to_str`/`bool_to_str`/`float_to_str`/ +`str_clone` shipped iter 24.1; `str_concat` shipped iter str-concat +(2026-05-13); the non-escape static-Str lowering pass landed iter +18b, move-tracking partial-drop iter 18d.3. Operator routing through +classes is deliberately deferred — it would migrate every fixture +and re-baseline the bench corpus (a new-baseline decision, not an +iter detail). `Num` is not in milestone 22: class-based numeric +overloading would invoke literal-defaulting which axis-7 excluded. + +### scope-boundaries.md — retired ops + deferral rationale + +Polymorphic-fn-as-value is deferred because it would need one +closure-pair global per instantiation. The per-type print ops +`io/print_int`/`io/print_bool`/`io/print_float` were retired in iter +rpe.1 (the polymorphic `print` is the canonical non-Str output path). + +### roundtrip-invariant.md / data-model.md — corpus + loop-recur provenance + +The Form-A round-trip corpus was flipped from `.ail.json` to `.ail` +at iter form-a.1. The `loop`/`recur` schema entries were added at +loop-recur iter 1 (strictly additive; pre-existing fixtures hash +bit-identically). Provenance only — the present-tense schema/contract +is the entry shapes themselves. diff --git a/docs/journals/2026-05-19-iter-design-md-rolesplit.tidy.md b/docs/journals/2026-05-19-iter-design-md-rolesplit.tidy.md new file mode 100644 index 0000000..56def13 --- /dev/null +++ b/docs/journals/2026-05-19-iter-design-md-rolesplit.tidy.md @@ -0,0 +1,96 @@ +# iter design-md-rolesplit.tidy — contract-history strip + clause-3 widening + +**Date:** 2026-05-19 +**Started from:** f2cdd67e69574f564b63bfd4b7f5715046d75a5a +**Status:** DONE +**Tasks completed:** 7 of 7 (Tasks 1, 2, 3, 4, 5, 5b, 6, 7 — task_range [1,7] covers the 5b sub-task) + +## Summary + +Closes the `[medium]`+`[low]` spirit-vs-letter drift from +audit-design-md-rolesplit: the `###`-whole relocation in iter .1 +dragged decision-record/history prose into 5 contract files. This +tidy extracts that prose into +`docs/journals/2026-05-19-design-decision-records.md` (each removed +history sentence replaced by its present-tense contract equivalent), +fixes the one stale `(see "Str ABI" below)` cross-ref in +float-semantics.md, re-scopes `architect_sweeps.sh` from +`design/contracts design/models` to `design/contracts` only (the +narrative tier is not honesty-bound) with its lockstep +`ailang-architect.md` sentence, and widens `design_index_pin.rs` +clause-3 into a hand-rolled **faithful superset** of Sweep-1 over +the contracts scope (case-sensitive digit-anchored `sweep1_line_anchor` ++ path-EXCLUDED `date_anchor` + case-insensitive decision-record +PHRASES; no `regex` dep, no blanket iter detector). Gate-first TDD: +clause-3 was verified RED against the un-stripped tree (PHRASES hit +`"an earlier draft"` in typeclasses.md) before any strip, then +flipped GREEN after Tasks 2–5b. End state: design_index_pin 4/4, +`architect_sweeps.sh` exit 0, `cargo test --workspace` 646 passed / +0 failed, acceptance grep CLEAN. + +## Per-task notes + +- Task 1: replaced `contracts_carry_no_decision_record_prose` + (:130-157) with the widened provable-superset matcher (verbatim + from plan; other 3 clauses + helpers untouched). RED verified + against un-stripped tree; other 3 clauses + build GREEN. +- Task 2: typeclasses.md — 6 spans rewritten present-tense (:77-78, + :182-186, :197-200, :279-289 deleted wholesale, :291-300, :302-317); + Prelude-classes evolution history appended to the decision-record + journal. `io/print_str` pin contiguous at :297; docs_honesty_pin 5/5. +- Task 3: str-abi.md — `(iter …)` parentheticals + deferred-operator + + `Num`/axis-7 rationale stripped (:14, :16, :18, :20, :22-23 + soft-wrap collapsed, :74, :38-43, :45-47); journal appended. + `type-installed; codegen is reserved…` pin contiguous at :19. +- Task 4: scope-boundaries.md — process-meta line plain-deleted + (:5-6), closure-pair-global + rpe.1-retirement rationale stripped + (:14-17, :36-38); journal appended. Diverge over-strip guard: + pin byte-untouched, effect_doc_honesty_pin 4/4 (pin line shifted + :9→:8 as the expected consequence of the authorized :5-6 two-line + collapse — content match unaffected). +- Task 5: float-semantics.md:99-100 stale `(see "Str ABI" below …)` + → `(see design/contracts/str-abi.md …)`. eq_float_noinstance 1/1. +- Task 5b: roundtrip-invariant.md:73 corpus-flip parenthetical + dropped; data-model.md:149/161 `// loop-recur iter 1:` → `// loop:` + / `// recur:`; :154 `pre-existing` left untouched (ordinary word); + journal appended. No lowercase iter-code provenance remains; + design_schema_drift 7/7, round_trip 2/2. +- Task 6: architect_sweeps.sh DESIGN_GLOB narrowed to + `design/contracts` with substantive-reason inline comment + header + prose; ailang-architect.md `:77-84` bullet gains the scope sentence. + All five sweeps clean, exit 0. +- Task 7: whole-tree gate — design_index_pin 4/4 (clause-3 RED→GREEN), + 3 pins + 2 E2Es PASS, workspace 646/0, sweep exit 0, acceptance + grep CLEAN. + +## Concerns + +(none) + +## Known debt + +(none — the audit Resolution scope is fully covered: Resolution-1 +history→journal across the corrected 5-file set, Resolution-2 stale +below, Resolution-3 sweep re-scope+lockstep, Resolution-4 faithful- +superset clause-3, Resolution-5 exit state.) + +## Blocked detail + +(none — DONE) + +## Files touched + +- Test gate: `crates/ailang-core/tests/design_index_pin.rs` +- Contract strips: `design/contracts/typeclasses.md`, + `design/contracts/str-abi.md`, + `design/contracts/scope-boundaries.md`, + `design/contracts/float-semantics.md`, + `design/contracts/roundtrip-invariant.md`, + `design/contracts/data-model.md` +- Decision-record archive: `docs/journals/2026-05-19-design-decision-records.md` +- Sweep re-scope + lockstep: `bench/architect_sweeps.sh`, + `skills/audit/agents/ailang-architect.md` + +## Stats + +bench/orchestrator-stats/2026-05-19-iter-design-md-rolesplit.tidy.json diff --git a/docs/journals/INDEX.md b/docs/journals/INDEX.md index 4a94df3..de280c5 100644 --- a/docs/journals/INDEX.md +++ b/docs/journals/INDEX.md @@ -117,3 +117,4 @@ - 2026-05-19 — iter design-md-rolesplit.1 (DONE 9/9, whole milestone): the 3020-line `docs/DESIGN.md` replaced by the `design/` ledger — `design/INDEX.md` (sole addressable spine, typed Contracts+Models tables, polymorphic links: prose file OR authoritative source `//!`), 14 `design/contracts/*.md` test-linked invariants + 3 source-link-only contracts (mangling/env-construction/qualified-xref, no prose file — code is SoT), 5 `design/models/*.md` onboarding whitepapers, and `docs/journals/2026-05-19-design-decision-records.md` (the relitigation-guard archive: every why/rejected/does-not-do/rollback/empirical `###` moved out at `###` granularity). Clean cut (`git rm docs/DESIGN.md`, no stub). RED-first `crates/ailang-core/tests/design_index_pin.rs` 4-clause anti-regrowth spine (DESIGN.md-gone / every-INDEX-link-resolves / every-contract-names-a-resolvable-ratifier / contracts-carry-no-decision-record-prose) demonstrably RED→GREEN. Build-atomic by task ordering (the only compile-time consumer, `design_schema_drift.rs` `include_str!`, retargeted to `design/contracts/data-model.md` BEFORE the deletion; the `## Data model`/`## Pipeline` slicer dropped — a simplification the split enables). 2 NoInstance diagnostics + their 2 lockstep E2Es retargeted to `design/contracts/{float-semantics,typeclasses}.md` (the contiguity-across-`\`-continuation hazard scrubbed). ~12 agent reading lists + 5 SKILL bodies + CLAUDE.md + skills/README.md + ~25 code/C/.ail/spec comment xrefs retargeted to the Appendix destinations; OQ7 dangling "Iter 13b" cite deleted (no forward target — a pointer would be fiction). honesty-rule.md rewritten so the rule names the new home (rationale→journals), resolving the recon-found internal contradiction; the two `docs_honesty_pin.rs:70,72` pinned phrases preserved verbatim+contiguous. Boss-verified independently: whole `cargo test --workspace` **646 passed / 0 failed**, `design_index_pin` 4/4, acceptance grep **CLEAN of live DESIGN.md refs** (residuals = only the spec-mandated clause-4 deletion-enforcer), honesty-rule repair carries no clause-3 marker. Spec grounding-check PASS ×2 (one re-dispatch after a corrected commitment-4 pin-status claim; one after the Boss-adjudicated relocation-appendix amendment resolving plan-recon's 7 open questions — ledger completed to 17 contract rows incl. the qualified-xref/str-abi/scope-boundaries additions the 12-list under-counted). 2 DONE_WITH_CONCERNS routed to the mandatory milestone-close `audit`: (a) `design/contracts/str-abi.md:23` `(iter str-concat, 2026-05-13)` API-provenance stamp trips advisory `architect_sweeps.sh` Sweep-1 — Boss-confirmed **byte-identical to DESIGN.md@deeffb1:2062-2065**, a faithfully-migrated PRE-EXISTING anchor (sweep regexes verbatim, only the path retargeted), NOT a split-introduced regression — RATIFY-or-tidy at audit; (b) the now stale-direction `(see "Str ABI" below)` intra-prose cross-ref in `float-semantics.md` (the Appendix is heading-level; no task prescribes intra-prose cross-ref rewrite) — audit-adjudication candidate. One plan defect recorded (Task 9 Step 4's verbatim acceptance grep used a `^\./` anchor not matching the system's `grep -rIn` output; substance independently re-verified CLEAN). → 2026-05-19-iter-design-md-rolesplit.1.md - 2026-05-19 — design-decision-records (migration): relitigation-guard archive — every why/rejected/does-not-do/rollback/empirical ### moved out of the former docs/DESIGN.md by the design-md-rolesplit milestone. Companion to spec 2026-05-19-design-md-rolesplit. → 2026-05-19-design-decision-records.md - 2026-05-19 — audit design-md-rolesplit (milestone close): DRIFT (one tidy iteration) + bench causally-exonerated (baseline pristine). Architect drift_found, relocation byte-faithful (MIXED Decisions / dual-link / source-link / rewritten honesty-rule all match the spec Appendix vs deeffb1; build-atomicity holds; design_index_pin 4/4; honesty-rule.md correct + pins retargeted; agent contracts coherent) — one [medium] spirit-finding: faithfully-migrated decision-record/history prose in design/contracts/{typeclasses,str-abi,scope-boundaries}.md DODGES the 6 literal clause-3 markers (case+wording variance) but IS the relitigation content the split's spirit sends to journals; plus [low] float-semantics.md stale-direction "see Str ABI below". Both routed items adjudicated strippable-doc-archaeology-to-TIDY-not-ratify (the str-abi.md:23 advisory Sweep-1 exit-1 correctly diagnoses real pre-existing history residue, byte-identical DESIGN.md@deeffb1:2062-2065, faithfully migrated — not split-introduced). Bencher: NO-ratify, causally-exonerated DECISIVE on byte-evidence — emitted IR AND final -O2 binaries byte-identical 176821c vs pre-milestone dd5b183 for all 6 check.py firings (sha256+cmp), all ~11 changed code/runtime files audited comment/docstring/diagnostic-string-only, zero IR-path change; the firings are tracked-P2 (*.bump_s staleness, *_at_rc.max_us -n5 tail jitter, *.gc_s Boehm-scan variance — NOT the M5 gc_rss trio); compile_check 24/24 + cross_lang 25/25 pristine corroborate; baseline untouched (identical to M2/M3/M5). Resolution: one tidy iter design-md-rolesplit.tidy — (1) move the history prose to the decision-record journal, (2) fix the stale "below", (3) re-scope architect_sweeps honesty sweeps to design/contracts only (models/ is the explicitly-narrative tier — scanning it for history-anchors is a post-split category error), (4) widen design_index_pin.rs clause-3 to SUBSUME Sweep-1's history-anchor regex over contracts/ (invariant: clause-3 GREEN ⟹ Sweep-1 clean in contracts/ — the hard gate enforces the spirit, closing the literal-marker dodge permanently). No fieldtest (zero authoring-surface change). Milestone closes after the tidy lands Boss-verified. → 2026-05-19-audit-design-md-rolesplit.md +- 2026-05-19 — iter design-md-rolesplit.tidy (DONE 7/7): resolves the milestone-close audit DRIFT (2ba5e16). Gate-first TDD: widened design_index_pin.rs clause-3 to a hand-rolled FAITHFUL Sweep-1 superset — case-sensitive digit-anchored Sweep-1 line anchors (confirmed ZERO across all contracts) + Sweep-1's `^[^/]*` path-EXCLUDED date_anchor (so docs/specs/2026-.. citations are not flagged) + the audit-named decision-record PHRASES (case-insensitive, closing the capital-variance dodge); NO regex dep, the blanket case-insensitive iter-detector REJECTED as unworkable (it conflated the memory-model rule-names "Iter A/B" + ordinary "pre-existing/pre-set/pre-Boehm" with provenance). Sentence-level strip of the faithfully-migrated history/decision-record prose out of 5 contract files (typeclasses/str-abi/scope-boundaries — the audit's spot-check — PLUS roundtrip-invariant.md:73 + data-model.md:149,161, the 2 the exhaustive plan-time scan found the spot-check missed) into docs/journals/2026-05-19-design-decision-records.md, each removed sentence replaced by its present-tense contract equivalent; float-semantics.md stale `(see "Str ABI" below)` → `(see design/contracts/str-abi.md)`; architect_sweeps.sh honesty sweeps re-scoped design/contracts+design/models → design/contracts only (models/ is the explicitly-narrative tier; scanning it for history-anchors is a post-split category error) + skills/audit/agents/ailang-architect.md lockstep. Invariant established: clause-3 GREEN ⟹ Sweep-1 finds nothing in contracts/. The prior dispatch correctly BLOCKED on a real plan defect (iso_date lacked Sweep-1's path-exclusion → over-fired on legit spec-path citations); per the "two+ defects in one iteration ⇒ fix the upstream artifact, not a third patch" discipline the audit Resolution mechanism+scope were corrected in lockstep (f2cdd67) before re-dispatch. Three docs_honesty_pin pinned-byte runs survived contiguous (str-abi.md:19, typeclasses.md:297, scope-boundaries.md:8 — shifted from :9 by the authorized :5-6 collapse, content byte-untouched). Boss-verified independently: cargo test --workspace 646/0, design_index_pin 4/4 (clause-3 RED→GREEN), architect_sweeps.sh exit 0 "All five sweeps clean" (acceptance criterion 9 met), acceptance grep CLEAN, 3 pins each exactly 1 contiguous match. Zero spec/quality re-loops. This is the FINAL design-md-rolesplit iteration — the milestone (DESIGN.md → design/ ledger role-split) is now functionally complete, audited, drift-resolved, and the in-code hard gate enforces the honesty spirit. → 2026-05-19-iter-design-md-rolesplit.tidy.md diff --git a/skills/audit/agents/ailang-architect.md b/skills/audit/agents/ailang-architect.md index 5544af0..31cdeab 100644 --- a/skills/audit/agents/ailang-architect.md +++ b/skills/audit/agents/ailang-architect.md @@ -81,7 +81,10 @@ If `milestone_scope` is empty, return a structural error and stop. review each match — a legitimate quote (e.g. a journal-entry citation inside a block-quote) is fine; a fresh history anchor / REVERTED narrative / workflow detail / stale cross-reference is - drift to flag. + drift to flag. Sweeps 1–4 scan `design/contracts/` only — + `design/models/` is the narrative tier (§ reading-list: "context, + not a drift surface"), so a milestone-context phrase there is not a + regrowth. - **design/ honesty drift.** Sweep 5 of `bench/architect_sweeps.sh` (the docs-honesty-lint invariant) flags Wunschdenken / non-citation post-mortem. Apply the discriminator from