Skip to main content
v0.14.0

Integration testing — v0.14.0

Session run: 2026-10-08 · against develop at 4cb6fbb7f67b8adb47e634b8b5c4d834215a7f51, with public docs at 14c22409150693ef3447864b7aa70a4d4a8ea387. Result: PASS — see Third rerun (2026-10-18), which supersedes every earlier sign-off; core develop code at 95f8b824, unchanged at the release freeze. Original-run result: BLOCKED — three reproduced findings; coverage expansion stopped at findings. This is not a completed release sign-off or a claim that the tree is frozen. Second rerun (2026-10-15): see Second rerun at the end; it supersedes the 2026-10-14 sign-off. Final rerun (2026-10-14): see Final rerun. The matrix below has since been completed: every pair has evidence (E39–E74 were added after the original run). The sections between are the historical record of how it got there.

Scope and features​

The matrix includes previously released capabilities, not only features newly shipping in v0.14.0. The inventory was cross-checked against all 33 milestone issues and implementation commits since v0.13.1; at session start the v0.14.0 changelog listed only a subset of the shipped surface. It has since been expanded to cover that implementation inventory. Design-only drafts and future features (general unsizing, comptime row iteration, Hash/Ord, label polymorphism, and default-enabled ownership enforcement) are not treated as implemented.

At session start the milestone had 32 closed issues and one open issue, #1398. Its implementation is merged in core PR #1404 and docs PR #318, but its tracker is still open. No issue or milestone edits were made during this session. The milestone description still refers to the abandoned postfix array spelling; that is administrative drift, not the implemented prefix syntax.

Labels group related capabilities; a cell records a concrete interaction of subcapabilities, not exhaustive verification of every member of either group.

LabelAvailabilityCapabilitySource
NRv0.14Named records; row/anonymous-row arguments on reusable nominal types791, 1310, 1307
ORv0.14Open rows, decomposition equations, row extensions and forwarding1301, 1306, 1310
ALLv0.14Field-wise bounds and Copy-safe width narrowing1302, 1337
IMv0.14Conditional row impls; disjoint candidates and brand priority833, 1322, 1386
RGv0.14Rigid generic bodies, associated bindings, conditional grants, bound forwarding1364
ASv0.14Field-wise record Copy/Display/Clone1337, 1338, 1350
RPv0.14Owned record rest patterns, field discard, mutable bindings, row spread1399
ERv0.14 extensionEmpty row residual identity, use and restoration1398
ARv0.14 extensionPrefix arrays, sized literal inference and lookup, List iteration1291, 1296, 871
DGv0.14Runtime/internal error classification and generic/row diagnostics991, 1297, 1386
TAprevious releasesTransparent aliases, including function and nominal aliasesRFC-0160
CLprevious releasesCapture lists, once/var closures, written move-only functions, multiplicity wideningRFC-0050/0134/0152/0153/0154/0157/0166
OWprevious releasesWhole/partial moves, path-sensitive ownership, Copy/Drop and referencesRFC-0071/0117/0137
DYprevious releasesdyn Aspect coercion and dispatchRFC-0008
PMprevious releasesStruct/enum patterns, generic payloads, Perhaps/Result and propagationRFC-0078 and pattern-matching spec
MOprevious releasesImports, re-exports, visibility and cross-module nominal identitiesmodule spec; v0.13.1 identity fixes
GAprevious releasesGeneric functions/aspects, associated types and default methodsRFC-0138/0082; v0.14 fixes 1329–1332/1365
COprevious releasesCollections, array methods, strings and interpolationruntime/collection spec

Interaction matrix​

All 153 unordered off-diagonal pairs are represented. The original run had 32 source-reviewed evidence cells, nine cells associated with three findings, and 112 GAP cells. The current continuation updates this to 76 evidence cells, 23 finding-associated cells, and 70 GAP cells. Evidence and finding counts overlap: a passing narrow case does not clear a failing boundary. A GAP is not a proven language defect or proof that no fixture exists: matrix-wide corpus review and no-interaction analysis remain incomplete. No unreviewed tag co-occurrence is counted as evidence and no pair is silently classified as non-interacting.

Legend: E# refers to a fixture below, executed as part of the full release suite in its checked-in mode; F## is a reproduced failure below; GAP is unresolved. Diagonal/lower triangle are omitted. Even an E cell needs its relevant boundary/mode reviewed before eventual sign-off: an old nonempty residual fixture cannot establish correctness of a new empty residual case.

NRORALLIMRGASRPERARDGTACLOWDYPMMOGACO
NR—E8E74E2E2E5E8E4E3E49E31/F08E51E8E57E8E33/F09E5E5
OR—E6/E24/F04E29/F06E6E25/F04E8E30E45E47E31/F08F01F03E28E8E7E7E54
ALL—E29/E37E6E25/F04E30E30E45E35E31/E35F01E30/E34E57E52E56E55E54
IM—E2/F06E39E40E40E41E50E59E21E59E28E59E33E2E59
RG—E25/F04E30/E38E30E42E36E31/E36F01E30/E34/F11E60E60E33/F09E15/F07E60
AS—E43E43E3E46E17E17E17E28E60E23/F05E5/E20E5
RP—E30E44E70E53F01F03E61E8E56E30E61
ER—E44E73F02E27/F02E27/F02E58E62E56E30E62
AR—E48E53E51E61E14E52E56E61E3
DG—E66E67E68E71E69E65E68E72
TA—E13E63E12E18E26E31E63
CL—E10/E27E16E63E22E19/E27E63
OW—E28E11E64E27E63
DY—E18E33E32/F10E63
PM—E64E63E63
MO—E7E64
GA—E5
CO—

Existing evidence​

Paths are relative to metel-interpreter/tests/integration/sources/. Their sidecars determine whether a case executes, only type-checks, or opts into ownership enforcement. Passing the existing suite does not imply every case passed with --move-check forced; F03 demonstrates this distinction.

