100%

Section 01: IndexSet Trait + updated Method + ARC COW

Goal

  • See frontmatter. Proposal Phase 1.
  • The updated method is the desugar target for index assignment (list[i] = x → list = list.updated(key: i, value: x)); it ships before the section-03 desugar consumes it.

Implementation Sketch

  • IndexSet<Key, Value> is a prelude trait (companion to read-only Index).
  • The updated method is publicly callable (functional style: list.updated(key: 0, value: x)) independent of the assignment sugar.
  • The contract is value-semantic: updated returns a NEW collection, observably distinct from the receiver.
  • Built-in impls are compiler-provided intrinsics. For [T], [T, max N], and {K:V}, frozen AIMS facts distinguish proved uniqueness from dynamic sharing, and each physical plan chooses an in-place or preserving-copy realization with identical value semantics. The current compiled ARC adapter uses a counter value of one as its dynamic uniqueness witness.
  • Map in-place COW is live in the current compiled runtime: ori_rt/src/map/cow.rs uses ori_rc_is_unique before overwriting in place. That adapter evidence does not make a counter part of the IndexSet or AIMS contract; VM/native/direct-WASM/JIT plans must prove equivalent value and ownership behavior through their selected mechanisms.
  • str deliberately omits IndexSet (codepoint replacement may change byte length).

01.1 IndexSet Trait + updated Method + ARC COW Implementation

Intelligence Reconnaissance

2026-06-01 — feature-mode scaffold; approved proposal index-assignment-proposal.md is the research artifact.

  • scripts/intel-query.sh symbols "Index" --repo ori --kind trait — mirror the read-side trait registration [ori:ori_types/src/check/registration/] for IndexSet.
  • scripts/intel-query.sh file-symbols "ori_eval/src/method_dispatch" --repo ori — built-in method routing surface [ori:ori_eval/src/method_dispatch/].
  • scripts/intel-query.sh similar "updated" --repo swift,rust --limit 5 — Array/Dictionary copy-on-write prior art.

Spec References

  • compiler_repo/docs/ori_lang/v2026/spec/13-variables.md §13.6.2 (index assignment) — the AUTHORITATIVE SSOT defining x = x.updated(key: i, value: v) as the index-assignment desugar contract. Its COW note must state the semantic uniqueness condition; any counter-based example is informative projection detail.
  • Proposal index-assignment-proposal.md §The IndexSet Trait, §Standard Implementations (research artifact; subordinate to the spec).
  • index-trait-proposal.md (the read-side Index pair).
  • Semantic contract: t.updated(key:k, value:v).index(key:k) == v (not compiler-enforced).

Tests

