iter docs-honesty-lint.1: canonical docs present-tense-honest + wrap-robust pin + Sweep 5
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.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
@@ -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::<Vec<_>>().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 <date> (this milestone)' is post-mortem narrative");
|
||||
assert!(!d.contains("primitives were retired 2026-05-14 in iter rpe.1"),
|
||||
"DESIGN.md: 'X were retired <date> 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");
|
||||
}
|
||||
+53
-48
@@ -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 <date> / 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 `<method>__<type-surface-name>` for primitive type targets
|
||||
(e.g. `show__Int`) and `<method>__<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`
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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`
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user