Skip to content

#617 M2: expose takeFlatMap/takeMap on std/list, and give the .ail suites a CI gate they never had - #668

Merged
sunholo-voight-kampff merged 1 commit into
devfrom
sprint/iter183-take-flatmap-m2
Aug 12, 2026
Merged

#617 M2: expose takeFlatMap/takeMap on std/list, and give the .ail suites a CI gate they never had#668
sunholo-voight-kampff merged 1 commit into
devfrom
sprint/iter183-take-flatmap-m2

Conversation

@sunholo-voight-kampff

Copy link
Copy Markdown
Collaborator

M2 of M-TAKE-FLATMAP-PEAK-MEMORY (#617). Closes AC-1, AC-2 (.ail half), AC-3a, AC-4.
Design doc + sprint plan: design_docs/planned/m-take-flatmap-peak-memory*.md. M1 landed in #661.

What ships

  • std/list.ailtakeFlatMap / takeMap exports delegating to the fused builtins, placed before the effectful section. Doc comments carry the corrected cost model (peak = source residency + largest single f(x) + n retained) and state plainly that neither bounds peak by n; what they bound is how many inputs f is invoked on.
  • examples/runnable/bounded_take_flatmap.ail + manifest entry, expected.stdout taken from the file's own run.
  • tests/stdlib/ — parity suite (n=0, n>total, empty inner lists, dedup∘takeFlatMap) and the delegation instrument: takeFlatMap(4, boom, [1,2,3,4,5]) exits 0 and prints [1, 1, 2, 2] only because f never runs on the input that divides by zero.

The delegation instrument is the point. An export body written as take(n, flatMap(f, xs)) is output-identical and passes every equality test, so nothing but a divergence probe pins the export to the fused mechanism.

Controller finding: the pins had no gate

grep -rn "ailang test" make/ Makefile returned zero (control: .ail in make/ = 35, 28 targets in test.mk). No make target and no CI job ran any .ail suite, so AC-3a and AC-4 would have shipped as one-shot acceptance commands against a tree that no longer exists.

Added make test-stdlib-ail, wired into ci.yml, with an anti-vacuity floor on both loops — an empty glob fails loudly, since "no suites found" and "all suites green" are otherwise the same exit code. The .expected fixtures are captured from the product's own stdout and diffed against a verbatim re-run rather than reconstructed by the gate.

Verification (controller-run, outside the executor sandbox)

Mutation LANDED BUILDS/type-checks Result
Unfused export bodies (take(n, flatMap(f, xs))) sha256 ✓ ailang check rc=0 make test-stdlib-ail rc=2; delegation fixture dies panic: division by zero
len(result) >= n> n (takeFlatMapImpl) sha256 ✓ go build rc=0 parity suite rc=1, 2 genuine arms
len(result) < n<= n (takeMapImpl) sha256 ✓ go build rc=0 parity rc=1 + Go suite TestTakeMapBasic/TestTakeMapEarlyExit
Empty glob (anti-vacuity floor) n/a n/a rc=2, instrument failure

The two early-exit sites use different forms, so a single sed cannot reach both — each was mutated separately. All mutants restored byte-identical from cp backups.

Gates: go test ./internal/builtins ./internal/pipeline rc=0 · verify-examples rc=0 (188 modules, missing-on-disk held at the pre-existing 1) · lint, fmt-check, check-file-sizes, check-changelog rc=0.

Out of scope (M3/M4): limitations docs, prompt v0.16.6, footgun row, changelog, the LIST_TAKE_AFTER_FLATMAP diagnostic.

🤖 Generated with Claude Code

…uites a CI gate they never had

M2 of M-TAKE-FLATMAP-PEAK-MEMORY. Closes AC-1, AC-2 (.ail half), AC-3a, AC-4.

- std/list.ail: `takeFlatMap` / `takeMap` exports delegating to the fused builtins, placed
  before the effectful section. Doc comments carry the corrected cost model
  (peak = source residency + largest single f(x) + n retained) and say plainly that neither
  bounds peak by n — what they bound is how many inputs f is invoked on.
- examples/runnable/bounded_take_flatmap.ail + manifest entry, expected.stdout taken from the
  file's own run.
- tests/stdlib/: parity suite (n=0, n>total, empty inner lists, dedup composition) and the
  delegation instrument — takeFlatMap(4, boom, [1,2,3,4,5]) exits 0 and prints [1, 1, 2, 2]
  only because f never runs on the input that divides by zero.

The delegation instrument is the point: an export body written as `take(n, flatMap(f, xs))` is
output-identical and passes every equality test, so nothing but a divergence probe pins the
export to the fused mechanism.

CONTROLLER FINDING — the pins had no gate. `grep -rn "ailang test" make/ Makefile` returned
ZERO (control: `.ail` in make/ = 35; 28 targets in test.mk), so no make target and no CI job
ran any .ail suite. AC-3a and AC-4 would have shipped as one-shot acceptance commands against
a tree that no longer exists. Added `make test-stdlib-ail`, wired into ci.yml, with an
anti-vacuity floor on both loops — an empty glob fails loudly, since "no suites found" and
"all suites green" are otherwise the same exit code. The .expected fixtures are captured from
the product's own stdout and diffed against a verbatim re-run rather than reconstructed.

Non-vacuity, controller-run outside the sandbox: the unfused-body mutant LANDS (sha256) and
still TYPE-CHECKS (so the red is not a compile failure) and reds `make test-stdlib-ail` rc=2;
the empty-glob arm hits the floor rc=2. Off-by-one mutants at both early-exit sites
(`len(result) >= n` in takeFlatMapImpl, `len(result) < n` in takeMapImpl — two different
forms, so one sed cannot reach both) each LAND, BUILD (go build rc=0) and red the parity
suite. All mutants restored byte-identical from cp backups.

Gates (controller, outside sandbox): go test ./internal/builtins ./internal/pipeline rc=0;
verify-examples rc=0 (188 modules, missing-on-disk held at the pre-existing 1); lint,
fmt-check, check-file-sizes, check-changelog all rc=0.

Co-Authored-By: codex gpt-5.6-sol
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@sunholo-voight-kampff
sunholo-voight-kampff merged commit 6a67bb7 into dev Aug 12, 2026
21 checks passed
@sunholo-voight-kampff
sunholo-voight-kampff deleted the sprint/iter183-take-flatmap-m2 branch August 12, 2026 09:18
sunholo-voight-kampff added a commit that referenced this pull request Aug 12, 2026
…ral pin had no CI gate (#673)

Gate 4 record: charter STATUS 183 (+ rotation, iteration 180 archived), log entry 186,
dashboard rewritten at exactly 40 lines.

Rotation arithmetic asserted before writing: before=1918, after=1918, expected=1918
(before + 2 - 2*1). Rotation invariant 3. Post-edit queue-row check passed (queue header
present, 68 LANDED rows) — the STATUS block cannot show that damage.

The iteration's finding: `grep -rn "ailang test" make/ Makefile` returns ZERO (control `.ail`
in make/ = 35). No make target and no CI job ran ANY .ail suite, so #617 M2's AC-3a and AC-4
were one-shot acceptance commands against a tree that no longer exists. Fixed in #668 by
`make test-stdlib-ail` + a ci.yml step with anti-vacuity floors.

Two bugs filed from the drills rather than from the sprint:
- #669 `ailang test` reports FALSE FAILURES for a stdlib export delegating to another
  same-module AILANG export; three hypotheses refuted by measurement.
- #670 `expected.stdout` is display-only for all 194 examples; corrupting one leaves
  `make verify-examples` at rc=0.

Gate 3b GREEN on 6a67bb7 (SHA-addressed checks=16, zero NOT-GREEN). Evaluator sonnet
PASS 95/100 r1, zero blocking. metered=$0.00.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant