# iter prose-loop-binders.1 — Form-B `loop` renders binders as a parenthesised init-list on the keyword **Date:** 2026-05-18 **Started from:** 6533134dab888605c24fb2e50a65fcbf99c1897e **Status:** DONE **Tasks completed:** 2 of 2 ## Summary Projection-only single-iteration milestone in `ailang-prose`. The `Term::Loop` arm of `write_term` (`crates/ailang-prose/src/lib.rs`) now renders loop binders as a parenthesised init-list on the keyword line — `loop(acc = 0, i = 1) { … }` — instead of bare `name = init;` statements inside the body block. The old shape implied C/Rust re-init-every-iteration semantics; the new shape mirrors the adjacent (untouched) `Term::Recur` arm's `enumerate()` + `", "`-separator idiom and renders init expressions at `level` (they sit on the keyword line, not the indented block). RED-first: two committed `examples/*.prose.txt` snapshot fixtures plus two `check_snapshot`-calling `#[test]` fns were added and verified failing against the old renderer before the arm rewrite made them pass. Loop/recur AST, Form-A, JSON-AST, typecheck, codegen and the Form-A↔JSON round-trip invariant are untouched by construction (single render-arm body rewrite, no signature change, no caller touched). ## Per-task notes - iter prose-loop-binders.1.1: RED — created `examples/loop_sum_to_run.prose.txt` (multi-binder + non-recur exit) and `examples/loop_forever_build.prose.txt` (single-binder recur-only) with the exact Option-A bytes from the plan; appended `snapshot_loop_sum_to_run` + `snapshot_loop_forever_build` after `snapshot_ordering_match` in `tests/snapshot.rs`. `cargo test -p ailang-prose snapshot_loop` → `0 passed; 2 failed; 8 filtered out` (filter resolved to exactly the two new tests; both panic with the expected `prose snapshot mismatch` message). RED confirmed. - iter prose-loop-binders.1.2: GREEN — rewrote the `Term::Loop` arm at `lib.rs:938-955` verbatim per the plan (parenthesised init-list, init at `level`, stale "not yet designed" comment removed). `cargo test -p ailang-prose snapshot_loop` → `2 passed; 0 failed`; full `ailang-prose` suite → `10 passed; 0 failed` (no pre-existing snapshot regressed); both `ail prose | diff` CLI byte-matches → `MATCH`; post-cleanup `git status --porcelain` is EXACTLY the four expected paths. ## Concerns (none) ## Known debt (none — projection-only single-arm rewrite, fully gated by whole-file byte-equality snapshots + live-CLI diff) ## Files touched - `crates/ailang-prose/src/lib.rs` — `Term::Loop` arm of `write_term` rewritten (single hunk, lines 938-953) - `crates/ailang-prose/tests/snapshot.rs` — two `#[test]` fns appended after `snapshot_ordering_match` - `examples/loop_sum_to_run.prose.txt` — new committed snapshot - `examples/loop_forever_build.prose.txt` — new committed snapshot ## Blocked detail (n/a — Status DONE) ## Stats bench/orchestrator-stats/2026-05-18-iter-prose-loop-binders.1.json