Skip to main content
v0.13.0

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 develop after 5ca689c8 and before the v0.13.0 tag — 17d5dadf (this session's own two cross-feature fixtures, metel-core#1028) and 2d2b9ea2 (the evaluator.md v0.13.0 doc pass, the crate version bump to 0.13.0, and the docs gitlink bump, metel-core#1029). Neither touches language-visible behaviour, so the PASS above stands against the frozen tip 2d2b9ea2 unchanged.

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-check narrowing-aware + path-sensitive across if / match arms — 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):

pairstatus
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 aliasprobe — 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_aspecttype 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)probeList<dyn Tag> filled from a [base]-capturing closure returning a concrete type; dispatch sums to 23
generic function as value × written move-only fn paramprobelet 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, and List<alias> through a transparent alias. Positive; spec cites type-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) × parenthesized match (RFC-0156). Positive; move_check = true; spec cites struct-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.manifest regenerated 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 = 69identical 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) because develop advanced after that report; the re-run confirms the current state is stable, and every user_move_violation is a pre-existing corpus fixture in the affine-rejecting style the --move-check help text describes.
  • check_doc_examples.py over README.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.