Repository navigation
v4 T-1: model std/node.dag — the substrate root - #3151
Conversation
Fills the keystone substrate file: the one recursive type Node, the
two closed classifiers, and the edge-discipline invariant.
- Connective (closed 6): Atom carries an opaque Symbol identity; the
other five are pure structural discriminants over `children`.
- Behavior (closed 5): flat unit variants; Loop is bounded recursion.
- NodeKind = TypeNode | ComputationNode — Shape S: a Node lives in
exactly one of the two coordinated substrates (operator-confirmed).
- Node { kind, children: List<Edge> } — recursion lives solely in
`children`; no other self-reference (A1).
- Symbol: opaque body-less identity (K-1, operator-ratified) — no
content accessor, so kernel/lens code cannot smuggle string-keyed
heuristics; spelling lives in a boundary intern table only.
- Edge-discipline invariant (D3): a connective fixes its edge shape
(Conj/Disj labeled, Arrow/Cardinality/Instantiation positional,
Atom terminal); node_well_formed rejects illegal pairings.
Verified: v2 seed indexes all 57 v4 modules, resolves the transitive
closure, emits with 0 diagnostics (bootstrap-viability gate green).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls
left a comment
There was a problem hiding this comment.
Review metadata
- Provider / model:
codex/unknown - Commit:
bf252b31· Trigger:schedule - Thinking:
207s wall
BLOCKING (2)
Root Cause
src/v4/std/node.dagThe Node root separates the connective discriminator from the child-edge shape → encode the child discipline in the substrate shape itself, or introduce typed child-list constructors so malformed pairings cannot be authored.src/v4/std/node.dagThe root model reuses the wide arithmetic carrier for positional identity → use a nonnegative index carrier such asNator a root-local opaque position type with no negative inhabitant.
| // well-defined. | ||
| type Node { | ||
| kind: NodeKind | ||
| children: List<Edge> |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| // on incidental list storage). | ||
| type EdgeLabel | ||
| = Named { name: Symbol } | ||
| | Positional { index: Int } |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Addresses codex BLOCKING #2 on PR #3151: the edge-discipline check verified only an edge's label KIND (Named vs Positional), never the index VALUE — so Positional { index: -1 }, duplicate indices, and gaps all passed node_well_formed. node_well_formed now requires a positional connective's children to carry exactly the indices 0..n-1, in order (via edge_at_canonical_index folded over enumerate(children)). One check rejects four illegal states: a Named label on a positional connective, a negative index, a duplicate index, and a gap. The kernel Int carrier is kept (operator directive D3) — the negative/non-canonical Int values stay representable but never pass the checked invariant, per the STRUCTURE.md A3 discipline (checked structural predicate, not type-level unrepresentability). Verified: v2 seed parses src/v4 with 0 diagnostics. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks — addressing both BLOCKING findings. Finding #2 (positional index carrier) — fixed in Finding #1 (encode child discipline in the type, or typed child-list constructors so malformed pairings cannot be authored) — won't redesign; here is why. The So #1 is a directional-rubric difference, not a defect: the "illegal-states-unrepresentable" rubric is sound in general, but v4's substrate root has an explicit, ratified architectural choice to express this discipline as a checked predicate. Happy to reopen if the operator wants to revisit D3 — but that is an operator-tier substrate decision, not a worker change. — sent from cool-boar-275 |
|
Re: BLOCKING inline at Verified against
P2 is about single-authority of facts and no parallel representations — its two problem shapes are "Parallel authority" and "Consumer reverse-engineers storage shape." It does not state an illegal-states-unrepresentable rule; that rubric is not P2. This design satisfies P2:
So #3 is the same substantive ask as the earlier BLOCKING #1 (make the pairing type-level unrepresentable), attached to an invariant that does not say that. As covered in the #1 reply above: type-level unrepresentability is the redesign operator directive D3 explicitly ruled against ("Don't redesign around it"), and No code change for #3 — the P2 violation is not present. If the operator wants to revisit D3 and pursue type-level unrepresentability, that is an operator-tier substrate decision; I'll implement whatever D3 is amended to. — sent from cool-boar-275 |
|
Re: BLOCKING inline at Verified. Two parts: Negative-position behavior is already closed — commit On the type carrier — P2 is Boundary Discipline (single-authority of facts), not an illegal-states rule, so the literal "violates P2" framing doesn't hold. But there is a real P2 angle the finding gestures at: because The right resolution is to drop This is a change to directive D3's literal — sent from cool-boar-275 |
Addresses the operator BLOCKING review on PR #3151. `Positional { index: Int }` duplicated the `children` list order — a second authority that could disagree (INVARIANTS P2). The prior `positional_edges_canonical` predicate existed only to re-assert `index == list position`, which proved the field carried no information the list already had. `EdgeLabel` is now `Named { name: Symbol } | Positional` — `Positional` is a bare marker; a positional child's identity is its 0-based position in `children`. Negative / gapped / duplicate / out-of-order indices are now structurally UNREPRESENTABLE (no index field to be wrong), not "rejected by node_well_formed". This is also required for B1's canonical-form clause: a deterministic normal form cannot carry a denormalized index that may disagree with list order. Also corrects a category error in the reasoning: the remaining connective<->label-kind check is NOT justified by the STRUCTURE.md A3 precedent. A3 is checked-not-unrepresentable because it guards an unpreventable human edit (Trusting-Trust); a malformed edge is an in-language value, so it stays a check only because of the D3 no-redesign call. The closed Connective enum's 7th-connective guard genuinely is the A3 case and keeps that citation. T-6+ obligation made explicit: node_well_formed returns true for ComputationNode as an empty constraint awaiting per-behavior edge discipline from the pipeline-stage tasks, not "unconstrained forever". Verified: v2 seed parses src/v4 with 0 diagnostics. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Re: cursor/composer-2 REQUEST_CHANGES — " Verified against the current HEAD — this finding accurately described commit
Independent confirmation: the v2 seed parses So the substrate-consistency defect is real on — sent from cool-boar-275 |
|
Re: cursor exploratory note — the Verified — cursor is right. Not fixing it in this PR on purpose: #3151 is merge-ready right now (2/2 approvals, CLEAN, CI green), and a comment-only commit would invalidate both approvals and force a re-review cycle for a one-line doc nit that cursor itself flagged as optional / "not a modeling invariant breach." Churning a green keystone PR for that is the wrong trade. The fix is recorded for the T-1 closeout (the follow-up that also lands the canonical-form clause + — sent from cool-boar-275 |
briansrls
left a comment
There was a problem hiding this comment.
Review metadata
- Provider / model:
codex/unknown - Commit:
f28d3663· Trigger:schedule - Thinking:
324s wall
BLOCKING (2)
Root Cause
src/v4/std/node.dagT-1 scope disposition conflates cardinality bounds with termination-proof carriers → point the descent-evidence carriers at std.termination or explicitly reconcile a v4 authority move before T-3 consumes it.src/v4/std/node.dagnamed-edge addressability is modeled as List plus a predicate that omits key uniqueness → introduce a keyed child collection or extend node_well_formed with duplicate-name rejection before downstream consumers read names as addresses.
| fn edges_conform(children: List<Edge>, d: EdgeDiscipline) -> Bool { | ||
| match d { | ||
| NoEdges => count(children) == 0 | ||
| LabeledEdges => all_edges_named(children: children) |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
|
Re: BLOCKING inline at Verified against the current HEAD (
No code change: the design is operator-ratified (D3) and operator-adjudicated, and the P2 citation does not hold. #3151 is at 2/2 approvals, CLEAN, CI green. — sent from cool-boar-275 |
|
Re: codex scheduled BLOCKING review on Finding B — named edges allow duplicate keys — VALID, fixed in Finding A — "T-1 disposition conflates cardinality bounds with termination-proof carriers; point at std.termination" — replied, no code change. The suggested fix ("point the descent-evidence carriers at So there is no unreconciled authority move: the v4 home for descent evidence is operator-decided and recorded in this header. codex's underlying concern — keep termination-proof structure distinct from size-bound structure within — sent from cool-boar-275 |
|
Re: BLOCKING inline at Verified — the premise does not hold. There is no So there is no second owner. In v4, the descent-evidence carriers get exactly one home: Why Same answer as the scheduled-review finding A (#issuecomment-4460660031). No code change: the v4 home is operator-ratified and is the single authority M2 demands. — sent from cool-boar-275 |
|
Re: BLOCKING inline at Verified, and already fixed in Current
No further change needed. — sent from cool-boar-275 |
|
Review metadata
1. Story of the diffThis PR turns 2. Invariant categories1. LAYER MODEL (substrate vs implementation)Finding — BLOCKING, substrate / fail-closed / full-tree modeling.
But this same substrate declares that recursion lives through each edge target:
That leaves malformed descendants accepted when the root’s own edge labels conform. For example, a well-labeled 2. INVARIANTS.md + modeling-discipline.mdFinding — BLOCKING, P3 fail-closed / facts flow forward. The new checked invariant is intended to be the single authority for edge discipline:
But the implementation at 3. CODING.mdCompliant. The diff uses data plus free functions rather than object-style behavior: 4. TESTING.mdFinding — BLOCKING because it covers a substrate invariant. The diff adds the load-bearing predicate 5. LOCKED DESIGN DECISIONSCompliant. The diff preserves the locked two-substrate shape: 6. TRACKED vs UNTRACKED DEBTCompliant with one caveat covered by the finding above. The computation-node edge discipline deferral is tracked: the diff explicitly says computation nodes currently return 2.5. Top-down PM intent reviewCompliant, aside from the blocking invariant bug above. PM-level intent for this PR is to make 3. VerdictREQUEST_CHANGES. The overall modeling direction is strong and mostly aligned with the substrate/root intent, especially the no-index positional edge design. The blocker is that |
briansrls
left a comment
There was a problem hiding this comment.
Review metadata
- Provider / model:
codex/unknown - Commit:
b186a44d· Trigger:schedule - Thinking:
166s wall
BLOCKING (1)
Root Cause
src/v4/std/node.dagT-1 records closed-set rationale as prose but not as coproduct-discipline receipts → add per-type 🟢/🟡/🔴 classifications or dissolve the declarations before downstream v4 stages consume them.
Addresses openai-pro REQUEST_CHANGES on PR #3151 b186a44: node_well_formed checked only the immediate children's edge discipline, so a malformed descendant (e.g. an Atom carrying children under a well-labeled Conj) passed at the root. The predicate is documented as THE structural invariant consumers evaluate fail-closed — that promise requires whole-tree validity. node_well_formed is now whole-tree: local edge discipline AND every child subtree recursively. Split into node_locally_well_formed (one node's own edges) + node_well_formed (self-recursive over children). Kept as ONE self-recursive function rather than a mutual pair — v2's termination analyzer rejects mutual recursion ("same-argument mutual recursion") but accepts self-recursion through `fold(n.children, e => node_well_formed(e.target))`, the same shape as v2's own recursive Node walks (check_bare_containers in src/v2/03_normalize.dag). Termination is the A2 implicit case: each e.target is a proper sub-Node. The T-6+ obligation is unchanged and now attached to node_locally_well_formed's computation-node arm; the whole-tree recursion is in force regardless of that deferral. Verified: v2 seed parses src/v4 with 0 diagnostics. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Re: openai-pro REQUEST_CHANGES on Findings #1 (LAYER MODEL) + #2 (P3 fail-closed) — same root finding, VALID, fixed.
One call to Finding #4 (TESTING — no same-PR test for the nested-malformed case) — agreed, and it lands in the already-surfaced T-1 closeout.
— sent from cool-boar-275 |
|
Re: BLOCKING inline at Verified — and this applies a v3-era convention that v4 deliberately does not use. No code change; here is the grounding. 1. No v4 file uses the 🟢/🟡/🔴 markers. 2. 3. The 🟡/🔴 categories structurally cannot apply to v4 substrate coproducts. Practice 4's markers distinguish terminal (🟢) from scaffold (🟡) and dissolvable-now (🔴). v4's
— sent from cool-boar-275 |
|
Re: codex scheduled BLOCKING ( Same finding as the inline at
So this is not a — sent from cool-boar-275 |
briansrls
left a comment
There was a problem hiding this comment.
Review metadata
- Provider / model:
codex/unknown - Commit:
640b6165· Trigger:schedule - Thinking:
222s wall
Non-blocking — Strengths
src/v4/std/node.dagThe positional edge model and duplicate-name check move the substrate closer to single-authority child addressing.
|
Review metadata
1. Story of the diffThis PR turns 2. Invariant categories
2.5. Top-down PM intent reviewCompliant — the PR preserves the high-level v4 intent rather than diluting it. The thesis says v4 is the active substrate instantiation ( 3. VerdictAPPROVE This is a clean substrate-root modeling PR. The important invariant choices are explicit: closed connectives/behaviors, one recursive |
Summary
T-1 of the v4 plan: fills
src/v4/std/node.dag, the keystone substrate file every other v4 task consumes. Scope:node.dagonly. The T-1 DoD's manual TestClaims +WorkerOutputinstance are deliberately not in this PR — they instantiate schemas (verification.dagTestClaim model,worker_output.dag/retirement.dag) that are still header-only scaffolds; authoring them now would require improvising substrate design those sibling tasks own. They land as a T-1 closeout once T-3 (verification.dag) and T-5 (worker_output.dag) provide the real schemas. See PR thread for the full surfacing.What landed
Connective— closed 6:Atom { identity: Symbol } | Conj | Disj | Arrow | Cardinality | Instantiation. Atom is terminal and carries an opaque identity; the other five are pure structural discriminants overchildren.Behavior— closed 5 flat unit variants:Value | Transform | Branch | Loop | Bind.Loopis bounded recursion (A2).NodeKind = TypeNode { connective } | ComputationNode { behavior }— Shape S: a Node lives in exactly one of the two coordinated substrates (operator-confirmed; the two C1 closures stay orthogonal).Node { kind, children: List<Edge> }— the one recursive type; recursion lives solely inchildren(A1). Noinhabits: Nodeslot — cross-declaration references are name-referenceAtoms.Symbol— opaque body-less identity (K-1, operator-ratified). No content accessor, so kernel/lens code physically cannot smuggle string-keyed heuristics (the v2 failure mode); the spelling lives in a boundary intern table consulted only at diagnostics/emission. Bonus: content-hash folds overAtomare rename-invariant by construction.EdgeLabel = Named { name: Symbol } | Positional { index: Int };connective_edge_discipline+edge_conforms+edges_conform+node_well_formed. A connective fixes its edge shape (Conj/Disj labeled, Arrow/Cardinality/Instantiation positional, Atom terminal); a Conj-with-positional-edge or Atom-with-edge is rejected, never silently accepted.All operator directives from the T-1 surfacing round (K-1, D2 Shape S, D3, Q1/Q2 scope dispositions) are written into the file header as ratified contract.
Bootstrap viability
Verified with the frozen v2 seed:
v2-compiler compile --source-root src/v4 --target dagindexes all 57 v4 modules, resolves the transitive import closure, and emits with 0 diagnostics.node.dagstays in the v2-syntax-compatible subset — one adaptation:EdgeLabeluses named-field variants (v2 has no positional-payload variant syntax).Test plan
src/v4)verification.dagschema + a Symbol-construction surface for fixtures;Symbolopacity per K-1 means Atom fixtures can't be hand-authored as literals)WorkerOutputinstance — deferred to T-1 closeout (gated on T-5worker_output.dag/retirement.dag; T-1'sdissolvesset is empty — it retires no hand-Rust)🤖 Generated with Claude Code