Files
AILang/skills/planner/SKILL.md
T
Brummel edd2558d35 iter loop-recur.3: codegen — real LLVM-IR lowering + run-to-value E2E (milestone terminal)
Third and terminal iteration of the standalone loop/recur
milestone (plan eae73bf). Replaces the iter-1 lower_term
CodegenError::Internal stub for Term::Loop/Term::Recur with real
LLVM-IR lowering: loop binders as entry-block allocas (mut.3
pending_entry_allocas, reusing mut_var_allocas so the existing
Term::Var load path is byte-unchanged), a fresh loop-header block,
recur stores + back-edge br, a loop_frames stack saved/restored at
the lambda boundary. clang -O2 mem2reg promotes the allocas to
phi. Four Boss design calls implemented verbatim and journalled
(alloca-not-hand-phi; mut_var_allocas reuse; emergent loop-exit
via the if/match join; single block_terminated field + parallel
SET site). Diff confirmed surgical: codegen/lib.rs 3 hunks (field
+ init + stub->2-arms), lambda.rs 2 hunks (save+restore); zero
edits to any existing block_terminated SET/READ site, tail-app
lowering, or verify_tail_positions (Boss call 4, the spec-pinned
invariant). Three new .ail fixtures: sum_to->55,
deep-n 1e6->500000500000 (clause-2 correctness made executable),
infinite-loop build-only. Codegen-only: no schema/typecheck
change; hash pins + drift trio stay green untouched.

One DONE_WITH_CONCERNS (T3): the plan's `cargo test ... tail`
filter resolved to no tests; ran via real names + the full 619/0
which subsumes it (feedback_plan_pseudo_vs_reality class, no
behaviour change). Boss systemic fix folded in: planner SKILL.md
Step-5 gains item 8 (verification-command filter strings must
resolve) — the second planner-meta-gap this milestone surfaced.

cargo test --workspace 616 -> 619 / 0 red (Boss-reran
independently); the 3 loop/recur e2e explicitly green. All three
components shipped: the loop/recur milestone is structurally
complete. Milestone-close audit + fieldtest is the next step.
2026-05-17 23:57:46 +02:00

280 lines
11 KiB
Markdown

