# 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
