Repository navigation
Conversation
briansrls
left a comment
There was a problem hiding this comment.
Director Review — Four-fixture ownership regression (#486)
This pins §3.3 of the design doc as a regression suite. Four .dag fixtures (id, drop, wrap, is_empty) cover the four reachability patterns from parameter to return:
| Fixture | Reachability | Expected disposition |
|---|---|---|
| id.v3 | Direct (param IS the return) | Consumed |
| drop.v3 | None (param unused) | Borrowed |
| wrap.v3 | Through construct site (record field) | Consumed |
| is_empty.v3 | Read-only (match scrutinee) | Borrowed |
Each fixture asserts: compiles with zero diagnostics + UnusedParametersLens classification matches reachability intent + clone count ratcheted.
The current ratchet is "today: zero clones each" with the future gate locked in for when Phase 2 (#482) lands the Borrowed|Consumed disposition rendering. That's the right shape — the test catches both directions of regression.
LGTM. Ship.
This comment has been minimized.
This comment has been minimized.
briansrls
left a comment
There was a problem hiding this comment.
codex · gpt-5.4 · 6a4b45a5
BLOCKING (1)
Root Cause
src/v3/compiler/tests/four_fixture_regression_test.rsThe suite makes Borrowed and Consumed observationally identical for the consumed fixtures by using Copy-typed data and a clone-string metric, so the green signal can arrive before §3.3 is actually implemented; assert the emitted owned-vs-borrowed shape directly today or use a non-Copy consumed fixture whose wrong contract is observable.
Non-blocking — Strengths
src/v3/compiler/tests/four_fixture_pressure/is_empty.v3The List-to-BoxedFx substitution is documented, bounded, and names the trigger for replacement, so it reads as tracked bridge debt rather than an unbounded workaround.
ROADMAP — Incomplete
- §3.3 validation gate: A green result here would not yet justify the design doc milestone that says the four-fixture pressure test validates §3.3, because id and wrap still pass under borrowed emission.
| // Ratchet at the current observed count so any regression | ||
| // that introduces a clone for this reachability pattern fires. | ||
| const ID_CLONE_COUNT: usize = 0; | ||
| assert_eq!( |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment has been minimized.
This comment has been minimized.
Wire the four canonical fixtures (id / drop / wrap / is_empty) from
docs/dependency-and-rendering-design.md §3.3 as executable tests.
Each fixture isolates a reachability pattern from the §3.3 table;
together they pin the model's one-fact-shape abstraction claim so a
per-fixture regression fires in one CI run.
Today the assertions use the UnusedParametersLens ("param used vs
unused"), which separates `drop` from the other three — the
strongest reachability fact available pre-Track-1-Phase-2. When
Phase 2 ships ParameterDisposition, the assertions tighten to
`Consumed | Borrowed` per the §3.3 table without the test interface
changing.
Clone-count ratchets pinned at zero per fixture.
`#[ignore]`'d go.dag cross-target variants stubbed for Lane 3.
Notes on fixture adaptations (documented in-file):
- `is_empty` swaps List<Int>+Empty/Cons → BoxedFx+BoxedV/Nil
because match-on-List core-type lowering isn't wired yet and
`is_empty`/`Empty` collide with src/v3/std/list.dag. The §3.3
abstraction (match-read-only, param inspected not forwarded) is
preserved; canonical form restorable later without test churn.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Address codex-review blocking comment: the previous clone-count
ratchet used Copy-typed data, which collapses Consumed and
Borrowed renderings observationally — so a green signal could
arrive before §3.3 is actually implemented.
Per §9 ("tests verify the facts, not symptoms"), the assertions
now check the parameter contract directly via emitted Rust
signature shape:
Borrowed → `fn <name>(p0: &T, ...)` (leading `&` on param)
Consumed → `fn <name>(p0: T, ...)` (no `&` on param)
Signature-shape is a fact, not a symptom: Copy-ness does not
collapse it. `fn id(p0: i64)` and `fn id(p0: &i64)` are
distinguishable regardless of whether the type is Copy.
Structure:
- Borrowed-contract tests (`drop`, `is_empty`) run live today —
Phase-1 conservative default already matches Borrowed, so they
verify the §3.3 fact and pass in one step.
- Consumed-contract tests (`id`, `wrap`) are `#[ignore]`'d with
a named Phase-2 unignore trigger. They encode the sound §3.3
fact; running them ignored today confirms they fail as expected
(the emitter renders `&i64` where §3.3 says `i64` for Consumed).
Removing `#[ignore]` is the single action that promotes Lane 6
from half-gate to full §3.3 gate when Phase 2 lands.
Removed the clone-count ratchet entirely — it was unsound and
the reviewer was right to flag it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Addressed in
This distinguishes the two contracts regardless of Copy-ness. Structure that keeps Lane 6 independently mergeable while installing the §9 sound gate:
Removing the The clone-count ratchet was deleted entirely (unsound per your point). |
ChatGPT ReviewPrinciple audit. Fail-closed. Satisfied. For a test harness, the failure paths all stop loudly and specifically: fixture I/O, compile, diagnostic, and emission failures are all surfaced at Illegal states unrepresentable. Mostly satisfied. The only new Rust coproduct is the local Facts flow forward. Mostly satisfied, and this is where the revision materially improved the PR: the old clone-count symptom is gone, and the per-fixture checks now pin the direct Rust consequence of the intended fact at chatgpt-review-97e242da-51fe-46… Coproduct dissolution. Satisfied. Single-authority metadata. Mostly satisfied. The fixture files are the authority for the four shapes, and the harness centralizes lookup through API-level enforcement. Partially satisfied. The new signature-shape assertion is a much stronger behavioral gate than the previous clone proxy, and the ignored consumed tests are explicitly documented with a named unignore trigger ( Design question. When Track 1 Phase 2 lands, is Lane 6 supposed to become a direct consumer of the compiler’s authoritative Verdict. APPROVE_WITH_COMMENTS. This revision fixes the main structural weakness from the earlier round: the suite no longer infers ownership from clone counts, and the remaining phase gap is tracked honestly rather than hidden. My only concern is to make sure the last shared-path proxy ( LOOP HEALTH: converging — this round replaces an unsound symptom gate with a sound contract-shaped one, and the debt it adds ( |
ChatGPT ReviewPrinciple audit. Fail-closed. Satisfied. The v3 harness still fails loudly at every boundary: fixture read, compile, diagnostics, signature extraction, and emit all stop with targeted messages in Illegal states unrepresentable. Satisfied. The new Rust-side state is implementation-local and clean: Facts flow forward. Satisfied. The four-fixture suite now carries the intended ownership fact forward through its direct emitted-signature consequence instead of backing into it from a symptom proxy in Coproduct dissolution. Satisfied. No new substrate enum lands here. Single authority. One NON-BLOCKING concern in the bootstrap helper. This round correctly centralizes the copied support-module set in API-level enforcement. Mostly satisfied on the v3 side: the live tests assert executable contract consequences, and the parked Phase-2 cases have explicit named triggers in Design question. Is Verdict. APPROVE_WITH_COMMENTS. The four-fixture lane itself looks clean in this round, and the CI bootstrap change is moving in the right direction by removing false diff noise rather than weakening the gate. My only comment is to finish collapsing the bootstrap diff authority so the new stabilization logic lives in one canonical path. LOOP HEALTH: converging — this round strengthens the ownership suite without inventing new fake greens, and the bootstrap change removes known CI noise; the only remaining debt I see is a small single-authority cleanup around bootstrap diff semantics. |
Meta-Review (Loop Health)According to a document from 2026-04-16, this loop is making real progress, but it has already reached diminishing returns on this PR. The core blocker was real, it got fixed, and what remains is tracked bridge debt rather than a still-unknown defect class. Loop summaryVisible in the attached history are 2 substantive patch rounds: the first round got one ChatGPT browser review at 21:04Z and one codex-cli review at 21:11Z; the second round got a revised ChatGPT browser review at 21:43Z. There is also 1 additional browser run still in progress at 22:07Z. So the visible counts are K=1 codex review and L=2 completed browser reviews plus one pending browser pass. The attachments do not expose exact GitHub commit count or separate inline-comment totals, so the honest summary is 2 visible patch revisions / review rounds, over about 63 minutes of review-loop time. Forward progress evidenceThe loop did produce a new consumer. The first browser round explicitly recognized that the PR turned prior ownership discussion into “four concrete fixtures plus a reusable CI harness,” with the same compiled More importantly, the loop fixed its most important flaw. Codex flagged that the original suite made Borrowed and Consumed observationally identical by using Copy-typed data plus a clone-string metric, so it was not a sound §3.3 gate. The next browser review says that weakness was materially fixed: the suite “no longer infers ownership from clone counts” and instead pins the direct emitted-signature consequence, which is exactly the right direction for “consumers define correctness” and “facts flow forward.” This also lines up with the project’s actual ownership roadmap: LS-4 says the long-term target is for read-only parameters to be borrowed and for call sites to stop cloning defensively. PR #486 is now testing that ownership distinction at the signature boundary instead of treating raw Debt accumulation evidenceDebt still accumulated, just in tracked form. The revised round still leaves a local That means principle 3 is only half-satisfied. A recurring finding did not fully graduate to an invariant inside the PR; it was fixed locally in per-fixture assertions, but the abstraction-level test still re-compresses the fact into a coarser proxy. Principle 4 is also only half-satisfied: the suite now spans lens reachability and emitter signature shape, but it still lacks one cross-layer authoritative ownership fact. In project terms, this is the same general disease the semantic-authority invariant was written to prevent: secondary representations hanging around because the authoritative fact is not yet surfaced where the consumer wants it. The scaffolds themselves are properly accounted for. Cheating signalThe cheating signal is low. The implementer is not hiding compromises. The reviews explicitly describe the remaining gap as “tracked honestly rather than hidden,” and the named triggers are written down in the test story instead of being smuggled in as silent “good enough for now” behavior. But the fixes are mixed. The move from clone-count proxy to signature-shape assertion is structural. The remaining Meta-verdict⚖️ SHIP_WITH_DEBT This is not the kind of stagnant loop that deserves PAUSE_AND_REGROUP. The history does not show the PR #445 pattern where the same root disease survived round after round until the project had to graduate it into an invariant. Here, one blocking finding landed, the author responded with a materially stronger consumer, and the remaining debt is mostly blocked on Track 1 Phase 2 exposing the authoritative ownership fact. It is also not KEEP_ITERATING territory anymore. Another round on this PR is unlikely to buy much more than arguing about the same known bridge: the local So the honest call is: merge it as a tracked Phase-1 half-gate. It enabled a real consumer, it fixed the main bluff in the loop, and the remaining debt is named. But do not count it as full §3.3 closure until the ignored Consumed tests are live and Lane 6 consumes the compiler’s authoritative ownership fact directly. |
briansrls
left a comment
There was a problem hiding this comment.
codex · gpt-5.4 · 6f062351
✅ Review (blocking: 0, non-blocking: 1+/0-)
Non-blocking — Strengths
src/v2/tests/src/bootstrap.rsCopying the hand-maintained stage0 support modules before the rustfmt/diff steps keeps the freshness and fixed-point checks focused on generated output instead of missing support files.
✅ The prior soundness hole is closed; the Borrowed fixtures verify the direct §3.3 consequence today, the Consumed fixtures are explicitly staged behind the named Phase-2 trigger, and I do not see new concerns in this PR.
|
✅ Review (blocking: 0, non-blocking: 1+/0-) Non-blocking — Strengths
✅ The prior soundness hole is closed; the Borrowed fixtures verify the direct §3.3 consequence today, the Consumed fixtures are explicitly staged behind the named Phase-2 trigger, and I do not see new concerns in this PR. |
|
Closing in favor of a unified reconciliation approach. The merge-train experiment on Rather than push each branch through another round of rebase-fix-review that would repeatedly rediscover cross-branch conflicts, all six PRs (#482, #483, #484, #485, #486, #487) are being reconciled into a single
All review comments (codex, chatgpt-browser, director) harvested into Class of fixes addressed uniformly in reconciliation:
Thanks for the work — all of it ships through the reconciliation. |
* Migrate cost lens to complexity.dag
* Fix complexity lens clippy naming
* test: pin §3.3 four-fixture ownership regression suite (Lane 6)
Wire the four canonical fixtures (id / drop / wrap / is_empty) from
docs/dependency-and-rendering-design.md §3.3 as executable tests.
Each fixture isolates a reachability pattern from the §3.3 table;
together they pin the model's one-fact-shape abstraction claim so a
per-fixture regression fires in one CI run.
Today the assertions use the UnusedParametersLens ("param used vs
unused"), which separates `drop` from the other three — the
strongest reachability fact available pre-Track-1-Phase-2. When
Phase 2 ships ParameterDisposition, the assertions tighten to
`Consumed | Borrowed` per the §3.3 table without the test interface
changing.
Clone-count ratchets pinned at zero per fixture.
`#[ignore]`'d go.dag cross-target variants stubbed for Lane 3.
Notes on fixture adaptations (documented in-file):
- `is_empty` swaps List<Int>+Empty/Cons → BoxedFx+BoxedV/Nil
because match-on-List core-type lowering isn't wired yet and
`is_empty`/`Empty` collide with src/v3/std/list.dag. The §3.3
abstraction (match-read-only, param inspected not forwarded) is
preserved; canonical form restorable later without test churn.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test: verify §3.3 ParameterContract facts, not symptoms (Lane 6)
Address codex-review blocking comment: the previous clone-count
ratchet used Copy-typed data, which collapses Consumed and
Borrowed renderings observationally — so a green signal could
arrive before §3.3 is actually implemented.
Per §9 ("tests verify the facts, not symptoms"), the assertions
now check the parameter contract directly via emitted Rust
signature shape:
Borrowed → `fn <name>(p0: &T, ...)` (leading `&` on param)
Consumed → `fn <name>(p0: T, ...)` (no `&` on param)
Signature-shape is a fact, not a symptom: Copy-ness does not
collapse it. `fn id(p0: i64)` and `fn id(p0: &i64)` are
distinguishable regardless of whether the type is Copy.
Structure:
- Borrowed-contract tests (`drop`, `is_empty`) run live today —
Phase-1 conservative default already matches Borrowed, so they
verify the §3.3 fact and pass in one step.
- Consumed-contract tests (`id`, `wrap`) are `#[ignore]`'d with
a named Phase-2 unignore trigger. They encode the sound §3.3
fact; running them ignored today confirms they fail as expected
(the emitter renders `&i64` where §3.3 says `i64` for Consumed).
Removing `#[ignore]` is the single action that promotes Lane 6
from half-gate to full §3.3 gate when Phase 2 lands.
Removed the clone-count ratchet entirely — it was unsound and
the reviewer was right to flag it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Stabilize v2 CI bootstrap diffs
* Stabilize v2 CI bootstrap diffs
* Lane 4: migrate provenance lens to .dag authority
Move the one-hop `produced_by` walk from hand-written Rust to
src/v3/lenses/provenance.dag. Rust callers consume an auto-emitted
snapshot via `v3_compiler::lens_provenance::origin_of`; the
hand-written `lens_provenance.rs` is deleted. Migration test
(m2_lens_provenance_migration_test.rs) pins the .dag snapshot,
ratchets the emitted clone count, and verifies behavioral
equivalence against a hand-written oracle across four fixtures.
Origin reshaped from 4 variants over `Option<NodeId>` to 5 flat
variants because v3's current surface grammar doesn't support
Some/None in expression position — `NoProducer` splits out the
`by: None` case, `Source(NodeId)` subsumes `by: Some(_)`.
Placement is src/v3/lenses/ (sibling to unused_parameters.dag),
not src/v3/std/, to avoid double-loading via STAGED_FILES; moving
into std/ is follow-up once the compile pipeline tolerates
re-lowering files bootstrap already staged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* complexity.dag: fix double-decrement underreport + document fuel scaffold
**Bug fix.** The prior fuel seed was `port_count` but each recursive
step decrements fuel twice (once entering a Transform's SumPorts
mode, once walking the input-list tail). Unary transform chains
therefore ran out of fuel early — a 3-transform chain returned 2
instead of 3. Fix: seed = 2 × port_count, which accommodates the
double-decrement without premature termination.
**Scaffold receipt.** Fuel is not the thesis-correct pattern; it's
a workaround for .dag's termination checker. The header comment
now carries a 🟡 scaffold receipt naming three concrete dissolution
triggers:
(a) .dag gains mutual recursion support → graph-descent and
list-descent split into separate structural functions (tried
in this PR, blocked by "mutual recursion not yet supported").
(b) .dag termination checker accepts DAG-walk termination via
substrate invariants (the DAG is acyclic and finite).
(c) Substrate exposes a fold_backward(d, port, f) or forward-fold-
by-topological-order primitive (tried in this PR as forward
fold over d.nodes; blocked by emit_rust dispatch_producer
failing on the new record-literal shape; investigation
deferred).
The oracle for correct behavior remains the original Rust cost
lens at `src/v3/compiler/src/lens_cost.rs` on commit 1247f4b —
a clean recursive walk via total Dag.port() / Dag.node() accessors,
no fuel needed (Rust has no termination checker). This .dag lens
agrees with it on the existing oracle fixture; when any dissolution
trigger fires, the fuel and CostMode scaffold disappear and the
lens becomes a pure structural walk matching the Rust oracle's
shape.
All migration tests pass (complexity_dag_compiles_cleanly,
complexity_dag_matches_handwritten_oracle_on_core_fixtures,
complexity_generated_module_matches_checked_in_snapshot). Generated
module regenerated to reflect the new seed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* complexity.dag: replace fuel counter with structural forward fold
The fuel counter was a 🟡 scaffold that papered over a false gap. The
actual blocker in the prior attempt was `Cons(...)` as expression-form
constructor (a parser limitation), misattributed as "substrate needs
fold_backward primitive."
Fix: import `cons` from std.list. Rewrite as forward fold over
`d.nodes` — the substrate already emits nodes in dependency order, so
a single `fold(d.nodes, empty(), |acc, node| cons(entry_for(acc, node), acc))`
walk builds a port→cost entry list in one pass. Termination is
structural on the finite List<Behavior>. No fuel, no mutual recursion.
Outcomes:
- complexity.dag: 271 → 128 lines
- lens_cost_generated.rs: 231 → 128 lines
- All 250 v3-compiler tests pass
- Receipt: 🟡 Scaffold → 🟢 TERMINAL
Also adds src/v3/compiler/src/bin/regen_lens_cost.rs to regenerate
the snapshot after future complexity.dag edits.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fmt: rustfmt regen_lens_cost.rs
Multi-line method chains broken per rustfmt on the new regen bin.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* complexity.dag: fail-closed MissingCost; pin Bind via method doc
Two blockers from PR #489 review:
A2 — fail-closed on malformed references. lookup_int returned 0 on
MissingCost, collapsing "port referenced but absent from d.nodes"
into "legitimate zero-cost leaf." Pre-seed the cost accumulator with
FoundCost(0) entries for every bind.params port (the only real
absent-from-d.nodes zero-cost leaves) and propagate MissingCost
through the sum/max helpers via a new CostLookup coproduct. cost_of
now returns CostLookup; CostLens::cost_of panics on MissingCost at
the Rust boundary, surfacing the fail-closed contract.
Bind semantics — explicit boundary. complexity.dag's Bind branch uses
`bind.result_port` (substrate name), tests use `bind.value` (Rust
struct field). BindNode::result_port() is the single point of
agreement; doc comment now says so. Added two Bind-with-parameters
fixtures (`fn double(x)`, `fn add(x, y)`) that exercise both the
seed_bind_params pre-seed and the Bind branch of entry_for.
Test harness: roundtrip harness now compiles once, reads fixtures
from argv, and runs inner rustc with -D warnings. Applied uniformly
across all three lens migration tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* tests: revert -D warnings + #[allow(warnings)] band-aids
The rustc roundtrip tests added `-D warnings` + `#[allow(warnings, clippy::all)]`
on the emitted `mod emitted { ... }` wrapper. That masks emitter warnings
(unused parens, unused pattern bindings, unused diagnostics import) at the
consumer instead of fixing them at the source.
Deferring the structural fix to a follow-up that teaches emit_rust to:
1. Wrap binops by precedence context, not unconditionally
2. Emit `_` for pattern bindings not referenced in the arm body
3. Include `use v3_compiler::diagnostics::*` only when the module uses it
The compile-once-run-many perf refactor (build_roundtrip_harness) stays
— that is a real structural win independent of the warning story.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* m1_3: batch 14 rustc-roundtrip tests into two shared harnesses
Each rustc invocation paid ~3-5s cold linker/codegen on CI; 14 tests
serialized into ~60s of pure rustc. Batch all 9 self-contained-program
fixtures into one binary (compiled with plain rustc) and all 5
reflected-module fixtures into another (compiled with v3_compiler
--extern). Tests dispatch via argv[1]; harnesses are built lazily via
`OnceLock<PathBuf>` on first access.
Local wall time: m1_3 dropped from 3.37s → 1.70s (-50%). CI win scales
with cold-cache rustc cost — expect 40-60s less on the v3 job.
Fixture descriptors live in const arrays (`PROGRAM_FIXTURES`,
`REFLECTED_FIXTURES`); submodule naming namespaces the emissions so
type and function declarations don't collide across fixtures. Group 1
programs get `fn main()` → `pub fn main()` rewritten so the nested
main is callable from the dispatcher.
The hand-written `roundtrip_stdout` helper stays because the
`#[ignore]`d `rustc_roundtrip_int_addition_prints_three` anchor test
uses it as the canonical end-to-end example.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* tests/common: extract RustcHarness — lazy DI / RAII for rustc roundtrips
Five test binaries (m1_3_emit_rust, m2_lens_{cost,provenance,unused_parameters}_migration)
each carried identical copies of `deps_dir`, `find_current_rlib`,
`next_roundtrip_dir`, and `compile_with_current_crate`. Extract into
`tests/common/mod.rs`; each test file imports via `mod common;`.
The harness API:
- `RustcHarness::new(scope)` — one per test binary, owns scratch root
and an atomic child-dir counter.
- `harness.compile(source, bin_name, HarnessLinkMode)` — rustc invoke
keyed on link mode. `Standalone` for self-contained emissions,
`WithV3Compiler` for reflected-DAG modules that need the v3_compiler
rlib.
- `RustcHarness::run(bin, args)` — spawn + assert + capture stdout.
Lazy init: each test file wraps `RustcHarness` in its own
`OnceLock<RustcHarness>` so construction happens at first test access
and the harness is reused across every `#[test]` in that binary.
Batched compilations remain lazy via `OnceLock<PathBuf>` on top of
the shared harness.
Net: 339 lines removed, 214 added. Helpers are declared once, and
the "which link mode does this test need?" question becomes a typed
enum rather than a choice between copy/pasted helpers.
`#[allow(dead_code)]` on common/mod.rs: each test binary exercises a
subset of the API (e.g. the cost lens migration never builds a
Standalone harness), so unused items per-binary would otherwise trip
clippy's -D warnings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
docs/dependency-and-rendering-design.md§3.3's four canonical fixtures (id/drop/wrap/is_empty) as executable regression tests so the ownership model's one-fact-shape abstraction is pinned in CI.UnusedParametersLens(the strongest reachability fact pre-Track-1-Phase-2); the doc block shows theParameterDisposition ∈ {Consumed, Borrowed}tightening path — test interface survives unchanged.#[ignore]'d go.dag cross-target variants stubbed for Lane 3 / Track 2.Fixture adaptations (documented in-file)
is_emptyswapsList<Int>+Empty/Cons→BoxedFx+BoxedV/Nilbecause match-on-List core-type lowering isn't wired yet andis_empty/Emptycollide withsrc/v3/std/list.dag. §3.3 abstraction (match-read-only, param inspected not forwarded) preserved; canonical form restorable later without test churn.Out of scope
Test plan
cargo test -p v3-compiler --test four_fixture_regression_test— 5 passed, 4 ignored (go.dag placeholders)cargo test --workspace --exclude v2-compiler-tests— all greencargo test -p v2-compiler-tests— 415 passed, 54 ignoredcargo test -p v2-compiler-tests ci_fixed_point ci_freshness -- --ignored— both pass (compile gates green on this branch)cargo clippy -p v3-compiler --all-targets -- -D warnings🤖 Generated with Claude Code