0%

Section 01: Runtime COW Protocol Centralization

Status: Not Started Goal: Reduce 17+ inline copies of the COW uniqueness formula, 3 copies of propagate_elem_header, 3 copies of write_collection_struct, and 4 copies of the iterator consumer loop harness into single canonical functions. Zero behavioral change.

Context: The COW uniqueness check !is_slice_cap(cap) && (cow_mode == 1 || (cow_mode != 2 && ori_rc_is_unique(data))) is inlined at 17 call sites across 7 files. The cow_mode semantics (0=dynamic, 1=static unique, 2=static shared) have no canonical home. propagate_elem_header exists as two identical functions with different names (propagate_elem_header in cow.rs, propagate_header in cow_sort/mod.rs) plus a third inline copy in cow_structural.rs. write_list_output, write_map_struct, write_set_struct are identical 3-line functions.


01.1 Centralize COW Uniqueness Check

File(s): compiler/ori_rt/src/cow_helpers.rs (new), all COW files

Create a single canonical function:

/// Determine whether a COW mutation can proceed in-place.
///
/// cow_mode semantics:
/// - 0: dynamic — check runtime uniqueness via ori_rc_is_unique
/// - 1: static unique — always mutate in-place (compiler proved uniqueness)
/// - 2: static shared — always copy (compiler proved sharing)
///
/// Slices are never mutated in-place (they are views into another allocation).
#[inline(always)]
pub(crate) fn cow_can_mutate_in_place(data: *const u8, cap: i64, cow_mode: i32) -> bool {
    !is_slice_cap(cap) && (cow_mode == 1 || (cow_mode != 2 && ori_rc_is_unique(data)))
}
  • Create compiler/ori_rt/src/cow_helpers.rs with cow_can_mutate_in_place()

  • Add mod cow_helpers; to compiler/ori_rt/src/lib.rs (note: lib.rs is already 512 lines — tracked in Section 08.4 for splitting; adding one mod line is fine here)

  • Replace all 17 inline copies across these files:

    • list/cow.rsori_list_push_cow, ori_list_pop_cow, ori_list_set_cow
    • list/cow_structural.rsori_list_insert_cow, ori_list_remove_cow
    • list/cow_sort/mod.rsori_list_concat_cow, ori_list_reverse_cow
    • list/cow_sort/sort.rsori_list_sort_cow
    • map/cow.rsori_map_insert_cow, ori_map_remove_cow
    • set/cow/basic.rsori_set_insert_cow, ori_set_remove_cow
    • set/cow/algebra.rsori_set_union_cow, ori_set_intersection_cow, ori_set_difference_cow
  • Verify: grep -rn "cow_mode == 1\|cow_mode != 2" compiler/ori_rt/src/ | grep -v cow_helpers | grep -v test returns 0 matches

  • timeout 150 cargo test -p ori_rt passes after this sub-section

  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (01.1) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-01.1 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 01.1: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.


01.2 Unify propagate_elem_header / propagate_header

File(s): compiler/ori_rt/src/cow_helpers.rs, compiler/ori_rt/src/list/cow.rs, compiler/ori_rt/src/list/cow_sort/mod.rs, compiler/ori_rt/src/list/cow_structural.rs

  • Move propagate_elem_header from list/cow.rs (line 21) into cow_helpers.rs as the single canonical copy

  • Delete propagate_header from list/cow_sort/mod.rs (line 23, identical body)

  • Replace the inline copy in cow_structural.rs with calls to cow_helpers::propagate_elem_header — check both ori_list_insert_cow and ori_list_remove_cow for inline header propagation

  • Update all import paths

  • Verify: grep -rn "fn propagate_header\|fn propagate_elem_header" compiler/ori_rt/src/ shows exactly 1 definition in cow_helpers.rs

  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (01.2) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-01.2 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 01.2: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.


01.3 Unify write_collection_struct

File(s): compiler/ori_rt/src/cow_helpers.rs, compiler/ori_rt/src/list/mod.rs, compiler/ori_rt/src/map/mod.rs, compiler/ori_rt/src/set/mod.rs

write_list_output, write_map_struct, write_set_struct are identical:

pub(crate) unsafe fn write_collection_struct(out: *mut u8, len: i64, cap: i64, data: *mut u8) {
    out.cast::<i64>().write(len);
    out.cast::<i64>().add(1).write(cap);
    out.add(16).cast::<*mut u8>().write(data);
}
  • Add write_collection_struct to cow_helpers.rs

  • Replace write_list_output in list/mod.rs with a re-export or inline call

  • Replace write_map_struct in map/mod.rs

  • Replace write_set_struct in set/mod.rs

  • Replace inline writes in list/cow.rs ori_list_push_cow (which doesn’t use write_list_output)

  • Verify: all collection sret writes go through write_collection_struct

  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (01.3) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-01.3 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 01.3: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.


01.4 Extract Iterator Consumer Loop Harness

File(s): compiler/ori_rt/src/iterator/consumers.rs

ori_iter_any, ori_iter_all, ori_iter_find, ori_iter_for_each share identical loop harness: null check, cast to IterState, loop calling state.next(), test element, cleanup via Box::from_raw.

  • Extract consume_iter() higher-order function:
    unsafe fn consume_iter<F, R>(
        iter: *mut u8,
        elem_size: i64,
        init: R,
        f: F,
    ) -> R
    where
        F: FnMut(R, &[u8]) -> ControlFlow<R, R>,
  • Rewrite ori_iter_any, ori_iter_all, ori_iter_find, ori_iter_for_each using consume_iter
  • Extract collect_to_reverse_vec() for shared collection phase in ori_iter_rfold and ori_iter_rfind
  • Verify: timeout 150 cargo test -p ori_rt passes

Cleanup (fix while touching these files)

  • [WASTE] compiler/ori_rt/src/iterator/consumers.rs:232 — Remove decorative unicode dash banner // ── Backward consumers ...──────────, replace with plain // Backward consumers (require double-ended iterators)

  • [WASTE] compiler/ori_rt/src/list/cow.rswrite_list_output is still defined here even after write_collection_struct extraction; ensure it’s fully removed, not left as dead code

  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (01.4) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-01.4 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 01.4: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.


01.R Third Party Review Findings

  • None.

01.T Test Strategy

This section is pure structural refactoring with zero behavioral change. The test strategy focuses on:

  1. Existing test suite as regression gate: ./test-all.sh must pass identically before and after each sub-section.
  2. Unit tests for new canonical functions: Each extracted function gets direct unit tests verifying it matches the old inline behavior.
  3. Structural invariant tests: Grep-based tests that verify no inline copies remain.
  • Add unit tests for cow_can_mutate_in_place() in compiler/ori_rt/src/cow_helpers/tests.rs:
    • cow_mode=1 (static unique) returns true regardless of RC
    • cow_mode=2 (static shared) returns false regardless of RC
    • cow_mode=0 (dynamic) returns true when ori_rc_is_unique returns true
    • cow_mode=0 (dynamic) returns false when refcount > 1
    • Slice cap always returns false regardless of cow_mode
  • Add unit tests for write_collection_struct(): verify struct layout matches the (len, cap, data) triple at correct offsets (0, 8, 16)
  • Add unit tests for consume_iter(): verify ControlFlow::Break stops iteration, ControlFlow::Continue processes all elements
  • Verify timeout 150 cargo test -p ori_rt passes after each sub-section (01.1, 01.2, 01.3, 01.4)
  • Verify timeout 150 ./test-all.sh passes after all sub-sections complete
  • Verify ORI_CHECK_LEAKS=1 reports zero leaks on COW-heavy test programs (e.g., tests/spec/collections/cow/)

01.N Completion Checklist

  • All 17 inline COW uniqueness checks replaced with cow_can_mutate_in_place()
  • Single propagate_elem_header function in cow_helpers.rs
  • Single write_collection_struct function in cow_helpers.rs
  • Iterator consumer loop harness extracted
  • Unit tests for all new canonical functions pass
  • timeout 150 cargo test -p ori_rt passes
  • timeout 150 ./test-all.sh passes (zero behavioral changes)
  • ./clippy-all.sh clean
  • /tpr-review covering Section 01
  • /impl-hygiene-review
  • /improve-tooling retrospective completed — MANDATORY at section close, after both reviews are clean. Reflect on the section’s debugging journey (which diagnostics/ scripts you ran, which command sequences you repeated, where you added ad-hoc dbg!/tracing calls, where output was hard to interpret) and identify any tool/log/diagnostic improvement that would have made this section materially easier OR that would help the next section touching this area. Implement every accepted improvement NOW (zero deferral) and commit each via SEPARATE /commit-push. The retrospective is mandatory even when nothing felt painful — that is exactly when blind spots accumulate. See .claude/skills/improve-tooling/SKILL.md “Retrospective Mode” for the full protocol.