plan: architect-iron-law extension — sweep script + lockstep-checklist
This commit is contained in:
@@ -0,0 +1,351 @@
|
||||
# Architect Iron-Law Extension — Implementation Plan
|
||||
|
||||
> **Parent:** `docs/roadmap.md` P2 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/implement`
|
||||
> to 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 against `docs/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:
|
||||
|
||||
```bash
|
||||
#!/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**
|
||||
|
||||
```bash
|
||||
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):
|
||||
|
||||
```markdown
|
||||
- **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:
|
||||
|
||||
```markdown
|
||||
2. `git log --oneline -30` and `git diff <prev-milestone-close>..HEAD` for
|
||||
the factual diff.
|
||||
```
|
||||
|
||||
Replace it with:
|
||||
|
||||
```markdown
|
||||
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.sh`
|
||||
all exist.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
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`:
|
||||
|
||||
```markdown
|
||||
## 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:
|
||||
|
||||
```markdown
|
||||
- [ ] **\[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**
|
||||
|
||||
```bash
|
||||
git add docs/JOURNAL.md docs/roadmap.md
|
||||
git commit -m "iter architect-iron-law.3: JOURNAL entry + close roadmap todo"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Self-review checklist
|
||||
|
||||
1. **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. ✓
|
||||
2. **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". ✓
|
||||
3. **Type / path consistency:** `bench/architect_sweeps.sh` is the
|
||||
same path in script, agent file, and JOURNAL. `lower_app` /
|
||||
`is_static_callee` line numbers match the verified `grep` output
|
||||
from this conversation (1749 / 2189). `pre_desugar_validation.rs`
|
||||
exists. ✓
|
||||
4. **Step granularity:** each step is a single file-edit-or-command,
|
||||
2-5 minutes. ✓
|
||||
Reference in New Issue
Block a user