Closes Gitea #4. Removes the Boehm-Demers-Weiser conservative GC
backend wholesale across six layers in one atomic iteration. After
this iter, `AllocStrategy` has two variants (`Rc`, `Bump`),
`--alloc=gc` is rejected at CLI parse with `unknown --alloc value`,
the libgc link arm is gone, and the design ledger describes RC
(canonical) + bump (raw-alloc bench-floor) as the only allocators.
Layer-by-layer summary:
CLI surface — `crates/ail/src/main.rs`:
`parse_alloc_strategy` arm `"gc" => Ok(AllocStrategy::Gc)`
removed; error wording updated to `(expected `rc` or `bump`)`;
clap-derive `value_parser = ["gc","bump","rc"]` allowlist on
BOTH `Build` and `Run` subcommands DROPPED so that
`parse_alloc_strategy` remains the sole gatekeeper for the
unknown-value diagnostic (otherwise clap shadows the runtime
diagnostic with `invalid value 'gc' for '--alloc'`, which would
miss the milestone-pin's stderr substring check). The
`default_value = "rc"` stays.
Codegen — `crates/ailang-codegen/src/lib.rs`:
`AllocStrategy::Gc` variant + `Default` derive removed (no
caller of `AllocStrategy::default()` existed in the workspace,
so the trait derivation was dead). `fn_name` (spec called it
`runtime_alloc_fn` loosely; actual identifier is `fn_name`)
drops the `Gc => "GC_malloc"` arm. `lower_workspace` and
`lower_workspace_staticlib` defaults flip from `Gc` to `Rc`.
In-source negative-complement codegen test (mod tests, lib.rs:3571ff)
retargets from `AllocStrategy::Gc` to `AllocStrategy::Bump`
(bump also doesn't emit per-type drop fns; the test's semantic
"no drop fns under non-RC" is preserved).
Link branch — `crates/ail/src/main.rs:2389ff`:
The `match strategy { AllocStrategy::Gc => { ... cmd.arg("-lgc"); ... } }`
arm and its libgc-link block are entirely gone. The surviving
match exhausts on `Bump` and `Rc` (Rust's exhaustiveness check
confirms; no `error[E0004]`). Staticlib-guard diagnostic
rewritten to drop the "shared Boehm collector" phrasing while
preserving the prefix `staticlib (swarm) artefact is RC-only`
verbatim (the surviving `staticlib_bump_is_rejected` test
depends on that substring).
Test suite — 3 pure-differential e2e tests deleted
(`gc_handles_recursive_list_construction`,
`alloc_rc_produces_same_stdout_as_gc`,
`alloc_rc_matches_gc_on_std_list_demo`); 9 RC-feature tests
stripped of their `stdout_gc` build call and differential
`assert_eq!(stdout_gc, stdout_rc, ...)` (absolute
`assert_eq!(stdout_rc.trim(), "<n>")` pin retained as
correctness oracle); `staticlib_gc_is_rejected` deleted; new
milestone-pin `crates/ail/tests/boehm_retirement_pin.rs`
asserts `ail build --alloc=gc` exits ≠ 0 with stderr containing
`unknown --alloc value` and `\`gc\``; `examples/gc_stress.ail`
fixture deleted (no remaining references).
Implementer expansion (not in plan): `iter17a_local_box_alloca`
(in `e2e.rs`) carried an IR-shape assertion against
`@GC_malloc`-absence as the witness for non-escaping
allocation. After the Task-2 codegen default flip, the witness
shifts to `@ailang_rc_alloc`-absence in escape-targeted
positions; assertion + doc-comment updated. Property
protected ("no heap allocation in non-escaping contexts") is
unchanged; only the named allocator shifts.
Bench harness — `bench/run.sh` 9→6 column compaction
(workload + bump(s) + rc(s) + rc/bump + bump RSS + rc RSS);
gc-arm `bench_latency_implicit_gc` build call + harness
invocation dropped from latency block; header comment reframed
from "GC-overhead bench harness" to "RC-overhead bench
harness"; "Decision 10's Boehm-retirement target (1.3x)"
rewording to "RC-overhead-vs-bump bench-health regression gate".
`bench/check.py:62` header-sentinel changes from
`"gc(s)" in line` to `"bump(s)" in line`; column-count check
at `:72` flips from `!= 9` to `!= 6`; per-workload field set
drops `gc_s`/`gc_over_bump`/`gc_rss_kb`; `ARM_LABEL_TO_KEY`
drops the `"implicit @ gc": "implicit_at_gc"` entry.
`bench/baseline.json` regenerated via `--update-baseline`.
Implementer note (planner-defect): `write_new_baseline`
iterated over the *existing* baseline's metric list when
emitting the regenerated file, so even after parser-level
`gc_*` removal, the fallback emitted them back into the JSON.
Scrubbed post-update; the cleaner fix (have
`write_new_baseline` emit only keys present in
`parsed_throughput[workload]`) is a follow-up if the script
becomes load-bearing for further allocator changes.
Design ledger — `design/models/rc-uniqueness.md` excises the
`## Dual allocator — RC canonical, Boehm parity oracle`
section and the `Boehm-Demers-Weiser conservative GC` choice
block + rationale + trade-offs; the per-fn-alloca section
generalises Boehm-specific language to allocator-agnostic;
the memory-model section's `## Choice.` paragraph reframes the
1.3× target from "Boehm-retirement gate" to "bench-health
regression gate".
`design/models/pipeline.md` drops the `--alloc=gc → links libgc`
arm of the pipeline diagram and replaces it with
`--alloc=bump → links bump-floor`; the accompanying prose
rewrites accordingly.
`design/contracts/scope-boundaries.md` rewrites the
"Memory management via Boehm conservative GC" bullet to
describe RC + per-fn-arena present-tense; the dead reference
to `examples/gc_stress.ail.json` (file never existed; the
fixture only ever had a `.ail` form, deleted by this iter) is
dropped along with the `examples/std_list_stress.ail.json`
reference whose purpose was Boehm-only soak testing.
`:67`'s `@printf` / `@GC_malloc` parenthetical updated.
`design/contracts/memory-model.md:232` drops the
"leaks like the pre-Boehm era" phrase; the RC inc/dec
instrumentation is wired up, so the "until then" conditional
that referenced pre-Boehm is closed.
`design/contracts/embedding-abi.md:42-44` rewrites the
staticlib-guard prose to drop the `--alloc=gc` clause (gc is
now a CLI-parser-level unknown-value, not a staticlib-guard
rejection) and reframe the swarm-safety justification around
`--alloc=bump` (leak-only bench instrument) rather than the
historical Boehm collector.
Honesty pin — `crates/ailang-core/tests/docs_honesty_pin.rs`
inverts the polarity: the present-tense Boehm-anchor assertion
on `pipeline.md` (`:116-117`) is deleted, and four
absence-pins are added to `design_md_has_no_wunschdenken`
against the Boehm-zombie strings `transitional Boehm`,
`parity oracle`, `GC_malloc`, `libgc`. The
`design_corpus()` already includes `rc-uniqueness.md` so no
path-list change was needed for the new pins to scan.
`crates/ailang-core/tests/design_index_pin.rs:166` drops the
`"pre-Boehm"` token from the protected-exception comment list
(the phrase no longer appears in `memory-model.md` after this
iter, so the exception is dead).
Runtime docs — `runtime/bump.c`, `runtime/rc.c`, `runtime/str.c`
header comments scrubbed of Boehm/`GC_malloc`/`libgc`
references. `bump.c`'s function signature description still
documents `void *bump_malloc(size_t)` as the bench-floor
allocator interface, but no longer cross-references libgc.
Example fixtures — `examples/bench_latency_implicit.ail`,
`bench_latency_explicit.ail`, `escape_local_demo.ail`,
`reuse_as_demo.ail`, `rc_pin_recurse_implicit.ail` doc-comment
headers scrubbed of `--alloc=gc` / Boehm references. The
`.ail` surface (AST) is untouched in every case; round-trip
invariant holds (`cargo test -p ailang-surface --test round_trip`
green).
Skill / agent prompts — `skills/audit/agents/ailang-bencher.md`
rewritten to use an RC-vs-bump worked example pattern for the
hypothesis-driven bench tutorial, replacing the recurring
"RC vs Boehm under heap pressure" example.
`skills/implement/agents/ailang-implementer.md` Decision-10 /
Boehm references replaced with present-tense RC-commitment
framing.
IR snapshots — the 5 checked-in snapshots
(`crates/ail/tests/snapshots/{hello,list,max3,sum,ws_main}.ll`)
regenerated via `UPDATE_SNAPSHOTS=1 cargo test -p ail --test
ir_snapshot`. Each previously contained
`declare ptr @GC_malloc(i64)` and (for `list.ll`) a `call ptr
@GC_malloc(...)` invocation; post-flip the snapshots contain
`declare ptr @ailang_rc_alloc(i64)` plus the rc inc/dec runtime
declarations.
Spec-vs-acceptance addendum (caught at orchestrator end-report,
absorbed here rather than in a follow-up spec edit): spec §6
acceptance criteria said "Boehm-grep returns matches ONLY in
docs_honesty_pin.rs". The plan itself prescribed historical Boehm
references in 3 additional files: (a) the new milestone-pin
`boehm_retirement_pin.rs` (must literally invoke `--alloc=gc` to
assert its rejection), (b) `embed_staticlib_alloc_guard.rs` file
doc-comment historical note ("`--alloc=gc` no longer exists as a
CLI value"), (c) `embedding-abi.md:44-45` contract historical
clause ("see the Boehm-retirement iter"). All three are
prescribed; the spec's grep wording was too narrow. The four
absence-pins in `docs_honesty_pin.rs` catch the actual zombies
(Boehm-narrative re-emerging in the design ledger), which is the
substantive intent the spec was aiming at — the four extra
documented-by-design exceptions are the cost of having an
explicit milestone-pin and contract-level historical anchors.
Net delta:
- 32 files modified, 2 new (boehm_retirement_pin.rs + stats),
1 deleted (gc_stress.ail);
- workspace tests: every binary `0 failed`. Pass-count delta:
-3 net (4 e2e tests deleted, 1 new milestone-pin test added);
- boehm-grep state: hits only in the four by-design exceptions
documented above;
- `bench/check.py` exit 0 against regenerated baseline;
- CLI must-fail fixture: `ail build --alloc=gc examples/hello.ail`
exits non-zero with stderr containing `unknown --alloc value`
and `\`gc\``;
- design ledger present-tense honest (Boehm-narrative gone from
`rc-uniqueness.md` + `pipeline.md`; the few historical
references in `embedding-abi.md` / `boehm_retirement_pin.rs` /
`embed_staticlib_alloc_guard.rs` are explicit milestone-pins
or contract anchors, not silent ledger residue).
Bench measurement variance noted: closure-chain and hof-pipeline
are ±1-5% jittery between runs; one regeneration flagged 2
metrics as `regressed` before a second run returned 0. The
captured baseline is within self-comparison range. Existing
per-metric tolerances absorb the jitter.
Stats file:
`bench/orchestrator-stats/2026-05-20-iter-boehm-retirement.1.json`.
closes#4
Tightens `skills/planner/agents/ailang-plan-recon.md` against two
recon-contract failure modes documented in Gitea #9:
(a) For signature-change / enum-variant-add-remove / public-symbol-
removal scopes, hand-listing of call sites or match arms has
under-counted the blast radius four times across two milestones,
each through a different site type (loop-recur.1 walker arms,
loop-recur.2 cross-module synth callers, loop-recur.tidy implicit,
remove-mut-var-assign.1 in-source `mod tests` fns + drift pin +
`.ail.json` carve-outs + a non-enumerated E0599). The recon now
MUST report a compile-driven enumeration (cargo check after a
stub / exhaustive `git grep -nE` / `cargo expand`) as the
authoritative code-site set; hand-listing is explicitly labelled
"advisory". The compile-driven channel only covers compile-checked
sites, so a separate sweep for drift pins, `.ail`/`.ail.json`
fixtures, and design-doc references is required and reported
under a "Non-compile-checked sites" section.
(b) Every path the spec names is now `ls`-verified before propagation
into the brief. An existence claim feeding a recon is itself
load-bearing — one prior recon brief inherited an unverified
"X does not exist" claim (form_a.md, remove-mut-var-assign.1)
and was caught only at milestone-close audit. The new "Spec-named
path existence table" is mandatory for every dispatch (regardless
of scope class); entries marked "not exists" must carry the exact
`ls` / `git ls-files` command run, and only verified-not-exists
entries may feed "Anchors not yet present".
Three new Common Rationalisations and three new Red Flags
calibrate against the named failure modes. The "Compile-driven
site set" / "Non-compile-checked sites" output sections may be
omitted for iterations that do not involve a signature / variant /
removal scope; the existence table is always required.
No language change; no code change. Agent-definition discipline
fix only.
closes#9
New label for "core functionality broken" — the only category
with a hard precedence rule baked into the skill system, not a
judgement call. No issues carry it today; the label and the
skills must know about it so that the first time one is filed,
the orchestrator handles it without a one-off "what now?"
exchange.
In-tree changes:
- CLAUDE.md: Gitea-issues bullet introduces a "precedence order
matters" note and lists `BLOCKER` first.
- skills/boss/SKILL.md: Step 1 gains a dedicated `BLOCKER`
precedence paragraph — every queue read starts with
`tea issues ls --labels BLOCKER --state open`; if hit, it's
the next dispatch (RED-first via skills/debug), preempting
whatever else is in flight. The "finish the current agent
call first, don't strand a working tree mid-edit" caveat is
written in.
- skills/brainstorm/SKILL.md: Step 7.5 tea-create template
flags that BLOCKER can stack on top of the kind label.
Universal bug-fix mechanics (RED-first TDD via skills/debug)
are unchanged — BLOCKER is a precedence tag, not a new
workflow. The /boss "Direction freedom" section continues to
gate cross-milestone hops; BLOCKER is an in-milestone preempt
that doesn't bounce back to the user (it has the orchestrator's
implicit authority by definition).
Verification: cargo test --workspace 647/0/2, architect_sweeps
exit 0.
New label for observable misbehaviour distinct from
additive-feature work and clean-up tasks. The /boss pickup
order treats a bug differently from a feature (a bug typically
gets RED-first TDD via skills/debug, a feature goes through
brainstorm), so the label earns its keep.
Tagged in Gitea (6 of 24 issues):
- #7 io/print_float always-emit-.0
(surface vs runtime printer inconsistent)
- #9 ailang-plan-recon site-undercount
(tool under-counted 4× across two milestones)
- #10 design_schema_drift.rs fidelity widening
(test produces false negatives on §"Data model" gaps)
- #12 Zero-arg `(app f)` rejected at parse
(parser disagrees with the AST schema)
- #15 *.bump_s throughput baseline stale
(bench false-positive on environmental drift)
- #16 check.py RC-latency *.max_us
(bench false-positive: 3-of-3 null changes)
Borderline cases left unlabelled (diagnostic usability,
load_workspace limitation, dormant constraint-drop, advisory
Sweep-5 wart) — they aren't observable wrong behaviour, just
suboptimal.
In-tree changes:
- CLAUDE.md: Gitea-issues bullet adds `bug` to the label set
with the same description string Gitea carries.
- skills/boss/SKILL.md: Step 1 filter snippet includes `bug`.
- skills/brainstorm/SKILL.md: Step 7.5 tea-create template
--labels choice set includes `bug`.
Distribution after tagging: 3 feature + 6 bug + 5 idea + 10
unlabelled = 24 open issues. Verification: cargo test
--workspace 647/0/2, architect_sweeps exit 0.
The `milestone` label was a dead duplicate of Gitea's first-class
milestone container. Zero issues carried it (the three actual
big-chunks — Flat array, Iteration-totality, Stateful islands —
live as Gitea milestone containers, not as labelled issues).
Same pattern as `prio:p1`: a slot that never gets used because
the concept it tries to label lives somewhere else.
Label deleted in Gitea. Remaining labels: `feature`, `idea`,
`in-progress` (three, all semantic, no taxonomy noise). Big-
chunk work continues to live as Gitea milestone containers
(reached via `tea milestones ls --repo Brummel/AILang`).
In-tree changes:
- CLAUDE.md: Gitea-issues bullet describes the three-label
shape; explicit note that milestone is a Gitea container,
not a label.
- skills/boss/SKILL.md: Step 1 filter set drops `milestone`,
adds `tea milestones ls` for the container view; direction-
freedom "new milestone" trigger reworded around the
container, not the label.
- skills/brainstorm/SKILL.md: Step 7.5 tea-create template
drops `milestone` from the choice set; adds a note that
spec-needing deferred work should be filed as a Gitea
milestone container via `tea milestones create` instead.
Verification: cargo test --workspace 647/0/2, architect_sweeps
exit 0, zero residual `milestone`-as-label refs in live docs
(grep skip-listed legitimate "Gitea milestone (container)"
prose).
`todo` and `feature` were semantically near-identical ("do it, no
spec needed") and the boss-pickup decision treated both the same.
Collapsing the larger one into "no label" cuts the tag-noise on
16 of 24 issues; the 3 `feature` issues retain the label as a
deliberate "substantive but no full spec" marker against the
unlabelled bucket of mechanical follow-ups.
Label `todo` deleted in Gitea (Tea removed it from the 16
issues automatically). Remaining labels: `milestone`, `feature`,
`idea`, `in-progress`.
In-tree changes:
- CLAUDE.md: Gitea-issues bullet describes the new shape —
three semantic labels + unlabelled-default-bucket.
- skills/boss/SKILL.md: Step 1 filter-snippet and direction-
freedom commentary updated.
- skills/brainstorm/SKILL.md: Step 7.5 tea-create template
drops `todo` from the choice set and notes that omitting
`--labels` is the default-bucket path.
Verification: cargo test --workspace 647/0/2, architect_sweeps
exit 0, zero residual `todo`-as-label refs in live docs.
Labels renamed in Gitea (Tea propagated the rename to all 24
issues automatically):
- kind:milestone → milestone
- kind:feature → feature
- kind:todo → todo
- kind:idea → idea
- state:in-progress → in-progress
Five live labels total; no semantic ambiguity since milestone,
feature, todo, idea are all "class" and in-progress is the only
"state" — the prefixes were carrying zero distinguishing weight.
In-tree changes:
- CLAUDE.md: Gitea-issues bullet uses the bare label names.
- skills/boss/SKILL.md: Step 1 filter snippets + direction-
freedom new-milestone trigger drop the prefixes.
- skills/brainstorm/SKILL.md: Step 7.5 tea-issues-create
template drops the prefix on the --labels argument.
Verification: cargo test --workspace 647/0/2, architect_sweeps
exit 0, zero residual `kind:*` / `state:*` refs outside
docs/specs/ and docs/plans/.
Empirical observation after one day of running with the Gitea
backlog: P1 was permanently empty (same pattern as the old
docs/roadmap.md — anything that becomes "next-up" instantly
moves to in-progress, never sits in P1), and P3 was 6-of-8
identical to `kind:idea`. Three prio-stages were theatre; the
real distinction is "ja, irgendwann" vs "may be cut", and
`kind:idea` already carries the latter.
`prio:p1` / `prio:p2` / `prio:p3` deleted from Gitea (Tea
auto-removed them from all 24 issues). Remaining labels:
`kind:{milestone,feature,todo,idea}` + `state:in-progress`.
Issue distribution: 3 feature + 16 todo + 5 idea = 24.
In-tree changes:
- CLAUDE.md (project): Gitea-issues bullet rewritten — no
formal priority axis, "what's next" is orchestrator
judgement per session, `kind:idea` flagged as the
may-be-cut marker.
- skills/boss/SKILL.md: Step 1 rewritten — `tea issues ls
--state open` walks every open issue; selection is by
orchestrator judgement, not by reading prio:p1 first.
Cross-references "Queue:" updated to match.
- skills/brainstorm/SKILL.md: Step 7.5 no-override BLOCK
template drops `prio:p2` from the `tea issues create`
--labels argument.
Why not keep one stage (e.g. `prio:next`): no in-flight need;
a `pinned` boolean label can be added later if "next-up" ever
becomes a real distinct state. The cost of adding a label
later is one `tea labels create`; the cost of carrying dead
labels is constant cognitive load on every new issue.
Verification: cargo test --workspace 647/0/2, architect_sweeps
exit 0, zero residual prio:p* refs outside docs/specs/ and
docs/plans/ (historical, unchanged per the JOURNAL-cut
precedent).
The forward queue moves out of the in-tree markdown file and into
Gitea issues at http://192.168.178.103:3000/Brummel/AILang/issues.
Labels: kind:{milestone,feature,todo,idea} + prio:{p1,p2,p3}
+ state:in-progress. Big chunks live as Gitea milestones
(containers) with full prose in the description; smaller items are
standalone issues. Browse-and-filter scales constant against
growing item count; the previous markdown file was 1059 lines, of
which ~850 were already-closed-entry verlauf (the same failure
class the JOURNAL cut removed).
Sync-drift Code<>Tracker mitigation: Soft-convention `closes #N`
/ `refs #N` in commit bodies — Gitea auto-closes the issue on
push. Captured in user-level CLAUDE.md (~/.claude/CLAUDE.md, not
in this commit) as the durable rule; no hook enforcement.
In-repo changes:
- docs/roadmap.md deleted.
- CLAUDE.md (project): Code-layout drops roadmap; /boss gating
retargeted; Roles section rewritten with a new "Gitea issues"
bullet (URL + tea-CLI snippet) and the closes-#N trailer note.
- skills/boss/SKILL.md: 10 sites retargeted, plus Step 1 now
prescribes `tea issues ls --labels prio:p1` as the queue read.
- skills/brainstorm/SKILL.md: Step 7.5 no-override BLOCK now
files a Gitea issue via `tea issues create` instead of
appending a roadmap entry; spec deletion stays.
- skills/audit/SKILL.md + ailang-architect.md: deferral
requirement and debt-heuristic retargeted; forward-intent
belongs in the Gitea backlog.
- skills/fieldtest/SKILL.md, skills/docwriter/SKILL.md +
ailang-docwriter.md: roadmap → backlog.
- design/contracts/honesty-rule.md: forward intent lives in
the Gitea backlog (pinned phrases unchanged).
- design/INDEX.md: Docs bullet drops roadmap, adds the backlog
URL.
- crates/ailang-core/tests/docs_honesty_pin.rs: two assert
messages retargeted (assertion bodies unchanged).
- bench/architect_sweeps.sh: Sweep-4 TABU extended with
`docs/roadmap\.md` so the deleted path cannot quietly regrow
as a cross-reference in design/contracts/.
Verification:
- cargo build --workspace clean.
- cargo test --workspace: 647 passed, 0 failed, 2 ignored.
- bench/architect_sweeps.sh exit 0 (all five sweeps clean, incl.
new TABU).
- grep over the live tree (excluding docs/specs/, docs/plans/)
shows zero residual docs/roadmap.md refs.
Not touched: ~55 historical files under docs/specs/ and
docs/plans/ that mention docs/roadmap.md. Snapshot-character,
analogous to the JOURNAL-cut precedent — historical specs are
not mass-edited just because a live file was retired; their
mentions were correct at write time.
A re-grep found 15 live references (excluding docs/specs/ and
docs/plans/, which stay historical) the previous two commits
missed — all in source comments, doctests, bench helpers, and one
agent file.
Per-file:
- crates/ail/src/main.rs: typeclass-coherence diagnostic comment
pointed at "the JOURNAL queue's wording" — points at
design/contracts/typeclasses.md alone.
- crates/ailang-prose/src/lib.rs: `//!` header referred to
docs/JOURNAL.md "Pinned: human-readable prose surface" —
retargeted to design/contracts/authoring-surface.md.
- crates/ailang-check/src/lib.rs: bugfix tag + "see iter
method-dispatch-refactor journal" prose collapsed to a clean
rationale paragraph; the canonical shape is stated inline.
- crates/ailang-surface/tests/prelude_decouple_carve_out_pin.rs:
"(d) record the rationale in a per-iter journal" →
"(d) record the rationale in the commit body".
- crates/ailang-surface/tests/prelude_module_hash_pin.rs: header
collapsed (pd.2/pd.3 milestone narrative dropped — the test's
purpose is self-evident from its body); both "per-iter journal"
drift-instructions point at the commit body.
- runtime/rc.c: "bench numbers in JOURNAL 18f.2" →
"original profiling bench numbers".
- bench/run.sh: two "JOURNAL entry" comments → "commit body".
- bench/architect_sweeps.sh: header rewritten (cross-ref to the
design-md-consolidation milestone commits, not a JOURNAL entry).
Sweep-4 extended with two new anti-regrowth phrases
("see the per-iter journal", "in a per-iter journal") so journal
prose can't grow back into design/contracts/ silently.
- skills/audit/agents/ailang-architect.md: "unlike a journal it
lives on main" → "since it lives on main".
- ail-embed/src/bin/timeshard_runner.rs: "records it in the
close-out journal" → "prints it to stderr".
- ail-embed/tests/timeshard.rs: two "journal-only friction timing"
→ "stderr-only friction timing".
Verification (after the edit):
- `grep -rin '\bjournal\b'` against live tree returns exactly two
hits: the Sweep-4 regex itself (intentional — TABU phrases that
prevent regrowth) and the PHRASES array in design_index_pin.rs
(intentional — the same regrowth guard at test level). Both are
load-bearing negative assertions.
- `bash bench/architect_sweeps.sh` exits 0 ("All five sweeps
clean") — no design/-side regrowth.
- `cargo build --workspace` green; `cargo test --workspace` green.
Strict application of the "Future-Use, not Verlauf" criterion to the
two remaining journal artefacts:
- `docs/journals/` (110 files): the per-iter and audit journals from
2026-05-11 onward. Pure history; no live reader after the previous
sweep. Entire directory removed.
- `docs/journals/2026-05-19-design-decision-records.md`: the one file
that had live readers (`docs_honesty_pin.rs:108`, `parse.rs:80`,
`duplicate_ctor_pin.rs:8`, three roadmap.md mentions) and was framed
as a "relitigation guard". On re-examination its three asserted
pinned phrases ("Regions were considered and rejected", the
"demands annotations *because*" rationale, the prose-render
placeholder statement) are rationale-prose, not load-bearing
invariants — the test pinned itself, not a system property. Any
Decision that still holds lives in the code, `design/contracts/`,
or `design/models/`. Removed with the rest.
- `docs/journal-archive.md` (pre-2026-05-11 history): content-frozen
long-tail history with no live reader. Removed; if anyone ever
needs the pre-cutoff rationale they can `git log --before=2026-05-11
--grep=<keyword>`.
Live-file consequences:
- `docs_honesty_pin.rs` `design_md_present_tense_anchors_present`:
the three `records.*` assertions and the `read("docs/journals/…")`
are dropped; the contract/model anchor pins remain.
- `duplicate_ctor_pin.rs`: the "why-two-overlays rationale lives in
docs/journals/…" comment is replaced with the rationale inline.
- `parse.rs`: the "form-refinement rationale lives in docs/journals/…"
comment is dropped (the rule body already states the refinement).
- `roadmap.md`: the decision-records mention in the DESIGN.md →
design/ entry's body is dropped; the journal-archive.md `context:`
pointers across ~12 closed entries are either rephrased to point
at the relevant iter/audit (no path), or simplified to a one-line
comment when the iter name alone carries the story.
- `CLAUDE.md` Roles section: the `docs/journal-archive.md` slot is
removed; vocabulary note rephrased.
- `design/INDEX.md`: the Docs bullet drops `journal-archive.md`.
- `skills/README.md` bootstrap-rationale pointer rephrased.
`docs/specs/` and `docs/plans/` (per-milestone specs and per-iteration
plans) are unaffected — they remain the structured-design artefacts
they were before this sweep.
Workspace builds, full test suite green.
The per-iter journal under docs/journals/ duplicated the iter commit
body's substance and accumulated as Verlauf-Doku with no Future-Use.
Sweep across all live control documents: CLAUDE.md, the 7 SKILL.md
files, the 11 agent files, design/INDEX.md and the contracts/models
that referenced journals, docs/roadmap.md, and the handful of source
comments + tests that pointed at journal files for rationale.
Mechanism changes:
- Standing-reading-lists in every agent now read `git log -N --format=full`
for recent project state, never per-iter journal files. The architect
reads `git log <prev-milestone-close>..HEAD --format=full` for audit
scope.
- implement-orchestrator no longer writes a journal file. DONE outcomes
emit just code + stats; the end-report is the per-task summary the
Boss uses to write the commit body. PARTIAL/BLOCKED outcomes emit
BLOCKED.md at the repo root — uncommitted by convention, Boss removes
on repair or discard. New iron-law line + four-rationalisation row
+ red-flag bullet codify it.
- audit ratify mechanic: --update-baseline is now paired with an explicit
ratify paragraph in the audit-close commit body, not a separate
JOURNAL ratify entry.
- design/contracts/honesty-rule.md: "history and rationale lives in
docs/journals/" → "lives in git log (iter and audit commit bodies)".
Pinned phrase preserved verbatim.
- CLAUDE.md "Roles of …" section reframed: design/, git log,
journal-archive.md (content-frozen), roadmap.md, specs/, plans/.
No docs/journals/ slot anymore.
- roadmap.md context-lines that pointed at per-iter journals are
dropped where the spec/commit already carries the rationale, or
rephrased to "shipped in the <iter> iter commit" / "docs/journal-
archive.md (<date> entry)" for pre-2026-05-11 references.
What stays (this commit):
- docs/journals/ directory and contents are NOT touched. Removing the
contents is a separate follow-up.
- docs/journals/2026-05-19-design-decision-records.md still has live
readers (docs_honesty_pin.rs Z 108 + parse.rs + duplicate_ctor_pin.rs
+ 3 roadmap mentions) — also follow-up.
- docs/journal-archive.md still exists; its self-pointer header has
been updated to drop the "see docs/journals/INDEX.md" mention.
Workspace builds, full test suite green.
WhatsNew.md duplicated the Notify text into a file the only reader
(the user) does not consult. Removed the file and trimmed every
reference in the live control docs (CLAUDE.md, skills/boss,
skills/implement). The editorial rules (no internals,
telegram-pragmatic, factual) are preserved in skills/boss as
notify-text discipline. Historical specs/plans/journals are not
rewritten — they show the contemporaneous state.
Gate-first TDD: widened design_index_pin.rs clause-3 to a hand-rolled
FAITHFUL Sweep-1 superset (case-sensitive digit-anchored line anchors
+ Sweep-1's ^[^/]* path-excluded date + the audit-named
decision-record phrases, case-insensitive); no regex dep; the blanket
iter-detector rejected as unworkable. Sentence-level strip of
faithfully-migrated history/decision-record prose out of 5 contract
files (the audit's 3 spot-checked + roundtrip-invariant.md +
data-model.md the exhaustive scan found) into the decision-record
journal, each replaced by its present-tense contract equivalent;
float-semantics.md stale 'see Str ABI below' -> str-abi.md;
architect_sweeps honesty sweeps re-scoped to design/contracts only
(models/ is the narrative tier) + ailang-architect.md lockstep.
Invariant: clause-3 GREEN => Sweep-1 clean in contracts/.
The prior dispatch correctly BLOCKED on a real plan defect (iso_date
lacked Sweep-1's path-exclusion, over-firing on legit
docs/specs/2026-.. citations); per the two+-defects-in-one-iteration
discipline the audit Resolution mechanism+scope were corrected
upstream in lockstep (f2cdd67) before re-dispatch, not patched a
third time.
Boss-verified independently: cargo test --workspace 646/0,
design_index_pin 4/4 (clause-3 RED->GREEN), architect_sweeps.sh exit
0 'All five sweeps clean' (acceptance criterion 9 met), acceptance
grep CLEAN, 3 docs_honesty_pin pinned runs each exactly 1 contiguous
match. Zero spec/quality re-loops. FINAL design-md-rolesplit
iteration — milestone functionally complete, audited, drift-resolved,
hard gate enforces the honesty spirit.
The 3020-line docs/DESIGN.md is replaced by the design/ ledger:
design/INDEX.md (sole addressable spine, typed Contracts+Models tables,
polymorphic links — prose file OR authoritative source //!), 14
design/contracts/*.md test-linked invariants + 3 source-link-only
contracts (mangling/env-construction/qualified-xref, no prose file —
code is SoT), 5 design/models/*.md whitepapers, and
docs/journals/2026-05-19-design-decision-records.md (the
relitigation-guard archive — every why/rejected/does-not-do/rollback/
empirical ### moved out at ###-granularity). Clean cut: git rm
docs/DESIGN.md, no stub.
RED-first crates/ailang-core/tests/design_index_pin.rs — the 4-clause
anti-regrowth spine (DESIGN.md-gone / every-INDEX-link-resolves /
every-contract-names-a-resolvable-ratifier /
contracts-carry-no-decision-record-prose) — demonstrably RED before,
GREEN after. Build-atomic by task ordering: design_schema_drift.rs's
include_str! (the only compile-time consumer) retargeted to
design/contracts/data-model.md BEFORE the deletion; its
## Data model/## Pipeline slicer dropped (a simplification the split
enables). 2 NoInstance diagnostics + 2 lockstep E2Es retargeted to
design/contracts/{float-semantics,typeclasses}.md. ~12 agent reading
lists + 5 SKILL bodies + CLAUDE.md + skills/README.md + ~25
code/C/.ail/spec comment xrefs retargeted; OQ7 dangling 'Iter 13b'
cite deleted (no forward target — a pointer would be fiction).
honesty-rule.md rewritten so the rule names the new home
(rationale->journals), resolving the recon-found internal
contradiction; the two docs_honesty_pin.rs:70,72 pinned phrases kept
verbatim+contiguous.
Boss-verified independently: cargo test --workspace 646 passed /
0 failed; design_index_pin 4/4; acceptance grep CLEAN of live
DESIGN.md refs (residuals = only the spec-mandated clause-4
deletion-enforcer). 2 DONE_WITH_CONCERNS routed to the mandatory
milestone-close audit: (a) str-abi.md:23 '(iter str-concat,
2026-05-13)' provenance stamp trips advisory architect_sweeps Sweep-1
— Boss-confirmed byte-identical to DESIGN.md@deeffb1:2062-2065, a
faithfully-migrated PRE-EXISTING anchor (regexes verbatim, only path
retargeted), NOT split-introduced — RATIFY-or-tidy at audit; (b) a
now stale-direction intra-prose 'see Str ABI below' cross-ref in
float-semantics.md — audit-adjudication candidate. Plan defect noted:
Task 9 Step 4's verbatim acceptance grep used a ^./ anchor not
matching the system's grep -rIn output; substance re-verified CLEAN.
Spec grounding-check PASS x2. Journals INDEX + decision-records
pointer appended (Boss-only).
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.
Second of three iterations of the standalone loop/recur milestone
(plan 5ac57fe). Replaces the iter-1 synth CheckError::Internal stub
for Term::Loop/Term::Recur with real binder typing + positional
recur arity/type checking via a new loop_stack: &mut Vec<Vec<Type>>
frame threaded as mut.2's mut_scope_stack, a new private
verify_loop_body tail-position pass (sibling of the byte-frozen
verify_tail_positions — 0 deletions there), and the four Recur*
diagnostics firing point-exactly on four negative fixtures. The
iter-1 loop_sum_to.ail fixture now also typechecks clean; an
infinite loop typechecks (no termination claim). NO codegen (the
iter-1 lower_term stub stays — iter 3); NO Diverge/guardedness
(spec boundary).
Three Boss design calls implemented verbatim and journalled:
RecurTypeMismatch is an Assign-style structural pre-check (not a
unify-propagate); loop_stack is positional Vec<Type> (binder names
via ordinary locals); diagnostic-code precedence is by pass
ordering (no explicit logic).
Two DONE_WITH_CONCERNS, both journalled: a plan-ordering defect
(Task 2's compile gate forced the check_fn threading the plan
deferred to Task 4 — resolved byte-identically, only resequenced)
and the recurring mut.2-class recon-undercount of cross-module
synth callers (resolved via the plan's compile-sweep oracle).
Boss systemic fix folded in: planner SKILL.md Step-5 gains item 7
(compile-gate vs. deferred-caller ordering) so the plan-ordering
defect class is scrubbed at plan time. cargo test --workspace
608 -> 616 / 0 red (Boss-reran independently).
Recurring-class plan defect, now twice (iter-revert Concern 2;
iter effect-doc-honesty Task 2): a presence-pin asserts a
single-line contains()/grep substring while the verbatim
replacement body that must contain it soft-wraps the substring
across two lines — two authoritative artefacts that cannot both
be applied literally. The implementer absorbs it (preserve
wording + pin, move the wrap column) but it is a planner
self-review miss, not an implementer judgement call. Add an
explicit Step-5 checklist item so plans pairing a presence-pin
with a verbatim text edit are scrubbed before handoff.
The effect-op-arg-modes brainstorm spec bundled a real, self-contained
DESIGN.md honesty fix with speculative build-ahead infra (an EffectOpSig
arg-mode field whose only consumer was a synthetic test op). Recon had
already destroyed the "effect-handler infrastructure" premise: the effect
raise/declare/subset/propagation machinery is fully generic over any
effect string; the only real prerequisite was one struct field, not a
milestone. The user rejected the bundle as incoherent and the
build-ahead half as the iteration-discipline trap repeated.
- Retire the uncommitted effect-op-arg-modes spec (deleted from the
working tree; never committed).
- roadmap: drop the false "sub-ms-2 = effect-handler infrastructure"
framing; mark Stateful-islands sub-milestone sequencing as UNDER
RE-THINK with the user (no !Mut planning until that conversation);
add the split-out effect-doc-honesty as an in-flight P2 [~] todo.
- plan docs/plans/2026-05-16-effect-doc-honesty.md: placeholder-free
tidy plan (the three DESIGN.md fictions + form_a.md + main.rs +
a new doc-presence pin) over recon-mapped exact byte sites.
- brainstorm SKILL: specs and design talk LEAD with the AILang (.ail)
program that should work (= the feature-acceptance clause-1
evidence); the Rust implementation shape is secondary, never a
substitute; a no-surface infra milestone still shows concrete .ail
(often a must-fail fixture). Codifies user feedback from this session.
One forward iteration; main never rewound. 1ff7e81 (the pre-9973546
commit) is the per-region byte oracle — every reverted source/test
file is byte-identical to it; crates/ailang-check/src/lib.rs fully so.
Root cause being corrected: the Iteration-discipline milestone was an
over-escalation of fieldtest finding F1 (a [friction] item whose own
minimal recommendation was a DESIGN.md note). Its totality dichotomy
made the maximally-LLM-natural build(d:Int)=Node(1,build(d-1),
build(d-1)) inexpressible (it.3 BLOCKED); the only in-thesis escape
(A1/it.2b) conceded the language's first documented-unenforced
totality precondition — a purity-pillar dilution the user rejected in
favour of a full revert + rebuild.
Removed: Term::Loop/Term::Recur/LoopBinder; the verify_structural_
recursion guardedness pass + term_contains_loop + Diverge-injection +
the transitively-it.2 module_fns plumbing; the five Recur*/
NonStructuralRecursion CheckError variants (+ code() + the 3 dedicated
ctx() arms); the it.1 codegen loop-header/phi/back-edge + parallel
block_terminated setter; all Loop/Recur walker arms; 16 it.1/it.2
fixtures; 2 pin files; bench/it3-oracle/. Restored: 2 RC fixtures to
1ff7e81 content.
Surgically kept (not in 1ff7e81, landed with the milestone but
independently sound): feature-acceptance clause 3 in DESIGN.md and
skills/brainstorm/SKILL.md, with its worked example de-claimed from
"shipped" to hypothetical-illustration form; the F3 P2 todo.
bench/orchestrator-stats/2026-05-15-iter-it.{1,2,3}.json kept as
historical record (like journals/plans).
Sole net addition: an honest F1/F4 documented-idiom note in DESIGN.md
(the tail-recursive accumulator fallback; examples/mut_counter.ail),
guarded by a doc-presence test — "a documentation note is not a
reshape", asserts nothing at the typecheck level.
Roadmap: the Iteration-discipline block + blocking-fork section
removed; the genuine total-Int-recursion ambition preserved as a
deferred P2 milestone sequenced behind a future Nat/refinement-types
milestone (not abandoned — correctly sequenced after the type
machinery it needs). 2026-05-15-iteration-discipline.md carries a
superseded header; it.1/it.2/it.3 journals + plans stay as history.
Correctness gate PRISTINE: 164 surviving 1ff7e81-era fixtures
ail check/ail run byte-identical to pre-milestone behaviour (verified
against a 1ff7e81 worktree reference compiler, zero drift);
cargo test --workspace 600/0; zero residual it.1/it.2 production
surface.
Spec docs/specs/2026-05-16-iteration-discipline-revert.md (b3853bf),
plan docs/plans/2026-05-16-iter-revert.md (abf0013).
Sharpen the feature-acceptance criterion (DESIGN.md, mirrored in the
brainstorm gate) with a third conjunctive-necessary clause: a feature
reintroduces no bug class the core constraint exists to eliminate.
Criterion 1 ("an LLM reaches for it") does not discriminate — an LLM
reaches for every construct native to its imperative training
distribution, so utility alone would launder the imperative paradigm
back in one construct at a time. Clause 3 is the discriminator; a
documentation note is not a reshape (the gate is whether the wrong
code fails to typecheck).
Record the decided iteration story as a P1 milestone: structural
recursion permitted (total-by-construction under Decision 10's
acyclic-ADT invariant) + named loop/recur as the only other
repetition + tail-app retired. Discharges fieldtest finding F1 without
introducing an imperative construct; closes the residual "forgot to
mark tail" trap completely; unifies with Decision 10 (acyclic values
AND acyclic implicit call graph). Supersedes the "while-loops legal"
scope bullet of the Stateful-islands milestone, which is amended for
internal consistency. The escaping-state path (ref/MutArray/Stateful)
is unaffected and stays in Stateful-islands.
Boss-dispatched fieldtest at milestone close. Agent authored 4 .ail
fixtures (factorial smoke + Show user-ADT + user-class Describe with
two instances + two-module workspace) from DESIGN.md + form_a.md only
(no compiler-source reads, no spec-of-milestone reads). All four
fixtures `ail check` ok and `ail run` produces expected stdout.
Findings (1 bug, 1 friction, 2 spec_gaps, 3 working):
- [bug] instance-method-body unbound-var bypasses `ail check` —
forma_3 first attempt called `str_concat` inside the instance
method body; `ail check` returned ok, `ail build` died with the
monomorphise_workspace "unknown identifier" diagnostic. Same
shape at fn-body level correctly fires `[unbound-var]` at check
time. Next: debug skill, RED-first against `ail check`.
- [friction] no `str_concat` primitive. Every realistic Show MyType
body wants string concatenation; the absence forced the agent to
shape examples around bare int_to_str / ctor-arity-1 patterns.
Next: small planner tidy iter wiring `str_concat` symmetric to
`str_clone` and `int_to_str`.
- [spec_gap] form_a.md has zero references to class, instance,
constraint, or method productions — pre-22 surface only. The
form-a-default-authoring milestone made .ail the authoring form,
but the form_a spec doc remains pre-typeclass.
- [spec_gap] form_a.md leaves the class-qualifier ambiguity in
`(instance (class X))` unspecified — bare-class-name vs canonical-
form rule from mq.1 is not documented at the surface level. The
agent picked the bare-name reading from the corpus; the canonical-
form reading is equally plausible from the schema.
Boss-side cleanup at commit time:
- Deleted 8 stale .ail.json sidecars in examples/fieldtest/ (4
forma_* derived by the fieldtester per old dual-form workflow + 4
pre-existing floats_* from the prior fieldtest milestone that
iter form-a.1 T8 missed because the bash deletion loop globbed
only examples/*.ail.json direct children).
- Updated skills/fieldtest/agents/ailang-fieldtester.md to remove
the now-obsolete "generate canonical JSON sidecar" step (Phase 3
rewritten + Iron Law + Reading list + Common Rationalisations +
Red Flags all aligned to the post-form-a single-form doctrine).
cargo test --workspace: 557 passed, 0 failed, 3 ignored (unchanged
from audit-form-a — the fieldtest fixtures are standalone, not
referenced by any test).
Findings deferred to follow-up iters; the milestone close itself is
still clean.
Cross-milestone hops are high-context work and I cannot compact my own
context window. Adding a `brainstorm`-on-an-unspec'd-roadmap-item rule
that forces a bounce-back lets the user decide whether the next
milestone wants a fresh session or a continuation of the current one,
instead of consuming tens of thousands of tokens on a fresh spec Q&A
on top of whatever the just-closed milestone left behind.
Mechanics: Iron Law gains a fourth clause; Direction-Freedom-Bouncebacks
list a fourth trigger with the rationale spelled out; Step 3 reroutes
"new milestone → brainstorm" through the trigger; Problem-state
notification list, Common Rationalisations, and Red Flags all gain
the corresponding entries.
The surface-form file extension changes from .ailx to .ail. AILang's
authoring surface now uses the same .ail stem as its canonical JSON
form (.ail.json), giving the language a single coherent extension
family: .ail is the LLM-authored Form A, .ail.json is the canonical
JSON-AST Form B.
Scope (touched):
- 61 example renames examples/**/*.ailx → .ail (git mv)
- 1 rename experiments/.../rendered/ailx.md → ail.md
- 35 content-edited live-toolchain files (crates/, docs/DESIGN.md,
docs/roadmap.md, docs/PROSE_ROUNDTRIP.md, skills/, bench/reference/*.c,
experiment crates under experiments/.../{render,harness,master})
- Experiment-crate cohort rename Cohort::Ailx → Cohort::Ail,
Form::Ailx → Form::Ail, per_cohort/ailx → per_cohort/ail,
{form-only: ailx} → {form-only: ail}, ```ailx → ```ail
Out of scope (deliberately untouched, to preserve honest history):
- docs/journal-archive.md (content-frozen per CLAUDE.md)
- docs/journals/, docs/specs/, docs/plans/, bench/orchestrator-stats/
- experiments/.../runs/ (frozen LLM-output artefacts; models actually
saw .ailx — renaming would falsify the experimental record)
Verification: cargo build/test --workspace green; experiment crate
cargo test green; bench/check.py + compile_check.py + cross_lang.py
all 0-regressed; negative grep for ailx|Ailx|AILX outside the
out-of-scope paths returns zero matches.
Opens immediate follow-up: roadmap.md P2 todo `ail check`/build/run
accept .ail extension — after this rename, .ail is canonical
authoring surface but the CLI still produces a misleading JSON-parse
error on `ail check foo.ail`. That's the next iter.
CLAUDE.md previously mixed universal facts (agent role boundaries,
commit discipline, design rationale, file roles, TDD-for-bugs) with
mode-specific autonomy rules (direction freedom, notifications,
WhatsNew procedure). Autonomous-by-default conflicted with the user's
intent that a fresh session should be collaborative-interactive unless
explicitly elevated.
Add `skills/boss/` containing only the three genuinely mode-specific
subsections — Direction freedom, Notifications, Done-state notifications:
WhatsNew.md. Trim CLAUDE.md from 343 to 243 lines; extend the skill-
system pointer paragraph with a one-sentence /boss gate. Universal
orchestrator discipline stays in CLAUDE.md because it applies whether
/boss is active or not.
Two cross-references that named the moved subsections by sub-heading
are repointed: skills/implement/SKILL.md and the implement-orchestrator
agent's standing reading list. The other ~11 agent-file references to
"orchestrator framing" still resolve correctly because that framing
stays in CLAUDE.md.
skills/README.md skill table extended with a `boss` row (now eight
skills); pipeline-diagram caption notes /boss wraps the pipeline.
.claude/skills/boss symlink follows the existing relative-path
convention.
Closes the P1 todo from earlier today: Step 7.5 PASS report is
bound to the exact bytes of the spec at dispatch time. Any
subsequent edit — wording polish, user-requested change, anything
— invalidates the report and forces a fresh dispatch before the
Step 8 commit.
Three edits:
- Step 7.5 gets a 'Re-dispatch on any post-PASS edit' subsection
stating the rule and explaining why (PASS attests to bytes).
- Step 8 wording: '... edit in place, re-run Step 7 AND re-dispatch
Step 7.5, then return here. Only proceed after approval AND a
fresh Step 7.5 PASS.'
- Common Rationalisations + Red Flags gain matching entries
('just polishing wording, no need to re-dispatch' / 'Editing the
spec after PASS without re-dispatching').
Roadmap P1 todo retired with this commit.
Two project-wide rules are now explicit across every skill:
1. Only the Boss commits. No skill agent (implementer,
brainstormer, planner, debugger, fieldtester, docwriter,
architect, bencher) runs `git commit`. Agents write their
artefacts to the working tree as unstaged changes; the Boss
inspects, decides commit shape, and commits.
2. main HEAD is sacrosanct. No actor runs `git reset` or
`git revert` on main. Bad work stays in the working tree
where it is still discardable via `git checkout -- <paths>`.
Implement loses the `iter/<iter_id>` branch mechanic entirely;
Phase 0 of the orchestrator-agent now does a clean-tree check
and refuses to start on a dirty tree. Per-task agent commits
are removed everywhere; reviewers operate against
`git diff HEAD` instead of `pre_task_sha..head_sha`.
Motivation: 2026-05-11 iter 23.4 stranded prep2/prep3 commits on
an iter-branch that never integrated to main, then a corrected
spec falsely claimed those commits had shipped. Branch-per-iter
+ manual-Boss-merge + iter-stacking made the strand structurally
possible. See docs/journals/2026-05-11-iter-disc.1.md for the
full per-task notes and motivation.
The orchestrator-agent ends its run with the worktree on
iter/<iter_id>. Step 3 previously listed 'append INDEX line' as
item 3 and 'switch+merge' as item 4 — natural reading order is
top-to-bottom, so the INDEX append (and any other Boss edit) was
landing on the iter branch by mistake. Observed three times on
2026-05-11 during the iter 23.4 family's prep iters.
Fix: explicit warning at the top of Step 3, plus reorder so the
'git switch main && git merge --ff-only' happens before any
Boss-side edit. Summary rewrites (step 2's decision) now defer to
step 5, which runs after the switch, so they also land on main.
Claude Code categorically forbids subagents from spawning other
subagents (code.claude.com/docs/en/sub-agents and the Agent SDK
subagents page). The `or.1` architecture (and `pr.1` that ran on
top of it) presumed a named-exception for `ailang-implement-
orchestrator` to dispatch implementer / spec-reviewer / quality-
reviewer / tester per task. That exception never existed at the
platform level; the `Agent` tool was silently dropped from the
orchestrator-agent's tool set at dispatch time.
Architecture revised, doc-only:
- Per-task phases (implementer → spec-compliance check → quality
check) now run as sequential role-switches in the orchestrator-
agent's own context, not as nested subagents.
- The four role-files (implementer / spec-reviewer / quality-
reviewer / tester) become phase reference files the
orchestrator-agent consults at role-switch boundaries.
- Boss-context offload preserved; fresh-per-phase context given
up (the property that drove or.1's nested-dispatch design is
not buildable in Claude Code).
Files touched:
- skills/implement/agents/ailang-implement-orchestrator.md
(frontmatter, Iron Law, Phase 2/3 rewrite, rationalisations,
red flags)
- skills/implement/SKILL.md (frontmatter, Iron Law, sub-status
vocabulary note, cross-references)
- skills/README.md (Conventions: no more named exception; agent
roster: role-files recast as phase references)
- docs/journals/INDEX.md (or.2 entry appended)
- docs/journals/2026-05-11-iter-or.2.md (new — full rationale)
- docs/roadmap.md (P1 tool-wiring item removed; resolved as
categorically-not-fixable)
- docs/WhatsNew.md (user-facing correction entry appended)
No code changes; no bench impact; CLAUDE.md untouched (no stale
references to fix there).
The or.1 Iron Law said `git switch -c iter/<iter_id> origin/main`,
which silently presupposed that the plan-commit lives on origin/main.
The Boss commits plan+spec to local main and dispatches immediately
without pushing, so origin/main lags. The first real dispatch (pr.1)
hit this and worked around it by mid-flight ff-merging local main
into the iter branch — clean end-state but pure rationalisation
through a 'branch already exists' clause meant for repair re-dispatch.
The intent of branch-per-iter was iter-isolation from main, not
push-state coupling. Branch from local main; let push remain
orthogonal.
Touches Iron Law (twice — agent + SKILL.md), Phase 0 step
(orchestrator-agent), Boss-merge explanation (SKILL.md). Also drops
the now-obsolete `git fetch origin main` Phase 0 prelude.
Recorded in docs/journals/2026-05-11-iter-pr.1.md Boss-side addendum;
this commit closes the first follow-up item from that addendum.