Skip to main content
Next (unreleased) · docs c218d875 · core f63c1e69 · built 2026-10-26 22:39 UTC

Integration testing — v0.14.1

Session run: 2026-10-26 · against develop at 9ce74e03 (all 53 milestone issues closed; the two process gates — rfc.py check and the pending-marker release gate — pass). Result: PASS — clear to release. The language owner recorded the language-visible changes as exceptions to the patch rule on 2026-10-26 (see Release type below).

Features exercised​

Twenty language-visible capabilities, from the ## v0.14.1 changelog section (diagnostics block and fixes block). No RFC reached 4-implemented this milestone; RFC-0181 reached 3-integrated (#1480, its slice issues #1483 and #1484 are closed and listed below). They are grouped into seven for the matrix. The grouping is a deliberate departure from a 20×20 grid: several members of a group share one code path, and a per-feature grid would invite cells claimed without a fixture.

GroupCapabilities
A diagnosticsmethod call on a function value is T0003 (#1242); whole value where a narrowed type is required, wording (#1458); record diff in unification errors (#1483); T0032 advice for an anonymous open record in a return type (#1484)
B block-local type identitysame-named block-local records with equal field names (#1553); zero-field local types (#1555); outer type restored after an inner block (#1561); identity kept on annotations and enum values (#1568)
C block-local type usabilitygeneric local struct/record/enum (#1556); local enums constructed and matched (#1557); struct patterns on local structs (#1565)
D namespaces and duplicatesT0037 duplicate top-level name (#1560); separate type and value namespaces, imports bring both (#1571); T0034 duplicate method in an aspect impl or aspect (#1229)
E value shadowing and visibilitya local shadows a same-named module function used as a value (#1578); private function beside a public imported type is T0009 (#1575)
F reserved and core namesintrinsic type names reserved, T0038 (#1582); shadowing Perhaps/Result keeps core behaviour on values from std (#1585)
G core paths and aliasesstd::core::T in a type position (#1587); variants of an aliased core enum (#1588)

Interaction matrix​

Upper triangle; the diagonal is covered per PR. Each cell is a fixture (path under metel-interpreter/tests/integration/sources/), n/a: <reason>, or BUG→#N (documented by a skip-tagged fixture). Fixtures added by this session are marked new.

BCDEFG
ABUG→#1618 (diff not applied to a named local record) typechecking/records/neg_a_record_missing_a_field_for_a_named_record_reports_a_record_diffBUG→#1618 (same cause)n/a: wording of expression diagnostics against declaration-level errors; no program reaches both messagestypechecking/structs/neg_method_on_a_function_value_held_in_a_local_is_t0003 newn/a: no shared pathn/a: no shared path
B—evaluator/enums/local_generic_enum_holding_a_local_struct new; evaluator/move_check/two_local_generic_records_of_one_name_keep_distinct_identity new; evaluator/move_check/zero_field_generic_local_record_is_copied new; evaluator/records/projection_on_same_named_local_records_in_two_functions newBUG→#1615 (a local type does not shadow a module-level one) evaluator/structs/a_local_struct_shadows_a_module_level_struct newevaluator/structs/an_inner_block_type_and_a_local_let_shadow_independently newBUG→#1615 for a core name evaluator/enums/a_local_enum_shadows_a_std_core_type new; typechecking/types/neg_a_local_type_named_like_an_intrinsic_type_is_t0038BUG→#1615 (a local Perhaps beside a qualified std::core::Perhaps)
C—n/a: T0037 and the namespace rules apply to top-level declarations only; local types live in a block scopeevaluator/functions/every_binding_kind_shadows_a_module_function new (pattern binding against a local struct)typechecking/types/neg_a_local_type_named_like_an_intrinsic_type_is_t0038n/a: no shared path
D—evaluator/structs/a_private_function_does_not_hide_a_public_type_of_its_name; typechecking/types/neg_private_function_beside_an_imported_public_type_is_t0009evaluator/functions/intrinsic_type_names_stay_usable_as_function_and_let_names new; module_semantics/an_imported_perhaps_of_the_users_own_sits_beside_the_core_one newmodule_semantics/an_aliased_import_brings_a_type_and_a_function_of_one_name new
E—n/a: value shadowing and type-name reservation are different namespacesn/a: value shadowing does not touch type-path resolution
F—module_semantics/an_imported_perhaps_of_the_users_own_sits_beside_the_core_one new; BUG→#1616 for the expression form evaluator/perhaps_result/a_qualified_core_variant_builds_the_core_value_when_the_module_shadows_it new

Within-group pairs that carry their own coverage: C×C evaluator/enums/local_enum_variant_holding_a_local_record_is_matched_by_pattern new and evaluator/generics/local_generic_struct_record_and_enum; D×D typechecking/types/neg_struct_and_enum_of_one_name_is_t0037, typechecking/structs/duplicate_method_in_one_aspect_declaration_is_t0034; G×G module_semantics/aliased_core_enum_constructs_variants_under_its_annotation, module_semantics/std_core_qualified_path_names_a_core_type.

Against the subsystem table in /milestone-integration-test: the milestone adds a subsystem the table does not list — name resolution and declaration identity (groups B to G). Treated as high-risk for this session, and every high-risk pair above is either a fixture or a documented bug. The older high-risk subsystems were crossed with the new features rather than skipped: closures × block-local types (evaluator/closures/local_types_cross_closure_boundaries new, under --move-check), move/ownership × block-local identity (the three move_check/ fixtures), pattern matching × shadowing (every_binding_kind_shadows_a_module_function), and record narrowing × same-named local records (records/projection_on_same_named_local_records_in_two_functions).

Fixtures added​

Metel-core#1619 (tracking issue #1617). Passing: 10 single-file evaluator fixtures, 2 module fixtures and 1 negative fixture. Documenting a finding (skip-tagged, each fails if unskipped): 4 fixtures for #1615, #1616 and #1618.

Findings​

None is a regression: each reproduces identically on the released v0.14.0 binary. None is soundness. Under the bug policy they are filed to Backlog and do not block the release.

  • #1615 — a block-local struct/record/enum does not shadow a same-named module-level, imported or std::core type, contrary to spec.declarations.variables.scoping-and-shadowing.legality-1 and modules.md. severity:incorrect. Deferred to Backlog.
  • #1616 — std::core::Result::Ok { .. } in an expression resolves to the module's own Result when it declares one. The #1587 changelog entry says the expression form "already worked"; that holds only when nothing shadows the name. severity:incorrect. Deferred to Backlog.
  • #1618 — the #1483 record diff covers a structural record type but not a named record, which still prints cannot unify { x: ?1 } with P. The changelog entry for #1483 overstates the fix. severity:diagnostic. Deferred to Backlog.

Release type​

The milestone and ROADMAP.md type v0.14.1 as a patch: "no accepted programs change". The ## v0.14.1 changelog section also contains changes to which programs are accepted:

  • previously accepted, now rejected: T0037 duplicate top-level names (#1560), T0038 reserved intrinsic type names (#1582), T0034 extended to aspect impls and aspects (#1229);
  • previously rejected, now accepted: block-local enums (#1557), generic block-local types (#1556), struct patterns on block-local structs (#1565), types named after an inner block ends (#1561), imports bringing a name in every namespace (#1571), a local let shadowing a module function (#1578), shadowed Perhaps/Result keeping core behaviour (#1585), and the qualified and aliased core types (#1587, #1588);
  • under --move-check only: block-local type identity (#1553, #1555, #1568).

Decision (language owner, 2026-10-26): these are recorded as exceptions on the v0.14.1 milestone, next to the earlier #1587/#1588 exception, and the release ships as v0.14.1. The milestone description lists each. This is not a test result; it is the answer to the release-type question this session raised, and it does not change the verdict.

Full-tree verification​

On develop at 9ce74e03:

  • cargo test --release --workspace: all suites pass (1514 integration, 427, 97, 26, 4, 3 and the doc-test targets; 0 failures). With the session fixtures (#1619): 1530 integration, 0 failures.
  • cargo clippy --release --workspace --lib -- -W clippy::pedantic: no warnings.
  • move-check-count: skipped_generic_bodies_user_total=0 (baseline 18). user_move_violations=100, inside the 84 to 108 range the v0.14.0 sessions recorded; this session did not re-triage each one.
  • check_doc_examples.py over README.md, the tutorials and the spec: 196 passed, 0 failed, 89 skipped.

Freeze reconciliation (2026-10-26)​

Commits landed on develop after 9ce74e03 and before the tag. None changes language-visible behaviour, so the PASS above stands against the frozen tip: the session's own fixtures (metel-core#1619, tests only, and the docs gitlink bumps #1620 and the release commit); and the release commit itself (crate version bump, typechecker.md notes, docs gitlink). The tip the tag points at is named in the release report, not here.

Sign-off​

All high-risk pairs have a fixture or a filed finding. The full release suite is green on 9ce74e03. The three findings are deferred to Backlog, none a regression or a soundness bug. Clear for /cut-release v0.14.1.