tests/spec/traits/index_set/{basic,updated_method,cow_behavior,fixed_oob,arc_insert,non_hashable_key}.ori + Rust unit tests in ori_types / ori_registry / ori_patterns / ori_arc + AOT integration compiler/ori_llvm/tests/aot/index_set_updated.rs per items above.

  • TDD-first: failing test matrix BEFORE implementation — updated on [int] / [str] / {str:int} / [int, max N] × {in-bounds, out-of-bounds, proved-unique in-place eligibility, dynamically shared preserving-copy} × {evaluator, VM, LLVM debug/release/AOT, every admitted native/direct-WASM/JIT projection}. The compiled ARC leg additionally exercises counter-one/counter-many witnesses. OOB semantics per type: [T].updated and [T, max N].updated panic for invalid keys; {K:V}.updated inserts. Negative pin: str.updated direct-resolution failure because str implements Index, not IndexSet.

    • [T, max N].updated OOB cell (parallels [T]): positive pin — a [int, max 3]-annotated literal .updated(key: 1, value: 9) yields [1, 9, 3] in both backends; negative pin — assert_panics(() -> fixed.updated(key: 5, value: 0)) for key >= length (in-bounds-of-capacity but out-of-bounds-of-length still panics, matching [T] index semantics, NOT the fixed-list try_push overflow path). Construction uses the [int, max 3] annotation form because BUG-02-043 records .to_fixed<$N>() as unimplemented.
      • Ori Tests: tests/spec/traits/index_set/fixed_oob.ori
  • Define IndexSet<Key, Value> trait in compiler_repo/library/std/prelude.ori with @updated (self, key: Key, value: Value) -> Self.

    • Ori Tests: tests/spec/traits/index_set/basic.ori
  • Register IndexSet trait definition + built-in derived/impl signatures in ori_types/src/check/registration/ (mirror how Index is registered). Mirrored outcome: Index carries NO check/registration/ entry — both traits register via prelude parse + registry-driven resolution (registry_bridge), so the registration surface is the ori_registry MethodDef (Some("IndexSet")) consumed by resolve_builtin_method; no parallel check/registration/ table exists to extend.

    • Rust Tests: ori_types/src/infer/expr/methods/tests.rs (resolution-path pins; check/registration/tests.rs has no Index-trait analog to mirror)
  • Register updated as a built-in method on [T] + {K: V} in ori_eval method dispatch + ori_registry (per .claude/rules/registry.md — methods on builtin types live in the registry). Map registration carries the K: Eq + Hashable bound (mirrors Index / map-key constraints). [T, max N] is NOT a separate registration surface: it erases to TypeTag::List at registration/resolution, so the [T] (List-tag) registration in ori_registry/src/defs/list/mod.rs (registered under tag: TypeTag::List) covers fixed-lists — registering updated on [T, max N] separately would be redundant.

    • Rust Tests: ori_types/src/infer/expr/methods/tests.rs (companion to resolve_builtin_method at ori_types/src/infer/expr/methods/mod.rs; the resolver lives in ori_types, NOT ori_eval/src/method_dispatch/) — registry resolution of updated succeeds for each type: [int].updatedIndexSet<int, int>, {str: int}.updatedIndexSet<str, int>, [int, max 4].updatedIndexSet<int, int> resolves via the List tag (assert resolve_builtin_method returns the registered impl + correct key/value types per type).
    • Rust Tests: non-hashable map-key negative pin lands as the spec compile-fail tests/spec/traits/index_set/non_hashable_key.ori (E2031 at map-type formation via check_map_key_hashable, which is private to infer/expr/type_resolution.rs — no Rust-level E2031 pin surface exists; the bound is enforced before method resolution is reached); positive pin: hashable K resolves per updated_method.ori + infer/expr/methods/tests.rs.
    • Ori Tests: tests/spec/traits/index_set/updated_method.ori
  • Implement updated value semantics in the ori_patterns / ori_eval model for [T], [T, max N], and {K:V}. The evaluator remains AIMS- and layout-abstract: clone-then-update is sufficient, while an optional host-container uniqueness optimization may mutate in place only when observationally transparent. List/fixed-list out-of-bounds panics; map inserts-or-replaces. The shared VM/compiled branch separately consumes AIMS COW facts and a validated physical plan.

    • Rust Tests: ori_patterns/src/value/tests.rs — value-semantics matrix (aliased list/map source remains unchanged; result contains the update); host in-place execution is not a semantic assertion
    • Ori Tests: tests/spec/traits/index_set/cow_behavior.ori
  • Register updated’s AIMS ownership contract so the shared calculus proves value flow once. self is consumed-and-returned, and value transfers into the collection; the caller must not discharge that logical owner afterward. Missing this contract can produce an extra logical release or an unfunded child owner. In the current compiled ARC adapter those defects manifest as counter-one leaks or counter-many double frees, but the contract itself contains no counter policy.

    • 3-param contract constructor required: updated is 3-param (self, key, value); the existing cow_receiver_only_contract (ori_arc/src/aims/builtins/mod.rs) marks ONLY the receiver and cannot express the value-param ownership-transfer — seed_builtin_contracts MUST NOT default updated into it (param-length mismatch). Add a new 3-param parameterized contract constructor (or specialized memory contract) that models self consumed-returned + value moved-in + key borrowed.
    • Uniform COW contract across all three types: [T], [T, max N], and {K:V} share one logical value-flow shape: self is consumed-returned, value moves in, and the result either reuses or replaces the receiver’s storage. AIMS freezes that shape and logical uniqueness once; each physical plan chooses its sharing observation and storage mechanism without list-vs-map policy forks.
    • Rust Tests: ori_arc/src/aims/builtins/tests.rs — contract seeded for updated on [T] / [T, max N] / {K:V}; value-param ownership-transfer asserted (no RC dec on the moved value).
    • Ori Tests: tests/spec/traits/index_set/arc_insert.ori — insert an ARC-managed element ([str] / {str: [int]}) under updated; ORI_CHECK_LEAKS=1 reports zero leaks debug + release, interpreter == AOT.
  • LLVM updated codegen for the three built-in types; verify interpreter == AOT (dual-execution parity); ORI_CHECK_LEAKS=1 zero leaks debug + release. The codegen + AIMS contract + runtime are CORRECT. BUG-04-142 (parallel session’s 59f645300 burden-only-default RC regression: __index double-inc str-element leak + premature receiver dec / alias corruption) resolved 2026-06-10; AOT parity restored.

    • Re: index_set_updated AOT 13/13 debug + 13/13 release (incl. test_updated_list_str_elements_no_leak, test_updated_list_str_shared_copy_no_double_free, test_updated_list_shared_preserves_alias, test_updated_map_arc_value_moved_no_leak — the exact cases BUG-04-142 had broken).
  • Verify: matrix green debug + release, both backends. Interpreter index_set spec corpus green (0 failures in tests/spec/traits/index_set/); LLVM AOT 13/13 debug + 13/13 release. BUG-04-142 resolved — AOT parity restored, section unblocked.

01.R — Third Party Review Findings

Section-close /tpr-review (codex + agy + opencode + fork-context Opus adjudicator), 2 rounds, exit cap_reached_with_substantive (wall-clock cap).

  • [TPR-01-001-codex][Major] (CURED) Decorative Unicode box-drawing banner comments in compiler/ori_llvm/tests/aot/index_set_updated.rs (6 occurrences, COMMENT_HYGIENE_DRIFT:decorative-banner). Replaced with plain ASCII section comments (working tree; commit deferred behind BUG-04-142 cross-scope gate).
  • [TPR-01-002-codex][Critical] (RESOLVED) INVERTED-TDD:commit-with-red-tests — section claimed complete + 13/13 AOT while 5/13 index_set_updated AOT tests fail. Adjudicated: the updated() feature is correct (interpreter 33/33; AOT was 13/13 at d2237c1df); the regression is the parallel session’s 59f645300 burden-only-default flip (two general ori_arc burden-path RC bugs). Dispositioned: filed BUG-04-142, reverted premature completion, declared blocked_by: [BUG-04-142]. BUG-04-142 resolved 2026-06-10; re — AOT 13/13 debug + release, interpreter index_set green. blocked_by cleared.

HISTORY

  • 2026-06-12 — BUG-04-142 cleared; §01 re-verified + unblocked: BUG-04-142 (parallel-session burden-only-default RC regression) resolved 2026-06-10. Re-verified index_set_updated AOT 13/13 debug + 13/13 release (the str-leak / double-free / alias cases the regression had broken now pass) and the interpreter index_set spec corpus green. Flipped §01.1’s two remaining verification items, cleared blocked_by: [BUG-04-142]. No code changed this session — verify-first re-close after the cross-scope blocker cleared.

Adjudicator-refuted (not actionable, recorded for trail): agy INVERTED-TDD claims on fixed_oob.ori turbofish removal were false because BUG-02-043 records .to_fixed<$N>() as unimplemented; construction uses the [int, max 3] annotation. opencode returned a VERIFIED:no-drift record.

  • 2026-06-11 — Stale review_pipeline: marker cleared by /continue-roadmap orchestrator: marker carried stage: ?, 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 in scripts/plan_orchestrator/markers.py:clear_stale_marker_if_unreviewed.