c218d875 · core f63c1e69 · built 2026-10-26 22:39 UTCIntegration 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.
| Label | Availability | Capability | Source |
|---|---|---|---|
| NR | v0.14 | Named records; row/anonymous-row arguments on reusable nominal types | 791, 1310, 1307 |
| OR | v0.14 | Open rows, decomposition equations, row extensions and forwarding | 1301, 1306, 1310 |
| ALL | v0.14 | Field-wise bounds and Copy-safe width narrowing | 1302, 1337 |
| IM | v0.14 | Conditional row impls; disjoint candidates and brand priority | 833, 1322, 1386 |
| RG | v0.14 | Rigid generic bodies, associated bindings, conditional grants, bound forwarding | 1364 |
| AS | v0.14 | Field-wise record Copy/Display/Clone | 1337, 1338, 1350 |
| RP | v0.14 | Owned record rest patterns, field discard, mutable bindings, row spread | 1399 |
| ER | v0.14 extension | Empty row residual identity, use and restoration | 1398 |
| AR | v0.14 extension | Prefix arrays, sized literal inference and lookup, List iteration | 1291, 1296, 871 |
| DG | v0.14 | Runtime/internal error classification and generic/row diagnostics | 991, 1297, 1386 |
| TA | previous releases | Transparent aliases, including function and nominal aliases | RFC-0160 |
| CL | previous releases | Capture lists, once/var closures, written move-only functions, multiplicity widening | RFC-0050/0134/0152/0153/0154/0157/0166 |
| OW | previous releases | Whole/partial moves, path-sensitive ownership, Copy/Drop and references | RFC-0071/0117/0137 |
| DY | previous releases | dyn Aspect coercion and dispatch | RFC-0008 |
| PM | previous releases | Struct/enum patterns, generic payloads, Perhaps/Result and propagation | RFC-0078 and pattern-matching spec |
| MO | previous releases | Imports, re-exports, visibility and cross-module nominal identities | module spec; v0.13.1 identity fixes |
| GA | previous releases | Generic functions/aspects, associated types and default methods | RFC-0138/0082; v0.14 fixes 1329–1332/1365 |
| CO | previous releases | Collections, array methods, strings and interpolation | runtime/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.
| NR | OR | ALL | IM | RG | AS | RP | ER | AR | DG | TA | CL | OW | DY | PM | MO | GA | CO | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| NR | — | E8 | E74 | E2 | E2 | E5 | E8 | E4 | E3 | E49 | E31/F08 | E51 | E8 | E57 | E8 | E33/F09 | E5 | E5 |
| OR | — | E6/E24/F04 | E29/F06 | E6 | E25/F04 | E8 | E30 | E45 | E47 | E31/F08 | F01 | F03 | E28 | E8 | E7 | E7 | E54 | |
| ALL | — | E29/E37 | E6 | E25/F04 | E30 | E30 | E45 | E35 | E31/E35 | F01 | E30/E34 | E57 | E52 | E56 | E55 | E54 | ||
| IM | — | E2/F06 | E39 | E40 | E40 | E41 | E50 | E59 | E21 | E59 | E28 | E59 | E33 | E2 | E59 | |||
| RG | — | E25/F04 | E30/E38 | E30 | E42 | E36 | E31/E36 | F01 | E30/E34/F11 | E60 | E60 | E33/F09 | E15/F07 | E60 | ||||
| AS | — | E43 | E43 | E3 | E46 | E17 | E17 | E17 | E28 | E60 | E23/F05 | E5/E20 | E5 | |||||
| RP | — | E30 | E44 | E70 | E53 | F01 | F03 | E61 | E8 | E56 | E30 | E61 | ||||||
| ER | — | E44 | E73 | F02 | E27/F02 | E27/F02 | E58 | E62 | E56 | E30 | E62 | |||||||
| AR | — | E48 | E53 | E51 | E61 | E14 | E52 | E56 | E61 | E3 | ||||||||
| DG | — | E66 | E67 | E68 | E71 | E69 | E65 | E68 | E72 | |||||||||
| TA | — | E13 | E63 | E12 | E18 | E26 | E31 | E63 | ||||||||||
| CL | — | E10/E27 | E16 | E63 | E22 | E19/E27 | E63 | |||||||||||
| OW | — | E28 | E11 | E64 | E27 | E63 | ||||||||||||
| DY | — | E18 | E33 | E32/F10 | E63 | |||||||||||||
| PM | — | E64 | E63 | E63 | ||||||||||||||
| MO | — | E7 | E64 | |||||||||||||||
| 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.
| Evidence | Fixture | Interaction |
|---|---|---|
| E1 | evaluator/structs/126_row_extend_target.mtl | Executable nominal row typestate and reverse spread. |
| E2 | typechecking/generics/row_conditional_method_declared_bound_satisfied.mtl | Declared row grant permits the conditional nominal method. |
| E3 | evaluator/structs/126_record_clone.mtl | Named nested record clone; array field; custom Clone dispatch. |
| E4 | evaluator/records/empty_residual_checked.mtl | Empty nominal/anonymous residuals, exact pass/return, restoration, Copy fields. |
| E5 | evaluator/aspects/record_display.mtl | Nominal/anonymous Display through a bounded generic borrowed wrapper and interpolation. |
| E6 | typechecking/generics/abstract_open_row_narrowing_all_copy_is_allowed.mtl | Abstract width narrowing granted by all R: Copy. |
| E7 | module_semantics/cross_module_method_row_tail_param/main.mtl | Imported method with an open-row parameter. |
| E8 | evaluator/records/row_remainder_construction.mtl | Mutable remainder binding, nominal rest match, Copy reference spread; corpus mode is not move-check. |
| E9 | evaluator/aspects/record_target_all_fields_constraint.mtl | Custom Label/Mark field-wise constraint; not evidence for built-in Copy/Display/Clone, so not used for ALL × AS. |
| E10 | evaluator/closures/v0_13_0_x_move_capture_of_narrowed_struct.mtl | Old-release nonempty narrowed capture regression; does not prove the new empty case. |
| E11 | evaluator/structs/v0_13_0_x_struct_pattern_partial_move_narrows.mtl | Old-release pattern move and local restoration. |
| E12 | evaluator/type_aliases/v0_13_0_x_alias_for_dyn_aspect.mtl | Aliased existential coercion/dispatch and collection. |
| E13 | evaluator/type_aliases/01_basic_and_parameterised.mtl | Aliases for written callbacks and higher-order use. |
| E14 | evaluator/aspects/101_dyn_aspect_array_literal_element_coercion.mtl | Fixed/dynamic arrays of existential elements. |
| E15 | evaluator/aspects/generic_aspect_method_runtime.mtl | Aspect method's own generics instantiated at multiple concrete types. |
| E22 | module_semantics/release_matrix_closure_cross_module/main.mtl | A helper returns a captured once closure through a public alias; the importing module invokes it with move checking enabled. |
| E29 | evaluator/records/release_matrix_row_impl_facts.mtl | Positive/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. |
| E30 | evaluator/records/release_matrix_bound_remainders.mtl | Abstract 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. |
| E31 | evaluator/type_aliases/release_matrix_row_aliases.mtl | Ordinary 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). |
| E32 | evaluator/aspects/release_matrix_generic_dyn_defaults.mtl | Aliased 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). |
| E33 | module_semantics/release_matrix_row_identities/main.mtl | Two 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). |
| E34 | typechecking/generics/release_matrix_noncopy_remainder_twice.mtl | Uncalled generic body reusing an unconstrained remainder reports T0019 at the second use, with move checking enabled. |
| E35 | typechecking/generics/release_matrix_all_copy_alias_violation.mtl | String field violates all-Copy despite an aliased generic result: T0012 plus field-specific message. |
| E36 | typechecking/generics/release_matrix_rigid_alias_violation.mtl | Transparent alias cannot collapse a declared type parameter to i64: definition-time T0001. |
| E37 | typechecking/generics/release_matrix_all_copy_conditional_missing.mtl | Structural conditional method without the all-Copy grant reports T0035 in an uncalled generic definition. |
| E38 | typechecking/generics/release_matrix_rigid_rest_violation.mtl | Destructuring with an empty rest does not make its generic payload concrete: definition-time T0001. |
| E39 | evaluator/records/release_matrix_conditional_impl_derived_aspects | IM × AS; added in the 2026-10-13 rerun. |
| E40 | evaluator/records/release_matrix_conditional_impl_residual | IM × RP, IM × ER; added in the 2026-10-13 rerun. |
| E41 | evaluator/records/release_matrix_conditional_impl_array_field | IM × AR; added in the 2026-10-13 rerun. |
| E42 | evaluator/records/release_matrix_rigid_generic_array_bodies | RG × AR; added in the 2026-10-13 rerun. |
| E43 | evaluator/records/release_matrix_rest_clone_display | AS × RP, AS × ER; added in the 2026-10-13 rerun. |
| E44 | evaluator/records/release_matrix_rest_array_fields | RP × AR, ER × AR; added in the 2026-10-13 rerun. |
| E45 | evaluator/records/release_matrix_open_row_array_all_copy | OR × AR, ALL × AR; added in the 2026-10-13 rerun. |
| E46 | typechecking/records/release_matrix_record_display_field_missing | AS × DG; added in the 2026-10-13 rerun. |
| E47 | typechecking/records/release_matrix_open_row_missing_label | OR × DG; added in the 2026-10-13 rerun. |
| E48 | typechecking/records/release_matrix_sized_array_length_mismatch | AR × DG; added in the 2026-10-13 rerun. |
| E49 | parsing/negative_record_public_field_is_parse_error | NR × DG; added in the 2026-10-13 rerun. |
| E50 | typechecking/generics/row_conditional_impls_overlap_is_t0015 | IM × DG; added in the 2026-10-13 rerun. |
| E51 | evaluator/records/release_matrix_residual_array_captures | NR × CL, AR × CL; added in the 2026-10-13 rerun. |
| E52 | evaluator/records/release_matrix_patterns_open_rows_arrays | ALL × PM, AR × PM; added in the 2026-10-13 rerun. |
| E53 | evaluator/records/release_matrix_alias_residual_arrays | RP × TA, AR × TA; added in the 2026-10-13 rerun. |
| E54 | evaluator/records/release_matrix_collection_open_rows | ALL × CO, OR × CO; added in the 2026-10-13 rerun. |
| E55 | evaluator/records/release_matrix_all_copy_associated_source | ALL × GA; added in the 2026-10-13 rerun. |
| E56 | module_semantics/release_matrix_record_rows_across_modules | ALL × MO, RP × MO, ER × MO, AR × MO; added in the 2026-10-13 rerun. |
| E57 | evaluator/records/release_matrix_dyn_row_impls | NR × DY, ALL × DY; added in the 2026-10-13 rerun. |
| E58 | evaluator/records/release_matrix_empty_residual_dispatch_follows_static_type | ER × DY; added in the 2026-10-13 rerun. |
| E59 | evaluator/records/release_matrix_conditional_impl_alias_collection | IM × TA, IM × OW, IM × PM, IM × CO; added in the 2026-10-13 rerun. |
| E60 | evaluator/records/release_matrix_rigid_generics_dyn_patterns | RG × DY, RG × PM, RG × CO, AS × PM; added in the 2026-10-13 rerun. |
| E61 | evaluator/records/release_matrix_rest_dyn_collections | RP × DY, RP × CO, AR × OW, AR × GA; added in the 2026-10-13 rerun. |
| E62 | evaluator/records/release_matrix_empty_residual_collections_patterns | ER × PM, ER × CO; added in the 2026-10-13 rerun. |
| E63 | evaluator/records/release_matrix_prior_release_pairs | TA × OW, TA × CO, CL × PM, CL × CO, DY × CO, OW × CO, PM × GA, PM × CO; added in the 2026-10-13 rerun. |
| E64 | module_semantics/release_matrix_enum_array_generic_across_modules | OW × MO, PM × MO, MO × CO; added in the 2026-10-13 rerun. |
| E65 | module_semantics/release_matrix_enum_variant_fields_private_across_modules | DG × MO; added in the 2026-10-13 rerun. |
| E66 | typechecking/records/release_matrix_diag_alias_argument_mismatch | DG × TA; added in the 2026-10-13 rerun. |
| E67 | typechecking/records/release_matrix_diag_closure_capture_needs_list | DG × CL; added in the 2026-10-13 rerun. |
| E68 | typechecking/records/release_matrix_diag_generic_double_move | DG × OW, DG × GA; added in the 2026-10-13 rerun. |
| E69 | typechecking/records/release_matrix_diag_non_exhaustive_enum_match | DG × PM; added in the 2026-10-13 rerun. |
| E70 | typechecking/records/release_matrix_diag_rest_names_absent_field | RP × DG; added in the 2026-10-13 rerun. |
| E71 | typechecking/aspects/dyn_generic_method_excluded_{local,parameter,tuple} | DG × DY; added in the 2026-10-13 rerun. |
| E72 | typechecking/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. |
| E73 | typechecking/records/release_matrix_diag_rest_remainder_is_not_branded{,_nonempty} | ER × DG; added in the 2026-10-13 rerun. |
| E74 | evaluator/records/all_fields_on_nominal_row_argument | NR × 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_pointermoves the same mutable-reference binding into two closures; seven struct/row fixtures reuse consumed nominal values;stage14_11_impl_method_own_generic_boundpasses the same non-CopyNumtwice. 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 limitation | Bodies |
|---|---|
| Aspect/default-method lookup on opaque symbolic receivers | 8 |
| Projection fields on opaque symbolic nominal arguments | 4 |
| Return-only generic inference | 3 |
| Mutable symbolic row field assignment | 2 |
| Discarded field in a symbolic nominal record row | 1 |
| Conditional method on a symbolic receiver | 1 |
| Numeric operator in an inferred generic signature | 1 |
| Implicit capture in a let-polymorphic closure | 1 |
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 --allandcargo 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 interactions | Passing evidence | Unresolved boundary |
|---|---|---|
| OR × IM; ALL × IM | E29, E37 | F06: generic dispatch on an equation-derived remainder; E29's structural generic body also skips ownership reconstruction under #273. |
| RG × RP; RG × ER; RG × OW | E30, E34, E38 | F11: associated-type row result reconstruction can hide a double move under #273. |
| ALL × RP; ALL × ER; ALL × OW | E30, E34 | Positive all-Copy and negative unconstrained cases are checked; this does not clear all Clone/custom-aspect reconstruction cases. |
| RP × ER; RP × GA; ER × GA | E30 | Empty and nonempty rest forwarding through a generic aspect method passes. |
| NR × TA; OR × TA; ALL × TA; RG × TA; TA × GA | E31, E35, E36 | F08: aliases declaring their own row parameter fail; ordinary generic and closed aliases pass. |
| NR × MO; IM × MO; RG × MO; DY × MO | E33 | F09: renamed nominal imports fail; the unrenamed control passes. |
| GA × DY | E32 | F10: 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 --allandcargo 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.
| Pairs | Evidence |
|---|---|
| IM × AS | evaluator/records/release_matrix_conditional_impl_derived_aspects |
| IM × RP; IM × ER | evaluator/records/release_matrix_conditional_impl_residual |
| IM × AR | evaluator/records/release_matrix_conditional_impl_array_field |
| RG × AR | evaluator/records/release_matrix_rigid_generic_array_bodies |
| AS × RP; AS × ER | evaluator/records/release_matrix_rest_clone_display |
| RP × AR; ER × AR | evaluator/records/release_matrix_rest_array_fields |
| OR × AR; ALL × AR | evaluator/records/release_matrix_open_row_array_all_copy |
| AS × DG | typechecking/records/release_matrix_record_display_field_missing (T0012, names the field) |
| OR × DG | typechecking/records/release_matrix_open_row_missing_label (T0012) |
| AR × DG | typechecking/records/release_matrix_sized_array_length_mismatch (T0001) |
| NR × DG; ALL × DG; IM × DG; RG × DG | existing: 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.
| Pairs | Evidence |
|---|---|
| NR × CL; AR × CL | evaluator/records/release_matrix_residual_array_captures |
| ALL × PM; AR × PM | evaluator/records/release_matrix_patterns_open_rows_arrays |
| RP × TA; AR × TA | evaluator/records/release_matrix_alias_residual_arrays |
| ALL × CO; OR × CO | evaluator/records/release_matrix_collection_open_rows |
| ALL × GA | evaluator/records/release_matrix_all_copy_associated_source |
| ALL × MO; RP × MO; ER × MO; AR × MO | module_semantics/release_matrix_record_rows_across_modules |
| NR × DY; ALL × DY | evaluator/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.
| Pairs | Evidence |
|---|---|
| IM × TA; IM × OW; IM × PM; IM × CO | evaluator/records/release_matrix_conditional_impl_alias_collection |
| RG × DY; RG × PM; RG × CO; AS × PM | evaluator/records/release_matrix_rigid_generics_dyn_patterns |
| RP × DY; RP × CO; AR × OW; AR × GA | evaluator/records/release_matrix_rest_dyn_collections |
| ER × PM; ER × CO | evaluator/records/release_matrix_empty_residual_collections_patterns |
| TA × OW; TA × CO; CL × PM; CL × CO; DY × CO; OW × CO; PM × GA; PM × CO | evaluator/records/release_matrix_prior_release_pairs |
| OW × MO; PM × MO; MO × CO | module_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 × TA | typechecking/records/release_matrix_diag_alias_argument_mismatch (T0001) |
| DG × CL | typechecking/records/release_matrix_diag_closure_capture_needs_list (T0026) |
| DG × OW; DG × GA | typechecking/records/release_matrix_diag_generic_double_move (T0019) |
| DG × PM | typechecking/records/release_matrix_diag_non_exhaustive_enum_match (T0008) |
| RP × DG | typechecking/records/release_matrix_diag_rest_names_absent_field, ..._rest_after_field_removed (T0012) |
| DG × DY | existing 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: Copyon arow Rthat 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 matchesfield-wise-row-constraints.legality-1. It is a documented restriction, but it means NR × ALL has no positive case.- Destructuring a named
recordwith..restyields an anonymous residual, notToken.{}; passing it whereToken.{}is required reportsT0001: 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.
| Class | Fixtures | Violations | Verdict |
|---|---|---|---|
Expects T0019 | 73 | 79 | Intentional. 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) | 2 | 2 | Intentional negatives; the error is raised by a later pass. |
Expects runtime R0015 (neg_mutating_reentrancy_rejected) | 1 | 2 | Intentional. |
Success with move_check = true | 0 | 0 | Clean, as the suite requires. |
Success in default mode, skip-tagged | 0 | 0 | None. |
| Success in default mode, not move-checked | 15 | 25 | All 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
selfor 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-
Copyvalue 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 selfmethod on a genericT:80_conditional_impl_defines_assoc_type(return self.value),81_generic_struct_iterable_for_in.--move-checkrejects both withcannot move self.value out of a reference. The report's moved-site column shows0:0for them because the move is a retained-fact, not a source span. - Two closures both capturing the same
&varby 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::pedanticandcargo fmt --check: clean.move-check-count:skipped_generic_bodies_user_total=0;user_move_violations=84in 77 fixtures, every one an intentional negative (73T0019, two other typecheck errors, oneR0015, and the rerun's added negatives), see the triage above. No default-mode fixture violates ownership.check_doc_examples.pyover the README, tutorials and spec: 193 passed, 0 failed; the records blog post: 15 passed, 0 failed.rfc.py checkandcheck_architecture.py: clean; generated architecture evidence is current.
Known limitations that remain and do not block the release.
- Same-value re-entrancy of a
varclosure (R0015) is a runtime error; the static form is #1026 (v0.16.0), tracked asGAP-OWNERSHIP-001. - Ownership enforcement is still off by default; the corpus is now clean under it.
Dropdestructor invocation and explicitdropare 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-
Copyfield. - #1465: a field write through
&varto a residual resolves its present fields; an absent field through a reference isT0003. - #1455: a projection is a move that keeps
the brand (spec and RFC-0137 reworded);
&h.{ f }/&var h.{ f }of a non-Copyfield isT0001until a borrowing form exists (RFC-0109/0122).
New interaction evidence (all pass with --move-check):
| # | Fixture | Pair |
|---|---|---|
| E75 | evaluator/records/release_matrix_projection_move_capture | CL × OW × NR: a once capture of a projected, branded value; the narrowed source still serves its Copy field |
| E76 | evaluator/records/release_matrix_projection_then_struct_pattern | PM × OW: the projected value travels through Perhaps and is matched out |
| E77 | evaluator/records/release_matrix_residual_write_then_restore | OW × NR: write through &var to a residual, then restore the moved field |
| E78 | evaluator/records/release_matrix_open_projection_alias | OR × TA × NR: Handle.{ ..R } absorbs an aliased value with a non-Copy remainder |
| E79 | evaluator/records/release_matrix_copy_projection_borrow_ok | OW × 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::pedanticandcargo fmt --check: clean.move-check-count:skipped_generic_bodies_user_total=0;user_move_violations=85in 78 fixtures (84 in 77 before): the one addition is the intentionalT0019negative for projection through a reference. No default-mode fixture violates ownership.check_doc_examples.pyover the README, tutorials and spec: 193 passed, 0 failed; the records blog post: 20 passed, 0 failed.rfc.py checkandcheck_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;
T0033keeps only spread-through-a-reference; aDropbrand given to such a parameter isT0036. - #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/varannotations and closure parameters;T0032in 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):
| NR | OR | ALL | IM | RG | AS | RP | ER | AR | DG | TA | CL | OW | DY | PM | MO | GA | CO | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| WH | E82 | E81 | E92 | E82 | E92 | n/a-1 | E81 | n/a-2 | E80 | E93 | E89 | E80 | E87 | n/a-3 | E90 | E88 | E82 | E80 |
| LR | E83 | E83 | E107 | E85 | E83 | E94 | E85 | E95 | n/a-4 | E96 | E97 | E84 | E85 | E98 | E91 | n/a-5 | E83 | n/a-4 |
| VS | E99 | E88 | n/a-6 | n/a-6 | n/a-6 | n/a-6 | n/a-6 | n/a-2 | n/a-4 | E100 | E101 | n/a-7 | E88 | n/a-3 | n/a-6 | E88 | E88 | n/a-4 |
| AT | E102 | E86 | n/a-8 | n/a-8 | n/a-8 | n/a-8 | n/a-8 | n/a-2 | n/a-4 | E103 | E104 | E80 | n/a-8 | n/a-3 | n/a-8 | n/a-5 | n/a-8 | n/a-4 |
| RE | E83 | E83 | n/a-9 | E85 | E83 | n/a-9 | E85 | n/a-2 | n/a-4 | n/a-9 | E97 | E91 | E85 | E98 | E91 | n/a-5 | E83 | n/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.
| # | Fixture | Pair |
|---|---|---|
| E80 | evaluator/records/release_matrix_late_whole_record_closure_param | WH × CL × AT × AR × CO |
| E81 | evaluator/records/release_matrix_late_whole_record_rest_pattern_return | WH × RP × OW × OR |
| E82 | evaluator/records/release_matrix_late_whole_record_conditional_row_impl | WH × IM × GA × NR |
| E83 | evaluator/records/release_matrix_late_literal_row_generic_payload | LR × GA × RE × RG × NR × OR |
| E84 | evaluator/records/release_matrix_late_literal_row_written_function_type | LR × CL |
| E85 | evaluator/records/release_matrix_late_literal_row_consuming_setters_matched | LR × OW × RP × IM × RE |
| E86 | evaluator/records/release_matrix_late_anonymous_tail_then_whole_record | AT × WH × OR |
| E87 | typechecking/records/release_matrix_late_whole_record_argument_is_moved | WH × OW (negative, T0019) |
| E88 | module_semantics/release_matrix_late_residual_privacy_with_whole_record_projection | VS × WH × OW × MO × GA × OR |
| E89 | evaluator/records/release_matrix_late_whole_record_alias_parameter | WH × TA × GA |
| E90 | evaluator/records/release_matrix_late_whole_record_match_and_rest_pattern | WH × PM × RP |
| E91 | evaluator/records/release_matrix_late_literal_row_closure_chain_matched | LR × CL × PM × RE |
| E92 | typechecking/generics/abstract_open_row_forwarding_needs_no_copy_bound | WH × ALL × RG |
| E93 | typechecking/records/open_projection_param_over_drop_brand_is_t0036 | WH × DG × OW |
| E94 | evaluator/records/release_matrix_late_literal_row_field_wise_clone | LR × AS |
| E95 | evaluator/records/literal_row_arg_setter_functions | LR × ER (..{}) |
| E96 | typechecking/records/literal_row_arg_possibly_present_label_rejected | LR × DG |
| E97 | evaluator/records/literal_row_arg_in_alias_and_field | LR × TA × RE |
| E98 | evaluator/records/release_matrix_late_literal_row_dyn_aspect | LR × DY |
| E99 | typechecking/records/public_function_return_names_private_field_rejected (and the other public_* fixtures) | VS × NR |
| E100 | typechecking/records/public_function_param_names_private_field_rejected | VS × DG |
| E101 | typechecking/records/release_matrix_late_public_alias_names_private_field_rejected | VS × TA |
| E102 | evaluator/records/anonymous_open_record_in_let_annotation | AT × NR |
| E103 | typechecking/records/anonymous_open_record_return_type_is_t0032 | AT × DG |
| E104 | evaluator/records/release_matrix_late_anonymous_tail_alias | AT × TA |
| E105 | evaluator/records/literal_row_arg_setter_functions | WH × LR |
| E106 | typechecking/records/literal_row_arg_anonymous_tail_in_return_is_t0032 | LR × AT |
| E107 | evaluator/records/release_matrix_late_literal_row_all_bound | LR × 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 namedrecordraisedI0001(no method to_string on P), althoughr.to_string()worked. Fixed (core PR #1494):printlnis generic instd::core, and reconstructing its body for a record the caller declared looked the record up by name fromstd::core, where it is not visible;row_condition_fieldsnow 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: Copywas rejected (T0012) whenRis the tail of a literal row argument,Req<..{ id: i64, ..R }>. Fixed (core PR #1494): the check recognised onlyReq<..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 Rbound 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 asI0010. 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 ondevelopbefore 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::pedanticandcargo fmt --check: clean.move-check-count:skipped_generic_bodies_user_total=0;user_move_violations=91in 81 fixtures, every one an intentional negative or documented case; the additions since the second rerun are theT0019/T0036/privacy negatives.check_doc_examples.pyover the README, getting-started, reference and blog: 220 passed, 0 failed.rfc.py checkandcheck_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).