EvidenceFixtureInteraction
E1evaluator/structs/126_row_extend_target.mtlExecutable nominal row typestate and reverse spread.
E2typechecking/generics/row_conditional_method_declared_bound_satisfied.mtlDeclared row grant permits the conditional nominal method.
E3evaluator/structs/126_record_clone.mtlNamed nested record clone; array field; custom Clone dispatch.
E4evaluator/records/empty_residual_checked.mtlEmpty nominal/anonymous residuals, exact pass/return, restoration, Copy fields.
E5evaluator/aspects/record_display.mtlNominal/anonymous Display through a bounded generic borrowed wrapper and interpolation.
E6typechecking/generics/abstract_open_row_narrowing_all_copy_is_allowed.mtlAbstract width narrowing granted by all R: Copy.
E7module_semantics/cross_module_method_row_tail_param/main.mtlImported method with an open-row parameter.
E8evaluator/records/row_remainder_construction.mtlMutable remainder binding, nominal rest match, Copy reference spread; corpus mode is not move-check.
E9evaluator/aspects/record_target_all_fields_constraint.mtlCustom Label/Mark field-wise constraint; not evidence for built-in Copy/Display/Clone, so not used for ALL × AS.
E10evaluator/closures/v0_13_0_x_move_capture_of_narrowed_struct.mtlOld-release nonempty narrowed capture regression; does not prove the new empty case.
E11evaluator/structs/v0_13_0_x_struct_pattern_partial_move_narrows.mtlOld-release pattern move and local restoration.
E12evaluator/type_aliases/v0_13_0_x_alias_for_dyn_aspect.mtlAliased existential coercion/dispatch and collection.
E13evaluator/type_aliases/01_basic_and_parameterised.mtlAliases for written callbacks and higher-order use.
E14evaluator/aspects/101_dyn_aspect_array_literal_element_coercion.mtlFixed/dynamic arrays of existential elements.
E15evaluator/aspects/generic_aspect_method_runtime.mtlAspect method's own generics instantiated at multiple concrete types.
E22module_semantics/release_matrix_closure_cross_module/main.mtlA helper returns a captured once closure through a public alias; the importing module invokes it with move checking enabled.
E29evaluator/records/release_matrix_row_impl_facts.mtlPositive/negative conditional nominal dispatch; equation-derived empty/nonempty tails dispatched at the caller; structural all-Copy conditional impl. The generic marked body warns that move reconstruction failed, so this is executable/type-checking evidence only for that body.
E30evaluator/records/release_matrix_bound_remainders.mtlAbstract all-Copy remainder duplication; empty/nonempty tails; generic payload extraction; mutable owned rest; empty branded residual forwarded through a generic aspect method. Move checking enabled, no skipped-body warning.
E31evaluator/type_aliases/release_matrix_row_aliases.mtlOrdinary generic aliases containing open rows; all-Copy duplication; closed nominal/anonymous empty aliases; aliased argument/return through a generic aspect method. Move checking enabled, no skipped-body warning. Does not establish row-parameter alias support (F08).
E32evaluator/aspects/release_matrix_generic_dyn_defaults.mtlAliased dyn aspect with concrete aspect arguments, default dispatch and static generic method on the concrete receiver. Move checking enabled. Does not call the excluded generic method through dyn (F10).
E33module_semantics/release_matrix_row_identities/main.mtlTwo imported nominal row families, bounded generic conditional dispatch, empty/nonempty generic identity and separate dyn aspect dispatch. Move checking enabled. Uses unrenamed imports; renamed nominal import boundary fails (F09).
E34typechecking/generics/release_matrix_noncopy_remainder_twice.mtlUncalled generic body reusing an unconstrained remainder reports T0019 at the second use, with move checking enabled.
E35typechecking/generics/release_matrix_all_copy_alias_violation.mtlString field violates all-Copy despite an aliased generic result: T0012 plus field-specific message.
E36typechecking/generics/release_matrix_rigid_alias_violation.mtlTransparent alias cannot collapse a declared type parameter to i64: definition-time T0001.
E37typechecking/generics/release_matrix_all_copy_conditional_missing.mtlStructural conditional method without the all-Copy grant reports T0035 in an uncalled generic definition.
E38typechecking/generics/release_matrix_rigid_rest_violation.mtlDestructuring with an empty rest does not make its generic payload concrete: definition-time T0001.
E39evaluator/records/release_matrix_conditional_impl_derived_aspectsIM × AS; added in the 2026-10-13 rerun.
E40evaluator/records/release_matrix_conditional_impl_residualIM × RP, IM × ER; added in the 2026-10-13 rerun.
E41evaluator/records/release_matrix_conditional_impl_array_fieldIM × AR; added in the 2026-10-13 rerun.
E42evaluator/records/release_matrix_rigid_generic_array_bodiesRG × AR; added in the 2026-10-13 rerun.
E43evaluator/records/release_matrix_rest_clone_displayAS × RP, AS × ER; added in the 2026-10-13 rerun.
E44evaluator/records/release_matrix_rest_array_fieldsRP × AR, ER × AR; added in the 2026-10-13 rerun.
E45evaluator/records/release_matrix_open_row_array_all_copyOR × AR, ALL × AR; added in the 2026-10-13 rerun.
E46typechecking/records/release_matrix_record_display_field_missingAS × DG; added in the 2026-10-13 rerun.
E47typechecking/records/release_matrix_open_row_missing_labelOR × DG; added in the 2026-10-13 rerun.
E48typechecking/records/release_matrix_sized_array_length_mismatchAR × DG; added in the 2026-10-13 rerun.
E49parsing/negative_record_public_field_is_parse_errorNR × DG; added in the 2026-10-13 rerun.
E50typechecking/generics/row_conditional_impls_overlap_is_t0015IM × DG; added in the 2026-10-13 rerun.
E51evaluator/records/release_matrix_residual_array_capturesNR × CL, AR × CL; added in the 2026-10-13 rerun.
E52evaluator/records/release_matrix_patterns_open_rows_arraysALL × PM, AR × PM; added in the 2026-10-13 rerun.
E53evaluator/records/release_matrix_alias_residual_arraysRP × TA, AR × TA; added in the 2026-10-13 rerun.
E54evaluator/records/release_matrix_collection_open_rowsALL × CO, OR × CO; added in the 2026-10-13 rerun.
E55evaluator/records/release_matrix_all_copy_associated_sourceALL × GA; added in the 2026-10-13 rerun.
E56module_semantics/release_matrix_record_rows_across_modulesALL × MO, RP × MO, ER × MO, AR × MO; added in the 2026-10-13 rerun.
E57evaluator/records/release_matrix_dyn_row_implsNR × DY, ALL × DY; added in the 2026-10-13 rerun.
E58evaluator/records/release_matrix_empty_residual_dispatch_follows_static_typeER × DY; added in the 2026-10-13 rerun.
E59evaluator/records/release_matrix_conditional_impl_alias_collectionIM × TA, IM × OW, IM × PM, IM × CO; added in the 2026-10-13 rerun.
E60evaluator/records/release_matrix_rigid_generics_dyn_patternsRG × DY, RG × PM, RG × CO, AS × PM; added in the 2026-10-13 rerun.
E61evaluator/records/release_matrix_rest_dyn_collectionsRP × DY, RP × CO, AR × OW, AR × GA; added in the 2026-10-13 rerun.
E62evaluator/records/release_matrix_empty_residual_collections_patternsER × PM, ER × CO; added in the 2026-10-13 rerun.
E63evaluator/records/release_matrix_prior_release_pairsTA × OW, TA × CO, CL × PM, CL × CO, DY × CO, OW × CO, PM × GA, PM × CO; added in the 2026-10-13 rerun.
E64module_semantics/release_matrix_enum_array_generic_across_modulesOW × MO, PM × MO, MO × CO; added in the 2026-10-13 rerun.
E65module_semantics/release_matrix_enum_variant_fields_private_across_modulesDG × MO; added in the 2026-10-13 rerun.
E66typechecking/records/release_matrix_diag_alias_argument_mismatchDG × TA; added in the 2026-10-13 rerun.
E67typechecking/records/release_matrix_diag_closure_capture_needs_listDG × CL; added in the 2026-10-13 rerun.
E68typechecking/records/release_matrix_diag_generic_double_moveDG × OW, DG × GA; added in the 2026-10-13 rerun.
E69typechecking/records/release_matrix_diag_non_exhaustive_enum_matchDG × PM; added in the 2026-10-13 rerun.
E70typechecking/records/release_matrix_diag_rest_names_absent_fieldRP × DG; added in the 2026-10-13 rerun.
E71typechecking/aspects/dyn_generic_method_excluded_{local,parameter,tuple}DG × DY; added in the 2026-10-13 rerun.
E72typechecking/records/release_matrix_diag_{array_index_not_u64,array_unknown_method,for_over_non_iterable,array_mixed_element_types,view_element_move}DG × CO; added in the 2026-10-13 rerun.
E73typechecking/records/release_matrix_diag_rest_remainder_is_not_branded{,_nonempty}ER × DG; added in the 2026-10-13 rerun.
E74evaluator/records/all_fields_on_nominal_row_argumentNR × ALL; added in the 2026-10-13 rerun.

Findings​

The findings are tracked separately in v0.14.0: F01 → #1405, F02 → #1406, and F03 → #1407, F04 → #1420, and F05 → #1421. No implementation changes were made and no invalid-acceptance fixtures were added to make the release look green.

F01 — Missing generic closure capture escapes the definition check​

The following program declares both the negative row condition and the all-Copy condition. Initial expected outcome was that the assertions would succeed (9 and 11). Investigation found that the explicit [copy] list also needs id, so the program must instead be rejected at its definition with T0026 under spec.functions.closures.legality-7. Actual at the session baseline, both default mode and --move-check: I0010, generic definition copied_tail and construction disagree. The equivalent program with the closure body directly in copied_tail succeeds. A simple all-Copy row capture without the transition also succeeds. Correcting the list to [copy, id] succeeds without move checking; with move checking it encounters the separate destructuring failure tracked by #1407. The callback alias also exercises previously released written function types and transparent aliases.

The local #1405 fix rejects the missing capture at definition time, even if the generic function is never called. The corrected [copy, id] form has executable coverage for both empty and nonempty tails. Ownership sign-off remains blocked by #1407; the reduced symbolic-row reconstruction warning below is fixed locally. This is not a completed integration pass.