---
name: planner
description: Use when a milestone spec exists in docs/specs/ and a new iteration is starting. Produces a placeholder-free, bite-sized implementation plan in docs/plans/ that the implement skill can execute task-by-task. Hard-gate before any implementation work.
---
# plan — spec → executable plan
> **Violating the letter of these rules is violating the spirit.**
## Overview
A plan is the contract between design (spec) and execution
(`implement`). It commits the file structure, names every file
that will be created or modified, and decomposes work into bites
small enough that a subagent can execute one in 2-5 minutes
without making judgement calls outside its remit.
Plans live at `docs/plans/<iteration>.md` and the header references
the parent spec. The plan decomposes work into tasks; each task is
the unit of review (spec-compliance and quality gates inside
`implement`), not the unit of commit. Commits are a Boss-only
decision taken at the end of the iter against the full working-tree
diff.
## When to Use / Skipping
Triggers:
- A spec at `docs/specs/<milestone>.md` is approved.
- A new iteration within an active milestone is starting.
May be skipped when:
- The work is a bug fix where the RED test from `debug` IS the
plan (handoff goes straight to `implement` mini-mode).
- The work is a trivial mechanical edit (one file, ≤30 LOC, no
design judgement).
**Never skipped** for a standard iteration within an active
milestone. "I know the milestone, plan from memory" is exactly the
failure mode this skill prevents.
## The Iron Law
```
NO PLACEHOLDERS — TBD, TODO, "implement later", "similar to Task N",
or "add appropriate error handling" are PLAN FAILURES.
EVERY STEP THAT CHANGES CODE INCLUDES THE CODE.
EVERY STEP THAT RUNS A COMMAND INCLUDES THE COMMAND AND EXPECTED OUTPUT.
```
Non-negotiable.
## The Process
### Step 1 — Read the parent spec
Read `docs/specs/<milestone>.md` in full. NOT from memory. Even if
the spec is recent and you wrote it yourself, re-read it before
planning.
The spec is the source of truth; the plan is the projection of one
iteration's worth of work onto a task list.
### Step 2 — Map file structure
Dispatch `ailang-plan-recon` with the spec path and iteration scope.
Read the returned file-map. Lift the relevant entries into the plan's
"Files this plan creates or modifies" section; the Boss may add or
amend entries that recon missed.
Dispatch carrier:
| Field | Content |
|-------|---------|
| `spec_path` | path to the parent spec |
| `iteration_scope` | which sections of the spec this iteration covers |
| `focus_hint` | optional — subsystem or symbol to prioritise |
Recon does NOT decide decomposition. Two recon dispatches per planner
run is unusual but legitimate (e.g. one for the main spec sections,
one with a sharper `focus_hint` for a tricky subsystem). Three or
more is a smell — re-read the spec; the iteration scope is probably
too broad.
The plan's "Files this plan creates or modifies" section keeps the
same shape:
```markdown
**Files this plan creates or modifies:**
- Create: `<exact path>` — <one-line responsibility>
- Modify: `<exact path>:<line range if known>`
- Test: `<exact path>` — <one-line case description>
```
Files that change together stay in the same task. Files that change
independently get separate tasks.
### Step 3 — Write tasks, bite-sized
Each task is a logical unit of change (one feature, one fix, one
extension). Each task contains steps; each step is ONE action that
takes 2-5 minutes:
```markdown
### Task N: <Component Name>
**Files:**
- Create: `<exact path>`
- Modify: `<exact path>:<line range if known>`
- Test: `<exact path>`
- [ ] **Step 1: Write the failing test**
```rust
#[test]
fn test_<specific_behaviour>() {
let result = function(input);
assert_eq!(result, expected);
}
```
- [ ] **Step 2: Run test to verify it fails**
Run: `cargo test --workspace -p <crate> test_<specific_behaviour>`
Expected: FAIL with "<exact expected message>"
- [ ] **Step 3: Write minimal implementation**
```rust
fn function(input: T) -> U {
// exact code
}
```
- [ ] **Step 4: Run test to verify it passes**
Run: `cargo test --workspace -p <crate> test_<specific_behaviour>`
Expected: PASS
```
No `git commit` step. Implement tasks leave their work in the
working tree; the Boss commits at the end of the iter.
### Step 4 — Plan header
Every plan starts with this header:
```markdown
# <Iteration Title> — Implementation Plan
> **Parent spec:** `docs/specs/<milestone>.md`
>
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking.
**Goal:** <one sentence>
**Architecture:** <2-3 sentences>
**Tech Stack:** <key crates/libs touched>
---
```
### Step 5 — Self-review
Before handing the plan off, run this checklist inline:
1. **Spec coverage:** every spec section has a task that implements
it. If a section has no task, add one.
2. **Placeholder scan:** grep for "TBD", "TODO", "implement later",
"similar to Task", "add appropriate error handling". Any hit is
a plan failure to fix.
3. **Type consistency:** function names, type names, file paths
referenced across tasks must match. `clearLayers()` in Task 3
and `clearFullLayers()` in Task 7 is a bug.
4. **Step granularity:** every step is 2-5 minutes. If a step is
"implement the parser", split it.
5. **No commit steps:** task templates must not contain
`git commit` instructions. Implement tasks leave work in the
working tree.
6. **Pin/replacement substring contiguity:** when a task ships a
test asserting `contains("<substring>")` (or a grep) AND another
task's verbatim replacement body is what must contain that
substring, the substring must appear *contiguously* in that
replacement body — no soft-wrap splitting it across two lines.
Two authoritative artefacts (exact pin vs. exact replacement)
that cannot both be applied literally is a plan defect, not an
implementer judgement call. This is the recurring grep/contains
line-wrap family (iter-revert Concern 2; iter effect-doc-honesty
Task 2) — scrub it here, every plan that pairs a presence-pin
with a verbatim text edit.
7. **Compile-gate vs. deferred-caller ordering:** when a task
changes a function signature (or any change that makes the
*whole crate* fail to compile until N call sites are updated)
AND that task ends with a `cargo build`/`cargo test` "0 errors"
gate, every caller the signature change touches MUST be threaded
*inside that same task* — not deferred to a later task. A
"0-errors" gate is unsatisfiable while any caller is still
unthreaded (hard `error[E0061]`), so a plan that defers a caller
(e.g. "the `check_fn` call site is handled in Task 4") past an
earlier task's compile gate is internally contradictory: the
executor is forced to pull the deferred code forward to satisfy
the gate, silently resequencing the plan. Either fold all
caller-threading into the signature-change task, or make the
gate a *partial* build of just the changed module with the
crate-wide build deferred to the task that finishes threading.
This is the recurring "compile-gate depends on a caller the plan
defers past the gate" family (iter loop-recur.2 Concern 1) —
scrub it here, every plan with a signature-change task.
8. **Verification-command filter strings must resolve.** Every
literal `cargo test … <filter>` / `grep <pat>` / `cargo test
--test <name>` in a Run step is itself a load-bearing artefact:
if its filter substring matches **no** test (or its `--test`
target file does not exist), the step silently asserts nothing —
a green "0 passed; 0 filtered" reads as success while proving
the opposite of the gate's intent. For every such command,
either (a) the filter substring must be one verified to match
≥1 real named test/line in the current tree (name it, do not
guess from the feature word — e.g. tail-app guards are
`*_tail_position_*` / `*musttail*`, NOT `tail`), or (b) use the
unfiltered suite plus an explicit result-count assertion
(`… | awk '{p+=$4} END{print p}'`, expected ≥ a stated baseline)
so "nothing ran" cannot masquerade as "nothing regressed". This
is the recurring "literal verification filter doesn't resolve to
its evident target" family (iter loop-recur.3 Concern) — scrub
every Run step whose assertion lives in a filter string.
Fix issues inline.
### Step 6 — Hand off
The plan sits in the working tree as an unstaged file at
`docs/plans/<iteration>.md`. Hand off to `implement` with: path to
the plan file + optional task focus ("only Tasks 1-3 this run").
The Boss commits the plan when handing it forward (suggested
commit subject: `plan: <iteration> <subject>`). The planner skill
does not perform the commit itself.
## Handoff Contract
| Direction | Carrier |
|-----------|---------|
| `brainstorm``planner` | path to `docs/specs/<milestone>.md` + iteration scope ("this iteration covers spec section X+Y") |
| `planner``implement` | path to `docs/plans/<iteration>.md` + optional task-range focus |
| `planner``brainstorm` (bounce) | spec contains placeholders or contradictions: name the offending section, request revision |
## Common Rationalisations
| Excuse | Reality |
|--------|---------|
| "TBD in step 4 lets me ship the plan tonight, fill in tomorrow" | Half-decided plans get re-litigated mid-iteration, costing more than the night's sleep saved. Make the decision tonight or close the laptop. |
| "Bundle Tasks 3 and 4, both small" | Tasks are the unit of review (spec-check + quality-check fire once per task). Bundling collapses two reviews into one and hides the smaller change inside the bigger one. If 3 and 4 are inseparable, they're one task — rewrite the decomposition. |
| "Spec is recent, I wrote it, plan from memory" | Memory diverges from disk. 15 minutes of re-reading is the cheapest insurance in the cycle. |
| "Step 5 'implement the parser' is fine, I'll detail it at execution time" | Then it's not a step, it's a wish. Steps are bite-sized OR the plan isn't done. |
| "Task 7 is similar to Task 4, just say so" | The executor may read tasks out of order. Repeat the code. |
| "The spec has a TBD too, I can pass it through" | Bounce back to `brainstorm`. Plans inherit spec gaps; spec gaps are not plan placeholders. |
## Red Flags — STOP
- Any of: "TBD", "TODO", "fill in later", "similar to", "add
appropriate <X>" — fix or bounce.
- Steps that describe what to do without showing how
- Function/type/path names that don't match across tasks
- Step descriptions longer than the code they describe
- Header missing parent spec reference
- Self-review skipped because "the plan looks fine"
## Cross-references
- **Input source:** `skills/brainstorm/SKILL.md` — produces the
spec this skill consumes.
- **Output target:** `skills/implement/SKILL.md` — runs the plan
task-by-task.
- **Agents dispatched:**
- `skills/planner/agents/ailang-plan-recon.md` — Step 2,
file-structure mapping (read-only). Mandatory; the Boss does
NOT do recon in-context.