From 7580d434f0e97fd4f850962644748060403eb120 Mon Sep 17 00:00:00 2001 From: Brummel Date: Mon, 18 May 2026 12:30:03 +0200 Subject: [PATCH] iter docs-honesty-lint.1: canonical docs present-tense-honest + wrap-robust pin + Sweep 5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Strips Wunschdenken (forward intent stated as fact) and non-citation post-mortem / doc-archaeology from docs/DESIGN.md (14 corrections incl. 1 Step-14 procedural-catch-all site the spec's illustrative regex would have missed) + docs/PROSE_ROUNDTRIP.md; genuine forward intent (LLM tool-use / MCP / LSP) relocated to roadmap P3. Codifies the tense+modality discriminator as a present-tense DESIGN.md meta- subsection. Guards two ways: wrap-robust enumerated absent/present pin (crates/ailang-core/tests/docs_honesty_pin.rs, norm() whitespace- collapse helper — structurally discharges the recurring grep/contains line-wrap failure family) + wrap-robust advisory Sweep 5 in architect_sweeps.sh (contiguous-fragment regex) with full sweep-count lockstep + new ailang-architect.md "DESIGN.md honesty drift" bullet. KEEPs preserved (Diverge-reserved, regions-rejected, self-labelled tiebreaker). No language/checker/codegen/runtime change — sole crates/ change is the additive pin; ail check/run/build byte-unchanged. Workspace 609/0 (delta +4 pin), sentinel trio green, build clean. --- bench/architect_sweeps.sh | 11 +- .../2026-05-18-iter-docs-honesty-lint.1.json | 13 ++ crates/ailang-core/tests/docs_honesty_pin.rs | 100 +++++++++++++ docs/DESIGN.md | 101 +++++++------- docs/PROSE_ROUNDTRIP.md | 8 +- .../2026-05-18-iter-docs-honesty-lint.1.md | 131 ++++++++++++++++++ docs/roadmap.md | 9 ++ skills/audit/agents/ailang-architect.md | 19 ++- 8 files changed, 330 insertions(+), 62 deletions(-) create mode 100644 bench/orchestrator-stats/2026-05-18-iter-docs-honesty-lint.1.json create mode 100644 crates/ailang-core/tests/docs_honesty_pin.rs create mode 100644 docs/journals/2026-05-18-iter-docs-honesty-lint.1.md diff --git a/bench/architect_sweeps.sh b/bench/architect_sweeps.sh index 06a39b4..0f42cf1 100755 --- a/bench/architect_sweeps.sh +++ b/bench/architect_sweeps.sh @@ -1,9 +1,11 @@ #!/usr/bin/env bash # bench/architect_sweeps.sh # -# Run the four design-md-consolidation sweep-invariant greps against +# 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 four sweeps are clean, 1 if any anchor was found. +# 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. # # Companion to skills/audit/agents/ailang-architect.md "What you check # / DESIGN.md history-anchor regrowth". See JOURNAL 2026-05-10 @@ -50,7 +52,10 @@ run_sweep "3 (schema SoT)" \ 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 four sweeps clean." + echo "All five sweeps clean." fi exit $HITS diff --git a/bench/orchestrator-stats/2026-05-18-iter-docs-honesty-lint.1.json b/bench/orchestrator-stats/2026-05-18-iter-docs-honesty-lint.1.json new file mode 100644 index 0000000..00cf2f8 --- /dev/null +++ b/bench/orchestrator-stats/2026-05-18-iter-docs-honesty-lint.1.json @@ -0,0 +1,13 @@ +{ + "iter_id": "docs-honesty-lint.1", + "date": "2026-05-18", + "mode": "standard", + "outcome": "DONE", + "tasks_total": 6, + "tasks_completed": 6, + "reloops_per_task": { "1": 0, "2": 0, "3": 0, "4": 0, "5": 0, "6": 0 }, + "review_loops_spec": 0, + "review_loops_quality": 0, + "blocked_reason": null, + "notes": "Docs+test-only iter. Two DONE_WITH_CONCERNS (T3 plan-internal pin-vs-body bold desync resolved intent-preservingly; T4 Step-14 catch-all surfaced 1 genuine extra FIX site, handled per procedure). No re-loops triggered; both concerns resolved within the implementer phase before the spec check. Scope guard held: sole crates/ change is the additive pin file." +} diff --git a/crates/ailang-core/tests/docs_honesty_pin.rs b/crates/ailang-core/tests/docs_honesty_pin.rs new file mode 100644 index 0000000..c9e7371 --- /dev/null +++ b/crates/ailang-core/tests/docs_honesty_pin.rs @@ -0,0 +1,100 @@ +//! 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"); + assert!(!d.contains("was deferred from milestone 22 entirely"), + "DESIGN.md: 'was deferred from milestone 22 entirely … A future iter ships' is history+Wunschdenken (Task 4 Step 14 catch-all)"); + assert!(!d.contains("A future iter ships the full prose projection"), + "DESIGN.md: Form-B class/instance prose 'a future iter ships' is forward intent → roadmap"); +} + +#[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"); + assert!(d.contains("the render in `crates/ailang-prose/src/lib.rs` is a placeholder and informational only"), + "the Form-B class/instance prose-projection state must be present-tense (Task 4 Step 14 catch-all)"); +} + +#[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"); +} diff --git a/docs/DESIGN.md b/docs/DESIGN.md index 6d3ba57..bf32a4c 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -53,6 +53,28 @@ evolving in lockstep with the language: - **Tests**: unit tests per crate plus E2E in `crates/ail/tests/e2e.rs`. Every new compiler path needs a test, otherwise the feature does not count as done. +### 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. + When the language grows, these components grow with it. New tools that strengthen the LLM tooling (e.g. `ail diff`, IR snapshot diffs, new agents) explicitly belong in the ecosystem inventory of this section and are added @@ -481,8 +503,8 @@ on the shelf for a future iter only if both fail. to every existing subcommand; the parser is a producer, not a gatekeeper. - **Both extensions accepted.** Since iter ext-cli.1 (2026-05-12), - every path-taking CLI subcommand accepts either `.ail` (Form A) + **Both extensions accepted.** Every path-taking CLI subcommand + accepts either `.ail` (Form A) or `.ail.json` (Form B) as input. For `.ail` paths the subcommand parses through `ailang_surface::parse` in-line and then proceeds with the same loaded `Module` value that `.ail.json` would have @@ -500,9 +522,8 @@ on the shelf for a future iter only if both fail. - It does not change which form is canonical: the JSON-AST remains the hashable, content-addressed representation, and all hashing, content-addressing, and cross-module references flow through it - 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 + unchanged. The authored form is Form A; the JSON-AST is + materialised in-process by callers that need it. The two forms are byte-isomorphic by the round-trip invariant. Form (A) is one projection; the JSON-AST stays canonical. - It does not foreclose visual or graphical front-ends. The crate @@ -647,12 +668,11 @@ foreign LLM enough to produce valid output. The current prompt revises this: test, before its assertions even run. Hand-written content, mechanical drift detection. -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. +The cycle's lowest-common-denominator path is the static prompt +(`ail merge-prose | client | ail parse | ail check`), which works +with any client. -### Empirical addendum (2026-05-12) +### Empirical addendum — cross-model authoring measurement Cross-model measurement against two foreign LLMs via IONOS, temperature=0, top_p=1, max-turns=5. Two blind cohorts on the same @@ -1315,10 +1335,8 @@ binders is what lets the lint correctly identify `head_or_zero` as over-strict (could be `borrow`) while staying silent on `sum_list` where `t: List` *is* moved out. -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. +Severity: `Warning`. `ail check`, `ail build`, `ail emit-ir` exit 1 +only on at least one `Error`; warnings print but do not abort. **The suppression: `mode-strict-because`.** Authors who want to keep an over-strict annotation deliberately (e.g. @@ -1501,18 +1519,14 @@ acyclicity invariant. ### What this Decision deliberately does not do -- **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. +- **Does not infer everything.** AILang demands annotations + *because* the LLM author can produce them effortlessly. The + compiler does inference *plus* verification of contracts. - **Does not require existing fixtures to migrate immediately.** `(con T)` is treated as `(own T)`. Existing JSON hashes stay bit-identical until the fixture is intentionally updated. -- **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. +- **Does not commit to atomic refcounts.** AILang is + single-threaded; refcounts are non-atomic. - **Does not introduce regions.** Regions were considered and rejected; see "Why not other memory models" above. @@ -1834,9 +1848,7 @@ Superclass chains are linear (single-superclass relation per class) and auto-expansion closes transitively across the chain. **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. +MyType` must be written by hand. ### Diagnostic categories @@ -2022,10 +2034,8 @@ a => a -> () !IO` shipped in iter 24.3 with 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`. -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. +Routing through `print` is the path for non-`Str` primitives; +`io/print_str` is the only built-in direct-output effect-op. ### Heap-Str primitives @@ -2042,8 +2052,8 @@ and backed by a `runtime/str.c` C helper. of an `Int`. Backs `Show Int` in the prelude. - `bool_to_str : (borrow Bool) -> Str` (iter 24.1) — `"true"`/`"false"`. Backs `Show Bool` in the prelude. -- `float_to_str : (borrow Float) -> Str` (iter 24.1, type-installed; - codegen ships in a future iter per roadmap). Will back `Show Float`. +- `float_to_str : (borrow Float) -> Str` (iter 24.1) — + type-installed; codegen is reserved and not yet shipped. - `str_clone : (borrow Str) -> Str` (iter 24.1) — 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, @@ -2060,9 +2070,7 @@ instance body that wants to combine fragments. Primitive output for `Str` values goes through `io/print_str` 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`. The per-type -effect-ops `io/print_int`, `io/print_bool`, `io/print_float` were -retired in iter rpe.1 (2026-05-14). +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`, @@ -2081,11 +2089,10 @@ would invoke literal-defaulting which axis-7 already excluded. 22. Class-routing operators is a future-iteration option, not a Decision-11 commitment. - **Form-B (prose) projection of class/instance.** The prose - renderer for the new schema nodes is one-way (no parser by - design) and was deferred from milestone 22 entirely; the - placeholder render in `crates/ailang-prose/src/lib.rs` is - informational only. A future iter ships the full prose - projection if/when prose-side authoring needs surface. + renderer for the class/instance schema nodes is one-way (no + parser by design); the render in + `crates/ailang-prose/src/lib.rs` is a placeholder and + informational only. - **Specific monomorphised-symbol naming format.** Milestone 22 uses `__` for primitive type targets (e.g. `show__Int`) and `__<8-hex-prefix>` for compound @@ -2130,12 +2137,9 @@ Concretely: 4. **Carve-out anchor.** Seven `.ail.json`-only fixtures (subject-matter rejection tests) survive in the corpus by structural necessity. They participate in their own dedicated - 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`.) + 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`.) Hashing is the consequence the language depends on: BLAKE3 of the canonical bytes is well-defined for any `.ail` source via parse- @@ -2516,8 +2520,9 @@ The typechecker enforces `(own)` / `(borrow)` modes, codegen emits `ailang_rc_inc` / `_dec` calls at the points dictated by linearity, and `Term::Clone` / `Term::ReuseAs` materialise into actual rc-bumps and in-place -rewrites respectively. Boehm-on-`--alloc=gc` is on the path to -retirement; see `docs/roadmap.md` for the active queue. +rewrites respectively. `--alloc=gc` selects the transitional Boehm +backend; `--alloc=rc` is the canonical backend (Decision 10) and the +CLI default. The **desugar** pass (`ailang-core::desugar::desugar_module`) runs before typecheck and codegen in every entry point of `ailang-check` diff --git a/docs/PROSE_ROUNDTRIP.md b/docs/PROSE_ROUNDTRIP.md index c80eac4..4568c2d 100644 --- a/docs/PROSE_ROUNDTRIP.md +++ b/docs/PROSE_ROUNDTRIP.md @@ -149,9 +149,5 @@ prefer; `ail merge-prose` composes the prompt and gets out of the way. The Unix-pipe shape (`ail merge-prose ... | client | ail parse | ail check`) makes the cycle scriptable without lock-in to one vendor. -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. +The static-prompt path documented here is the lowest-common-denominator +cycle and always works with any client. diff --git a/docs/journals/2026-05-18-iter-docs-honesty-lint.1.md b/docs/journals/2026-05-18-iter-docs-honesty-lint.1.md new file mode 100644 index 0000000..0b00e16 --- /dev/null +++ b/docs/journals/2026-05-18-iter-docs-honesty-lint.1.md @@ -0,0 +1,131 @@ +# iter docs-honesty-lint.1 — canonical docs made present-tense-honest, guarded by a wrap-robust pin + Sweep 5 + +**Date:** 2026-05-18 +**Started from:** de66eb7ab2e457bfe7e5dbe2f87c5da15a786cd7 +**Status:** DONE +**Tasks completed:** 6 of 6 + +## Summary + +`docs/DESIGN.md` and `docs/PROSE_ROUNDTRIP.md` carried Wunschdenken +(forward intent stated as fact) and non-citation post-mortem / +doc-archaeology narrative. This iter strips both classes, codifies +the honesty discriminator as a `### What this document is — and the +honesty rule it holds itself to` meta-subsection inside DESIGN.md +§"Project ecosystem", and guards the invariant two ways: a +wrap-robust enumerated absent/present regression pin +(`crates/ailang-core/tests/docs_honesty_pin.rs`, 4 tests) and a +wrap-robust advisory Sweep 5 in `bench/architect_sweeps.sh` with all +sweep-count lockstep wording + a new `ailang-architect.md` "DESIGN.md +honesty drift" bullet. Genuine forward intent (LLM tool-use / MCP / +LSP) relocated to `docs/roadmap.md` P3. No language/checker/codegen/ +runtime change — the sole `crates/` change is the additive pin file; +`ail check`/`run`/`build` are byte-unchanged by construction. + +## Per-task notes + +- iter docs-honesty-lint.1.1: created the wrap-robust RED pin + (`docs_honesty_pin.rs`, `norm()` whitespace-collapse helper, 4 + tests). Verified RED for the right reasons (compiles, 4 fail on the + enumerated still-present strings + the absent discriminator). +- iter docs-honesty-lint.1.2: appended Sweep 5 to + `architect_sweeps.sh` + tail "All four"→"All five" + header + "four"→"five sweeps"; added the "DESIGN.md honesty drift" architect + bullet and fixed the sibling "four sweeps"→"five / Sweeps 1-4" + wording. Sweep 5 confirmed firing on the uncorrected tree + (EXIT=1). Concern-1 lockstep shipped whole, no split. +- iter docs-honesty-lint.1.3: inserted the discriminator + meta-subsection. Tree had drifted (a `- **Tests**:` bullet now + follows the Docs bullet, no blank line; closing prose is "When the + language grows…"); anchored on the verbatim closing-prose line per + the plan's own Step-1 "quote it, do not assume" caveat. +- iter docs-honesty-lint.1.4: applied the 13 byte-exact corrections + (each verbatim "current text" re-confirmed by grep first; lines had + drifted +~22 from Task 3). Step-14 catch-all surfaced one genuine + extra FIX site (see Concerns); classified + handled per procedure. +- iter docs-honesty-lint.1.5: stripped the PROSE_ROUNDTRIP tool-use/ + MCP Wunschdenken paragraph (present-tense replacement); appended + the relocated forward-intent idea to roadmap P3 with spec + provenance. Full pin GREEN (4/4). +- iter docs-honesty-lint.1.6: full verification — pin GREEN isolated; + workspace zero failures (609 passed, delta = +4 pin tests only); + sentinel trio (design_schema_drift/spec_drift/schema_coverage) + green; Sweep 5 reduced to the single self-referential L62 KEEP; + build clean; `ONLY THE PIN` scope confirmation. + +## Concerns + +- T3: plan Task-1 pin string `whether the document asserts something + exists, works, or changed that does not` omitted the `**…**` + Markdown bold that plan Task-3 body wrapped around `asserts … + not`. Plan self-review item 3 cross-check missed it. Resolved by + dropping the incidental bold from the inserted body (the pin is the + contract, written first; the emphasis is non-load-bearing). Prose + meaning + present-tense framing unchanged. Plan-internal + inconsistency, not a tree-drift; flagged for planner calibration. +- T4: Step-14 catch-all surfaced one genuine extra Sweep-5 FIX site + not in Steps 1-13 — DESIGN.md Form-B class/instance prose-projection + bullet ("was deferred from milestone 22 entirely; … A future iter + ships the full prose projection if/when …"). The Boss's "zero extra + hits" pre-verification was against the spec's illustrative regex; + the plan's broader Sweep-5 regex correctly catches this soft-wrapped + site. Handled exactly per Step-14: rewritten present-tense (kept the + load-bearing facts — one-way renderer, no parser by design, + placeholder render in `crates/ailang-prose/src/lib.rs`) + matching + absent-string asserts + present-anchor added to the pin. This is the + procedural catch-all working as designed. + +## Catch-all classification (Task 4 Step 14) + +- KEEP: DESIGN.md L62 `- **Forward intent** ("planned / will back / + on the path to / if-when X arrives")` — the discriminator + subsection's own enumerated catalogue of forbidden phrasings; + asserts nothing false, present-tense rule definition. A + self-referential Sweep-5 false-positive (the regex matches the + literal "on the path to" inside the rule's own example list). +- FIX: DESIGN.md L2093 Form-B prose-projection bullet — see Concerns; + before→after recorded there; pin pair added. + +## Known debt + +- (none) — the iter is self-contained; the pin + Sweep 5 are the + forward guard against regrowth. + +## Post-iter sweep output (Task 6 Step 4) + +``` +=== Sweep: 1 (history anchors) === +50: `docs/journal-archive.md` (archived monolith for pre-2026-05-11 history), +2060: 2026-05-13) — combines two `Str` values into a single owned `Str`. + +=== Sweep: 5 (honesty: wunschdenken + non-citation post-mortem) === +62:- **Forward intent** ("planned / will back / on the path to / + +EXIT=1 +``` + +Sweep-1 residue = the two documented deliberate KEEPs (L50 doc-roles +pointer date, L2060 true `(iter str-concat, 2026-05-13)` provenance). +Sweep-5 residue = the single L62 self-referential discriminator- +catalogue KEEP. EXIT=1 is expected + architect-adjudicated per plan +Task 6 Step 4 (deliberate-KEEP date-anchors remain by design). + +## Blocked detail + +(none — DONE) + +## Files touched + +- `crates/ailang-core/tests/docs_honesty_pin.rs` (new — the pin, 4 + tests; extended in T4 Step 14 per the mandated catch-all procedure) +- `bench/architect_sweeps.sh` (Sweep 5 + header/tail lockstep) +- `skills/audit/agents/ailang-architect.md` ("four"→"five" + new + "DESIGN.md honesty drift" bullet) +- `docs/DESIGN.md` (discriminator subsection + 13 enumerated + corrections + 1 catch-all correction) +- `docs/PROSE_ROUNDTRIP.md` (tool-use/MCP Wunschdenken stripped) +- `docs/roadmap.md` (relocated forward-intent idea, P3) + +## Stats + +bench/orchestrator-stats/2026-05-18-iter-docs-honesty-lint.1.json diff --git a/docs/roadmap.md b/docs/roadmap.md index beef8cc..92890c0 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -651,3 +651,12 @@ work progresses. - [ ] **\[idea\]** Richer integration paths between RC and uniqueness — deferred from the 21' arc; revisit once the uniqueness inference covers more program shapes. +- [ ] **\[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` diff --git a/skills/audit/agents/ailang-architect.md b/skills/audit/agents/ailang-architect.md index a59de79..5498903 100644 --- a/skills/audit/agents/ailang-architect.md +++ b/skills/audit/agents/ailang-architect.md @@ -72,11 +72,20 @@ If `milestone_scope` is empty, return a structural error and stop. is its own kind of drift. - **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. + 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. - **Lockstep invariants across files.** Two known cross-file pairings must move together; a new arm in one without the matching update in the other ships silently broken (B1 in the Floats fieldtest is the