type Callback := once || -> i64;
fun invoke(f: Callback) -> i64 { f() }

fun transition<row R: !{token}>(r: { ..R }) -> { token: String, ..R } {
{ ..r, token = "secret" }
}

fun copied_tail<row R: !{token}>(r: { id: i64, ..R }) -> i64 where all R: Copy {
let { id, ..rest } := r;
let copy := rest;
let callback := [copy] once || {
let extended := transition(copy);
let { token, ..again } := extended;
id + token.len() as i64
};
invoke(callback)
}

fun main() {
assert(copied_tail({ id = 3, count = 7 }) == 9);
assert(copied_tail({ id = 5 }) == 11);
}

A reduced forwarding/capture variant previously ran with a warning that move checking could not analyze the generic body (T0002: cannot infer open-row remainder). The local symbolic-row fix now checks it without that warning; regressions also require a move violation when the field-wise Copy bound is absent.

fun add<row R: !{token}>(r: { ..R }) -> { token: String, ..R } {
{ ..r, token = "secret" }
}
fun test<row R: !{token}>(r: { ..R }) -> i64 where all R: Copy {
let f := [r] once || {
let added := add(r);
7
};
f()
}
fun main() { assert(test({ n = 1 }) == 7); }

F02 — Empty nominal residual cannot be restored after parameter rebinding​

Expected: the brand supplies the declared field types, and assigning both missing fields reconstructs Pair. Actual, with and without move checking: T0001 at the function tail, saying a partially moved Pair.{} cannot satisfy Pair. The direct local restoration in empty_residual_checked.mtl passes; the parameter/rebinding case does not. An aliased empty residual captured by a written once || -> Pair callback also fails with T0001; the unaliased capture variant instead reports T0002 on field assignment. These variants need triage without assuming one root cause for every diagnostic. The local #1406 fix now restores initial absence state on residual bindings. Parameter rebinding and aliased/written callback variants have executable coverage under move checking, with missing-field and wrong-type negative guards.

The regression includes both a transparent Pair.{} alias and a transparent callback-type alias. A direct locally emptied capture is a separate ownership finding: [pair] once var || -> Pair { pair.left := "new"; pair.right := "back"; pair } executes without move checking but is rejected at capture with T0019 when ownership checking is enabled. The capture collector encounters an assignment target first, records no use-site type for it, and falls back to the original whole binding type rather than its current residual. The ordinary [pair] once || spelling correctly requires var for writes (T0028). The direct mutable-capture case is separately tracked as #1409, dependent on #1406. Its local fix carries owned source entry types into ownership analysis; the executable regression now restores empty and partial nominal captures under move checking. Negative fixtures retain missing-field/incomplete-restoration errors and whole-source move checks, including shadowed and unused generic captures. This does not resolve the report's other ownership-audit limitations or complete its release sign-off.

struct Pair { left: String, right: String }
fun rebuild(empty: Pair.{}) -> Pair {
var restored := empty;
restored.left := "new";
restored.right := "back";
restored
}
fun main() {
let p := Pair { left = "old", right = "gone" };
let left := p.left;
let right := p.right;
let restored := rebuild(p);
assert(restored.left == "new");
}

F03 — Equation-derived rest destructuring reports its own consumption as reuse​

Existing fixture: evaluator/records/equation_derived_remainder.mtl. Its first function is:

fun strip<row R, row Rest>(d: { ..R }) -> { ..Rest }
where R = { token: String, ..Rest } {
let { token: _, ..rest } := d;
rest
}

The checked-in fixture executes successfully without ownership enforcement. Forcing --move-check reports T0019 on line 3, column 33: d is used after being moved at that very same line and column. This is the single consumption that should distribute fields to the owned remainder, not a subsequent use. The full move-check-count audit aborts with its corresponding invariant assertion: checker bug: move site reported as its own use for d. Consequently neither a final generic-skip count nor a negative-fixture-only violation inventory was obtained; the baseline-of-18 gate is not verified.

The local #1407 fix gives record patterns sole ownership of place consumption. The fixture now runs with move checking enabled, including empty and non-Copy remainders, mutable bindings and chained equations. Its three by-value Box method calls use independent receivers rather than reusing a moved one. Field discard and #1405's full row/callback fixture also run with ownership checks; a separate negative fixture retains T0019 for genuine later source reuse.

F04 — Field-wise Clone does not grant cloning an owned open-row record​

#1420 tracks a definition-time T0035 on value.clone() for fun clone_head<row R>(value: { id: i64, ..R }) where all R: Clone. The fixed id field and every field in R satisfy Clone, but the generic body cannot clone the whole record. The issue-backed regression evaluator/records/release_matrix_bounded_clone_residual_callback.mtl is skipped with the issue citation; it also exercises nominal partial moves and a closure callback, but those downstream interactions do not execute because the generic definition is rejected first. The affected matrix intersections are OR × ALL, OR × AS, ALL × AS, and RG × AS. OR × ALL already has E6 for the distinct all-Copy narrowing behavior; the other three intersections move from GAP to F04.

F05 — Field-wise Clone is unavailable across a module boundary​

The Packet record in model.mtl has only public Clone fields, and the consumer imports both model::Packet and std::core::Clone. Calling original.clone() still reports T0003 (no method clone on Packet); the equivalent record declared and used in one module passes. The issue-backed skipped regression is module_semantics/release_matrix_record_clone_cross_module; see metel-core#1421. This classifies AS × MO as F05 pending investigation and a passing cross-module regression.

