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.
15 KiB
Architect Iron-Law Extension — Implementation Plan
Parent:
docs/roadmap.mdP2 todo "Architect-iron-law standing-grep extension" (no per-iteration spec — this is a tooling-discipline extension, not a milestone).Context: JOURNAL 2026-05-10 "Milestone close: design-md-consolidation" (the four sweep regexes); JOURNAL 2026-05-10 "Fieldtest close: Floats milestone" (the lockstep failure-mode that B1 surfaced).
For agentic workers: REQUIRED SUB-SKILL: use
skills/implementto run this plan. Steps use- [ ]checkboxes for tracking.
Goal: Extend ailang-architect's drift review with two standing
checks so DESIGN.md cannot silently regrow history anchors, and so
new typecheck-reject / lower_app arms cannot ship without their
cross-file companion update.
Architecture: A new helper script bench/architect_sweeps.sh
runs the four sweep regexes from the design-md-consolidation
milestone against docs/DESIGN.md and prints any matched lines.
The architect agent's standing reading list and "What you check"
section are extended with two new bullets: one that invokes the
sweep script, one that walks the two known cross-file lockstep
pairings (Pattern::Lit::* rejects ↔ pre_desugar_validation.rs,
and lower_app arms ↔ is_static_callee). No production code
changes; this is process-tooling only.
Tech Stack: bash, markdown.
Files this plan creates or modifies:
- Create:
bench/architect_sweeps.sh— runs the four design-md- consolidation sweep regexes againstdocs/DESIGN.md. Exit 0 if all sweeps are clean, 1 if any anchor is found. Output is the matched lines, prefixed by sweep name. - Modify:
skills/audit/agents/ailang-architect.md— adds two new bullets to "What you check" (DESIGN.md history-anchor regrowth + Lockstep invariants across files), and inserts a Step 2.5 in "The Process" that runs the sweep script. - Modify:
docs/JOURNAL.md— append a closing entry under today's date. - Modify:
docs/roadmap.md— strike the "Architect-iron-law standing-grep extension" P2 todo (entry done).
Task 1: Helper script bench/architect_sweeps.sh
Files:
-
Create:
bench/architect_sweeps.sh -
Test: manual invocation against current
docs/DESIGN.md -
Step 1: Write the script
Create bench/architect_sweeps.sh with the following exact contents:
#!/usr/bin/env bash
# bench/architect_sweeps.sh
#
# Run the four design-md-consolidation sweep-invariant greps against
# docs/DESIGN.md. Output: matched lines, prefixed by sweep name. Exit 0
# if all four sweeps are clean, 1 if any anchor was found.
#
# Companion to skills/audit/agents/ailang-architect.md "What you check
# / DESIGN.md history-anchor regrowth". See JOURNAL 2026-05-10
# ("Milestone close: design-md-consolidation") for the rationale of
# each sweep regex; the regexes here are copied verbatim from JOURNAL
# entries 12487 (Sweep 1), 12619 (Sweep 2), 12718-12720 (Sweep 3),
# and 12840 (Sweep 4).
#
# A non-zero exit is advisory, not authoritative: the architect agent
# reviews each match and decides whether it is a legitimate quote
# (e.g. a JOURNAL citation inside a block-quote) or fresh drift.
set -u
DESIGN="docs/DESIGN.md"
HITS=0
if [[ ! -f "$DESIGN" ]]; then
echo "architect_sweeps: $DESIGN not found (run from repo root)" >&2
exit 2
fi
run_sweep() {
local name="$1"
local pattern="$2"
local matches
matches=$(grep -nE "$pattern" "$DESIGN" || true)
if [[ -n "$matches" ]]; then
echo "=== Sweep: $name ==="
echo "$matches"
echo
HITS=1
fi
}
run_sweep "1 (history anchors)" \
'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'
run_sweep "2 (REVERTED + migration)" \
'REVERTED|preserved for the audit trail|Migration plan|[Oo]riginally framed|original rationale|empirically-grounded version|A future (iter|iteration|milestone|Prelude) may|A future iter that|a (later|future) iter(ation)? \(deferred\)|Concrete design deferred'
run_sweep "3 (schema SoT)" \
'^\s*(struct |enum |pub (struct|enum|fn))|whenever the two disagree|ast\.rs is the source of truth'
run_sweep "4 (workflow + stale cross-references)" \
'agents/README\.md|ailang-docwriter|Recently lifted|see the JOURNAL queue|later the same day|Sharpened later|closure conversion in JOURNAL'
if [[ $HITS -eq 0 ]]; then
echo "All four sweeps clean."
fi
exit $HITS
- Step 2: Make it executable
Run: chmod +x bench/architect_sweeps.sh
Expected: no output, exit 0.
- Step 3: Run against current DESIGN.md, expect clean
Run: bash bench/architect_sweeps.sh
Expected: stdout = All four sweeps clean., exit code 0.
If any sweep matches, the script implementation is wrong (the design-md-consolidation milestone closed all four sweeps as clean on 2026-05-10; today's DESIGN.md is the post-close baseline). Diff the regex against the JOURNAL-recorded one character-by-character.
- Step 4: Commit
git add bench/architect_sweeps.sh
git commit -m "iter architect-iron-law.1: bench/architect_sweeps.sh runs the four design-md-consolidation sweeps against DESIGN.md"
Task 2: Extend ailang-architect agent prose
Files:
-
Modify:
skills/audit/agents/ailang-architect.md -
Step 1: Add "DESIGN.md history-anchor regrowth" bullet to "What you check"
In skills/audit/agents/ailang-architect.md, locate the "What you
check" section (currently has bullets: Drift against DESIGN.md, Drift
against the milestone spec, Growing debt, Consistency across crates,
Test coverage, Scaling break points, JOURNAL truthfulness).
Insert a new bullet immediately AFTER the "JOURNAL truthfulness" bullet (i.e. as the last bullet in the list):
- **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 citation inside a block-
quote) is fine; a fresh history anchor / REVERTED narrative /
workflow detail / stale cross-reference is drift to flag.
- **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
canonical example). On every milestone-close, walk these pairs:
| Pair | Failure mode |
|---|---|
| `Pattern::Lit::*` typecheck rejects in `crates/ailang-check/src/lib.rs` ↔ pre-desugar walkers in `crates/ailang-check/src/pre_desugar_validation.rs` | A reject arm placed AFTER `desugar_module` in the call chain is unreachable through the public `check` API if the desugar pass rewrites that pattern shape first (e.g. `desugar::build_eq` rewrites `Pattern::Lit::Float` into `(== scrut lit)` before typecheck runs). New rejects on a `Pattern::Lit::*` shape MUST live in `pre_desugar_validation.rs`, or be paired with a written guarantee that no desugar pass eats the shape. |
| `lower_app` arms in `crates/ailang-codegen/src/lib.rs::lower_app` (line ~1749) ↔ name recognition in `crates/ailang-codegen/src/lib.rs::is_static_callee` (line ~2189) | A name lowered by a direct `lower_app` arm but unrecognised by `is_static_callee` falls through to the indirect-call path with `UnknownVar` (`UnknownVar` panic in worst case). Every new builtin lowering arm in `lower_app` must have a matching `is_static_callee` entry. |
Walk procedure: for each milestone-scope commit-range arm landed in
these files (use `git diff <prev-close>..HEAD --` on each file in
the pair), open both files in the pair and confirm the matching
update is present. Flag any unpaired arm as drift.
- Step 2: Add Step 2.5 to "The Process"
In skills/audit/agents/ailang-architect.md, locate "The Process"
section. Steps are currently numbered 1 through 6.
Replace Step 2 + the current Step 3 with Step 2 + Step 2.5 + Step 3 (renumbering nothing else). The current Step 2 reads:
2. `git log --oneline -30` and `git diff <prev-milestone-close>..HEAD` for
the factual diff.
Replace it with:
2. `git log --oneline -30` and `git diff <prev-milestone-close>..HEAD` for
the factual diff.
2.5. Run `bash bench/architect_sweeps.sh` from the repo root. If exit
code is 1, treat each matched line as a drift-suspicion to verify.
If exit code is 2, the script could not find DESIGN.md — fix the
working directory and re-run before continuing.
- Step 3: Self-check by re-reading the modified agent file
Read skills/audit/agents/ailang-architect.md end-to-end. Verify:
-
The two new bullets appear at the end of "What you check".
-
Step 2.5 appears between Step 2 and Step 3 in "The Process".
-
File path references resolve:
crates/ailang-check/src/lib.rs,crates/ailang-check/src/pre_desugar_validation.rs,crates/ailang-codegen/src/lib.rs,bench/architect_sweeps.shall exist. -
Step 4: Commit
git add skills/audit/agents/ailang-architect.md
git commit -m "iter architect-iron-law.2: extend ailang-architect with sweep-script invocation + lockstep-checklist for two known cross-file pairings"
Task 3: JOURNAL entry + roadmap close-out
Files:
-
Modify:
docs/JOURNAL.md -
Modify:
docs/roadmap.md -
Step 1: Append JOURNAL entry
Append the following block at the end of docs/JOURNAL.md:
## 2026-05-10 — Architect iron-law extension: sweep script + lockstep-checklist
`ailang-architect`'s drift-review iron law extended with two
standing checks, both motivated by failure modes that shipped in
the closing milestones of the typeclass-and-floats arc:
1. **DESIGN.md history-anchor regrowth.** The four sweep regexes
from the design-md-consolidation milestone (history anchors,
REVERTED + migration, schema SoT, workflow + stale cross-
references) are now packaged as `bench/architect_sweeps.sh` and
run as Step 2.5 of the architect's process. Today's DESIGN.md
is clean against all four; the script's job is to keep it that
way against future commits. Non-zero exit is advisory: the
architect reads each match and decides legitimate-quote vs. fresh
drift.
2. **Lockstep invariants across files.** Two cross-file pairings
are pinned in the agent's "What you check" section as standing
walks: `Pattern::Lit::*` typecheck-rejects ↔
`pre_desugar_validation.rs` walkers (the B1 lockstep — the
typecheck reject is unreachable through `check_module` if a
desugar pass rewrites the shape first), and `lower_app` arms ↔
`is_static_callee` recognition (the iter-4.2 / 4.4 lockstep —
a direct lowering arm without `is_static_callee` recognition
falls through to indirect-call with `UnknownVar`). For each
milestone-scope commit-range arm landed in these files, the
architect now opens both files in the pair.
Both pairings are real, both shipped silently broken at least once,
and both were caught only by post-hoc means (B1 by fieldtest, the
iter-4 ones by mid-iter implementer review). The architect was the
right role to catch them prospectively; the standing checklist is
how that role catches them in future.
Per-task commits:
- `<hash 1>` iter architect-iron-law.1: bench/architect_sweeps.sh runs the four design-md-consolidation sweeps against DESIGN.md
- `<hash 2>` iter architect-iron-law.2: extend ailang-architect with sweep-script invocation + lockstep-checklist for two known cross-file pairings
The roadmap entry "Architect-iron-law standing-grep extension"
under P2 is closed by this iteration. Future lockstep pairings, as
they surface in JOURNAL entries, can extend the table inline
without further iteration ceremony.
(The hashes will be filled in when the actual commits are made; the commit-creating step in this task patches them in.)
- Step 2: Resolve commit-hash placeholders
After Tasks 1 and 2 have been committed, get the two short hashes:
Run: git log --oneline -5 | head -3
Expected: top three lines start with the two iter-1/iter-2 commits
plus the previous (Floats) commit.
Edit docs/JOURNAL.md — replace <hash 1> and <hash 2> with the
short SHA from the corresponding commits. The Task 1 commit is
"iter architect-iron-law.1:..." and Task 2 is "...iron-law.2:...".
- Step 3: Strike the roadmap entry
In docs/roadmap.md, locate the bullet:
- [ ] **\[todo\]** Architect-iron-law standing-grep extension —
the architect agent's drift review should run the four sweep
invariant greps on every milestone-close so DESIGN.md cannot
silently regrow history anchors / REVERTED narratives /
workflow detail / stale cross-references. Path-anchored
exceptions (`docs/specs/2026-05-09-*`) need an allowlist.
Same extension should add the **lockstep-checklist** the
Floats fieldtest exposed: for every new typecheck reject arm
on a pattern shape, verify the corresponding desugar pass does
not eat that shape first; for every new lowering arm in
`lower_app`, verify `is_static_callee` recognises it. Both
shipped silently-broken in the Floats milestone (B1 and the
iter-4.2/4.4 pull-forwards) and the architect missed them.
- context: JOURNAL 2026-05-10 ("Milestone close:
design-md-consolidation"); 2026-05-10 ("Fieldtest close:
Floats milestone") — B1 + architect-checklist follow-up.
Delete it entirely. (Done entries are deleted from the roadmap once they are no longer interesting context; the JOURNAL entry above preserves the rationale.)
- Step 4: Verify the script still runs clean after agent-prose changes
Run: bash bench/architect_sweeps.sh
Expected: All four sweeps clean., exit 0. (Sanity — Tasks 2 and 3
should not have touched DESIGN.md.)
- Step 5: Commit
git add docs/JOURNAL.md docs/roadmap.md
git commit -m "iter architect-iron-law.3: JOURNAL entry + close roadmap todo"
Self-review checklist
- Spec coverage: the roadmap entry has two halves (standing greps + lockstep checklist); Task 1 covers the script that embodies the greps, Task 2 covers the agent-prose for both halves, Task 3 covers the JOURNAL + roadmap closure. All covered. ✓
- Placeholder scan:
<hash 1>/<hash 2>are placeholders resolved in Task 3 Step 2 by the implementer reading actual git output. No "TBD", no "TODO", no "implement later", no "similar to Task N". ✓ - Type / path consistency:
bench/architect_sweeps.shis the same path in script, agent file, and JOURNAL.lower_app/is_static_calleeline numbers match the verifiedgrepoutput from this conversation (1749 / 2189).pre_desugar_validation.rsexists. ✓ - Step granularity: each step is a single file-edit-or-command, 2-5 minutes. ✓