Skip to content

v2 stage rework — 00_core.dag — substrate — apply v4 modeling discipline (coproduct dissolution + grounding + compiler homomorphism); CALIBRATION investigation; sibling-parallel to deep-seal-431 (complexity.dag) - #3404

Closed
briansrls wants to merge 2 commits into
mainfrom
session/cool-bee-832

Conversation

@briansrls

@briansrls briansrls commented May 19, 2026 •

Copy link
Copy Markdown
Contributor

v2 stage rework — 00_core.dag — v4 modeling discipline + CALIBRATION

First concrete v2-stage-rework PR. The operator's ask was to see what dies
under modeling discipline
on a load-bearing substrate file. 00_core.dag
(v2.std.core, 1707 lines) is already heavily dissolved; this is a focused
calibration result, not a churn maximizer.

What dissolved

Walker dissolution (Practice 10) — expr_has_self_call

expr_has_self_call (00_core.dag:1319) was a hand-rolled any-descendant
recursion over Node.children — the recursion mirrored the Node data graph
by hand. It is now derived: a fold_node catamorphism + a per-node
disjunction algebra. The tree recursion lives once, in fold_node.

New substrate (existing-file extension, no new file):

  • type NodeFold<R> { init, step } — the catamorphism algebra.
  • fn fold_node<R> — the structural fold over the children spine.

