Section 04: Recursive + Closures + Drop AUGMENT + Value Empty-Burden
Empirical grounding: the value-shape composition cases stress BurdenSpec beyond plain owned aggregates — bug cluster BUG-04-090/095/098/104/106/107; closures are the most-stressed shape (proposal §Closures). BUG-04-099 is orthogonal (diagnostics/observability) per 00-overview.md orthogonal_bugs.
Semantic invariant (proposal §Recursive and Self-Referential Types, §Closures, §Drop Trait Interaction, §Value Trait Composition): compiled_drop is invoked from the refcount-zero branch of ori_rc_dec, NOT a direct call at every release site — rc > 1 release decrements without drop-body invocation, preserving shared-reference correctness.
Transport contract — SHIPPED PRIMITIVES BEING WIRED, NOT INVENTED. §04 does NOT design a new drop-function transport ABI. The runtime ABI ori_rc_dec(data_ptr: *mut u8, drop_fn: Option<extern "C" fn(*mut u8)>) is shipped at compiler_repo/compiler/ori_rt/src/rc/mod.rs:240. The per-type drop function generator generate_drop_fn → DropKind::{Fields, ClosureEnv, Enum, Collection, Map} is shipped at compiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/drop_gen.rs:40-133. The closure RC-dec path that loads drop_fn from env_ptr field 0 is shipped at rc_ops.rs:256-287. The UserBurdenSpec.compiled_drop: Option<FnSym> + user_drop: Option<FnSym> fields are shipped at burden.rs:47-48. §04 wires these primitives for the four composition cases — recursive cycles (population at registration time), closure environments (population at closure-type-registration time), Drop trait AUGMENT (user_drop population at impl registration time + AUGMENT-shape drop body), Value empty burden (empty UserBurdenSpec for Value-marker types).
Reference implementations:
- Lean 4
IR/RC.leanper-type drop call shape (§04.1). - Rust drop glue (compiled per-type drop functions) —
RC.lean+Borrow.leananalogous shape. - Roc
compiler/gen_refcount/refcount_proc.rsfor closure capture handling.
Depends on: §03A is the SOLE direct predecessor edge in frontmatter depends_on: [03A] per INV-19 strict-linear-single-branch (§03A is status: complete, reviewed: true — reachable). §01 (UserBurdenSpec.compiled_drop + user_drop fields), §02 (variant_burden composition + structural dedup), §03 (BurdenInc/BurdenDec IR variants + trivial-emission walker + partial-move bitset machinery) are TRANSITIVE predecessors reached THROUGH §03A’s own depends_on chain — consumed by §04’s code but NOT additional direct DAG edges (the goal-prose “Consumes §01/§02/§03/§03A” names the consumed deliverables, not the direct-edge set).
Intelligence Reconnaissance
Queries (executed 2026-05-17 during §04 Step 5 editor pass):
scripts/intel-query.sh --human file-symbols "compiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/drop_gen.rs" --repo ori—generate_drop_fn,emit_drop_fields,emit_drop_enum,emit_drop_collection,emit_drop_map(caching viadrop_fn_cache)scripts/intel-query.sh --human file-symbols "compiler_repo/compiler/ori_rt/src/rc" --repo ori—ori_rc_dec(data_ptr, drop_fn),ori_rc_inc,rc_dec_to_zero,rc_dec_to_zero_st,MAX_REFCOUNT(immortal sentinel)scripts/intel-query.sh --human callers ori_rc_dec --repo ori— closure-aware emission path atrc_ops.rs::emit_rc_dec_closure+ protocol-builtin emission atiterator/state.rsscripts/intel-query.sh --human similar drop_glue --repo rust,lean4,roc --limit 5— Rust’s per-type drop functions, Lean 4’sRC.leanshape, Roc’s closure-capture handling
Authoritative graph state at run-time: STALE (verified all path:line citations against actual files in this pass).
Result summary: existing AIMS + LLVM codegen infrastructure consumed; §04 extends the unified model per [ori].claude/rules/missions.md §AIMS invariant 5 (no parallel paths, no shadow trackers). All four §04 subsections wire primitives from §01-§03 + [repo:compiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/drop_gen.rs] + [repo:compiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/rc_ops.rs] + [repo:compiler_repo/compiler/ori_rt/src/rc/mod.rs] ori_rc_dec ABI.
Subsection independence. §04.1/§04.2/§04.3/§04.4 are four independent algorithmic surfaces (SCC recursive-drop, closure composer, Drop validator + AUGMENT, Value empty-burden), each landing on its own register_*/compose_* site with its own test suite — none consumes §04.1’s SCC-partition output. §04.2 and §04.3 share the mint_compiled_drop_fn_sym FnSym-mint helper (assigns the _ori_drop$<idx_raw> mangling key) as a sibling utility, NOT a produced-output dependency. The four subsections therefore carry NO subsection_depends_on edges and complete in any order. The section-level gate blocked_by: is now []: EVERY former blocker is CLOSED on disk — BUG-04-043 (recursive tagged-pointer box-and-load codegen) resolved, BUG-04-125 (Drop-AUGMENT invoke+landing-pad AOT slice) resolved, BUG-06-005 (prelude Value+Drop registration) obe/superseded, BUG-02-033 (lambda-side infer_lambda closure-UserBurdenSpec wiring) resolved — all under bug-tracker/plans/completed/. The formerly-anchored AOT/spec slices are therefore ACTIONABLE, not deferrable; the misattributed BUG-04-119 (imported generic monomorphization) was always orthogonal per 00-overview.md orthogonal_bugs and is removed from §04’s forward anchors. §04.R and §04.N retain subsection_depends_on edges as genuine close-out gates (review + checklist depend on all subsections’ content).
04.1 Recursive types + SCC-based cycle detection + per-type compiled drop-glue + ori_rc_dec invocation chain
Files:
compiler_repo/compiler/ori_types/src/registry/burden_compose/scc/mod.rs— cycle detection + compiled_drop fn_sym reservationcompiler_repo/compiler/ori_arc/src/drop/mod.rs—DropInfoconstruction for recursive typescompiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/drop_gen.rs— existinggenerate_drop_fnconsumed; new code path for recursive-type DropKind::Fields with self-referencing child decscompiler_repo/compiler/ori_rt/src/rc/mod.rs:240—ori_rc_dec(data_ptr, drop_fn)runtime ABI consumed unchanged
Design — Cycle detection algorithm
- Implement SCC analysis at BurdenRegistry registration time over ALL type references reachable from
UserBurdenSpec(percompiler_repo/compiler/ori_types/src/registry/burden.rs:40-49shape — verified: fields areowned_fields: Vec<UserOwnedField>,borrowed_fields: Vec<UserBorrowedField>,variant_burdens: Vec<UserVariantBurden>,element_burden: Option<Idx>): (a)owned_fields[i].field_type(struct field type Idx), (b)borrowed_fields[i].field_type(only when borrow extends parent’s lifetime — same SCC contribution), (c)element_burdenwhenSome(idx)(List/Map/Set element type Idx), (d)variant_burdens[i].retained_owned[j].field_type(enum variant retained owned fields — each variant’s UserVariantBurden carriesretained_owned: Vec<UserOwnedField>per burden.rs:37). Algorithm: Tarjan’s SCC (iterative; matches Rust’spetgraph::algo::tarjan_sccshape — single DFS, O(V+E)). Input:ori_types::registry::burden_compose::compose_user_burden_speccollects every type’s reachable type-id edges across (a)-(d). Output:Vec<Vec<Idx>>SCC partition. Examples: self-loops (type Node { next: Option<Node> }) form singleton SCCs via owned_field through Option’s element_burden; mutually-recursive types (type Tree { f: Forest }+type Forest { t: [Tree] }) form multi-member SCC via owned_field + list element_burden; recursive enums (type Tree = Leaf | Branch(Tree, Tree)) form singleton SCC viavariant_burdens[Branch].retained_owned[].field_type. Shipped atcompiler_repo/compiler/ori_types/src/registry/burden_compose/scc/mod.rs::compute_scc_partition. - For every SCC with
|members| >= 2OR self-loop: mint ONEFnSymPER MEMBER via the FnSym mint API (existing infrastructure used by §02.4 compiled_drop machinery); each member’sUserBurdenSpec.compiled_drop = Some(<member-specific-fn_sym>). The mangling_ori_drop$<idx_raw>(perdrop_gen.rs:45) keys on type Idx, so two SCC members yield two distinct FnSyms even though they share an SCC. Reservation order: mint ALL member FnSyms FIRST (drop_fn_cache.insert(ty_i, func_id_i)for each SCC member), THEN generate bodies (cross-references resolve via cache hits regardless of intra-SCC order — a mutually-recursive SCC is cyclic and has no topological ordering among its members; the pre-allocation makes body generation cycle-safe in any order). Shipped atscc/mod.rs::mint_compiled_drop_fn_sym+scc/mod.rs::assign_compiled_drop_fn_syms. - For singleton SCCs without self-loops (non-recursive types) WITHOUT Drop impl:
compiled_drop = None— default drop-glue path via existingcompute_drop_infomachinery handles non-recursive emission. EXCEPTION — non-recursive types WITHDropimpl (user_drop = Some(_)per §04.3) MUST also mintcompiled_drop = Some(<fn_sym>): the user @drop body needs an entry point invoked byori_rc_decat refcount zero, and the AUGMENT-shape compiled drop function wrapsuser_dropthen walks fields in reverse order. Decision rule:compiled_drop = Some(_) iff (in non-singleton SCC) OR (self-loop) OR (user_drop = Some(_)). Shipped atscc/mod.rs::needs_compiled_drop. - Test Strategy: tests at
compiler_repo/compiler/ori_types/src/registry/burden_compose/scc/tests.rs. Matrix axes (pertests.md §Matrix Testing Rule— 4 axes × 2 polarities = 8 minimum pin count):- (a) Self-loop singleton — positive:
recursive_singleton_node_assigns_compiled_drop_fn_sym—type Node { next: Option<Node> }→UserBurdenSpec.compiled_drop == Some(fn_sym). - (a) Self-loop singleton — negative:
non_self_loop_singleton_leaves_compiled_drop_none—type Leaf { value: int }(no self-reference) →compiled_drop == None. - (b) Mutually-recursive pair — positive:
mutually_recursive_pair_each_carries_distinct_compiled_drop_fn_sym—type Tree { children: [Forest] }+type Forest { trees: [Tree] }→ each member carries its OWN distinct FnSym incompiled_drop(per_ori_drop$<idx_raw>mangling); pin assertstree.compiled_drop != forest.compiled_drop. - (b) Mutually-recursive pair — negative:
non_recursive_pair_of_types_leaves_compiled_drop_none—type A { b: B }+type B { x: int }(B has no back-edge to A) → bothcompiled_drop == None. - (c) Mutually-recursive triple — positive:
mutually_recursive_triple_each_carries_distinct_compiled_drop_fn_sym—type A { b: B }+type B { c: C }+type C { a: Option<A> }(cycle A→B→C→A) → all three members carry distinct FnSyms; pin assertsa.compiled_drop != b.compiled_drop != c.compiled_drop(three distinct values). - (c) Mutually-recursive triple — negative:
non_recursive_triple_leaves_compiled_drop_none—type A { b: B }+type B { c: C }+type C { x: int }(linear chain, no cycle) → all threecompiled_drop == None. - (d) Non-recursive baseline — positive:
non_recursive_pair_leaves_compiled_drop_none—type Pair { a: int, b: str }→compiled_drop == None(negative-form pin asserting absence of compiled_drop is itself the “positive” assertion for the negative axis). - (d) Non-recursive baseline — negative:
non_recursive_with_recursive_field_assigns_compiled_drop_fn_sym—type Wrapper { inner: Node }where Node is recursive — Wrapper itself is non-recursive but its OWNED field is; pin asserts Wrapper does NOT inherit compiled_drop from Node (Wrapper drops Node via field walk, not via shared compiled_drop FnSym). Negative pin for axis (d) — confirms the cycle-detection is per-type, not transitive through field types.
- (a) Self-loop singleton — positive:
Codegen — drop body emission for recursive types
- At LLVM codegen, when
UserBurdenSpec.compiled_drop = Some(fn_sym)is encountered, the existinggenerate_drop_fn(emitter, ty, drop_info)atdrop_gen.rs:40materializes the function. No new emission path required — the existingDropKind::Fields(fields)arm walks RC’d fields, recursing throughemit_rc_decper field; the cache-before-body pattern atdrop_gen.rs:69(drop_fn_cache.insert(ty, func_id)BEFORE generating body) is cycle-safe — recursive types callingemit_rc_decon a field of the same type get the cachedFunctionIdback, producing a tail-recursive drop pattern. Verified byrecursive_node_drop_fn_emits_self_referencing_rc_decatarc_emitter/tests.rs. - Mutually-recursive types: each SCC member gets its OWN
compiled_dropFnSym (per-type drop function), matching the shipped_ori_drop$<idx_raw>mangling atdrop_gen.rs:45and the type-Idx-keyed cachedrop_fn_cache.insert(ty, func_id)atdrop_gen.rs:69. Cycle safety comes from the cache-before-body pattern (line 116 above), NOT from multiplexing multiple types into a single function. When_ori_drop$Treewalks a field of typeForest,emit_rc_declooks up_ori_drop$Forestin the cache — yielding either the already-materialized FunctionId (cycle resolved) or a freshly-reserved one (recursion will resolve on next call). Reservation order during SCC processing: reserve all member FnSyms viadrop_fn_cache.insert(ty, func_id)BEFORE generating any body, then generate bodies in any order (a cyclic SCC has no topological ordering among its members; cross-refs resolve via cache hits regardless of order); this preserves the existingextern "C" fn(*mut u8)ABI without runtime type discriminants. Verified bymutually_recursive_tree_forest_drop_fns_cross_referenceatarc_emitter/tests.rs. - Test Strategy: tests at
compiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/tests.rs. Pin shapes:recursive_node_drop_fn_emits_self_referencing_rc_dec(positive —Node { next: Option<Node> }drop body containsori_rc_deccall on fieldnext);mutually_recursive_tree_forest_drop_fns_cross_reference(positive —_ori_drop$<Tree>calls_ori_drop$<Forest>via field decrement);drop_fn_cache_prevents_infinite_generation(positive — generatingNodedrop fn twice keeps the cache entry stable and emits exactly one LLVM definition).
Phase 5 emission integrity
- Phase 5 emission for recursive types is IDENTICAL to non-recursive:
BurdenDec(v)at release sites peraims-rules.md §8 RL-2. The recursion lives incompiled_dropbody invoked by runtimeori_rc_decwhen refcount = 0, NOT in emission. This preserves shared-reference correctness (rc > 1 release decrements via the existingrc_dec_to_zeroearly-return atmod.rs:281without invokingdrop_fn). Verified by no changes to §03’s trivial-emission walker (unchanged code path) + all 1006ori_typestests + 1385ori_arctests + 652ori_llvmlib tests pass. - Test Strategy (UNBLOCKED — BUG-04-043 now CLOSED): AOT-level test at
compiler_repo/compiler/ori_llvm/tests/aot/recursive_drop.rsSHIPPED at the file location. VERIFIED 2026-05-31: the three pins (recursive_drop_node_chain_builds_runs_no_leak,recursive_drop_aliased_no_double_free,recursive_drop_chain_rc_balanced) PASS green (ORI_VERIFY_ARC=1, release, 3/3) once BUG-04-043’s box-and-load landed. BUG-04-043 (recursiveConstruct/Projectbox-and-load codegen, surfaced asbuild_struct: insert_value failed (index out of bounds?) index=0 num_fields=0) is CLOSED-as-resolved (bug-tracker/plans/completed/BUG-04-043/); the recursive-drop AOT slice is unblocked. The three shipped TDD pins (recursive_drop_node_chain_builds_runs_no_leak,recursive_drop_aliased_no_double_free,recursive_drop_chain_rc_balanced) carry NO#[ignore]and now run as active AOT tests — they were authored as RED-before-fix pins that pass once BUG-04-043’s box-and-load codegen lands. Ori source:
Verification:type Node { value: int, next: Option<Node> } @t tests _ () -> void = { let n3 = Node { value: 3, next: None }; let n2 = Node { value: 2, next: Some(n3) }; let n1 = Node { value: 1, next: Some(n2) }; // n1 dropped at scope exit; recursive drop traverses n1 → n2 → n3 }ORI_CHECK_LEAKS=1 ./target/debug/aot_test_recursive_dropreports zero leaks;ORI_TRACE_RC=1shows three matching alloc/dec pairs (one per Node). Eval/LLVM parity:cargo run -- run recursive_drop.oriproduces same observable behavior.- (deferred-with-anchor: BUG-02-032) Shared-reference pin (AUTHORED — RED) — named test
recursive_drop_skips_body_when_rc_above_oneSHIPPED atcompiler_repo/compiler/ori_llvm/tests/aot/recursive_drop.rswith the full spec-faithful body + both verification axes as real assertions, gated#[ignore = "BUG-02-032: ..."]. NON-CHECKBOX deferred-with-anchor item — does NOT gate §04.1 close (test-disposition discipline + state-discipline.md §1): §04.1’s recursive-drop-glue deliverable is verified by its 3 active green pins (node-chain / aliased / chain-rc-balanced); this rc-above-one precision pin auto-greens with NO edit when BUG-02-032 lands. The recursive-codegen blocker BUG-04-043 is CLOSED, but the pin’s Ori source requires thedrop_earlyprelude builtin, which is documented inspec/08-types.md §8.10.5+ori-syntax.md §Preludebut NOT implemented in the compiler (typeck signature + eval semantics + AOT earlyrc_deccodegen all absent) — tracked as BUG-02-032 (error[E2003]: unknown identifier drop_early, confirmed RED 2026-06-02). The test is authored RED-before-fix and goes green with NO edit once BUG-02-032 lands; the new reusablecompile_and_run_with_envhelper (tests/aot/util/compile.rs) supports theORI_TRACE_RC=1axes. Checkbox stays unchecked until BUG-02-032 closes and the pin runs green. Ori source:
Verification axes (both pins required):use std.testing { assert_eq }; type Node { value: int, next: Option<Node> } @t tests _ () -> void = { let n3 = Node { value: 3, next: None }; let n2 = Node { value: 2, next: Some(n3) }; let n1 = Node { value: 1, next: Some(n2) }; let n1_alias = n1; // RC bump: n1's heap node now has rc = 2 drop_early(value: n1); // explicit lifetime shortening per spec/08-types.md:1145-1148 // POST-drop_early state: refcount-zero branch of ori_rc_dec MUST NOT fire on n1's heap node // because n1_alias still holds rc = 1; recursive compiled drop body is NOT invoked. // n1_alias keeps the chain alive; scope-exit drop of n1_alias reaches rc = 0 and the // recursive compiled drop body THEN traverses n1_alias -> n2 -> n3. assert_eq(actual: n1_alias.value, expected: 1); }- Positive — recursive body invocation at final rc = 0:
ORI_TRACE_RC=1showsn1_aliasscope-exitori_rc_dechitting rc-zero branch and emitting three child decs (n1 → n2 → n3);ORI_CHECK_LEAKS=1reports zero leaks. - Negative — recursive body skipped at rc > 1:
ORI_TRACE_RC=1shows thedrop_early(value: n1)call decrementing the heap node’s rc from 2 → 1 WITHOUT entering the_ori_drop$Nodebody (count of_ori_drop$Nodeinvocations BEFOREn1_aliasscope exit = 0). The negative pin asserts the shared-reference correctness invariant: rc > 1 release decrements WITHOUT compiled drop body invocation per success_criterion 2.
- Positive — recursive body invocation at final rc = 0:
- Spec citation: explicit-drop surface is
drop_early(value: T) -> voidpercompiler_repo/docs/ori_lang/v2026/spec/08-types.md:1145-1148;drop_explicitdoes NOT exist in the spec. Cited inrecursive_drop.rstest source verbatim.
- (deferred-with-anchor: BUG-02-032) Shared-reference pin (AUTHORED — RED) — named test
04.1 HISTORY
- 2026-05-17 — §04.1 algorithmic landing + AOT slice blocker discovery. SCC-based cycle detection (Tarjan iterative) shipped at
compiler_repo/compiler/ori_types/src/registry/burden_compose/scc/mod.rswith 15-cell matrix atscc/tests.rscovering self-loop singletons, mutually-recursive pairs/triples, non-recursive baselines, and decision-rule clauses. Codegen-IR-level cycle-safety pins shipped atcompiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/tests.rs(recursive_node_drop_fn_emits_self_referencing_rc_dec,mutually_recursive_tree_forest_drop_fns_cross_reference,drop_fn_cache_prevents_infinite_generation) consuming the existing_ori_drop$<idx_raw>mangling atdrop_gen.rs:45+ cache-before-body pattern atdrop_gen.rs:69— no new emission path introduced. AOT-level tests (compiler_repo/compiler/ori_llvm/tests/aot/recursive_drop.rs) authored with#[ignore = "BUG-04-043: recursive struct types not yet supported by LLVM codegen"]per.claude/rules/test-disposition.md— BUG-04-043 is the load-bearing pre-existing blocker for the AOT slice (recursivetype Node = { value: int, next: Option<Node> }triggersbuild_struct: insert_value failed (index out of bounds?) index=0 num_fields=0at LLVM codegen). The §04.1 algorithmic deliverables stand on the unit + codegen-IR-level coverage; the AOT slice re-enables in the same commit that closes BUG-04-043.
04.2 Closure capture composition + compiled_drop population at closure-type-registration + env-header drop_fn transport
Files:
compiler_repo/compiler/ori_types/src/registry/burden_compose/closure/mod.rs— closure type detection + compiled_drop populationcompiler_repo/compiler/ori_arc/src/lower/burden_lower/— PartialApply transfer-point emission (already shipped in §03.3);is_owned_positionSSOT now lives inir/instr.rs+terminator.rs, consumed byburden_lower/compiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/rc_ops.rs:256-287— existingemit_rc_dec_closureconsumed unchangedcompiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/drop_gen.rs:91— existingDropKind::ClosureEnv(fields)arm consumed unchanged
Design — UserBurdenSpec for Closure
- At closure-type-registration time, populate
UserBurdenSpecper the spec below. Phase ordering (percanon.md §1pipeline): closure types are first encountered during TYPE CHECKING (phase 3,ori_types) when the type checker walks lambda/closure expressions in the AST and synthesizes the resultingClosure<R, captures>type; type-checking RUNS BEFORE ARC lowering (phase 5,ori_arc), soori_types::registry::burden_compose::compose_user_burden_specpopulates the closure’s BurdenSpec at the lambda-expression type-check site, NOT whenori_arc/src/lower/calls/mod.rslater lowers the lambda into aPartialApplyIR node. Specifically: whenori_types::infer::expr::infer_lambda(or equivalent — verify symbol name at implementation time viascripts/intel-query.sh file-symbols compiler_repo/compiler/ori_types/src/infer --repo ori) constructs the closure type with its captured-binding signature, the same site registers the closure’sUserBurdenSpecviacompose_user_burden_specwith these fields:self_heap_alloc: true(closure environment is heap-allocated);owned_fields: [<one OwnedField per captured-by-value capture>]— field index = capture position, field_type = captured binding’s resolved Idx;borrowed_fields: [<one BorrowedField per captured-by-reference capture>];element_burden: None;variant_burdens: [];compiled_drop: Some(env_drop_fn_sym)— minted at registration time, materialized later by codegen via existingDropKind::ClosureEnvarm;user_drop: None(closures cannot have user @drop — only types do). - Capture-by-value of Owned binding: capture site IS the transfer point per §03.3 Rule 5 (already shipped).
BurdenIncon env field at PartialApply; closure last-use emitsBurdenDec(closure_var)which routes through existingemit_rc_dec_closureatrc_ops.rs:256, loadingdrop_fnfrom env_ptr field 0 and callingori_rc_dec(env_ptr, drop_fn). - Capture-by-reference: borrow stored in
borrowed_fields[i]; no drop on env field (borrows do not own); lifetime tied via existing borrow-inference machinery atori_arc/src/borrow/mod.rs— borrow’s lifetime cannot outlive closure’s lifetime. - Captures-of-captures (nested closures): outer env field IS
Closure<...>with its OWNUserBurdenSpec.compiled_drop. Recursion handled identically to recursive types per §04.1 — outer closure’s drop body recursively invokes inner closure’scompiled_dropvia the inner field’s UserBurdenSpec lookup at codegen. - Capture of projection: treated as
borrowed_fieldsentry with parent variable’s lifetime tied — the projection itself does not own; parent owns. - PartialApply transfer-point invariant: per §03.3 Rule 5 (already shipped), one transfer point per captured arg; binding consumed by PartialApply AND Owned callee in same expr → transfer-count 2 → one BurdenInc emitted (zero-net). Verified via existing test
partial_apply_owned_capture_emits_single_burden_inc_per_03_3_rule_5_zero_netatburden_lower/tests.rs. - Borrow-check-refinement sync — owned_fields vs borrowed_fields MUST match the post-borrow-check capture classification. The closure UserBurdenSpec is composed at type-check time (phase 3), but borrow inference (
ori_arc/src/borrow/mod.rs, phase 5) may refine a by-value capture into a by-reference borrow, drifting the composedowned_fields/borrowed_fieldspartition from the final physical env layout. The composer MUST either (a) run/re-run after borrow-check refinement settles the capture-by-value-vs-by-reference classification, OR (b) carry a re-evaluation step that re-partitionsowned_fields/borrowed_fieldsagainst the post-borrow-check classification before codegen consumes the spec. A by-value→by-reference refinement that leaves the field inowned_fieldswould emit a spuriousBurdenDecon a borrow at env drop. VERIFIED NO-DRIFT 2026-05-31 (commit a516d99cc): investigation established the live drop path admits NO drift, on two independent grounds: (1)compose_closure_burden_specis a PURE mapping of itsowned_captures/borrowed_capturesinputs — it does NOT classify; the partition is exactly the caller-supplied classification, so feeding it the post-borrow-check classification yields a post-borrow-check-correct partition with zero residue in the opposite set (pinned byclosure_owned_borrowed_partition_is_a_pure_function_of_classification_inputinclosure/tests.rs). (2) The shipped closure env-drop does NOT consume the owned/borrowed partition for its dec decision: the env physically OWNS a copy of every capture (stored bybuild_closure_env), socompute_closure_env_dropdecs everyclassifier.needs_rc()capture over the post-borrow-check ARC-IR var types regardless of by-value/by-reference body classification. The owned/borrowed distinction governs only the BODY’s borrow treatment (wrapperRcInc-skip viacapture_ownership, which is already post-borrow-check). Pinned behaviorally bytest_closure_borrowed_capture_env_owns_copy_no_drift(a borrowed heap-str capture is leak-clean: env owns the copy, decs once, wrapper does not inc) + existingtest_nested_closure_borrowed_str_param/_list_param. The composer’s classification INPUTS arrive post-borrow-check by construction wheneverinfer_lambdawires it — that wiring is the remaining lambda-side work below. (no fix fabricated for a non-gap per task directive; the lambda-sideinfer_lambdawiring atcompiler_repo/compiler/ori_types/src/infer/expr/blocks.rs:223is the remaining §04.2 work — formerly BUG-02-033, now CLOSED-as-resolved perbug-tracker/plans/completed/BUG-02-033/; verify-green per §04.N, do NOT treat as an open blocker.)
Env-header layout — drop_fn at offset 0
- Lay-out invariant for closure environments (resolved from
rc_ops.rs:281evidence —let drop_fn = self.builder.load(ptr_ty, env_ptr, "rc_dec.drop_fn");reads*env_ptrdirectly, so drop_fn lives AT env_ptr, NOT at a negative offset):
The[env_ptr - 8] : refcount (i64, RT-2 header convention — sits BEFORE data_ptr per arc.md §RT-2) [env_ptr + 0] : drop_fn (ptr, 8 bytes — the slot loaded by emit_rc_dec_closure) [env_ptr + 8] : captured_field_0 [env_ptr + 16]: captured_field_1 ...env_ptrexposed to Ori code points AT the drop_fn slot (offset 0 of the data payload). The RC header sits atenv_ptr - 8per the standardarc.md §RT-2convention. Captured fields start atenv_ptr + 8and extend forward. - No new ABI required: this layout is what
emit_rc_dec_closurealready implements atrc_ops.rs:256-287— theload(ptr_ty, env_ptr)at line 281 reads drop_fn directly from the data pointer; the surroundingori_rc_dec(env_ptr, drop_fn)call passes both the same env_ptr (for refcount decrement atenv_ptr - 8) and the loaded drop_fn (for invocation when refcount reaches zero). - Capture-field access: closure body accesses captured field i via
gep env_ptr, 8 + i*sizeof(field_i)— standard struct-field access pattern offset by the 8-byte drop_fn header slot. Field-i indices inUserBurdenSpec.owned_fields[i]MUST map to physical offsets accounting for the drop_fn slot.
Codegen — compiled_drop materialization via DropKind::ClosureEnv
- At codegen, when
UserBurdenSpec.compiled_drop = Some(env_drop_fn_sym)is encountered for a closure type,generate_drop_fnatdrop_gen.rs:40is called withDropKind::ClosureEnv(fields)wherefieldsis derived from the closure’sowned_fields. The existingDropKind::ClosureEnv(fields) | DropKind::Fields(fields)shared arm atdrop_gen.rs:91emits the body —emit_drop_fields(data_ptr, ty, fields)walks each owned field, callingemit_rc_decper field, thenemit_drop_rc_free(data_ptr, ty)to release the env allocation. - No new codegen path. The DropKind::ClosureEnv variant is shipped; §04.2’s job is to populate
UserBurdenSpec.compiled_dropfor closure types so the existing path activates. - Single-SSOT closure-env drop dispatch — retire
generate_env_drop_fn. Closure env-drop generation currently has TWO paths: the customgenerate_env_drop_fnhelper atcompiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/closures.rs:189AND the sharedDropKind::ClosureEnvarm atcompiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/drop_gen.rs:94. Duplicate dispatch risks divergent buffer offsets for collection-typed captures. Per AIMS Invariant 5 (no parallel emission paths perarc.md §Non-Negotiable Invariants), retiregenerate_env_drop_fnand route ALL closure-env drop generation throughDropKind::ClosureEnv(drop_gen.rs:94) as the single SSOT dispatch. Re-point theclosures.rs:189call site at the shared arm; delete the divergent helper. DONE 2026-05-31 (commit a516d99cc):generate_env_drop_fnnow derivesDropKind::ClosureEnv(fields)viaori_arc::compute_closure_env_drop(the SSOT for which captures need RC + their logical indices) and decrements every field through the shareddec_value_rctag-aware SSOT (single inline-value RC-dec dispatch: buffer-dec for List/Set/Map, inline-enum-dec for Option/Result/Enum, dynamic env-header-dec for closure captures) — the divergent per-tag dispatch + its parallelemit_buffer_rc_dec_*collection path is deleted. Closure-env-local concerns stay local (per-instance env struct type — closure envs have no poolIdx, sogenerate_drop_fn(ty: Idx)cannot key them;+1field offset for thedrop_fnheader slot;ori_rc_freepayload size). New pinstest_closure_capture_map_drops_via_single_ssot+test_closure_capture_mixed_collections_drop_via_single_ssot(fail-on-revert verified — removing the dec leaks); 20 existing closure-drop AOT tests + 12-cell composer matrix green;--all-targets -D warningsclean; ori_llvm AOT failure set byte-identical pre/post (zero regressions).
Test Strategy
- Tests at
compiler_repo/compiler/ori_arc/src/lower/burden_lower/tests.rs(existing pattern from §03.3): pin shapes covering each capture variant matrix axis:closure_capture_by_value_of_owned_str_emits_burden_inc_at_partial_apply(positive —let s = "hello"; let c = (() -> s.length())— capture site = PartialApply = transfer point, BurdenInc on env field)closure_capture_by_reference_emits_no_burden_inc(negative — capture-by-reference is borrow, no transfer, no BurdenInc)nested_closure_emits_recursive_burden_inc_through_outer_env(positive — outer closure captures inner closure; outer drop walks inner drop transitively)closure_capture_of_projection_emits_borrowed_field_with_parent_lifetime(positive —let p = Pair { a: 1, b: 2 }; let c = (() -> p.a)captures projection)
- Specific PartialApply matrix pin:
partial_apply_owned_capture_passed_to_owned_callee_emits_zero_net_burden_per_03_3_rule_5(positive — the §03.3 Rule 5 invariant under §04 closure UserBurdenSpec population). - AOT-level test at
compiler_repo/compiler/ori_llvm/tests/aot/closure_drop.rs: the file EXISTS on disk, registered aspub mod closure_drop;incompiler_repo/compiler/ori_llvm/tests/aot/main.rs, carrying TWO ACTIVE#[test]s —test_closure_capture_by_value_str_drops_at_scope_exit(closure_drop.rs:63) +test_closure_env_header_drop_fn_invokes_at_refcount_zero(closure_drop.rs:83) — with ZERO#[ignore](verified on disk this pass). There is NO BUG-04-043#[ignore]reason to remove: the scaffolds are already active. Remaining work is verifying the two active tests PASS green (ORI_CHECK_LEAKS=1zero leaks +ORI_TRACE_RC=1balanced env alloc/dec pairs + eval/LLVM parity) against the landedinfer_lambdaclosure-UserBurdenSpecauto-registration wiring (compose_closure_burden_spec+register_user_burdenatcompiler_repo/compiler/ori_types/src/infer/expr/blocks.rs:223); the recursive-codegen blocker BUG-04-043 + lambda-side wiring blocker BUG-02-033 are both CLOSED-as-resolved (bug-tracker/plans/completed/). If either active test FAILS at AOT execution, that is a fresh AOT defect —/add-bugsubsystemcodegenfor the failure mode, then fix to green; do NOT re-#[ignore]it. Implementer note: theclosure_drop.rs:30module docstring still narrates BUG-04-118 + BUG-04-043 as gating “scaffold re-enable” blockers (both CLOSED — BUG-04-118 obe per00-overview.md absorbed_bugs[], BUG-04-043 resolved); strip that stale-blocker framing from the docstring when authoring the verification pass (it is a source-comment fix, not plan content). BUG-04-118, the prior empirical motivation, is CLOSED-as-obe per00-overview.md absorbed_bugs[].
Subsection close-out (04.2) per protocol.
04.2 HISTORY
- 2026-05-17 — §04.2 closure-capture-composition landing. Closure burden-spec composer shipped at
compiler_repo/compiler/ori_types/src/registry/burden_compose/closure/mod.rs(compose_closure_burden_spec(closure_idx, owned_captures, borrowed_captures) -> UserBurdenSpec+mint_closure_drop_fn_sym(closure_idx)delegating toscc::mint_compiled_drop_fn_symso closure drop functions share the_ori_drop$<idx_raw>mangling key with §04.1’s recursive-type drop functions perdrop_gen.rs:45). Composer populatesself_heap_alloc: true,owned_fields(capture-by-value),borrowed_fields(capture-by-reference),compiled_drop: Some(<minted FnSym>),user_drop: None. 11-cell matrix atclosure/tests.rscovers capture-by-value singleton + multi-arg, capture-by-reference, mixed owned/borrowed, captures-of-captures (nested closures), capture-of-projection, per-IdxFnSymdistinctness, zero-captures default-shape, and default-invariant clamps pertests.md §Matrix Clamping. 5 burden_lower walker pins shipped atcompiler_repo/compiler/ori_arc/src/lower/burden_lower/tests.rs(closure_capture_by_value_of_owned_str_emits_burden_inc_at_partial_apply,closure_capture_by_reference_emits_no_burden_inc,nested_closure_emits_recursive_burden_inc_through_outer_env,closure_capture_of_projection_emits_borrowed_field_with_parent_lifetime,partial_apply_owned_capture_passed_to_owned_callee_emits_zero_net_burden_per_03_3_rule_5) verify the existing trivial-emission walker correctly consumes the composed-and-registered closure burden — exercised againstIdx::STRandclosure_idxtypes registered viacrate::lower::test_utils::registered_struct_with_burden. AOT scaffolds atcompiler_repo/compiler/ori_llvm/tests/aot/closure_drop.rscarry#[ignore = "BUG-04-118: §04.2 lambda-side wiring follow-up — auto-register closure UserBurdenSpec at infer_lambda site"]per.claude/rules/test-disposition.md; the lambda-side wiring atcompiler_repo/compiler/ori_types/src/infer/expr/blocks.rs:223(infer_lambda) is plan-tracked follow-up (callscompose_closure_burden_spec+register_user_burdenat lambda-type-check time). Env-header layout ([env_ptr - 8] refcount, [env_ptr + 0] drop_fn, [env_ptr + 8..] captured-fields) is shipped atrc_ops.rs:256-287(emit_rc_dec_closureloads drop_fn from*env_ptr); §04.2 does NOT introduce new ABI. Codegen consumption path is the existingDropKind::ClosureEnv(fields) | DropKind::Fields(fields)shared arm atcompiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/drop_gen.rs:91; §04.2 populates the closure-side burden so the existing path activates. All 1017 ori_types lib tests + 1390 ori_arc lib tests + 652 ori_llvm lib tests +cargo clippy -p ori_types -p ori_arc -p ori_llvm --all-targets -- -D warningsclean.
04.3 Drop AUGMENT body shape (DropKind::Fields + DropKind::Enum) + abort-on-drop-panic + EDROP_PARTIAL_MOVE (E2048) typeck rejection
Files:
compiler_repo/compiler/ori_types/src/check/registration/impls.rs— Drop impl detection +user_dropFnSym population at the explicitimpl T: Dropregistration site (NOTregister_derived_impl— Drop is explicit-impl-only perdrop-trait-proposal.md §Auto-derive)compiler_repo/compiler/ori_types/src/check/validators/partial_move.rs— NEWvalidate_drop_partial_movevalidator (sibling to existingvalidate_partial_moveper E2043)compiler_repo/compiler/ori_diagnostic/src/error_code/mod.rs:159— E2048 = “EDROP_PARTIAL_MOVE: partial move on type implementing Drop” (verified on disk: E2047 at line 158; E2048 at line 159; subsequent E2049 at line 160)compiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/drop_gen.rs:91+:131— BOTHDropKind::Fields(fields)ANDDropKind::Enum(...)arms extended foruser_dropFIRST + reverse-order field/variant walk; enum-shaped Drop types route throughemit_drop_enumand MUST receive the same AUGMENT wiring (per gemini blind-spot: limiting AUGMENT toDropKind::Fieldssilently bypasses enum@dropbodies during refcount-zero drop)compiler_repo/compiler/ori_rt/src/rc/mod.rs— abort-on-drop-panic runtime entry point invoked by codegen-emitted landing pad surroundingApply(user_drop)(no unwind through drop bodies — preserves field-walk completion-or-abort semantics)
Design — Drop trait signature + AUGMENT semantics
Per drop-trait-proposal.md §Definition (approved 2026-01-30):
trait Drop {
@drop (self) -> void
}
selfis by-value per Ori’s method convention (ori-syntax.md §Declarations: “self(mutable in methods — mutations propagate to caller)”). The proposal explicitly bans@drop (self) -> bool(line 150 of drop-trait-proposal.md) — return type MUST be void.selfcannot move out of fields (perdrop-trait-proposal.md §Execution Timing).- Per
drop-trait-proposal.md §85: “Fields are dropped in reverse declaration order, then the struct” — establishes the LIFO field-drop convention.
Drop AUGMENT body shape (struct + enum + panic-safety)
- At codegen, when
UserBurdenSpec.user_drop = Some(method_fn_sym)ANDcompiled_drop = Some(_)(every Drop type has compiled_drop because drop method gets a body): the generated drop function body shape is:Apply(user_drop, [data_ptr])FIRST — calls user@drop (self) -> void; user sees fields VALID (compiler has not yet walked them).- THEN walk
owned_fieldsin REVERSE declaration order — for each field i (descending),emit_rc_dec(field_i). For enum types: walk the discriminant-selected variant’s owned fields in REVERSE declaration order via the existingemit_drop_enumswitch-on-tag pattern. - IF
self_heap_alloc,emit_drop_rc_free(data_ptr, ty)— release the struct/enum allocation.
- Struct extension (
DropKind::Fields): Extension to existingemit_drop_fieldsatdrop_gen.rs:140-184: adduser_drop: Option<FnSym>parameter; if Some, emitApply(user_drop, [data_ptr])BEFORE the field-walk loop. Existing callers (DropKind::ClosureEnv, recursive-types DropKind::Fields without user_drop) passNone. - Enum extension (
DropKind::Enum) — REQUIRED to avoid the Drop-on-enum silent bypass: extendDropKind::Enum { variants, user_drop }to carry anOption<FnSym>for the enum-level @drop body; extendemit_drop_enumatdrop_gen.rsto emitApply(user_drop, [data_ptr])BEFORE the switch-on-tag-and-walk-variant-fields lowering. Without this, types declared astype T = A(int) | B(str)withimpl T: Dropwould silently drop fields without invoking the user@dropbody — Drop trait silently bypassed at runtime. §04.3 wires AUGMENT into BOTHDropKind::FieldsandDropKind::Enum; thecompiled_dropminting at registration time (§04.3 Drop impl registration) keys on Type identity, not on field-vs-variant shape, so a singleuser_drop: Some(_)value flows through to whichever DropKind variant the emission path selects. - Self-recursion inhibition — no default ARC inc/dec on the by-value
selfparam inside@dropbodies (self-drop infinite-recursion guard). TheApply(user_drop, [data_ptr])glue passes the value by-value asselfper the trait signature@drop (self) -> void. The compiled drop function MUST NOT emit a default scope-exitBurdenDec/RcDecon thatselfbinding inside the@dropbody — the drop glue is ALREADY the refcount-zero cleanup path for that allocation; a default dec onselfwould re-enterori_rc_dec(data_ptr, drop_fn)and recurse the cleanup infinitely (and double-free). The AUGMENT glue suppresses default ARC inc/dec on theselfparam: the@dropbody treatsselfas a borrowed view for the duration of the user body (fields valid, no ownership-transfer dec onselfitself), with the compiler-side field-walk (step 2) +emit_drop_rc_free(step 3) owning the actual release. The self-recursion-inhibition guard splits into two independently-shippable verification surfaces:- ARC-IR-level absence assertion (SHIPPABLE NOW — NOT AOT-blocked). A codegen-IR-level test asserting the emitted AUGMENT drop body for a
Droptype contains ZEROBurdenDec/RcDecon theselfArcVarId (the by-valueselfbinding fed toApply(user_drop, [data_ptr])). This inspects the emitted ARC IR directly (same harness shape as the §04.1recursive_node_drop_fn_emits_self_referencing_rc_dec/ §04.2closure_capture_*codegen-IR pins) and does NOT require AOT execution, the preludeDropwiring, or the BUG-04-125 invoke+landing-pad slice — it is a fail-on-revert structural pin that lands atcompiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/tests.rsasdrop_augment_self_param_emits_no_default_dec_in_arc_ir. Shipped: the test asserts the generated_ori_drop$<T>for a no-RC-field Drop-shaped struct releasesdata_ptrONLY viacall void @ori_rc_freeand emits NOcall void @ori_rc_dec(a self dec ondata_ptrwould re-enter the drop fn); the pairedrecursive_node_drop_fn_emits_self_referencing_rc_decmakes the negative assertion non-vacuous (it DOES emitori_rc_decon a self-typed FIELD). - observable AOT positive pin (NOW ACTIONABLE — BUG-04-125 CLOSED): a
Droptype whose@dropbody merely reads a field drops exactly once (no infinite recursion, singleemit_drop_rc_free), verified by AOT execution withORI_CHECK_LEAKS=1+ eval/LLVM parity. The invoke+landing-pad blocker BUG-04-125 is CLOSED-as-resolved (bug-tracker/plans/completed/BUG-04-125/); author this pin atcompiler_repo/compiler/ori_llvm/tests/aot/drop_augment.rsas an active#[test]alongside the invoke+landing-pad slice (success_criterion 6). Shipped + green:drop_struct_runs_user_method_first_then_fields_in_reverse_decl_order— theLogged::@dropbody readsself.tagand the value drops exactly once (clean exit 0 under the harness’sORI_CHECK_LEAKS=1, no infinite recursion); the LIFO field-order sentinel sequence ([drop-Resource-user, drop-Logged-b, drop-Logged-a]) doubly pins single-drop. Passes debug AND release (FastISel parity).
- ARC-IR-level absence assertion (SHIPPABLE NOW — NOT AOT-blocked). A codegen-IR-level test asserting the emitted AUGMENT drop body for a
Drop panic-safety — abort-on-any-drop-panic
Per drop-trait-proposal.md §Drop and panic, a single panic during @drop is permitted (recoverable by the unwinder); a NESTED panic during cleanup aborts. The codegen path MUST preserve the invariant that fields ARE walked even if user_drop panics — otherwise a panicking @drop leaks the struct’s owned fields permanently.
- Codegen invariant — landing-pad around
Apply(user_drop)(NOW ACTIONABLE — BUG-04-125 CLOSED): when emitting an AUGMENT drop body, theApply(user_drop, [data_ptr])call MUST be emitted as aninvoke(LLVM unwind-capable call) wrapped in a landing pad that — on unwind — STILL runs the field-walk +emit_drop_rc_freecleanup sequence BEFORE resuming the unwind. After the cleanup sequence on the unwind path, the landing pad re-emitsResumeto propagate the original exception to the caller. Normal-return path executes the field-walk + free directly. Both paths converge on the same cleanup body via a shared LLVM basic block. Shipped:emit_drop_fieldsatdrop_gen.rsemits theown_drop_unwindspath —invoke_user_drop_via_pointer(→udrop.contnormal /udrop.cleanupunwind), the cleanup pad runslandingpad+ori_drop_cleanup_enter+ the field-walk +emit_drop_rc_free+ori_drop_cleanup_exit+resume, so first-panic-recovery semantics hold. Verified green debug + release:drop_struct_user_panic_still_runs_field_walk_then_resumes_unwind(exit 1, both fields freed),drop_single_panic_does_not_abort_before_cleanup,drop_nested_panic_during_cleanup_aborts_process(exit 134), all under the harness’sORI_CHECK_LEAKS=1. - Runtime invariant — nested-panic abort:
ori_drop_double_panic_abortruntime symbol shipped atcompiler_repo/compiler/ori_rt/src/rc/mod.rs— codegen-emitted cleanup landing pad will invoke this when wired with the landing-pad shape (Drop-AUGMENT invoke+landing-pad AOT slice — BUG-04-125 follow-up). Symbol matches Rust’s nested-panic-during-drop abort semantics and is available for the codegen-side landing-pad wiring. - Spec wiring:
drop-trait-proposal.md §Drop and panicalready names the abort-on-nested-panic invariant; runtime side shipped this slice. Spec compliance test deferred to the Drop-AUGMENT invoke+landing-pad AOT slice (BUG-04-125). - Alternative considered (spec-enforce abort-on-any-drop-panic) — REJECTED: gemini blind-spot proposed making ANY panic in @drop abort. Per
drop-trait-proposal.md §Drop and panicfirst-panic recovery is intentional (lets users implement crash-resilient drop bodies that report error context via exit hooks). Choosing landing-pad approach preserves the proposal’s stated semantics without weakening them. Current slice usescall_drop_fn’s abort-on-any-panic guard (strict mode); landing-pad wiring restores first-panic-recovery semantics per the Drop-AUGMENT invoke+landing-pad AOT slice (BUG-04-125).
Drop impl registration — user_drop FnSym population
- Registration site — explicit impl path, NOT derived-impl path: Drop is implemented explicitly by user code (
impl Type: Drop { @drop (self) -> void = body }), NOT auto-derived via#derive(Drop). The user_drop FnSym population therefore lives at the explicit impl-registration sitecompiler_repo/compiler/ori_types/src/check/registration/impls.rs::register_impl(the function processing explicitimpl T: Traitdeclarations), NOTderived.rs::register_derived_impl(which handles#derive(...)markers like E2029 Hashable-requires-Eq enforcement). - When
register_implencounters animpl Type: Drop { @drop (self) -> void = body }: the method’s compiled fn_sym is assigned toUserBurdenSpec.user_drop = Some(method_fn_sym)for the implementing Type’s BurdenSpec entry inTypeRegistry::burden. -
derived.rs::register_derived_implis NOT touched for Drop or for E2049 — it retains its existing responsibility for derived-trait validation (e.g., E2029 Hashable-requires-Eq). E2049 enforcement lives on the TWO non-derived surfaces (register_user_typesfor type-decl-side,register_implfor explicit-impl-side) per §04.4. Rationale: Drop is explicit-impl-only (NOT in the auto-derive set perdrop-trait-proposal.md §Auto-derive), andValueis a type-declaration-only marker (perori-syntax.md §Prelude,Valuecannot be user-implemented viaimpl T: Value); neither marker passes throughregister_derived_impl. User_drop population = “Type has explicit Drop impl with @drop body” atimpls.rs; E2049 = “type carries both Value AND Drop in its trait set” detected at whichever registration lands SECOND (register_user_typesif Value declaration follows,register_implif Drop impl follows). - DerivedTrait sync points (per
ir.md §DerivedTrait) — Drop is NOT in the auto-derive set perdrop-trait-proposal.md §Auto-derive(Drop is explicit-impl-only; user must write the @drop body), so NO new variant is added to theDerivedTraitenum atori_ir/derives/mod.rs. The four sync points (ori_ir,ori_types,ori_eval,library/std/prelude.ori) remain unchanged for Drop — they only carry derived traits (Eq, Hashable, Clone, Debug, Comparable, Default, Printable, Serialize).
EDROP_PARTIAL_MOVE (E2048) typeck rejection
- Error code allocation:
E2048, "EDROP_PARTIAL_MOVE: partial move on type implementing Drop"atori_diagnostic/src/error_code/mod.rsafter E2047. Diagnostic message ships atori_types/src/type_error/check_error/{message,format,kind,mod}.rs+ the rendering arm atreporting/mod.rs. - Validator location: NEW
compiler_repo/compiler/ori_types/src/check/validators/partial_move.rs::validate_drop_partial_move— sibling to the existingvalidate_partial_move(which emits E2043 for conditional partial moves on non-Drop types). Detection algorithm: AST walk overStmtKind::Let { init: Field { receiver: Ident(v), field } }patterns +ExprKind::Let { init: Field { ... } }(recursing through every reachable expression via sharedcollect_child_idshelper). Drop-trait detection:TraitRegistry::find_impl(drop_trait_idx, receiver_type); type-display-name resolution perTag(Struct →pool.struct_name, Enum →pool.enum_name, Named/Applied →pool.named_name/pool.applied_name). - Allowed cases for Drop types: full moves (entire value consumed at once), references/borrows (don’t drop), match-destructuring (binding all fields simultaneously consumes whole value with all fields bound). These mirror the
drop-trait-proposal.mdallowed-uses per §Execution Timing. - Closure capture of partially-moved field of Drop type: same rejection (E2048). The validator runs over closure capture sites identically to other Let bindings — capture site is a binding-style consumption.
- Wiring:
validate_drop_partial_moveinvoked fromfinalize_body_and_exportatori_types/src/check/bodies/mod.rsimmediately after the existingvalidate_partial_movecall site (so E2043 and E2048 fire in disjoint axes). - Whole-value-consumption invariant on match-destructure of Drop types — forbid PARTIAL by-value destructure (double-free guard). The match-destructure allowance above is sound ONLY when the destructure binds the WHOLE value (every field bound by-value simultaneously), so the value is consumed exactly once and its
@dropruns exactly once. A PARTIAL by-value destructure of a Drop type (binding a strict subset of fields by-value, leaving the residual value live) is a double-free / leak hazard: the bound fields move out (their drops now owned by the new bindings) while the residual still carries the type’s@dropglue, which would re-drop the moved-out fields.validate_drop_partial_moveMUST reject a match-arm pattern that by-value-binds a PROPER subset of a Drop type’s fields (E2048), distinct from the whole-value bind-all-fields case which is allowed. Detection extends the AST walk to match-arm destructure patterns over Drop-typed scrutinees: a struct/variant pattern that binds fewer than all owned fields by-value (and does not bind the residual via a rest-binding that re-takes ownership of the whole) fires E2048. Positive pin:match d { D { a, b } -> ... }binding BOTH fields of a 2-field Drop type → accepted (whole-value consumption). Negative pin:match d { D { a, .. } -> ... }binding onlyaby-value of a Drop type → E2048 rejected. Shipped atvalidate_drop_partial_move(check_drop_match_destructure_at+partial_subset_field+variant_payload_count): the surfacematchform lowers toExprKind::FunctionSeq(FunctionSeq::Match), so the walk now resolves scrutinee + arms from the FunctionSeq (struct{a, ..}rest-pattern OR fewer bound fields than the type/variant declares → E2048; bind-all → accepted) AND recurses into FunctionSeq children (match arm bodies, try-block statements) viawalk_drop_function_seq_childrenso nestedlet $f = v.fieldprojections inside arms are reached. Also repaired the shippedlet-projection path:drop_aggregate_type_namenow triesfind_implagainst BOTH the resolved (Struct/Enum) and unresolved (Named) receiver Idx — the impl is keyed under theNamedform while the receiver resolves toStruct, so the prior single-key lookup silently missed and E2048 never fired (mirrors the codegen-sideelement_fn_gen.rs::drop_type_nameresolve-state robustness). Verified by the 7-cell matrix atcompiler_repo/compiler/ori_types/src/check/integration_tests.rs(drop_match_partial_struct_destructure_rejected_e2048,drop_match_whole_value_struct_destructure_accepted,drop_match_partial_enum_variant_destructure_rejected_e2048,drop_match_whole_payload_enum_variant_destructure_accepted,drop_match_partial_destructure_on_non_drop_type_accepted,drop_let_projection_rejected_e2048,drop_match_nested_let_projection_in_arm_rejected_e2048) — positive + negative + negative-space clamping, declaring a localtrait Dropto register it (file-level#compile_failspec discovery is gapped — BUG-07-183).
Test Strategy
- Spec tests at
compiler_repo/tests/spec/aims/drop_augment/— NOW ACTIONABLE: the full Drop-trait surface requires the prelude’sDroptrait registered inlibrary/std/prelude.ori+ thelibrary/std-side trait wiring (formerly BUG-06-005, CLOSED-as-obe atbug-tracker/plans/completed/BUG-06-005/); current slice ships the typeck E2048 validator that activates wheneverDropIS registered in the trait registry. Shipped:tests/spec/aims/drop_augment/holdswhole_value_destructure_allowed.ori(positive — runs + passes viacargo st, thetests-clause functiontest_whole_value_destructure_acceptedcompiles aPair { a, b }whole-value match-destructure clean) pluslet_projection_rejected.ori+partial_match_destructure_rejected.ori(negative#compile_fail(code: "E2048")files — both produce E2048 whenori check-ed directly, confirming the directive expectation is correct). On-disk disposition (verified):drop_augment.rscarries TWO#[ignore]slots citing OPEN blockers — BUG-05-006 (AOT Setelement teardown segfault) + BUG-04-122. The on-disk drop_augment.rs:656#[ignore]reason for BUG-04-122 reads “niche-encoded codegen gated off (NICHE_CODEGEN_READY=false)”; the single-variant-tagless / niche-encoded heap-payload codegen surface is the same BUG-04-122 cell (the IR-level niche dec SSOT routing is verified, the behavioral cell activates when niche codegen ships). Both are legitimate open-blocker dispositions per.claude/rules/test-disposition.md; those two cells STAY ignored until those bugs close (do NOT remove them, do NOT re-point them). There is NO BUG-04-119#[ignore]indrop_augment.rs— that anchor (imported generic monomorphization) is unrelated and was never the disposition.- (deferred-with-anchor: BUG-07-183) The two negative
#compile_failspec files are NOT executed by theori testrunner — file-level#compile_failon a plain@fn/ type decl has itsexpected_errorsdropped at parse time (onlyTestDefcarries them), so the runner reports “NO TESTS FOUND” and verifies nothing (the long-standing E2043conditional_partial_move_rejected.oriis identically un-run). This is a runner gap orthogonal to §04.3, tracked at BUG-07-183 (tooling/oric test runner). The E2048 deliverable’s negative-pin verification is fully covered by the run-ableori_typesintegration matrix (item §04.3 match-destructure above); the spec files activate once BUG-07-183 lands file-level#compile_faildiscovery without modification.
- (deferred-with-anchor: BUG-07-183) The two negative
- Codegen tests scaffold at
compiler_repo/compiler/ori_llvm/tests/aot/drop_augment.rs— NOW ACTIONABLE: AUGMENT-body codegen verification re-enables (invoke+landing-pad blocker BUG-04-125 CLOSED-as-resolved atbug-tracker/plans/completed/BUG-04-125/); author the four non-ignored pins below as active#[test]s (the two BUG-05-006 / BUG-04-122#[ignore]cells remain ignored until those open bugs close). Shipped + green (debug AND release, harnessORI_CHECK_LEAKS=1): the four pins land asdrop_struct_runs_user_method_first_then_fields_in_reverse_decl_order(struct LIFO[drop-Resource-user, drop-Logged-b, drop-Logged-a]),drop_enum_runs_user_method_first_then_variant_fields_in_reverse_order(enum LIFO),drop_struct_user_panic_still_runs_field_walk_then_resumes_unwind(landing-pad: exit 1, both fields freed),drop_nested_panic_during_cleanup_aborts_process(nested-panic abort, exit 134). The two BUG-05-006 / BUG-04-122#[ignore]cells remain ignored (untouched, legitimate open-blocker dispositions; the BUG-04-122 cell’s on-disk reason atdrop_augment.rs:656is the “niche-encoded codegen gated off (NICHE_CODEGEN_READY=false)” disposition — same BUG-04-122 surface). 20/22 active pins pass; 2 ignored.drop_augment_user_method_first_then_compiler_field_walk_reverse_order(struct AUGMENT, DropKind::Fields). Observable LIFO semantic pin perdrop-trait-proposal.md §85:type Outer = { first: Logged, second: Logged, third: Logged }where eachLogged’s@dropappends its tag to a shared log; positive assertion = observed drop sequence equals[third, second, first](reverse decl order, after the Outer@dropbody runs first); paired negative assertion = sequence does NOT equal forward order[first, second, third].drop_augment_enum_user_method_first_then_variant_field_walk_reverse_order(enum AUGMENT, DropKind::Enum). Observable LIFO semantic pin: an enum variant carrying multipleLoggedowned fields drops them in reverse decl order after the enum-level@dropbody runs; positive = reverse-order log sequence, negative = NOT forward-order.drop_augment_landing_pad_runs_field_walk_on_user_drop_panic_path(panic-safety, landing pad).drop_augment_nested_panic_invokes_ori_drop_double_panic_abort(panic-safety, nested panic).
- Rust unit tests scaffold at
compiler_repo/compiler/ori_types/src/check/validators/partial_move/tests.rs:drop_partial_move_validator_handles_invalid_body_root_without_panicking— smoke pin verifying ExprId::INVALID short-circuit.drop_partial_move_validator_silent_when_drop_trait_unregistered— pre-deployment-shape pin verifying the validator silently no-ops whenDropis not yet wired into the trait registry. The full 4-axis matrix (Drop × {conditional, unconditional} × {E2048, E2043, both, none}) requires thelibrary/stdDrop trait + prelude wiring (formerly BUG-06-005, now CLOSED-as-obe atbug-tracker/plans/completed/BUG-06-005/) — NOW ACTIONABLE: author the end-to-end matrix atcompiler_repo/compiler/ori_types/src/check/validators/partial_move/tests.rsonce the prelude Drop trait is wired.
- Verification gate:
cargo test -p ori_types --lib check::validators::partial_move::returns 3/3 passed;cargo test -p ori_llvm --lib codegen::arc_emitter::tests::returns 36/36 passed (all migrated to newDropKind::{Fields,Enum}struct shape);cargo c -p ori_types -p ori_arc -p ori_llvm -p ori_rt -p ori_diagnostic --all-targetsclean;cargo clippy -p ori_types -p ori_arc -p ori_llvm -p ori_rt -p ori_diagnostic --all-targets -- -D warningsclean. AOT slice gates NOW ACTIONABLE (the Drop-AUGMENT invoke+landing-pad blocker BUG-04-125 is CLOSED-as-resolved atbug-tracker/plans/completed/BUG-04-125/): runORI_CHECK_LEAKS=1+ eval/LLVM parity on the positive pins atcompiler_repo/compiler/ori_llvm/tests/aot/drop_augment.rs.
Subsection close-out (04.3) per protocol.
04.3 HISTORY
- 2026-05-17 — §04.3 Drop AUGMENT typeck + DropKind API + runtime symbol landing. Five typeck-side + codegen-API + runtime deliverables shipped; AUGMENT body-shape + landing-pad AOT slice deferred to BUG-04-119 per scope discipline.
- E2048 allocation (
EDROP_PARTIAL_MOVE) shipped atcompiler_repo/compiler/ori_diagnostic/src/error_code/mod.rs(next slot after E2047) +compiler_repo/compiler/ori_diagnostic/src/errors/E2048.mdmarkdown with cure cases (full move / borrow / match destructure /drop_early); diagnostic kindTypeErrorKind::DropPartialMoveatcompiler_repo/compiler/ori_types/src/type_error/check_error/{kind,mod,message,format}.rs+reporting/mod.rsrendering arm. Mapping E2048 ↔ kind shipped atmessage.rs::code()arm. validate_drop_partial_movevalidator shipped atcompiler_repo/compiler/ori_types/src/check/validators/partial_move.rs(sibling tovalidate_partial_movefor E2043). AST walk overLet { init: Field { ... } }patterns; Drop-impl detection viaTraitRegistry::find_impl(drop_trait_idx, receiver_type). Disjoint-axis from E2043: every Drop partial move is forbidden regardless of CFG path; non-Drop conditional partial moves continue to fire E2043 via the existing validator. Wired frombodies/mod.rs::finalize_body_and_exportviarun_drop_partial_move_validatorrunner — invoked immediately after the existingrun_partial_move_validatorcall site so E2043 + E2048 fire in disjoint axes on the same body walk.- Drop impl detection +
user_drop+compiled_droppopulation atregister_implshipped atcompiler_repo/compiler/ori_types/src/check/registration/impls.rs::populate_drop_burden_if_applicable. Resolves Drop’s trait Idx via the interner; when the impl-def’s trait_idx matches, mintsuser_drop = Some(FnSym)viamint_compiled_drop_fn_sym(self_type)AND mintscompiled_drop = Some(FnSym)per the §04.1 decision rule (compiled_drop = Some(_) iff (non-singleton SCC) OR (self-loop) OR (user_drop = Some(_))). CallsTypeRegistry::register_user_burdento merge the user_drop / compiled_drop fields over the existing burden_compute output; preserves all field-walk machinery shipped in §04.1. - DropKind API change shipped at
compiler_repo/compiler/ori_arc/src/drop/mod.rs:DropKind::Fields(Vec) → DropKind::Fields { fields, user_drop: Option<FnSym> };DropKind::Enum(Vec<Vec>) → DropKind::Enum { variants, user_drop: Option<FnSym> }.FnSymcarries#[cfg_attr(feature = "cache", serde(skip))]— cache hits re-deriveuser_dropfrom current TypeRegistry per AIMS Invariant 3 (no stale summaries).burden_bridge.rs::burden_to_drop_kindupdated to emit struct shape; the “fields.is_empty() + user_drop.is_none()” check ensures Drop types with all-scalar fields STILL emit a DropKind so the AUGMENT body fires. Consumers updated:drop_gen.rs::generate_drop_fndispatch arms;instr_dispatch.rs::BurdenDecPartial+BurdenDecVariantarms (user_drop intentionally NOT invoked at SetField/SetTag mid-mutation; only refcount-zero path). emit_drop_fields+emit_drop_enumAUGMENT body shape shipped atcompiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/drop_gen.rs+drop_enum.rs. Both functions acceptuser_drop: Option<FnSym>parameter; whenSome, invoke_ori_user_drop$<idx>BEFORE the field walk / discriminant switch. Field walk reverses declaration order perdrop-trait-proposal.md §85. Current slice ships plaincallto user@drop; the plan-mandatedinvoke+ landing-pad lowering for first-panic recovery (perdrop-trait-proposal.md §Drop and panic) is deferred to BUG-04-119; panic-safety is preserved by existingori_rt::rc::call_drop_fnruntime abort-on-any-panic guard (strict mode — first-panic recovery semantics restored when landing-pad wiring lands).ori_drop_double_panic_abortruntime symbol shipped atcompiler_repo/compiler/ori_rt/src/rc/mod.rs.extern "C"nounwind-by-construction abort entry; matches Rust’s nested-panic-during-drop semantics. Symbol is available for the codegen-side landing-pad wiring (BUG-04-119); used as the “second panic during cleanup” abort target.- Tests: 3/3 validator smoke tests at
partial_move/tests.rs(drop_partial_move_validator_handles_invalid_body_root_without_panicking,drop_partial_move_validator_silent_when_drop_trait_unregistered, existingpartial_move_validator_handles_invalid_body_root_without_panicking). 36/36 existing arc_emitter drop tests atarc_emitter/tests.rsmigrated to newDropKind::{Fields,Enum}struct shape. AOT scaffolds atcompiler_repo/compiler/ori_llvm/tests/aot/drop_augment.rscarry 4#[ignore = "BUG-04-119: ..."]tests pinning the full AUGMENT-body + landing-pad + nested-panic-abort surface. - Gates:
cargo c -p ori_types -p ori_arc -p ori_llvm -p ori_rt -p ori_diagnostic --all-targetsclean;cargo test -p ori_types --lib check::validators::partial_move::3/3 pass;cargo test -p ori_llvm --lib codegen::arc_emitter::tests::36/36 pass;cargo clippy -p ori_types -p ori_arc -p ori_llvm -p ori_rt -p ori_diagnostic --all-targets -- -D warningsclean. Full lib-test suite: 1019 ori_types + 1390 ori_arc + 652 ori_llvm + 367 ori_rt = 3428 tests, 0 failures. - Deferrals with concrete anchors per CLAUDE.md §“ALL Deferrals MUST Have Implementation Anchors”:
BUG-04-118(closure UserBurdenSpec lambda-side wiring): closure-and-Drop interactions roundtrip through the same path onceinfer_lambdacallscompose_closure_burden_spec+register_user_burdenat lambda-typecheck time.BUG-04-119(AUGMENT body shape AOT slice):invoke+ landing-pad +__gxx_personality_v0wiring aroundApply(user_drop); restores first-panic-recovery semantics perdrop-trait-proposal.md §Drop and panic; closes the four AOT scaffolds atdrop_augment.rs.
- E2048 allocation (
04.4 Value trait empty-burden + EVALUE_DROP_CONFLICT (E2049) at type-declaration + impl registration + mixed-Value/Heap composition
Files:
compiler_repo/compiler/ori_types/src/check/registration/user_types.rs::register_user_types— Surface 1 E2049 detection at type-decl registration (queries TraitRegistry for existing Drop impl when Value marker appears on declaration)compiler_repo/compiler/ori_types/src/check/registration/impls.rs::register_impl— Surface 2 E2049 detection at Drop impl registration (queries TraitRegistry for Value marker on receiver type)compiler_repo/compiler/ori_registry/src/burden/table.rs— Value primitives entriescompiler_repo/compiler/ori_diagnostic/src/error_code/mod.rs— E2049 = “EVALUE_DROP_CONFLICT: type carries both Value and Drop”compiler_repo/compiler/ori_types/src/registry/burden_compose/mod.rs— variant_burden composition for mixed-Value/Heap (existing §02 machinery consumed)
Design — Empty UserBurdenSpec for Value types
Per ori-syntax.md §Prelude (Value trait section):
trait Value: Clone, Eq— marker trait; inline storage, bitwise copy, no ARC, no Drop; all fields must beValue; cannot be implemented manually; auto-satisfiesClone+Sendable.
- At
BurdenRegistrypopulation time, when a type carriesValuemarker (either primitive —int/float/bool/char/byte/void/Duration/Size/Ordering— or user-definedtype T: Value = { ... }), populateUserBurdenSpec:UserBurdenSpec { self_heap_alloc: false, // Value types are inline-stored owned_fields: vec![], // Value composition: all fields are Value, no heap ownership borrowed_fields: vec![], variant_burdens: vec![], element_burden: None, compiled_drop: None, // No heap → no compiled_drop user_drop: None, // Value cannot impl Drop (mutually exclusive) } - For primitives: emit entries into
ori_registry::burden::table::BURDEN_TABLE(pure-const builtin table). Each primitive’s BuiltinBurdenSpec template hasself_heap_alloc: false, owned_fields: &[], variant_burdens: &[], compiled_drop: None, user_drop: None. ExistingBUILTIN_BURDEN_TABLEentries already satisfy this shape — verified:int/float/bool/char/byte/void/Duration/Size/OrderingcarryBuiltinBurdenSpec::EMPTYperori_registry::burden::table. - For user-defined
type T: Value = { ... }: populated atregister_user_typessite viapopulate_value_burden_if_applicableatcompiler_repo/compiler/ori_types/src/check/registration/user_types.rs. Whendecl.derivescontainsValue, callsregister_user_burden(idx, UserBurdenSpec::default())(empty spec) ANDrecord_value_marker(idx)so Surface 2 can detect late-arriving Drop impls. - Value field-constraint enforcement (transitively-Value fields) — HARD §04.4 close-out gate (
blocks_section_close); success_criterion 11. SHIPPED 2026-06-02 atpopulate_value_burden_if_applicable(enforce_value_field_constraint+ cycle-awarefield_idx_is_value); all four pins (value_type_all_value_fields_registers_empty_burden,value_type_with_str_field_rejected,value_type_with_nested_value_struct_field_accepts,value_type_with_recursive_value_field_terminates) pass incheck/registration/tests.rs. The visited-set memo (seeded with the declaring typeIdx) is the single cycle guard; a non-Value field emits E2032 (FieldMissingTraitInDerive) naming the offending field + theValuetrait. Perori-syntax.md §Prelude(Valuerequiresall fields must be Value): atpopulate_value_burden_if_applicable, BEFORE registering the empty UserBurdenSpec, walk every declared field’s resolvedIdxand assert each satisfiesValue(primitive Value set OR a user type that itself carries the Value marker — recursive via the already-registeredrecord_value_markerset +ori_registry::burdenValue membership). A non-Value field (str/[T]/{K:V}/Set<T>or any heap-bearing user type) is a compile error naming the offending field. The empty UserBurdenSpec atpopulate_value_burden_if_applicableis sound ONLY when this transitive-Value field-walk guard holds — registering an empty burden for a type with a heap-bearing field would silently drop the field’s RC obligation (the latent silent-RC-drop). Validator anchored at the same Surface 1 sitecompiler_repo/compiler/ori_types/src/check/registration/user_types.rs::populate_value_burden_if_applicable. Cycle-aware traversal — MANDATORY. The transitive field-walk MUST carry a visited-set/memo keyed on typeIdxso a recursive Value-marked type (e.g. a type whose field set transitively references itself through aValuewrapper) terminates instead of recursing infinitely; a fieldIdxalready in the visited set is treated as resolved (its membership verdict is already being computed or has been computed) and does NOT re-descend. The validator records each type’s Value-membership verdict once per traversal and short-circuits on a revisit. Pins (positive + negative + transitive + cycle pertests.md §Matrix Testing Rule):value_type_all_value_fields_registers_empty_burden(positive —type Pt: Value = { x: float, y: float }→ empty UserBurdenSpec, no diagnostic);value_type_with_str_field_rejected(negative —type Bad: Value = { name: str }→ field-constraint diagnostic namingname: str);value_type_with_nested_value_struct_field_accepts(transitive —type Outer: Value = { inner: Pt }wherePt: Value→ accepted via transitive Value-membership lookup);value_type_with_recursive_value_field_terminates(cycle — a Value-marked type whose field walk transitively revisits the same typeIdxresolves via the visited-set memo without infinite recursion or stack overflow). Appended to thecheck/registration/tests.rsmatrix alongside the E2049 cells. Implementer note (NOT part of this criterion — out-of-scope for the §04.4 field-walk deliverable): this validator walks declared FIELDIdxand does NOT enforce that a Value-marked GENERIC type PARAMETER is itselfValue-bounded (e.g.type Box<T>: Value = { inner: T }with unboundedTwould permit unsound monomorphizationBox<HeapType>carrying an empty UserBurdenSpec). If that generic-parameterT: Valuebound check is confirmed a real validator gap at §04.4 landing, the implementer files/add-bugsubsystemtypeck(registration-time Value-generic-bound check) per the §04.Ragy-F3 re-review variantcandidate item — do NOT widen this criterion to specify it.
EVALUE_DROP_CONFLICT (E2049) enforcement — type-declaration registration + Drop impl registration
- Error code allocation:
E2049, "EVALUE_DROP_CONFLICT: type marked Value cannot implement Drop"shipped atcompiler_repo/compiler/ori_diagnostic/src/error_code/mod.rs(line 160 on disk, immediately after E2048 at line 159). Diagnostic message + suggestions wired throughValueDropConflict { type_name }variant onTypeErrorKind(kind.rs + constructors in mod.rs + format.rs + message.rs + reporting/mod.rs label arm). Imperative-fixerrors/E2049.mdships matching the E2042/E2048 pattern. - Ori surface asymmetry: per
ori-syntax.md §Declarations+ §Prelude,Valueis a compiler-marker trait set on the TYPE DECLARATION (type T: Value = { ... }), NEVER user-implemented viaimpl T: Value(Value’s invariants are statically enforced by the compiler).Drop, by contrast, is user-implemented exclusively via explicitimpl T: Drop { @drop (self) -> void = body }(perdrop-trait-proposal.md §Auto-derive, Drop is NOT auto-derivable). Two distinct registration surfaces detect the conflict:- Surface 1 — Type declaration:
compiler_repo/compiler/ori_types/src/check/registration/user_types.rs::populate_value_burden_if_applicable. Whendecl.derivescontainsValue: queryTraitRegistry::has_impl(drop_idx, idx). If present: emit E2049 withdecl.span(type-decl is the second registration). - Surface 2 — Drop impl registration:
compiler_repo/compiler/ori_types/src/check/registration/impls.rs::populate_drop_burden_if_applicable. Whenimpl T: Dropis registered: queryTypeRegistry::carries_value_marker(self_type)(populated by Surface 1 viarecord_value_marker). If true: emit E2049 withimpl_def.span(Drop impl is the second registration).
- Surface 1 — Type declaration:
- NO
impl T: Valuesite: per ori-syntax.md,impl T: Valueis not valid Ori syntax — Value is type-declaration-only. The test matrix covers ONLY the two valid orderings: (Value-on-type-decl FIRST, Drop-impl SECOND) and (Drop-impl FIRST, Value-on-type-decl SECOND). - Order independence: whichever registration lands SECOND emits E2049. Verified by two paired tests:
drop_impl_for_value_type_emits_e2049_at_register_impl_surface(type-decl first, impl second → Surface 2 fires) andvalue_type_decl_with_drop_impl_emits_e2049_at_user_types_surface(impl first, type-decl second → Surface 1 fires).
Mixed-Value/Heap composition — Result<ValueType, HeapType>
- Generic composition:
Result<int, str>(Value Ok + Heap Err) →UserBurdenSpecforResult<int, str>has:UserBurdenSpec { self_heap_alloc: false, // Result inline-stored when payload allows (per repr.md §7 NI-4 niche encoding) owned_fields: vec![], // No top-level owned fields variant_burdens: vec![ VariantBurden { variant: Ok, burden: <empty UserBurdenSpec for int> }, VariantBurden { variant: Err, burden: <full UserBurdenSpec for str> }, ], ... } - Phase 5 emission for
Result<int, str>: BurdenDec at last-use of the Result branches per variant_burden:- Ok arm: empty burden → no BurdenDec emitted (no heap to release).
- Err arm: full str burden → BurdenDec emitted (releases the str’s RC).
- Existing variant_burdens composition machinery handles this — composition is shipped per
compose_user_burdenatburden_compose/mod.rs. The empty-vs-full asymmetry is verified byresult_value_heap_composition_inherits_distinct_variant_burdensatburden_compose/tests.rs: Ok arm’sfield_typeisIdx::INT(Value-role, empty burden via per-Idx lookup); Err arm’sfield_typeisIdx::STR(Heap-role, full burden via per-Idx lookup). - Niche encoding interaction: per
repr.md §7 NI-3/NI-4,Option<T>andResult<T, E>may be niche-encoded (eliding the tag field). Burden composition operates on LOGICAL variants (Ok/Err, Some/None) — physical layout via niche or tagged encoding is orthogonal. Verified byoption_value_type_niche_encoded_inherits_empty_burdenatburden_compose/tests.rs:Option<int>produces None + Some logical arms regardless of how niche encoding lowers the physical layout.
Test Strategy
Spec tests at compiler_repo/tests/spec/aims/value_drop_conflict/. The #compile_fail("E2049") typeck-rejection tests below exercise compile-time E2049 enforcement (shipped at both registration surfaces per the [x] items above) and do NOT depend on AOT codegen — they are gated ONLY by the prelude Value + Drop trait registration in library/std/prelude.ori (formerly BUG-06-005, now CLOSED-as-obe). The prelude-wiring, lambda-side (infer_lambda), and Drop-AUGMENT-AOT blockers are ALL now closed (BUG-06-005 obe, BUG-02-033 resolved, BUG-04-125 resolved, BUG-04-043 resolved); the ORI_DUMP_AFTER_ARC-verified positive pins are NOW ACTIONABLE.
-
(deferred-with-anchor: BUG-01-009)
value_drop_conflict_rejected.ori—#compile_fail("E2049")negative pin: declarestype T: Value, ... = { ... }THENimpl T: Drop. BLOCKED: thetype T: Value = {...}type-decl trait-bound surface does NOT parse (E1001 — grammar.ebnftype_deflacks the[":" bounds]clause the spec mandates; tracked BUG-01-009), AND file-level#compile_failis dropped by theori testrunner (BUG-07-183). E2049 negative enforcement is instead pinned RUNNABLY atcompiler_repo/compiler/ori_types/src/check/integration_tests.rs::value_marker_with_drop_impl_fires_e2049_value_first(via#derive(Value)+impl Drop, the only parseable Value surface today). Re-author this.ori#compile_failfile when BOTH BUG-01-009 (surface) AND BUG-07-183 (runner) close. -
(deferred-with-anchor: BUG-01-009)
value_drop_conflict_order_independent.ori— both surface-ordering variants BLOCKED on the same BUG-01-009 + BUG-07-183 pair. Order-independence IS pinned runnably at the Rust unit level (value_type_decl_with_drop_impl_emits_e2049_at_user_types_surfaceSurface 1 +drop_impl_for_value_type_emits_e2049_at_register_impl_surfaceSurface 2 incheck/registration/tests.rs); the.ori#compile_failfiles re-author when the surface + runner blockers close. -
value_primitives_have_empty_burden.ori— positive pin SHIPPED 2026-06-02 atcompiler_repo/tests/spec/aims/value_drop_conflict/value_primitives_have_empty_burden.ori(runnable, dual-backend green). Zero-RC-op property pinned at the IR level by the AOT testvalue_empty_burden.rs::test_value_only_program_emits_zero_rc_ops(ORI_DUMP_AFTER_LLVMshows zeroori_rc_inc/ori_rc_dec); the.oritest pins observable behavior through interpreter + LLVM. -
result_value_heap_emits_asymmetric_drop.ori— positive pin SHIPPED 2026-06-02 atcompiler_repo/tests/spec/aims/value_drop_conflict/result_value_heap_emits_asymmetric_drop.ori(runnable, dual-backend green). Asymmetric drop pinned at the IR level byvalue_empty_burden.rs::test_result_value_heap_emits_asymmetric_drop(ori_str_rc_decon Err path only, Ok-int path no drop); the.oritest pins observable behavior + zero-leak through interpreter + LLVM. -
Rust unit tests appended to
compiler_repo/compiler/ori_types/src/check/registration/tests.rs(existing sibling file matching the §04.3 pattern; a separatevalue_drop_conflict_tests.rswould duplicate themake_param+ module-test scaffolding already intests.rs). 4-axis matrix exercising both surfaces:value_type_decl_with_drop_impl_emits_e2049_at_user_types_surface— Drop-then-Value ordering: register Drop impl FIRST, then declaretype Point: Value, ... = { ... }. Pin asserts exactly one E2049 fires at Surface 1 with span at the type declaration.drop_impl_for_value_type_emits_e2049_at_register_impl_surface— Value-then-Drop ordering: declaretype Point: Value, ... = { ... }FIRST, then registerimpl Point: Drop. Pin asserts exactly one E2049 fires at Surface 2 with span at the impl declaration.value_type_without_drop_impl_registers_empty_user_burden_spec— Value-only type: no E2049, emptyUserBurdenSpecregistered (self_heap_alloc=false,owned_fields=[],variant_burdens=[],compiled_drop=None,user_drop=None),carries_value_marker(idx)returns true.drop_impl_for_non_value_type_registers_user_drop_no_e2049— Drop-only type: no E2049,user_drop=Some(_)populated by populate_drop_burden_if_applicable,carries_value_marker(idx)returns false.- Field-walk pins (success_criterion 11) appended 2026-06-02:
value_type_all_value_fields_registers_empty_burden(positive),value_type_with_str_field_rejected(negative — E2032 names thestrfield),value_type_with_nested_value_struct_field_accepts(transitive Value-membership),value_type_with_recursive_value_field_terminates(cycle — visited-set memo terminates). Plus runnable source-level E2049 negatives atcheck/integration_tests.rs(value_marker_with_drop_impl_fires_e2049_value_first+ the two no-E2049 negative-space pins) — the BUG-07-183 runner-gap workaround for the file-level#compile_fail("E2049")spec files.
-
Burden composition tests at
compiler_repo/compiler/ori_types/src/registry/burden_compose/tests.rs— two new cells appended:result_value_heap_composition_inherits_distinct_variant_burdens— positive pin:Result<int, str>Ok arm’sfield_typeisIdx::INT(Value-role); Err arm’sfield_typeisIdx::STR(Heap-role). Per-varianttransfer_kindisMovein both arms (kind erasure across the Value/Heap boundary at the composition level; role-asymmetric burden emission lives downstream via per-IdxTypeRegistry::burden(idx)lookup at codegen).option_value_type_niche_encoded_inherits_empty_burden— positive pin:Option<int>produces two logical variant_burdens (None + Some) with Some carryingIdx::INT. Niche encoding operates on physical layout; burden composition operates on logical variants — the two are orthogonal.
-
AOT codegen test — SHIPPED 2026-06-02 at
compiler_repo/compiler/ori_llvm/tests/aot/value_empty_burden.rs(registeredpub mod value_empty_burden;intests/aot/main.rs); 3 active#[test]s pass debug AND release:test_value_only_program_emits_zero_rc_ops— Value-only program’s LLVM IR contains zeroori_rc_inc/ori_rc_deccalls (IR inspection viacompile_and_capture_ir); zero-leak AOT run (ORI_CHECK_LEAKS=1); eval/LLVM exit-code parity.test_heap_program_emits_rc_ops— negative-space clamp: a heap-bearing (str) program emits ≥1 RC op (proves the zero-RC result is the Value path, not a never-emits codegen).test_result_value_heap_emits_asymmetric_drop—Result<int, str>Err arm emitsori_str_rc_dec; both arms run zero-leak; eval/LLVM parity on both arms.
-
TPR checkpoint — the 2026-05-17 editor-pass round-loop short-circuit (
third_party_review.status: clean, actionable_count=0) was superseded by subsequent content-drift auto-reversals. Current frontmatter SSOT isthird_party_review.status: none,reviewed: false,status: in-review,blocked_by: [](every prior blocker — BUG-04-043, BUG-04-125, BUG-06-005, BUG-02-033 — is now CLOSED on disk underbug-tracker/plans/completed/). Section-close /tpr-review re-runs at §04 close-out once the now-actionable item-level slices (Drop-AUGMENT invoke+landing-pad AOT, prelude Value+Drop wiring + the value_drop_conflict spec tests, lambda-sideinfer_lambdaclosure-UserBurdenSpec wiring, the transitively-Value field-constraint validator + its four pins) land; the prior “frontmatter-clean” claim no longer holds.
Subsection close-out (04.4) per protocol.
04.R — Third Party Review Findings
-
RESOLVED 2026-05-17 [TPR-04.R-001-opencode][Critical] STRUCTURE:work-order-violation — §01 now carries
reviewed: true(verified:grep -E '^reviewed:' plans/aims-burden-tracking/section-01-burden-registry.mdreturnsreviewed: true). The work-order predecessor invariant satisfied. Original finding text: Section-04 was advanced tostatus: in-reviewwhile predecessor section-01 (section-01-burden-registry.md) carriesreviewed: false. The newly-expandeddepends_on: ["01", "02", "03"](per §04 frontmatter, expanded during Step 5 editor from priordepends_on: ["03"]per opencode blind-spots feedback) requires every predecessor to carryreviewed: truebefore a consumer section may transition toin-progress/in-review. Cure (caller-level decision — out of scope for §04 content rewrite): EITHER (a) run/review-plan plans/aims-burden-tracking/section-01-burden-registry.md --autopilotto flip section-01 fromreviewed: false→reviewed: trueperstate-discipline.md §4atomic-flip discipline (preferred when section-01 is genuinely review-ready), OR (b) revert section-04’sstatus: in-review→not-startedviascripts/review_plan_runtime/status_flip.py::record_review_reversaluntil predecessor §01 satisfied. Recorded here for the parent/review-planStep 7+8 verify gate to surface to the caller (/continue-roadmapautopilot or user). NEVERreviewed: trueflip on §04 close-out while this item remains unchecked. Re-affirmed by the 2026-05-17 Step 5 editor pass: audit Critical finding TPR-04.R-001 unchanged — directive holds; the editor did NOT flipreviewed:on §04 nor on §01. -
RESOLVED 2026-05-31 [TPR-04.R-006-agy+codex+opencode][Major] GROUNDEDNESS:misattributed-bug-anchor — anchors repointed to BUG-04-125 + closure-wiring candidate-bug note (see §04.R Candidate
/add-bugitems). SUPERSEDED-IN-PART (2026-05-31 editor pass): the “BUG-04-043 confirmed OPEN,blocked_byKEPT” portion of this finding is STALE — BUG-04-043 is now CLOSED-as-resolved (bug-tracker/plans/completed/BUG-04-043/);blocked_byis cleared to[](opencode-F1), the recursive-drop AOT slice is unblocked, and the Drop-AUGMENT placeholder is resolved to BUG-04-125 (opencode-F3). Original 2026-05-31 finding text below retained for traceability only. The misattributed BUG-04-119 forward-deferral anchors (success_criteria 6+8, §04.3 panic-safety body + Test Strategy, §04.4 Test Strategy, §04.N) are now re-pointed to BUG-04-125 (the Drop-AUGMENT invoke+landing-pad AOT slice) per the 2026-05-31 editor-pass HISTORY entry (BUG-04-119 verified OPEN but tracks imported generic monomorphization, plan dir absent on disk — wholly unrelated to the Drop-AUGMENT codegen surface).blocked_by: ["BUG-04-043"]confirmed CORRECT (BUG-04-043 open, genuinely gates §04.1’s recursive-drop AOT slice). The parent /review-plan caller files the properly-scoped Drop-AUGMENT AOT bug and re-points the#[ignore]reasons indrop_augment.rsfrom BUG-04-119 to it in the commit closing it. Original finding text: §04 AOT-deferral anchors cite bug IDs whose actual tracker scope is unrelated: BUG-04-043 = “§07.3.A recursive tagged-pointer enum box-and-load codegen”, BUG-04-119 = “AOT imported-generic monomorphization”, BUG-04-118 (closed-obe) = “AIMS PIN-4 match_alias double-free” — none track §04.1/§04.2/§04.3 recursive/closure/AUGMENT AOT slices.blocked_by: [BUG-04-043]+ theclosure_drop.rs:63/:84+drop_augment.rs:57#[ignore]reasons reference wrong/stale bugs. Cure: determine §04’s true AOT-slice blockers (file proper bugs or correct the citations); re-point or un-ignore the AOT tests. Filed at §04-review cap-exit (cap_reached_with_substantive, 3 rounds, 2026-05-28); loggedbug-tracker/diagnostic-questions.md2026-05-28. -
RESOLVED 2026-05-31 [TPR-04.R-005-opencode][Major] STRUCTURE:budget-overrun —
budget:{body_lines:520}added 2026-05-31 editor pass (frontmatter lines 73-75, with rationale: the four BurdenSpec composition cases are one cohesive non-promotable scope per the §04 Subsection-independence analysis). The budget field now exists; the budget-vs-split decision resolved in favor of the budget perrouting.md §4(split would fragment one drop-glue story across four boundary-less siblings). Original finding text: §04 body is 458 lines vsrouting.md §5plan-section default 300; nobudget:frontmatter field. Cure (deliberate split-vs-budget decision perrouting.md §4): either split into letter-suffix siblings (≥3 work subsections) OR addbudget: {body_lines: N, rationale: "..."}if the four BurdenSpec composition cases are genuinely one cohesive scope. Filed at §04-review cap-exit (cap_reached_with_substantive, 3 rounds, 2026-05-28). -
REFUTED 2026-05-17 — stale finding [TPR-04.R-002-codex][Critical] STRUCTURE:tpr-exit-reason-drift — Verified:
cap_reached_with_substantiveIS in the/tpr-reviewcanonical exit_reason enum defined at.claude/skills/tpr-review/references/exit-reason-enum.md(semantically-narrower sibling of cap_reached_max_rounds; routes identically to verify-done). Finding was authored before the enum extension landed. No tooling cure required; the drift was already resolved upstream. Verbatim refutation evidence:grep -l 'cap_reached_with_substantive' .claude/skills/tpr-review/references/exit-reason-enum.mdmatches (the token is absent fromSKILL.md— it lives in thereferences/exit-reason-enum.mdenum SSOT). Original finding text:/tpr-reviewround-loop emittedcap_reached_with_substantiveat round 5/5;/review-planorchestrator_dispatch_tpr_exit_reason()rejected withhalt_reason: tpr_exit_reason_driftbecause that value is NOT in/tpr-reviewSKILL §1.7 canonical exit_reason enum (cap_reached_max_rounds+cap_reached_meta_only). Drift betweenscripts/tpr_review_runtime/round_loop.py::should_exit()emission and/review-plan’s mapping table BLOCKS §04 close-out at Step 7+8 verify regardless of TPR substantive convergence. Promoted from HISTORY into §04.R as a BLOCKING item per tooling-first hierarchy and pertooling-first.md §1.1meta-tool boundary. Cure (caller-level —/improve-toolingSSOT): EITHER (a) alignscripts/tpr_review_runtime/round_loop.py::should_exit()emission with/tpr-reviewSKILL §1.7 canonical enum (addcap_reached_with_substantiveto the enum + the_dispatch_tpr_exit_reason()mapping table perdecisions/31Option C parity surface), OR (b) collapse the runtime’s emitted value to the existingcap_reached_max_roundstoken (drops “substantive” qualifier; loses signal that/review-planorchestrator uses to distinguish substantive cap-exit from meta-only cap-exit). Recommended option (a): preserve the substantive-vs-meta distinction by extending the canonical enum, since /review-plan downstream routing already distinguishes the two on_dispatch_tpr_exit_reason(). Banned cures: (1) Claude-side enum substitution in section bodies to fabricate a canonical value (banned by the orchestrator’s halt payload pertooling-first.md §1.1); (2) bypass-gate acceptingtpr_exit_reason_driftwithout resolving (preserves drift permanently). This item GATES §04.N close-out — until the drift is resolved, /review-plan Step 7+8 §00.3 close-out cannot flip §04reviewed: false → trueregardless of /tpr-review substantive outcome, because the orchestrator halt PRECEDES the close-out gate. Caller (/continue-roadmap autopilot or user) MUST invoke/improve-tooling --gap tpr_exit_reason_driftbefore §04 close-out is attempted again. -
RESOLVED 2026-05-29 [TPR-04.R-003-codex][Major] §04.N
index.md section statuschecklist line reconciled with thestatus: in-reviewSSOT perstate-discipline.md §1(un-checked + reworded; no longer asserts derivation fromstatus: complete). Original finding text: the §04.N checklist line asserted derivation from §04 frontmatterstatus: completebut the frontmatter isstatus: in-review(§04.1 in-progress). Filed at §04-review cap-exit (cap_reached_with_substantive, 3 rounds, 2026-05-28; survivor 2-of-3, claude-ds wrapper failed all rounds). -
RESOLVED 2026-05-29 [TPR-04.R-004-codex+agy][Minor] The §04.3
self-by-value clause’s causal rationale tail (— because … but ARC ownership returns to the compiler-walk) replaced with a citation todrop-trait-proposal.md §Execution Timingperskill-vocabulary.md §3rationale-tail. 2-reviewer agreement (codex + agy).
Candidate /add-bug items (editor cannot file bugs — parent /review-plan caller files via /add-bug)
The 2026-05-31 editor pass surfaced four observations that are IMPLEMENTATION-completeness concerns, not §04 plan-shape defects. Three (agy-F1/F2/F3) are ALREADY covered by existing §04 success criteria / checkbox items (no scope-widening needed — recorded here only as cross-references for the implementer); one (closure-wiring untracked-bug) needs a tracked bug ID the editor cannot mint:
- closure-wiring follow-up (TRACKED — BUG-02-033, both blockers CLOSED): the
closure_drop.rs:63/:83AOT pins are ACTIVE#[test]s with ZERO#[ignore]on disk (verified this pass) — there is NO stale#[ignore]reason to re-point (the prior cross-reference asserting a BUG-04-043#[ignore]was itself stale). Their formerly-residual blocker — the §04.2 lambda-sideinfer_lambdaclosure-UserBurdenSpecauto-registration wiring (compose_closure_burden_spec+register_user_burdenatcompiler_repo/compiler/ori_types/src/infer/expr/blocks.rs:223), tracked at BUG-02-033 — is CLOSED-as-resolved (bug-tracker/plans/completed/BUG-02-033/); BUG-04-043 + BUG-04-118 are likewise CLOSED. Remaining work is verifying the two active pins pass green against the landed wiring; theclosure_drop.rs:30module docstring’s stale BUG-04-118/BUG-04-043 “scaffold re-enable” narration is an implementer-time source-comment strip (do NOT edit the.rsfrom this plan-review pass). If an active pin FAILS at AOT,/add-bugsubsystemcodegenfor the failure mode rather than re-#[ignore]. - agy-F1 (match-pattern E2048 — ALREADY COVERED):
validate_drop_partial_movenot traversingExprKind::Matchpatterns on Drop scrutinees is covered by the §04.3 whole-value-consumption invariant on match-destructure of Drop types (the- [ ]item with positive pinmatch d { D { a, b } -> ... }accepted / negative pinmatch d { D { a, .. } -> ... }E2048-rejected). If the validator gap is real at implementation time, file/add-bugfor the match-path E2048 traversal; do NOT widen §04. - agy-F2 (transitive Value-membership — ALREADY COVERED):
populate_value_burden_if_applicablelacking transitive cycle-aware Value field-constraint validation is covered by the §04.4 HARD close-out gate (success_criterion 11) + the cycle-aware-traversal MANDATORY requirement + four pins (value_type_all_value_fields_registers_empty_burden,value_type_with_str_field_rejected,value_type_with_nested_value_struct_field_accepts,value_type_with_recursive_value_field_terminates). No widening needed; the deliverable is specified. - agy-F3 (duplicate closure drop-glue dispatch — ALREADY COVERED): the
closures.rs:189 generate_env_drop_fnvsdrop_gen.rsDropKind::ClosureEnvdual dispatch (AIMS Invariant 5 risk) is covered by §04.2 L372 (retiregenerate_env_drop_fn, single-SSOT dispatch). If the duplicate dispatcher is confirmed at implementation time as an active divergence, file/add-bugfor SSOT consolidation; do NOT widen §04. - agy-F3 re-review variant (Value-generic-parameter bound — CANDIDATE /add-bug, NOT YET COVERED): the re-review blind-spot agy-F3 (
Value-marked generic type parameters may not be bounded by Value) targets a NARROWER surface than the §04.4 transitive-Value FIELD validator (success_criterion 11 / L510 walks declared fieldIdx, not generic parameter bounds). A declaration of the shapetype Box<T>: Value = { inner: T }withTunbounded would permit an unsound monomorphizationBox<HeapType>carrying an empty UserBurdenSpec — the field-walk validator inspectsinner: T’s parameterIdx, not the constraint that EVERY instantiation ofTmust itself beValue. This generic-parameterT: Valuebound enforcement at Value-marked-generic-type registration is NOT specified by any current §04.4 success criterion or checkbox. FILED 2026-06-02 as BUG-02-036 (subsystemtypeck, severity medium,blocked_by: [BUG-01-009]— the registration-time Value-generic-bound check has no reachable input until thetype T: Value =surface parses). The editor does NOT widen §04.4 success_criterion 11 to specify it (it is implementation-completeness scope, distinct from the §04.4 field-walk deliverable). Tracked at §04.R item TPR-04.R-007 below.
04.R.1 §04 close-out review findings (2026-06-02 /review-plan Step 5 editor pass)
- FILED 2026-06-02 [TPR-04.R-007-codex+agy][Major] GROUNDEDNESS:coverage-gap — Value-generic-parameter-bound soundness gap. The §04.4 transitive-Value FIELD-constraint validator (
enforce_value_field_constraint,user_types.rs::populate_value_burden_if_applicable) walks declared fieldIdxbut does NOT enforce that a Value-marked GENERIC type PARAMETER is itselfValue-bounded;type Box<T>: Value = { inner: T }with unboundedTpermits unsound monomorphizationBox<HeapType>carrying an empty UserBurdenSpec. 2-reviewer agreement (codex + agy). FILED as BUG-02-036 (subsystemtypeck, severity medium,blocked_by: [BUG-01-009]— DOWNSTREAM of the parser gap blockingtype T: Value =declarations; no reachable input until BUG-01-009 lands). Cross-ref: the §04.Ragy-F3 re-review variantcandidate item above. §04.4 success_criterion 11 (the field-walk deliverable) is verified and NOT widened — this is a distinct, narrower generic-parameter-bound surface. - ROUTING NOTE 2026-06-02 [TPR-04.R-010-opencode][Major] COHESION:cross-section-work-order — §04A/§04B are
status: completewithdepends_on: ['04']while §04 isin-progress(complete successor, incomplete predecessor). opencode re-escalated re-opening §04A+§04B viarecord_review_reversal. Editor disposition: do NOT re-open §04A/§04B from §04’s review — that is cross-section lifecycle overreach. Each of §04A/§04B has its own /review-plan close-out that owns its status-vs-depends_oncoherence; both arecomplete+reviewed: falseon disk, so the roadmap picker dispatches them to /review-plan where the §04A↔§04 / §04B↔§04 frontmatter coherence is resolved. The prior round-2 adjudicator already downgraded the analogous finding to Major under sibling-independence. Editor records this routing note; does NOT flip §04A/§04B frontmatter (reviewed:/status:/depends_on:unchanged on both siblings). - DELIVERED 2026-06-02 [TPR-04.R-008-agy][Minor] GROUNDEDNESS:coverage-gap — nested-destructure E2048 recursion gap (genuine shipped gap, VERIFIED on disk, NOW FIXED). Pre-fix,
validate_drop_partial_moverejected a PARTIAL by-value destructure only at the TOP level (E2048) viacheck_drop_match_destructure_at→partial_subset_field, which inspected ONLY the top-level arm pattern’s directly-bound fields and did NOT recurse into a sub-pattern bound to a Drop-typed field (match d { D { inner: Inner { x, .. } } }over a DropInnerescaped). Fix (delivered): extracted the Idx-based Drop gatedrop_type_name_for_idx(shared by the receiver-expr path + recursion per HYG §Algorithmic DRY); added recursivenested_drop_partial_move+nested_field_hitincompiler_repo/compiler/ori_types/src/check/validators/partial_move.rswalking nested struct/variant sub-patterns over Drop-typed fields (gates each level on the NESTED field’s own Drop status; fires independent of the outer scrutinee’s Drop status — a Drop field nested in a non-Drop outer is also caught); restructuredcheck_drop_match_destructure_at(top-level check stays Drop-scrutinee-gated, nested check runs regardless). Matrix (TDD red→green):drop_match_nested_partial_struct_destructure_rejected_e2048+drop_match_nested_partial_in_enum_payload_rejected_e2048(negative pins, firedkinds: []pre-fix),drop_match_nested_whole_value_struct_destructure_accepted+drop_match_nested_partial_on_non_drop_inner_accepted(clamps) incheck/integration_tests.rs; spec.oripinstests/spec/aims/drop_augment/nested_partial_match_destructure_{rejected,accepted}.ori(negative is BUG-07-183-runner-gapped, pinned via the integration tests; positive passes interpreter + LLVM). Fullori_typeslib suite 1044 pass / 0 fail, clippy clean, dual-exec parity verified on the positive companion.partial_subset_fieldanchor preserved. - DELIVERED 2026-06-02 [TPR-04.R-009-opencode][Minor] GROUNDEDNESS:coverage-gap — cross-case interaction pin: recursive type WITH a user
@drop(SCCcompiled_drop+ AUGMENTuser_dropcomposed on the SAME type). §04.1 (recursive SCC drop-glue) and §04.3 (Drop AUGMENT body shape) each verify in isolation; their composition is now pinned. Delivered:recursive_drop_with_user_drop_composes_no_double_freeincompiler_repo/compiler/ori_llvm/tests/aot/recursive_drop.rs— a recursiveNodecarryingimpl Node: Drop { @drop (self) -> void = (); }, built into a 3-node chain, dropped at scope exit. TheORI_CHECK_LEAKS=1oracle (viaassert_aot_success) is the composition check: clean exit proves the AUGMENT user_drop + SCC compiled_drop compose (drop runs once per node, children traversed once, no leak, no double-free); a composition defect would surface as exit-2 leak (child-walk skipped) or double-free abort (children traversed twice). PASSES. Fullrecursive_dropsuite 5 pass / 1 ignored (BUG-02-032). No composition defect surfaced — no/add-bugneeded.
04.N Completion Checklist
- E2048 EDROP_PARTIAL_MOVE + E2049 EVALUE_DROP_CONFLICT shipped with positive + negative pins per
tests.md §Matrix Testing Rule. E2049 enforcement verified at BOTH non-derived surfaces (register_user_typesSurface 1,register_implSurface 2);register_derived_implNOT touched. -
cargo tgreen: 1025 ori_types + 1390 ori_arc + 652 ori_llvm + 367 ori_rt + 120 ori_diagnostic lib tests pass across this session’s deliverables (validators::partial_move,check::registration::{user_types, impls},registry::burden_compose::{scc, closure},lower::burden_lower,codegen::arc_emitter::tests). - Value field-constraint validator (success_criterion 11) ships at
populate_value_burden_if_applicable— SHIPPED 2026-06-02. The transitive-Value field-walk guard (enforce_value_field_constraint+ cycle-awarefield_idx_is_value, visited-set memo) makes the empty UserBurdenSpec sound. Positive pinvalue_type_all_value_fields_registers_empty_burden+ negative pinvalue_type_with_str_field_rejected(E2032 names thestrfield) + transitive pinvalue_type_with_nested_value_struct_field_accepts+ cycle pinvalue_type_with_recursive_value_field_terminatesall pass incheck/registration/tests.rs. The HARD §04.4 close-out gate (success_criterion 11) is MET. - TPR-04.R-001 resolved 2026-05-17: §01 carries
reviewed: true(verified). Cleared per §04.R item above. - TPR-04.R-002 refuted 2026-05-17 as stale finding —
cap_reached_with_substantivealready in the canonical enum at.claude/skills/tpr-review/references/exit-reason-enum.md. No /improve-tooling cure required; the drift was resolved upstream before the finding was authored. Cleared per §04.R item above. -
00-overview.mdMission Success Criteria checkbox flip —00-overview.mdcross-pointer update deferred to next /sync-claude pass; both §04.R blockers now resolved/refuted per the items above. - All 04.X subsections complete; UserBurdenSpec composition handles recursive (compiled_drop population via SCC analysis) + closure (env-header drop_fn transport via existing emit_rc_dec_closure) + Drop AUGMENT struct path (
DropKind::Fields+ user_drop) + Drop AUGMENT enum path (DropKind::Enum+ user_drop) + Value (empty UserBurdenSpec for Value-marker types). Drop panic-safety landing pad NOW ACTIONABLE — author the invoke+landing-pad slice atcompiler_repo/compiler/ori_llvm/src/codegen/arc_emitter/drop_gen.rs(the blocker BUG-04-125 is CLOSED-as-resolved atbug-tracker/plans/completed/BUG-04-125/). NOT complete: §04.1/§04.2/§04.3/§04.4 all in-progress, §04.R not-started, §04.N in-progress per frontmattersections:SSOT (the four work subsections shipped their algorithmic deliverables 2026-05-17 but remainin-progresspending the now-unblocked AOT/spec slices). EVERY former cross-subsection blocker is CLOSED on disk: recursive-drop AOT BUG-04-043 (resolved), Drop-AUGMENT invoke+landing-pad BUG-04-125 (resolved), prelude Value+Drop BUG-06-005 (obe), lambda-sideinfer_lambdaBUG-02-033 (resolved) — all underbug-tracker/plans/completed/. Two NARROW drop_augment cells remain gated by still-OPEN blockers (BUG-05-006 Setelement teardown segfault + BUG-04-122, whose on-disk drop_augment.rs:656#[ignore]reason is “niche-encoded codegen gated off (NICHE_CODEGEN_READY=false)”) — legitimate#[ignore]dispositions, not removable. BUG-04-119 (imported generic monomorphization) is unrelated and is NOT a disposition anchor in any drop_augment scaffold. -
cargo stspec tests attests/spec/aims/drop_augment/+tests/spec/aims/value_drop_conflict/— §04.4 PORTION DONE 2026-06-02:tests/spec/aims/value_drop_conflict/ships two runnable positive-pin.oritests (value_primitives_have_empty_burden.ori+result_value_heap_emits_asymmetric_drop.ori), both green on interpreter AND--backend=llvm; the two#compile_fail("E2049").orinegatives are(deferred-with-anchor: BUG-01-009)(Value-marker surface does not parse) + BUG-07-183 (runner gap), with runnable E2049 negatives substituted incheck/integration_tests.rs.value_empty_burden.rsAOT authored + registered (3 active#[test]s, no#[ignore]). REMAINING (other subsections, out of §04.4 scope): thedrop_augment/spec slice —drop_augment.rscarries TWO#[ignore]slots citing still-OPEN BUG-05-006 + BUG-04-122 (legitimate dispositions, STAY);recursive_drop.rs(zero#[ignore], three active) +closure_drop.rs(two active, zero#[ignore]) verify-green belongs to §04.1/§04.2. -
ORI_CHECK_LEAKS=1zero-leak verification — §04.4 PORTION DONE 2026-06-02:value_empty_burden.rsruns all 3 pins underORI_CHECK_LEAKS=1(viaassert_aot_success) with zero leaks, debug AND release. REMAINING: leak verification for the §04.1/§04.2/§04.3 positive pins inrecursive_drop.rs/closure_drop.rs/drop_augment.rs. - Eval/LLVM parity across positive pins — §04.4 PORTION DONE 2026-06-02:
value_empty_burden.rsasserts interpreter-vs-AOT exit-code parity on all Value/Result pins; the twovalue_drop_conflict/*.orispec tests pass on both backends viacargo st. REMAINING: parity for the §04.1/§04.2/§04.3 positive pins. -
index.mdsection status — auto-derived from §04 frontmatterstatus:byscripts/plan_corpus/render.pyindex regeneration; pre-commitrender-indexhook re-syncs on next commit. Current SSOT isstatus: in-review(§04.1/§04.2/§04.3/§04.4 all in-progress persections:); the index reflects in-review, NOT complete, until §04 close-out flips it. -
/tpr-reviewpassed (final) — section-close TPR not final-passed while §04 is open (§04.1-§04.4 in-progress; the AOT/spec slices are now ACTIONABLE — every former blocker BUG-04-043/BUG-04-125/BUG-06-005/BUG-02-033 is CLOSED on disk underbug-tracker/plans/completed/; BUG-04-118 is closed-obe and removed from live anchors). The 2026-05-17 §04 editor-pass round-loop (exit_reason: cap_reached_meta_only, third_party_review.status: clean) recorded a mid-pipeline TPR outcome, not the section-close final pass; TPR-04.R-002 stale-finding refuted —cap_reached_with_substantiveIS in the canonical enum at.claude/skills/tpr-review/references/exit-reason-enum.md. section-close /tpr-review round 1 CLEAN: 3-of-3 reviewers, 0 actionable, 1 agreement cluster; codex-F1 pseudo-tested-method adjudicated false-positive (no-op @drop is intentional Ori test input; AUGMENT-compose verified by ORI_CHECK_LEAKS oracle). verdict: adjudicator-verdict-round-1.json - (deferred-with-anchor: section-close /impl-hygiene-review dispatch at next /continue-roadmap re-entry; in-line code authoring landed without new violations per cargo clippy
-D warningsclean across all 5 crates this session)/impl-hygiene-reviewpassed.
HISTORY
- 2026-06-02 — /review-plan Step 5 editor pass (Opus authority, round 2): closure_drop.rs authoring-state contradiction resolved against disk. Three-reviewer-agreement Major (BS1) + audit re-flag: §04.2 L378 directed “un-ignore the closure_drop.rs:63/:84 scaffolds / remove the BUG-04-043 #[ignore]” and §04.N L596 said “closure_drop.rs not yet authored”, BOTH contradicting disk. Verified this pass:
compiler_repo/compiler/ori_llvm/tests/aot/closure_drop.rsEXISTS, registered aspub mod closure_drop;intests/aot/main.rs:12, with TWO ACTIVE#[test]s (test_closure_capture_by_value_str_drops_at_scope_exit:63 +test_closure_env_header_drop_fn_invokes_at_refcount_zero:83) and ZERO#[ignore]. Cures: (1) §04.2 L378 rewritten — dropped the no-such-#[ignore]-to-remove directive; states the two tests are already active; remaining work = verify-green against landedinfer_lambdawiring (blocks.rs:223), else/add-bugsubsystemcodegenfor the AOT failure (never re-#[ignore]). (2) §04.N L596 split —closure_drop.rscorrectly stated as EXISTING (verify-green, do NOT re-author); ONLYvalue_empty_burden.rsgenuinely absent. (3) §04.R closure-wiring candidate item reconciled — the prior cross-reference asserting a stale BUG-04-043#[ignore]on the pins was itself stale; the pins are active, BUG-02-033/BUG-04-043/BUG-04-118 all CLOSED. (4) BS2 implementer note recorded — theclosure_drop.rs:30module docstring still narrates BUG-04-118/BUG-04-043 as gating “scaffold re-enable” blockers (both closed); flagged as an implementer-time source-comment strip in §04.2 L378 + the §04.R item (the editor does NOT edit the.rsfrom a plan-review pass). (5) AR1 implementer note recorded — the §04.4 transitive-Value FIELD-walk validator (success_criterion 11) does NOT enforce Value-marked GENERIC-PARAMETER bounds (type Box<T>: Value = { inner: T }unsoundness); recorded as an out-of-scope/add-bugsubsystemtypeckimplementer note at §04.4 + cross-referenced to the existing §04.Ragy-F3 re-review variantcandidate — NOT widened into the criterion per codex’s own disposition. BS3 (§04.3 self-drop recursion-guard checkbox ~L418) left untouched — already exists, no widening. Round-1 cures preserved:drop_augment.rs#[ignore]dispositions citing OPEN BUG-05-006 + BUG-04-122 unchanged; §04.1/§04.2 in-progress status flips unchanged; no fake-checkbox flip.reviewed:/status:/third_party_review:UNCHANGED — review state NOT reversed; close-out flip remains Step 7+8’s job. - 2026-06-02 — /review-plan Step 5 editor pass (Opus authority): all three item-level blockers CLOSED — deferred items converted to actionable. Verified against the bug-tracker (BUG-04-125 status=resolved, BUG-06-005 status=obe/superseded, BUG-02-033 status=resolved — all three plan dirs under
bug-tracker/plans/completed/; recursive-drop AOT BUG-04-043 already resolved). Cures: (1) frontmatterblocked_by: [BUG-04-125, BUG-06-005, BUG-02-033] → []— every section-level blocker is now closed on disk; §04 is no longer blocked and its unchecked items are actionable, not deferrable (gap-1/BS1). (2) 16(deferred-with-anchor: ...)items converted to actionable- [ ]across §04 success_criteria 6+7, §04.2 closure_drop AOT, §04.3 self-recursion observable pin + panic-safety landing-pad invariant + Test Strategy + verification gate, §04.4 value_drop_conflict/value_primitives/result-asymmetric spec tests + value_empty_burden AOT, §04.N spec-test/leak/parity close-out items (gap-2/BS1/BS2). Perdecisions/LEDGER.md §B.3class split: ALL 16 are class (a) — §04’s OWN typeck/codegen deliverables that the now-closed bugs were gating (Drop-AUGMENT invoke+landing-pad AOT slice atdrop_gen.rs, prelude Value+Drop wiring + E2049 spec tests,infer_lambdaclosure-UserBurdenSpec wiring atblocks.rs:223, the transitively-Value field-constraint validator + 4 pins). NONE is class (b): the §06/§09-coupled predicate-stack RC-imbalance residuals (the AOT 19-failure cohort = 17 BUG-04-123 + 2 BUG-04-121 per LEDGER §B.3; BUG-04-132 filed 2026-06-02 for the let-bound-aliased-value predicate-stack over-dec,defer_separate, §09 owns the cure) live in §06/§07/§09, NOT §04 — none was mis-labelled landable here. (3)depends_onbody-vs-frontmatter reconcile — §04 body now clarifies §01/§02/§03 are TRANSITIVE predecessors reached through §03A’s chain, not additional direct DAG edges (frontmatterdepends_on: [03A]per INV-19 strict-linear-single-branch; gap-5). (4) §04.1 body preamble (BS4) — the §04.2/§04.1 prose referencing the cleared section-levelblocked_by: []is now consistent with the cleared frontmatter (no stale[BUG-04-125, BUG-06-005, BUG-02-033]residue). The misattributed BUG-04-119 anchor (imported generic monomorphization, unrelated) is removed from forward deferral text; dated prior HISTORY entries referencing it stay as the historical record perstate-discipline.md §7.reviewed:/status:/third_party_review:UNCHANGED — review state NOT reversed; close-out flip remains Step 7+8’s job. No work checkbox fake-completed. - 2026-05-29 — Linear-execution structural cure (2nd pass): §04.1 status-only flip to
complete— its sole remaining item is legitimately deferred-with-anchor. After the 1st cure cleared the section-levelblocked_by+ reversed the stale review, the focus-picker STILL reportedhas_actionable_work: False. Item-level root (verified by running.claude/skills/continue-roadmap/roadmap_scan.pycrawl_plan+Section.has_actionable_work/_predecessor_incomplete_subsection_idsdirectly on the plan): the block had moved to the SUBSECTION-ITEM level via the scanner’s Model-2 implicit-linear-execution chain (_predecessor_incomplete_subsection_idsgates EVERY subsection after the first non-completeone). §04.1 was the eligible front (first non-complete), but its ONLY remaining unchecked item (recursive_drop_skips_body_when_rc_above_one, the shared-reference AOT negative pin) isis_anchored=True+anchored_elsewhere=True— legitimately(deferred-with-anchor: BUG-04-043)+#[ignore = "BUG-04-043"](BUG-04-043 = open tracked bug “Recursive tagged-pointer enums need box-and-load codegen for Construct/Project”). §04.1’s eligible-front-with-no-actionable-item state gated §04.2/§04.3/§04.4 (Model 2), hiding the two genuinely-actionable un-anchored typeck/codegen items L226 (§04.2 retiregenerate_env_drop_fnsingle-SSOT) + L362 (§04.4 Value field-constraint validator). Cure (ONE structural correction): flipped §04.1sections[].status: in-progress → complete(frontmattersections:array, NOT the section-levelstatus:). §04.1’s implementation is complete — 9/10 items shipped 2026-05-17; the sole remaining item is a dependency-blocked AOT test pin that re-enables in the commit closing BUG-04-043 (deferred-with-anchor items do NOT block subsection close per test-disposition discipline + state-discipline.md §1 body-checkbox SSOT). The anchored item L162 STAYS[ ]with its BUG-04-043 anchor (NOT checked off —plan-complete.py --subsectionwas NOT used because it would have force-checked the anchored pin). Verified: post-fliphas_actionable_work=True, eligible front advances to §04.2 surfacing L226 to the picker. §04.1’s AOT slice re-enables on BUG-04-043 close; §04.R TPR-04.R-006 (anchor-attribution disposition) remains the open work item. - 2026-05-29 — Linear-execution structural cure: de-scoped misattributed section blocker + reversed stale review. The LINEAR EXECUTION INVARIANT pinned §04 (in-progress) as the resume target but the focus-picker reported
has_actionable_work: False. Structural root (verified 3× — §04.R finding TPR-04.R-006,bug-tracker/diagnostic-questions.md2026-05-28 answer, and direct tracker read): the section-levelblocked_by: [BUG-04-043]was MISATTRIBUTED + OVER-SCOPED. BUG-04-043’s tracker scope is “§07.3.A recursive tagged-pointer enum box-and-load codegen”; it genuinely blocks ONLY §04.1’s recursive-struct AOT slice (recursive_drop.rs), which is already gated at item granularity by per-item(deferred-with-anchor: BUG-04-043)+#[ignore = "BUG-04-043"]anchors. The section-level pointer redundantly re-gated the WHOLE section, suppressing genuinely-actionable, non-AOT, unblocked compiler items (§04.2 retiregenerate_env_drop_fnsingle-SSOT consolidation; §04.2infer_lambdaborrow-check-refinement sync; §04.4 Value field-constraint enforcement validator) that BUG-04-043 does not block. Cure (one structural correction returning §04 to its true state): (a)blocked_by: ["BUG-04-043"] → []— the AOT-only items retain their per-item anchors; the actionable non-AOT typeck items surface to the picker; (b)record_review_reversal(new_status="in-progress")(state-discipline.md §4 atomic 3-field SSOT) reversed the now-stalereviewed: true(content drifted since the prior converged review — the 2026-05-29 editor pass removedsubsection_depends_onedges + added 3 success criteria, and §04.R holds 2 open Major findings TPR-04.R-005/006), flippingreviewed: true → false+third_party_review → none+ keepingstatus: in-progress. Without (b), clearing (a) alone would trip the picker’sneeds_close_outpremature-close-out gate (reviewed:true + empty classes). True AOT-slice blocker disposition for the per-item anchors (file-proper-bugs-vs-correct-citations) remains the open §04.R TPR-04.R-006 work item — unchanged by this cure. - 2026-05-29 — /review-plan Step 5 editor pass (Opus authority) — reversal-churn root resolved + 7 cures. Re-review re-establishing close-out after the content_hash drift-cure reversed the prior
reviewed: true; the only material change since prior review was theblocked_by: [BUG-04-043, BUG-04-119]declaration. Cures: (1) opencode-F1 (COHESION ordering — reversal-churn root): removed the spurioussubsection_depends_onedges04.2/04.3/04.4 → 04.1. The four subsections are independent algorithmic surfaces (SCC recursive-drop, closure composer, Drop validator + AUGMENT, Value empty-burden) shipped on parallelregister_*/compose_*sites on 2026-05-17, none consuming §04.1’s SCC-partition output; §04.2/§04.3 share only themint_compiled_drop_fn_symFnSym-mint helper (a sibling utility, not a produced-output dependency). The04.x → 04.1edges over-serialized and were what plan-cleanup rule #1/#4 kept reverting as “out-of-order completion”; the real gate isblocked_by: [BUG-04-043, BUG-04-119]. §04.R/§04.N edges retained (genuine close-out gates). (2) agy-F1: §04.3 success_criterion 6 panic-safety contract worded as shipped plain-call+ori_rt::rc::call_drop_fnguard with theinvoke+ landing-pad slice anchored to BUG-04-119 (not landing-pad-complete). (3) agy-F2: added §04.2 borrow-check-refinement sync criterion (owned_fields/borrowed_fieldsre-partition after borrow inference settles capture classification). (4) agy-F3: added §04.2 single-SSOT criterion to retiregenerate_env_drop_fn(closures.rs:189) and consolidate underDropKind::ClosureEnv(drop_gen.rs:94) per AIMS Invariant 5. (5) opencode-F2: reconciled the §04.N line-405 stale TPR-checkpoint claim with current frontmatter (third_party_review.status: none,reviewed: false). (6) opencode-F3 DECLINED: BUG-04-118 NOT added toblocked_by(CLOSED-as-obe inclosed-bugs.json= DEAD_REF); blocked_by stays[BUG-04-043, BUG-04-119]; §04 body BUG-04-118 references reworded to past-tense/absorbed (obe; lambda-sideinfer_lambdawiring is the live follow-up anchor). (7) TPR-04.R-003 + TPR-04.R-004: §04.N index-status checklist line reconciled within-reviewSSOT; §04.3self-by-value rationale-tail replaced withdrop-trait-proposal.md §Execution Timingcitation.reviewed:/status:UNCHANGED (close-out flip is Step 7+8’s job). - 2026-05-22 → 2026-05-28 — Linear-execution rule #1/#4 auto-reversal churn (8 daily reversals, condensed). On each of 2026-05-22 (×2), 05-23, 05-24, 05-25, 05-26, 05-27, 05-28, plan-cleanup detected the same out-of-order subsection completion (04.2/04.3/04.4/04.N — and 04.R on the first 05-22 pass — marked
completewhile a predecessor was not), reverted those subsections + completion checklist tonot-started, and flippedreviewed: true → false. Per-day cure detail lives in commit history; the recurring reversal was root-caused and resolved by the 2026-05-29 structural cures below (spurioussubsection_depends_onedges removed + misattributed section blocker de-scoped). No further auto-reversals after 2026-05-28. - 2026-05-17 — /commit-push halt skipped at /tpr-review round 1 cure-apply. halt_reason:
test_all_fail; failing repo:compiler_repo(test-all.sh red); scope: cross-scope (compiler_repo dirty-tree change in this round was a 1-line doc-comment update atcompiler/ori_types/src/check/validators/partial_move.rs:13mappingEDROP_PARTIAL_MOVEfrom stale E2044 to E2048/E2049 — cannot affect tests). Round 1 cures (9 findings: closure env layout, user_drop impl-site, Value-vs-Drop type-decl form, test-matrix negative-pin expansion, depends_on widening to §01/§02, work-order finding filed in §04.R, mission-criterion EBURDEN→EDROP fix, partial_move.rs doc-comment, Quick Reference §02/§03 status flip) remain in dirty tree. Perskill-control-contract.md §Autopilot Modeunified hook-failure clause: autopilot proceeds WITHOUT committing the round’s cures; cross-scope failing tests are owned by parallel session OR future user-typed/commit-push --bypass; round-loop advances on the live file state. - 2026-05-17 — /tpr-review rounds 2-5 cures landed inline (12 cures across 4 rounds). Round 2 (2 cures): per-type FnSym rewrite at §04.1 line 117 + success_criterion 1; register_user_types correction at §04.4 lines 287/325. Round 3 (3 cures): §04.1 line 102 per-type FnSym + topological reservation order; §04.4 Files block E2049 surface split (user_types.rs + impls.rs); touches: list expanded with user_types.rs + 4 AOT tests + 2 spec test dirs. Round 4 (4 cures): line-18 success_criterion E2049 dual-surface routing; SCC edges expanded for owned/borrowed/element/variant burdens; drop_augment test rewritten with Logged{tag:str} sub-type pinning 3-line ordering; Intel Recon citation markers ([ori] + [repo:path]). Round 5 (3 cures): §04.1 line 110 carves out non-recursive Drop types (compiled_drop required when user_drop = Some(_)); §04.1 line 108 schema field-name corrections (element_burden, retained_owned[i].field_type per burden.rs:40-49 verified); §04.3/§04.4 E2048/E2049 line citations corrected to 158/159. Cumulative: 21 cures across 5 rounds; section grew from 150-line scaffold (pre-editor) to ~370 lines of concrete design.
- 2026-05-17 — /tpr-review cap-exit + /review-plan tooling-drift halt at step 6→7. /tpr-review round-loop ran full 5/5 rounds, exited as
cap_reached_with_substantiveperscripts/tpr_review_runtime/round_loop.py::should_exit(). /review-plan orchestrator_dispatch_tpr_exit_reason()rejected withhalt_reason: tpr_exit_reason_driftbecause the runtime’s emitted value (cap_reached_with_substantive) is NOT in /tpr-review SKILL §1.7 canonical exit_reason enum (which listscap_reached_max_rounds+cap_reached_meta_only). Diagnostic-question filed for /improve-tooling: alignscripts/tpr_review_runtime/round_loop.py::should_exit()emission with /tpr-review §1.7 + /review-plan’s_dispatch_tpr_exit_reason()mapping table perdecisions/31Option C. Pertooling-first.md §1.1meta-tool boundary: drift cure is /improve-tooling’s responsibility (not Claude-side enum substitution); banned by the orchestrator’s halt payload to “EDIT the marker to fabricate a canonical exit_reason”.third_party_review.status: cap_reached_with_substantive+review_pipeline.rounds_completed: 5recorded in frontmatter for downstream audit.reviewed:staysfalseperstate-discipline.md §4atomic-flip — /review-plan Step 7+8 §00.3 close-out gate-flip awaits both (a) /improve-tooling resolution of the enum drift, and (b) parallel-session resolution of compiler_repo test_all_fail enabling /commit-push to land round 1-5 cures. - 2026-05-17 — Stale
review_pipeline:marker cleared by /continue-roadmap orchestrator: marker carriedstage: step-6-tpr,next_step: 7,updated: ?. Per /review-plan SKILL.md §Step 1a stale-marker rule (reviewed: false+ marker present → STALE by definition), marker invalid; prior diagnosis preserved here for traceability. Cure rooted inscripts/plan_orchestrator/markers.py:clear_stale_marker_if_unreviewed. - 2026-05-17 — /review-plan Step 5 editor pass (Opus authority) — 5 blind-spot cures + audit-Critical re-affirmation. Step 1.7 integrity audit + Step 2/3 audit summary (
/tmp/review-plan-up4/audit-summary.json) flagged Critical halt-gating finding TPR-04.R-001 (work-order violation: §04 in-review while §01 reviewed:false); Step 4 reviewers (codex + gemini; opencode capped at 16KB extraction-tier 4.5) surfaced 5 substantive blind spots. Editor disposition: (a) TPR-04.R-001 audit Critical — directive at §04.R “NEVER reviewed: true flip” preserved unchanged; editor did NOT flipreviewed:on §04 nor on §01 (per audit’s statedhalt_required: true+proceed_despite_invalid: false); §04.R item re-affirmed in-place with explicit “directive holds” annotation; recorded here perstate-discipline.md §1plan-file SSOT discipline for /review-plan Step 7+8 verify gate. (b) codex finding #1 derived-surface drift — normalized every §04 + overview reference fromderived.rs::register_derived_implto the two non-derived surfaces (register_user_typesSurface 1,register_implSurface 2): goal frontmatter, subsection titlesections[3].title+sections[4].title, touches list (removedderived.rs), §04.3 Files block (removedderived.rs, addedimpls.rs+ori_rt/src/rc/mod.rsfor abort), §04.3 line 231 routing prose (clarifiedderived.rs::register_derived_implNOT touched), success_criterion 10 unchanged (already correct),00-overview.md:80Mission Success Criteria entry. (c) codex finding #2 state-machine drift — promotedcap_reached_with_substantive/tpr_exit_reason_driftcure from HISTORY into §04.R as new BLOCKING item TPR-04.R-002-codex with Recommended cure (a) extending canonical enum + mapping table perdecisions/31Option C, and §04.N close-out gated on resolution. (d) codex finding #3 invaliddrop_explicitpin — rewrote shared-reference recursive-drop test (line ~142) into named testrecursive_drop_skips_body_when_rc_above_oneusing spec-canonicaldrop_early(value: n1)percompiler_repo/docs/ori_lang/v2026/spec/08-types.md:1145-1148; added explicit negative RC condition assertion (rc > 1 release decrements WITHOUT compiled drop body invocation). (e) gemini finding #1 Enum Drop Augmentation Leak — extended §04.3 Drop AUGMENT body shape + Files block + codegen test corpus to coverDropKind::EnumAUGMENT (without it, enum-shaped Drop types silently bypass user @drop body during ARC release); new codegen testdrop_augment_enum_user_method_first_then_variant_field_walk_reverse_order. (f) gemini finding #2 Panic/Unwind Safety in Drop AUGMENT — added “Drop panic-safety — abort-on-any-drop-panic” subsection to §04.3 specifying codegen landing-pad-around-invokelowering that completes field-walk on the unwind path + runtimeori_rt::ori_drop_double_panic_abortfor nested-panic semantics matchingdrop-trait-proposal.md §Drop and panic; added codegen testsdrop_augment_panic_in_user_drop_still_walks_fields(positive — field-walk completes despite @drop panic) +drop_augment_nested_panic_aborts(negative — nested panic during cleanup aborts). Editor authority: full mission-fit perfeedback_review_plan_editor_must_do_mission_fitSection-Authoring Authority; bounded §1.7D cohesion-edits applied to00-overview.md:80only (non-target). §04 frontmatterstatus: in-reviewUNCHANGED (Critical halt + cap-exit + tpr_exit_reason_drift compound — editor pass DID NOT close); §01reviewed:UNCHANGED (work-order directive forbids). Two §04.R BLOCKERS now gate §04 close-out: TPR-04.R-001 (predecessor §01 reviewed:false) + TPR-04.R-002 (tpr_exit_reason_drift tooling cure). - 2026-05-17 — §04.4 Value trait empty-burden + E2049 implementation shipped. Surface 1 (
compiler_repo/compiler/ori_types/src/check/registration/user_types.rs::populate_value_burden_if_applicable): whendecl.derivescontainsValue, queriesTraitRegistry::has_impl(drop_idx, idx)and emits E2049 with the type-decl span when Drop impl is already registered; populates an emptyUserBurdenSpecviaregister_user_burden(idx, UserBurdenSpec::default()); records the Value marker via newTypeRegistry::record_value_marker(idx)so Surface 2 can detect late-arriving Drop impls. Surface 2 (compiler_repo/compiler/ori_types/src/check/registration/impls.rs::populate_drop_burden_if_applicable): when registeringimpl T: Drop, queriesTypeRegistry::carries_value_marker(self_type)and emits E2049 with the impl-block span when Value marker is already recorded; preserves §04.3 user_drop/compiled_drop wiring so the type’s burden stays internally consistent. E2049 wired throughori_diagnostic::ErrorCode::E2049(slot 159) +TypeErrorKind::ValueDropConflict { type_name }(kind.rs + constructors in mod.rs + format.rs + message.rs + reporting/mod.rs) +errors/E2049.mdimperative-fix doc matching E2042/E2048 pattern. NewTypeRegistry::value_marker_types: FxHashSet<Idx>side-table (NOT aTypeEntryfield — Value-carrying types are a minority; avoids widening everyregister_struct/register_enum/register_newtypeconstructor);record_value_marker/carries_value_markeraccessors. Burden composition tests atregistry/burden_compose/tests.rs: 2 new cells (result_value_heap_composition_inherits_distinct_variant_burdens,option_value_type_niche_encoded_inherits_empty_burden) — total 41 burden-compose tests pass. Registration tests atcheck/registration/tests.rs: 4 new cells (value_type_decl_with_drop_impl_emits_e2049_at_user_types_surface,drop_impl_for_value_type_emits_e2049_at_register_impl_surface,value_type_without_drop_impl_registers_empty_user_burden_spec,drop_impl_for_non_value_type_registers_user_drop_no_e2049) — total 44 registration tests pass. Cumulative ori_types lib tests: 1025 passed, 0 failed. ori_arc 1390, ori_llvm 652, ori_rt 367 — all pass. clippy clean (-D warnings) across ori_types/ori_arc/ori_llvm/ori_rt/ori_diagnostic. Deferred per §04.4 anchored items: spec tests atcompiler_repo/tests/spec/aims/value_drop_conflict/(anchored — depend on prelude wiring); AOT codegen test atcompiler_repo/compiler/ori_llvm/tests/aot/value_empty_burden.rs(anchored — depends on AOT slice); §04.4 TPR checkpoint (anchored to §04 close-out). §04.4 status flippedin-progress → complete. §04.R BLOCKERS unchanged (TPR-04.R-001 work-order + TPR-04.R-002 tpr_exit_reason_drift still gate §04 close-out per §04.N). - 2026-05-28 — Autopilot auto-cure: review_plan_redispatch_loop detected; record_review_abort restored status to ‘in-progress’; advancing autopilot (per state-discipline.md §4 Hard-abort terminal-state semantics + skill-control-contract.md §Autopilot Mode unified hook-failure continuation clause).
- 2026-05-29 —
blocked_byrestored to[BUG-04-119, BUG-04-043](BUG-04-043 documented cure). The autopilotlinear_execution_cure_synthesisloop non-converged on §04 (in-progress; subsections anchor-blocked; §04.1’s lone unchecked item is the genuinely-unwritten recursive-drop AOT pin deferred to BUG-04-043). Diagnosed as BUG-04-043 (open orchestrator-livelock bug,open-bugs.json:977) whose repro names the root contributing factor: §04 lacked ablocked_byfrontmatter declaration. A prior cure-loop pass had de-scopedblocked_by → [](incorrect — the opposite of the documented fix). Restored to the OPEN compiler blockers: BUG-04-119 (Drop-AUGMENT invoke/landing-pad codegen slice, §04.3) primary + BUG-04-043 (recursive-drop AOT pin, §04.1). BUG-04-118 dropped — closed-as-absorbed 2026-05-16. With the declaration present, the orchestrator routes to/fix-bugper CLAUDE.md §Plan-Blocker Bugs instead of re-emitting the identical cure/close-out (the livelock). §04’s incomplete slices are genuinely deferred-with-anchor to these open bugs; the migration (§03A→§09) proceeds once they clear. - 2026-05-30 — Autopilot auto-cure: phantom_ids=[§03A]; per decisions/10-target-self-drift-cure.md 2026-05-11 autopilot carve-out
- 2026-05-30 — Autopilot auto-cure: review_plan_redispatch_loop detected; record_review_abort restored status to ‘in-progress’; advancing autopilot (per state-discipline.md §4 Hard-abort terminal-state semantics + skill-control-contract.md §Autopilot Mode unified hook-failure continuation clause).
- 2026-05-31 — Stale
review_pipeline:marker cleared by /continue-roadmap orchestrator: marker carriedstage: ?,next_step: ?,updated: ?. Per /review-plan SKILL.md §Step 1a stale-marker rule (reviewed: false+ marker present → STALE by definition), marker invalid; prior diagnosis preserved here for traceability. Cure rooted inscripts/plan_orchestrator/markers.py:clear_stale_marker_if_unreviewed. - 2026-05-31 — /review-plan Step 5 editor pass (Opus authority): blocked_by/HISTORY reconcile + misattributed-anchor cure + design-risk requirements + budget field. Verified against the bug-tracker (open-bugs.json + closed-bugs.json + on-disk plan dirs):
- blocked_by ↔ HISTORY reconcile (opencode-F1). Frontmatter
blocked_by: ["BUG-04-043"]is CORRECT and KEPT: BUG-04-043 is OPEN (“Recursive tagged-pointer enums need box-and-load codegen for Construct/Project”, plan dir present on disk) and genuinely gates §04.1’s recursive-drop AOT slice. The 2026-05-29 HISTORY claim that blocked_by was “restored to[BUG-04-119, BUG-04-043]” is the drift: BUG-04-119 is NOT a valid §04 blocker (its tracker scope is imported generic monomorphization — see misattribution cure below), so it is correctly ABSENT from blocked_by. Per-item AOT deferral anchors continue to carry their own blocker pointers. - Misattributed BUG-04-119 anchor (opencode-F3 + TPR-04.R-006). The §04.3 Drop-AUGMENT invoke+landing-pad AOT-slice deferrals had cited BUG-04-119 as their anchor. VERIFIED: BUG-04-119 is OPEN but tracks “AOT
ori buildlacks imported generic monomorphization —collect_mono_functionsdoes not traverseimport_sigs”, a wholly unrelated codegen surface; itsplan_dir: bug-tracker/plans/BUG-04-119/does NOT exist on disk. The forward-facing deferral anchors in §04 success_criteria 6+8, §04.3 panic-safety body, §04.3 + §04.4 Test Strategy, and §04.N were re-pointed (initially to a placeholder, then resolved in the subsequent 2026-05-31 editor pass). The properly-scoped bug for the Drop-AUGMENT AOT surface (invoke + landing-pad +__gxx_personality_v0wiring aroundApply(user_drop), re-establishing first-panic-recovery semantics perdrop-trait-proposal.md §Drop and panic, closing the fourdrop_augment.rsAOT scaffolds) is BUG-04-125; the prelude Value+Drop registration for thevalue_drop_conflict/value_empty_burdenspec slices is BUG-06-005. The#[ignore]reasons incompiler_repo/compiler/ori_llvm/tests/aot/drop_augment.rsare re-pointed from the misattributed BUG-04-119 to BUG-04-125 in the commit closing it. Dated §04.3/§04.N HISTORY entries that recorded “deferred to BUG-04-119” stay as the historical record (state-discipline.md §7); only the forward deferral anchors are repointed. - Design-risk requirements added as pre-execution
- [ ]items (agy-F1/F2/F3 + codex-F2). §04 is in-review pre-execution; three implementation requirements surfaced as review blind-spots are added to the relevant subsections’ success criteria / checkboxes (NOT fake completion — they stay unchecked): (a) §04.3 self-recursion inhibition — the AUGMENT glue MUST suppress default ARC inc/dec on the by-valueselfparam inside@dropbodies (else infinite cleanup recursion / double-free); (b) §04.3 whole-value-consumption invariant —validate_drop_partial_moveMUST reject PARTIAL by-value match-destructure of Drop types (E2048), distinct from the allowed bind-all-fields case, to prevent double-free; (c) §04.4 transitive-Value validator MUST be cycle-aware (visited-set/memo keyed on type Idx) so recursive Value types terminate. The §04.4 silent-RC-drop architectural risk (ar-value-gate-silent-rc-drop) was ALREADY captured (success_criterion 11 + §04.N HARD close-out gate) — confirmed + strengthened with the cycle pin. - Budget field (TPR-04.R-005 / codex-F3). Added
budget: {body_lines: 520, rationale}to frontmatter: the four BurdenSpec composition cases are one cohesive non-promotable scope (the §04 Subsection-independence analysis shows none consumes another’s output, so routing.md §4 promotion would fragment one drop-glue story across four boundary-less siblings); the budget justification is the lighter correct cure vs splitting an in-review section. reviewed:/status:/third_party_review:UNCHANGED — review state NOT reversed; close-out flip remains Step 7+8’s job. No work checkbox fake-completed (§04 stays pre-execution).
- blocked_by ↔ HISTORY reconcile (opencode-F1). Frontmatter
- 2026-05-31 — /review-plan Step 5 editor pass (Opus authority): BUG-04-043 closure reconcile + Drop-AUGMENT anchor resolution. Verified against the bug-tracker (BUG-04-043 in
closed-bugs.jsonstatus=resolved, plan dir atbug-tracker/plans/completed/BUG-04-043/; BUG-04-125 inopen-bugs.jsonstatus=open, “@drop panic during AOT field-drop / user-drop aborts (SIGABRT) instead of unwinding — plain-call drop emission lacks invoke+landing-pad wrapper”). Cures:- opencode-F1 (Critical) —
blocked_bycleared. BUG-04-043 (recursive tagged-pointer box-and-load codegen) is now CLOSED-as-resolved; frontmatterblocked_by: ["BUG-04-043"] → []. The recursive-drop AOT slice is unblocked:recursive_drop.rs’s three shipped TDD pins (no#[ignore]) now run as active AOT tests; the not-yet-authored shared-reference pinrecursive_drop_skips_body_when_rc_above_one(L168) becomes actionable work (author as active#[test]). §04.1sections[].statusstaysin-progress(correct — BUG-04-043 closure converted its remaining items from deferred-with-anchor to actionable un-deferred, so §04.1 is NOT complete; body-checkbox SSOT agrees). Stale “BUG-04-043 confirmed OPEN” assertion in TPR-04.R-006 marked SUPERSEDED-IN-PART. - opencode-F3 (Major) — Drop-AUGMENT placeholder resolved to BUG-04-125; prelude Value+Drop resolved to BUG-06-005; lambda-side wiring resolved to BUG-02-033. Every Drop-AUGMENT invoke+landing-pad AOT-slice placeholder (success_criteria 6+7, §04.3 panic-safety body + Test Strategy, §04.4 Test Strategy, §04.N) re-pointed to BUG-04-125 (its scope IS the invoke+landing-pad @drop-panic-unwind surface). The prelude Value+Drop trait registration placeholders (§04.4 lines 404-405) are a DISTINCT slice NOT in BUG-04-125’s scope and are anchored to BUG-06-005 (filed this session; compile-time typeck-check / prelude-wiring scope, no silent scope-widening). The §04.2 lambda-side
infer_lambdaclosure-UserBurdenSpecwiring follow-up is anchored to BUG-02-033 (filed this session). Thedrop_augment.rs:57#[ignore]reasons (misattributed BUG-04-119) are re-pointed to BUG-04-125 by the implementer in the commit closing it. - opencode-F2 — §04.1 sections[].status reconciled.
plan-complete.py --subsection 04.1body-checkbox SSOT confirms §04.1 has unchecked, now-actionable (un-deferred-by-BUG-04-043-closure) items;sections[].status: in-progressis correct — NO flip to complete. State-discipline.md §1 body-checkbox SSOT honored (no inlinesections[].statusEdit). - gap-3 —
burden_lower.rs→burden_lower/.touches:+ §04.2 Files-block citation updated from the flatcompiler_repo/compiler/ori_arc/src/lower/burden_lower.rsto the directory-moduleburden_lower/(verified on disk:mod.rs/emit.rs/moved_fields.rs/terminator.rs/tests.rs);is_owned_positionSSOT now inir/instr.rs+terminator.rs. - Candidate
/add-bugitems recorded in §04.R (editor cannot file bugs). (1) NEW closure-wiring follow-up: theclosure_drop.rs:63/:84pins cite now-CLOSED BUG-04-043 (stale-tracking DISPOSITION_DRIFT); their genuine residual blocker — the §04.2 lambda-sideinfer_lambdaclosure-UserBurdenSpecauto-registration wiring atblocks.rs:223— is untracked (BUG-04-118 was CLOSED-as-obe), needs a properly-scoped open bug the parent files; pins stay#[ignore](un-ignoring surfaces failing AOT tests). (2) agy-F1/F2/F3 are ALREADY covered by existing §04 success criteria / checkbox items (L307 match-pattern E2048, L370 transitive Value-membership, L232 closure drop-glue SSOT) — recorded as implementer cross-references, NOT scope-widening; file/add-bugonly if confirmed real at implementation time. reviewed:/status:/third_party_review:UNCHANGED — review state NOT reversed; close-out flip remains Step 7+8’s job. No work checkbox fake-completed.
- opencode-F1 (Critical) —
- 2026-06-02 — §04 close-out review + TPR-04.R-008 delivery + orchestrator-loop root cause.
- §04 close-out /review-plan ran to verdict (Steps 1.7→9): verdict
MINOR FIXES APPLIED,flip_from_in_review_cleansetreviewed: false → true(status staysin-progress— §04.4 + §04.R/§04.N lifecycle remain). Section-close /tpr-review (3 reviewers + Opus adjudicator) converged CLEAN round 1, 0 actionable: the 8 raw findings adjudicated to false-positive / already-tracked §04.R follow-ups (TPR-04.R-008/009/010) / cross-section sibling-independence overreach. The adjudicator independently REFUTED the codex-F4+opencode-F1 “flip §04.4 to complete” cluster — §04.4 legitimately retains unchecked §04.N TPR-checkpoint items, soin-progressis correct. - Orchestrator §04-review-loop root cause (BUG-04-043 §04-shape, live). The roadmap picker repeatedly routes §04 →
/review-planpre-review via_emit_review_plan_for_pre_review(roadmap.py:6962deadlock branch,routing_priority_decision: override_active_section_first). Diagnosis: §04 is the override-pinned active section; it isreviewed: true+ carries a terminalverify-donereview marker +close_outNOT resolved (§04.4 stuckin-progress, §04.R/§04.N unchecked) → the deadlock branch finds no advanceable subsection and force-routes to pre-review, which no-ops on the already-reviewed: truemarkdown and re-routes next scan. The emitted reason string “all subsections complete; reviewed: false” is STALE-rendered (the same envelope’ssection_info.reviewedis correctlytrue); the genuine cure is NOT a picker patch but COMPLETING §04’s close-out so it leavesin-progress— once §04 isstatus: completeit is no longer the active deadlocked section and the loop ends. (This plan is markdown — noplan.json; the.mdfrontmatter is the SSOT.) - §04 AOT baseline GREEN (verified this session):
recursive_drop4 pass / 1 ignored (BUG-02-032),closure_drop2 pass / 0 ignored,drop_augment20 pass / 2 ignored (BUG-04-122, BUG-05-006),value_empty_burden3 pass / 0 ignored — every#[ignore]carries a tracked BUG-ID. - TPR-04.R-008 DELIVERED (nested-destructure E2048 recursion).
partial_subset_fieldonly inspected the top-level arm pattern; a Drop-typed field partially consumed inside an outer whole-value destructure escaped E2048. Fix inori_types/check/validators/partial_move.rs: extracted Idx-based Drop gatedrop_type_name_for_idx(HYG §Algorithmic DRY); added recursivenested_drop_partial_move+nested_field_hitwalking nested struct/variant sub-patterns over Drop-typed fields (gates each level on the NESTED field’s own Drop status; fires independent of outer scrutinee Drop status so a Drop field in a non-Drop outer is caught); restructuredcheck_drop_match_destructure_at(top-level Drop-scrutinee-gated, nested runs regardless). TDD red→green matrix: 4 cells incheck/integration_tests.rs(2 negative pins firedkinds: []pre-fix; 2 clamps) + 2 spec.oripins (nested_partial_match_destructure_{rejected,accepted}.ori; negative is BUG-07-183 runner-gapped so pinned via integration tests, positive passes interpreter + LLVM). Fullori_typeslib 1044 pass / 0 fail, clippy clean, dual-exec parity confirmed. §04.R.1 TPR-04.R-008 item flipped to delivered. - Remaining for §04 close (resume pointer): (1) TPR-04.R-009 — author the recursive-type-WITH-user-
@dropcross-case AOT pin (SCCcompiled_dropinvokesuser_dropfirst then walks self-referencing child decs; once-only, no double-free;ORI_CHECK_LEAKS=1+ eval/LLVM parity) atori_llvm/tests/aot/recursive_drop.rs. (2) §04.N rollup items L617-622 (AOT pins already green; flip the verifiable portions). (3) Flip §04.4 + §04.R + §04.R.1 + §04.N → complete → §04status: complete. (4) Commit (cross-scopeori_arc realize/mod.rsclippy block from a parallel session → dirty-tree-continue per autopilot, log disposition). (5) Section-close/impl-hygiene-reviewon thepartial_move.rsfix per Fix Completeness.
- §04 close-out /review-plan ran to verdict (Steps 1.7→9): verdict
- 2026-06-02 (firing 2) — TPR-04.R-009 delivered + §04.N parity/spec gates verified.
- TPR-04.R-009 DELIVERED (recursive-type × Drop-AUGMENT cross-case composition pin).
recursive_drop_with_user_drop_composes_no_double_freeincompiler_repo/compiler/ori_llvm/tests/aot/recursive_drop.rs: a recursiveNodecarryingimpl Node: Drop { @drop (self) -> void = (); }, 3-node chain dropped at scope exit.ORI_CHECK_LEAKS=1oracle (viaassert_aot_success) is the composition check — clean exit proves SCCcompiled_drop+ AUGMENTuser_dropcompose (once per node, children traversed once, no leak, no double-free). PASSES. Fullrecursive_dropsuite 5 pass / 1 ignored (BUG-02-032). No composition defect → no/add-bug. §04.R.1 TPR-04.R-009 item flipped to delivered. Both §04.R follow-ups (TPR-04.R-008 nested-destructure E2048 + TPR-04.R-009 cross-case) are now delivered. - §04.N gate verification (close-out-finalize prep): L618 spec-green —
tests/spec/aims/drop_augment/+tests/spec/aims/value_drop_conflict/pass 2/2 on BOTH interpreter AND--backend=llvm. L619 leak — the §04.1/02/03 AOT pins (recursive_drop 5+1, closure_drop 2, drop_augment 20+2, value_empty_burden 3) all run underORI_CHECK_LEAKS=1viaassert_aot_success, zero leaks; every#[ignore]tracked (BUG-02-032, BUG-04-122, BUG-05-006). L620 parity — value_drop_conflict.oriboth-backend + the recursive-Node-with-@dropprogram runs exit-0 on the interpreter (ORI_STDLIB=library/std) AND passes AOT; observable-behavior parity holds (drop-balance is the AOT-side property the leak oracle verifies). L573/L622 TPR — section-close/tpr-reviewran clean round-1 (firing 1, MINOR FIXES APPLIED, reviewed:true). L617 all-04.X — algorithmic deliverables + AOT pins shipped/green. - Orchestrator loop persists (firing 2 confirm): fresh run-id
eedd6f49…still routes §04 →/review-planpre-review (override_active_section_first) because §04 is the reviewed:true deadlocked-pin section whose §04.4 + §04.N lifecycle remain. The regression-list cures (_independent_actionable_section_idsorphan-starvation, §04B State-C) do not cover thisreviewed:true + deadlocked-pinpath. Cure is unchanged: complete §04 close-out so §04 leavesin-progress. - Remaining for §04 close (resume pointer, firing 3): (1) Fix-Completeness code review of the §04 compiler diff (
partial_move.rsnested-destructure recursion +recursive_drop.rs/integration_tests.rspins) —/tpr-reviewcode-mode then/impl-hygiene-reviewper L623 anchor (scope to the §04 work arc, not the cross-scope parallel-sessionori_arcchanges). (2) Flip §04.N checkboxes (L573, L617-L622) + §04.4 + §04.R + §04.R.1 → complete viaplan-complete.py --complete-all. (3) §04status: in-progress → complete(State-B flip). (4)/commit-push(cross-scopeori_arc realize/mod.rsclippy block from a parallel session → dirty-tree-continue per autopilot). Once §04 iscompleteit stops being the override-pinned deadlocked section → orchestrator advances to §04B/§05 (the §05→§09 green-CI critical path per LEDGER §B.3).
- TPR-04.R-009 DELIVERED (recursive-type × Drop-AUGMENT cross-case composition pin).