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:
+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`
|
||||
|
||||
Reference in New Issue
Block a user