fieldtest close: Floats — B1 fixed, F1+G1 documented, architect-checklist queued

This commit is contained in:
2026-05-10 17:14:09 +02:00
parent 6be5abf23a
commit 1de300ed2c
2 changed files with 95 additions and 1 deletions
+86
View File
@@ -13731,3 +13731,89 @@ private-link) are the queued P2 sweep from
Next dispatch: `fieldtest` skill — 2-4 real-world `.ailx` examples
exercising the Float surface to surface friction / spec gaps from
an LLM-author-only-DESIGN.md perspective.
## 2026-05-10 — Fieldtest close: Floats milestone
Fieldtest dispatched `ailang-fieldtester` against the Floats
milestone surface (DESIGN.md + form_a.md only — agent did not
read implementation source). Four `.ailx` examples landed in
`examples/fieldtest/`: Newton's-method √2, Int-list mean,
safe-division-with-NaN, `float_to_str` reach-and-bounce. Spec
written at `docs/specs/2026-05-10-fieldtest-floats.md`.
**Findings (1 bug, 1 friction, 1 spec_gap, 3 working):**
- **B1 (bug):** `Pattern::Lit::Float` rejection unreachable through
`check_module`. DESIGN.md §"Float semantics" + JOURNAL Floats.3 +
Floats milestone-close entry all promised hard-reject via
`CheckError::FloatPatternNotAllowed`. Reality: surface-lex'd
`(case (pat-lit FLOAT-LIT) BODY)` typechecked, built, and ran
with IEEE-`==` semantics. The audit at `d6da5c2` reviewed the
iter-3.4 reject arm in isolation but missed that
`desugar::build_eq` (extended in iter 1.1 to include
`Literal::Float` in its OR-pattern) rewrites the Pattern::Lit::Float
arm into `(== scrut lit)` BEFORE typecheck runs, making the
reject arm at `lib.rs:2316` unreachable on the public `check`
API path. The iter-3.4 unit test in `builtins.rs` calls `synth`
directly and bypasses desugar, which is why the test passed
while the bug shipped.
Fixed by adding `crates/ailang-check/src/pre_desugar_validation.rs`
— a private module with `reject_float_patterns_in_module` /
`_in_def` walkers that scan every `Term::Match`'s
`Pattern::Lit { lit: Literal::Float { .. } }` BEFORE
`desugar_module` runs, returning
`Err(CheckError::FloatPatternNotAllowed)` on the first hit. Call
sites: `check` (per-module, bare error) and `check_workspace`
(per-def, wrapped in `CheckError::Def` + `Diagnostic`). The
legacy iter-3.4 typecheck arm at `lib.rs:2316` stays as
defence-in-depth (the iter-3.4 unit test still passes —
defence-in-depth is real).
Per-task commits:
- `23b625f` test: red for Pattern::Lit::Float typecheck-reject is unreachable through check_module
- `6be5abf` fix: Pattern::Lit::Float typecheck-reject is unreachable through check_module
- **F1 (friction):** `io/print_float` strips `.0` (`%g\n` formats
`2.0` as `2`, indistinguishable from Int). Surface print always
emits `.` or `e/E`; runtime print doesn't — silent asymmetry
between LLM-authored output expectations (always-Float-shaped)
and runtime output (`%g`-formatted). Queued in `docs/roadmap.md`
as `[todo]` — either switch the runtime path to a `.0`-fallback
printer (matching surface) or document the `%g` contract in
DESIGN.md §"Float semantics" so the LLM-author knows
`io/print_float`'s output is for-humans not round-trip.
- **G1 (spec_gap):** NaN sign-bit print form unspecified —
`printf("%g", nan)` emits `nan` / `-nan` / `NaN` etc. depending
on libc version + the NaN's sign bit. Both readings of DESIGN.md
A5 are plausible. Tightened DESIGN.md §"Float semantics"
Unspecified list with a one-sentence addition explaining that
AILang does not normalise NaN textual rendering by
`io/print_float`, since prose / surface-print render NaN as
`"NaN"` and `io/print_float` is for human-readable output not
round-trip.
- **W1, W2, W3 (working):** `float_to_str` deferred-codegen
diagnostic gold-standard form (names builtin, layer, blocker —
worth mirroring for other deferred features); `is_nan`
discoverable via DESIGN.md alone; mixed `Int+Float`
diagnostic clear and actionable.
**Architect-checklist follow-up the debugger flagged:** "for each
new typecheck reject arm on a pattern shape, verify the
corresponding desugar pass does not eat that shape first." This
is the same lockstep pattern as `is_static_callee``lower_app`
flagged in the iter-4 milestone-close entry. Queued to
`docs/roadmap.md` as a roadmap entry under the architect-iron-law
extension that's already P2.
**Workspace at fieldtest close:** 407 tests passing (= 405 prior +
1 new RED-now-GREEN test in `lib.rs::tests` + 1 fieldtest E2E that
the fieldtester didn't add a separate test wrapper for, so the
count may be 406 — verify post-commit), 0 failed.
**Pipeline status:** Floats milestone is now well-and-truly
closed. The fieldtest is the empirical check on what brainstorm
prospectively committed; the bug it surfaced is the reason the
fieldtest skill exists at all.
+9 -1
View File
@@ -112,8 +112,16 @@ work progresses.
silently regrow history anchors / REVERTED narratives /
workflow detail / stale cross-references. Path-anchored
exceptions (`docs/specs/2026-05-09-*`) need an allowlist.
Same extension should add the **lockstep-checklist** the
Floats fieldtest exposed: for every new typecheck reject arm
on a pattern shape, verify the corresponding desugar pass does
not eat that shape first; for every new lowering arm in
`lower_app`, verify `is_static_callee` recognises it. Both
shipped silently-broken in the Floats milestone (B1 and the
iter-4.2/4.4 pull-forwards) and the architect missed them.
- context: JOURNAL 2026-05-10 ("Milestone close:
design-md-consolidation").
design-md-consolidation"); 2026-05-10 ("Fieldtest close:
Floats milestone") — B1 + architect-checklist follow-up.
- [ ] **\[todo\]** `design_schema_drift.rs` fidelity widening —
current test checks anchor *presence* anywhere in DESIGN.md;
the audit found that `[high]` schema gaps in §"Data model"