Post-fix ownership audit (#1407)​

The audit now completes with both invariant assertions unchanged. On the local #1407 branch it reports 91 user violations in 74 fixtures:

  • 61 expected typecheck-negative fixtures account for 67 violations.
  • 12 ownership-opt-out fixtures account for 22 violations. Three aspect fixtures reuse by-value receivers; 75_two_closures_share_state_via_pointer moves the same mutable-reference binding into two closures; seven struct/row fixtures reuse consumed nominal values; stage14_11_impl_method_own_generic_bound passes the same non-Copy Num twice. These are corpus migration cases, not the same-span destructuring defect, and have not been silently skipped.
  • The opt-out runtime-negative reentrancy fixture accounts for two violations; its runtime-error test is not an ownership-clean example.

There are 21 skipped user generic bodies, above the historical baseline of 18, and 30 embedded-standard-library skips. The earlier run aborted, so it did not establish a comparable current baseline. The audit now prints each skipped user body's source location and reason. The 21 reasons group as follows:

Reconstruction limitationBodies
Aspect/default-method lookup on opaque symbolic receivers8
Projection fields on opaque symbolic nominal arguments4
Return-only generic inference3
Mutable symbolic row field assignment2
Discarded field in a symbolic nominal record row1
Conditional method on a symbolic receiver1
Numeric operator in an inferred generic signature1
Implicit capture in a let-polymorphic closure1

In particular, equation_derived_remainder's strip_extra and Box.strip still expose reconstruction limitations (field assignment and discarded field). Their concrete instantiations execute with ownership checking, but the generic definitions are not fully analyzed by that optional checker. The full row/callback probe from #1405 executes with ownership checking and no skip warning.

The audit execution gate is repaired; the stricter milestone criterion is not clear. Generic reconstruction and the opt-out corpus need separate triage and a release decision. These counts do not justify enabling ownership checking by default or declaring the cross-release matrix complete.

Fixtures added​

None. Exploratory reproducers and controls were run from an isolated temporary directory. The integration procedure says to stop adding coverage fixtures when a bug is found and track each finding separately rather than fix it inline. Issue-backed regression/skip fixtures and remaining high-risk pair coverage must follow the normal per-PR process.

Full-tree verification​

Against the recorded core SHA (no compiler or fixture edits):

  • cargo test --release --workspace: PASS, 1,227 integration tests, 243 frontend, 96 type-engine, 26 interpreter and three benchmark tests; doc-test targets also pass.
  • cargo test --workspace --no-fail-fast: PASS, the same test counts.
  • cargo clippy --release --workspace --lib -- -D warnings -D clippy::pedantic: PASS, zero warnings.
  • cargo fmt --all and cargo fmt --check --all: PASS, no code changes.
  • cargo build --release -p metel --bins: PASS.
  • python3 tools/check_doc_examples.py --binary target/release/metel README.md docs/getting-started/tutorials docs/reference/spec: 192 passed, zero failed, 89 skipped (82 unverifiable fragments, seven annotated skips).
  • python3 docs/rfcs/tools/rfc.py check: PASS; its scheduled tracker network lookup was skipped because sandbox DNS was unavailable. Milestone inventory was separately read using authenticated GitHub access.
  • python3 docs/architecture/tools/check_architecture.py: PASS, no findings (existing phrasing warnings remain).
  • target/release/move-check-count metel-interpreter/tests/integration/sources: FAIL, invariant assertion in F03. Do not substitute old release counts.

The green suite proves the current corpus, not the broader new × old interaction matrix. The dedicated probes and mandatory ownership audit exposed gaps that ordinary per-PR verification missed.

Matrix continuation — 2026-10-08​

The closure × dynamic-Aspect cell now has executable evidence: E16, evaluator/aspects/release_matrix_dyn_closure_capture.mtl, passes with move_check = true. It captures a dyn Describe value through a transparent type alias in a once closure whose written callback type is also an alias, then dispatches the aspect method from the closure body. It supplies evidence for CL × DY, TA × CL, and TA × DY. The original-run 32/9/112 counts remain historical; the current cumulative classification is 41/12/100 after E16–E21 and F04, as reflected in the matrix above.

E17, evaluator/aspects/release_matrix_clone_capture.mtl, also passes with move_check = true. It clones a record through a transparent alias, partially moves a non-Copy field from the clone, and captures the remaining nominal value in a once closure. This supplies positive evidence for AS × CL, TA × AS, TA × CL, OW × CL, and AS × OW.

E18, evaluator/aspects/release_matrix_dyn_aspect_pattern.mtl, passes with move_check = true. An enum stores a value as an aliased dyn Render; a match extracts the payload and dispatches the method. This supplies evidence for PM × DY, TA × PM, and TA × DY.

E19, evaluator/closures/release_matrix_generic_closure.mtl, passes with move_check = true. A T: Clone generic function returns a once-closure that owns and clones a value of the rigid type parameter. This supplies evidence for CL × GA.

E20, evaluator/aspects/release_matrix_generic_record_clone.mtl, passes with move_check = true. A generic nominal record with a T: Clone parameter is cloned inside a generic function whose parameter declares the same bound. This extends the existing AS × GA evidence from record Display to field-wise Clone.

E21, evaluator/aspects/release_matrix_conditional_dispatch_closure.mtl, passes with move_check = true. A closure captures a named record and invokes a method provided by a row-conditional impl selected from that record's current row. This adds positive evidence for IM × CL.

Corpus review also confirmed that existing E2, typechecking/generics/row_conditional_method_declared_bound_satisfied.mtl, checks a conditional inherent method from inside a generic function. It supplies IM × GA evidence in addition to its existing IM × RG entry.

An owned open-row Clone probe found an additional gap, tracked as #1420. A generic function with where all R: Clone is rejected with T0035 when it calls clone() on its entire { id: i64, ..R } argument. The issue-backed skipped fixture is evaluator/records/release_matrix_bounded_clone_residual_callback.mtl. It exercises the conjunction of open rows, field-wise bounds, rigid generic bodies, built-in record Clone, aliases, partial moves, and a closure callback; the issue remains open and the fixture is not counted as passing evidence.

The nine newly evidenced cells include the eight additions E16–E19/E21 and the newly mapped E2 cell. Three previously unresolved intersections now carry F04; OR × ALL has both the older positive E6 and the Clone failure. The other original cells remain as classified in the table. Unreviewed GAP cells are not promoted to positive evidence. The release remains blocked pending the remaining corpus review and disposition of findings.

For this continuation, all six new fixtures and manifest validation passed; cargo test --workspace --no-fail-fast passed all 1,261 integration tests, release strict Clippy, and formatting also passed. RFC and architecture checks passed locally; the RFC check could not reach GitHub for its scheduled tracker lookup in this network-restricted environment.

Sign-off​

Not clear for release. Triage #1405–#1407 separately, resolve or explicitly defer each finding with the user's release decision, complete the remaining matrix classifications and every high-risk coverage gap, reconcile #1398 and the incomplete release inventory, then rerun this integration session on the final frozen tree. The three finding issues were created with user approval and assigned to v0.14.0. No tag, push, PR, merge, or release was performed as part of this report.

Sensitive-matrix follow-up — 2026-10-08​

The follow-up runs on develop at 784eb8f96f598122b4cacbd2f8e099b42f3f31e2 after the ownership fixes and preserves the historical audit above. It added executable move-check coverage for array-pattern callbacks (evaluator/records/release_matrix_array_pattern_callback.mtl) and conditional dispatch/capture on a residual (evaluator/records/release_matrix_residual_dispatch_capture.mtl), plus a definition-time T0033 guard for a closure whose captured open row is not declared Copy (typechecking/records/release_matrix_closure_width_requires_copy.mtl). Four independently reproduced gaps are represented by skipped regressions and architecture limitations: generic residual capture (#1411), borrowed all R: Clone (#1412), residual-to-dyn Aspect coercion (#1413), and a public alias whose defining module's nominal type is not imported (#1414).

At that point, the table still reflected the original 32/9/112 snapshot. The matrix continuation below updates it cumulatively for E16–E19 and F04 to 39/12/102. These totals account only for the newly reviewed cells; they do not mean the remaining matrix was fully audited or provide release sign-off.

The integration harness passed all 1,254 registered integration cases in debug and release workspace runs (including the four new skipped regressions), 251 frontend, 96 type-engine, 26 interpreter, and three benchmark tests. Release strict Clippy, formatting, fixture-manifest validation, RFC checks, architecture checks, and generated architecture-evidence validation passed. These results verify the current fixture corpus only; the unresolved GAP cells remain open and the milestone is not clear for release.

Continued matrix coverage — 2026-10-08​

E22, module_semantics/release_matrix_closure_cross_module/main.mtl, passes with move_check = true. The helper module creates and returns a captured once closure under a public alias; the root module imports and invokes it. This supplies executable evidence for CL × MO. The cumulative table now has 42 evidence cells, 13 finding-associated cells, and 98 unresolved GAP cells. F05 records the newly issue-backed AS × MO failure.

Local remediation follow-up — 2026-10-08​

On the current unmerged worktree, E23 (module_semantics/release_matrix_record_clone_cross_module) passes after registry merges began preserving record-kind identity. E24 (evaluator/records/release_matrix_borrowed_all_clone) passes after borrowed open-row parameters retained their row bounds without receiving the by-value Copy width check. E25 (evaluator/records/release_matrix_bounded_clone_residual_callback) passes after generic method entailment began combining the declared tail grant with typed fixed-field facts. These add four newly evidenced pairs (AS × MO and the three formerly F04-only pairs); OR × ALL already had E6. The three passing regressions are unskipped locally, but #1420 and #1421 remain open pending merge.

E26 (module_semantics/release_matrix_row_callback) now passes without a skip after alias expansion adds a synthetic import for the defining module's nominal dependency. It supplies TA × MO evidence. E27 (evaluator/records/release_matrix_generic_residual_capture) passes with move checking enabled after captured source types were threaded into generic-body construction and move analysis. It covers partial and empty nominal residuals, mutable field restoration, and a negative use-after-move guard; it adds evidence for ER × CL, ER × OW, and OW × GA. The table now has 50 evidence cells; the 98 unresolved GAP cells remain unaudited.

E28 (evaluator/records/release_matrix_residual_dyn_alias) passes without a skip after residuals convert through their row-aware inference form and dyn values retain enough receiver metadata for nominal and structural aspect dispatch. It adds AS × DY, OR × DY, IM × DY, and OW × DY evidence, bringing the cumulative table to 54 evidenced cells and 98 unresolved GAP cells. The #1411, #1412, #1413, #1414, #1420, and #1421 regressions all pass locally, but their trackers remain open pending integration.

The expanded integration run on this worktree passes all 1,265 cases. It also exercises the empty branded-residual ownership rule: consuming a non-Copy empty residual marks that binding moved, while capturing a residual after only field-wise moves remains legal so a closure can restore it. The existing use-after-move fixtures cover both paths. Generic move analysis still warns that it cannot reconstruct two row-Clone method bodies; those cases pass execution with move checking enabled, but do not count as evidence that those generic bodies were ownership-checked.

High-risk coverage follow-up — 2026-10-08​

Baseline: core b85a6cd6bdaef308718210f9279edada8cb420cf; this section describes local, uncommitted coverage additions, not merged release sign-off. Ten fixtures were added (E29–E38): five executable positives and five definition/call-site negatives with exact error codes and message substrings. Ownership-sensitive positives and the double-move negative opt into move checking. Spec fixture backlinks and the core fixture manifest were regenerated.

Every prioritized pair now has source-reviewed evidence for a concrete case:

Prioritized interactionsPassing evidenceUnresolved boundary
OR × IM; ALL × IME29, E37F06: generic dispatch on an equation-derived remainder; E29's structural generic body also skips ownership reconstruction under #273.
RG × RP; RG × ER; RG × OWE30, E34, E38F11: associated-type row result reconstruction can hide a double move under #273.
ALL × RP; ALL × ER; ALL × OWE30, E34Positive all-Copy and negative unconstrained cases are checked; this does not clear all Clone/custom-aspect reconstruction cases.
RP × ER; RP × GA; ER × GAE30Empty and nonempty rest forwarding through a generic aspect method passes.
NR × TA; OR × TA; ALL × TA; RG × TA; TA × GAE31, E35, E36F08: aliases declaring their own row parameter fail; ordinary generic and closed aliases pass.
NR × MO; IM × MO; RG × MO; DY × MOE33F09: renamed nominal imports fail; the unrenamed control passes.
GA × DYE32F10: excluded generic method calls are not reliably rejected on dyn bindings.

F07 additionally exposes RG × GA: a generic bound's concrete aspect arguments are not substituted for a default-method call. E30 adds OR × ER evidence beyond the prioritized list. The matrix now has 76 evidence cells, 23 finding-associated cells (overlapping evidence), and 70 GAP cells. All 153 pairs remain represented. This recount also corrects earlier bookkeeping: the AS row lacked the PM cell, and CL × MO's E22 was in the PM column. The older prose's GAP/finding totals did not match its actual table; they should not be used as the current baseline.

The five newly failing boundaries F06–F10 and the additional #273 probe F11 are preserved with standalone sources and controls in the boundary-probe report. New tracker creation awaits approval; none is counted as a passing negative fixture. No compiler fixes or outward-facing edits were made in this batch.

Verification on the coverage worktree:

  • cargo test -p metel --test integration release_matrix_: 28 passed.
  • cargo test --workspace --no-fail-fast: passed, including all 1,275 integration cases.
  • cargo clippy --release --workspace --lib -- -D warnings -D clippy::pedantic: passed.
  • cargo fmt --all and cargo fmt --check --all: passed.
  • Manifest regeneration completed and its subsequent validation passed.
  • Docs RFC/index and architecture checks passed (existing architecture prose warnings remain).

The scheduled GitHub tracker check was skipped because the checker could not reach the API. The architecture tool also reported its fixture arch cross-check as unavailable; its explicit --core skipped-fixture LIMIT citation check ran. These tool limitations are not counted as verified release gates.

The forced ownership audit reports 24 skipped user generic bodies and 96 user move violations across 79 fixtures. Its raw violations include intentional negative fixtures and fixtures whose corpus mode does not enforce moves; these are not 96 newly found bugs or a zero-violation sign-off. The new double-move negative contributes one expected violation. E29 contributes one newly exposed skipped generic body. The total exceeds the milestone's baseline of 18; the remaining violations also need mode-aware classification before sign-off.

Verdict: BLOCKED. The prioritized gaps have been exercised, not universally cleared. F06–F10 need separate trackers and fixes or explicit deferral; #273's reconstruction failures qualify the ownership evidence. The 70 remaining GAP cells still require corpus review/coverage or justified non-interaction analysis.

Boundary fixes following the high-risk probes (local, pending merge)​

The preceding verdict describes the probe baseline. Trackers #1423, #1424, #1425, #1426, and #1427 now have local fixes and focused regression fixtures, listed in the boundary-probe report.

The fixes preserve remainder exclusions during conditional lookup, substitute concrete aspect arguments (including inherited struct bounds), expand row alias tails, preserve renamed imports' generic arguments and nominal identities, and enforce generic-method exclusion through dyn locals and aggregates. Additional negative fixtures reject distinct same-named imported brands, reject treating a typed exclusion as unconditional label absence, and reject non-Copy moves through a borrowed open-row field.

Two concrete #273 reconstruction failures are fixed as well: associated-type equalities now supply the symbolic method's concrete return type, and anonymous structural rows retain their field entitlements. E29's marked body reconstructs without a skipped-body warning. The associated-result negative fixture reports T0019 at the second consuming call in an uncalled generic definition; its valid single-call counterpart executes without a reconstruction warning.

Adversarial controls confirm that stronger untyped exclusions can prove typed exclusions, not the reverse; distinct nominal brands stay distinct; concrete Copy associated results can be reused; and unbounded record parameters do not gain Copy merely from symbolic sampling.

This is not a release-wide sign-off. #273's broad fail-open policy remains at v0.16.0, including inherited-bound reconstruction and generic parameters appearing only in associated equalities. An ordinary impl that renames its nominal type parameter (extend<U> Wrapper<U> for Wrapper<T>) also has a separate pre-existing runtime lookup limitation, reproduced independently of aspect bounds. The 70 GAP cells and the earlier ownership audit still need mode-aware triage. The five new trackers remain open until the fixes are merged.

Local verification after the fixes:

  • cargo test --workspace --no-fail-fast: passed, including 1,287 integration cases.
  • cargo clippy --release --workspace --lib -- -D warnings -D clippy::pedantic: passed.
  • Formatting, fixture manifest validation, RFC/index checks, and architecture integrity checks passed.
  • The scheduled RFC tracker API check was unavailable in the sandbox. Evidence regeneration requires the core changes to be committed first: the generator's line-range history lookup cannot resolve shifted ranges in the uncommitted worktree. Refresh generated architecture evidence during commit/PR preparation.

Remediation status audit — 2026-10-09​

The implementations for #1411–#1414, #1420, and #1421 merged in metel-core PR #1422 (commit 5f038b189cb67c5ec40e51d16a3e11a831a4535e). The high-risk boundary fixes merged in PR #1428, and #1423–#1427 are closed. Earlier "pending integration" notes describe the pre-merge worktrees. The original regressions remain unskipped and pass on the merged baseline; the 28 release-matrix tests were rerun during this audit.

An acceptance check for #1414 found a remaining constructor visibility gap: although an imported alias preserves its defining nominal identity, a written bare constructor could still find an unimported type through broad registry lookup. Constructor inference now requires a normalized import identity or a name in the current module's scope. The negative module_semantics/alias_rhs_constructor_not_imported guards that boundary; module_semantics/imported_nominal_alias_definition_scope verifies renamed and re-exported row/ordinary generic aliases against consumer-module name collisions. The older renamed-import positive fixture now constructs using the imported alias consistently with spec.modules.imports.legality-2.

The remaining diagnostic cleanup in #1412 also removes references to closed #1302 from unsupported function/impl field-wise constraint contexts. Existing negative fixtures continue to require T0012 and describe the required row tail instead of treating the original implementation tracker as outstanding. These constructor/diagnostic follow-ups are committed in core 26c4de8d and awaiting shipping.

Verification of this worktree passed debug and release workspace suites (1,289 integration cases), strict release Clippy, formatting, RFC/spec checks, and architecture integrity checks. The RFC check reached GitHub and verified 48 open milestoned RFC trackers. All six original bug reproducers execute in both default and move-check modes. A generic Clone call returning the same type parameter also preserves a nominal residual; returning an anonymous row instead would erase its brand and is correctly rejected.

The generic row-Clone move-analysis warning remains a separate unresolved limitation under #273. This remediation does not provide release sign-off or change the matrix's coverage totals. Generated architecture evidence was refreshed against core 26c4de8d during shipping preparation.

Rerun — 2026-10-13​

Run against develop at 9cb4c9de (after the #273 abstract-bodies work, #1432/#1433/#1438, the #1440 record-field visibility change and the #1442 orphan-diagnostic fix). Fixtures added on core PR test/v0.14.0-integration-rerun.

Pairs newly evidenced (33 of the 70 GAP cells, counting the second batch below). All seven positives run with move checking enabled; the negatives assert the exact code and message.

PairsEvidence
IM × ASevaluator/records/release_matrix_conditional_impl_derived_aspects
IM × RP; IM × ERevaluator/records/release_matrix_conditional_impl_residual
IM × ARevaluator/records/release_matrix_conditional_impl_array_field
RG × ARevaluator/records/release_matrix_rigid_generic_array_bodies
AS × RP; AS × ERevaluator/records/release_matrix_rest_clone_display
RP × AR; ER × ARevaluator/records/release_matrix_rest_array_fields
OR × AR; ALL × ARevaluator/records/release_matrix_open_row_array_all_copy
AS × DGtypechecking/records/release_matrix_record_display_field_missing (T0012, names the field)
OR × DGtypechecking/records/release_matrix_open_row_missing_label (T0012)
AR × DGtypechecking/records/release_matrix_sized_array_length_mismatch (T0001)
NR × DG; ALL × DG; IM × DG; RG × DGexisting: negative_record_public_field_is_parse_error, E35, row_conditional_impls_overlap_is_t0015, E36

Second batch (15 more pairs and one BUG cell). The same tree, move checking enabled.

PairsEvidence
NR × CL; AR × CLevaluator/records/release_matrix_residual_array_captures
ALL × PM; AR × PMevaluator/records/release_matrix_patterns_open_rows_arrays
RP × TA; AR × TAevaluator/records/release_matrix_alias_residual_arrays
ALL × CO; OR × COevaluator/records/release_matrix_collection_open_rows
ALL × GAevaluator/records/release_matrix_all_copy_associated_source
ALL × MO; RP × MO; ER × MO; AR × MOmodule_semantics/release_matrix_record_rows_across_modules
NR × DY; ALL × DYevaluator/records/release_matrix_dyn_row_impls

One pair surfaced a bug: aspect dispatch on a {} residual follows the hidden brand of the record it came from, not its static type (#1446). It is recorded as the skipped evaluator/records/release_matrix_empty_residual_dispatch_follows_static_type, which covers ER × DY as a BUG cell. Fixed since in v0.14.1 (the fixture is unskipped and passes). Two smaller findings were filed as #1444 (field-wise bounds cannot constrain a named record's row argument; NR × ALL) and #1445 (rest pattern on a named record gives an anonymous residual and a confusing T0001; ER × DG). All three are in v0.14.1.

Rest patterns inside enum struct-variant patterns (Shape::Circle { r, ..rest }) do not parse; the v0.14 rest-pattern surface covers record patterns only, so RP × PM is not extended there.

The matrix now has 3 unresolved GAP cells (36 before the third batch; DG × CO is closed below) and one BUG cell (ER × DY).

Third batch (33 more pairs). Same tree, move checking enabled unless a negative.

PairsEvidence
IM × TA; IM × OW; IM × PM; IM × COevaluator/records/release_matrix_conditional_impl_alias_collection
RG × DY; RG × PM; RG × CO; AS × PMevaluator/records/release_matrix_rigid_generics_dyn_patterns
RP × DY; RP × CO; AR × OW; AR × GAevaluator/records/release_matrix_rest_dyn_collections
ER × PM; ER × COevaluator/records/release_matrix_empty_residual_collections_patterns
TA × OW; TA × CO; CL × PM; CL × CO; DY × CO; OW × CO; PM × GA; PM × COevaluator/records/release_matrix_prior_release_pairs
OW × MO; PM × MO; MO × COmodule_semantics/release_matrix_enum_array_generic_across_modules
DG × MO; PM × MO (negative)module_semantics/release_matrix_enum_variant_fields_private_across_modules (T0009)
DG × TAtypechecking/records/release_matrix_diag_alias_argument_mismatch (T0001)
DG × CLtypechecking/records/release_matrix_diag_closure_capture_needs_list (T0026)
DG × OW; DG × GAtypechecking/records/release_matrix_diag_generic_double_move (T0019)
DG × PMtypechecking/records/release_matrix_diag_non_exhaustive_enum_match (T0008)
RP × DGtypechecking/records/release_matrix_diag_rest_names_absent_field, ..._rest_after_field_removed (T0012)
DG × DYexisting typechecking/aspects/dyn_generic_method_excluded_{local,parameter,tuple}

Remaining after this batch: three GAP cells (NR × ALL, which is the documented restriction filed as #1444; ER × DG, filed as #1445; DG × CO, closed in the next paragraph) and the BUG cell ER × DY (#1446). A rest pattern on a non-record (let { a, ..rest } := 5) reports "field a is not known to be present" rather than naming the non-record scrutinee; the wording is misleading but the code (T0012) is right.

Diagnostics × collections (closed). Five negatives in typechecking/records/: release_matrix_diag_array_index_not_u64 (T0001), ..._array_unknown_method (T0003), ..._for_over_non_iterable (T0001), ..._array_mixed_element_types (T0001) and ..._view_element_move (T0019, move checking). The last one prints the old postfix spelling T[] in its message, which is filed as #1448 (v0.14.0); the fixture asserts only the code and "borrowed from a". A separate defect, a fake 0:0 moved-site span on illegal-move violations, is #1447. The matrix now has no unresolved GAP cells (NR × ALL closed by #1444, ER × DG by #1445) and the BUG cell ER × DY (#1446).

Observations (now filed, see below).

  • where all R: Copy on a row R that only appears as a named record's argument (Packet<..R>) is rejected with T0012 ("must name the row tail of an open-row parameter"), which matches field-wise-row-constraints.legality-1. It is a documented restriction, but it means NR × ALL has no positive case.
  • Destructuring a named record with ..rest yields an anonymous residual, not Token.{}; passing it where Token.{} is required reports T0001: cannot unify { } with Token.{ }. The wording is poor but the behaviour follows from the residual rules.

Full-tree verification on the same tree, release mode:

  • cargo test --release --workspace: 1,346 integration cases and every other suite, 0 failures.
  • move-check-count: skipped_generic_bodies_user_total=0 (was 24 in the 2026-10-08 audit, baseline 18). The 24 skipped generic bodies are gone, the completeness test (every_generic_body_in_the_corpus_is_analyzed) passes.
  • user_move_violations=107 (108 with the later fixtures), up from 96. Triaged below: 76 intentional negative fixtures and 15 legacy default-mode fixtures, since made ownership-clean (83 violations, all negatives, afterwards).
  • check_doc_examples.py: 192 passed, 0 failed.

Move-violation triage (2026-10-13). move-check-count reports 108 user violations in 91 fixtures on develop plus the new fixtures (107 before the third batch). Each fixture was classified from its sidecar and every violation in the non-negative ones was read against its source line.

ClassFixturesViolationsVerdict
Expects T00197379Intentional. Every asserted line (7 fixtures pin one) is a reported use.
Expects another typecheck error (neg_generic_capture_once_even_for_copy_instantiation, neg_nested_move_makes_enclosing_once)22Intentional negatives; the error is raised by a later pass.
Expects runtime R0015 (neg_mutating_reentrancy_rejected)12Intentional.
Success with move_check = true00Clean, as the suite requires.
Success in default mode, skip-tagged00None.
Success in default mode, not move-checked1525All 25 were true positives; none was a checker false positive. Fixed, see below.

The 15 default-mode fixtures predate move checking and reuse a value after a by-value receiver or argument moved it, or move a field out of a reference. By group:

  • Use after a by-value self or argument call: aspect_impls_with_disjoint_bounds, default_methods_on_generic_impls_variants, row_conditional_aspect_impls, 100_value_receiver_keeps_value_semantics, 114_record_upgrade_path_whole_value_unchanged, 123_method_row_tail_param (6), 124_row_kinded_nominal_params, 125_row_rest_derived_from_equation, 126_row_extend_target (2), 127_row_conditional_inherent_impls, stage14_11_impl_method_own_generic_bound.
  • Non-Copy value moved twice in one expression: rfc0034_aspect_extend_and_match_bound (self.item.compare(self.item)).
  • Move out of a reference in a &self / &var self method on a generic T: 80_conditional_impl_defines_assoc_type (return self.value), 81_generic_struct_iterable_for_in. --move-check rejects both with cannot move self.value out of a reference. The report's moved-site column shows 0:0 for them because the move is a retained-fact, not a source span.
  • Two closures both capturing the same &var by move: 75_two_closures_share_state_via_pointer.

So the count was not a regression and hid no checker bug. All 15 fixtures have since been made ownership-clean and now run with move_check = true, keeping what each one tests: fresh values for by-value receivers and arguments (aspect_impls_with_disjoint_bounds, default_methods_on_generic_impls_variants, row_conditional_aspect_impls, 123_method_row_tail_param, 124_row_kinded_nominal_params, 125/126/127), Copy for the value-semantics fixtures (100, 114), .clone() with a Clone bound for the generic self.value returns (80, 81), borrowed comparison receivers (rfc0034_..., stage14_11_...), and a single owner of the &var with the second closure snapshotting x after inc is done (75).

After the cleanup move-check-count reports 83 violations in 76 fixtures, all intentional negatives (73 T0019, two other typecheck errors, one R0015); skipped_generic_bodies_user_total is still 0. The acceptance rule ("zero, or every one a documented negative") now holds.

Verdict: still not clear for release. 0 GAP cells remain (NR × ALL is covered by evaluator/records/all_fields_on_nominal_row_argument since #1444); ER × DG is now covered by release_matrix_diag_rest_remainder_is_not_branded{,_nonempty} (#1445), and the move-violation rule now holds. #1440 and #1442 landed after the original run, so this report needs a final rerun on the frozen tree.

Final rerun — 2026-10-14​

Run against core develop at 4ab80fc1 and docs main at 92a4871, after every v0.14.0 and v0.14.1 follow-up from this review round had landed (PRs #1422, #1428, #1442, #1443, #1449, #1450, #1451, #1452, #1453 and their docs counterparts).

Matrix. All 153 pairs are represented and none is a GAP. The table above now cites an evidence fixture in every cell (E39–E74 are new in this rerun; E58 was a BUG cell, #1446, and passes now). Cells that still cite an F-number record the historical failure next to the fixture that passes after its fix.

Findings. F01–F11 and the follow-ups found during the rerun are all fixed and closed: #1398, #1405–#1407, #1411–#1414, #1420, #1421, #1423–#1427 (v0.14.0), and #1444–#1448 (the rerun's own findings: all-fields on a nominal row argument, rest-pattern remainder message and runtime brand, moved_span, T[] spelling). The v0.14.0 milestone has no open issue. #273's broader fail-open policy is closed too; the abstract-bodies work removed the skipped generic bodies.

Full-tree verification (release mode, one run on the tree above):

  • cargo test --release --workspace: 1,380 integration cases, 377 frontend, 97 type-engine, 26 interpreter, 3 benchmark; 0 failures.
  • cargo clippy --release --workspace --lib -- -D warnings -D clippy::pedantic and cargo fmt --check: clean.
  • move-check-count: skipped_generic_bodies_user_total=0; user_move_violations=84 in 77 fixtures, every one an intentional negative (73 T0019, two other typecheck errors, one R0015, and the rerun's added negatives), see the triage above. No default-mode fixture violates ownership.
  • check_doc_examples.py over the README, tutorials and spec: 193 passed, 0 failed; the records blog post: 15 passed, 0 failed.
  • rfc.py check and check_architecture.py: clean; generated architecture evidence is current.

Known limitations that remain and do not block the release.

  • Same-value re-entrancy of a var closure (R0015) is a runtime error; the static form is #1026 (v0.16.0), tracked as GAP-OWNERSHIP-001.
  • Ownership enforcement is still off by default; the corpus is now clean under it.
  • Drop destructor invocation and explicit drop are unimplemented (#261, #949), exempted in the spec coverage report.

Sign-off. Every pair of the matrix has a passing fixture, the full release suite is green on 4ab80fc1, and every finding is resolved. Clear for /cut-release v0.14.0, provided no further change lands on develop: this report is stale as soon as the tree moves, and the release freeze exists for that. The records blog post is still draft: true and needs its real date and the part-2 link from the first post at release time.

Second rerun — 2026-10-15​

The 2026-10-14 sign-off went stale: develop moved after 4ab80fc1. Run against core develop at 4232ab95 and docs main at d3deb6f, after the follow-ups of the last review round (PRs #1457, #1463, #1464, #1466, #1467 and their docs counterparts).

What changed since the final rerun.

  • #1456: a typed negative row bound is not an absent-label fact.
  • #1460 and #1461: Handle.{ ..R } is exempt from the forget rule; a misplaced open projection gets a targeted error.
  • #1454: the inference pass narrows on a projection that moves a non-Copy field.
  • #1465: a field write through &var to a residual resolves its present fields; an absent field through a reference is T0003.
  • #1455: a projection is a move that keeps the brand (spec and RFC-0137 reworded); &h.{ f } / &var h.{ f } of a non-Copy field is T0001 until a borrowing form exists (RFC-0109/0122).

New interaction evidence (all pass with --move-check):

#FixturePair
E75evaluator/records/release_matrix_projection_move_captureCL × OW × NR: a once capture of a projected, branded value; the narrowed source still serves its Copy field
E76evaluator/records/release_matrix_projection_then_struct_patternPM × OW: the projected value travels through Perhaps and is matched out
E77evaluator/records/release_matrix_residual_write_then_restoreOW × NR: write through &var to a residual, then restore the moved field
E78evaluator/records/release_matrix_open_projection_aliasOR × TA × NR: Handle.{ ..R } absorbs an aliased value with a non-Copy remainder
E79evaluator/records/release_matrix_copy_projection_borrow_okOW × TA: a Copy-only projection may still be borrowed, through an alias

The negative sides are the #1455/#1465 fixtures in evaluator/records/ (repeat projection T0003, through-reference move T0019, borrowed projection T0001, whole reference not narrowing T0001, absent-label write through a reference T0003).

Findings. None new. No GAP cell. Every previously reported finding remains fixed.

Full-tree verification (release mode, on the tree above):

  • cargo test --release --workspace: 1,404 integration cases, 377 frontend, 97 type-engine, 26 interpreter, 3 benchmark; 0 failures.
  • cargo clippy --release --workspace --lib -- -D warnings -D clippy::pedantic and cargo fmt --check: clean.
  • move-check-count: skipped_generic_bodies_user_total=0; user_move_violations=85 in 78 fixtures (84 in 77 before): the one addition is the intentional T0019 negative for projection through a reference. No default-mode fixture violates ownership.
  • check_doc_examples.py over the README, tutorials and spec: 193 passed, 0 failed; the records blog post: 20 passed, 0 failed.
  • rfc.py check and check_architecture.py: clean.

Sign-off. Every pair of the matrix has a passing fixture, the full release suite is green on 4232ab95, and every finding is resolved. Clear for /cut-release v0.14.0, provided no further change lands on develop. The records blog post is still draft: true.

Third rerun — 2026-10-18​

The 2026-10-15 sign-off went stale: nine more changes reached develop after 4232ab95. Run against core develop at 08872146 plus the fixture branch test/v0.14.0-late-cross-feature-fixtures (tip d1f40994), and docs main after #373.

What changed since the second rerun.

  • RFC-0180 / #1473: a row argument may be a literal row, Req<..{ host: String, ..R }>, with closed forms ..{ host: String } and ..{}.
  • RFC-0179 / #1469, #1471: a by-value open-row parameter takes the whole record; T0033 keeps only spread-through-a-reference; a Drop brand given to such a parameter is T0036.
  • #1488: a private field stays private through a residual (read, project, name), and a public signature may not name one.
  • #1478 / RFC-0181: anonymous open-record tails in let/var annotations and closure parameters; T0032 in return types and written function types.
  • #1472: a nested row extension is flattened once its tail resolves (chained setters keep earlier fields).
  • #1455 follow-up: using a moved-out field of a branded residual is T0019.

New labels. WH (whole-record open rows), LR (literal row arguments), VS (residual privacy and the public-signature rule), AT (anonymous open-record tails), RE (flattened row extension). The #1455 follow-up is folded into OW.

New matrix rows (new feature × the 18 existing labels; E# are the fixtures below):

NRORALLIMRGASRPERARDGTACLOWDYPMMOGACO
WHE82E81E92E82E92n/a-1E81n/a-2E80E93E89E80E87n/a-3E90E88E82E80
LRE83E83E107E85E83E94E85E95n/a-4E96E97E84E85E98E91n/a-5E83n/a-4
VSE99E88n/a-6n/a-6n/a-6n/a-6n/a-6n/a-2n/a-4E100E101n/a-7E88n/a-3n/a-6E88E88n/a-4
ATE102E86n/a-8n/a-8n/a-8n/a-8n/a-8n/a-2n/a-4E103E104E80n/a-8n/a-3n/a-8n/a-5n/a-8n/a-4
REE83E83n/a-9E85E83n/a-9E85n/a-2n/a-4n/a-9E97E91E85E98E91n/a-5E83n/a-4

Among the new features: WH×AT E86, WH×LR E105 (literal_row_arg_setter_functions: a literal-row result passed to an open-row parameter), WH×VS E88, WH×RE E85/E82 chain, LR×AT E106 (literal_row_arg_anonymous_tail_in_return_is_t0032), LR×VS n/a-6, LR×RE E83, VS×AT n/a-8, VS×RE n/a-9, AT×RE n/a-8.

Legend. n/a-1: a record whose fields are all Copy is itself Copy, so passing it copies and the whole-record rule changes nothing (RFC-0179 §1.3). n/a-2: an empty remainder, empty residual or empty row has nothing to own, hide or discard; the rule is vacuous. n/a-3: dyn Aspect objects have no row to name. n/a-4: array and collection element types do not interact with a row rule beyond what E80 shows (a remainder holding an array of Strings). n/a-5: imports resolve the nominal type, not the row written in an argument or annotation. n/a-6: visibility is checked on names written in a signature, field access and projection; none of these label pairs gives it another route. n/a-7: closures are not declarations, so the public-signature rule never applies to them. n/a-8: anonymous-tail annotations only occur in parameters, annotations and closure parameters (RFC-0181), where the other label has no distinct behaviour. n/a-9: a row extension is only observable as a row; all-bounds, field-wise built-ins and diagnostics see the same type as for any open row (see E92, E94).

Fixtures added or reused.

#FixturePair
E80evaluator/records/release_matrix_late_whole_record_closure_paramWH × CL × AT × AR × CO
E81evaluator/records/release_matrix_late_whole_record_rest_pattern_returnWH × RP × OW × OR
E82evaluator/records/release_matrix_late_whole_record_conditional_row_implWH × IM × GA × NR
E83evaluator/records/release_matrix_late_literal_row_generic_payloadLR × GA × RE × RG × NR × OR
E84evaluator/records/release_matrix_late_literal_row_written_function_typeLR × CL
E85evaluator/records/release_matrix_late_literal_row_consuming_setters_matchedLR × OW × RP × IM × RE
E86evaluator/records/release_matrix_late_anonymous_tail_then_whole_recordAT × WH × OR
E87typechecking/records/release_matrix_late_whole_record_argument_is_movedWH × OW (negative, T0019)
E88module_semantics/release_matrix_late_residual_privacy_with_whole_record_projectionVS × WH × OW × MO × GA × OR
E89evaluator/records/release_matrix_late_whole_record_alias_parameterWH × TA × GA
E90evaluator/records/release_matrix_late_whole_record_match_and_rest_patternWH × PM × RP
E91evaluator/records/release_matrix_late_literal_row_closure_chain_matchedLR × CL × PM × RE
E92typechecking/generics/abstract_open_row_forwarding_needs_no_copy_boundWH × ALL × RG
E93typechecking/records/open_projection_param_over_drop_brand_is_t0036WH × DG × OW
E94evaluator/records/release_matrix_late_literal_row_field_wise_cloneLR × AS
E95evaluator/records/literal_row_arg_setter_functionsLR × ER (..{})
E96typechecking/records/literal_row_arg_possibly_present_label_rejectedLR × DG
E97evaluator/records/literal_row_arg_in_alias_and_fieldLR × TA × RE
E98evaluator/records/release_matrix_late_literal_row_dyn_aspectLR × DY
E99typechecking/records/public_function_return_names_private_field_rejected (and the other public_* fixtures)VS × NR
E100typechecking/records/public_function_param_names_private_field_rejectedVS × DG
E101typechecking/records/release_matrix_late_public_alias_names_private_field_rejectedVS × TA
E102evaluator/records/anonymous_open_record_in_let_annotationAT × NR
E103typechecking/records/anonymous_open_record_return_type_is_t0032AT × DG
E104evaluator/records/release_matrix_late_anonymous_tail_aliasAT × TA
E105evaluator/records/literal_row_arg_setter_functionsWH × LR
E106typechecking/records/literal_row_arg_anonymous_tail_in_return_is_t0032LR × AT
E107evaluator/records/release_matrix_late_literal_row_all_boundLR × ALL

Fixtures that documented the findings, un-skipped once fixed: evaluator/records/release_matrix_late_println_named_record (#1492, with the cross-module regression module_semantics/generic_body_in_other_module_displays_named_record) and evaluator/records/release_matrix_late_literal_row_all_bound (#1493, E107, with the negative typechecking/records/literal_row_arg_all_bound_rejects_non_copy_remainder).

Findings.

  • #1492: println(r) of a named record raised I0001 (no method to_string on P), although r.to_string() worked. Fixed (core PR #1494): println is generic in std::core, and reconstructing its body for a record the caller declared looked the record up by name from std::core, where it is not visible; row_condition_fields now uses the value's declaration identity, as #1222 did for field access. It reproduced with any generic function in another module.
  • #1493: where all R: Copy was rejected (T0012) when R is the tail of a literal row argument, Req<..{ id: i64, ..R }>. Fixed (core PR #1494): the check recognised only Req<..R>; it now recognises the tail of a literal row too, and the bound is enforced at the call (negative fixture).
  • #1495, found while fixing #1493 and deferred to v0.14.1: a generic body that forwards an all R bound through a nominal's row argument (Req<..R> or the literal form) without declaring it is accepted at the definition and rejected at the first call as I0010. It predates RFC-0180 (reproduces with the variable form) and needs an RFC-0173 definition-time check, not a patch.
  • Observation, not filed: a closure parameter's type is not inferred from the expected written function type when the body accesses a field (apply(p, |q| { q.x }) needs |q: T|); it is independent of rows and reproduces with a plain struct.

Full-tree verification (debug profile on this machine, for disk reasons; the profile does not change results):

  • cargo test --workspace: 1,452 integration cases at the fixture branch tip (1,441 on develop before the late fixtures and the two fixes), 377 frontend, 97 type-engine, 26 interpreter, 3 benchmark; 0 failures.
  • cargo clippy --workspace --lib -- -D warnings -D clippy::pedantic and cargo fmt --check: clean.
  • move-check-count: skipped_generic_bodies_user_total=0; user_move_violations=91 in 81 fixtures, every one an intentional negative or documented case; the additions since the second rerun are the T0019/T0036/privacy negatives.
  • check_doc_examples.py over the README, getting-started, reference and blog: 220 passed, 0 failed.
  • rfc.py check and check_architecture.py: clean.

Sign-off. Every pair of the new rows has a passing fixture or a justified n/a, the findings #1492 and #1493 are fixed with regression fixtures, and #1495 is deferred to v0.14.1 (it predates the milestone and is not a regression). The release suite is green on 95f8b824. PASS — clear for /cut-release v0.14.0, provided core PR #1494 and this report merge and nothing else lands on develop (a new commit makes the <short-sha> stale).