Shape mirrors src/v4/std/node.dag fold_node (#3297), adapted for v2's
Node (children: List<Node> directly, no Edge indirection).

expr_has_non_tail_self_call (:1328) deliberately stays a hand-written
recursion: it is genuinely irregular — tail position flips per expression
kind, so the call graph is not the data graph. Clean 🟢, not a catamorphism
candidate.

CALIBRATION — blocking vs omit

Audited all ~18 coproducts + the homomorphism surface of 00_core.dag.

finding location disposition blocking?
expr_has_self_call hand-rolled walker :1319 🔴 dissolved this PR —
diagnostic_to_span — 16 match arms, every arm an identical projection of a universally-present span field :297 🟡 gated no
ChildRole.accessor: String — function identity carried as a string :760 🟡 gated no
is_error_diagnostic — -> Bool { true }, ignores its argument :339 finding — cross-file follow-up no
NodeFieldRole.MetadataField, FunctionSizeEffect.TreeSizePreserving — variants matched but never constructed :860 / :899 minor — omit no

The remaining ~13 coproducts (Connective, TokenShape, InferredNode,
MethodSemantics, ExprData, MatchPattern, CompilerDiagnostic itself,
NodeFieldRole, FunctionSizeEffect, …) are genuinely closed with
RHS-distinct consumers — well-shaped, no metadata mechanically attached.

🟡 gates (no substrate primitive exists yet — not blocking; fixing later is no harder):

  • diagnostic_to_span — the 16 identical arms are fixed by the shape: every
    CompilerDiagnostic variant carries a span. Dissolving needs a
    coproduct-common-field facility (a field declared once across all variants).
    v2 sum types have none. Trigger: a common-field-on-coproduct substrate feature.
  • ChildRole.accessor — a String naming the projecting function. The
    in-file comment already states the resolution: "When .dag supports
    function references, accessor should become a structural reference."
    Trigger: parser-stage function-reference capability.

is_error_diagnostic is a genuine predicate-dissolution finding (a Bool
helper whose body is the constant true — CompilerDiagnostic is currently
all-error). Resolving it removes ~12 filter call sites across compile.dag,
04_infer.dag, 05_emit_rust.dag, and an emitted Rust template in
compiler_tests_rust.dag — a cross-file cascade out of scope for a focused
00_core.dag rework. Tracked as a follow-up.

Net: one walker dissolved onto one new catamorphism primitive; remaining
findings are substrate-gated 🟡 or cross-file follow-ups. Modest dissolution
— the expected calibration result for a mature, already-dissolved substrate file.

Downstream consumer

fold_node lands here with a proven consumer (expr_has_self_call), not
speculative. The 05_emit rework (session crisp-dove-396) has further
Practice-10 consumers queued for follow-up against this primitive:
render_node_type, emit_rust_tco_*, collect_type_names_from_node,
has_nested_records_node.

Verification

The v2 self-host fixed-point gate (bootstrap_fixed_point) is broken on
main
— independent of this PR — and surfaced to the PM: (1) CI's v2:
job filters with --exact bootstrap_fixed_point, which matches 0 tests (the
path is bootstrap::bootstrap_fixed_point); (2) the test shells a removed
v3-compiler bin emit_method_template_projection. Both are Rust test-infra
defects, routed for separate disposition.

Verified instead by direct compile via the v2 stage0 compiler:

  • 00_core.dag + its 8 dep modules: 13 files emitted, 0 diagnostics on the
    file
    — parses, resolves, typechecks, emits.
  • fold_node's recursion is accepted by the v2 complexity analyzer.
  • The dissolution is semantically equivalent to the prior walker (per-node
    predicate, OR-combined over the same children spine).

Acceptance criteria

  • 00_core.dag compiles clean via the v2 stage0 compiler (verified above).
  • Once the bootstrap_fixed_point harness is repaired, the full self-host
    fixed point should hold — the change is behavior-preserving.

briansrls and others added 2 commits May 19, 2026 16:37
Adds NodeFold<R> + fold_node to 00_core.dag (v2.std.core) — the structural
fold over a Node tree, mirroring src/v4/std/node.dag fold_node (#3297).
expr_has_self_call was a hand-rolled any-descendant recursion over
Node.children (Practice-10 walker dissolution); it is now derived as a
fold_node disjunction. expr_has_non_tail_self_call stays a hand-written
recursion — genuinely irregular (tail position flips per expr kind), a
clean 🟢, not a catamorphism candidate.

Verified: 00_core.dag parses, resolves, typechecks and emits with 0
diagnostics; fold_node's recursion passes the v2 complexity analyzer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@briansrls
briansrls marked this pull request as ready for review May 19, 2026 20:51
@briansrls

Copy link
Copy Markdown
Contributor Author

Thanks for the review. On the exploratory note (stage0 freshness):

The v2 stage0 freshness gate described in src/v2/tests/testing-strategy.md is retired infrastructure — verified just now:

  • scripts/regenerate-stage0.sh and scripts/check-stage0-freshness.sh both exit 1 with a "retired" message (T-V2-Retirement).
  • No CI job diffs .dag ↔ src/v2/stage0/. The only freshness gate in ci.yml (line 137, regen_bootstrap --verify) is for v3 Pure-Bootstrap, not v2 stage0.
  • src/v2/stage0/ is a frozen bootstrap seed: it compiles the src/v2/*.dag self-hosted sources; it is not itself regenerated from them. A .dag-only change like this one needs no stage0 regen pass.

So testing-strategy.md's description of a "regenerate → diff → empty" stage0 gate is stale doc — no merge action needed here. (Separately surfaced to the PM: the v2 bootstrap_fixed_point self-host test is also currently broken on main — stale removed v3 bin — so v2 self-host is unverified by CI regardless of this PR; routed for its own disposition.)

This PR was verified by direct compile via the v2 stage0 compiler: 00_core.dag + deps emit with 0 diagnostics on the file, and fold_node's recursion is accepted by the v2 complexity analyzer.

— sent from cool-bee-832

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 634c16a9 · Trigger: schedule
  • Thinking: 328s wall

Non-blocking — Strengths

  • src/v2/00_core.dag The PR is a .dag substrate change that replaces a hand-rolled descendant walker with the new NodeFold/fold_node catamorphism without changing the self-call predicate's meaning.

✅ No blocking concerns in the changed lines.

@briansrls

Copy link
Copy Markdown
Contributor Author

Closing per operator wrap-up directive 2026-05-20.

@briansrls briansrls closed this May 20, 2026
@briansrls

Copy link
Copy Markdown
Contributor Author

This is the close-comment from gh pr close per the operator wrap-up directive 2026-05-20 (PM msg_b85782fb). PR is CLOSED — no further action. The relay is reading my own close-comment as a finding; posting this with the marker so the relay loop terminates.

— sent from cool-bee-832

@briansrls
briansrls deleted the session/cool-bee-832 branch June 1, 2026 18:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant