# iter 24.2 — Show class + 4 primitive instances + 22b TShow/tshow migration **Date:** 2026-05-13 **Started from:** 64cea0e **Status:** DONE **Tasks completed:** 8 of 8 ## Summary Ships `class Show a where show : (a borrow) -> Str` in `examples/prelude.ail.json` alongside primitive instances `Show Int`, `Show Bool`, `Show Str`, `Show Float`. Each instance body is a single-application lambda invoking the corresponding runtime primitive (`int_to_str`, `bool_to_str`, `str_clone`, `float_to_str`) — first prelude instance bodies to call runtime primitives directly (prior Eq/Ord bodies used operator + codegen intercept). The 22b typeclass test corpus migrates `class Show` / `show` → `class TShow` / `tshow` preemptively (Tasks 1–2 before Task 3 lands `prelude.Show`) so the workspace stays green throughout. Three new tests pin the post-mono shape: mono-synthesis existence (`show_mono_synthesis.rs`), dispatch singleton (`show_dispatch_pin.rs` × 2 cases), and body-hash stability (`mono_hash_stability.rs::primitive_show_mono_symbol_hashes_stay_bit_identical`). DESIGN.md §"Prelude (built-in) classes" gains a milestone-24 paragraph naming Show + instances + the Float caveat. `print`-rewire stays deferred to iter 24.3. ## Per-task notes - iter 24.2.1: Renamed `"Show"`/`"show"` → `"TShow"`/`"tshow"` across 21 `test_22b*_*.ail.json` fixture files; cross-module qualifier forms (`".Show"` → `".TShow"`) handled by regex in 3 fixtures (`test_22b1_dup_a`, `test_22b1_dup_b`, `test_22b1_orphan_third`). False-positive scan empty; fixture parse round-trip green. - iter 24.2.2: Renamed literals in `crates/ail/tests/typeclass_22b{2,3}.rs` (`"Show"` → `"TShow"`, `"show"` → `"tshow"`, `show__T` → `tshow__T`), including comment-prose forms (`` `Show` `` → `` `TShow` ``, `class Show` → `class TShow`, etc.) and one assertion-message string ("exactly one show__Int across the workspace" → "tshow__Int..."). Plan undercount surfaced: the rename touches more than the 2 named test files — see Concerns below. - iter 24.2.3: Inserted 5 new top-level defs into `examples/prelude.ail.json` immediately before `fn ne` (line 223 pre-edit). The `instance Show Str` body invokes `str_clone` as `Term::Var` — first prelude instance body to do so. Round-trip green; `primitive_eq_ord_mono_symbol_hashes_stay_bit_identical` stays green (Eq/Ord hashes unaffected by Show defs). - iter 24.2.4: New fixture `examples/show_mono_pin_smoke.ail.json` exercises `show 42`, `show true`, `show "x"`, `show 1.5` in a let-chain ending in `io/print_str s1`. New test `crates/ail/tests/show_mono_synthesis.rs::primitive_show_mono_symbols_synthesise` asserts `show__Int`/`show__Bool`/`show__Str`/`show__Float` materialise as `Def::Fn` entries in the `prelude` post-mono module. `str_clone` reachability in instance-lambda position verified implicitly: `show__Str` materialises, which means the lambda body's `Term::Var "str_clone"` resolved against the checker's builtin table during typecheck. - iter 24.2.5: New pin test `crates/ailang-check/tests/show_dispatch_pin.rs` asserts `env.method_to_candidate_classes["show"] == {"prelude.Show"}` (singleton) and `env.method_to_candidate_classes["tshow"] == {"*.TShow"}` (singleton). API spelled `build_check_env(&ws)` not `Env::from_workspace` (plan's placeholder name). 2/2 cases pass first-shot. - iter 24.2.6: Extended `crates/ail/tests/mono_hash_stability.rs` with a second test function `primitive_show_mono_symbol_hashes_stay_bit_identical` loading `show_mono_pin_smoke.ail.json` (kept separate from the Eq/Ord fixture to avoid coupling). Hashes captured first-run: `show__Int 891eaebe64b3180d`, `show__Bool 1bdb621494e50607`, `show__Str 3f1d57c90ddce081`, `show__Float 5ab0bdd40b9f8b8f`. - iter 24.2.7: DESIGN.md §"Prelude (built-in) classes" amended: milestone-23 paragraph drops "Show" from the deferred list and notes Show ships in milestone 24; new milestone-24 paragraph names class signature, instance set (including Float), body shape (single-app lambda invoking runtime primitive), and the iter-24.3 carry-forward for `print`-rewire. - iter 24.2.8: Workspace tests 552 passed / 0 failed (was 548 pre-iter, +4 new: 1 `show_mono_synthesis` + 2 `show_dispatch_pin` + 1 hash-stability). `bench/compile_check.py` exit 0 (24/24 stable). `bench/cross_lang.py` exit 0 (25/25 stable). `bench/check.py` exit 1 with 2 noise-class metrics (`bench_list_sum.bump_s` +11.71% — 4th consecutive sighting per `audit-mq` / `mq.tidy` lineage; `latency.implicit_at_rc.max_us` +145.55% — 7th consecutive sighting of the documented noise envelope, metric-identity-migrating across runs). Baseline pristine per the conservative-call convention. ## Concerns - **Plan undercount on 22b migration scope.** The plan's "2 Rust test files" carrier (typeclass_22b{2,3}.rs) missed 4 additional consumer sites that hardcode the renamed literals: (a) `crates/ailang-core/src/hash.rs` ct4 canonical-form hash pin (2 entries); (b) `crates/ailang-core/src/workspace.rs` 3 in-crate iter22b1 tests; (c) `crates/ailang-prose/tests/snapshot.rs` (1 snapshot file at `examples/test_22b2_instance_present.prose.txt`); (d) one `mono_symbol_compound_type_uses_hash_suffix` assertion in typeclass_22b3.rs that called `mono_symbol("tshow", ...)` (post my batch rename) but still asserted `name.starts_with("show__")`. All fixed inline per the precedent of mq.1 / mq.3 "Plan defects fixed inline" — fixture parse was the only "green" pre-iter signal the plan's Step 3/4 anchored on, which masked the broader downstream consumer surface. Suggested Boss-side reaction: future migration plans run an upfront `grep -rln '""' crates/` to enumerate the full consumer set before committing to a per-file enumeration. - **`str_clone` reachability is implicit.** Pre-flight note 3 flagged this as needing first-round-trip verification; verification is implicit in `primitive_show_mono_symbols_synthesise` passing (mono of `show 42 / true / "x" / 1.5` requires the four `show__T` bodies to typecheck, including the `str_clone` call in `show__Str`). No explicit isolated unit test for `str_clone`-in-lambda was added because the integration pin is strictly stronger; consider an isolated unit pin only if a future regression makes the integration test slow to bisect. - **Hash-stability pin uses a separate fixture, not the existing `mono_hash_pin_smoke.ail.json`.** Plan Task 6 offered both options; the separate-fixture path was chosen because `show_mono_pin_smoke.ail.json` already existed (minted in Task 4) and reusing it kept the Eq/Ord pin structurally isolated. Both fixtures live side-by-side; the second test function in `mono_hash_stability.rs` mirrors the first byte-for-byte modulo the fixture path and pin table. - **`bench/check.py` exit 1 is the documented recurring noise envelope.** `latency.implicit_at_rc.*` max-tail metric has been migrating between runs since `audit-cma` (2026-05-12) — 7th consecutive observation; `bench_list_sum.bump_s` is the 4th since `audit-mq`. Plan Task 8 Step 4 explicitly anticipates "1-3 regressed metrics ratify-without-attribution per conservative-call convention"; this iter follows that. The baseline stays pristine. ## Known debt - **iter 24.3 still pending.** Carries `print : forall a. Show a => a -> () !IO` rewire to route through `show` + `io/print_str`. Spec at `docs/specs/2026-05-13-24-show-print.md`. 24.2 is structurally complete; 24.3 is operationally distinct. - **mq1 cross-module fixtures unmigrated by design.** `examples/mq1_xmod_constraint_class.ail.json` and `..._dep.ail.json` reference `mq1_xmod_constraint_class_dep.Show` (cross-module, fully qualified) and ship zero `show` call sites; no dispatch ambiguity arises once `prelude.Show` lands. They stay as-is per the plan's pre-flight ratification. - **mq3 fixtures deliberately retain two-Show shapes.** `examples/mq3_two_show_*` fixtures test the multi-class dispatch scenarios (ambiguity + qualifier resolution) and stay unchanged in 24.2 by design. ## Files touched **Created (3):** - `crates/ail/tests/show_mono_synthesis.rs` - `crates/ailang-check/tests/show_dispatch_pin.rs` - `examples/show_mono_pin_smoke.ail.json` **Modified (29):** Prelude + DESIGN: - `examples/prelude.ail.json` (+5 defs) - `docs/DESIGN.md` (§"Prelude (built-in) classes" amendment) 22b fixture migration (21 files): - `examples/test_22b1_dup_a.ail.json` - `examples/test_22b1_dup_b.ail.json` - `examples/test_22b1_dup_classmod.ail.json` - `examples/test_22b1_dup_same_module.ail.json` - `examples/test_22b1_orphan_class.ail.json` - `examples/test_22b1_orphan_third.ail.json` - `examples/test_22b1_orphan_third_classmod.ail.json` - `examples/test_22b2_class_method_lookup.ail.json` - `examples/test_22b2_constraint_declared.ail.json` - `examples/test_22b2_instance_present.ail.json` - `examples/test_22b2_missing_constraint.ail.json` - `examples/test_22b2_no_instance.ail.json` - `examples/test_22b2_two_fns_missing_constraint.ail.json` - `examples/test_22b2_xmod_classmod.ail.json` - `examples/test_22b2_xmod_classmod_noinst.ail.json` - `examples/test_22b2_xmod_instance_present.ail.json` - `examples/test_22b2_xmod_missing_constraint.ail.json` - `examples/test_22b2_xmod_no_instance.ail.json` - `examples/test_22b3_dup_call_sites.ail.json` - `examples/test_22b3_no_call_sites.ail.json` - `examples/test_22b3_shadow_class_method.ail.json` 22b consumer-test migration (5 source files + 1 snapshot): - `crates/ail/tests/typeclass_22b2.rs` - `crates/ail/tests/typeclass_22b3.rs` - `crates/ailang-core/src/hash.rs` (ct4 hash pin) - `crates/ailang-core/src/workspace.rs` (3 iter22b1 tests) - `crates/ail/tests/mono_hash_stability.rs` (new show test fn) - `examples/test_22b2_instance_present.prose.txt` (snapshot accept) ## Stats `bench/orchestrator-stats/2026-05-13-iter-24.2.json`