§12 Partial-Move Validator Overcorrection
Chain predecessor: §07 (close-out) — INV-19 linear-chain edge (ordering-only; see 00-overview.md HISTORY 2026-06-07).
§12.0 Discovered Work Context
| Field | Value |
|---|---|
| Source commit | e186e2754 feat(typeck): conditional-partial-move validator + pre/post-contract validation + tagged_ptr drop walk |
| Sibling commit | f5a37d327 test(typeck): partial_move validator sibling tests |
| Discovery date | 2026-05-16 (via ./test-all.sh baseline run; 114 failures total, ~60 traced to this regression) |
Routing case (per routing.md §3) | (b) Independently-workable in plan’s bounded context |
| Insertion ordering | inserts_after: 11; sibling to §02 Validator Module (not amendment-of — §02 covers PC-2 enforcement post-body, §12 covers a NEW validator added at a separate seam) |
| Failures absorbed | ~60 (10 AOT E2043 + 47 interpreter destructure/match + 3 compile-fail contract-test expectations) |
§12.1 Mission
Narrow the conditional-partial-move validator’s projection-conditionality detection so it correctly distinguishes:
- Conditional partial moves (validator MUST flag) —
if c then move w.name else { /* w.name remains valid */ }; use(w)— branches diverge on whether a field projection was moved out, leaving the parent struct in an inconsistent partial-move state at the join point. - Unconditional total bindings (validator MUST NOT flag) —
let { name, age } = w/let (a, b, c) = t/let [$h, ..$rest] = xs— every branch (or the single binding site) moves the same set of fields/elements; no inconsistency at any join point. - Match-arm independent rebinding (validator MUST NOT flag) —
match scrutinee { Some(x) -> ..., None -> ..., _ -> ... }— each arm independently rebinds the scrutinee or its sub-projections; arms do not share partial-move state across the match expression because each arm’s binding scope ends at the arm’s->body terminus.
§12.2 Root Cause Hypothesis
Per CLAUDE.md §Invariant-Anchoring Before Test-Chasing:
| Question | Answer |
|---|---|
| What invariant does this validator enforce? | Reject moves out of struct fields where the projection is taken conditionally (branches diverge on whether the projection happened) — guards against the canonical w.name-on-one-branch failure mode where w ends up partially-moved on one path but not another, leaving downstream code observing inconsistent partial-move state. |
| Which downstream subsystem consumes this invariant? | AIMS lattice + ARC realization — partial-move state on a heap-allocated struct affects RC accounting (which fields’ RC ops fire on which branches) and drop ordering. |
| Tests fail → fix code-under-test or the invariant? | Almost always code-under-test. The validator predicate is too broad: it currently flags any pattern where field projection appears (destructure literals, match arms), regardless of whether the projection is genuinely conditional (taken on some branches, not on others) vs unconditional (taken always, in every branch / arm). |
| Where is the predicate? | compiler/ori_types/src/check/validators/partial_move/ (full path to be confirmed during §12.3 discovery — directory landed in e186e2754; section may include mod.rs, classify.rs, or similar). The predicate’s projection-walk logic does not currently exclude (a) let-binding destructure literals (no branch divergence — every bind takes every field), (b) match-arm rebinding scopes (each arm’s bindings live within the arm’s body terminus; no cross-arm partial-move state). |
§12.3 Implementation Sketch
| Phase | Description | Files touched |
|---|---|---|
| Discovery | Read compiler/ori_types/src/check/validators/partial_move/ end-to-end; map the projection-walk + branch-divergence detection. Identify where destructure literals and match-arm bindings flow through the validator. Compare against the validator’s stated invariant (§12.2 question 1) to identify the precise over-broad branch. | compiler/ori_types/src/check/validators/partial_move/**/*.rs |
| TDD matrix authoring | Author the §12 test matrix BEFORE touching validator code per CLAUDE.md §TDD for Bugs + tests.md §Matrix Testing Rule. Positive cells (destructure + match-arm rebinding patterns currently failing) + negative cells (genuine conditional partial moves the validator MUST continue to reject). Co-locate matrix in compiler/ori_types/src/check/validators/partial_move/tests.rs (sibling to the validator module per tests.rs SSOT convention). | compiler/ori_types/src/check/validators/partial_move/tests.rs |
| Validator narrowing | Modify the projection-conditionality predicate so destructure literals and match-arm rebinding scopes are excluded from the “conditional partial move” classification. Implementation shape TBD during §12.3 discovery — likely an early-return on (a) AST node is Pattern::Tuple/Pattern::Struct/Pattern::List in let-binding position, (b) AST node is a MatchArm body’s binding scope. NOT a syntactic skip-list — predicate refinement that captures the semantic distinction. | compiler/ori_types/src/check/validators/partial_move/<module>.rs |
| Compile-fail expectation refresh | Update expectation strings in 3 tests/compile-fail/*_contract_*.ori files to match the actual E2044/E2046/E2047 wording the validator now emits. Verify by reading the validator’s emission site + comparing the produced wording vs the test expectation. | tests/compile-fail/post_contract_void_return.ori, tests/compile-fail/pre_contract_not_bool.ori, tests/compile-fail/pre_contract_scope_violation.ori |
| Verification | timeout 150 ./test-all.sh clean; dual-exec parity clean; /tpr-review + /impl-hygiene-review clean. | — |
§12.4 Implementation Items
- §12.3.0 Discovery: read
compiler/ori_types/src/check/validators/partial_move/end-to-end; document the projection-walk + branch-divergence detection algorithm; identify the precise predicate location that classifies destructure/match-arm as “conditional partial move” when it should not. - §12.3.1 TDD matrix author (positive pins): write failing tests in
compiler/ori_types/src/check/validators/partial_move/tests.rscovering tuple/struct/list destructure + match-arm rebinding patterns. Tests assert validator does NOT flag these. RED state before §12.3.3 lands. - §12.3.2 TDD matrix author (negative pins): write tests in same file covering genuine conditional partial moves (canonical
w.name-on-one-branch repro + 2-3 variants). Tests assert validator DOES flag these. GREEN state immediately (validator already flags correctly here). - §12.3.3 Validator narrowing: modify the projection-conditionality predicate. §12.3.1 tests flip from RED to GREEN; §12.3.2 tests remain GREEN.
- §12.3.4 Compile-fail expectation refresh: update
tests/compile-fail/post_contract_void_return.oriexpectation string to match actualE2046wording emitted by pre/post-contract validator. - §12.3.5 Compile-fail expectation refresh: update
tests/compile-fail/pre_contract_not_bool.oriexpectation string to match actualE2044wording. - §12.3.6 Compile-fail expectation refresh: update
tests/compile-fail/pre_contract_scope_violation.oriexpectation string to match actualE2047wording. - §12.3.7 Cross-coverage verification:
timeout 150 cargo t -p ori_llvm --test aot test_borrow_separate_heap_types test_h12 test_h3passes; AOT E2043 cluster clears. - §12.3.8 Spec sweep:
timeout 150 cargo st tests/spec/patterns/binding_patterns.ori tests/spec/patterns/syntax.oripasses; interpreter cluster clears. - §12.3.9 Compile-fail sweep:
timeout 150 cargo st tests/compile-fail/post_contract_void_return.ori tests/compile-fail/pre_contract_not_bool.ori tests/compile-fail/pre_contract_scope_violation.oripasses. - §12.3.10 Regression guard:
timeout 150 cargo stf tests/spec/types/empty_literalsshows identical pre/post counts (validator narrowing did not perturb empty-literal defaulting). - §12.3.11 Dual-execution parity:
timeout 150 diagnostics/dual-exec-verify.sh --json | jq '.per_test[] | select(.parity_status != "match")'returns empty. - §12.3.12 Debug + release parity:
timeout 150 ./test-all.shclean in both profiles per CLAUDE.md §Fix Completeness. - §12.3.R
/tpr-reviewon §12 diff returns clean across codex + gemini + opencode; no actionable findings. - §12.3.N
/impl-hygiene-reviewon §12 diff returns clean after TPR. - §12.3.Close flip
status: in-progress → completein this section’s frontmatter viaflip_from_in_review_clean()perstate-discipline.md §4.
§12.5 Banned Approaches
Per CLAUDE.md §INVERTED-TDD + §The One Rule + §Never Reason Out of TPR Findings:
- Adding
#[skip]markers to destructure/match-arm tests — banned. Tests are the deliverable that caught the validator regression; the validator is the deliverable that needs narrowing. - Weakening test expectations to match the over-broad validator — banned. Test expectations are correct; validator predicate is wrong.
- Gating destructure/match-arm patterns syntactically (e.g.,
if ast_node.kind == Pattern::Tuple { return Ok }) — banned shape per §INVERTED-TDD. The fix is predicate refinement that captures the semantic distinction (unconditional total binding vs conditional projection), NOT a syntactic skip-list. - Reverting commit
e186e2754wholesale — banned. The validator’sPre/Post-Contract+tagged_ptr drop walkdeliverables are correct and load-bearing; only the conditional-partial-move predicate is over-broad. Surgical narrowing, not whole-commit revert. - “Pre-existing” framing — banned per
routing.md §2. The regression is from a recent commit, butrouting.md §NEVER Investigate "Pre-Existing?"says timeline is irrelevant; only question is “is it fixed?”
Intelligence Reconnaissance
Date: 2026-05-16. Graph: HEAD be3a7ba (CPG stale per status; symbols/relationships current).
- [ori:compiler/ori_types/src/check/validators/]
scripts/intel-query.sh file-symbols compiler/ori_types/src/check/validators/ --repo ori→ 30 symbols (ValidatorContext,validate_body_types,site_from_expr_kind,narrow_to_lambda_param_span, …) — §02’s existing validator module surface. - [ori:compiler/ori_types/src/check/validators/partial_move/]
scripts/intel-query.sh file-symbols compiler/ori_types/src/check/validators/partial_move/ --repo ori→ 1 symbol (partial_move_validator_handles_invalid_body_root_without_panickingintests.rs:14); production-code symbols frome186e2754not yet indexed (embedding staleness — partial_move/ landed post lastenrich_embeddings.pyrun). §12.3.0 discovery must read the directory contents directly (Readpermitted at execution-time perplan-read-discipline.md §3.1). - [ori]
scripts/intel-query.sh symbol-plans partial_move_validate --repo ori→ 0 hits (no cross-plan references; this is the first plan section to claim ownership of the partial_move validator narrowing). scripts/intel-query.sh status→ ori repo HEADbe3a7ba, 31,374 symbols indexed;last_synced: 2026-05-16T19:21:28Z(post-e186e2754);cpg_stale: true+embedding_stale: truewarnings noted. CPG queries (callers,callees) on the new partial_move/ symbols will return empty untilintel-query.sh refresh --coderuns against the post-e186e2754 tree.- Symbol references confirmed via direct file read at §12.3.0 will populate
MENTIONS_CODEfor/review-planStep 4 blind-spot synthesis on subsequent re-runs.
§12.6 References
e186e2754— source commit (typeck validator + pre/post contract + tagged_ptr drop walk)f5a37d327— sibling tests commitcompiler/ori_types/src/check/validators/partial_move/— validator implementation (path to be confirmed during §12.3.0 discovery)tests/spec/patterns/binding_patterns.ori— interpreter destructure failurestests/spec/patterns/syntax.ori— interpreter match failurestests/compile-fail/post_contract_void_return.ori—E2046expectation refreshtests/compile-fail/pre_contract_not_bool.ori—E2044expectation refreshtests/compile-fail/pre_contract_scope_violation.ori—E2047expectation refreshsection-02-validator-module.md— sibling validator module (PC-2 enforcement at body-finalize seam; NOT amended by §12)- CLAUDE.md §INVERTED-TDD Is BANNED
- CLAUDE.md §Invariant-Anchoring Before Test-Chasing
- CLAUDE.md §Fix Completeness
.claude/rules/tests.md §Matrix Testing Rule.claude/rules/impl-hygiene.md §Cross-Phase Invariant Contracts
HISTORY
- 2026-05-16 — Section created via
/create-plan --inlineinline-insertion: discovered work routed perrouting.md §3case (b) — conditional-partial-move validator overcorrection in commite186e2754regressed ~60 tests across AOT + interpreter + compile-fail surfaces. Section absorbs the regression into typeck-inference-completeness umbrella (validator landed adjacent to §02 Validator Module’s existing work; shares typeck inference completeness bounded context). Sibling section to §02 (not amendment-of — §02 covers PC-2 enforcement post-body, §12 covers a separate validator at a different seam).