From de66eb7ab2e457bfe7e5dbe2f87c5da15a786cd7 Mon Sep 17 00:00:00 2001 From: Brummel Date: Mon, 18 May 2026 12:18:14 +0200 Subject: [PATCH] =?UTF-8?q?plan:=20docs-honesty-lint.1=20=E2=80=94=20RED?= =?UTF-8?q?=20pin=20+=20Sweep=205=20+=2014=20byte-exact=20corrections?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single-iter, 6 tasks. Wrap-robust resolution of the spec's naive line-based pin/regex (DESIGN.md is hard-wrapped ~70col): pin uses a norm() whitespace-collapse helper (discharges spec Testing-item 0 AND planner self-review item 6 structurally); Sweep 5 uses verified contiguous source-line fragments. Concern-1 sweep-count lockstep (architect_sweeps.sh tail+header, ailang-architect.md "four"->"five") bundled into the Sweep-5 task per self-review item 7. FIX set is the post-Sweep-5 classified sweep output (procedural, spec L92-102); 14 currently-knowable sites shown byte-exact + a catch-all step. recon DONE_WITH_CONCERNS — all 3 concerns Boss-adjudicated in-plan. --- docs/plans/docs-honesty-lint.1.md | 908 ++++++++++++++++++++++++++++++ 1 file changed, 908 insertions(+) create mode 100644 docs/plans/docs-honesty-lint.1.md diff --git a/docs/plans/docs-honesty-lint.1.md b/docs/plans/docs-honesty-lint.1.md new file mode 100644 index 0000000..38155d6 --- /dev/null +++ b/docs/plans/docs-honesty-lint.1.md @@ -0,0 +1,908 @@ +# docs-honesty-lint.1 — Implementation Plan + +> **Parent spec:** `docs/specs/2026-05-18-docs-honesty-lint.md` +> +> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement` +> to run this plan. Steps use `- [ ]` checkboxes for tracking. + +**Goal:** Make `docs/DESIGN.md` + `docs/PROSE_ROUNDTRIP.md` mirror only +the current state (present-tense), codify the honesty discriminator +in-tree, and guard it with a wrap-robust enumerated pin + a wrap-robust +advisory Sweep 5. + +**Architecture:** Single iteration, six tasks. Task 1 lays the RED +pin (the contract; wrap-robust via a whitespace-normalising helper). +Task 2 ships wrap-robust Sweep 5 + all sweep-count lockstep wording + +the architect bullet. Task 3 inserts the discriminator meta-subsection. +Task 4 applies the 14 byte-exact DESIGN.md corrections + a procedural +catch-all for any extra sweep hit. Task 5 fixes the PROSE satellite + +relocates genuine forward intent to the roadmap. Task 6 turns the pin +GREEN and runs full verification. No language/checker/codegen/runtime +change; `ail check`/`run`/`build` byte-unchanged by construction. + +**Tech Stack:** Rust integration test (`crates/ailang-core/tests/`), +Bash (`bench/architect_sweeps.sh`), Markdown (`docs/`), agent-def +Markdown (`skills/audit/agents/`). + +--- + +## Files this plan creates or modifies + +- Create: `crates/ailang-core/tests/docs_honesty_pin.rs` — wrap-robust enumerated absent/present regression pin, sibling to `effect_doc_honesty_pin.rs`. +- Modify: `bench/architect_sweeps.sh:50-56` — append wrap-robust Sweep 5; fix the "four sweeps clean" tail + header wording. +- Modify: `skills/audit/agents/ailang-architect.md:73-79` — add "DESIGN.md honesty drift" bullet after L79; fix "four sweeps" wording at L74,L77. +- Modify: `docs/DESIGN.md` — insert discriminator meta-subsection into the `## Project ecosystem` section (after L52); 14 byte-exact present-tense corrections (Task 4). +- Modify: `docs/PROSE_ROUNDTRIP.md:152-157` — strip the tool-use/MCP Wunschdenken paragraph; present-tense replacement. +- Modify: `docs/roadmap.md` (P3 — Ideas) — add the relocated LLM tool-use / MCP / LSP forward-integration idea (the sole genuine forward intent stripped that is not already represented). + +**Procedural-enumeration note (spec L92-102, recon concern 3).** The +authoritative FIX scope is *every hit of `bash bench/architect_sweeps.sh` +after Sweep 5 is added, classified by the Task-4 discriminator table*. +The 14 corrections in Task 4 are every site knowable at plan time +(Boss ran the corrected Sweep-5 regex against the current tree); Task 4 +Step "catch-all" handles anything the sweep surfaces that is not in the +table. The list is concrete (Iron Law) without being frozen-as-scope +(the sweep stays authoritative at exec time). + +**Out of FIX scope — deliberate KEEPs (do NOT edit these):** +- `docs/DESIGN.md` L1215-1221 — the `(con T)`/`Type`-unchanged + parenthetical is *self-labelled* "a tiebreaker, not a rationale — + the substantive reasons above are what justify the choice." It + asserts nothing false; it honestly discloses it is not a reason. + Effort-as-rationale-disguised is a *different* anti-pattern with + its own CLAUDE.md home; it is outside this spec's two-pronged + discriminator. KEEP. +- `docs/DESIGN.md` L1516-1517 — "Does not introduce regions. Regions + were considered and rejected; see …" is present-tense design + rationale (a current exclusion + internal pointer). KEEP. +- `docs/DESIGN.md` L2725 — "`Diverge` is a reserved effect name with + no op and no codegen." Gold-form honest-reserved. KEEP (and pinned + present in Task 1). +- `docs/DESIGN.md` the bare `(iter 24.1)` / `(iter str-concat)` + provenance tags on the heap-Str primitive list (L2041, L2043, L2045, + L2047, L2049) — terse true provenance, asserts nothing false, not + narrative. KEEP. (L2050's Sweep-1 hit is the bare date inside this + true provenance tag — a Sweep-1 date false-positive, not drift.) +- `docs/DESIGN.md` L48-52 — the `## Project ecosystem` Docs bullet + ("`docs/journal-archive.md` (archived monolith for pre-2026-05-11 + history)") is the present-tense doc-roles pointer the discriminator + subsection joins. The L50 Sweep-1 hit is its embedded date. KEEP. +- `crates/ailang-core/specs/form_a.md` — not modified, not pinned. + Its only forward-style line ("multi-superclass chains are not yet + supported", soft-wrapped L130-131) is gold-form honest-reserved. + (Recon concern 2: the spec prose collapsed the line-wrap; the + *decision* — no change — is correct and needs no pin.) + +--- + +## Task 1: RED pin — `docs_honesty_pin.rs` (wrap-robust contract) + +**Files:** +- Create: `crates/ailang-core/tests/docs_honesty_pin.rs` + +Rationale for the `norm()` deviation from the spec's illustrative pin +shape (spec L164-201 used naive `d.contains()`): `docs/DESIGN.md` is +hard-wrapped at ~70 columns, so almost every target phrase is split +across two source lines. A naive single-line `contains()` would assert +nothing on wrapped phrases (false green). `norm()` collapses every +whitespace run (incl. newline+indent) to a single space before +matching, making every assertion wrap-independent. This simultaneously +discharges spec Testing-strategy item 0 AND planner self-review item 6 +(pin ↔ replacement-body contiguity): with `norm()`, contiguity is +automatic — Task 4 may wrap replacement prose however Markdown needs; +the pin still matches on word content. This is strictly more robust +than the effect-doc-honesty precedent's fragile "keep the phrase on +one line" approach. + +- [ ] **Step 1: Write the pin file** + +```rust +//! Regression pin: the canonical docs must stay present-tense-honest. +//! +//! `docs/DESIGN.md` (and `docs/PROSE_ROUNDTRIP.md`) must not assert +//! something exists/works/changed that does not. This pin fails if any +//! swept-and-corrected Wunschdenken / post-mortem string reappears, or +//! if any present-tense corrected anchor (incl. the protected +//! honest-reserved exceptions) is dropped. Matching is +//! whitespace-normalised so the assertions are independent of the +//! docs' hard line-wrap. Companion to `effect_doc_honesty_pin.rs` and +//! to Sweep 5 of `bench/architect_sweeps.sh`. + +use std::fs; + +fn read(rel: &str) -> String { + let p = concat!(env!("CARGO_MANIFEST_DIR"), "/../../"); + fs::read_to_string(format!("{p}{rel}")) + .unwrap_or_else(|e| panic!("read {rel}: {e}")) +} + +/// Collapse every whitespace run (incl. newline + indent) to a single +/// space, so a phrase split across the docs' hard line-wrap still +/// matches a single-line assertion substring. +fn norm(s: &str) -> String { + s.split_whitespace().collect::>().join(" ") +} + +#[test] +fn design_md_has_no_wunschdenken() { + let d = norm(&read("docs/DESIGN.md")); + assert!(!d.contains("is on the path to retirement"), + "DESIGN.md: Boehm retirement is forward intent — it lives in docs/roadmap.md, not DESIGN.md"); + assert!(!d.contains("Will back `Show Float`"), + "DESIGN.md: 'Will back Show Float' asserts a future capability as fact"); + assert!(!d.contains("codegen ships in a future iter"), + "DESIGN.md: float_to_str codegen is reserved/not-yet-shipped, not a promised future ship"); + assert!(!d.contains("may land in a future iteration"), + "DESIGN.md: auto-derivation 'may land in a future iteration' is Wunschdenken"); + assert!(!d.contains("If/when concurrency arrives"), + "DESIGN.md: 'if/when concurrency arrives … will be' is forward conditional"); + assert!(!d.contains("was deferred — all three layer additively"), + "DESIGN.md: deferred future integration paths are roadmap intent, not DESIGN.md"); +} + +#[test] +fn design_md_has_no_doc_archaeology() { + let d = norm(&read("docs/DESIGN.md")); + assert!(!d.contains("An earlier draft of this Decision said"), + "DESIGN.md: doc-archaeology ('an earlier draft said … a follow-up replaced it') lives in docs/journals/"); + assert!(!d.contains("previously all diagnostics were `Error`"), + "DESIGN.md: 'previously all diagnostics were Error' is project history → docs/journals/"); + assert!(!d.contains("What did change in 2026-05-13 (this milestone) is"), + "DESIGN.md: 'what did change in (this milestone)' is post-mortem narrative"); + assert!(!d.contains("primitives were retired 2026-05-14 in iter rpe.1"), + "DESIGN.md: 'X were retired in iter Y' is history → docs/journals/"); + assert!(!d.contains("were retired in iter rpe.1 (2026-05-14)"), + "DESIGN.md: the second per-type-print-op retirement-narrative sentence is history"); + assert!(!d.contains("originally listed here as the eighth fixture, was retired"), + "DESIGN.md: 'originally listed … was retired by milestone X' is doc-archaeology"); +} + +#[test] +fn design_md_present_tense_anchors_present() { + let d = norm(&read("docs/DESIGN.md")); + // the discriminator meta-subsection (Task 3) + assert!(d.contains("the honesty rule it holds itself to"), + "DESIGN.md must carry the discriminator meta-subsection heading"); + assert!(d.contains("whether the document asserts something exists, works, or changed that does not"), + "DESIGN.md discriminator must state the operational test"); + // protected honest-reserved exceptions — over-correction guard + assert!(d.contains("`Diverge` is a reserved effect name with no op and no codegen"), + "the gold-form honest-reserved anchor must remain (do not over-strip)"); + assert!(d.contains("Regions were considered and rejected"), + "the present-tense design-rationale exclusion must remain (do not over-strip)"); + assert!(d.contains("a tiebreaker, not a rationale"), + "the self-labelled tiebreaker is honest and stays (do not over-strip)"); + // corrected present-tense anchors (Task 4) + assert!(d.contains("`--alloc=gc` selects the transitional Boehm backend"), + "DESIGN.md must describe Boehm present-tense, not as 'on the path to retirement'"); + assert!(d.contains("type-installed; codegen is reserved and not yet shipped"), + "float_to_str must be present-tense honest-reserved"); + assert!(d.contains("AILang demands annotations *because* the LLM author can produce them effortlessly"), + "the 'does not infer everything' bullet must be present-tense (no doc-archaeology)"); + assert!(d.contains("`io/print_str` is the only built-in direct-output effect-op"), + "the print-op set must be stated present-tense, not as a retirement narrative"); +} + +#[test] +fn prose_roundtrip_md_has_no_wunschdenken() { + let p = norm(&read("docs/PROSE_ROUNDTRIP.md")); + assert!(!p.contains("A future iter may layer a tool-use schema"), + "PROSE_ROUNDTRIP.md: tool-use/MCP forward intent lives in docs/roadmap.md"); + assert!(p.contains("the lowest-common-denominator cycle and always works with any client"), + "PROSE_ROUNDTRIP.md must close present-tense on the static-prompt path"); +} +``` + +- [ ] **Step 2: Run the pin — verify it fails RED for the right reasons** + +Run: `cargo test --workspace -p ailang-core --test docs_honesty_pin` +Expected: COMPILES, 4 tests run, all 4 FAIL. Specifically: +`design_md_has_no_wunschdenken` fails on the first `assert!` ("is on +the path to retirement" still present); `design_md_has_no_doc_archaeology` +fails ("An earlier draft of this Decision said" still present); +`design_md_present_tense_anchors_present` fails ("the honesty rule it +holds itself to" absent — Task 3 not yet done); +`prose_roundtrip_md_has_no_wunschdenken` fails ("A future iter may +layer a tool-use schema" still present). This RED state is the +contract Tasks 3-5 discharge. + +--- + +## Task 2: Wrap-robust Sweep 5 + sweep-count lockstep + architect bullet + +**Files:** +- Modify: `bench/architect_sweeps.sh:50-56` +- Modify: `skills/audit/agents/ailang-architect.md:73-79` (bullet) and `:74,77` (wording) + +Concern-1 lockstep (recon): adding a fifth sweep makes "All four +sweeps clean." / the header "four design-md-consolidation sweeps" / +`ailang-architect.md` "the four sweeps" stale. Per planner self-review +item 7, every coordinated edit ships in THIS task — no deferral. + +The Sweep-5 regex uses **contiguous source-line fragments**, not full +phrases: `architect_sweeps.sh`'s `run_sweep` is line-based +(`grep -nE … "$DESIGN"`), and the target phrases are soft-wrapped, so a +full-phrase pattern would miss them (Boss verified: the spec's +illustrative full-phrase regex caught only 4 of the ~12 sites). Each +fragment below was verified contiguous on a single current DESIGN.md +line. + +- [ ] **Step 1: Append Sweep 5 after Sweep 4** + +In `bench/architect_sweeps.sh`, the current lines 50-56 are: + +```bash +run_sweep "4 (workflow + stale cross-references)" \ + 'agents/README\.md|ailang-docwriter|Recently lifted|see the JOURNAL queue|later the same day|Sharpened later|closure conversion in JOURNAL' + +if [[ $HITS -eq 0 ]]; then + echo "All four sweeps clean." +fi +exit $HITS +``` + +Replace those exact lines with: + +```bash +run_sweep "4 (workflow + stale cross-references)" \ + 'agents/README\.md|ailang-docwriter|Recently lifted|see the JOURNAL queue|later the same day|Sharpened later|closure conversion in JOURNAL' + +run_sweep "5 (honesty: wunschdenken + non-citation post-mortem)" \ + 'on the path to|may land in a future|ships in a future iter|[Ww]ill back `Show|[Ww]ill eventually (be|support|back)|[Ii]f/?when [a-z]+ (arrives|lands)|[Aa]n earlier draft of this|previously all diagnostics were|[Ww]hat did change in 20|were retired 20[0-9]{2}-|retired in iter [a-z]|originally listed|\bwas deferred\b|foundation for [a-z]' + +if [[ $HITS -eq 0 ]]; then + echo "All five sweeps clean." +fi +exit $HITS +``` + +- [ ] **Step 2: Fix the script header "four sweeps" wording** + +In `bench/architect_sweeps.sh`, the current header lines 4-6 are: + +```bash +# Run the four design-md-consolidation sweep-invariant greps against +# docs/DESIGN.md. Output: matched lines, prefixed by sweep name. Exit 0 +# if all four sweeps are clean, 1 if any anchor was found. +``` + +Replace with: + +```bash +# Run the five DESIGN.md honesty/anchor sweep-invariant greps against +# docs/DESIGN.md. Output: matched lines, prefixed by sweep name. Exit 0 +# if all five sweeps are clean, 1 if any anchor was found. Sweeps 1-4 +# are the design-md-consolidation history-anchor invariants; Sweep 5 +# is the docs-honesty-lint Wunschdenken / post-mortem invariant. +``` + +And the current header line 16: + +```bash +# A non-zero exit is advisory, not authoritative: the architect agent +``` + +is unchanged (the advisory contract still holds for all five). No edit +to line 16; it is quoted only to bound the replacement at line 6. + +- [ ] **Step 3: Run the sweep — confirm Sweep 5 fires on the still-uncorrected tree** + +Run: `bash bench/architect_sweeps.sh; echo "EXIT=$?"` +Expected: EXIT=1. Output now includes a `=== Sweep: 5 (honesty: …) ===` +block listing the uncorrected honesty sites (at minimum DESIGN.md +lines containing "on the path to", "may land in a future", "ships in +a future iter", "Will back `Show", "If/when concurrency", "An earlier +draft of this", "previously all diagnostics were", "What did change in +20", "were retired 20…", "retired in iter", "originally listed", "was +deferred"). Sweeps 1-4 unchanged from the recon baseline. This proves +Sweep 5 detects the wrapped sites the spec's illustrative regex missed. + +- [ ] **Step 4: Add the "DESIGN.md honesty drift" architect bullet** + +In `skills/audit/agents/ailang-architect.md`, the current lines 73-79 +are the "DESIGN.md history-anchor regrowth" bullet: + +```markdown +- **DESIGN.md history-anchor regrowth.** Run + `bash bench/architect_sweeps.sh` from the repo root. Exit 0 = clean. + Exit 1 = at least one of the four sweeps from the + design-md-consolidation milestone (2026-05-10) matched. 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. +``` + +Replace those exact lines with (the wording fix "four"→"five +sweeps … 1-4 / Sweep 5" PLUS the new sibling bullet appended): + +```markdown +- **DESIGN.md history-anchor regrowth.** Run + `bash bench/architect_sweeps.sh` from the repo root. Exit 0 = clean. + Exit 1 = at least one of the five sweeps matched. Sweeps 1-4 are the + design-md-consolidation history-anchor invariants (2026-05-10): + 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. +- **DESIGN.md honesty drift.** Sweep 5 of `bench/architect_sweeps.sh` + (the docs-honesty-lint invariant) flags Wunschdenken / non-citation + post-mortem. Apply the discriminator from DESIGN.md §"What this + document is — and the honesty rule it holds itself to": a hit is + drift unless it is a present-tense correctly-labelled + reserved/excluded claim, present-tense design rationale, or a + block-quote journal citation. Forward intent is roadmap drift; + document/project history is journal drift. +``` + +- [ ] **Step 5: Confirm no other "four sweeps" string survives in the architect file** + +Run: `grep -n "four sweeps\|the four sweeps\|four design-md" skills/audit/agents/ailang-architect.md` +Expected: no output (exit 1 from grep = no match). If any line prints, +it is a missed lockstep site — fix it to the "five / Sweeps 1-4 + +Sweep 5" wording before proceeding. + +--- + +## Task 3: Insert the discriminator meta-subsection into DESIGN.md + +**Files:** +- Modify: `docs/DESIGN.md` (insert after L52, inside `## Project ecosystem`) + +The `## Project ecosystem` section spans L19-L59. Its Docs bullet is +L48-L52; the section's closing prose begins L56. Insert the new `###` +subsection between the Docs bullet and the closing prose. + +- [ ] **Step 1: Read the exact insertion anchor** + +Run: `sed -n '52,57p' docs/DESIGN.md` +Expected (verbatim, current tree): + +``` + specs), `plans/` (per-iteration implementation plans). + +The set of skills + agents is the development toolchain; new entries +are added here as soon as they are established. The skill system is +documented in `skills/README.md`; the agent roster lives there too. +``` + +(Line 52 ends the Docs bullet; line 53 is blank; lines 54-55 begin the +closing prose. The exact closing-prose wording on your tree is what +Step 2 anchors against — quote it from this Step's output, do not +assume.) + +- [ ] **Step 2: Insert the meta-subsection after the blank line that follows L52** + +Insert, immediately after the `specs), \`plans/\` …` line and its +following blank line (i.e. as a new block before +`The set of skills + agents is the development toolchain`): + +```markdown +### What this document is — and the honesty rule it holds itself to + +DESIGN.md describes what AILang **is now**: schema, semantics, +invariants, runtime contracts, and the rationale for each. It is +present-tense by construction. Two things never belong here: + +- **Forward intent** ("planned / will back / on the path to / + if-when X arrives") — that lives in `docs/roadmap.md`. +- **History** ("an earlier draft said / previously / what changed + in / retired in iter Y") — that lives in `docs/journals/`. + +The single legitimate exception is a present-tense reserved or +deliberately-excluded claim that is explicitly and correctly +labelled (e.g. "`Diverge` is a reserved effect name with no op and +no codegen"; "No `deriving` — instances are written by hand"; +"Regions were considered and rejected; see X"). The discriminator +is not whether a sentence mentions past or future, but whether the +document **asserts something exists, works, or changed that does +not**. Design rationale — *why* the language excludes a thing — is +in scope and present-tense; the *narrative of how the document +reached that wording* is not. + +``` + +(Trailing blank line included so the following `The set of skills + +agents …` paragraph keeps its blank-line separator.) + +- [ ] **Step 3: Verify the subsection landed and is present-tense** + +Run: `grep -n "the honesty rule it holds itself to\|asserts something exists, works, or changed that does not" docs/DESIGN.md` +Expected: two lines print (the heading ~L54 area and the discriminator +sentence). Confirm by eye that the inserted block contains no +first-person future ("we will", "planned") — it describes a rule the +document *currently* obeys. + +--- + +## Task 4: Apply the 14 byte-exact DESIGN.md corrections + procedural catch-all + +**Files:** +- Modify: `docs/DESIGN.md` (14 enumerated sites + any extra sweep hit) + +Every correction below gives the exact current text (verbatim, with +its line numbers as of plan time — re-confirm with the cited `grep` +since Task 3 shifted lines below L54 by +~22) and the exact +replacement. Apply each with an exact-string edit. The discriminator +classification is stated for each so the implementer can verify the +judgement, not just transcribe. + +> **Line-number caveat:** Task 3 inserted ~22 lines at ~L54, so every +> site below L54 is now ~22 lines lower than its plan-time number. +> Anchor every edit by the verbatim *string*, not the line number. +> The `grep` in each step relocates the site reliably. + +- [ ] **Step 1: L484 — strip the iter history-anchor (history-anchor)** + +Run: `grep -n "Both extensions accepted" docs/DESIGN.md` +Current text (verbatim, two lines): + +``` + **Both extensions accepted.** Since iter ext-cli.1 (2026-05-12), + every path-taking CLI subcommand accepts either `.ail` (Form A) +``` + +Replace with: + +``` + **Both extensions accepted.** Every path-taking CLI subcommand + accepts either `.ail` (Form A) +``` + +(The bold lead is a present-tense fact and stays; only the +`Since iter ext-cli.1 (2026-05-12),` provenance clause is removed. +The trailing `or \`.ail.json\` (Form B) as input.` on the next line is +unchanged.) + +- [ ] **Step 2: L503 — present-tense the authored-form statement (post-mortem)** + +Run: `grep -n "What did change in 2026-05-13" docs/DESIGN.md` +Current text (verbatim): + +``` + unchanged. What did change in 2026-05-13 (this milestone) is + which form is authored: authors now write Form A; the JSON-AST + is materialised in-process by callers that need it. The two +``` + +Replace with: + +``` + unchanged. The authored form is Form A; the JSON-AST is + materialised in-process by callers that need it. The two +``` + +- [ ] **Step 3: L650-653 — present-tense the cycle's fallback (Wunschdenken + malformed)** + +Run: `grep -n "richer integration paths" docs/DESIGN.md` +Current text (verbatim, four lines — note the current text is also +grammatically broken: "layer additively on the static-prompt path +ships, which remains"): + +``` +The discussion of richer integration paths (LLM tool-use, MCP +server, LSP) was deferred — all three layer additively on the +static-prompt path ships, which remains the +lowest-common-denominator fallback that always works. +``` + +Replace with: + +``` +The cycle's lowest-common-denominator path is the static prompt +(`ail merge-prose | client | ail parse | ail check`), which works +with any client. +``` + +(LLM tool-use / MCP / LSP forward integration intent is relocated to +`docs/roadmap.md` P3 in Task 5 Step 2.) + +- [ ] **Step 4: L655 — de-date the empirical-addendum heading (mild archaeology)** + +Run: `grep -n "### Empirical addendum" docs/DESIGN.md` +Current text (verbatim): + +``` +### Empirical addendum (2026-05-12) +``` + +Replace with: + +``` +### Empirical addendum — cross-model authoring measurement +``` + +(The section *content* — the measurement results — is present-tense +evidence for Decision 6 and is unchanged.) + +- [ ] **Step 5: L1318-1321 — present-tense the Warning severity (post-mortem)** + +Run: `grep -n "The first ever Warning-level diagnostic" docs/DESIGN.md` +Current text (verbatim, four lines): + +``` +Severity: `Warning`. The first ever Warning-level diagnostic; +previously all diagnostics were `Error`. CLI exit semantics +adjusted: `ail check`, `ail build`, `ail emit-ir` exit 1 only on +at least one Error. Warnings print but do not abort. +``` + +Replace with: + +``` +Severity: `Warning`. `ail check`, `ail build`, `ail emit-ir` exit 1 +only on at least one `Error`; warnings print but do not abort. +``` + +- [ ] **Step 6: L1504-1509 — present-tense the "does not infer everything" bullet (doc-archaeology)** + +Run: `grep -n "An earlier draft of this" docs/DESIGN.md` +Current text (verbatim, six lines): + +``` +- **Does not infer everything.** An earlier draft of this + Decision said "uniqueness is fully inferred" — that was the + mainstream RC position. A follow-up discussion + replaced it: AILang demands annotations *because* the LLM + author can produce them effortlessly. The compiler does + inference *plus* verification of contracts. +``` + +Replace with: + +``` +- **Does not infer everything.** AILang demands annotations + *because* the LLM author can produce them effortlessly. The + compiler does inference *plus* verification of contracts. +``` + +- [ ] **Step 7: L1513-1515 — present-tense the atomic-refcount bullet (Wunschdenken)** + +Run: `grep -n "Does not commit to atomic refcounts" docs/DESIGN.md` +Current text (verbatim, three lines): + +``` +- **Does not commit to atomic refcounts.** AILang is currently + single-threaded. If/when concurrency arrives, atomic-vs-non- + atomic will be a separate decision per allocation kind. +``` + +Replace with: + +``` +- **Does not commit to atomic refcounts.** AILang is + single-threaded; refcounts are non-atomic. +``` + +- [ ] **Step 8: L1837-1839 — drop the auto-derivation future tail (Wunschdenken)** + +Run: `grep -n "AILang does not auto-derive instances" docs/DESIGN.md` +Current text (verbatim, four lines): + +``` +**No `deriving`.** AILang does not auto-derive instances. `instance Eq +MyType` must be written by hand. Auto-derivation may land in a future +iteration if the Feature-acceptance criterion holds for it; that +discussion is out of scope here. +``` + +Replace with: + +``` +**No `deriving`.** AILang does not auto-derive instances. `instance Eq +MyType` must be written by hand. +``` + +(The "may land in a future iteration if the criterion holds" tail is +speculative — not a committed forward intent — so it is deleted, not +relocated; a roadmap "maybe someday" entry would itself be vapour.) + +- [ ] **Step 9: L2045-2046 — present-tense honest-reserved float_to_str (Wunschdenken)** + +Run: `grep -n "float_to_str : (borrow Float)" docs/DESIGN.md` +Current text (verbatim, two lines): + +``` +- `float_to_str : (borrow Float) -> Str` (iter 24.1, type-installed; + codegen ships in a future iter per roadmap). Will back `Show Float`. +``` + +Replace with: + +``` +- `float_to_str : (borrow Float) -> Str` (iter 24.1) — + type-installed; codegen is reserved and not yet shipped. +``` + +(`type-installed` is honest present-reserved and stays in present- +tense form; "codegen ships in a future iter per roadmap" and "Will +back `Show Float`" are the Wunschdenken removed. The roadmap already +carries the heap-Str/`float_to_str` queue entry — no relocation.) + +- [ ] **Step 10: L2025-2028 — present-tense the print-op set (post-mortem)** + +Run: `grep -n "primitives were retired 2026-05-14 in iter rpe.1" docs/DESIGN.md` +Current text (verbatim, four lines): + +``` +Routing through `print` replaces the ad-hoc per-type print +effect-ops; the `io/print_int`, `io/print_bool`, `io/print_float` +primitives were retired 2026-05-14 in iter rpe.1, leaving +`io/print_str` as the only surviving direct-output effect-op. +``` + +Replace with: + +``` +Routing through `print` is the path for non-`Str` primitives; +`io/print_str` is the only built-in direct-output effect-op. +``` + +- [ ] **Step 11: L2063-2065 — delete the duplicate retirement-narrative sentence (post-mortem)** + +Run: `grep -n "were retired in iter rpe.1 (2026-05-14)" docs/DESIGN.md` +Current text (verbatim, three lines): + +``` +the heap-Str result of `show x` into `io/print_str`. The per-type +effect-ops `io/print_int`, `io/print_bool`, `io/print_float` were +retired in iter rpe.1 (2026-05-14). +``` + +Replace with: + +``` +the heap-Str result of `show x` into `io/print_str`. +``` + +(The preceding clause already states the present behaviour; the +"were retired in iter rpe.1" sentence is pure history and is deleted.) + +- [ ] **Step 12: L2133-2138 — present-tense the prelude-embed parenthetical (doc-archaeology)** + +Run: `grep -n "originally listed" docs/DESIGN.md` +Current text (verbatim, six lines): + +``` +rejection-shape tests, not in the round-trip gate. (The +prelude's compile-time-embed carve-out, originally listed +here as the eighth fixture, was retired 2026-05-14 by +milestone prelude-decouple; the prelude is now embedded as +`examples/prelude.ail` in `ailang-surface` and parsed at +compile time via `ailang_surface::parse_prelude`.) +``` + +Replace with: + +``` +rejection-shape tests, not in the round-trip gate. (The prelude is +embedded as `examples/prelude.ail` in `ailang-surface` and parsed +at compile time via `ailang_surface::parse_prelude`.) +``` + +- [ ] **Step 13: L2519-2520 — present-tense the Boehm backend (Wunschdenken)** + +Run: `grep -n "is on the path to" docs/DESIGN.md` +Current text (verbatim, two lines): + +``` +rewrites respectively. Boehm-on-`--alloc=gc` is on the path to +retirement; see `docs/roadmap.md` for the active queue. +``` + +Replace with: + +``` +rewrites respectively. `--alloc=gc` selects the transitional Boehm +backend; `--alloc=rc` is the canonical backend (Decision 10) and the +CLI default. +``` + +(Boehm-retirement forward intent is already a P2 todo in +`docs/roadmap.md` — no relocation needed.) + +- [ ] **Step 14: Procedural catch-all — classify any remaining Sweep-5 hit** + +Run: `bash bench/architect_sweeps.sh` +For every line in the `=== Sweep: 5 (honesty: …) ===` block that is +NOT one of the 13 sites corrected in Steps 1-13 above, apply the +discriminator (DESIGN.md §"What this document is — and the honesty +rule it holds itself to"): + - present-tense correctly-labelled reserved/excluded claim → + **KEEP**, record "KEEP: — reason" in the per-iter journal. + - present-tense design rationale → **KEEP**, record likewise. + - block-quote journal citation → **KEEP**, record likewise. + - Wunschdenken (forward intent) → rewrite present-tense or, if + genuine committed forward intent not already in `docs/roadmap.md`, + relocate there; record "FIX: — before→after" in the + journal AND add a matching `assert!(!d.contains("…"))` + + present-anchor pair to `docs_honesty_pin.rs`. + - post-mortem / doc-archaeology → rewrite present-tense; record + + pin as above. +This step makes the enumeration the sweep-output-classified set (spec +L92-102), not a frozen list. Expected on the current tree: zero +additional hits beyond Steps 1-13 (Boss pre-verified), so this step +typically records only the KEEP set; it exists so a missed/new site +cannot slip the gate. + +- [ ] **Step 15: Re-run the pin — DESIGN.md assertions now GREEN** + +Run: `cargo test --workspace -p ailang-core --test docs_honesty_pin design_md` +Expected: `design_md_has_no_wunschdenken`, `design_md_has_no_doc_archaeology`, +and `design_md_present_tense_anchors_present` all PASS (Task 3 + Task 4 +discharged them). `prose_roundtrip_md_has_no_wunschdenken` is NOT in +this filter (Task 5 discharges it). + +--- + +## Task 5: PROSE_ROUNDTRIP satellite + roadmap relocation + +**Files:** +- Modify: `docs/PROSE_ROUNDTRIP.md:152-157` +- Modify: `docs/roadmap.md` (P3 — Ideas) + +- [ ] **Step 1: Strip the tool-use/MCP Wunschdenken paragraph** + +Run: `grep -n "A future iter may layer a tool-use schema" docs/PROSE_ROUNDTRIP.md` +Current text (verbatim, L152-157, the final paragraph of the file): + +``` +A future iter may layer a tool-use schema (LLM calls back into +`ail parse` / `ail check` from inside its turn) or an MCP server +(any MCP-compatible client discovers AILang's resources, tools, and +prompts) on top of this cycle. Both are additive — the static-prompt +fallback documented here remains the lowest-common-denominator path +that always works. +``` + +Replace with: + +``` +The static-prompt path documented here is the lowest-common-denominator +cycle and always works with any client. +``` + +- [ ] **Step 2: Add the relocated forward intent to roadmap P3** + +In `docs/roadmap.md`, the `## P3 — Ideas` section ends with the +`Richer integration paths between RC and uniqueness` idea. Read the +last P3 entry: + +Run: `grep -n "Richer integration paths between RC and" docs/roadmap.md` +Current tail (verbatim): + +``` +- [ ] **\[idea\]** Richer integration paths between RC and + uniqueness — deferred from the 21' arc; revisit once the + uniqueness inference covers more program shapes. +``` + +Append immediately after that entry's last line: + +``` +- [ ] **\[idea\]** LLM tool-use schema / MCP server / LSP front-end + over the prose-roundtrip cycle — additive layers on top of the + static-prompt `ail merge-prose | client | ail parse | ail check` + path (LLM calls back into `ail parse`/`ail check` mid-turn; an + MCP-compatible client discovers AILang's resources/tools/prompts). + Relocated here from DESIGN.md §"prose roundtrip" + PROSE_ROUNDTRIP.md + by the docs-honesty-lint milestone (forward intent does not live in + the canonical docs). + - context: `docs/specs/2026-05-18-docs-honesty-lint.md` +``` + +- [ ] **Step 3: Re-run the full pin — all four tests GREEN** + +Run: `cargo test --workspace -p ailang-core --test docs_honesty_pin` +Expected: 4 tests, all PASS. + +--- + +## Task 6: Full verification + +**Files:** none modified — verification only. + +- [ ] **Step 1: Pin GREEN in isolation** + +Run: `cargo test --workspace -p ailang-core --test docs_honesty_pin` +Expected: `test result: ok. 4 passed; 0 failed`. + +- [ ] **Step 2: Full workspace test — no regression** + +Run: `cargo test --workspace 2>&1 | tail -5` +Expected: all suites pass; total = prior baseline + 4 (the new pin +tests). Zero failures. (Baseline before this iter is whatever +`cargo test --workspace` reported at `928e1c0`; the only delta is +4.) + +- [ ] **Step 3: Sentinel drift/coverage trio still green** + +Run: `cargo test --workspace -p ailang-core --test design_schema_drift --test spec_drift --test schema_coverage` +Expected: all green — empirically confirms none of the three scans the +corrected prose regions (same invariant the effect-doc-honesty iter +relied on). + +- [ ] **Step 4: Sweep 5 clean; Sweeps 1-4 reduced where corrected** + +Run: `bash bench/architect_sweeps.sh; echo "EXIT=$?"` +Expected: the `=== Sweep: 5 …===` block is ABSENT (zero honesty hits — +every FIX site corrected). Sweeps 1-4: Sweep 1's hit count is reduced +versus the recon baseline (the corrected L484/L503/L655/L2027/L2065/L2135 +date-anchors are gone); any residual Sweep-1 hits are the deliberate +KEEPs (L50 doc-roles pointer date, L2050 true `(iter str-concat, +2026-05-13)` provenance). EXIT may still be 1 iff a deliberate-KEEP +Sweep-1 date-anchor remains — that is expected and architect- +adjudicated, not a failure of this iter. Record the post-iter sweep +output in the per-iter journal. + +- [ ] **Step 5: Workspace builds; no language/codegen change** + +Run: `cargo build --workspace 2>&1 | tail -2` +Expected: `Finished` clean, zero warnings introduced by this iter. +(No `crates/**/src/**` file other than the new test was touched — +confirm with `git diff --stat -- 'crates/**/src/**'` = empty.) + +- [ ] **Step 6: `ail` behaviour byte-unchanged (spec invariant)** + +Run: `git diff --stat -- 'crates/' 'runtime/' | grep -v 'tests/docs_honesty_pin.rs' || echo "ONLY THE PIN"` +Expected: `ONLY THE PIN` (the sole `crates/` change is the new test +file; no checker/codegen/runtime source touched, so `ail +check`/`run`/`build` are byte-unchanged by construction — no behavioural +re-test needed). + +--- + +## Self-review (planner Step 5) — completed inline + +1. **Spec coverage:** spec Architecture layer 1 (discriminator + subsection) → Task 3; layer 2 (corrections, DESIGN.md + satellites) + → Tasks 4-5; layer 3 (pin + Sweep 5 + architect bullet) → Tasks + 1-2. Spec Components table rows all mapped (DESIGN.md→T3/T4, + PROSE→T5, doc-comments→T4 catch-all if any echo surfaces, pin→T1, + architect_sweeps.sh→T2, ailang-architect.md→T2, roadmap→T5). + Acceptance criteria 1-8 each have a verifying step (T3S3, T4S14, + T1+T5S3, T6S4, T2S4-5, T6S2-3, T6S5-6, T5S2). Covered. +2. **Placeholder scan:** no "TBD/TODO/implement later/similar to + Task/add appropriate". Every edit shows verbatim before + exact + after. The Task-4 catch-all is a fully-specified decision + procedure with a concrete rubric, not a placeholder (spec-mandated + procedural enumeration, L92-102). +3. **Type/name/path consistency:** `docs_honesty_pin.rs`, `norm()`, + `read()`, sweep name "5 (honesty: …)", the bullet title "DESIGN.md + honesty drift", the subsection heading "What this document is — and + the honesty rule it holds itself to" are identical across Tasks + 1/2/3/6. Pin present-anchors quote the exact Task-3/Task-4 + replacement strings (cross-checked: "`--alloc=gc` selects the + transitional Boehm backend" = T4S13 after; "type-installed; codegen + is reserved and not yet shipped" = T4S9 after; "AILang demands + annotations *because* the LLM author can produce them effortlessly" + = T4S6 after; "`io/print_str` is the only built-in direct-output + effect-op" = T4S10 after; "the lowest-common-denominator cycle and + always works with any client" = T5S1 after; discriminator anchors = + T3 body). +4. **Step granularity:** every step is one edit or one command, + 2-5 min. Task 4 is 15 steps but each is one site. +5. **No commit steps:** none present. +6. **Pin/replacement substring contiguity:** discharged structurally + by `norm()` (Task 1) — all pin assertions match on + whitespace-normalised content, so no replacement-body line-wrap can + desync from a pin substring. Each pin present-anchor was + word-for-word cross-checked against its Task-3/4/5 replacement + (item 3 above). This is the recurring grep/contains line-wrap + family (iter-revert Concern 2; effect-doc-honesty Task 2) — scrubbed + here by the normalising mechanism, not by fragile single-line + discipline. +7. **Compile-gate vs deferred-caller:** N/A — no signature change; the + only `crates/` change is an additive test file. No crate-wide + compile gate depends on a deferred edit. Task 2's Sweep-5-fires + check (T2S3) precedes the corrections by design (makes the + candidate list runnable — recon concern 3 chicken/egg resolved). +8. **Verification-command filter strings resolve:** `--test + docs_honesty_pin` targets the file created in T1 (exists by the + time any Run referencing it executes — T1 is first). `--test + design_schema_drift --test spec_drift --test schema_coverage` — + recon ratified all three files exist. `cargo test … design_md` + filter (T4S15) matches the three `design_md_*` test fns named in + T1. `grep -n "four sweeps…"` (T2S5) is an expect-empty negative + check with an explicit "no output" expected result, so "nothing + matched" is the asserted success, not a masked no-op. `git diff + --stat` filters (T6S5-6) are existence/emptiness checks with + explicit expected output.