832375f2ac
All 176 files in the four accumulating directories now use a zero-padded 4-digit counter prefix that reflects creation order (`NNNN-slug.md`). The counter is assigned per directory in strict git-log creation order; ties broken alphabetically by original name. The old `YYYY-MM-DD-` prefix on docs/specs/ and docs/plans/ files is dropped — the date is recoverable from git log and the counter carries the ordering. A file's counter is stable for the life of the file: never reassigned, never reused, never compacted. Deleted files retire their counter; subsequent files do not fill the gap. This is the property that lets cross-references stay literal — refs use the full filename including the counter (`design/contracts/0007-honesty-rule.md`) so they grep cleanly and resolve directly without a glob step. 313 cross-references updated across .md/.rs/.toml/.c/.json files (test pins, include_str! paths, design-INDEX entries, baseline notes, runtime C comments, inter-contract markdown links incl. bare basename and `../models/foo.md` forms). CLAUDE.md gets a new "File-naming convention" section spelling out the rule and rationale. skills/brainstorm/SKILL.md and skills/planner/SKILL.md updated so new spec/plan creation produces counter-prefixed names from the start. The full test suite (cargo test --workspace) passes.
797 lines
30 KiB
Markdown
797 lines
30 KiB
Markdown
# design-md-consolidation iter 2 — sweep 2: REVERTED + migration plans + correction history + future speculations
|
||
|
||
> **Parent spec:** `docs/specs/0004-design-md-consolidation.md`
|
||
> §"Sweep 2 — REVERTED + migration plans out".
|
||
>
|
||
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
|
||
> to run this plan. Steps use `- [ ]` checkboxes for tracking.
|
||
|
||
**Goal:** Remove the REVERTED-decision body, the completed migration
|
||
plan, the correction-history paragraph, and the non-binding future
|
||
speculations from `docs/DESIGN.md`; condense binding-prohibition
|
||
forward-looking statements into assertive form.
|
||
|
||
**Architecture:** Documentation-only refactor. Each task targets one
|
||
self-contained section or one decision class. "RED" is a pre-task
|
||
grep / line-range read showing the target sites; "GREEN" is the
|
||
post-task grep returning empty (or only inside the binding-
|
||
prohibition contexts the spec wants preserved). No code changes.
|
||
|
||
**Tech Stack:** Edit (`docs/DESIGN.md`), grep, `cargo test
|
||
--workspace`, `bench/check.py`, `bench/compile_check.py`.
|
||
|
||
**Lesson from Sweep 1.** The acceptance grep must cover the spec's
|
||
full intent, not one specific anchor form. This plan's composite
|
||
acceptance grep is therefore the union of all variant phrasings the
|
||
spec section names — encoded once at Step 1 of Task 6 — so the
|
||
sweep cannot ship while any variant survives.
|
||
|
||
**Files this plan modifies:**
|
||
- Modify: `docs/DESIGN.md` — five edit tasks (sections / paragraphs).
|
||
- Append: `docs/JOURNAL.md` — one iter entry.
|
||
- Modify: `docs/roadmap.md` — flip Sweep 2 entry from `[ ]` → `[x]`.
|
||
|
||
---
|
||
|
||
## Task 1: Delete Decision 7 (`Term::If` removal — REVERTED)
|
||
|
||
**Files:** Modify: `docs/DESIGN.md` (delete lines 593-624 inclusive at
|
||
iter start; line numbers may shift slightly).
|
||
|
||
The entire Decision 7 block is REVERTED-and-restored audit-trail
|
||
text. `Term::If` exists in the language; the witness is the Term
|
||
schema in the Data-model section. The decision body has no
|
||
state-only content to preserve — every claim it makes describes a
|
||
removal that was rolled back.
|
||
|
||
- [ ] **Step 1: Pre-test — verify decision boundaries**
|
||
|
||
```bash
|
||
grep -n '^## Decision 7\|^## Decision 8' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: two adjacent matches; the first is line ~593
|
||
(`## Decision 7: redundancy removal — \`Term::If\` is not a
|
||
primitive`), the second is line ~625 (`## Decision 8: explicit,
|
||
verified tail calls`). The block to delete spans the first up to
|
||
(but not including) the second.
|
||
|
||
- [ ] **Step 2: Read the block to confirm scope**
|
||
|
||
```bash
|
||
sed -n '593,624p' docs/DESIGN.md
|
||
```
|
||
|
||
Expected output: 32 lines starting with `## Decision 7: …` and
|
||
ending with `… the new hashes become the new identity.` followed
|
||
by a blank line. The next line is `## Decision 8: …`.
|
||
|
||
- [ ] **Step 3: Delete the Decision 7 block**
|
||
|
||
Use the Edit tool. The `old_string` is the full 32-line block from
|
||
line 593 (`## Decision 7: redundancy removal — \`Term::If\` is not
|
||
a primitive`) through line 623 (`max3\`) is intentional; the new
|
||
hashes become the new identity.`) plus the trailing blank line at
|
||
624 — i.e. delete the entire block AND the blank line that follows
|
||
it, so line 625's `## Decision 8: …` becomes contiguous with
|
||
whatever previously preceded line 593 plus a single blank-line
|
||
separator.
|
||
|
||
The exact `old_string` to pass to Edit (32 lines):
|
||
|
||
```
|
||
## Decision 7: redundancy removal — `Term::If` is not a primitive
|
||
|
||
This decision was made on shaky grounds —
|
||
applying CLAUDE.md's "no redundancies" rule to a case that turned out to
|
||
be primitive control flow, not redundancy. The post-removal match-on-Bool
|
||
form (3× the tokens, asymmetric `pat-wild` for the false case) was
|
||
worse for token economy and worse for the natural shape of the language.
|
||
`Term::If` is restored. The text below is preserved for the audit trail.
|
||
|
||
`Term::If { cond, then, else_ }` is semantically a subset of
|
||
`Term::Match` on `Bool`. Per CLAUDE.md the language must contain no
|
||
redundancies; two AST nodes for the same operation produces an
|
||
authoring decision with no semantic content and an extra codegen
|
||
path. `Term::If` was removed. Migration shape on the JSON side:
|
||
|
||
{"t":"if","cond":C,"then":A,"else":B}
|
||
→
|
||
{"t":"match","scrutinee":C,
|
||
"arms":[
|
||
{"pat":{"p":"lit","lit":{"kind":"bool","value":true}},"body":A},
|
||
{"pat":{"p":"wild"},"body":B}]}
|
||
|
||
The wildcard arm satisfies the typechecker's
|
||
`primitive-needs-wildcard` rule. A future iter may upgrade the
|
||
exhaustiveness check to recognise the `true`+`false` arm pair as
|
||
covering Bool without a wildcard; until then, wildcard is the
|
||
canonical migration target.
|
||
|
||
No schema version bump (no third-party consumes `ailang/v0`).
|
||
Hash invalidation for the three migrated fixtures (`sum`, `sort`,
|
||
`max3`) is intentional; the new hashes become the new identity.
|
||
|
||
```
|
||
|
||
`new_string` is the empty string (the entire block is deleted, including the trailing blank line; section boundary collapses to whatever blank-line separator already existed before line 593).
|
||
|
||
- [ ] **Step 4: Post-test**
|
||
|
||
```bash
|
||
grep -n '^## Decision' docs/DESIGN.md | head -15
|
||
```
|
||
|
||
Expected: Decision 7 absent; Decision 6 followed directly by
|
||
Decision 8. Decisions 1, 2, 3, 4, 5, 6, 8, 9, 10, 11 — note that
|
||
Decision numbering is NOT renumbered (Decision 8 stays Decision 8;
|
||
the gap is intentional and matches existing JOURNAL references).
|
||
|
||
```bash
|
||
grep -n 'REVERTED\|preserved for the audit trail\|primitive-needs-wildcard.*future iter' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: empty.
|
||
|
||
- [ ] **Step 5: Commit**
|
||
|
||
```bash
|
||
git add docs/DESIGN.md
|
||
git commit -m "design-md-consolidation 2.1: delete Decision 7 (Term::If REVERTED block)"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 2: Condense Decision 9 narrative-of-changes opener
|
||
|
||
**Files:** Modify: `docs/DESIGN.md` (lines ~682-689 at iter start;
|
||
shifted by -32 after Task 1; re-locate at Step 1).
|
||
|
||
Decision 9's current opener is a three-frame narrative ("Originally
|
||
framed as X; then re-framed as Y; the revision flips Z"). This
|
||
recounts how the framing changed across three points in time. State-
|
||
only form: one sentence stating what Decision 9 currently is, with
|
||
the "Boehm as parity oracle" rationale preserved (it is the
|
||
substantive content; only the narrative-of-changes wrapping is cut).
|
||
|
||
- [ ] **Step 1: Pre-test — locate the paragraph**
|
||
|
||
```bash
|
||
grep -n '^## Decision 9' docs/DESIGN.md
|
||
```
|
||
|
||
Note the line number; then:
|
||
|
||
```bash
|
||
sed -n '<line>,<line+15>p' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: the opener reads "Originally framed as 'transitional
|
||
Boehm until the RC pipeline lands and the default flips'; then
|
||
re-framed as a symmetric dual-allocator policy with Boehm as the
|
||
CLI default. The revision flips the asymmetry to match Decision 10:"
|
||
followed by the three RC/Boehm/bump bullets.
|
||
|
||
- [ ] **Step 2: Replace the narrative-of-changes opener**
|
||
|
||
Edit:
|
||
- old (the paragraph between the `## Decision 9` heading and the
|
||
three bullet points):
|
||
```
|
||
Originally framed
|
||
as "transitional Boehm until the RC pipeline lands and the default flips"; then re-framed
|
||
as a symmetric dual-allocator policy with Boehm as
|
||
the CLI default. The revision flips the asymmetry to
|
||
match Decision 10:
|
||
```
|
||
- new:
|
||
```
|
||
AILang ships two allocator backends with an asymmetric role:
|
||
```
|
||
|
||
The substantive content (RC canonical, Boehm parity oracle, bump
|
||
leak-only) follows immediately as the existing three bullets, so
|
||
the new opener leads directly into them.
|
||
|
||
- [ ] **Step 3: Verify the surrounding sentences scan**
|
||
|
||
After the edit, the paragraph reads:
|
||
|
||
```
|
||
## Decision 9: dual allocator — RC canonical, Boehm parity oracle
|
||
|
||
AILang ships two allocator backends with an asymmetric role:
|
||
|
||
- **RC is canonical.** `--alloc=rc` is the CLI default …
|
||
- **Boehm stays as a parity oracle.** …
|
||
- **`--alloc=bump`** is unchanged: a leak-only bench instrument, …
|
||
```
|
||
|
||
- [ ] **Step 4: Also condense the second narrative paragraph**
|
||
|
||
The current text after the bullets contains a second narrative
|
||
paragraph (around line 717 originally; shifted): "Originally,
|
||
every ADT box, lambda env, and closure pair was allocated with
|
||
bare `malloc` and never freed…" — this is also pre-Decision-9
|
||
history. Read its full span:
|
||
|
||
```bash
|
||
grep -n 'Originally, every ADT box' docs/DESIGN.md
|
||
```
|
||
|
||
If present, the paragraph and the surrounding two paragraphs (the
|
||
"`--alloc=bump` mode introduced for the bench is a measurement
|
||
tool, not a production target." sentence and the ADT-box history)
|
||
together describe how the GC arrived in AILang. The state-only
|
||
content is in the bullets above; this is purely history.
|
||
|
||
Edit: delete from the line "The `--alloc=bump` mode introduced for
|
||
the bench is a measurement tool, not a production target." through
|
||
the line "both make a collector necessary." (the end of the
|
||
"Originally, every ADT box…" paragraph). The next paragraph
|
||
beginning **Choice: Boehm-Demers-Weiser conservative GC.** is the
|
||
state-only content and stays.
|
||
|
||
Verify the precise text by reading the region first:
|
||
```bash
|
||
sed -n '<bullets-end>,<Choice-line-1>p' docs/DESIGN.md
|
||
```
|
||
|
||
The block to delete is approximately:
|
||
|
||
```
|
||
|
||
The `--alloc=bump` mode introduced for the bench is a
|
||
measurement tool, not a production target.
|
||
|
||
Originally, every ADT box, lambda env, and closure pair was
|
||
allocated with bare `malloc` and never freed. That worked for the
|
||
17 test fixtures (all small, all short-lived) but is incompatible
|
||
with any real workload — a stdlib `fold` over a million-element
|
||
list would leak a million boxes. The "Goal" section's "no GC for
|
||
the MVP" framing predates the parameterised-ADT pipeline and the
|
||
explicit-recursion expectation; both make a collector necessary.
|
||
|
||
```
|
||
|
||
The next non-blank line (`**Choice: Boehm-Demers-Weiser conservative GC.**`) is the start of the state-only Boehm description and stays.
|
||
|
||
- [ ] **Step 5: Post-test**
|
||
|
||
```bash
|
||
grep -nE '[Oo]riginally framed|Originally, every ADT box|--alloc=bump.*measurement tool' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: empty.
|
||
|
||
```bash
|
||
grep -n '## Decision 9' docs/DESIGN.md
|
||
```
|
||
|
||
Read 30 lines forward; verify the section reads as state ("AILang
|
||
ships two allocator backends … RC is canonical … Boehm parity
|
||
oracle … bump leak-only … Choice: Boehm-Demers-Weiser conservative
|
||
GC …").
|
||
|
||
- [ ] **Step 6: Commit**
|
||
|
||
```bash
|
||
git add docs/DESIGN.md
|
||
git commit -m "design-md-consolidation 2.2: condense Decision 9 narrative-of-changes opener + drop pre-Decision-9 history paragraphs"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 3: Delete Decision 10 §"Migration plan"
|
||
|
||
**Files:** Modify: `docs/DESIGN.md` (lines ~1384-1414 at iter start
|
||
in the original file; shifted further by Tasks 1-2; re-locate at
|
||
Step 1).
|
||
|
||
Decision 10's §"Migration plan" is a 7-point list of past iters
|
||
(annotation feature → RC runtime → uniqueness inference → reuse
|
||
hints → drop-iterative → validation bench → advisory lint).
|
||
Migration is complete; the end state is what the rest of Decision
|
||
10 already describes. The list is pure history.
|
||
|
||
- [ ] **Step 1: Pre-test — locate the section**
|
||
|
||
```bash
|
||
grep -n '^### Migration plan\|^### Adjacent extensions' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: two matches. The first (Migration plan) is the section
|
||
to delete; the second (Adjacent extensions) is what comes after.
|
||
|
||
- [ ] **Step 2: Read the block to confirm scope**
|
||
|
||
```bash
|
||
grep -n '^### Migration plan' docs/DESIGN.md # gives <start>
|
||
grep -n '^### Adjacent extensions' docs/DESIGN.md # gives <end>
|
||
sed -n '<start>,<end-1>p' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: 30+ lines starting with `### Migration plan` and ending
|
||
just before the `### Adjacent extensions for mutability …` header.
|
||
The 7 numbered items follow the section header.
|
||
|
||
- [ ] **Step 3: Delete the entire `### Migration plan` block**
|
||
|
||
Use the Edit tool with `old_string` set to the entire Migration
|
||
plan section (header + 7 items + the trailing blank line that
|
||
separates it from the next subsection). The `new_string` is the
|
||
empty string. After the edit, `### Codegen contract` (or whatever
|
||
the prior subsection is) is followed directly by
|
||
`### Adjacent extensions for mutability …` separated by one blank
|
||
line.
|
||
|
||
- [ ] **Step 4: Post-test**
|
||
|
||
```bash
|
||
grep -n '^### Migration plan' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: empty.
|
||
|
||
```bash
|
||
grep -n '^### Adjacent extensions for mutability' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: still present (this was NOT deleted; it follows directly
|
||
after whatever subsection precedes it).
|
||
|
||
- [ ] **Step 5: Commit**
|
||
|
||
```bash
|
||
git add docs/DESIGN.md
|
||
git commit -m "design-md-consolidation 2.3: delete Decision 10 §Migration plan (7-point completed-iter list)"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 4: Condense Decision 11 §"Why mono, not virtual dispatch"
|
||
|
||
**Files:** Modify: `docs/DESIGN.md` (lines ~1603-1618 at iter start;
|
||
shifted by Tasks 1-3; re-locate at Step 1).
|
||
|
||
The current §"Why mono, not virtual dispatch (the empirically-
|
||
grounded version)" paragraph is structured as a correction history:
|
||
"The original rationale implicitly argued X. A micro-benchmark
|
||
refutes that specific claim. The correct rationale is one level up:
|
||
Y." State-only form skips the correction step: only Y stays.
|
||
|
||
- [ ] **Step 1: Pre-test — locate the paragraph**
|
||
|
||
```bash
|
||
grep -n 'empirically-grounded version' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: 1 line, around `**Why mono, not virtual dispatch (the
|
||
empirically-grounded version).**`.
|
||
|
||
```bash
|
||
sed -n '<line>,<line+20>p' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: the correction-history paragraph as currently formed
|
||
(starts with `**Why mono, not virtual dispatch (the empirically-
|
||
grounded version).** The original rationale implicitly argued …`,
|
||
ends with `… while the older "saves an indirect call" framing
|
||
does not.`).
|
||
|
||
- [ ] **Step 2: Replace with the state-only form**
|
||
|
||
Edit:
|
||
- old (the full correction-history paragraph):
|
||
```
|
||
**Why mono, not virtual dispatch (the empirically-grounded version).**
|
||
The original rationale implicitly argued that mono saves a per-call
|
||
indirect-jump cost. A mono-vs-vdisp micro-benchmark
|
||
(`bench/mono_dispatch.py`, JOURNAL bench-notes entry) refutes
|
||
that specific claim: on a saturating branch predictor with a
|
||
monomorphic indirect target, indirect dispatch is free relative to
|
||
the same-shape non-inlined direct call.
|
||
The correct rationale is one level up: **mono makes the call target
|
||
visible to the optimiser, unlocking inlining and downstream loop
|
||
transformations that virtual dispatch prevents in principle.** The
|
||
measured end-to-end win on a tight LCG hot loop is substantial vs
|
||
non-inlinable direct call and larger still vs polymorphic vdisp (4 distinct
|
||
targets cycling). On larger callee bodies or cold call sites the
|
||
inlining win shrinks toward zero, but the architectural claim — "mono
|
||
enables optimisations vdisp forbids" — holds across the spectrum,
|
||
while the older "saves an indirect call" framing does not.
|
||
```
|
||
- new:
|
||
```
|
||
**Why mono, not virtual dispatch.** Monomorphisation makes the call
|
||
target visible to the optimiser, unlocking inlining and downstream
|
||
loop transformations that virtual dispatch prevents in principle.
|
||
On a saturating branch predictor with a monomorphic indirect
|
||
target, the indirect call itself is comparable in cost to a
|
||
non-inlined direct call — the win is in what the optimiser can do
|
||
with the visible target, not in the call instruction. The
|
||
end-to-end gain shrinks toward zero on larger callee bodies and
|
||
cold call sites, but the architectural claim — "mono enables
|
||
optimisations vdisp forbids" — holds across the spectrum
|
||
(`bench/mono_dispatch.py` and the corresponding JOURNAL bench-notes
|
||
entry record the measured ratios).
|
||
```
|
||
|
||
This drops "(the empirically-grounded version)" from the header,
|
||
removes "the original rationale … refutes" framing, and folds the
|
||
indirect-call-cost observation into a state-only form (it is true,
|
||
in the present tense, that the indirect call is comparable in
|
||
cost). The bench reference becomes a parenthetical pointer to
|
||
JOURNAL, not a claim-and-refutation narrative.
|
||
|
||
- [ ] **Step 3: Post-test**
|
||
|
||
```bash
|
||
grep -nE 'empirically-grounded version|original rationale|refutes that specific claim' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: empty.
|
||
|
||
```bash
|
||
grep -n 'mono makes the call target\|optimiser, unlocking inlining' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: at least one match — the substantive rationale survived.
|
||
|
||
- [ ] **Step 4: Commit**
|
||
|
||
```bash
|
||
git add docs/DESIGN.md
|
||
git commit -m "design-md-consolidation 2.4: condense Decision 11 mono-vs-vdisp correction history to state-only rationale"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 5: Future-iter speculations — per-site decisions
|
||
|
||
**Files:** Modify: `docs/DESIGN.md` (5 sites at iter start: lines
|
||
616, 762, 1063, 1134, 1424, 1750. Site 616 is moot — it lives
|
||
inside Decision 7's body, deleted by Task 1. Verify at Step 1.)
|
||
|
||
Per-site decisions:
|
||
|
||
| Site (iter-start line) | Text fragment | Decision |
|
||
|------------------------|---------------|----------|
|
||
| 616 | `A future iter may upgrade the exhaustiveness check to recognise the \`true\`+\`false\` arm pair…` | MOOT — inside Decision 7 deleted by Task 1; verify the line is gone. |
|
||
| 762 | `A future iter may layer a per-fn-arena optimisation on top: when a fn's return type contains no boxed ADT…` | CONDENSE — the per-fn arena is already shipped (Decision 9 §"Per-fn arena via stack `alloca`"). Drop the "future iter may layer" framing; the layering exists. |
|
||
| 1063 | `A future iter that proposes any of laziness, recursive value bindings, shared mutable state, or any feature that creates cycles must either prove the cycle is collectible by an extension (e.g. linear ownership) or be rejected at design time.` | KEEP, tighten — this is a binding language constraint; restructure as an assertive forward-looking rule (drop "A future iter that proposes" wrapper; lead with the prohibition). |
|
||
| 1134 | `a later iter (deferred) makes the explicit annotation mandatory and rejects \`Implicit\` for boxed parameter types.` | REMOVE — non-binding aspiration; if it ever ships, the language at that point describes itself. |
|
||
| 1424 | `Concrete design deferred until the need materialises with a real workload.` | KEEP, condense — the binding part (no tracing GC backstop, ownership/linear extension) precedes; the "deferred" sentence is the punchline. Condense to remove the "until the need materialises" framing. |
|
||
| 1750 | `A future milestone may add a Prelude when concrete LLM-author code surfaces a case that benefits from \`Show a\` / \`Eq a\` / \`Ord a\` over per-type primitive functions. Until then, primitive output goes through \`io/print_int\` / \`io/print_bool\` / \`io/print_str\` directly.` | REMOVE the first sentence; KEEP the second (the second describes current state). |
|
||
|
||
- [ ] **Step 1: Pre-test — locate surviving sites**
|
||
|
||
```bash
|
||
grep -nE 'A future (iter|milestone|Prelude) may|A future iter that|a later iter \(deferred\)|Concrete design deferred' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: 5 sites (line 616 from the original is gone; the
|
||
remaining 5 sites have shifted by -32-30-? lines after Tasks 1-3).
|
||
|
||
If 6 sites match, line 616's content survived Task 1 — investigate
|
||
before continuing.
|
||
|
||
- [ ] **Step 2: Site 762 (per-fn arena)**
|
||
|
||
Read the surrounding paragraph (typically a 10-line block opening
|
||
with `A future iter may layer a per-fn-arena optimisation on top`).
|
||
The next subsection (`### Per-fn arena via stack \`alloca\``)
|
||
already describes the implemented arena. The "future iter may
|
||
layer" paragraph is announcement; the next subsection is the spec.
|
||
Delete the whole paragraph (the announcement); the implementation
|
||
description stands alone.
|
||
|
||
Edit:
|
||
- old (the announcement paragraph):
|
||
```
|
||
A future iter may layer a per-fn-arena optimisation on top: when
|
||
a fn's return type contains no boxed ADT, ADT boxes allocated
|
||
inside that fn cannot escape, so an arena freed at fn return is
|
||
sound by construction. That requires
|
||
escape analysis, the corresponding AST/IR plumbing, and is its
|
||
own design pass. Boehm-everything is the floor; arena is an
|
||
optimisation above it.
|
||
|
||
```
|
||
- new: (empty — delete entire paragraph; the next subsection
|
||
header `### Per-fn arena via stack \`alloca\`` follows directly.)
|
||
|
||
Note: the paragraph may already differ slightly from the example
|
||
above due to Sweep 1's history-anchor strips. Verify by reading
|
||
the actual current text first.
|
||
|
||
- [ ] **Step 3: Site 1063 (binding prohibition — KEEP, tighten)**
|
||
|
||
Edit:
|
||
- old (current form):
|
||
```
|
||
A future iter that proposes any of laziness, recursive value
|
||
bindings, shared mutable state, or any feature that creates
|
||
cycles must either prove the cycle is collectible by an
|
||
extension (e.g. linear ownership) or be rejected at design time.
|
||
```
|
||
- new:
|
||
```
|
||
Laziness, recursive value bindings, shared mutable state, or any
|
||
feature that creates cycles is rejected at design time unless the
|
||
proposal proves the cycle is collectible by an extension (e.g.
|
||
linear ownership).
|
||
```
|
||
|
||
This restructures from "a future iter that proposes X must Y" to
|
||
"X is rejected unless Y" — the same constraint, in assertive
|
||
present-tense form.
|
||
|
||
- [ ] **Step 4: Site 1134 (REMOVE)**
|
||
|
||
Read the surrounding paragraph; the sentence to remove is in the
|
||
list under "Schema additions" (the Type::Fn parameter modes
|
||
paragraph). The current text reads:
|
||
|
||
```
|
||
The legacy `(con T)` form is treated as `(own T)` semantically
|
||
throughout existing fixtures; a later iter (deferred) makes the
|
||
explicit annotation mandatory and rejects `Implicit` for boxed
|
||
parameter types.
|
||
```
|
||
|
||
Edit:
|
||
- old: ` a later iter (deferred) makes the explicit annotation mandatory and rejects \`Implicit\` for boxed parameter types.`
|
||
- new: `` (empty)
|
||
|
||
The remaining sentence reads "The legacy `(con T)` form is treated
|
||
as `(own T)` semantically throughout existing fixtures." — this is
|
||
state-only and stands alone.
|
||
|
||
Adjust capitalisation/period: the ", a later iter" was preceded by
|
||
a semicolon; after removal, the sentence ends at "fixtures." and
|
||
the semicolon becomes a period. Verify the final form scans:
|
||
|
||
```
|
||
The legacy `(con T)` form is treated as `(own T)` semantically
|
||
throughout existing fixtures.
|
||
```
|
||
|
||
- [ ] **Step 5: Site 1424 (KEEP, condense)**
|
||
|
||
Read the surrounding paragraph (section "Adjacent extensions for
|
||
mutability"). The current text reads:
|
||
|
||
```
|
||
If future workloads need mutable arrays, hash tables, or other
|
||
inherently mutable primitives, the answer is **not** a tracing GC
|
||
backstop. The answer is a separate ownership/linear extension
|
||
that gates mutability behind static single-owner discipline. RC
|
||
+ uniqueness is the universal floor; ownership extends it for
|
||
specific high-performance primitives without rebreaking the
|
||
acyclicity invariant. Concrete design deferred until the need
|
||
materialises with a real workload.
|
||
```
|
||
|
||
Edit:
|
||
- old: `Concrete design deferred until the need materialises with a real workload.`
|
||
- new: (empty — drop the entire sentence; the prior content carries
|
||
the binding constraint, the "deferred" sentence adds nothing.)
|
||
|
||
The paragraph now ends at "without rebreaking the acyclicity
|
||
invariant." which is a clean state-only conclusion.
|
||
|
||
- [ ] **Step 6: Site 1750 (REMOVE first sentence, KEEP second)**
|
||
|
||
Edit:
|
||
- old:
|
||
```
|
||
A future milestone may add a Prelude when concrete LLM-author code
|
||
surfaces a case that benefits from `Show a` / `Eq a` / `Ord a`
|
||
over per-type primitive functions. Until then, primitive output
|
||
goes through `io/print_int` / `io/print_bool` / `io/print_str`
|
||
directly.
|
||
```
|
||
- new:
|
||
```
|
||
Primitive output goes through `io/print_int` / `io/print_bool` /
|
||
`io/print_str` directly.
|
||
```
|
||
|
||
The second sentence describes current state (how primitive output
|
||
works today); the first is pure aspiration for an unbuilt feature.
|
||
|
||
- [ ] **Step 7: Post-test**
|
||
|
||
```bash
|
||
grep -nE 'A future (iter|milestone|Prelude) may|A future iter that|a later iter \(deferred\)|Concrete design deferred' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: empty.
|
||
|
||
```bash
|
||
grep -nE 'Laziness, recursive value bindings, shared mutable state' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: 1 line — the binding prohibition (Site 1063, in
|
||
restructured form) survived.
|
||
|
||
- [ ] **Step 8: Commit**
|
||
|
||
```bash
|
||
git add docs/DESIGN.md
|
||
git commit -m "design-md-consolidation 2.5: future-iter speculations — remove aspirations, tighten binding prohibitions"
|
||
```
|
||
|
||
---
|
||
|
||
## Task 6: Final validation + JOURNAL entry + roadmap update
|
||
|
||
**Files:** Read: `docs/DESIGN.md`. Append: `docs/JOURNAL.md`.
|
||
Modify: `docs/roadmap.md`.
|
||
|
||
- [ ] **Step 1: Composite acceptance grep**
|
||
|
||
```bash
|
||
grep -nE 'REVERTED|preserved for the audit trail|Migration plan|[Oo]riginally framed|original rationale|empirically-grounded version|A future (iter|milestone|Prelude) may|A future iter that|a later iter \(deferred\)|Concrete design deferred' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: empty.
|
||
|
||
```bash
|
||
grep -n 'Term::If' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: at least one match in the Term-schema section (line ~1909
|
||
region, `{ "t": "if", "cond": Term, "then": Term, "else": Term }`)
|
||
— `Term::If` exists in the language; the schema shows it. The
|
||
Decision 7 *block* is gone, but `Term::If` itself is still
|
||
described in the schema.
|
||
|
||
- [ ] **Step 2: cargo test sweep**
|
||
|
||
```bash
|
||
cargo test --workspace 2>&1 | grep -E "test result:|FAILED" | head -25
|
||
```
|
||
|
||
Expected: every line ends `0 failed`.
|
||
|
||
- [ ] **Step 3: Bench gates**
|
||
|
||
```bash
|
||
python3 bench/check.py 2>&1 | tail -5
|
||
python3 bench/compile_check.py 2>&1 | tail -5
|
||
```
|
||
|
||
Expected: each summary line shows `0 regressed`.
|
||
|
||
- [ ] **Step 4: Sweep-1 acceptance grep stays clean**
|
||
|
||
```bash
|
||
grep -nE 'Iter [0-9]+[a-z]?(\.[0-9]+)?|Family [0-9]+|^[^/]*2026-[0-9]{2}-[0-9]{2}|\*\*Status: |pre-[0-9]+[a-z]?|[0-9]+[a-z]? sketch|21.g' docs/DESIGN.md
|
||
```
|
||
|
||
Expected: empty (no regression of Sweep-1's invariant).
|
||
|
||
- [ ] **Step 5: Append JOURNAL entry**
|
||
|
||
Append to `docs/JOURNAL.md`. Template:
|
||
|
||
```markdown
|
||
|
||
## 2026-05-10 — Iteration design-md-consolidation 2: REVERTED + migration + correction history + future speculations
|
||
|
||
Second iteration of the milestone defined in
|
||
`docs/specs/0004-design-md-consolidation.md`. Sweep 2 closes
|
||
the "REVERTED + migration plans + correction history + future
|
||
speculations" item: the audit-trail preservation of Decision 7,
|
||
the 7-point Decision 10 Migration plan, the Decision 9
|
||
narrative-of-changes opener, the Decision 11 mono-vs-vdisp
|
||
correction history, and the non-binding future-iter speculations
|
||
are removed or condensed. DESIGN.md now describes only the current
|
||
state plus the timeless rationale; the discarded narratives live
|
||
in JOURNAL (this entry plus the original iter entries that
|
||
recorded each change at the time).
|
||
|
||
Sections deleted entirely:
|
||
- Decision 7 (Term::If REVERTED block) — 32 lines. `Term::If`
|
||
exists in the language; the witness is the Term-schema
|
||
section. Decision numbering preserves the gap (Decision 6 →
|
||
Decision 8) so JOURNAL cross-references remain stable.
|
||
- Decision 10 §"Migration plan" — 7-point list of past iters
|
||
(annotation feature → RC runtime → uniqueness inference →
|
||
reuse hints → drop-iterative → validation bench → advisory
|
||
lint). The end state is described in the rest of Decision 10.
|
||
|
||
Paragraphs condensed:
|
||
- Decision 9 narrative-of-changes opener ("Originally framed as
|
||
X; then re-framed as Y; the revision flips Z") → one-line
|
||
state opener leading into the existing three RC/Boehm/bump
|
||
bullets.
|
||
- Decision 9 pre-Decision-9 history paragraphs ("Originally,
|
||
every ADT box, lambda env, and closure pair was allocated
|
||
with bare malloc and never freed…") removed.
|
||
- Decision 11 §"Why mono, not virtual dispatch (the
|
||
empirically-grounded version)" → state-only form. The
|
||
substantive rationale ("mono enables optimisations vdisp
|
||
forbids") survives; the correction history (`The original
|
||
rationale implicitly argued … the 2026-05-10 micro-benchmark
|
||
refutes that specific claim`) is dropped.
|
||
|
||
Future-iter speculations — per-site decisions:
|
||
- Site `A future iter may layer a per-fn-arena optimisation`
|
||
REMOVED — the per-fn arena is shipped; the announcement is
|
||
history.
|
||
- Site `A future iter that proposes any of laziness…` KEPT,
|
||
TIGHTENED — restructured from "future iter that proposes X
|
||
must Y" to "X is rejected unless Y" (assertive present-tense
|
||
form of the same binding constraint).
|
||
- Site `a later iter (deferred) makes the explicit annotation
|
||
mandatory` REMOVED — non-binding aspiration.
|
||
- Site `Concrete design deferred until the need materialises`
|
||
REMOVED — the binding content (no tracing GC backstop,
|
||
ownership/linear extension) precedes; the "deferred" sentence
|
||
was the unneeded punchline.
|
||
- Site `A future milestone may add a Prelude` REMOVED first
|
||
sentence (aspiration), KEPT second sentence (current-state
|
||
description of how primitive output works today).
|
||
|
||
Acceptance:
|
||
- composite grep
|
||
`grep -nE 'REVERTED|preserved for the audit trail|Migration plan|[Oo]riginally framed|original rationale|empirically-grounded version|A future (iter|milestone|Prelude) may|A future iter that|a later iter \(deferred\)|Concrete design deferred' docs/DESIGN.md`
|
||
returns empty.
|
||
- Sweep-1 invariant grep stays empty (no regression).
|
||
- `cargo test --workspace` 0 FAILED.
|
||
- `bench/check.py` 0 regressed; `bench/compile_check.py` 0 regressed.
|
||
- `Term::If` in the Term schema (Data-model section) still
|
||
present; only the Decision 7 *block* is gone, not the AST node.
|
||
- DESIGN.md size: <X> lines (down from 2253 — record the actual
|
||
number).
|
||
|
||
Tasks (commit subjects):
|
||
|
||
- design-md-consolidation 2.1: delete Decision 7 (Term::If REVERTED block)
|
||
- design-md-consolidation 2.2: condense Decision 9 narrative-of-changes opener + drop pre-Decision-9 history paragraphs
|
||
- design-md-consolidation 2.3: delete Decision 10 §Migration plan (7-point completed-iter list)
|
||
- design-md-consolidation 2.4: condense Decision 11 mono-vs-vdisp correction history to state-only rationale
|
||
- design-md-consolidation 2.5: future-iter speculations — remove aspirations, tighten binding prohibitions
|
||
|
||
Carried into sweep 3: schema SoT inversion (DESIGN.md §Data-model
|
||
becomes the canonical schema; ast.rs gains a doc-comment pointing
|
||
to it; new drift test `design_schema_drift.rs` enforces structural
|
||
agreement). Carried into sweep 4: workflow / cross-reference
|
||
cleanup (Project ecosystem `agents/` path correction; Verification
|
||
section workflow detail; "What is not (yet) supported" §Recently
|
||
lifted gates removal).
|
||
|
||
Process note: this iter's plan-time composite grep matched the
|
||
spec's full intent on the first attempt — no fixup commits for
|
||
missed anchor variants. The Sweep 1 lesson held.
|
||
```
|
||
|
||
Adjust the template's specifics to match what was actually edited;
|
||
record the actual final DESIGN.md line count.
|
||
|
||
- [ ] **Step 6: Update roadmap.md**
|
||
|
||
Edit `docs/roadmap.md`:
|
||
- old:
|
||
```
|
||
- [x] Sweep 1 — remove history anchors
|
||
- [ ] Sweep 2 — REVERTED + migration plans out
|
||
- [ ] Sweep 3 — schema SoT inversion + data-model hardening
|
||
```
|
||
- new:
|
||
```
|
||
- [x] Sweep 1 — remove history anchors
|
||
- [x] Sweep 2 — REVERTED + migration plans out
|
||
- [ ] Sweep 3 — schema SoT inversion + data-model hardening
|
||
```
|
||
|
||
- [ ] **Step 7: Commit**
|
||
|
||
```bash
|
||
git add docs/JOURNAL.md docs/roadmap.md
|
||
git commit -m "design-md-consolidation 2: journal entry + roadmap sweep-2 closed"
|
||
```
|