Integration testing — v0.13.0
Session run: 2026-09-06 · against develop at 5ca689c8 (post the changelog
gap-fill / gitlink bump, metel-core#1027) · re-run of /milestone-integration-test
(metel-core#956). The 2026-09-03 report was written against develop at 9adde73;
38 commits landed after it — including the fixes for that session's own findings
(metel-core#958, #959, #960) and the aspect-registry-per-module fix (#989) — so it went
stale and this session repeats the gate on the frozen tree.
Result: PASS — clear to release. No findings.
Freeze reconciliation (2026-09-06): two commits landed on
developafter5ca689c8and before thev0.13.0tag —17d5dadf(this session's own two cross-feature fixtures, metel-core#1028) and2d2b9ea2(theevaluator.mdv0.13.0 doc pass, the crate version bump to0.13.0, and thedocsgitlink bump, metel-core#1029). Neither touches language-visible behaviour, so the PASS above stands against the frozen tip2d2b9ea2unchanged.
Features exercised
Named by capability. Cross-checked against the 4-implemented RFCs with
target: v0.13.0, the ## v0.13.0 changelog section (feature blocks + Fixes), and the
3-integrated RFCs that shipped in slices this milestone.
- pipe-notation closures / function types — RFC-0154 (#…), superseding RFC-0041
- capture lists + capture default
move— RFC-0050 (#926) / RFC-0157 D5 - closure qualifiers
once/var+ same-value re-entrancy guard (R0015) — RFC-0134 (#927) / RFC-0153 (#929) - written function types are move-only — RFC-0166 (#947)
- function-type multiplicity widening (
many→once,reading→var, first-order) — RFC-0152 - type aliases (
type X := Y;, transparent, parameterised, cross-module, value/pattern position) — RFC-0160 (#921) - struct row narrowing + widening (move a field →
Handle.{ fd }residual; reassign → widen) — RFC-0137 slice 2 (#858) - anonymous-record row narrowing — RFC-0117 (#789)
--move-checknarrowing-aware + path-sensitive acrossif/matcharms — RFC-0071 (#950) / #958- aspect objects —
dyn Aspect(existentials, object safety, coercion,List<dyn Aspect>) — RFC-0008 (#865/#866/#870/#864/#872) - struct pattern matching + row-bounded
{ x, .. }rest — #753 / #755 / #646 - parenthesized
match (x)scrutinee — RFC-0156 (#701) - generic functions as first-class values — RFC-0138 (#736)
Also in range but not interaction axes: extends Aspect keyword rename (RFC-0130), aspect
method generic-constraint conformance (RFC-0129, #746) incl. the per-module aspect-registry
fix (#989), Self::AssocType / Self.{ field } in extend blocks (#740/#774), array
literal defaults to T[] (#715), turbofish argument checking (#775), and the R0012
phantom removal / R0013–R0016 → R0012–R0015 renumber (#983 — a code shift, exercised by
its own per-PR fixtures, no pairwise interaction).
Interaction matrix
The diagonal (single feature) is covered per-PR — skipped. Off-diagonal pairs are marked:
✓ path a corpus fixture exercises both in one program · probe verified by an ad-hoc
program this session, no committed fixture (reason given) · n/a the two cannot
meaningfully interact.
High-risk pairs (both features touch the same subsystem — move/ownership, type inference, closures, or pattern matching):
| pair | status |
|---|---|
| capture list × closure qualifier | ✓ the v0_13_0_* closure corpus (~40 fixtures) |
| capture list / qualifier × written move-only fn type | ✓ evaluator/closures/v0_13_0_x_mutating_closure_via_written_var_fn_param, …/v0_13_0_written_fn_type_move_only, typechecking/structs/neg_49_struct_pattern_move_only_fn_field_used_twice |
| closure qualifier × multiplicity widening | ✓ v0_13_0_many_widens_to_once_slot, v0_13_0_widened_reading_keeps_plain_dispatch, v0_13_0_neg_once_does_not_widen_to_many |
| move-capture closure × struct row narrowing | ✓ evaluator/closures/v0_13_0_x_move_capture_of_narrowed_struct |
| written move-only fn type × type alias | ✓ evaluator/type_aliases/01_basic_and_parameterised, …/04_cross_module, …/05_reexport (type Transform := |Vec2| -> Vec2) |
| multiplicity widening × type alias | probe — a many closure widens into an aliased once |i64| -> i64 slot and calls once (= 42). The alias erases to the written type before the multiplicity check, so this is the widening path already covered above; a dedicated fixture would be redundant. |
| type alias × struct row residual | ✓ evaluator/structs/108_alias_qualified_method_on_narrowed_receiver |
type alias × dyn Aspect | ✓ new evaluator/type_aliases/v0_13_0_x_alias_for_dyn_aspect — type Glyph := dyn Draw; erases transparently: coercion into it, dynamic dispatch through it, List<Glyph> heterogeneous (total 13) |
struct / record row narrowing × --move-check | ✓ typechecking/structs/neg_50_narrowing_one_arm_move_taints_join, evaluator/structs/110_narrowing_if_arms_independent, …/111_narrowing_match_arms_independent |
struct pattern × row narrowing/widening × parenthesized match | ✓ new evaluator/structs/v0_13_0_x_struct_pattern_partial_move_narrows — a match (h) struct pattern binds a non-Copy field: h narrows, a still-present field stays readable, reassigning the moved field widens back; green under --move-check |
path-sensitive narrowing × match arms | ✓ 110 / 111 / neg_50 (arm-local moves, join = union) |
| struct pattern × generic bound in arm body | ✓ typechecking/generics/struct_pattern_preserves_generic_bound_in_arm_body |
struct pattern × parenthesized match scrutinee | ✓ every struct-pattern fixture is written match (x) { … } |
dyn Aspect × same-named aspects across modules / generic aspect methods (#989) | ✓ evaluator/aspects/989_* family (7 multi-file fixtures) + typechecking/aspects/989_wrong_aspect_method_still_rejected |
dyn Aspect × move-capture closure (heterogeneous List built from a closure) | probe — List<dyn Tag> filled from a [base]-capturing closure returning a concrete type; dispatch sums to 23 |
| generic function as value × written move-only fn param | probe — let f := identity; apply(f, 3) == 3 with apply(f: |i64| -> i64, …); f pins at the arg position and moves in, stays polymorphic for identity("hi") |
No-interaction pairs (recorded, not filled): dyn Aspect × struct pattern (a dyn
value is opaque — no fields to bind); closure qualifier × dyn Aspect (a closure cannot
implement an aspect — v0_13_0_neg_closure_no_aspects); parenthesized match scrutinee ×
anything (a pure spelling rule — the migration rewrote every match in the corpus, and
match (x) composes with each feature exactly as the bare form did); type aliases × the
R0012 renumber (unrelated); Self.{ field } in extend × pattern matching (different
resolution contexts).
Fixtures added
metel-interpreter/tests/integration/sources/evaluator/type_aliases/v0_13_0_x_alias_for_dyn_aspect.{mtl,toml}— type alias (RFC-0160) ×dyn Aspect(RFC-0008); asserts coercion, dynamic dispatch, andList<alias>through a transparent alias. Positive;speccitestype-aliases.legality-1,dyn-aspect.dynamics-1.metel-interpreter/tests/integration/sources/evaluator/structs/v0_13_0_x_struct_pattern_partial_move_narrows.{mtl,toml}— struct pattern (#753) × row narrowing/widening (RFC-0137 slice 2) × parenthesizedmatch(RFC-0156). Positive;move_check = true;speccitesstruct-patterns.legality-1,narrowing.legality-1,widening.legality-1.
Landed on metel-core#1028 (test(#956), PR to develop).
Findings
- (none) — every high-risk pair has a fixture or a passing probe; nothing surfaced.
Full-tree verification
On develop @ 5ca689c8 + the two fixtures (branch tip 4d630ac3):
cargo test --release: 1022 integration + 96 lib, 0 failed (the two new fixtures pass;fixtures.manifestregenerated and committed on the branch).cargo clippy --release --lib -- -W clippy::pedantic: clean.cargo build --release -p metel: ok.move-check-count:skipped_generic_bodies_user_total = 21,user_move_violations = 69— identical with and without the two new fixtures (verified by removing them and re-running); this session adds zero. The absolute numbers are above the 2026-09-03 report's stated baseline (18) becausedevelopadvanced after that report; the re-run confirms the current state is stable, and everyuser_move_violationis a pre-existing corpus fixture in the affine-rejecting style the--move-checkhelp text describes.check_doc_examples.pyoverREADME.md,docs/getting-started/tutorials,docs/reference/spec: 195 passed, 0 failed, 48 skipped (unverifiable fragments + annotated skips).
Sign-off
Every high-risk pair has a committed fixture or a passing ad-hoc probe with a recorded
reason. Full release suite green on 4d630ac3. No findings — nothing to fix or defer.
Clear for /cut-release v0.13.0.