Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bd8725b
WIP: tidy-wolf-507
briansrls Apr 29, 2026
2fd9eed
WIP: tidy-wolf-507
briansrls Apr 29, 2026
7994d36
chore: apply cargo fmt
briansrls Apr 29, 2026
fd494f6
Merge remote-tracking branch 'origin/main' into session/tidy-wolf-507
briansrls Apr 29, 2026
ef14405
WIP: tidy-wolf-507
briansrls Apr 29, 2026
57bbd40
chore: apply cargo fmt
briansrls Apr 29, 2026
d92b3e0
Merge remote-tracking branch 'origin/main' into session/tidy-wolf-507
briansrls Apr 29, 2026
186c0f8
WIP: tidy-wolf-507
briansrls Apr 29, 2026
4602659
Merge remote-tracking branch 'origin/main' into session/tidy-wolf-507
briansrls Apr 29, 2026
208150a
Merge remote-tracking branch 'origin/main' into session/tidy-wolf-507
briansrls Apr 29, 2026
660e2ab
Merge remote-tracking branch 'origin/main' into session/tidy-wolf-507
briansrls Apr 29, 2026
51fb2b4
WIP: tidy-wolf-507
briansrls Apr 29, 2026
6496a0c
fix(v3): SG-0 ratchet receipt + parse-corpus manifest refresh
briansrls Apr 29, 2026
7f475e0
WIP: tidy-wolf-507
briansrls Apr 29, 2026
2c13dc8
Merge remote-tracking branch 'origin/main' into session/tidy-wolf-507
briansrls Apr 29, 2026
61ad6ea
Merge remote-tracking branch 'origin/main' into session/tidy-wolf-507
briansrls Apr 29, 2026
b18a5ec
chore(v3): re-regen bootstrap on top of merged main
briansrls Apr 29, 2026
b7e6988
Merge remote-tracking branch 'origin/main' into session/tidy-wolf-507
briansrls Apr 29, 2026
66fa643
Merge remote-tracking branch 'origin/main' into session/tidy-wolf-507
briansrls Apr 29, 2026
45f24c9
Merge remote-tracking branch 'origin/main' into session/tidy-wolf-507
briansrls Apr 29, 2026
0ef4771
WIP: tidy-wolf-507
briansrls Apr 29, 2026
fa5bba2
feat(v3): T-Substrate-Lens-Primitive — Lens<C> carrier + Q6.5 widening
briansrls Apr 29, 2026
cdcaecc
WIP: tidy-wolf-507
briansrls Apr 29, 2026
c515b7e
docs(v3): explicitly cover kind_decl resolution gap in SCAFFOLD comment
briansrls Apr 29, 2026
818126b
Merge remote-tracking branch 'origin/main' into session/tidy-wolf-507
briansrls Apr 29, 2026
5bb049c
chore(v3): re-regen bootstrap on top of merged main
briansrls Apr 29, 2026
1eeadb7
Merge remote-tracking branch 'origin/main' into session/tidy-wolf-507
briansrls Apr 29, 2026
d1d2599
chore(v3): re-regen bootstrap on top of merged main (#1188 fix)
briansrls Apr 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,839 changes: 1,426 additions & 1,413 deletions src/v3/compiler/src/bootstrap_generated.rs

Large diffs are not rendered by default.

2,673 changes: 1,343 additions & 1,330 deletions src/v3/compiler/src/bootstrap_generated_without_parse_surface.rs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/v3/compiler/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ mod lane2_stage_2e_parallelism_test;
mod lane3_stage_3b_db1_test;
#[path = "integration/lens_register_correspondence_test.rs"]
mod lens_register_correspondence_test;
#[path = "integration/lens_substrate_carrier_test.rs"]
mod lens_substrate_carrier_test;
#[path = "integration/m0_acceptance.rs"]
mod m0_acceptance;
#[path = "boundary/m1_3_emit_go_test.rs"]
Expand Down
163 changes: 163 additions & 0 deletions src/v3/compiler/tests/integration/lens_substrate_carrier_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
//! **Layer:** integration
//!
//! Acceptance for the T-Substrate-Lens-Primitive first slice
//! (`docs/design-lens-framework.md`, `docs/briefs/r2-substrate-manager.md`).
//!
//! Director-locked option (c) per parent inbox #1130 dispatch:
//! - `Lens<C>` lands in `src/v3/std/lens.dag` with the locked 6-field
//! shape (`name`, `read`, `sequential: Monoid<C>`, `branch`, `iterate`,
//! `validate`).
//! - `Diagnostic.kind` widens from `CompilerDiagnosticKind` to
//! `AnyDiagnosticKind`; the Layer-1 closed sum stays unchanged.
//! - `LensInstanceKindWitness` is decl-only (no payload value field)
//! until refinement/dependent typing lands; this is the explicit
//! substrate gap receipt.

use std::collections::HashSet;
use v3_compiler::dag::{Dag, DeclarationId, TypeConnective};
use v3_compiler::generated_full_bootstrap_dag;

fn conj_field_labels(dag: &Dag, name: &str) -> Vec<String> {
let decl = dag
.declaration_by_name(name)
.unwrap_or_else(|| panic!("`{name}` missing from full bootstrap"));
match &decl.connective {
TypeConnective::Conj { children } => children.iter().map(|f| f.label.clone()).collect(),
other => panic!("`{name}` is not a Conj: {other:?}"),
}
}

fn disj_variant_labels(dag: &Dag, name: &str) -> Vec<String> {
let decl = dag
.declaration_by_name(name)
.unwrap_or_else(|| panic!("`{name}` missing from full bootstrap"));
match &decl.connective {
TypeConnective::Disj { variants } => variants.iter().map(|v| v.label.clone()).collect(),
other => panic!("`{name}` is not a Disj: {other:?}"),
}
}

fn decl_id_by_name(dag: &Dag, name: &str) -> DeclarationId {
dag.declaration_by_name(name)
.unwrap_or_else(|| panic!("`{name}` missing from full bootstrap"))
.id
}

#[test]
fn lens_carrier_has_locked_six_field_shape() {
let dag = generated_full_bootstrap_dag();
let labels: HashSet<String> = conj_field_labels(&dag, "Lens").into_iter().collect();
let expected: HashSet<&str> = [
"name",
"read",
"sequential",
"branch",
"iterate",
"validate",
]
.into_iter()
.collect();
let actual: HashSet<&str> = labels.iter().map(String::as_str).collect();
assert_eq!(
actual, expected,
"Lens<C> field set diverged from Director-locked 6-field shape"
);
}

#[test]
fn diagnostic_kind_widened_to_any_diagnostic_kind() {
let dag = generated_full_bootstrap_dag();
let any_id = decl_id_by_name(&dag, "AnyDiagnosticKind");

let diag_decl = dag
.declaration_by_name("Diagnostic")
.expect("Diagnostic missing from full bootstrap");
let kind_field = match &diag_decl.connective {
TypeConnective::Conj { children } => children
.iter()
.find(|f| f.label == "kind")
.expect("Diagnostic missing `kind` field"),
other => panic!("Diagnostic is not a Conj: {other:?}"),
};
assert_eq!(
kind_field.ty, any_id,
"Diagnostic.kind must point at AnyDiagnosticKind, not the Layer-1 closed sum"
);
}

#[test]
fn compiler_diagnostic_kind_closed_sum_unchanged() {
let dag = generated_full_bootstrap_dag();
let variants: HashSet<String> = disj_variant_labels(&dag, "CompilerDiagnosticKind")
.into_iter()
.collect();
let expected: HashSet<&str> = [
"TokenizerError",
"ParseError",
"TypeMismatch",
"UnitMismatch",
"ArityMismatch",
"ResolveError",
"NominalOpacityViolation",
]
.into_iter()
.collect();
let actual: HashSet<&str> = variants.iter().map(String::as_str).collect();
assert_eq!(
actual, expected,
"CompilerDiagnosticKind closed sum changed — Layer-1 must stay locked; \
lens-instance kinds enter via Layer-2 LensInstanceKindWitness, NOT \
by extending this sum (anti-bridge invariant per Q6.5)"
);
}

#[test]
fn any_diagnostic_kind_has_two_layer_constructors() {
let dag = generated_full_bootstrap_dag();
let variants: HashSet<String> = disj_variant_labels(&dag, "AnyDiagnosticKind")
.into_iter()
.collect();
let expected: HashSet<&str> = ["CompilerKind", "LensInstanceKind"].into_iter().collect();
let actual: HashSet<&str> = variants.iter().map(String::as_str).collect();
assert_eq!(
actual, expected,
"AnyDiagnosticKind must have exactly two constructors — Layer-1 \
CompilerKind(CompilerDiagnosticKind) and Layer-2 \
LensInstanceKind(LensInstanceKindWitness)"
);
}

#[test]
fn lens_instance_kind_witness_payload_intentionally_absent() {
// Layer-2 substrate gap receipt (per parent #1130 dispatch + Q6.5
// §State-space discipline). Today's .dag grammar cannot express
// `payload: <inhabits kind_decl.payload>` — a refinement-type-on-
// sibling-field shape. The flat alternative (free `TypeShape`
// payload coordinate) ratifies the very illegal state Q6.5 rejects:
// `(Lens<TenantFlow>, "WrongName", payload-of-different-shape)`.
//
// Director-approved option (c): land Layer-2 kind identity and
// namespace authority via `LensInstanceKindWitness { kind_decl }`
// alone; the structured payload value is intentionally NOT carried
// through the substrate until dependent-field typing or substrate
// inhabitance witnesses lower without hand-Rust scaffolding.
//
// This test pins the gap. When that grammar feature lands and
// `LensInstanceKindWitness` grows a checked `payload` field, this
// test fails loudly and forces the dissolution-trigger comment in
// `diagnostics.dag` to retire in lock-step.
let dag = generated_full_bootstrap_dag();
let labels: HashSet<String> = conj_field_labels(&dag, "LensInstanceKindWitness")
.into_iter()
.collect();
let expected: HashSet<&str> = ["kind_decl"].into_iter().collect();
let actual: HashSet<&str> = labels.iter().map(String::as_str).collect();
assert_eq!(
actual, expected,
"LensInstanceKindWitness field set drifted. Adding a `payload` \
field is a substantive change — verify the dependent-field \
typing trigger in `diagnostics.dag` has actually closed before \
landing it (do not pretend payload is enforced via a free \
TypeShape coordinate; that is the Q6.5-rejected illegal state)."
);
}
3 changes: 2 additions & 1 deletion src/v3/compiler/tests/integration/parse_corpus_manifest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ src/v3/std/algebra.dag 42 303630 8be5b86cc9520bc3
src/v3/std/clean_emission.dag 15 23867 e7bc1e6145f4781e
src/v3/std/computation.dag 18 36754 8023f388c3fb0918
src/v3/std/computation_model.dag 14 22953 20e458fe097d175a
src/v3/std/diagnostics.dag 6 7982 6dc35615cc265b02
src/v3/std/diagnostics.dag 10 12179 bc414c493551b464
src/v3/std/dimensions.dag 21 40239 d595746d2bda22f6
src/v3/std/effects.dag 53 97984 1acdbeaa68acfd2e
src/v3/std/emit_model.dag 34 65593 49cc4eb1f1faadcd
src/v3/std/extdeps_bootstrap_fixtures.dag 4 4912 e2b6d96f5900a70a
src/v3/std/induction.dag 56 88794 546f74c63c189c50
src/v3/std/lens.dag 6 9852 28d5539a5b28716e
src/v3/std/list.dag 19 40269 8c648d4a4fd05c21
src/v3/std/lookup.dag 5 4734 f97d4e536b675b1b
src/v3/std/parse_surface.dag 18 99510 b73114d5b178303d
Expand Down
12 changes: 12 additions & 0 deletions src/v3/compiler/tests/integration/sg0_census_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,18 @@ const EXPECTED_HAND_AUTHORED_TEST: &[&str] = &[
"src/v3/compiler/tests/integration/lane2_stage_2e_parallelism_test.rs",
"src/v3/compiler/tests/integration/lane3_stage_3b_db1_test.rs",
"src/v3/compiler/tests/integration/lens_register_correspondence_test.rs",
// T-Substrate-Lens-Primitive (R2 Substrate, first slice): Director-
// approved hand-Rust acceptance for `Lens<C>` substrate carrier and
// Q6.5 two-layer diagnostic-kind authority. Five structural claims
// over the regenerated bootstrap Dag — Lens<C> 6-field shape,
// Diagnostic.kind widened to AnyDiagnosticKind, Layer-1 closed sum
// unchanged, AnyDiagnosticKind two-constructor shape, and Layer-2
// payload-intentionally-absent gap receipt. Dispatch (#1130 +
// `docs/design-lens-framework.md` Q6.5) accepted "focused structural
// acceptance tests" rather than a parallel testgen harness.
// Dissolves into .dag `TestClaim` form when testgen covers reflected-
// Dag structural assertions over std/ types.
"src/v3/compiler/tests/integration/lens_substrate_carrier_test.rs",
"src/v3/compiler/tests/integration/m0_acceptance.rs",
"src/v3/compiler/tests/integration/m1_3_lens_cost_test.rs",
"src/v3/compiler/tests/integration/m1_3_lens_unused_parameters_test.rs",
Expand Down
89 changes: 87 additions & 2 deletions src/v3/std/diagnostics.dag
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
module v3.std.diagnostics

import std.list { List }
import v3.std.substrate { SourceSpan }
import v3.spec.v3_l1 { DeclarationRef }
import v3.std.substrate { SourceSpan, TypeShape }

// 🟡 SCAFFOLD. Mirrors the compiler's native diagnostic taxonomy for
// the staged v3 diagnostics surface. Kept distinct from
// `std.verification.DiagnosticKind` to avoid introducing a second
// imported top-level declaration with the same name during bootstrap.
// Dissolution trigger: reflected diagnostics or a shared diagnostic
// kind authority once the staged/bootstrap-local split disappears.
//
// Layer 1 (per `docs/design-lens-framework.md` Q6.5 two-layer
// authority): Substrate-Manager-owned closed sum of compiler-primitive
// diagnostic kinds. Layer-2 lens-instance kinds live separately under
// `DiagnosticKindDecl` / `LensInstanceKindWitness` below — they MUST
// NOT be added as variants here. Adding a Layer-1 kind is rare,
// design-locked, and requires SCAFFOLD-note acknowledgment of where
// the diagnostic surfaces.
type CompilerDiagnosticKind
= TokenizerError
| ParseError
Expand All @@ -30,11 +39,87 @@ type Correction {
new_source: String
}

// Layer 2 lens-instance diagnostic-kind declaration (per
// `docs/design-lens-framework.md` Q6.5). A `DiagnosticKindDecl`
// appears inside the `diagnostic_kinds` list of an `inhabits Lens<C>`
// declaration; the containing inhabitance IS the owning lens (P2
// single-authority via structural containment, NOT via a duplicated
// `lens_instance` field). The decl's `name` MUST NOT collide with any
// `CompilerDiagnosticKind` Layer-1 variant name (anti-shadowing
// protocol per Q6.5 §Name-collision protocol).
//
// 🟡 TRANSITIONAL. Owner-by-containment is the structural authority,
// not a re-declared field. The decl name is a String today; refines
// to a typed `KindName` namespace-scoped to the parent lens once the
// substrate exposes namespace-typed identifiers.
type DiagnosticKindDecl {
name: String
payload: TypeShape
}

// Layer 2 lens-instance kind witness (per Q6.5 §Substrate change
// required). A structural pointer to a declared `DiagnosticKindDecl`.
//
// 🟡 SCAFFOLD coproduct (single-arm record). Pattern 1 (per-call
// payload typing) fails because the payload's TypeShape is dependent
// on the runtime-resolved `kind_decl.payload` field — `.dag` grammar
// today cannot express `payload: <inhabits kind_decl.payload>`
// (refinement-type-on-sibling-field). Pattern 2 (collapse to a flat
// `{ kind_decl, payload_kind_shape }` record with a free `TypeShape`
// payload coordinate) ratifies exactly the parallel-authority illegal
// state Q6.5's §State-space discipline rejected — three independent
// coordinates (lens / name / payload-shape) that admit
// `(Lens<TenantFlow>, "WrongName", payload-of-different-shape)`.
// Pattern 3 is the dissolution path: when refinement/dependent field
// typing OR declaration-shaped inhabitance witnesses land in the .dag
// substrate, this carrier grows a checked `payload` value field
// constrained to inhabit the shape `kind_decl.payload` names; until
// then the witness is decl-only — Layer-2 kind identity and
// namespace authority are present, but the structured payload value
// is intentionally NOT carried through the substrate. Trigger:
// dependent-field typing or substrate inhabitance witnesses lower
// without hand-Rust scaffolding.
//
// Note on `kind_decl` typing: bare `DeclarationRef` admits any
// declaration. The structural constraint (\"must resolve to a
// `DiagnosticKindDecl` whose parent is the owning `Lens<C>`
// inhabitance\") is checked fail-closed at the runtime resolution
// boundary — same residual class as `PatternRealization` (`emit_model.dag`
// lines 140–152, where `empty_variant`/`cons_variant` admit any
// declaration but are validated as variants-of-target at parse time)
// and `MethodTemplateContract.dag_method` (`emit_model.dag:371`).
// Refining to `DeclarationRef<DiagnosticKindDecl>` is part of the
// SAME dissolution trigger above — substrate-level
// refinement-typing-on-DeclarationRef is the mechanism that closes
// both the payload-typing gap and the kind-decl resolution gap in
// one move.
type LensInstanceKindWitness {
kind_decl: DeclarationRef

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.

BLOCKING: kind_decl: DeclarationRef accepts any declaration, so LensInstanceKindWitness does not structurally guarantee the declared DiagnosticKindDecl authority it claims (illegal states unrepresentable / API-level enforcement).

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.

Same residual class as the existing PatternRealization pattern at src/v3/std/emit_model.dag lines 140–152 and (recently merged) MethodTemplateContract.dag_method: DeclarationRef at emit_model.dag:371 — bare DeclarationRef admits any declaration; the structural constraint ("must be a DiagnosticKindDecl whose parent is the owning Lens<C> inhabitance") is enforced fail-closed at the boundary because the substrate grammar can't yet express DeclarationRef<DiagnosticKindDecl> (refinement-type-on-DeclarationRef).

Per parent-inbox #1130 dispatch (verbatim) on the option (c) lock: "For Q6.5, do not encode a fake dependent payload. Add DiagnosticKindDecl and AnyDiagnosticKind ... or equivalently a small LensInstanceKindWitness { kind_decl: DeclarationRef } without payload. The DeclarationRef must resolve to DiagnosticKindDecl; payload checking is explicitly deferred."

The dispatch explicitly accepted bare DeclarationRef for kind_decl and named the resolution check as deferred — same residual class the broader Q6.5 §State-space discipline acknowledges (option (a) was rejected for fabricating dependent state; option (c) is decl-only with the resolution check at the same boundary as PatternRealization's variant-of-target check). The 🟡 SCAFFOLD comment at diagnostics.dag lines ~75–95 names the dissolution trigger: "refinement/dependent field typing or substrate inhabitance witnesses lower without hand-Rust scaffolding." Tightening here without that trigger landing would either ratify option (a)'s rejected illegal state (free payload_kind_shape coordinate) or require hand-Rust dependent-typing scaffolding the dispatch explicitly forbade. — sent from tidy-wolf-507

}

// Two-layer diagnostic-kind parent (Q6.5). `Diagnostic.kind` widens
// from `CompilerDiagnosticKind` to this sum so a single `Diagnostic`
// value can carry either Layer-1 (substrate-owned closed sum) or
// Layer-2 (lens-namespace-scoped) kinds without re-introducing a
// cross-manager handoff for lens-instance kind authoring.
//
// Anti-bridge invariant (Q6.5): adding a lens-instance kind MUST NOT
// extend `CompilerDiagnosticKind` — Layer-2 kinds enter via
// `LensInstanceKind(LensInstanceKindWitness)` exclusively. The closed
// Layer-1 sum stays the authority for compiler-primitive kinds only.
type AnyDiagnosticKind
= CompilerKind(CompilerDiagnosticKind)
| LensInstanceKind(LensInstanceKindWitness)

// 🟡 SCAFFOLD until reflected diagnostics replace the compiler's
// native enum. The record shape is the authority for consumers that
// only need the diagnostic carrier, including `fixes`.
//
// `kind: AnyDiagnosticKind` carries either Layer-1 (closed-sum
// compiler-primitive) or Layer-2 (lens-instance, namespace-scoped)
// kinds per Q6.5 two-layer authority.
type Diagnostic {
kind: CompilerDiagnosticKind
kind: AnyDiagnosticKind
span: SourceSpan
message: String
fixes: List<Correction>
Expand Down
77 changes: 77 additions & 0 deletions src/v3/std/lens.dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// std.lens — `Lens<C>` substrate carrier (Director-locked 6-field shape).
//
// 🟡 TRANSITIONAL. First substrate slice for the lens framework
// (`docs/design-lens-framework.md`). This carrier authors the structural
// shape generic compositional analyses fold over the 5 L1 behaviors;
// `fold_lens<C>: Lens<C> → Dag → DimensionReport<C>` and the four worked
// instances (complexity / tenant-flow / IFC / cost-lens) consume this
// shape in subsequent lanes (R3-T-CostLens-Composition,
// R2-Evaluator PR-A..E, T-LensAPI rescope).
//
// The `Lens<C>` carrier deliberately reuses existing substrate types —
// `Witness<C>` / `OptionalDiagnostic` / `DimensionReport<C>` from
// `dimensions.dag`, `Monoid<C>` from `dsl/std/algebra.dag`, `Diagnostic`
// from `diagnostics.dag` — rather than authoring parallel
// representations (per `feedback_parallel_representation_debt`).
//
// Home: `src/v3/std/` (not `dsl/std/`). The carrier references v3-only
// substrate types (`Dag`, `Behavior`, `LoopBound`, `DeclarationRef`),
// so `dsl/std/lens.dag` would need import inversions. Convergence
// trigger: when v3 substrate types graduate into shared `dsl/std/`,
// this file moves to `dsl/std/lens.dag` alongside `dsl/std/algebra.dag`.

module v3.std.lens

import std.list { List }
import std.algebra { Monoid }
import std.substrate { Dag, Behavior, LoopBound }
import v3.std.dimensions { Witness, OptionalDiagnostic, DimensionReport }

// 🟢 TERMINAL at the lens-primitive scope. The six fields are the
// irreducible contract a generic compositional analysis publishes:
//
// - `name` — human-facing dimension identifier; populates
// `DimensionReport.dimension_name`.
// - `read` — per-Behavior cost-basis extraction. Returns
// `Witness<C>` (NOT `C`) so a missing per-Behavior
// substrate fact surfaces as `Violates` rather than
// fabricating a default carrier (fail-closed).
// - `sequential` — `Monoid<C>` for `BindNode` composition. Structural
// inhabitance over `Monoid<C>` (`dsl/std/algebra.dag`)
// means the monoid law (associativity + identity) is
// structurally enforceable, not merely documented.
// Replaces the prior parallel `compose: (C,C)->C` +
// `unit: C` field pair (Director directive 2026-04-28
// + gpt-5-5-pro Finding #4: same drift shape as
// `AnalysisDimension<Carrier>` already carried).
// - `branch` — exclusive-choice composition for `BranchNode`. NOT
// a monoid op; only one arm runs at runtime, so
// composition is `max/join` over arms. No identity
// element is required (no "no-op branch").
// - `iterate` — bounded iteration for `LoopNode`. Takes the body
// cost and the loop's `LoopBound` and returns the
// loop-iteration cost.
// - `validate` — aggregate side-condition check after the fold has
// composed all per-Behavior witnesses. Returns
// `OptionalDiagnostic` (NOT `Witness<C>`) because by
// this point there is no single Behavior to attach a
// per-node `at:` reference to; aggregate-level
// diagnostics use `Diagnostic.span`. The `Dag`
// parameter carries program-structure context
// (workflow capability grants, sink declarations,
// etc.) that side-conditions look up structurally.
//
// Why three composition operations and not four (sequential / branch /
// iterate, no parallel): v3 has three composition primitives among the
// 5 L1 behaviors — `BindNode`, `BranchNode`, `LoopNode`. There is no
// `ParallelNode`; auto-parallelism is *emergent* from dependency-graph
// analysis on `BindNode` sequences, not a declared substrate primitive.
// The lens framework declares operations over the actual L1 behaviors.
type Lens<C> {
name: String
read: fn(Dag, Behavior) -> Witness<C>
sequential: Monoid<C>
branch: fn(C, C) -> C
iterate: fn(C, LoopBound) -> C
validate: fn(Dag, C) -> OptionalDiagnostic
}
Loading