# Testing This is the single source of truth for Vera's testing infrastructure, coverage data, and test conventions. ## Overview | Metric | Value | |--------|-------| | **Tests** | 12,290 across 181 files (~157,000 lines of test code; 12,091 passed + 26 stress-deselected, 173 skipped) | | **Compiler code coverage** | 95% Python, 87% JavaScript (CI minimum: 80%) | | **Conformance programs** | 244 programs across 9 spec chapters, validating every language feature | | **Example programs** | 43, all validated through `vera check` + `vera verify` | | **Spec code blocks** | 189 parseable blocks from 14 spec chapters: 92 parse, 86 type-check, 85 verify (the rest carry inline `vera:skip` annotations, #538) | | **README code blocks** | 4 Vera blocks (4 validated, 0 annotated) | | **FAQ code blocks** | 3 Vera blocks in FAQ.md (2 validated, 1 annotated snippet) | | **HTML code blocks** | 5 Vera blocks in docs/index.html (5 validated: parse + check + verify) | | **Contract verification** | 411 of 533 obligations (77.1%) across the 43 examples verified statically (Tier 1) — the denominator grew with the auto-synthesised primitive-op obligations of the soundness campaign | | **CI matrix** | 13 combinations (Python 3.11/3.12/3.13 × ubuntu-latest/macos-15/macos-26/windows-latest, plus an advisory ubuntu-24.04-arm × 3.12 cell) + browser parity (Node.js 22) + wheel-availability preflight | ## Running Tests All commands assume the virtual environment is active (`source .venv/bin/activate`). ```bash # Test suite pytest tests/ -v # full suite, verbose pytest tests/test_codegen_expressions.py # single file pytest tests/test_codegen_expressions.py::TestArithmetic # single class pytest tests/test_conformance.py -v # conformance suite only pytest tests/ --cov=vera --cov-report=term-missing # with coverage # JavaScript coverage (browser runtime) VERA_JS_COVERAGE=1 pytest tests/test_browser.py -v # V8 coverage via c8 # GC-rooting diagnostic (forces $gc_collect on every alloc, see ENVIRONMENT.md) VERA_EAGER_GC=1 pytest tests/test_codegen_closures.py::TestClosureReturnShadowPushBalance -v # Host-binding diagnostic (re-raises a host callback's own exception, see ENVIRONMENT.md). # The suite sets and unsets VERA_DEBUG_HOST_ERRORS itself, so run it without a prefix: pytest tests/test_runtime_traps.py::TestHostErrorDebugKnob1302 -v # Type checking mypy vera/ # strict mode # Validation scripts python scripts/check_conformance.py # conformance suite (244 programs, see manifest.json) python scripts/check_examples.py # 43 example programs python scripts/check_spec_examples.py # spec code blocks python scripts/check_readme_examples.py # README code blocks python scripts/check_skill_examples.py # SKILL.md code blocks python scripts/check_faq_examples.py # FAQ.md code blocks python scripts/check_pypi_readme_examples.py # PYPI_README.md code blocks (parse + check + verify) python scripts/check_html_examples.py # docs/index.html code blocks python scripts/check_version_sync.py # version consistency python scripts/check_wheel_availability.py # pre-flight: every runtime dep has wheels for all supported platforms (#691 backstop) ``` ## Test Files | File | Tests | Lines | What it covers | |------|------:|------:|----------------| | `test_parser.py` | 171 | 1370 | Grammar rules, operator precedence, parse errors | | `test_ast.py` | 138 | 1,145 | AST transformation, node structure, serialisation, string escape sequences, ability declarations | | `test_checker_types.py` | 249 | 3,830 | Primitive types, literals, binary/unary ops, generics, constructors, refinement types, arrays, tuples, zero-size container rejection (E135 for Map/Set — #1075), return/match-arm types, the fresh-ctor-var family (a bare `None` adopting the expected type at return/`let`/match #971, nested ctor fields #979, comparison operands #981, and call/op/init arguments #993 — with cross-ADT and `None == None` guardrail rejections), byte-arithmetic + integer-literal-range rejection (#420 split), the #898 cross-argument type-argument merge (`eq2(MkErr(5), MkOk("x"))` fully determines `Res` and type-checks; a per-parameter conflict `eq2(MkOk("x"), MkOk(5))` is a clear E205; a determined-non-Eq type still type-checks), the #900/#939 generic-over-zero-size rejection (E206 fires only when the `forall` READS `@T` and `T` erases to no WASM local — bare `Unit` OR a transparent `Future` (#939) — in the body (direct return, match scrutinee, nested `let`/`if`) OR in a `requires`/`ensures` clause (#939); a `@T`-unread generic like `firstInt`/`ignore`, a boxed `Option`, a `Future`, and the built-in `async(IO.print(...))` over Unit all stay accepted), the #945 array-of-zero-size rejection (`Array` / a bare `[()]` is E135 at both the type-resolution and array-literal gates — emitted exactly once, the literal gate defers to the annotation when both apply (including a refined `{ @Array \| p }` annotation, whose `RefinedType` the guard strips via `base_type`), and a zero-size `Array` param reports E135 once via the general exact-duplicate diagnostic dedup (PR #938); `Array` stays accepted), the #1204 quantifier-bound gate (E128 for array/String/Float64 domains; count form, `@Nat`, refined-integer, and TypeVar bounds accepted), the #1206 handler-state cell gate (E336 when the declared state type diverges from the builtin State effect's resolved `T` — `state_cell_decl_equal` on resolved types, since `is_subtype` conflates `Int`/`Nat` and erases refinements, with refined predicates compared structurally so a refined-vs-refined divergence is caught; aliases of `T`, a refined alias on both sides, and two textually identical refinement aliases stay accepted, a TypeVar cell defers to instantiation, and a user effect's handler state stays free), and the E337 builtin-effect handle arity gate (bare `handle[State]`, `State`, and the Exn twin) | | `test_checker_int_nat.py` | 8 | 153 | #755 — mixed `Int Nat` arithmetic joins to the formal LUB `Int` (not `Nat`); direct `expr_types` observation that `@Int.0 - 2`, `@Int.0 + @Nat.0`, `@Int.0 * @Nat.0`, `@Int.0 / @Nat.0`, and `@Int.0 % @Nat.0` synthesise `Int` (the DIV/MOD pins kill a per-operator `numeric_join` bypass nothing else in the suite catches), with `Nat`/`Nat` → `Nat` and `Int`/`Int` → `Int` guards against over-correction | | `test_checker_patterns.py` | 59 | 932 | Pattern matching, match-arm typing, exhaustiveness, pattern/match coverage, bidirectional inference, typed holes (#420 split) | | `test_checker_functions.py` | 86 | 1103 | Function signatures, slot references, result refs, calls, control flow, higher-order, where-blocks (incl. #969 closed-scope isolation over bodies + contract clauses, nested-where hint targeting, handler-vs-where hint ordering), expression diagnostics, IO operations, string interpolation (#420 split) | | `test_slot_naming.py` | 56 | 810 | The rule table for `vera/naming.py`, the ONE slot/family naming renderer (#1208/#1209): each clause of THE RULE pinned to an exact rendered string — syntactic (alias-opaque) head vs fully-resolved type arguments, refinement at top level (base) vs argument position (the elided `{@Int \| ...}` form) with alias parameters substituted BEFORE the refinement branch, `Fn` at top level vs the full `fn(...) effects(...)` spelling with a SORTED effect row in argument position, the total `?` paths (arity mismatch, `Decimal` with arguments, a removed alias, an unresolvable type expression), type parameters shadowing same-named aliases, declaration-order alias visibility (a cycle and a forward reference terminate on the checker's opaque placeholder; a 40-deep in-order chain resolves, and a 400-hop chain — bare names and composites alike — resolves without a per-hop frame; a 300-level alias graph whose bodies mention SIBLINGS as well as ancestors resolves too, and at 1000 levels the resolver is instrumented to prove its nesting is CONSTANT rather than merely under this machine's recursion limit), slot-reference keys matching the binding side, `family_name` collapsing scalar / composite / parameterised-composite aliases and its fallbacks, `family_base_name` (identity vs representation, #1218), the refinement-binder derivation (including its deliberately syntactic argument naming), a declared ADT outranking the `Decimal` and removed-alias branches (a user `data Float` / `data Decimal` renders as itself and keeps its type arguments) while an alias still outranks a same-named ADT, ADT visibility bounded by declaration index in BOTH directions (an ADT declared below the alias body that names it is invisible to it, above it is not — and the bound stops at the alias body, so a top-level slot names the ADT whatever the order), and the env builder | | `test_slot_naming_differential.py` | 6 | 912 | The load-bearing proof behind `vera/naming.py` (#1208/#1209): the checker's two naming entry points (`_type_expr_to_slot_name` and `_slot_type_name`, the latter also carrying every `_slot_ref_key` reference) are instrumented to record a (reference, module) rendering pair on EVERY call, and the whole `.vera` corpus (examples, conformance programs and their module fixtures, the PR #1202 probe corpus) plus a 31-program inline battery aimed at the alias / refinement / function-type / shadowing / declared-ADT corners (four of them carrying their own preludes, because the declaration-ORDER corner is about where the `data` sits relative to the `type`) is swept for ZERO divergence. The checker DELEGATES its naming, so the module side is what the checker returns and the reference side is a test-local statement of the rule (syntactic head, arguments through the checker's own `_resolve_type`, joined by `canonical_type_name`, plus the refined-top recursion) — independent by design, so a future edit to the module has to disagree with a written-down rule rather than re-baseline both sides at once. It is also what pins the join: `vera/naming.py` renders each argument through `type_arg_name` and restates only the `Head` bracketing, and this side calls `canonical_type_name` itself. Check failures still contribute observations (naming runs while diagnostics accumulate); only parse failures are skipped, and counted. Self-protecting: floors on total observations, observations under a non-empty alias env, and — counted over the CORPUS alone, so battery growth cannot mask corpus decay — both the number of `.vera` files swept and the arguments naming an alias pre-resolution; a battery reach test that names the exact string each corner must render, so an entry contributing nothing fails instead of reading as agreement; a `VeraError`-only absorption around the check, so a compiler-level raise propagates rather than silently emptying an entry; and a live proof the gate can go red (perturb the module renderer, assert the harness reports it and that the reference side stands still) | | `test_slot_naming_blast_radius.py` | 15 | 337 | The MEASURED radius of the #1208 core flip: every subsystem downstream of the checker (the monomorphizer, codegen, the verifier, the SMT layer) derives slot names AND slot-reference keys from `vera/naming.py`, and the radius is measured over the whole `.vera` corpus (`check --json` diagnostics for every file, `run` for every probe). Six shapes differ, all one class: a program that died on a dangling-slot `[E699]` now resolves and runs with the value the CHECKER's binding rule gives — each pinned by path and entry point with its expected value, so a regression that re-splits the naming names the program rather than failing diffusely. The six live in `tests/conformance/`, which is where the assertions read them. No `check` diagnostic moved anywhere (the checker was already delegating), and five slot-heavy sentinels outside the radius are asserted still clean. Also pins the two things the corpus cannot show: `--explain-slots` reporting the merged parameter stack under the checker's own name, and the module-scope rule — an imported generic's clone has its De Bruijn recount rendered in the DEFINING module's alias namespace (§8.4.1), not the importer's, or the merge goes unseen and the clone silently resolves onto the wrong parameter | | `test_family_naming.py` | 66 | 1,583 | The State/Exn cell FAMILY is the cell the CHECKER typed (#1209): the checker resolves an effect instance's type arguments in full, so `State` under `type MaybeInt = Option` and `State>` are ONE instance, and the family is named from the resolution rather than from the source spelling — a spelling-keyed family mints two host cells behind a green check for anything that does not resolve to a scalar. Pins the collapse where it is OBSERVABLE (a mixed-spelling program returns the shared cell's 7, not the split cell's -1 — bare alias, parameterised alias, and an `Exn`/`type Msg = String` payload whose `i32_pair` (ptr, len) has to arrive through the SAME tag), the import surface collapsing with it (one `state_get_` import, not two), the same collapse across a MODULE boundary (each side resolving in its own alias namespace), the negative (`Option` and `Option` stay two cells, and the outer cell keeps its value — a renderer that dropped type arguments passes every positive and fails here), the resolved function-carrying family (#1219 — `State` under `type Handler = Option Int) effects(pure)>` takes its resolution's name, and the alias and the resolution share one cell, proved by the value), the surviving bare-function-type fallback (the residue, refused downstream so the split is free), the refined cell's own family (#1218 — nested `Pos`/`Neg` route to their own cells, and a refined cell keeps its base's write guards and pair-ness), the linear-in-the-predicate symbol length with its `MAX_CELL_FAMILY_SYMBOL` backstop refused loudly on both targets, and the two formatter-coverage gates behind the predicate renderer, byte-stable family symbols for seven alias-free corpus programs (the emitted names are ABI), and the whole measured radius: the six shapes the flip moved (now in `tests/conformance/`), each at the symbols AND the value it renders to | | `test_naming_env_provenance_1208.py` | 45 | 2,097 | The other half of the #1208 contract: every consumer is handed the ENVIRONMENT the checker rendered under, not just the same renderer. Four provenance seams, each pinned by the adversarial probe that exhibited it — an IMPORTED callee's contract rendered in its DEFINING module's alias namespace (a violated precondition that vanished, and its mirror, a correct call spuriously rejected, both under a `Cnt` that names different bodies on the two sides), an imported GENERIC monomorphized and verified in that same namespace (a lying postcondition that proved clean, plus a verifier↔codegen clone differential over the recounted slot references — the desync is invisible to a unit test on either side), a `forall` variable shadowing a same-named module alias wherever a generic signature renders (the mono clone, a body `let`, the verifier's collapsed premises, and the exported uninstantiated template), and the tester's `SmtContext` holding the narrowed scope its own names were keyed in — the last one behavioural, since a generator handed the wrong scope collapses two parameters onto one variable and returns NO inputs at all. Three of the seams are also crossed against a SECOND component rather than checked for internal consistency, because a wrong-but-consistent scope is invisible from inside one: the verifier's declared parameter names against `slots.slot_table`'s, its `where`-helper scope against `slots.fn_scopes`' accumulation, and the monomorphizer's post-substitution names against what the consumers rebuild on the clone — each independent on the axis under test (which variables the two sides narrow by) but sharing `fn_slot_scope`/`slot_name` below it, so the hand-derived literal rendering beside every comparison is what a shared-renderer defect cannot satisfy. An imported generic nested under a non-generic function is pinned too — both its discovery-time recount and its verification-time clone must run in the DEFINING module's namespace. Three more seams arrived from the PR #1224 review, each with the false Tier-1 or miscompile that exhibited it: an UNPINNED callee (an imported generic's own `where`-helper, which the origin registry never pins) rendering in the module under verification rather than the entry program, whose absence let a violated precondition discharge as true and trap at run time; a callee's refined-RETURN predicate translated in the callee's namespace alongside its `requires`/`ensures`, pinned by provenance because today's bare-headed binder masks it behaviourally; and codegen's declaration-index space keyed PER NAMESPACE, without which a module's stamp turned the main file's forward alias reference into a backward one and a check-clean, verify-clean program read the wrong parameter through valid WASM. Two seams from the #1213 burndown close the same shape from the other side: the prelude's own aliases are injected only into the reserved `Vera` namespace, so no name a program can spell resolves on the codegen side alone (#1221 — the differential compares the checker's and codegen's partition of one signature, with the emitted WAT beside it), and an imported ADT is ordered at the index its OWN module gave it rather than the built-in floor (#1227), each with the control that differs by exactly the namespace under test. Controls carried alongside: the same programs with the alias renamed or the shadowing declaration removed, and the runtime oracle that shows the new E500/E501 agrees with the emitted code rather than merely reporting more | | `test_callee_contract_scope_1220_1225_1226.py` | 40 | 1,433 | A callee's contract is READ in the callee's own module. Three burndown defects, each asserted against the runtime oracle wherever the two directions of a wrong namespace (an obligation that vanishes, one that fires for no reason) look identical from inside the verifier: an E501's `Precondition:` line quoted from the file that DECLARED the clause (#1220 — in the misattribution direction too, both files carrying a plausible `requires` on the same line number, plus the imported-generic `where`-helper whose clause sits past the end of a short importer and used to quote nothing at all); a bare-name call inside an IMPORTED callee's contract resolved through the CALLEE's module registry (#1225 — the false Tier-1 whose run traps and its mirror spurious E501, through the `requires` and the `ensures` path, against a no-collision control); and the refined-RETURN binder derived through the naming layer, so a refinement over a PARAMETERISED base pushes the key its own predicate looks itself up under (#1226 — single-module and cross-module, the second proving the derivation happens INSIDE the callee scope); plus the PR #1239 review round — a module's pinned registry holds what its OWN file imports (a DEPTH-2 chain, the shape the single-level corpus could not exhibit: requires and ensures directions, bare-vs-qualified tier agreement, a name outside the middle module's import filter still missing per §8.5.1, and the mirror gate that filling the registry does not re-export), and every part of a diagnostic follows the declaring module (location, file name and excerpt, including a clause past a shorter importer's end, with a multi-line clause quoted whole), and the characterization of the binder-reference walk's one documented exception — a CLOSURE inside a predicate owns the first `@T.n` in traversal order, whose consequence is a Tier-3 demotion rather than a fact assumed about the wrong term; and the mini-review round — an obligation carries the FILE its line number belongs to, so the documented `(file, line, column)` join between the two `--json` arrays holds for a module-located obligation, with the entry-file control and warm==cold parity, and a multi-line clause is quoted with its `--` comments blanked (a `--` inside a string literal surviving, which a naive split would corrupt) | | `test_alias_application_refinement_base_1237.py` | 11 | 398 | A parameterised alias APPLICATION substitutes its arguments in the verifier's own resolver (#1237). `type Box = T;` applied as `@Box` resolved to `AdtType('T')` — the alias's binder leaking as an ADT name — so a refinement over it failed the modelled-primitive gate, the refined-return fact was dropped, and a valid program was rejected with a spurious E501 while `vera run` returned the right answer. Both halves of the fix are asserted separately: the alias body registers its own parameters as type variables (`substitute` maps type variables, so an ADT-named binder is unsubstitutable however the application side is written) and the application substitutes. Plus depth (an argument that is itself an application, and an alias whose body applies another alias), the bounded direction (a consumer wanting `>= 100` where the refinement grants `>= 18` is still rejected, and the runtime agrees), and the gate that must NOT move — an unmodelled `@Byte` base resolves correctly and still degrades to a Tier-3 runtime check, with a consumer of its predicate still refused | | `test_exn_throw_payload_1268.py` | 42 | 1056 | `throw`'s payload is obligated AND runtime-guarded like every other narrowing site (#1268). `throw(0 - 5)` under `effects(>)` verified at 4/4 Tier 1 with ZERO obligations while `vera run` returned -5 out of the `@Nat` payload — check-green, verify-green, silently wrong — because `throw` is a bare call with no function-registry entry, so the argument loop never saw it and the table-driven fallback added for the same hole at the State `put` was keyed on that one name. All three arms are asserted (the `@Nat` refutation, the refined refutation over a modelled base, and the `@Nat`->`@Int` widening obligation appearing where none existed), plus the #1251(b) concrete gate reaching the payload for free (`throw(200)` into an `Exn<{ @Byte \| @Byte.0 < 10 }>` names the value; the satisfying twin proves at Tier 1), the user-effect contrast that localized the bug (a declared op's argument was loud for the same value — both are loud now, at the same site name), and the refined-alias payload spelling. The GUARD is checked against codegen rather than asserted: an undischargeable payload must land on the runtime-guarded `tier3` leg, counted in the totals, and a run must confirm the payload really is stopped — the two together go red whichever side moves without the other (delete the emission and the runs go red; flip the flag back and the statuses do). Both arms are run at the boundary: a `@Nat` payload traps on -5 and delivers 5, a refined `{ @Int \| @Int.0 > 0 }` payload traps through the `$vera.contract_fail` channel on BOTH -5 and 0 — the value that clears the base's `>= 0` and violates the predicate, so a sign guard standing in for the predicate guard fails here — and delivers 7. The type gate carries its own over-refusal control: an `Exn` payload has no invariant to violate, so a negative one is a correct program and must still return -5. Both REPRESENTATIONS are covered — a scalar payload in one local, and a `@String`-based one whose (ptr, len) pair has to be saved in two, checked over the ptr and put back in the right order (the satisfying twin is what shows the order). The **soundness differential** is the point of the guard rather than a property of it: the clause parameter's type is what the verifier hands every downstream consumer, so a consumer discharging `ensures(@Bool.result)` at Tier 1 from its `@Nat` parameter alone is asserted PROVED and then run — pre-fix the run reported a postcondition violation on that proved postcondition, with nothing else in the path (the argument is already `@Nat`-typed, so no call-site narrowing guard fires). A dischargeable twin proves the site is not merely always-loud, and the six `Exn` conformance programs are verified whole as canaries so obligating a position that had none names itself instead of arriving as one line of a corpus sweep. The adversarial round adds the three places the `guarded` PROMISE and the emitted guard could disagree in a direction no value oracle can see, because the program either never runs or runs identically either way: a refinement OVER a refinement is asserted `tier3_unguarded` AND `E618`-refused at compile in one cell (the mirror claimed a runtime check for a program that cannot be compiled at all — either half alone reads as consistent); the bare and qualified spellings of one operation are asserted to record IDENTICAL statuses as a differential rather than two literals, on both arms, with the run confirming which value is the true one (`Exn.throw` was disclosed unguarded while codegen delegated it to the guard-emitting dispatcher, and `State.put` had been since #1203); the #820 INTERSECTION at this boundary — a refinement over `@Int` keeps the widening obligation AND its guard beside the predicate's, pinned as a differential against the unrefined spelling (both must trap at u64.MAX, where the refined one used to return -1) with an in-range control so the guard is not simply always-on; and `E504`'s rationale is read from a real diagnostic — reached through the site that IS still unguarded, a user-declared effect's operation argument — to pin that it no longer lists the `throw` payload among the sites with no runtime guard | | `test_refinement_binder_convergence_1208.py` | 16 | 459 | Codegen's refinement boundary guard and `vera/naming.py` derive the predicate binder ONCE (#1208). A per-shape differential over a direct refinement, an alias hop, `@Nat`- and `@Byte`-based refinements (both range-conjoining), a composite base whose binder is a RESOLVED argument list, and two non-refinements that must be `None` on both sides — plus the property the convergence exists to hold, that the guard's binder equals the key a predicate's own `@Base.n` resolves to. A per-shape differential is green either way while two copies agree — which is exactly how a duplicated derivation drifts unnoticed — so the load-bearing assertion is a MUTATION: perturb `naming.refinement_binder_parts` and codegen's guard must report the perturbed binder. Codegen's two layered WASM decisions are pinned alongside — the loud E618 for a nested refinement base, reported ONCE per declaration however many call sites consult the derivation and however many clones a generic is instantiated into (two genuinely distinct sites still report twice), and no guard at all for an erased one (parametrized over `@Unit` and `Future`, the corner that erases identically but is not spelled `Unit`) — plus runtime traps proving BOTH the `@Byte` and the `@Nat` range conjunctions reach the emitted check, each pinned by trap `kind` as well as by the conjunct its message names. The mutation perturbs the predicate as well as the binder name: the two travel by different routes, and the range conjunction lives on the predicate. The once-per-site dedup is keyed on a resolved location, so a cross-module pin holds up the premise that a location carries its owning file: two imported library modules of identical shape, declaring their nested refinement at the same line and column, must produce two diagnostics attributed to two files — each quoting its own module's declaration, which is also what catches an attribution pointing past the importer's last line | | `test_checker_effects.py` | 90 | 1,465 | Effect declarations, abilities, effect subtyping, async effect, handler typing (#420 split), and the #1149 built-in-effect redeclaration gate (E152: divergent and faithful `effect IO`, codegen-only `Exn`, a registry-parametrised sweep, and a differential pinning the gate's name set to what `vera effects --json` publishes) | | `test_state_exn_registration.py` | 30 | 1,298 | #1210 — State/Exn host-import registration covers the whole handler, not just its body. Four shapes, one per sub-expression position the walk used to miss (a nested handler in a clause body, in the state-init expression, in a clause's `with` update, and an `Exn` handler in a clause body), each check-green and verify-clean and therefore required to COMPILE — pre-fix every one died at whole-module WAT compilation with `unknown func` / `unknown tag`; plus the `i32_pair` cell (`handle[State]` in a `pure` function) that the walk skipped in silence, now the same loud E607 the declared-effect gate emits. The **registration-completeness differential** is the cross-component invariant itself: over every `examples/` + `tests/conformance/` program that compiles, every `state_*` / `exn_*` symbol the emitted WAT REFERENCES must have a matching import or tag DECLARATION — a desync between the registration pass and the lowering pass is invisible to a unit test on either. Round two adds the Exn twin of the silent skip (`handle[Exn]` in a `pure` function — the walk called the shared tag registration and discarded the verdict, so it compiled where the declared-row spelling was a clean E612) and the four CONTRACT positions, which are lowered code: a handler in a `requires`, an `ensures`, an `assert`, or a `decreases` measure. The differential gained a **validation leg** — every HANDLER-BEARING module is handed to `wasmtime.Module` through the exceptions-enabled engine `execute()` uses, because a symbol declared at the WRONG TYPE passes the name comparison while being invalid WASM, and 10 of the 30 handler-bearing modules fail to load with `wasm_exceptions` off — a supported wasmtime configuration, though the current runner defaults it on. The conformance suite's deliberate negatives are filtered out of the sweep: they never reach codegen through `vera check`. Carries floors on programs swept, modules validated, summed symbol references and globally distinct symbols, plus three can-go-red tests: the State and Exn extractions each stripped of their declaration lines, and a planted retyped import that only the validation leg catches. Round five adds the three positions no corpus program contained — a destructuring `let`'s value (which also disarmed the E612 gate), a module call's ARGUMENTS, and a signature refinement predicate reached through the alias table — and a cross-module shape test for the module-call leg. Round seven adds the boundary-guard routes that enumeration missed (a tuple parameter's components, a tuple return's, and a closure's refined formal and return) and the co-extensiveness half those shapes cannot show: a refined tuple behind a CLOSURE formal must declare nothing, since the closure path emits no component guards, and the nested-refinement (E618) and erased-base bails must stay silent registrars too. Plus the cycle guard on the closure signature leg, asserted in both directions — the walk terminates, and with the guard neutered the same walk blows the recursion limit | | `test_closure_lift_boundaries_1234_1235_1245.py` | 18 | 757 | Closure lifting at refinement boundaries — three burndown defects of one seam. **#1245**: `_lift_pending_closures` ran BEFORE `_compile_postconditions`, so a closure created while lowering a refined-RETURN guard, a tuple return's component guards, or an `ensures(...)` predicate was registered and never lifted — the table stayed empty, its `call_indirect` was orphaned, and the #1185 propagation dropped the function and every caller: a check-green, verify-clean program compiling to ZERO exports. The param-position twin (lowered before the lift, so it always worked) is carried as the control that makes it an ORDERING defect, the `ensures`-clause twin shows the same bug with no refinement in sight, and a violating return asserts the lifted guard ENFORCES rather than merely existing. **#1234**: the lift worklist fed itself — a refinement whose predicate holds a closure refined by a type whose chain leads back to it (`type SelfRef = { @Int \| ... fn(@SelfRef -> @Int) ... }`, and equally a mutual `A -> B -> A` or a three-type cycle) had each lift's own boundary guard queue an `AnonFn` for ever, and `vera compile` never returned. All three cycle lengths are asserted on a daemon thread with a wall-clock budget, so a regression fails fast instead of hanging the suite, and each on the [E602] naming the closure it refused (a guard that never fired cannot produce it). Two controls carry the other half — the guard is keyed on the lift CHAIN, not on everything already lifted, so `fn f(@R, @R -> @Int)` and a diamond, which each legitimately lift one predicate's closure twice, must still run; mutation-measured, they are the only two tests a seen-set spelling reddens. **#1235**: a `Tuple` formal crossing into a closure was unguarded where the named path traps — both spellings of the same boundary are run against each other, violating and passing | | `test_byte_literal_joins_1212.py` | 25 | 759 | #1212 — a `@Byte` literal inside a value-position join lowers at the i32 Byte width. `@Byte` is i32 (spec §11) while an int literal defaults to `i64.const`, and the #865 / #1092 coercions each tested for a TOP-LEVEL `IntLit` — which the checker's bidirectional coercion is equally happy to type inside an `if` or `match` branch. Ten write boundaries are parametrized with the literal in a branch (`let`, handler state-init, clause-dispatched `put`, bare `put`, get-clause `resume` — verbatim the form the E602 clause-lowerability skip message recommends — a clause `with` update, a `@Byte` call argument, a generic constructor field at `Box`, a lifted closure's own RETURN whose named twin had been coerced since #865 while the closure path had no such step, and a HETEROGENEOUS join at a `@Byte` return, where the arm the result-type decider reads is already i32 and a sibling is a bare literal — arm ORDER decided which way that one failed, so both orders and both paths are pinned). The module docstring states what that list is and is not: measured coverage, since the checker's single Byte coercion makes the true enumeration "every position propagating a Byte expectation", which nothing enumerates in one place, each a check-green program that failed WASM validation with `type mismatch: expected i32, found i64` before the fix. Every case carries a VALUE oracle (200, distinguishable from every other constant in its fixture) rather than merely asserting the module runs, and a separate test drives the OTHER branch so a fix that marked only the arm the result type is read off would still fail. The controls are the load-bearing half: a plain `@Int` join must stay i64 — pinned on 5,000,000,000, which an i32 store cannot represent, so a spreading mark is a wrong VALUE and not just a validation failure — a Byte join with no literal arm must be untouched, and a Byte-RETURNING literal join must keep its own #865 return coercion. The constructor-field case runs through the real pipeline (checker artifacts threaded), because the #1092 width keys on the checker-recorded target type | | `test_closure_boundary_widths_1255_1256_1269.py` | 52 | 973 | Widths and pointer-ness at a closure or effect boundary — three burndown defects of one seam, each a boundary answering "what is this declared type" from something other than that type. **#1255**: GC pointer-ness was read off the SYNTACTIC head, so `type SmallByte = { @Byte \| ... }` was rooted on the shadow stack at the closure parameter, return and capture and at the two named-function twins. The oracle is a DIFFERENTIAL against the `@Byte` spelling of the same program rather than an absolute push count — these bodies must allocate or no prologue is emitted at all, so they legitimately root their own intermediates — with the base spelling's own count PINNED beside it, because equality alone also holds when both spellings root the scalar, which is the pre-fix state and what a mutation deleting the exclusion outright would produce. A genuine pointer at each of the four boundaries is the control (rooting nothing anywhere satisfies the differential too), and every shape runs under `VERA_EAGER_GC=1` — a collection at each `$alloc`, where removing a load-bearing push reads back as a wrong value rather than as a passing test. The heap-layout invariant the defect was inert behind is executable here: a module with no string pool at all — the exposure the issue named — still starts its heap above the inline scalar range, and shrinking the two constants that create that margin fires the build guard. **#1256**: the `apply_fn` `call_indirect` signature took each parameter's width from the ARGUMENT, so a `@Byte` formal fed a literal registered two incompatible `$closure_sig` types and trapped; asserted by run AND by the emitted signature list, since a value oracle alone would also pass if both sides converged on the wrong shared width. The join spelling, the refined formal, the function-type-alias arm of the formal recovery, a directly-called named twin and an i64 control (pinned above 2^32, which an i32 parameter cannot carry) surround it. **#1269**: `throw`'s payload was not a `@Byte` write boundary, so `throw(5)` into `Exn<{ @Byte \| @Byte.0 < 10 }>` put an `i64.const` under an i32 tag and failed WASM validation at load. Both halves of the width agreement are pinned — a fix that widened the TAG would also run, and would put a Byte cell at eight bytes everywhere else — across the bare, aliased, refined, branch-literal, qualified-`Exn.throw` and thrown-inside-the-handled-body spellings, the last two reaching registration paths the others do not | | `test_nested_handler_clause_ops.py` | 27 | 971 | #1211 — a handler clause body's bare `get`/`put` belongs to the handler's DECLARATION scope, not to the body it refines. Eight nested shapes, each asserted on all three components (checker accepts, verifier discharges clean, compiled program returns the checker-derived value): `put` in a put clause and in a get clause, a bare `get` in a `with` state-update expression, depth-3 nesting proving the IMMEDIATELY enclosing handler wins, the qualified `State.put` spelling, a nested handle expression inside a clause body (its registries must be restored to the declaration's, not the intervening handler's), and the two op-result-type mirrors — a bare `get(())` in match-scrutinee (`_effect_op_result_wt`) and array-element (`_effect_op_result_vera`) position, both of which emitted invalid WASM for a check-green program before the alignment. Every oracle is derived from the checker's story, never from what codegen emits, and a meta-test asserts each shape still SEPARATES enclosing-cell from inner-cell routing (the pre-fix value is recorded per case) so none can go vacuous. Round two adds the two dispositions of an EMPTY enclosing handler stack — the declared effect row (the only route that reads the restored `_effect_ops`, which every handler-enclosed case bypasses) and the outermost handler in a `pure` function (E122 at check) — the enclosing handler's own clause running on the outward-routed op (a transforming `with` one level out: 300100, where the intrinsic reading gives 300050), `IO.print` inside a clause body, the #1233 same-family refusals (nested handler, `with` expression, declared row) with their different-family control, and the outward-re-entry depth cap (below it, at it with a WAT-size bound, and past it as a loud E602) | | `test_handler_op_ownership_1284.py` | 15 | 419 | #1284 — whose declaration a bare `get`/`put` call site denotes. The checker resolves user-fn-first (pinned directly: an over-applied `get` under a `handle[State]` reports the USER signature's arity), and codegen used to answer that question twice more and differently — the declared-effect row withheld the op when a function owned the name, the handler expression overwrote unconditionally. Four shapes from check-green source, each asserted on the CHECKER's value and on the dispatch target in the emitted WAT: a handled body returning the cell instead of the function's answer (silently 5 for 4), a `@Bool`-returning user `get` whose module WASM validation rejected, same-family nesting refused outright with a spurious `[E602]` naming a State operation the source never contained, and different-family nesting emitting the enclosing cell's getter at the wrong width. A parametrized differential runs all five shapes (the four plus a user `put`) as one table with each case's pre-fix behaviour recorded, so a case that stops distinguishing the two answers is visible rather than vacuous; the controls — an unshadowed handler and an unshadowed declared row, both of which must still reach the intrinsics — are what a fix that simply stopped installing the ops would fail, and `new(State)` under a shadowed op name pins that the #1285 family registry composes with this | | `test_new_state_family_1285.py` | 9 | 323 | #1285 — which cell `new(State)` reads under a multi-`State` effect row. `old()` has been family-keyed since #1205/#1209 while `new()` read the name-keyed op registry, so the two sides of one `ensures` clause read different cells: `effects(, State>)` with `ensures(new(State) == …)` was check-green and verify-green, put `state_get_Int`'s i64 into the Bool comparison's `i32.eq`, and died at load. Three multi-row cases — the width-mismatched shape that could not load, an `Int`/`Nat` pair that loaded and answered about the wrong cell, and `old()` beside `new()` of one family, whose unchanged-cell claim the runtime refuted on a contract the verifier had discharged — plus the single-`State` and alias-spelled controls the whole existing corpus exercises. Each cell is seeded from a caller's handler at a value the other cell is not holding, so a wrong-cell read cannot coincide with the right answer, and a deliberately false postcondition asserts the Tier 3 runtime check really traps, without which every "the program runs" assertion here would prove nothing | | `test_adt_membership_scope_1253.py` | 5 | 334 | #1253 — a checker↔codegen DIFFERENTIAL over one module's slot table. `_adt_layouts` is one map across every absorbed namespace, so a sibling module's ADTs were members of a module that never imported them while the checker kept the name opaque: `['Array', 'Array']` against `['Array', 'Array']` for the same signature. Each case renders the module's parameters through `vera.naming` twice — once against the environment the checker binds that module's declarations in (built by the production `_modules_visible_to` + `check_program` path, not a rebuild of it) and once against codegen's `_alias_env` inside `_module_alias_scope` — and asserts both the agreement and the checker's own value, so an alignment on the WRONG name still fails. Three membership cases (an unimported public sibling, a private sibling, and the imported positive control that is green before and after — what separates scoping the membership from erasing cross-module ADTs) plus the entry program's own view, which must keep seeing the ADT it imports by name | | `test_prelude_decl_stamp_1287.py` | 4 | 240 | #1287 — the prelude's declaration-index block is a fact about the prelude. `_stamp_decl_order` guarded the PRELUDE write on `_decl_order`, the active (main-file) namespace, so a main-file `type Option = Int` — accepted under §8.4.1, and not a `data`, so it does not suppress the prelude's own `Option` — made the guard fire and left `Option` out of `_prelude_decl_order` entirely, with every later prelude declaration shifted one place earlier because the counter never advanced. That map is the base layer under every module's index space (`{**prelude, **module_own}`), so the wrong index reached `AliasEnv.data_types` as `_BUILTIN_DECL_INDEX`. Stated as an INVARIANCE — the same program with and without the shadowing alias must stamp an identical prelude block — plus the module-namespace index it feeds, and a control that the main file's own stamp still wins its own namespace (which a fix stamping `_decl_order` unconditionally would break) | | `test_prelude_adt_namespace_1277.py` | 61 | 1034 | #1277 — one file's `data Json` must not evict the prelude's from another namespace, and a module declaration contending with a prelude one must be loud. Three halves, pinned by disjoint cases so a regression in any is attributable. **Acceptance battery**: all eight prelude ADT names × {module declares it alone, entry also uses the prelude's}, asserting that no cell reports `[E602]`/`[E620]` and that a cell which does not report `[E621]` emits every public function the entry declares — the silent-drop check, and the guard against the rail's original four-of-eight coverage returning (the layout harvest skips a built-in name, so a layout-keyed rail saw `data Json` and never `data Option`). That battery accepts either answer per cell by design, so the §8.4.1 injection split is pinned separately: an entry that never names the type must still report `[E621]` for the four every program compiles (`Option`, `Result`, `Ordering`, `UrlParts`) and must stay clean for the four injected on demand, with a partition cell holding the two halves to the battery's own name list. Plus two-declaring-module cells in both import orders — the entry's import order is derived from the parametrization, and the both-differ cell asserts the two reports arrive in that order, so the pair cannot quietly become one program compiled twice — covering restate+differ, both-differ, both-restate, and a non-prelude control that must stay E609's, because the rail asks every declarer and a first-wins lookup made it order-dependent. Plus the restatement control for all eight: a module that restates the prelude's shape shares the one layout, compiles and runs, and must not be refused — measured legal at the branch point, and refused by the rail's first form for four of them. **Rail detail**: severity, the module's own file and line, the description naming the type and the module, the empty exports, and `cmd_compile` returning 1 over a `cmd_check`-green program. **Floor**: the checker registers the prelude ADTs in every `TypeEnv` unconditionally, so codegen's membership must too; asserted as a differential against the checker's own `data_types` in a module namespace, and on the entry namespace's member set for the issue's measured shape. `prelude_adt_names()` is compared against `inject_prelude` itself, and `data_decl_shape` is pinned on the directions that matter — a renamed type parameter is the same layout, a reordered constructor is not, an alias-spelled restatement keys EQUAL to the prelude's, and a type parameter shadows an alias of its own name. Each declaration is resolved through the aliases of the namespace it was written in, one side only: the two whole-program cells pin both directions of that — a module restating the prelude through `type Payload = String;` must compile, and a module hiding a mismatch behind `type Array = Int;` must not | | `test_import_visibility_entry_point_1244.py` | 6 | 269 | #1244 — `vera check` reports the same diagnostics whether it was given a module or a file that imports it. Registration alone says what a module DECLARES; the importer never checked its bodies, so a name a module never imported was rejected standalone (E200, §8.5.1) and accepted in silence through an importer. Written as EQUALITY between the two entry points rather than as "the importer warns", because the property is agreement — a future change making the standalone verdict lenient would satisfy a one-sided assertion and must fail here on the standalone leg. Six cases: the leaked unimported name, the honest control that imports what it uses (green before and after, so the new body check is the visibility rule rather than a blanket rejection of cross-module programs), the issue's type-error-through-importer shape (an `@Int` call bound to a `@Bool` slot: check-clean, Tier-1, failing at compile), a diamond proving each module is reported ONCE (the body check is memoised by path across nested checkers), and both entry points into an import cycle proving the memo terminates it | | `test_clone_body_declaring_module_1241_1243.py` | 5 | 344 | #1241 + #1243 — an imported generic's clone body resolves its bare calls in the DECLARING module, on both sides. The verifier's lexical lookup fell through to the importer's registry (`_declaring_module_scope` swapped the naming env, source and file but not the function registry) and codegen's clone-emission door was the one door that did not thread the module's intra-rename map, so `glib`'s `gen` called the importer's `need`. The two halves are one routing rule, and the tests are written so neither passes alone: each case asserts the `vera verify` verdict AND the `vera run` value together, so the verifier half alone (which makes verify clean while the compiled program still traps on the postcondition it just proved — the measured false Tier-1) fails the same test the codegen half alone (right value, verify still refusing) fails. Every expected value comes from the module verified and run STANDALONE, never from what the importer produces. Shapes: a private direct callee, a two-hop private chain, the type-discriminating pair (`@Int` vs `@Bool` — check-green source that emitted invalid WASM), and the unshadowed-callee control that was correct before and after, which is what pins the defect to the SHADOWED name rather than to cross-module calls in general | | `test_module_generic_namespace_1274.py` | 24 | 1,015 | #1274 — a module generic that does not own the importer's bare name is reached under `mod$$name`. Pre-fix only PRIVATE module generics were routed that way (#1000), so a PUBLIC one collided with the importer's same-named generic in the clone-name space: both files' `gen2` mangled to one `gen2$Bool`, one overwrote the other, and the module's own body ran the importer's — a **false Tier-1** (`check`/`verify` clean, the module's proved `ensures` violated at run: 999 where the declaring module answers 111). The full visibility matrix (module generic × importer generic), the import-filter dimension (out-of-filter, in-filter, wildcard), the unshadowed-out-of-filter cell that assembled to `unknown func $gen2`, and a type-discriminating shape whose two clones have different WAT result types. Each cell asserts the verify VERDICT and the runtime VALUE together in one test — a clean verify beside a violated postcondition IS the bug, so splitting them across sibling tests would let it hide — against the standalone library as oracle, and re-checks that the importer's own generic still answers its own value. The per-module both-sides differential lives in `test_monomorphize_differential.py`. Two further families joined after the adversarial round: the module→module **hop** — a module's bare call to a DIFFERENT module's qualified-only generic, which the per-module classification never rerouted, in both a LOUD spelling (a contract pins the answer, so a captured call traps) and a SILENT one (every contract admits both answers, so only the value distinguishes them) plus the two-hop shape where the entry never imports the declaring module at all; and the **shared-input** pair, which pins that the two sides compute the importer's occupied bare names identically — codegen reads them after Pass 0's helper renames, the verifier from the pre-transform AST, and a non-generic `where`-helper named `gen2` made the same imported generic bare-name-owning on one side and qualified-only on the other. The idempotence of that derivation is asserted directly across BOTH Pass-0 transforms and their composition — over a fixture carrying every helper shape it distinguishes (non-generic under non-generic, under a generic parent, under a generic helper, and a generic helper), since a fixture missing one would let a partial assertion look total — with each shape's membership pinned individually beside it, because idempotence alone would hold for a derivation that answered the same WRONG set every time. Two more families close the visibility dimension: the **transitive** one, driven through the production `ModuleResolver` (a hand-built `ResolvedModule` defaults `direct=True` and would never reach the path), asserting that a module reached only transitively has ALL its generics qualified-only — the entry's namespace does not hold them at all; and the **user-written qualified call** (`deep::gen(true)` where the importer declares its own `gen`), which must key its instantiation to the module's declaration rather than to whoever owns the bare name | | `test_module_shadowed_generic_effect_op_1310.py` | 4 | 410 | #1310: a qualified-only (shadowed) module generic's instantiation discovery had no effect-operation registry at all, unlike #1207's unshadowed discovery walk. `idg(get(()))` inside `handle[State]`, where `idg` is a `forall` generic declared in an imported module, checked and verified clean and then compiled with `[E602]`/`[E620]` notes and no `main` in the emitted module: the WASM call-rewrite correctly named `mod$mlib5$idg$Int`, but `_collect_shadowed_qualified_calls` (codegen) and its mirror `walk_seed` (the verifier's `_collect_shadowed_qualified_instances`, #732) fell through to the phantom-var `Bool` default for the effect-op argument, so `mod$mlib5$idg$Bool` was the clone actually emitted and verified. The issue's own repro is pinned end to end (no E602/E620, the checker's own clone name in the WAT, and the runtime value), plus a nested-distinct-state cell (mirroring #1207's own) that would still pass a fix stopping the `Bool` default without preserving `HandleExpr`'s merge-over-the-enclosing-scope semantics, now also asserting the outer cell's clone is absent, matching the first cell's shape. Two more cells run the #732 differential directly on both fixtures: codegen's `_emitted_instances` and the verifier's `_instances` must name the identical instantiation, red if either side's `HandleExpr` merge is reverted alone | | `test_ambiguous_import_refusal_1304.py` | 40 | 1,202 | #1304 — two imports supplying one bare name are refused, in every namespace. Spec §8.5 ordered a local declaration against an import and gave the qualified form for a clash it hides, but defined no order between two IMPORTS of one name, and neither did the implementation: a module importing two dependencies that each export `forall fn gen` — one `@Int`-returning, one `@Bool` — bound its bare call to whichever supplier a set of module paths yielded first, so one unchanged file was check-green on one run and `[E121] body has type Bool` on the next (at the branch point: accepted on hash seeds 0, 2 and 3, rejected on 1, 4, 5, 6 and 7). The load-bearing cells are the DETERMINISM ones — each import order checked in four fresh subprocesses under four `PYTHONHASHSEED` values, asserting one byte-identical verdict including message and location, which the base tree cannot satisfy and which a merely deterministic PICK would also fail (the refusal is what removes the choice). Around them: the refusal is definition-gated like the E608 rail it generalises, so an unused clash is still refused and swapping a bare call for the qualified form does not lift it; the two escape hatches — a local declaration (§8.5.2) and a selective import — are asserted to their RUNTIME VALUE, since a disambiguation resolving to the wrong supplier is silent at check and wrong at run; four non-ambiguous controls (one supplier, disjoint names, a private namesake, an out-of-filter namesake) hold the refusal to bare-name ambiguity; and the emitted code is held to a typecheck-phase range, because reusing a codegen code would carry #1304's own complaint — a scope question enforced at the wrong layer — into the fix. A subprocess canary pins that every fresh interpreter measures this checkout | | `test_module_generic_collision_1281.py` | 20 | 809 | #1281 — E608 must not refuse two modules' PROVABLY DISTINCT generics. A generic emits nothing under its bare name, and since #1274 its clones live in a namespace chosen per OWNER, so the diamond (`base` public, `mid1` private, both named `gen`) cannot overwrite anything — and was refused outright, with `vera verify` returning rc=0 beside the refusal. Each door now answers its own module's generic (555 + 111) against the standalone oracles, and the emitted module carries `mod$…$mid1$gen$Bool` and `mod$…$base$gen$Bool` with nothing in the entry's bare clone namespace. The relaxation is gated on three conditions, each with its own cell: both declarations are top-level generics (a generic beside a non-generic keeps the refusal), at most one owns the bare name (asked of the predicate directly, since end to end the ambiguity gate catches that shape first), and no namespace can name both — a module importing two dependencies that each export `gen` would resolve its own bare call to one of them, and spec §8.5 refuses the name outright rather than ordering the two imports (issue 1304). The CHECKER reports that (E155) and this rail is its backstop, so both cells drive the shape through `build_multi_module_past_check` and assert both layers: a rail no test can reach is one that can rot into a relaxation nobody measures. A namespace that declares its own `gen` is not ambiguous however many dependencies export one (§8.5.2). The registration half — a qualified-only generic contributing no bare `_fn_sigs` or `_fn_ret_type_exprs` entry — is pinned by two STRUCTURAL cells, one per table, and its docstring says why: with #1299's scope narrowing in place both withholdings are defence in depth, reverting them leaves every suite and the whole conformance corpus green, and they are kept only because four consumers read those tables per NAME and nothing but their current internals stops each from picking one | | `test_lexical_fn_scope_1299.py` | 56 | 1,554 | #1299 — codegen's bare-call ownership table must be the CALL SITE's lexical scope. The #1284 predicate is one rule over two tables, and codegen's was `set(_fn_sigs)`: every symbol the whole compilation absorbed, including names the compiling body cannot see, so a bare `get(())` the checker resolved to a `State` operation was lowered as a call to some other declaration. Four routes, all check-green — an imported module's **private** `get`, a **public** one a selective import excludes, a `where` helper of a **`forall` parent** (which keeps a bare key beside its clone-qualified one where a non-generic parent's does not), and the ability operation `show`, which E151 does not reserve and which reaches the same table through the INTRINSIC gate rather than the op one. Where the widths agreed the module loaded and answered the invisible declaration's value (7007 for the cell's 42007); where they differed it failed to load; the generic-`where` route is always loud (`unknown func $get`). Every expected value is the checker's, PROVEN by a type oracle rather than assumed — the invisible `get` returns `@Bool` while the caller returns `@Int` from it and checks green — and each route carries a rename control. The visibility matrix (public/private × in-filter/excluded/wildcard × shadowed/unshadowed × direct/transitive) asserts the verify verdict and the runtime value together per cell. The two directions are pinned at once: the sibling loses the name, the generic TEMPLATE keeps it (asserted on the emitted instruction stream, since monomorphization supersedes the template and a value assertion would be green either way), and a lifted closure — compiled through its own `WasmContext` — inherits its parent's scope. Four table invariants sit beside them: the scoped set is a subset of the registry, every `$`-bearing key stays in it, prelude names stay in it, and every emission door supplies a declaration its own helpers | | `test_phantom_generic_instances_1271.py` | 14 | 358 | #1271 — discovery inside a still-generic scope must not instantiate a callee at an ENCLOSING scope's type VARIABLE. `pick(@U.1, @U.0)` inside `forall fn helper` bound `pick`'s variable to the NAME `U`, so a `pick$U` clone was emitted whose parameter has no WASM type and which the compilability pass then skipped with a loud `[E604]` — the noise that kept #1223's shapes out of the conformance suite. Drives the four #1223 fixtures plus a mutual-recursion shape (two sibling generic helpers under a generic parent, whose phantoms include one arriving through a callee's declared RETURN type, `leaf$W`), asserting on ONE compile that no clone is keyed by a type variable, that no E602/E604/E605 skip is emitted, AND that the genuinely concrete clone is still there — the third assertion being what separates the filter from an over-filter that would take the real instantiation with it. Plus the **primitive-spelled binder** matrix (`forall`, ``, ``, ``), each row instantiating a sibling at exactly the type its binder is spelled like — a shared `idw(5)` would have let every row but `Int` pass for free — asserted on the clone set AND on the program still running; with the `Q`-binder control that keeps a genuine type variable filtered, so the fix cannot degenerate into "never filter". That control CREATES a live phantom candidate — a generic helper under a generic parent, handing its callee an argument typed by its own binder — because a control that merely fails to create one holds under any filter including none; mutation-checked by disabling the filter, which turns it red | | `test_handle_exn_divergent_result_1276.py` | 10 | 391 | #1276 — a `handle[Exn]` whose clause body AND handled body both diverge emitted a result-LESS `block` into a result-expecting context: check-green, verify-green, rejected at load with `type mismatch: expected i64 but nothing on stack`. Four divergent shapes (the issue's Int rethrow, the `Byte` payload spelling #1269 unmasked, a three-deep rethrow chain, and a clause diverging through both arms of an `if`), each asserted on valid WASM AND on the observable — the OUTER handler's clause value, 1000. Paired with the Unit TWIN, which infers `None` for the same reason but DOES complete: it must keep running and its WAT must contain no `unreachable` at all. The pairing is the point — `result_wt is None` means two things wanting opposite lowerings, and a fix that terminated both would trap a program that runs. The MIRROR family covers a clause that throws on one path and COMPLETES on the other (`if` and `match` spellings), where the inference read only the `then` branch / arm 0, answered `None`, and left the completing path's value stranded in a result-less block; the `if` case appears twice with different thrown values so both the throwing and the completing path are exercised from one inference | | `test_infer_vera_type_join_1286.py` | 26 | 577 | #1286 — the VERA-level siblings of #1276's WAT join. `InferenceMixin._infer_vera_type` (the WASM call-rewrite consultor) read `then_branch` only and `arms[0]` only, and `Monomorphizer._infer_vera_type_name` (the instantiation-discovery consultor) read `then_branch` only and had no `MatchExpr` arm at all — so a branch that throws, naming no type, decided the answer for the whole expression. Two symptoms from check-green (and, with contracts, verify-green) source: as an array-literal ELEMENT the `None` raised `CodegenSkip` and the declared `main` simply left the exports with a loud [E602] note, and as a GENERIC ARGUMENT it left the type variable unbound, so `idg$Bool` — the phantom-var default, an i32 clone — was emitted for an i64 `Int` argument and the module failed to load. Seven witnesses (array literal in the `if`, `match` and pair-representation `String` spellings; generic argument in the `if` and `match` spellings; the constructor FIELD behind the same conditional), each asserted on the value, on `main` surviving into the exports, and on the absence of the skip note — the drop is quiet at the value level once the function is gone. The seventh witness is the consultor-AGREEMENT case, where every arm completes and nothing diverges: the rewrite named `idg$Int` from arm 0 while discovery named the phantom default, and the caller was dropped on a dangling target — which is why the repair lands on both consultors together, the clone-name agreement contract (#772) making the pair the unit. Each witness carries its ARM-SWAPPED twin and the pair must agree, so the join property under test is order-invariance rather than a remembered value; a WAT assertion pins WHICH clone the module carries, since a value can be right for the wrong reason. The PR review round found the same divergence one shape over and the sweep it prompted found a third, both closed here: discovery had no `Block` arm, and the transformer leaves a braced match-arm body AS a `Block`, so `Some(@Int) -> { let … }` named nothing there while the rewrite named the concrete clone — `idg$Int` emitted and never registered, `main` dropped from a check-green program. It only reaches a wrong answer when no later arm yields either, so the witness pairs the block-bodied arm with a throwing one; the braced-`if` variant needs the branch TAIL to be a block in its own right, a `let` inside the branch being a statement. The third is a `handle` in argument position, a presence cell since it has no branches to exchange. An `IndexExpr` argument dangles the same way and is deliberately NOT closed here, tracked as #1327 — the rewrite's arm resolves chained indexing, aliases and `Future` payloads against codegen tables the monomorphizer lacks, so a partial mirror would trade "both say unknown" for "the two disagree". WAT membership is tested through `wat_fn_names` / `wat_calls`, not `in wat`: the substring form is a prefix test that a longer mangled symbol satisfies, which is exactly how one clone impersonates another. Mutation-checked one edit at a time: reverting the rewrite-side `if` fails 13, its `match` 8, the discovery-side `if` 8, `match` 9, `Block` 6 and `HandleExpr` 2, and all six at once fails all 26 | | `test_generic_under_generic_callees_1223.py` | 8 | 298 | #1223 — a generic `where`-helper under a GENERIC parent instantiates its own generic callees. The helper is monomorphized only during clone hoisting, outside the worklist that rescans every clone it emits, so a top-level generic called from the helper body was discovered only in its still-generic spelling (`pick$U`, binding the enclosing type variable's NAME) while the rewrite called `pick$Bool` — E602 skip, E620 drop of the parent and of `main`, "No exported functions" from a check-clean, verify-clean program. Four shapes — a user generic, the prelude twin (`option_unwrap_or`), two levels of generic nesting where the INNER helper is the caller, and the non-generic-parent control that compiled before the fix and must keep compiling (it is what proves the trigger is the generic ancestor rather than the nested helper) — each asserted on no E602/E620, the checker's run value (the helper's argument order is non-commutative, so a miswiring gives 7 instead of 3), and a REGISTERED-vs-RESOLVED differential. That differential captures the emitted mono-decl names rather than `_emitted_instances` (whose generic-under-generic entries are keyed by the concrete-free lexical chain, not by the per-clone emission name the rewrite calls) and captures the rewrite side on `_resolve_generic_call` rather than from the WAT, because a desync skips the calling function and removes the dangling `call` along with it. The verifier's half of the pair is pinned in `test_monomorphize_differential.py`'s inline corpus, not here | | `test_mono_effect_op_naming_1207.py` | 9 | 339 | #1207 — monomorphization discovery and the WASM call-rewrite name ONE clone when an effect operation fixes a generic's type argument. A differential over the two consultors, not a unit test on either: the compiler's own E602 ("call target not registered in this module") IS the two sides disagreeing, so each case asserts no E602/E620, and additionally pins WHICH name they agreed on — an alignment on the wrong one still fails. Four instantiation-driving shapes (`get(())` as an array-literal element under a plain `State` cell, under a `type Count = Nat` alias cell whose clone must be `pick$Count`, in a function whose operation comes from the DECLARED effect row rather than an enclosing `handle`, and in direct argument position), plus the `array_append` builtin-argument control and a shadowed-name control — a user `get(@Unit -> @Bool)` is NOT an effect op in a declared row, so the clone must be `pick$Bool` and not the cell's; that case is green before the fix as well as after, which is what makes it a guard against the alignment over-reaching rather than a second copy of the repro | | `test_effect_op_determinism.py` | 9 | 504 | #1215 — bare effect-op resolution order: the built-in `State` and `Http` both declare `get`, so `effects(, Http>)` is a two-candidate row with no user `effect` declaration needed. The two candidate bindings are made to produce DIFFERENT observables (the source-order program runs to `70`; the reversed row is a loud `E217` naming `Http.get`), swept across six `PYTHONHASHSEED` values in child interpreters so a frozenset-order flip cannot pass — plus the innermost-handler-beats-declared-row precedence case, a signature-level assertion that the resolved `OpInfo` follows the recorded order both ways (including the deterministic name tiebreak for a row member no order tuple mentions), and the qualified-lookup control. The type-ARGUMENT sibling rides here too: `effects(, State>)` (two independent cells, spec §7.3.3) had the identical frozenset dependence in `_effect_type_mapping`, and codegen took the LAST instantiation in the row where the checker takes the first — both now source-order-first, swept the same way. A sixth sweep covers the public `ordered_effect_row()` fallback for a row member no order tuple mentions: its two members share the effect NAME and differ only in type ARGUMENT, so a name-only sort key ties them and hands back frozenset order — the order AND the `_effect_type_mapping` selection it drives are both asserted stable across the same seeds. Two further sweeps take that structural key down a level: a type argument may itself be a FUNCTION type, whose own effect row was rendered by `pretty_effect` — so two outer instances differing only INSIDE a nested row (by a refinement's predicate, or by a type variable's built-in marker) tied again, and both legs are asserted single-outcome across the same seeds, separately, so a regression names the elision that came back | | `test_db_effect.py` | 9 | 136 | #229 — the built-in `` effect: `DB.query` / `DB.execute` type-check under `effects()` (E122 without it; E204 on a non-`String` SQL argument), plus `is_db_sql_op` — the predicate the #309 gate keys on — gating any `DB.query`/`DB.execute` by `parent_effect == "DB"` + op name (the same axis codegen routes to the host on), so a user `effect DB` shadow's op IS gated (it would still reach the host) while an unrelated effect's `query` is not — the shadow is itself rejected at its declaration since #1149 (E152), so this predicate is defence in depth; a checker↔codegen differential pins the gated set to the built-in DB ops | | `test_db_marshalling.py` | 35 | 234 | #229 — the `` marshalling helpers: `Array>` params (inbound reader), `Array>>` query grids (`_alloc_result_ok_rows`) and `Result` row-counts, round-tripped through an `InstanceCaller` over a real compiled module — each case run normally AND under `VERA_EAGER_GC=1` (every `$alloc` fires `$gc_collect`), the large-grid case forcing free-block reuse; mutation-validated (dropping a shadow-stack root corrupts the read-back / SIGBUSes the swept-pointer read) | | `test_db_runtime.py` | 21 | 301 | #229 — the `` host binding (`vera/runtime/db.py`) on stdlib `sqlite3`: create/insert/select round-trips against `:memory:`, NULL cells → `None`, the affected-row count (incl. the `-1` DDL sentinel), a BLOB cell UTF-8-decoded with replacement, the `Err`-not-crash error path, an unopenable `VERA_DB_URL` deferred to an `Err` (not a host crash), and injection-safety (a malicious param binds as a literal, table intact); plus `_open_connection`'s `VERA_DB_URL` surface (memory + file URLs, in-memory default) and `register_db`'s bind/no-op paths | | `test_sql_provenance_309.py` | 79 | 780 | #309 — the SQL literal-provenance gate (SQL injection as a compile-time error): non-literal SQL rejected `E207` (bare param slot, function result, `\(expr)` interpolation, `string_concat` with a runtime operand, let-bound runtime value, `if`-expression), literal / concat-of-literals / let-chain-with-shadowing / empty-string accepted, placeholder/param arity `E208` with quote- and comment-aware counting (named/numbered placeholders are rejected outright, `E209`), the `count_placeholders`↔sqlite3 differential (exact count accepted, one too many rejected), and gate scoping — a user `effect DB` shadow is rejected at its declaration (`E152`, #1149) *and* its runtime SQL still draws `E207` alongside it (defence in depth), an unrelated effect's `query` is not gated, and no `E207` cascade onto a mistyped SQL arg | | `test_checker_modules.py` | 242 | 2,632 | Module-call diagnostics, cross-module typing, visibility enforcement, builtin redefinition (function E151 and effect E152 surfaced from a module into its importer), reserved function names (E153 — the contract state forms `old` / `new` and the keyword class `assert`/`assume`/`forall`/`exists`/`match`/`if`/`let`/`fn`/`true`/`false`, each top-level, `where`-helper, and module-surfaced, plus the `handle` host-invoked carve-out and the probe record behind both halves; the twenty-one *contextual* keywords `then`/`else`/`data`/`type`/`module`/`import`/`public`/`private`/`requires`/`ensures`/`invariant`/`decreases`/`effect`/`with`/`in`/`where`/`pure`/`ability`/`effects`/`op`/`result`, derived from `grammar.lark` rather than hand-listed and reachable rather than traps — each declared, was called and answered its value before the fix — over five parametrized batteries (declaration, visibility, `where`-helper, a rationale free of the keyword branch's false unreachability claim, and a usable per-name fix suggestion) with `handle` and fifteen keyword-containing names as controls; and `resume`, reserved on separate grounds — not a keyword, so the declaration parses and outside a handler a bare call reaches it, but it collides with the resumption binding every clause body carries, and the pins cover the rejection, the where-helper depth, that the rationale carries none of the other two branches' false claims, that handler-clause `resume(...)` still checks AND that a wrongly-typed one is still E202 — the pair, since a binding that accepted anything would satisfy the first alone — and that the rejected declaration draws no second error out of the correct clause bodies it used to shadow, at both top level and where-helper depth), parsed module calls (#420 split) | | `test_checker_errors.py` | 73 | 1,196 | Error codes, resolution-coverage diagnostics, contracts, error accumulation (#420 split); cyclic type aliases incl. #1059 self-reference through a type argument (`Future`, mutual `Future`/`Future`, `Array`) rejected E132 | | `test_checker_builtins_collections.py` | 97 | 848 | Map / Set / Decimal / Json / Html / Http / Inference built-in type-checking (#420 split) | | `test_checker_builtins_strings.py` | 122 | 945 | String / numeric / type-conversion / float-predicate / string-search / markdown / regex built-in type-checking, removed-legacy-name regression (#420 split) | | `test_obligations.py` | 775 | 1,741 | Reified proof obligations + warm `VerificationSession` (#222 Phase A): full-corpus differential oracle (warm session == cold `verify()` on diagnostics, summary, and obligation stream, plus warm-twice determinism, across all 43 examples and every verify/run-level conformance program), summary↔obligation tier-bookkeeping consistency (including the #967 `total == tier1_verified + tier3_runtime` leg, plus a focused self-consistency pin on the three call-demotion examples), the #1242 stream partition — over a corpus widened to every conformance program that type-checks, at any level, `len(obligations) == total + violated + tier3_unguarded` and every status is one of the documented five, with the vocabulary read from the `ObligationStatus` Literal so a sixth member fails rather than vanishing from the counts — per-kind unit tests (requires / ensures / decreases / nat_sub / call_pre statuses, counterexamples, error codes), content-key stability + same-text-two-sites span disambiguation, session solver reuse, type-error short-circuit, ADT-registry resync between programs; plus the Phase B incremental suite — identical-source full replay, callee-body-edit replays callers while callee-contract-edit invalidates them, span-shift and ADT-edit conservative invalidation, cross-program isolation, timeout-status never cached (monkeypatched solver), FIFO eviction bound; plus the #727 dedup pin — a violating call in a let RHS records exactly one E501 diagnostic and one call_pre obligation; plus the #1208 call-site rendering pin — a PARAMETERISED callee slot substitutes into the E501 message and its fix instead of falling back to the generic wording | | `test_verifier_contracts.py` | 96 | 898 | Z3 verification over the example corpus, trivial/ensures/if-else/let/multi-clause contracts, counterexamples, tier classification, arithmetic, verification summaries, Diverge effect, edge cases, string-length + string-predicate verification (#839 split) | | `test_verifier_nat_obligations.py` | 82 | 1,743 | **`@Nat` subtraction underflow obligation** (#520 — Path-A discharge via requires/path-conditions/path-aware Z3 refutation, pure-literal exclusion, Int-Int and Nat-Int exemptions) and **`@Nat` binding-site narrowing obligation** (#552/#747/#749 — Tier-1 `value >= 0` at let/call-arg/effect-op-arg/ctor-field/match-bind/destructure narrowing — a concrete site classifies `tier3_runtime` (codegen-guarded) while the effect-op argument and generic-instantiated constructor field classify `E504` (obligated but unguarded, #754/#757) whose rationale names its actual cause — an untranslatable value — rather than the untranslatable-or-timeout conflation #1251 removed, walker-recursion pins, `_narrows_into_nat` verifier/codegen soundness parity; PR #972 clone-instantiated side-table substitution — a `Some(@T)` bind in an `Option`-instantiated clone is no narrowing, genuine clone-path narrowings still obligated); #1201 — a builtin `Tuple` parameter's match-bound components carry their declared component facts (a valid ensures over one proves instead of falsely violating) and an `Int` component bound as `@Nat` fires one loud `E503` per component, both mutation-caught (#839 split) | | `test_verifier_primitive_ops.py` | 39 | 662 | **Primitive-operation safety obligations** (#680) — division/modulo by-zero `E526` and array-index-bounds `E527`, the in-bounds/out-of-bounds two-check with float-exemption, honest Tier-3 for opaque lengths, off-by-one and lower-bound pins, De Bruijn-correct fix hints (#839 split) | | `test_verifier_calls_modules.py` | 81 | 2,199 | Call-site preconditions (incl. branch-aware), pipe-operator verification, cross-module contracts (#839 split); #764 — block translation continues through a `let`-destructure (E501 fires at/after it, De Bruijn component order pinned with a mutation-caught reversed-order check, ensures over the block result proves Tier 1, the #730 statement-position product case, and the pre-fix before-destructure guard); #1199 — an untranslatable `let` value binds a span-keyed opaque constant (violating call after it fires E501, `assert` repairs the proof via #804, two effect-op lets are never provably equal, an ensures depending on the opaque value demotes E522 rather than falsely violating — the taint gate, mutation-caught; a registered user `data Tuple` routes through the registry constructor path, pinned by an isomorphic-rename differential and an uncached-instantiation demotion check, both mutation-caught); #1236 — a GENERIC callee's call-site precondition demotes loudly (E532 Tier-3) instead of vanishing, in the violating direction with the runtime oracle that makes the old all-Tier-1 verdict a FALSE one, in the satisfied direction (conservative until #732 translates the contract per instantiation), and from the ensures-clause drain as well as the body's, against a non-generic twin that is still discharged statically and a `requires(true)` generic that stays silent | | `test_verifier_fresh_scope.py` | 46 | 1,106 | Fresh-scope obligation walking (#779/#985): primitive ops and binding sites inside closure bodies, quantifier predicates, and handler clauses are obligated Tier-3 under the empty fresh-scope slot environment — with scope-honesty soundness pins for BOTH walkers (a closure param or clause payload never proves against the outer requires; mutation-derived, each killing a full-suite-surviving mutant) — quantifier domains, handler state-inits, and handler bodies walk at enclosing-scope full precision (Tier-1 from requires), manifest violations in closures stay loud (E526/E527/E507/E503), a refined closure narrowing discloses `tier3_unguarded` + E506, assert/assume conditions are descended by the nat-binding walker, ensures-position quantifier predicates record Tier-3, a nested closure's return widening/narrowing is reported matching codegen's lifted-closure guards, the #1203 boundary obligations fire through a scalar `State` alias exactly as their codegen guards do (loud E503 init/put through `type Count = Nat`, Tier-1 from requires — #1205 obligation↔guard parity), and the E533 per-instantiation state-declaration recheck is pinned both ways (a concrete `(@Nat = ...)` on `handle[State]` at T=Int is loud with the failing instantiation named; the honest `@T` control is clean with zero `state_decl` obligations) | | `test_verifier_budget.py` | 36 | 285 | #1350 — the configurable Z3 budget. Resolution order (explicit argument > `VERA_Z3_TIMEOUT_MS` > 10 s default), malformed values raising rather than silently reverting, the seams that construct a solver honouring it, and the CLI surface (`--timeout-ms`, the effective budget echoed in `verify --json`, refusal by name on every command that cannot honour it — including the no-file ones that dispatch early, `lsp` worst of all — and `compile` unaffected by a stray env value). The budget's arrival is checked by SPYING on `z3.Solver.set` rather than by timing anything: explicit argument, environment and default each reach the solver, cold and warm, and a warm session and a cold `verify()` given the same budget hand the solver the same number — the differential oracle's property at the plumbing level. Deliberately no wall-clock assertions live here; the categorical control that separates "needed more time" from "cannot see through it" is `test_examples_ephemeris.py::test_transcendentals_stay_tier_3_at_any_budget`, which re-verifies at three budgets instead of measuring elapsed time. | | `test_verifier_adt_decreases.py` | 22 | 822 | Match/ADT verification, decreases measures (incl. ADT decreases), mutual recursion (#839 split) | | `test_mutual_recursive_sorts_881.py` | 15 | 317 | #881 mutually-recursive `data` declarations — Z3 sort construction for a mutual group (issue repro, 3-cycle, one-base-case pair, Float64-field pair) declared together via `z3.CreateDatatypes` rather than recursing unboundedly into fresh sort creation (which otherwise raises a raw `RecursionError` on a check-green program); plus the `Tuple`-mediated cases (self-recursion `MkC(Tuple)` and a well-founded mutual pair through a `Tuple` field), where a fresh `Tuple` sort build re-entered the same `RecursionError`; pins non-FP mutual equality (direct and `Tuple`-mediated) as Tier-1 and recursive-FP mutual equality as a loud Tier-3 (#871 interaction), with a mutation-kill that re-raises `RecursionError` when the direct or `Tuple`-mediated group construction is reverted | | `test_adt_float64_eq_871.py` | 9 | 306 | ADT equality over Float64 fields: per-field fpEQ soundness differentials (NaN, signed zero), multi-constructor recognizer guards, recursive-ADT Tier-3 demotion (#871) | | `test_adt_ord_reject_921.py` | 40 | 676 | #921 `compare`/ordering on a user ADT is rejected (`E242`) rather than returning a silent wrong result — the `Ord` ability op's bare type variable is now constrained to the §4.5/§9.8.1 orderable primitives (`Int`/`Nat`/`Float64`/`Byte`/`String`); covers simple/recursive/enum ADT rejection, constrained-generic accept vs ADT-instantiation reject, the diagnostic naming the offending type, the `ensures`-position no-traceback pin, primitive `compare` still checks + runs, structural ADT `==` untouched, and a Tier-1 verify + false-`ensures` rejection differential | | `test_adt_eq_reject_928.py` | 23 | 447 | #928 `==`/`!=`/`eq` on a non-Eq-derivable type is rejected (`E243`) rather than a silent pointer-identity comparison — the equality sibling of #921; covers function-typed `==`/`!=`/`eq()`, `State`/composite-with-`Map`-field, direct `Map`/`Array`-field ADT reject (upgraded from a late `E613`); positive controls (Int/String/Bool, `Box`, `List`, `Option`, `Result`, nested-generic `List>`) still check + compile + run to the correct structural-equality result; plus the **checker↔codegen Eq-derivability differential** (both real predicates over a shared corpus) and codegen ground-truth pins, mutation-validated | | `test_verifier_refinements.py` | 92 | 2,480 | Refined Bool/String/Float64 param sorts, **refinement-predicate translation + verification** (#746 — Tier-1 discharge at narrowing/return positions, E505 with counterexample, E506 Tier-3 for untranslatable predicates, the R3 already-refined exemption, refined-ADT-sub-pattern arm-fact carry into `@Nat` narrowings and call preconditions, alias-base refined returns, refined returns from match arms) (#839 split); plus the #1214 zero-size-argument differential — `mk(())` and `mk(1)` must record the same `refine_bind`/`violated`/E505 obligation and the same summary, a satisfying call-site precondition must discharge under both spellings, and a zero-size formal sitting BEFORE an informative one must not shift which argument the callee's precondition is checked against, an ERASED argument that is itself a call keeps its own nested precondition obligation (the walk happens, only the result is discarded), and `Future` — direct and behind an alias — is masked as the second zero-size type; plus the #1251 disclosure-honesty set — an E506 over an UNMODELLED base names the base rather than blaming Z3's decidable fragment, a modelled base with a deferred predicate still names the predicate (the over-correction guard), and a SYMBOLIC narrowing keeps its obligation, status and code once the concrete gate lands; plus the #1251(b) concrete-decision set — a LITERAL narrowing over an unmodelled base is decided rather than disclosed (`@Small = 200` is a rejection naming the value, `@Small = 5` a Tier-1 proof, the alias spelling of the cell the same), a predicate the fold cannot settle stays disclosed so the gate is shown to DECIDE rather than widen the base, and `ch02_byte_refinement` is pinned whole — verdict, counts and per-obligation status in order, since counts alone would net out a rejection here against a new proof there; plus the non-verdict split — `check_valid`'s `opaque` (#1199) and `unknown` outcomes get different reasons, driven directly by injecting the outcome since no whole program is known to reach those branches, with two structural pins over `vera/verifier.py`'s AST, both ranging over all three Tier-3 recorders (refinement, `nat_bind`, `nat_to_int_coerce`) and checking that roster against the source so a rename cannot make them vacuous: no demotion site fixes a solver reason at the call site instead of deriving it from `result.status`, and no call that is not literally `guarded=True` omits the reason its disclosure has to state — closed against the two measured escapes (an f-string parses as `JoinedStr`, a shared module constant as `Name`), failing on any `reason=` shape it cannot classify, and reading the module through `inspect.getsourcefile` so it is neither cwd-dependent nor able to inspect a different file than the tests import | | `test_verifier_shadow_audits.py` | 71 | 1,395 | **Per-monomorphization generic verification** (#732 — per-instantiation body verification, collapsed-type-var De Bruijn reindex soundness, one-diagnostic dedup, decreases-only discovery, Tier-3 `E520` residual) and the **#680 shadow/projection audit battery** — 57 differential tests pinning the safe→verified / opaque→Tier-3 / unsafe→loud trichotomy across compound shadows, destructure De Bruijn alignment, opaque match scrutinees, and intra-block scoping; **mutation-validated** (every test flips RED when its target machinery is broken) (#839 split) | | `test_verifier_mutation_obligations.py` | 38 | 888 | #387 mutation-hardening: obligation-record completeness and projection-helper pins (#839 split) | | `test_verifier_mutation_gates_smt.py` | 52 | 1,317 | #387 mutation-hardening: the verifier's soundness-gate predicates, generic-instantiation aggregation/meet logic, and SMT translation pins (#839 split) | | `test_soundness_392.py` | 36 | 584 | #392 audit batches 1–2 — verifier soundness/completeness fixes: signed div/mod truncate toward zero (#799), body `assert(P)` carries a Tier-1 obligation (#800), divisions in contract predicates carry a `div_zero` obligation (#801), and the #804 assume-half of #800's `assert` rule — a prior `assert`/`assume` discharges later obligations (including a later call's precondition) + the postcondition at Tier 1, removing false E501/E503/E500/E505 | | `test_int_overflow.py` | 6 | 143 | #798 — `@Int`/`@Nat` arithmetic-overflow obligations (part of the #392 `smt.py` soundness audit): `+`/`-`/`*` on `@Int`/`@Nat` now emit an `int_overflow` obligation (the analog of `nat_sub`/`div_zero`) rather than modelling the operands as Z3's unbounded integers, so a `ensures(@Int.result > @Int.0)` over `@Int.0 + 1` no longer proves a contract the i64/u64 runtime violates under two's-complement wraparound. Unbounded operands leave the obligation undischarged (Tier-3, runtime-guarded); operand bounds that prove the result stays in range discharge it at Tier 1 | | `test_int_overflow_codegen.py` | 62 | 718 | #798 Stage 3 — runtime overflow-trap codegen: the codegen emits a guard at *exactly* the `@Int`/`@Nat` `+`/`-`/`*` sites the verifier obligates, so `vera run`/`vera compile` programs trap on overflow instead of silently wrapping at the i64/u64 boundary. #808 wired the guard to the `vera.overflow_trap` host import, so the trap now classifies `kind="overflow"` (carrying the overflow Fix paragraph) rather than the generic `unreachable`; `TestOverflowTrapKind808` pins that, with controls proving the #520 `nat_sub` underflow and #813 `@Nat`→`@Int` widen guards still classify `unreachable` | | `test_int_overflow_differential.py` | 259 | 398 | #798 Stage 3 verifier↔codegen classification differential (cross-component soundness rule): the codegen overflow guard must fire at exactly the sites the verifier obligates *and* classify each site's operand type (`@Int` i64 vs `@Nat` u64) identically — else a Tier-1-clean program traps spuriously or a wrapping op slips through unguarded. Over a corpus exercising all five operand combos plus the literal-left ambiguity (a naive codegen mis-classifies it as `@Nat`), asserts the verifier's per-site gated classification equals the codegen's site for site, both sides driven by the same `ast.span_key` | | `test_nat_int_widening.py` | 36 | 602 | #813 — `@Nat -> @Int` widening coercion obligation (dual of #552 `nat_bind`, part of the #392 soundness audit): a `@Nat` in (i64.MAX, u64.MAX] reinterprets when widened (u64.MAX → -1), so a `nat_to_int_coerce` obligation that the value is `<= i64.MAX` now fires at the return position — provably-in-range → Tier-1, provably-out-of-range (`@Nat.0 >= 2**63`) → loud E530, unbounded → honest Tier-3 (runtime-guarded), with an `@Int -> @Int` control that must not fire; the unguarded generic-`@Int`-field case also has its `E531` rationale read for WHAT IT SAYS — a value bounded on neither side, not the untranslatable-or-timeout conflation #1251 removed. The #813 follow-up adds the explicit `nat_to_int` built-in and heterogeneous `if`/`match` arms with a non-negative-literal alternative; #820 adds the heterogeneous-`@Int`-slot arm, closure argument, and closure return/capture obligations (each per-arm / per-site, with `@Int`-arm and `@Nat`-formal controls that must not fire) | | `test_int_widening_codegen.py` | 52 | 535 | #813 Stage 3 — runtime `@Nat -> @Int` widening-trap codegen: the codegen emits a guard at *exactly* the `@Nat -> @Int` coercion sites the verifier obligates (return, `let`, call argument, and — since #820 — array element, tuple construction/destructure, heterogeneous `if`/`match` arm, closure argument/return), so `vera run`/`vera compile` programs trap when a `@Nat` above i64.MAX would reinterpret to a negative `@Int` instead of silently returning the wrong value. The trap is a bare `unreachable` (shares `_emit_negative_i64_guard` with the #552 nat-bind guard), classified `kind="unreachable"` today (a dedicated widening trap kind is a follow-up) | | `test_int_widening_differential.py` | 26 | 320 | #813 verifier↔codegen behavioural differential (cross-component soundness rule): at every `@Nat -> @Int` coercion site the verifier's `nat_to_int_coerce` classification must AGREE with the runtime — a `tier3` (codegen-guarded) site MUST trap on a `@Nat` above i64.MAX (return / `let` / call-arg / constructor field / ADT sub-pattern / match-bind, and the #820 array-element / tuple-component / heterogeneous-arm / closure argument-return sites), while a `tier3_unguarded` (E531) site must NOT trap (the generic-instantiated `@Int`-field coercion codegen cannot guard). Runs BOTH sides on one corpus so the "runtime-guarded" claim is checked against the actual trap — catching a verifier deferral codegen never guards (unsound silent -1) or a spurious trap | | `test_nat_narrowing_return_differential.py` | 136 | 2,897 | #758 verifier↔codegen behavioural differential (cross-component soundness rule): at the function-return `@Int -> @Nat` coercion slot the verifier's `nat_bind` verdict must AGREE with the runtime — an unproven narrowing leaves the return obligation undischarged (loud E503, or an honest `tier3` for an opaque value) and codegen's return guard TRAPS on a negative input, while a proven narrowing (`requires` / path condition) discharges at Tier 1 and the guard is dead (`vera run` returns the value, no trap). Runs BOTH sides on one corpus so "the verifier obligates this return" is checked against the actual guard — the return-position dual of `test_int_widening_differential`. #983 review adds the `tier3` quadrant (opaque `float_to_int`, verify + compile in one run), `let_before_tail` / `nested_if_join` join shapes, a `type Count = Nat` alias case, and threads `file=` + `resolved_modules=` through the verify side for CLI-pipeline fidelity. #1017 adds the `apply_fn` ARGUMENT-narrowing quadrant (the `@Int -> @Nat` dual of the #820 argument widening): a provably-negative arg is E503, a runtime arg is obligated + `call_indirect`-guarded (run traps), a `requires`-bounded arg proves Tier 1, a `@Nat -> @Nat` arg is unobligated, and an opaque `float_to_int` arg records `tier3` with the codegen `i64.lt_s`/`unreachable` guard emitted (verify + compile cross-checked in one pipeline run). #1024 adds the REFINED apply_fn-argument quadrant (`refine_bind`, the refinement dual of #1017): an argument narrowing into a `{@Nat \| @Nat.0 > 0}` closure formal discharges the FULL predicate refined-first — a constant `0` is E505 (clears the `@Nat` base's `>= 0` but violates `> 0`), a runtime arg is obligated + guarded at the lifted closure's prologue (run(0) traps with a `contract_violation` Refinement-violation message), a constant `5` / `requires`-bounded arg proves Tier 1, and a `@Pos -> @Pos` arg is unobligated. #1032 adds the REFINED closure-RETURN quadrant (the return-side dual of #1024): `fn(@Int -> @Pos) { @Int.0 }` records exactly one tier3 `refine_bind` (opaque body — never a false Tier 1), run(-5) AND run(0) trap at the lifted body's return guard with the "return value" refinement message, a satisfying value passes, and the always-satisfying body stays an honest tier3 with no spurious trap — plus the re-derived single-guard pin (exactly one `contract_fail` refinement check in the lifted body, zero `i64.lt_s` narrowing checks). PR #1202 adds the #1203 handler-boundary quadrants (init/put/with/resume × trap/pass/zero, bare-put and clause-body-put dispatch shapes, widen duals at U64_MAX with i64.MAX boundary controls) and the #1205 scalar-alias family quadrants: alias and refined-alias `State` cells compile and run, every #1203 guard keys through the alias (init/put trap on negatives, widen dual at U64_MAX), the alias-equal annotation binds clause slots under its SOURCE name, a stateless handler's clause `@T.0` reaches the op ARGUMENT (the pre-fix capture skew read the cell — pinned in both directions), `Exn` compiles with the payload bound under the clause pattern's name, `old(State)` snapshots through the collapsed family, and the retired lying-annotation fixture is pinned as check-rejected E336. The second adversarial round adds the clause-scope checker-parity battery (mixed-spelling State and Exn shapes bind under the checker's canonicalized argument names, both patternless twins bind nothing, the declaration-scope shadow probe), the parameterised-alias family differentials (`State>`, alias-of-generic-alias, `Exn>`), and the `State` write-boundary battery (init/clause-put/bare-put/`with`/resume literals at i32) | | `test_nat_bind_construction_soundness_1332.py` | 42 | 713 | #1332 — a `@Nat` tuple component narrowed at CONSTRUCTION is obligated, never assumed (part of the #392 false-Tier-1 audit; the construction-position counterpart to `test_nat_narrowing_return_differential.py`'s return-position half). `let @Tuple = Tuple(@Int.0, N)` destructured by an irrefutable single-arm `match` verified as **proved** while `vera run` trapped on a negative: `_translate_match` asserted the arm's `@Nat` sub-pattern source fact UNCONDITIONALLY at the solver's base level, where the datatype accessor axiom reduced it to the construction obligation's own goal — the obligation discharged itself. The anti-circularity test existed but was SYNTACTIC (is the scrutinee AST a `ConstructorCall`?) where a `let`-bound tuple arrives as a slot reference whose TERM is one. Every cell pins the verdict against a control that must not move, because a verdict alone cannot separate the repair from over-rejection: the precondition-discharged form still proves and still runs, the return-position form is unchanged in both directions, and the two construction spellings — with and without the destructure — must agree with each other, which is the internal inconsistency the bug consisted of. The soundness differential asserts the verdict and the run in ONE test (verify-clean beside a trapping run IS the bug, so siblings would each pass alone), with its `requires(@Int.0 >= 0)` parametrisation verify-clean so the implication is exercised with a true antecedent. The REFINED sibling is here too, repaired by the same change and worse in kind — a refined tuple component carries no runtime guard, so pre-fix it returned `-7` for a `PosInt` from a verify-clean build rather than trapping. Two over-rejection controls straddle the guard: one where it FIRES (a tuple built from an already-`@Nat` parameter, whose postcondition still proves from the parameter's own declaration) and one where it does NOT (an opaque `@Tuple` parameter, whose declared source facts must survive). The suite is then parametrised over how the scrutinee is PRODUCED, because a guard asking "is this term literally `C(args)`" is defeated by anything that wraps the construction — an `if` producing the tuple laundered past the first version, verifying both narrowings while the program trapped, and a `match`-produced spelling did the same. Bare constructor, `if` with both arms constructed, `if` with one constructed and one call-produced, `match`-produced and let-of-let are each required to keep the narrowing obligated, in the `@Nat` and refined families alike, beside call-produced and opaque-parameter controls that must keep their facts — the boundary being PROVENANCE: a call- or parameter-produced value's component facts were established in the callee's context, a locally constructed one's are still outstanding | | `test_nested_ctor_sort_1360.py` | 30 | 680 | #1360 — a `Tuple` nested inside a constructor translates, and `verify --json` always envelopes. `let @Option> = Some(Tuple(@Nat.0, 1234));` was check-green and killed `vera verify` with a raw `z3.z3types.Z3Exception: Sort mismatch`, emitting NO `--json` envelope at all. Two sorts derived by different routes disagreed: a nested `Tuple` argument is built by the variadic-tuple branch keyed on the arguments' Z3 sorts (`Nat` reads back as `Int`, so always the `Int` spelling), while the enclosing ctor's sort comes from `_resolve_pinned_sort`, which prefers a cached instantiation equal to the pin MODULO `Nat`/`Int` — sound at a scalar position where both spell one `IntSort`, unsound at a datatype position where #884 made the two injective sorts. The `Nat` appears even in an all-`Int` program because a positive literal types as `Nat` on the declared side, which is why the trigger is the NESTING and not `Nat`; same-ADT nesting (`Some(Some(...))`) is carried as a control, measured passing before the fix, so the repair is pinned to the disagreeing sorts rather than to nesting in general. The envelope half is asserted INDEPENDENTLY of that crash — a translation function is monkeypatched to raise and the cell asserts stdout is a parseable `E699` envelope rather than empty, so the machine-readable contract holds for the next translator bug too — and the pair mutation-validates apart: reverting the sort fix reddens the four translation cells while the controls stay green, breaking the backstop reddens exactly the two envelope cells. A fourth group covers the guard PREDICATE itself: `_ctor_accepts` exists to intercept Z3's raise-instead-of-error behaviour, so a predicate that can itself raise defeats its own purpose — hostile stand-ins whose `arity()`, `domain()` and `sort()` raise must be ANSWERED `False` (the conservative "does not accept", which routes to the decline path) rather than propagate, beside a discrimination cell over real Z3 terms so the group cannot be satisfied by a predicate that swallowed its body and declined everything | | `test_hetero_widen_tailcall.py` | 21 | 312 | The heterogeneous per-arm widen guard vs tail calls (#986) and targets: an arm whose `@Nat` value is a tail call must lower to a plain `call` so the appended guard stays live (`return_call` would skip it — the widening dual of the #983 per-leaf narrowing), the genuine `@Int` arm's recursive `return_call` keeps TCO (100k-depth run), the gate is target-aware (`_is_hetero_int_widen_join`: a hetero join in a `@Nat`-returning context must NOT widen-guard its legal `@Nat` arm — the target-blind gate false-trapped 2^63), and a user `data Tuple` must not take the builtin variadic carrier's target-table path (verifier emits no obligation there; guarding it was an opposite-direction desync) | | `test_xmod_span_collision.py` | 4 | 156 | #987 — the span-keyed target-type table is single-module (keyed by bare span, no file identity): an imported body's expression span can coincide with a main-file entry. #987 threads each module's OWN table into codegen (`CheckArtifacts.module_artifacts` → `_compile_fn(module_tables=...)`), so the engineered line-for-line collision pair now proves the legal all-`@Nat` imported function is not falsely widen-guarded by CORRECTNESS (its own table targets `Tuple`), not merely suppression — with a `thread_modules=False` control pinning the #986 suppression fallback still holds when no module tables are threaded, and a same-file control proving top-level guards unaffected | | `test_xmod_widening_differential.py` | 18 | 293 | #987 verifier↔codegen widening differential run THROUGH THE IMPORT DOOR (the same-file `test_int_widening_differential` was green while this door was open): for each cross-module shape (array-element, tuple-construction, tuple-destructure control, transitive 3-level, and shadowed-import) the library's standalone verify must classify the `@Nat -> @Int` coercion Tier-3, AND the importing program compiled the way `vera run`/`vera compile` compile it (per-module tables threaded) must TRAP at `u64.MAX` — never the silent -1 — while passing `2^63-1` and `42` unchanged. Pins that the #820 array/tuple-construction guards, recovered from the span-keyed target table, now fire for imported bodies. Also pins the import-door trap is the guard's bare `unreachable` net (not some other trap), and a two-independent-libraries-both-widen scenario asserting BOTH imported bodies trap at `u64.MAX` (kills a first-module-only partial-collection mutant) | | `test_xmod_artifact_collection.py` | 5 | 205 | The per-module `CheckArtifacts.module_artifacts` pass is OPT-IN (`collect_module_artifacts=`, default off) because only the codegen-bound callers consume it and it is O(N²) sub-checks in the module count. Pins that `typecheck_with_artifacts` WITHOUT the flag leaves `module_artifacts` empty (the `vera verify` / warm-session path pays nothing) and WITH it collects each resolved module's own table; plus the GAP-1 artifact-level pin — in a transitive fixture (`main -> alib -> blib`) the middle module `alib`'s target table has 2 entries only because its `direct` flags are re-derived from its OWN imports (a first-module-only / top-level-flags mutant drops it to 1) | | `test_xmod_generic_widen_gap.py` | 15 | 413 | #998 guarded differential: an imported **generic** function's mono clones carry their origin module and compile against ITS span tables, so the #820 widen guards fire at every instantiation through the import door. For the array-element and tuple-construction sites × `T=Bool`/`T=Int` instantiations, the standalone library verify must promise Tier-3 AND the importer must trap with the guard's bare `unreachable` at `u64.MAX` (never the silent `-1`) while in-range values round-trip — through both the bare-call and shadowed (`lib::wrap` → `mod$…`) doors, plus a hoisted-where-helper-widen scenario (the per-clone hoisted copy inherits the clone's origin) and a local-generic control (local clones keep the main-file tables) | | `test_xmod_ability_ops_992.py` | 5 | 156 | #992 imported-body ability-op rewrite: `eq` in an imported top-level fn, its where-helper, and a nested grandchild; `compare` (the other AST-rewritten ability op); and the shadowed (`mod$…`, Pass 2.6) door — each runs end-to-end through the import door (a raw call would drop the body and dangle the importer's call) | | `test_xmod_where_helper_import_991.py` | 3 | 190 | A non-generic where-helper's name (#991) no longer suppresses a same-named IMPORT's bare emission — the shadow set is collected from the POST-hoist program, so the import wins outside the parent (spec §5 helper locality) while the parent's body call reaches its own hoisted helper (`go(0) == 701`, both doors observed; a stale bare-name shadow would dangle `unknown func` or silently capture the import-bound call). Controls: a TOP-LEVEL local sharing an import's name still shadows it (§8.5.2), and an UNINSTANTIATED T-unused generic helper's name still shadows (its template still emits bare; dropping it would duplicate the import's bare emission) | | `test_generic_where_helper_990.py` | 10 | 339 | #990 nested-generic monomorphization: a `forall` where-helper under a NON-generic parent is a mono base — the issue repro (direct instantiation), the grandchild variant (all-non-generic ancestor chain), two instantiations (`T=Int` + `T=Bool`) both emitted, and WAT-level single-emission pins (exactly one `gid$Int` clone, no bare `@T` template); plus the #904 control (helper under a GENERIC parent stays hoisted per-clone, no standalone duplicate) and the own-where-child shape (the generic's T-dependent and T-independent children are hoisted per-clone only — the Pass-2 where-fn sweep stops at the generic template) | | `test_codegen_where_helper_mangling_991.py` | 13 | 553 | #991 non-generic where-helper name collisions: parent-qualified mangling (`compute$where$branchA$where$leaf`) so two siblings' same-named nested helpers, and a helper named like a top-level function, compile and run each their OWN body (RUN-value assertions — sibling `leaf`s summing to a value only distinct bodies yield, nested-helper vs top-level both reachable) instead of crashing WAT assembly with `duplicate func identifier`; plus WAT name-scheme pins (top-level names stay bare, nested helpers mangled), full lexical resolution (a grandchild calling an ancestor-scope "aunt", and an inner helper shadowing an outer same-named one), a collision coexisting with a nested generic (`gid$Int` still emitted), the generic-subtree capture battery — a generic helper's call to its OWN nested `shared` must not be captured onto an ancestor's hoisted name (silent-wrong-value shape, the false-Tier-1 verify+run differential, the unshadowed-ancestor-call no-regression guard, and a generic child's name shadowing an ancestor's) — and the CHECKER leg: a differing-signature diamond (`@Int -> @Int` vs `@Int -> @String` leaves) that the flat last-wins lookup falsely E121'd must check clean AND run to the three-subsystem-agreement value | | `test_monomorphize_differential.py` | 62 | 2,191 | #732 differential soundness: the verifier's per-monomorphization instantiation discovery covers every instantiation codegen emits (name coverage + per-generic count), over real generic programs (conformance ch02/ch09, `examples/generics.vera`) plus inline cases for the soundness-critical scenarios — collapsed type vars, **prelude combinator emission** (`option_map`), transitive generics, a generic whose type arg is fixed only by a **where-helper's return** (a `Float64`-returning helper, so the unresolved-var `"Bool"` phantom default cannot mask a miss), a generic whose type arg is fixed only by an **imported constructor** (`id2(MkBox(7))` — the verifier's mono-context must include `_module_constructors`, else it phantom-defaults and misses codegen's `id2`), a generic whose type arg is fixed only by an **imported function's return** (`id_g(make_int(...))` — the verifier's mono-context must seed `fn_ret_types` from imported functions, else it phantom-defaults and misses codegen's `id_g`, plus a **private-shadow** case pinning the imported-fn seeding stays unfiltered like codegen since filtering would diverge into a false Tier-1), and a generic reached only through a **contract clause or `where` helper** (codegen must seed Pass 1.5 from the shared node-level walk, not just `decl.body`, or it skips the clone → `CodegenSkip` at run time) — so a missed instantiation (a false Tier-1) is caught. Guards against a vacuous pass when codegen emits nothing, plus a **determinism guard** (`vera compile --wat` is byte-stable across `PYTHONHASHSEED` — the mono worklist sorts its instantiation sets); plus the #899 **call-rewrite↔emitted-clone differential** (`test_call_rewrite_matches_emitted_clones`) — the THIRD consultor the verifier⊇codegen check never exercised: captures every mangled target the WASM call-rewriter (`_resolve_generic_call`) resolves and asserts each is an actually-emitted clone, over user-fn-return-into-generic-arg shapes (a non-generic user fn returning `Option`/`Result` in `Option`/`Result` position; a scalar-resolving alias `type Age = Int` and a named refinement in bare `@T` position; and a non-generic user fn returning a LITERAL parameterized type `Option<…>`/`Result<…>`/`Box<…>` bound to a bare `@T`, where discovery keys the clone by base name `pick_last$Option` — the base-name key is sound because a bare-`@T` body is representation-polymorphic) — a dangling target is the check-green-then-`run`-drops-`main` desync. All three consultors (discovery, verifier, call-rewrite) route the user-fn-return clone key through ONE shared `declared_return_clone_key`, so they cannot desync by construction. The #898 cross-argument merge (`eq2(MkErr(5), MkOk("x"))` — one argument fixes each of a sparse `Res`'s two parameters) is in BOTH corpora: a symmetric collapse of the merge trips the inline differential's vacuous-emission guard (codegen emits nothing once the type under-determines), and an asymmetric one-sided merge surfaces in the call-rewrite differential as a dangling bare `eq2$Res` clone. The #1274 per-module half lives here too: every QUALIFIED-ONLY module generic (private, out-of-filter, or locally shadowed) must be emitted AND discovered under the same `mod$$name` base, with the complement pinned beside it — a public in-filter unshadowed generic must keep the bare name, or #774's bare-call routing would break in silence | | `test_codegen_expressions.py` | 89 | 787 | Int/Bool/Float64 literals, slot refs, arithmetic, comparison, boolean logic, unary ops, if/let, function calls, recursion, pipe operator, `CompileResult` surface (#419 split) | | `test_codegen_calls.py` | 32 | 1,402 | Statement-position unit calls (#556), **WASM tail-call optimization** (#517 — `return_call` emission, 50K- and 1M-iteration stress, structural `return_call`/plain-`call` boundary assertions, **GC-aware TCO for allocating fns** (#549 — `$gc_sp` restore before each `return_call`), postcondition-fallback regression, analyzer unit tests over tail-transparent constructs), pair-typed closure params + captures (#535) (#419 split) | | `test_codegen_infrastructure.py` | 24 | 455 | Module assembly import/memory conditionals, execute error paths, unsupported-construct skips + node-level E602 reasons (#626), built-in shadowing (#154), typed holes, example round-trips (#419 split) | | `test_codegen_interpolation.py` | 35 | 1,321 | String interpolation, the E615 loud inference-fallthrough channel (#630) (#419 split) | | `test_codegen_effects.py` | 117 | 2,665 | State\ host imports, effect handlers, Exn\ handlers (incl. expression-bodied, #475), Async/Future\, Random effect (#419 split); plus the #841 concurrent-Async battery (`TestConcurrentAsync841`) — fused `async_http_get`/`async_http_post`/`async_await` import pins, sync-import suppression, pure-shape eager pin (no task imports), kind-4 `register_wrapper` structural pin, a generic-fn-with-concrete-Future-return await classification pin, the behavioural two-gets-overlap test (local `ThreadingHTTPServer`, server-side request-log ordering, no wall-clock), and the #843 indirect-closure Ok-path pin (payload byte-exact through `await(apply_fn(...))`); plus the #1109 alias-Future battery (`TestConcurrentAsyncAlias1109`) — alias-typed let, alias-declared fn return, two-hop alias chain, and payload-alias (`Future`) shapes classify for the fused-handle check (import pins + byte-exact Ok payloads), plus the aliased two-gets-overlap behavioural pin | | `test_state_clause_semantics.py` | 27 | 696 | #976 intrinsic-hybrid State clause semantics: clause bodies execute (get-transform 105/30), `with` overrides the intrinsic store (10), the pre-store capture makes `with @T = @T.0` keep-old (7 — the corpus-migration canary); composite (heap) state transform + a captured-pointer-read-after-alloc shape; non-tail `resume` skips loudly; canonical clauses pinned as exact identity (99, and the spec §7.5.3 counter anchor 10); #1006 effect ops as array-literal elements (identity + transforming get clause, and the declared-`effects(>)` helper covering the second op-injection site) | | `test_codegen_data_types.py` | 93 | 1,864 | ADT metadata + constructors, match expressions (incl. nested patterns), tuples (incl. the #902 zero-size `Unit` component in a by-value Tuple / user-ADT layout — construct, match-extract, multi-Unit, Unit in any position, and a side-effecting `Unit`-returning call field `Tuple(IO.print(...), n)` all compile + run; the #1031 transparent `Future` component erasing like bare `Unit` through both let-destructure and match, incl. an alias to the compound and an alias-of-alias chain; and the #1037 alias to a representable compound `type FI = Future` binding a real local through destructure, match, an alias chain, and a standalone let), ADT string fields, generic-monomorphization regressions (#604, #767) (#419 split) | | `test_codegen_structural_eq.py` | 58 | 1371 | Structural `Eq` auto-derivation (#773): String-field ADTs compared by content (distinct `string_concat` allocations), nested-ADT fields compared by value not pointer, 2-level recursion, a recursive generic ADT (`List` — the self-calling `$eq_` function + deep `List` param substitution), a mutually-recursive ADT pair, `P` wrapping `Box`, `Box` under an `Eq`-constrained generic, type-alias fields (alias-to-Int/String/ADT/refinement + 2-hop chains resolve before Eq dispatch), NaN-field runtime consistency with primitive `==`, Byte fields, loud E613 for `Map`/`Array`/`Set`-field ADTs on the generic path AND for direct `==` (Map-field, Md-builtin, ctor-inferred bare generic, and the always-true `Tuple` placeholder), the checker↔codegen derivability differential, the #772 constructor-path lockstep probe, and the #898 sparse-multi-type-parameter probe (a fully-determined `Res` derives + compares by value on the ctor path; the under-determined `id1(MkErr(5))` — `A` free — reports the clearer E619 not the misleading E613; the determined-but-non-Eq `Res` soundness gate stays E613; the cross-argument merge `eq2(MkErr(5), MkOk("x"))` compiles + runs the `Res` clone; a determined-non-Eq cross-arg type is E613; the E619-accuracy split — a recovered non-Eq component `Res>` or a structural non-Eq field `W{K(Array,B)}` is E613, an all-known-Eq free-param case stays E619); and the #923 nested-generic direct-`==` probe (a `List>` / 3-level `List>>` / `Chain>` operand inferred from constructor calls derives + compares by value where a one-level type-arg recovery would spuriously E613; the `eq(...)` builtin form matches; a non-Eq nested component `List>>` stays E613); and the #932 generic-call sibling (the same `List>` / 3-level / `Chain>` nesting reached THROUGH an `Eq`-constrained generic call `eq2(@T, @T -> @Bool)` derives + runs where a one-level clone-path recovery would spuriously E613; a non-Eq nested leaf stays E613 — the fix recurses the derivability-name recovery without changing the mangled clone name) | | `test_codegen_zero_size_fields_1043.py` | 22 | 463 | Registered constructor layouts erase zero-size fields (#1043): the layout differential — registered `field_offsets`/`field_types` for a bare `Unit`, `Future`, or alias/alias-chain field (erased first, last, and multi-erased) match construction's `"unit"` (size 0 / align 1) convention — plus every consumer end-to-end: a wildcard-over-erased nested match extracts the real value (not zeroed fresh-alloc memory), structural `Eq` over an erased field first / multi (equal compares equal, distinct stays false), `show` renders the field as `unit`, `hash` is payload-sensitive (not garbage), no-erased-field controls stay green, and the builtin variadic `Tuple` wildcard-over-erased still LOUD-skips (E602, not silent); a dedicated `Future` end-to-end block (construct via `async(())` + wildcard-match + `Eq` + `show`, exact values) pins that `async(())` construction is not blocked by any skip; mutation-validated (each edit site reverted independently flips its consumer's tests RED) | | `test_codegen_orphan_call_indirect_1185.py` | 9 | 433 | No `call_indirect` reaches the output without a table to dispatch on (#1185), the unclosed half of the #1100 class: an [E602] skip swallowing a module's ONLY closure rolled the lift back, suppressing the `(table)`/`(elem)` sections while every surviving carrier kept its indirect call — an uninstantiable module emitted with zero error diagnostics, raw `unknown table 0` on the first call to ANY export. Both carrier shapes are pinned (the `apply_fn` special form on a closure-typed parameter, and a monomorphized clone of prelude `option_map` — the clone's drop attributed to ``, not to whatever the user's file holds at that line), plus the no-closure-anywhere shape that previously produced NO diagnostic at all; each asserts the [E620] chain names the [E602] root with its location and that the unrelated victim export RUNS (41). Over-correction controls, green before and after: a surviving closure keeps the table so the `apply_fn` carrier is NOT dropped and still computes (107), the `array_map`/`array_fold` emission site likewise (63), and a closure-free program has neither. Mutation-validated — neutering the carrier seeding flips exactly the three orphan tests RED with the controls green, and un-hardening #1100's acceptance helper on the same broken module makes it pass again. The exception-path lift skip (a raise ESCAPING `_lift_pending_closures`, unreachable from a check-green program today) is pinned by a stubbed-lift regression asserting the carrier's [E620] names the root rather than claiming the program creates no closure | | `test_codegen_skip_propagation_1100.py` | 8 | 325 | A codegen skip propagates to (transitive) callers before module assembly (#1100): the repro (helper skipped, `main` calls it — clean [E620] warning naming caller + root, no raw wasmtime `unknown func` text, module still assembles), depth-2 transitive drops in BOTH declaration-order permutations (caller-first needs a second fixed-point round, so a single-sweep propagation goes RED), root-cause naming with the skip's line embedded and the E620 located at the caller's declaration, an untouched public sibling that keeps its export and RUNS (41 — no fallback coincides), mutual-recursion termination (ping/pong cycle + skipped callee drops all three callers, sibling still runs), the closure shape (the dangling call lives in the lifted closure's WAT; the parent drops via the construction edge and the stub keeps table indices valid), and a no-callers control (root E602 only, no E620, everything else untouched); mutations — single sweep, dropped closure edge, dropped stubbing, hop-instead-of-root threading — each killed by a named test | | `test_dropped_entry_1183_1186.py` | 21 | 561 | A dropped entry function is refused, never silently replaced (#1183), and an imported body's skip locates in its own module (#1186). #1183: the repro — declared `main` dropped, one public sibling surviving — exits nonzero with `main` and the root [E602]/[E620] named, and the sibling's 4243 sentinel (a value no fallback, default, or error path produces) never appears on stdout; the same for an explicit `--fn`, for the `--json` envelope (`ok: false`), and at the `execute()` library boundary; `CompileResult.dropped_fns` is pinned as the reified source of the refusal; the `Compilation notes:` block appears when a sibling survives (the ungating); auto-selection survives for the never-declared case and prints a one-line stderr note naming its choice; zero-export `compile` exits nonzero in both text and JSON; and the browser bundle refuses a dropped `main` using the SURVIVING-sibling fixture, so a non-empty export list rules out the zero-export check as the cause. #1186: the root E602 carries the MODULE's path with module-local line/column and quotes the module's source line, the [E620] cross-file prefix fires with its exact wording derived from the root's own location, a same-file control keeps the bare `at line N, column M` form, and `vera test` names the [E602] root instead of calling a public-but-dropped function private. Mutations — api.py refusal, CLI refusal, the E620 drop record, the module source scope, the tester reason, the notes ungating, the auto-select note, the zero-export gate, the browser refusal — each killed by a named test | | `test_imported_trap_source_map_1189.py` | 8 | 342 | An imported function's runtime trap frame names ITS module's file (#1189), the source-map sibling of #1186's diagnostic fix. Fixtures split the basenames (`chinchilla.vera` module, `stargazer.vera` importer) so a frame's attribution is decidable from the string alone, and every trap is a precondition violation so `WasmTrapError.kind` is pinned. Covers the three doors: an imported non-generic fn (pre-fix `` — never registered on the main generator), a monomorphized clone of an imported generic (pre-fix the IMPORTER's path with the module's line range, which in the fixture names a real-but-unrelated importer function), and the `mod$…` emission of a locally-shadowed import (whose rightmost-`$` strip yields nobody's entry). Asserted at the `cmd_run` text backtrace (per-frame line, never the whole stderr blob — `main` legitimately names the importer), the `--json` frames array, `fn_source_map` itself, and `execute()`'s `WasmTrapError.frames`. Over-correction control: a wholly main-file trap keeps the main file, green before and after. Mutations — the module file on the Pass-0.5 registrar, the bare-name harvest, the mangled-name mirror, the Pass-1.5 module source scope — each killed by a distinct named test | | `test_codegen_typeparam_unit_wildcard_1060.py` | 31 | 959 | Wildcard over a type-parameter field instantiated to `Unit` (#1060), the type-parameter sibling of #1043's declared-`Unit` field: a WILDCARD over `Box` field `T` used to advance the match offset walk by the generic `i32` width, so on `Box` (field erased to 0 bytes) every later field read four bytes high — silently check-green. Bug-manifesting shapes go end-to-end (`Box` trailing-`Int`, `Named` `String` read-back, `Entry` nested-ctor tag, `Bool`-following, second-type-parameter, and a nested-generic `Outer` wrapping `Inner` that exercises the deeper-recursion type substitution); controls stay green (before-erased field, trailing wildcards, `Option`/`Result` builtins, `Box`/`Box`/`Tagged` alignment-coincidence, structural `Eq`/`show` recompute path); the direct-call boundary is pinned (#1065) — a `match mk() { … }` scrutinee recovers its concrete instantiation from the callee's declared return type, so a wildcard followed by a read now compiles and reads the real value (`Box` trailing-`Int`, `Entry` nested-ctor, `Named` `String` read-back) instead of the sound #1060 interim LOUD-skip, while a trailing direct-call wildcard still compiles; the generic-call sibling (#1072) resolves the declared return's type variables from the call site (`P2` at T=Int, the var-typed field at `String` i32_pair width, a fully concrete parameterized return on a generic fn, nested-ctor and `String`-read-back variants, plus a trailing-wildcard control), and the module-call door (#1073) routes `boxlib::mk()` — and the imported-generic #1072 x #1073 compound — through the shared resolver into the same recovery; mutation-validated per arm (reverting the #1060 instantiation-awareness flips exactly the #1060 bug-manifesting shapes RED with declared-`Unit` #1043 tests green; reverting the #1065 declared-return threading flips exactly the three direct-call value shapes RED; neutralizing the #1072 generic arm flips exactly the five generic value shapes + the imported-generic compound RED; neutralizing the #1073 module arm flips exactly the two module tests RED) | | `test_codegen_alias_adt_name_width_1309.py` | 112 | 423 | A `type` alias whose name is also a registered ADT's must emit the ALIAS TARGET's width (#1309). Codegen's `_type_expr_to_wasm_type` tested `_adt_layouts` — and `Array`/`Map`/`Set`/`Decimal`, none of them primitives — before the alias table, where the checker's `_resolve_named` resolves primitive, then alias, then declared ADT; so `type Option = Int;` emitted the ADT's i32 pointer for an i64 slot on a check-green, verify-green program. Three dispositions are pinned separately because they fail differently: LOUD scalar targets (`Int`/`Nat` i64, `Float64` f64) died at load; PAIR targets are the SILENT ones the issue's "matching widths" prediction missed — an `i32_pair` is two words and the single i32 dropped the length, so `string_concat("ab", "ab")` returned junk bytes and `array_length` over three elements returned 0, both at exit 0; and matching-width targets (`Bool`/`Byte`/`Map`/`Set`/`Decimal`, all i32) are INERT, kept as green-both-sides guards that the reorder leaves them alone. The battery is the differential that makes width-luck unreintroducible: every name in the LIVE built-in ADT registry (read off a real `CodeGenerator`, so a new built-in joins without anyone widening a list) crossed with every representation class, comparing the emitted `twice` body in full — header widths and the instructions under them — against the identical program under a fresh alias name, plus the two unit duals — under an alias the derivation answers the target's width, without one it still answers the ADT pointer, so "the alias wins" cannot be satisfied by breaking every ordinary ADT parameter. Primitives are asserted to still shadow a same-named alias — the one branch that must NOT move — across all seven spellings by asking the derivation directly, which is the only way to reach every one of them since two are checker-refused (`@Bool.0 + @Bool.0` is E140, `type Int = Int;` is E132); a run-level program carries the behavioural half, because `type Bool = Int;` used AS a Bool is check-green, runs, and distinguishes the hoist mutant. An earlier draft claimed the checker refuses every program that would exercise this, which is measured false. A separate block covers the THIRD consumer of the same disease (CR on PR #1323): `_return_type_is_string` tested the `Future` transparency strip before the alias table, so under `type Future = Array;` a `@Future` return was classified a string and `execute()` decoded the array's backing bytes as UTF-8 — two NULs where the fresh-name control printed the pointer, measured identically at the branch point and so pre-existing. `String` stays ahead of the alias branch there too, being the one primitive involved, and three over-correction controls hold the #841/#1047 transparent-`Future` decode and PR #1041's alias-to-`Future` shape. `Json` and `HtmlNode` are deliberately outside the prelude-ADT row: their prelude combinator bodies render against the flat alias map a main-file shadow pollutes, which is an alias-env SCOPING defect (#1316) the reorder does not reach — though it does MOVE that failure (17 prelude `json_*` signatures flip width, the loader's complaint reverses direction, `html_attr` loses a push), so "fails identically" — an earlier draft's wording — is measured false | | `test_codegen_pair_scrutinee_1305.py` | 32 | 685 | A `match` whose SCRUTINEE is pair-represented (`String` / `Array`) took one local at the internal `i32_pair` pseudo-type, so the module carried `(local $l1 i32_pair)` and never assembled (#1305). The issue reached it through `json_keys` and framed it as an `Option>` payload binder; the docstring records why measurement does not support that — `json_keys` returns `Array`, and `array_length(json_keys(j))` compiled and ran at the branch point — so the tests are built on the shapes that actually trigger it: `match @String.0 { @String -> … }` and `match @Array.0 { @Array -> … }`, both legal and check-green, plus the slot, call-result and builtin-result scrutinee forms. One test returns the BOUND STRING rather than its length, because a fix that allocated two locals and copied only the pointer passes every length-free assertion. The issue's own repro matches `Some`/`None` against that array; a pair carries no tag, so the assertion is that the module assembles and the refusal is a located E602 — not that the nonsense compiles (the checker accepting it is #1315). The guard is a WHITELIST (wildcard and binding only) and these cells are why: as a blacklist naming the two constructor kinds it let `true ->` and `1 ->` fall through into the arm-condition emitter, turning a loud WAT failure into a check-green program that exits 0 printing 100 from the scrutinee's heap POINTER read as a truth value, and its integer twin into a shipped `.wasm` that died at instantiation with no diagnostic — so five unlowerable-arm cells (bool/int/string literals over both pair spellings) and a nullary-arm-FIRST program pin each half, the last because both original repros led with `Some` and left the nullary half droppable green. The two shadow pushes are pinned as EMISSION by a WAT differential against the match-free twin (exactly two more push idioms) plus a position assertion that no length half is rooted: deleting both pushes leaves the whole suite, the GC rooting and reclamation suites, and four allocate-in-the-arm probes under `VERA_EAGER_GC=1` green, so a behavioural claim would be one no probe supports. The two controls the issue listed as already-compiling are kept as regression guards, and an Option/Result binder battery over `Array`/`Array`/`Array`/`Map`/`Set`/`String`/`Int` payloads plus a nested `Option>>` pins the boundary: the scrutinee change left pair-typed constructor FIELDS alone | | `test_codegen_erased_alias_typeargs_1070.py` | 15 | 398 | Non-literal erases-to-Unit type ARGUMENTS (#1070): `Box` (`type U = Unit;`), `Box>`, `Box`, and alias chains — the #1060 width recomputation's zero-size test was the literal name `Unit`, so these spellings got 4 bytes and every later field read a shifted offset (silent 22→0, nested 314→0); the same literal-test disease made structural `Eq` over the same spellings fall back to the scalar POINTER compare (pre-existing — equal structs compared unequal, silently) and `show`/`hash` loud-skip. Pins every spelling end-to-end: wildcard reads (trailing `Int`, nested ctor), `Eq` equal/distinct + `Future` arg, `show` renders `unit` + the real fields, `hash` payload-sensitive + deterministic, literal-`Unit` controls; the rider — a zero-size `@Unit` BINDING after an unrecoverable wildcard is not a read (compiles), while a genuine read beyond it still LOUD-skips (E602); mutation-validated per site (width fn, field-name canonicalisation, both dispatch gates, derivability gate, rider — each flips exactly its own test subset) | | `test_codegen_alias_typeargs_eq_1076.py` | 34 | 499 | The Eq-dispatch ground-spelling cluster (#1076/#1077/#1078). #1076: structural `==` over NON-Unit alias type args (`Box`/`MyStr`/`MyBool`/`Future`/chains) silently pointer-compared (equal structs → 0, check-green) — equal AND distinct pairs per spelling, i64-width pins with >2^32 payloads whose low 32 bits collide, `MyStr` content-vs-pointer compare, plus the #1060-walk width shapes (`Bool` follows the type-param field, so an i32-sized `MyInt`/`MyStr`/`Future` manifests); a genuine free `T` (dead base-generic clone, #912) still compiles via its scalar fallback. #1077: `show`/`hash` of `Tuple` (raw-args Tuple plan branch) and of bare aliased-Unit values (literal-name top-level arms) loud-skipped — all four now compute (exact renders, payload-sensitive hash), literal controls pinned. #1078: element-wise `==` on arrays of parameterized ADTs (`Array>`, literal included) pointer-compared (the `IndexExpr` operand's element head drops its type args) — equal/distinct/`>2^32`/aliased-element shapes, non-generic-array + direct-compare controls; mutation-validated per site (canonicalization helper, width fn, both dispatch gates, derivability gate, Tuple plan branch, top-level Unit arms, IndexExpr recovery arm — each flips exactly its own subset) | | `test_codegen_alias_of_adt_eq_show_1085.py` | 49 | 1,140 | The alias-of-ADT / forall-Eq / bare-Future dispatch cluster (#1085/#1086/#1087 + the PR #1090 review round: #1091/#1092), siblings of #1076/#1077 at entry points the ground-spelling pass never reached. #1085: structural `==` over an alias of a WHOLE ADT (`type MyBox = Box;`, `@MyBox.0 == @MyBox.1`) silently pointer-compared (equal structs → 0, check-green) — the operand reaches the dispatch as the bare alias name, absent from `_adt_type_names`; equal AND distinct pairs, i64-width `>2^32` low-bits-collide pins, `String`-content, non-generic-ADT and alias-chain shapes, direct-compare control, plus the refinement-over-whole-ADT `==` (`type NB = { @Box \| true };` — the same silent pointer compare, equal + distinct pins). #1086: a `forall>` instantiated at an Eq alias (`@Box`) wrong-loud E613'd (the top-level constraint gate misses alias / `Future` spellings) — equal / distinct / i64 pins for `MyInt` and `Future`, an alias-of-whole-ADT positive, plus a non-Eq alias (`Array`) differential (still E613, never the codegen E699 — gate↔codegen lockstep, #732). #1087: `show` / `hash` of a bare or aliased `Future` value loud-skipped (E602) — the inferred type reaches the top-level dispatch un-peeled; aliased + bare `Future` / `Future` renders, payload-sensitive i64 hash, plain-Int + aliased-primitive + refinement controls. #1091 + composite-Future (PR #1090 review): the composite path's `_parameterized_arg_type` recovery UNDID the grounding — bare/aliased `Future>` show+hash, alias-of-whole-ADT show/hash (`type MyBox = Box;`, `type MB = Box;`), `@Array` slot + array-literal element grounding, with Tuple-component and ctor-argument GREEN pins (grounded at plan consumption, #1076/#1077). #1092: an in-range int literal coerced into a `@Byte`-instantiated generic ctor field was stored i64 while every reader sizes i32 — `MkB(0) == MkB(255)` silently equal, extraction read 0 for a stored 255; distinct + equal + extraction + aliased-forall-Eq shapes through the full checked pipeline (`_run_checked` threads the checker's target-type table exactly as the CLI does), passthrough + `Int`-instantiation controls; mutation-validated per site (operand grounding, gate fallback, show + hash grounding, recovery grounding, Array-arm element grounding, Byte width coercion — each flips exactly its own subset) | | `test_composite_postcondition_eq_912.py` | 16 | 492 | Composite (`Box`/`Option`/nested-ADT) `==` in an `ensures` postcondition lowers its runtime check to STRUCTURAL equality, not a pointer compare (#912): true `@T.result == ctor` postconditions run without a spurious `Postcondition violation` trap in both operand orders, the `E500`+runtime-trap negative controls prove a false composite postcondition is still rejected by `vera verify` AND traps, and a Tier-1 verify pin; a function generic over the parameterized ADT itself (`fn id2(@Box -> @Box)`) with a slot-vs-slot postcondition compiles + runs — the free-type-var scalar fallback affects only the DEAD base generic clone, while the reachable monomorphized clone lowers the `==` structurally (pinned by a `rebox` test where a FRESHLY-constructed, structurally-equal, DIFFERENT-pointer result is Tier-1-verified AND runs without trapping, plus a WAT assertion that the reachable mono clone's postcondition uses `call $eq_` not `i32.eq`); a genuinely non-`Eq` contract composite (`Box>`, `Tuple`) is a clean `E613` not an uncaught crash — mutation-validated (neuter the `ResultRef` arm → left-`@T.result` run tests AND the `rebox`/structural-WAT pins flip RED; neuter the free-type-var routing → the `Box` run tests flip RED via the dead-base-clone `E613`; remove the postcondition backstop → the clean-`E613` tests raise an uncaught exception) | | `test_contract_predicate_degradation_922.py` | 9 | 250 | A non-`Eq` composite `==` / unsupported `hash`/`show` in a CONTRACT-PREDICATE position degrades to a clean diagnostic, never an uncaught Python traceback (#922): a `Tuple == Tuple` in a `requires` or a `{ @T \| P }` refinement guard is a clean `E613`, a `hash(recursiveADT)` in a `requires`/`ensures` is a clean `E602` (the #912 postcondition backstop caught only `AdtEqNotDerivableError`, not `CodegenSkip`); regression pins that valid contracts (primitive `==`, derivable-ADT `==`, refinements over primitives, primitive postconditions) still compile + run, plus a cross-check that the #912 concrete-`Tuple` postcondition still degrades to `E613` — mutation-validated (neuter each new catch → its repro re-crashes with an uncaught traceback) | | `test_codegen_arrays.py` | 242 | 4,467 | Byte type, array literals / bounds checking / length / range / concat, direct indexing of builtin call results (#1048, #1051, alias-canonicalized #1055), `array_flatten` of inline nested literals + type-variable builtins nested as call arguments + alias-spelled / user-fn call-emission arguments incl. the Map/Set host-import tag inference (#1052, #1053, #1063), nested-alias element classification (#1067), generic-alias container returns (#1068), bare-alias returns + Block args (#1071), `Future` element sizing (#1074), map/mapi/fold closure-return `Future` sizing incl. the fold SlotRef-init fallback (#1079), the post-#1041 `Future` map stride-desync regression (#1081), collection-alias `Array>` payload canonicalization (#1082), construction builtins (#209), compound element types (#132), array utilities (#419 split) | | `test_array_map_slot_closure_1056.py` | 10 | 227 | #1056 — a fn-typed slot (`@Mapper.0` where `type Mapper = fn(A -> B)`) as the closure argument to `array_map` / `array_mapi` / the `array_fold` accumulator: let-bound and parameter slots, type-changing `Int -> String` mappers (map and mapi), chained two-slot maps, order-pinned mapi and fold (non-commutative, non-literal initializer), an `apply_fn`-parity pin, and the inline-`AnonFn` control | | `test_codegen_refinements.py` | 72 | 1,208 | Assert/assume, forall/exists quantifiers (incl. WAT inspection), refinement type aliases, **refinement-predicate runtime guards** (#746 — primitive- and `@Array`-base boundary guards, `@Byte`-base i32-width guards incl. `@Byte`-returning fn-call operands + `0..255` range conjoin (#766), tuple-component decomposition at the FFI boundary, generic tuple aliases, infinite-alias E617 fail-closed, refinement-over-tuple unwrapping, zero-size base guard-skip for `@Unit` **and** `@Future` (#943)), head-over-refinement shape (#655) (#419 split) | | `test_codegen_strings.py` | 113 | 1,266 | String literals + IO host bindings, WAT string escaping (unit + end-to-end), String/Array signatures, format expressions, core string ops (length/concat/slice/char codes/repeat), char classification, string utilities (#419 split) | | `test_codegen_string_builtins.py` | 153 | 1,341 | parse\_nat/float/int/bool (Result-returning), base64, URL encode/decode/parse/join, search/transform builtins (#198), universal to-string (#106) (#419 split) | | `test_codegen_numeric.py` | 86 | 1,104 | Math builtins (#199), numeric type conversions (#208), Float64 predicates + constants (#212), int64-min / float-carry to-string regressions (#475) (#419 split) | | `test_codegen_io.py` | 42 | 821 | IO operations (#135: read\_line, read\_file, write\_file, args, exit, get\_env, sleep, time, stderr), Markdown + Regex host bindings (#419 split) | | `test_codegen_collections.py` | 69 | 1,141 | Map + Set collections (#62), wrapper-handle bit-31 tagging (#578) (#419 split) | | `test_codegen_json.py` | 116 | 1,112 | Json collection, typed accessors (#419 split), canonical serialization (#1293 — `format_json_number`'s ECMAScript boundaries and `dumps_canonical`'s shape, insertion-ordered keys, non-finite refusal, and rejection of values outside `read_json`'s domain) | | `test_json_accept_domain_1306_1308.py` | 97 | 720 | `json_parse`'s accepted domain on the reference host (#1306, #1308): spec §9.7.1 states it as RFC 8259-valid text that decodes to finite numbers and strings of Unicode scalar values, and all three exclusions are pinned end-to-end through a compiled program that reports which arm it took plus the whole `Err` message — the JavaScript constants at the top level and nested in containers, with the first of two naming the refusal; a number that OVERFLOWS to an infinity (`1e999`, `-1e999`, `[1e999]`, `{"a":1e309}`, `1E999`, `[[1e999]]`), the second entry route to a non-finite `JNumber` and the one both host parsers accepted, so it diverged from the stated domain on both hosts at once rather than between them; the same overflow in its INTEGER spelling (`1` followed by 309, 310 and 400 zeros, signed and nested), which was reference-host-only because `json.loads` returns an `int` there and a float-only range check never saw it, with the bound pinned as the double ROUNDING boundary against `float()` as oracle and `int(sys.float_info.max) + 1` as the control that separates it from the obvious-but-wrong bound; and a lone surrogate parameterised over position (value, key, array element, nested, top-level string) and escape casing. The controls carry the weight the refusals cannot: matched surrogate pairs (single, adjacent, at end of string, literal astral) still parse, `1e308` / `-1e308` / the largest representable double still parse so the overflow refusal is a boundary and not a wall, **underflow is decided rather than assumed** (`1e-999` decodes to `0`, finite and in the domain, so it is accepted — the plausible wrong answer is symmetry with overflow), `"NaN"` as a string value and as a key is ordinary JSON, and text malformed for any other reason keeps its host-native syntax message — the constant-lookalike shapes (`[Infinity_x]`, `{Infinity:1}`) that a raise-on-sight `parse_constant` hook would have misreported, which is why the hook records and the refusal is decided after the parse, and the sign/case shapes (`-NaN`, `[-NaN]`, `+Infinity`, `infinity`, `nan`, `-Infinityx`) that a token scan without a value-start constraint would have claimed. Unit tests on `first_domain_violation` — the ONE document-order walk both value-level exclusions share, so "whichever comes first names the refusal" needs no precedence table — pin the traversal directly (key before its own value, earlier entry before later, D800/DFFF inclusive at both ends, an `int` and a `bool` never read as a non-finite number, and the NaN arm that no JSON text can reach) where the end-to-end probe can only observe the first refusal. The cross-host half is `TestBrowserJsonAcceptDomainParity1306_1308` in `test_browser.py` | | `test_codegen_decimal.py` | 57 | 779 | Decimal collection, Decimal monomorphization (#419 split) | | `test_codegen_host_effects.py` | 71 | 1,135 | Html/Http/Inference host effects, provider dispatch, postcondition host-import propagation (#823) (#419 split) | | `test_inference_response_shapes_1333.py` | 164 | 2,131 | #1333 — `Inference.complete` parses a provider response by SHAPE, not by position. The Anthropic Messages API returns `content` as a list of TYPED blocks and a reasoning-capable flagship leads with a `thinking` block, so `content[0]["text"]` raised `KeyError('text')` and the host boundary published the bare key `'text'` as the whole `Result::Err` payload. Three properties, one per defect: selection by `type` across both response families — the OpenAI-style `message.content` is a string, a list of typed parts, or `null` on a reasoning turn, where the old `str(...)` returned the literal completion `"None"` — with a selected entry's `text` itself required to BE a string, the review having found the same coercion one level deeper, where `text: null` became that completion and an object became a Python repr; every shape failure and HTTP rejection naming the provider AND the model that answered, with the error body read under a 64 KiB cap so the message bound is a memory bound too, every interpolated field routed through the same 200-character limit, and the configured key plus any credential-shaped token redacted before it can reach a Vera value — on every route, a table of twelve parametrized rows standing in for the invariant after a review pass found the non-JSON-body path unredacted, a sweep found six more, and a second pass found four render sites whose `api_key` could be dropped with nothing red; two structural tripwires now hold it — the count of `api_key`-carrying render sites, read by an AST walk rather than a regex (which undercounted the same source by one and could not see a positional key in a multi-line call), and the row count itself, since deleting a row was invisible to the first and left the suite green one cell lighter. An empty or whitespace-only completion is an error only when the provider explained it — `stop_reason` `refusal` or `max_tokens`, `message.refusal`, `finish_reason` `length` — with the reason matched case-insensitively and the token carried verbatim into the diagnostic, and a response with no block or part of the selected type at all reported as an error naming the types that were present, and the blank test is `.strip()` on both the string and list paths, which is what round 9 claimed and delivered only for the exactly-empty fragment, which is what makes the sweep's own misattribution impossible to repeat — with `VERA_INFERENCE_PROVIDER` unset, auto-detect takes the first key set to a non-empty value in registry order, so a still-exported Anthropic key won the "xAI run"; and a boundary that labels any exception this module did not itself write. The verbatim channel belongs to a dedicated `InferenceError` and nothing else: the original rule named plain `RuntimeError` / `ValueError` by exact type, which the PR review refuted — those are the types an unforeseen transport failure raises too, so `RuntimeError("boom")` from below claimed the channel and surfaced as the bare `boom`. The headline cells run END TO END through `execute()` over a mocked `urlopen` — the product path the report came from — with the six-provider sweep parametrized in registry order, its rows pinned against `_PROVIDERS` so a new provider cannot silently leave the sweep. Mutation-checked, every count re-measured on the tree as it stands: the by-position read 45, the boundary's plain-type rule 18, the shared redaction helper 28, the boundary label 8, the `str()` coercion 8, the missing-`text`-key skip 7, the reason clause 21 (the same whether its function body is emptied or all four call sites are neutralised — an earlier note claimed the two forms differed), the `output_text` preference 6, the empty-completion rule 10, the blank test's truthiness revert 4, the reason's case fold 3, the `xai` credential prefix 3, the strict `.decode("utf-8")` 3, and the narrower one-to-three-cell guards (redact-before-truncate, the exact-key rule, the `output_text` preference, the truncation window's start, the "(no keys)" honesty rule, the credential pattern's eight-character floor, and the three bounded-read guards). Every `pytest.raises` in the file names `InferenceError` rather than `RuntimeError`: the class is a `RuntimeError` subclass, so the looser assertion accepted a site regressing to a plain one — making that regression fails 15 cells now against 2 before. The plain-type figure had read 5 with the drop blamed on cells bypassing the boundary; that was wrong. Threading the model into the boundary label made it a prefix of itself, so eleven `startswith` cells matched the wrapped message they existed to reject and lost discrimination silently — they now assert the label's absence too, via one shared helper, and the figure went back to 16, rising with each `_assert_deliberate` cell added since | | `test_codegen_nat_guards.py` | 61 | 1,435 | **`@Nat` runtime guards**: subtraction underflow (#520) and binding-site narrowing (#552 let site; #747 tuple-destructure / match-bind / ADT sub-pattern / ctor-field / call-arg sites; #758 per-leaf function-return guards incl. type-alias returns and TCO preservation on mixed-arm tails — `i64.lt_s; unreachable` net, `@Int` targets exempt) (#419 split); #758 `@Int -> @Nat` return-position guard; #983 review adds alias-aware return gates (`type Count = Nat` narrow, `type MyInt = Int` widen), the alias-to-refinement single-guard exclusion, and the per-narrowing-leaf emission that keeps a non-narrowing `@Nat -> @Nat` recursive tail call's `return_call` (TCO) intact. #1256 extends both alias-aware gates to a parameterised alias APPLICATION (`type Ident = T; type Count = Ident;`), which the name-only chase resolved to the bare head `Ident` — so neither gate fired and `f(0 - 5)` returned -5 through the `@Nat` slot, #983's silent negative one spelling over. Each parameterised case carries its unparameterised twin as the oracle (the claim is that the two spellings compile to the SAME guard, which a bare presence assertion would not catch losing), plus the run-trap on the violating value, the pass on a satisfying one, and the refinement-over-application control that pins the `_refinement_guard_parts` conjunct still keeps a refined return single-guarded | | `test_codegen_translator_fixes.py` | 27 | 528 | WASM call-translator regression fixes (#475): string/array slice clamps, char-code bounds, URL/base64/parse edge cases, map-array-value rejection (#419 split) | | `test_codegen_gc_alloc.py` | 39 | 892 | Layout helpers, bump allocator, GC core (#515), shadow-stack overflow, multi-page grow (#487), worklist overflow (#348) (#419 split) | | `test_codegen_gc_rooting.py` | 38 | 1,560 | Opaque-handle param rooting (#347, #490), host-walker GC rooting (#692), Map host-store reachability (#695), ADT-builder rooting (#743) (#419 split); plus the #841 Future-handle battery (`TestFutureHandleGCRooting841`) — eager-GC survival across an intervening alloc, the operand-stack window (`both(async(A), async(B))` with get/post-distinguished Err text), Phase-2c reclamation of fire-and-forget futures via `host_store_sizes["future"]`, and repeated-await memoization; host-import pair-let rooting (`TestHostImportPairLetRooting846`) — `IO.args` / `IO.read_line` pairs surviving an intervening alloc under eager GC, with `IO.read_file` / `IO.get_env` ADT-path confirmation; and the `_ShadowGuard.push` slot-complete bound (`TestShadowGuardPushBound791`) — partial-headroom / full-window / negative-`sp` rejection and the exact-final-slot accept boundary, constructed directly on a hand-rolled module | | `test_codegen_gc_reclamation.py` | 21 | 706 | Transient Map/Set/Decimal reclamation (#573; scale trio marked `stress`, #738), bucket occupancy (#706), SameValueZero keys (#743) (#419 split) | | `test_codegen_contracts.py` | 33 | 601 | Runtime pre/postconditions, contract fail messages, old/new state postconditions, the #958 tier-agnostic always-emit pin | | `test_codegen_decreases_guard.py` | 24 | 859 | The #1172 runtime termination guard: non-terminating measures trap through the contract channel instead of hanging (the issue's ADT repro, constant/growing/negative-floor scalars, a lexicographic violation, mutual `where` recursion), terminating programs run clean with the guard emitted (Tier-1 countdown, the corrected spec Ackermann, sequential siblings pinning the exit restore, a concrete ADT measure), the tier3-obligation ⇒ emitted-guard differential, E127 rejection of non-well-founded measures (Float64/String/Bool and a lex component) plus acceptance of the well-founded family, and the parameterized-ADT-measure no-guard pin (#1177) | | `test_codegen_monomorphize.py` | 258 | 5,102 | Generic instantiation, type inference, monomorphization edge cases, ability constraint satisfaction (Eq/Ord/Hash/Show), operation rewriting (eq/compare), show/hash dispatch (incl. structural show/hash for composites, same-base finite nesting, and `_split_param_type` — #911; recursive-ADT show/hash via a generated self-calling helper, deep-list termination + GC-frame `$gc_sp` restore, non-generic mutual recursion — #924), ADT auto-derivation, array operations (slice/map/filter/fold), nested `where`-helper emission on the non-generic path (#978/#989 — a grandchild helper using `eq`/`compare` in its body or contracts must have its ability op rewritten so its body is emitted, and a node with two nested helpers emits both) | | `test_codegen_nested_nullary_ctor_994.py` | 7 | 229 | **#994 F2 nested payload-less constructor in a `forall` `==`/`!=`** — the #979/#981 checker adoption newly accepts `ensures(Some(None) == @Option>.result)` under `forall`; `check`+`verify` passed but `compile` raised a spurious E613 because the structural-Eq derivation erased the type argument (the inner `None` renders bare `Option`, so `Some(None)` recovers as `Option