Skip to content

M2 + CM: structural type knowledge, concept modeling, ownership threading - #322

Merged
briansrls merged 24 commits into
mainfrom
cm-track
Apr 6, 2026
Merged

briansrls merged 24 commits into
mainfrom
cm-track

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Summary

  • M2 (type knowledge dissolution): Replace ad-hoc type-name comparisons with structural predicates (L1 32→30), add normalization gate for bare containers, gate empty list/map literals on expected-type context, extract is_fully_resolved, thread expected types to formal params and fold init, add CallableOf to AlgebraTypeTemplate, make clone semantics data-driven via CloneTemplates, consolidate transport identity via kind constants, eliminate bare_map_node from method registry
  • CM (compiler concept modeling): Precompute TypedItemKind, ServiceFieldSet, FunctionSignature, and ResourceDefinition on EmitGraphInfo — eliminates ad-hoc structural interrogation across all three emit backends
  • Ownership threading: Thread pre-computed OwnershipProof list from compile through emit, eliminating duplicate analyze_ownership calls in the Rust emitter
  • Performance: Eliminate O(N²) HashMap cloning in fold accumulators via Rc::try_unwrap, fix O(n²) block inference

Verification

  • 289 tests pass, 0 failures
  • 0 bootstrap diagnostics (strict_compile_diagnostic_count)
  • L1 ratchet at 30 (within limit)
  • Clippy clean

Test plan

  • cargo test -p v2-compiler-tests — 289 pass
  • cargo test -p v2-compiler-tests strict_compile_diagnostic_count -- --ignored — 0 diagnostics
  • scripts/l1-ratchet.sh --check — L1 30 ≤ 30
  • cargo clippy --all-targets -- -D warnings — clean
  • Review CM precomputation correctness (EmitGraphInfo fields)
  • Verify ownership threading produces identical output

🤖 Generated with Claude Code

briansrls and others added 5 commits April 5, 2026 15:43
… in emit

Add TypedItemKind enum to EmitGraphInfo with 10 variants (Struct, Enum,
TypeAlias, TypeDecl, Function, TransportFunction, DataDef, ServiceDef,
ResourceDef, Unhandled). classify_typed_item runs once during infer and
stores results in item_kinds map. All three emit backends now dispatch on
precomputed kind instead of re-interrogating Node properties.

- Add classify_typed_item + lookup_item_kind + helper predicates to emit_info.dag
- Move build_item_kinds to infer.dag (avoids circular dep with infer_items)
- Replace ~40 ad-hoc classification branches across emit_rust/go/python/generic
- Extract build_fn_emit_info helper in emit_rust for ownership threading
- 289 tests pass, 0 diagnostics, clippy clean

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…gation in emit

ServiceFieldSet (has_rest, has_shell, has_file, has_auth) is now computed once
during inference via classify_service_fields and stored on EmitGraphInfo. All
three emit backends (Rust, Go, Python) look up the precomputed struct via
lookup_service_fields instead of calling compute_service_fields at each use site.

Removes compute_service_fields and service_has_* helpers from 05_emit.dag.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…dy extraction in emit

FunctionSignature precomputes params, return_type, body, and uses during
inference so emit backends read structured facts instead of reaching into
raw Node fields. All three emit backends (Rust, Go, Python) now use
lookup_function_signature + sig fields instead of item.params/rt_type/body.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ility inspection in emit

Add CapabilitySignature and ResourceDefinition types to EmitGraphInfo.
classify_resource_definition extracts capability name, params, and
return_type during reconcile so all three emit backends (Rust, Go,
Python) read precomputed facts instead of reaching into Node children.

Dispatch sites now use lookup_resource_definition match, and
emit_resource_def / emit_capability_method take the precomputed types
instead of raw Nodes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…alysis

Ownership analysis was running twice: once in compile.dag for diagnostics,
then again in emit_rust via build_ownership_index which re-called
analyze_ownership per function. Now the pre-computed proofs from compile
flow through emit_from_artifact_plan → emit_artifact → emit_rust, and
build_ownership_index simply indexes the existing proofs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 841276f865

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/v2/stage0/src/v2_compiler_infer.rs Outdated
}

pub fn build_item_kinds(modules: Rc<Vec<Rc<TypedModule>>>) -> Rc<HashMap<String, TypedItemKind>> {
modules.iter().cloned().fold(v2_rt::rc_empty_map::<TypedItemKind>(), |acc: Rc<HashMap<String, TypedItemKind>>, tm: Rc<TypedModule>| tm.items.clone().iter().cloned().fold(acc.clone(), |inner: Rc<HashMap<String, TypedItemKind>>, item: Rc<Node>| v2_rt::rc_map_insert(inner.clone(), item.name.clone(), classify_typed_item(item.clone()))))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Key emit graph metadata by module-qualified name

build_item_kinds indexes metadata with item.name alone, and the same unqualified key is then used by build_service_fields, build_function_signatures, and build_resource_definitions; this causes cross-module collisions because top-level item names are not globally unique (e.g. AuthScheme exists in both dsl/std/cloud.dag and dsl/std/types.dag). After this change, emitters rely on lookup_item_kind/lookup_* for every item, so a later module can overwrite an earlier module’s classification/signature and make the earlier item emit incorrectly or disappear.

Useful? React with 👍 / 👎.

@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 (INVARIANTS: 3, MODELING: 1+/1-, ROADMAP: 0✓/1!)

INVARIANTS — Violations (3)

MODELING — Strengths

  • src/v2/04_emit_info.dag TypedItemKind is the right closed sum for item classification, so struct/enum and fn/transport-fn dispatch now composes as data instead of repeated connective/use checks.

MODELING — Improvements

  • src/v2/04_emit_info.dag FunctionSignature, ServiceFieldSet, and ResourceDefinition should be attached by structural item reference or carried on the item itself rather than re-looked-up through Map<String, ...>, so the boundary can actually move toward M4 structural identity.

ROADMAP — Incomplete

  • M2 boundary sufficiency: The new emitter-facing fact tables still rely on item-name lookups and miss defaults, so emit is still compensating for an insufficient boundary instead of consuming a fail-closed structural contract.

ROADMAP — Unclaimed

  • CM semantic fact precomputation: This diff does advance the CM direction by precomputing item/service/function/resource facts in EmitGraphInfo, but ROADMAP.md was not updated to record that partial milestone progress.

The PR moves several emitter decisions upstream, but it still introduces new name-keyed shadow authorities and fail-open lookup paths that break the repo’s structural-identity and fail-closed rules.

Comment thread src/v2/04_infer.dag Outdated
)
}

fn build_item_kinds(modules: List<TypedModule>) -> Map<String, TypedItemKind> {

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.

Invariant violation: build_item_kinds/build_service_fields/build_function_signatures/build_resource_definitions index new emit authorities by item.name, which keeps the reconcile→emit boundary name-driven instead of structural and violates No duplicate representations and Boundary sufficiency.

Comment thread src/v2/04_emit_info.dag Outdated
}

// Lookup precomputed service fields from EmitGraphInfo.
fn lookup_service_fields(emit_info: EmitGraphInfo, name: String) -> ServiceFieldSet {

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.

Invariant violation: lookup_service_fields fabricates ServiceFieldSet { false, false, false, false } on miss, so emit silently omits required service config instead of failing closed, violating No fallbacks that fabricate.

Comment thread src/v2/05_emit_go.dag Outdated
} else if (kind == TypedItemTypeDecl) {
""
} else if (kind == TypedItemTransportFunction) {
match lookup_function_signature(emit_info: emit_info, name: item.name) {

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.

Invariant violation: The new None => "" branch silently drops a function definition when function_signatures misses instead of producing a diagnostic, violating No fallbacks that fabricate.

The hand-edited scaffold_for_target call doesn't match what the
compiler generates from the .dag source. Use the literal ".go" that
the code generator produces.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@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 (INVARIANTS: 5, MODELING: 1+/1-, ROADMAP: 0✓/1!)

INVARIANTS — Violations (5)

MODELING — Strengths

  • src/v2/04_emit_info.dag TypedItemKind is a properly closed sum, so moving Struct/Enum and Function/TransportFunction classification to reconcile is better layering than re-deriving those cases in each backend.

MODELING — Improvements

  • src/v2/04_emit_info.dag FunctionSignature, ServiceFieldSet, and ResourceDefinition are still stored behind Map<String, ...> identity-proxy tables, so the model duplicates Node authority instead of composing from structural references as M4/M9 require.

ROADMAP — Incomplete

  • M2 acceptance: The new boundary still fabricates on misses (TypedItemUnhandled, empty strings, false service-field defaults), so emit is not yet consuming a fully fail-closed structural contract.

ROADMAP — Unclaimed

  • CM concept categories (item classification / transport-service / function signatures / property-resource): This diff precomputes exactly those semantic facts in EmitGraphInfo, but ROADMAP.md does not record the advance.

The PR moves useful classification work upstream, but it still relies on sentinel/name proxies and adds new fail-open miss paths, so the reconcile→emit boundary remains structurally unsound.

Comment thread src/v2/04_emit_info.dag Outdated
| TypedItemResourceDef
| TypedItemUnhandled

// Check if a return type indicates a type alias (not Unit).

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.

Invariant violation: is_type_alias_return_node decides alias-vs-decl by special-casing the string name "Unit", which keeps item classification name-driven instead of structural and violates Boundary sufficiency / Heuristics indicate lost structure.

Comment thread src/v2/04_emit_info.dag Outdated
} else {
TypedItemUnhandled
}
}

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.

Invariant violation: lookup_item_kind collapses a missing boundary fact into TypedItemUnhandled, a fabrication fallback that violates M5 / No fallbacks that fabricate.

Comment thread src/v2/05_emit_go.dag
}
} else if (kind == TypedItemDataDef) {
emit_go_data_def(name: item_text, type_node: item.type_annotation.value, value: item.body.value, registry: registry, scope: scope)
} else if (kind == TypedItemServiceDef) {

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.

Invariant violation: emit_go_typed_item returns "" when lookup_resource_definition misses, silently deleting a resource interface instead of failing closed, violating No fallbacks that fabricate.

Comment thread src/v2/05_emit_python.dag
emit_py_enum_from_children(name: item_text, children: item.children, env: env)
} else if (kind == TypedItemTypeAlias) {
concat(item_text, " = ", emit_node_type(n: rt_type(n: item), target: Python))
} else if (kind == TypedItemTypeDecl) {

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.

Invariant violation: emit_py_typed_item turns missing precomputed function/resource facts into "", silently dropping definitions instead of diagnosing the broken boundary, violating No fallbacks that fabricate.

Comment thread src/v2/05_emit_rust.dag Outdated
movable: fn_movable,
owned_bindings: empty_map()
} else if (kind == TypedItemTransportFunction) {
match lookup_function_signature(emit_info: emit_info, name: item.name) {

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.

Invariant violation: emit_typed_item turns missing precomputed function/resource facts into "", silently dropping emitted items instead of producing a diagnostic, violating No fallbacks that fabricate.

@briansrls

briansrls commented Apr 6, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I’ve narrowed the review to a refactor that centralizes item classification and ownership into precomputed EmitGraphInfo/emit-info facts across infer, emit, and all backends. I’m checking whether those facts remain exact and authoritative, especially around stale or lookup-by-default paths that could silently misclassify output instead of failing.


View conversation

- Add TypeSummary/EnumRepr/lookup_emit_type_summary imports to Go and
  Python emit .dag files so all three backends read precomputed unit_only
  from EmitGraphInfo instead of re-walking enum children at render time.
- Use match on Bool instead of if(not ...) for .dag compatibility.
- Reconcile stage0 .rs files after merge with main: cm-track types
  (TypedItemKind, FunctionSignature, etc.) as base, main's fold_eligible
  and ownership features layered on top.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@briansrls

briansrls commented Apr 6, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I reviewed the uploaded diff. Biggest takeaways:

  1. Blocker: ownership threading is only API plumbing right now.

compile.dag now threads ownership into emit_artifact(...) / emit_from_artifact_plan(...), and the Rust emitter signature changed to accept it, but src/v2/05_emit_rust.dag immediately ignores that input and recomputes ownership from typed.modules:

  • uploaded diff lines 1196–1199: fn emit_rust(..., ownership: List<OwnershipProof>) followed by let ownership = build_ownership_results(modules: typed.modules)
  • stage0 mirror lines 2454–2458 do the same
  1. So the new boundary fact is not actually consumed by the downstream stage. Rust also still rebuilds EmitGraphInfo from modules instead of consuming the graph’s existing emit info. That is exactly the pattern INVARIANTS warns about: boundary facts are only valid if they are exact and actually used as the authority downstream; emit is supposed to translate annotated facts, not redetermine them. The roadmap also already calls out “emit consumes, not rediscovers” and “ownership as pipeline output” as the direction. INVARIANTS

Pasted markdown (2)

ROADMAP

I would block on this. The fix is to start from typed.emit_graph_info and derive the ownership indexes from the passed-in proofs, or pass the already-built ownership result instead of recomputing inside emit.

  1. Blocker: several new lookup paths fail open instead of fail closed.

The new fact tables are a good idea, but the miss path is too permissive:

  • lookup_service_fields(...) returns all-false defaults at diff lines 140–144
  • Go returns "" on missing function/resource facts at 674–698
  • Python returns "" on missing function/resource facts at 953–977
  • Rust returns "" on missing function/resource facts at 1324–1350
  • enum rendering in all three backends falls back to unit_only = false if the summary lookup misses:
    • Go 664–666
    • Python 943–945
    • Rust 1288–1290
  1. That means a broken boundary can silently drop a function/resource, silently omit service init fields, or silently flip enum rendering instead of surfacing an error. INVARIANTS is explicit that compiler stages should fail closed and not fabricate “valid-looking” output when facts are missing. INVARIANTS

Pasted markdown

I would turn these into diagnostics / compile_error!-style failures, not empty strings or default booleans.

  1. Modeling concern: ResourceDefinition looks lossy for capability names.

In src/v2/04_emit_info.dag, CapabilitySignature stores name: c.name (diff lines 165–170). Then the backends switched from rendering capability names with authored_name(...) to rendering cap.name directly:

  • Go: old authored_name(..., cap_node) replaced by cap.name at 821–830
  • Python: same at 1099–1102
  • Rust: same at 1491–1503
  1. If authored/source text matters for rendering, this new fact table dropped a witness that the emitter used before. That makes the boundary less exact than the original node. I am not certain this is user-visible in every case, but it is a real regression risk. I would prefer CapabilitySignature to carry either the original capability node or authored text/source-span alongside the structural fields.
  2. Possible collision risk: new emit-info tables are keyed by bare item.name.

build_item_kinds, build_service_fields, build_function_signatures, and build_resource_definitions all fold across all modules into Map<String, ...> keyed only by item.name (diff lines 2991–3056 in 04_infer.dag).

If top-level duplicate names across modules are legal, these tables will alias and later modules will overwrite earlier ones. If the compiler already guarantees global uniqueness here, then this is fine; if not, these should be module-qualified keys.

What looks good:

  • Moving TypedItemKind, ServiceFieldSet, FunctionSignature, and ResourceDefinition into 04_emit_info.dag, then building them once in 04_infer.dag, is the right direction. That is much better than each backend re-scanning raw nodes independently.
  • The enum change is especially good: Go/Python/Rust now consume EnumRepr { unit_only } instead of re-deriving “simple enum vs tagged union” from child shape. That is a real compositional-model improvement.
  • The stage0 mirrors were updated consistently.

On roadmap review: ROADMAP.md is not modified in this diff, so there is no roadmap text change to review. Directionally, though, this PR fits the existing roadmap work on boundary migration and ownership-as-pipeline-output, but it does not complete either one because Rust still recomputes both emit info and ownership internally. Pasted markdown (2)

ROADMAP

If I were leaving PR comments, I’d mark #1 and #2 as merge blockers, and #3 as a strong follow-up / likely bug depending on authored-name semantics.


View conversation

@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 (INVARIANTS: 4, MODELING: 1+/2-, ROADMAP: 0✓/0!)

INVARIANTS — Violations (4)

MODELING — Strengths

  • src/v2/04_emit_info.dag FunctionSignature, ResourceDefinition, and ServiceFieldSet move emitter needs into explicit boundary products, which is the right M2 direction because the facts are computed once and consumed downstream.

MODELING — Improvements

  • src/v2/04_emit_info.dag TypedItemKind duplicates ItemKind plus type/transport facts as a second flat taxonomy; composing the existing authorities would model the domain more faithfully.
  • src/v2/04_emit_info.dag ServiceFieldSet is effectively a small capability powerset/lattice, so if it needs merges or comparisons it should reuse algebraic/set grounding instead of four ad-hoc Bool fields.

ROADMAP — Unclaimed

  • M2: Boundary Sufficiency / CM: Compiler Concept Modeling: The PR adds new emit-boundary fact tables and partial ownership threading for these tracks, but ROADMAP.md was not updated to record that partial progress.

The PR moves emit toward explicit boundary facts, but several new consumers still fail open and the ownership-threading change does not land end-to-end.

Comment thread src/v2/05_emit_rust.dag
}

// =========================================================================
// Entry point -- Rust target

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.

Invariant violation: The new ownership parameter adds a boundary that emit_rust still does not use as authority, so this introduces speculative metadata and violates Explicit boundary contracts / No parallel implementations.

Comment thread src/v2/05_emit_rust.dag Outdated
} else { [] }
None => []
}
)

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.

Invariant violation: collect_workflow_funcs turns a missing function_signatures fact into [], so workflow default validation silently skips broken functions instead of failing closed, violating No fallbacks that fabricate / Explicit boundary contracts.

Comment thread src/v2/05_emit_go.dag Outdated
let kind = lookup_item_kind(emit_info: emit_info, name: item.name)
if (kind == TypedItemStruct) {
emit_go_struct_from_children(name: item_text, children: item.children, env: env)
} else if (kind == TypedItemEnum) {

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.

Invariant violation: This new None => false branch fabricates unit_only = false when the enum-summary boundary is missing, so Go emit chooses a tagged-union path instead of failing closed, violating No fallbacks that fabricate / Explicit boundary contracts.

Comment thread src/v2/05_emit_python.dag Outdated
let kind = lookup_item_kind(emit_info: emit_info, name: item.name)
if (kind == TypedItemStruct) {
emit_py_dataclass_from_children(name: item_text, children: item.children, env: env)
} else if (kind == TypedItemEnum) {

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.

Invariant violation: This new None => false branch fabricates unit_only = false when the enum-summary boundary is missing, so Python emit chooses a tagged-union path instead of failing closed, violating No fallbacks that fabricate / Explicit boundary contracts.

Three missing models (MM-1 item identity, MM-2 type structure, MM-3
expression semantics) generate all the heuristic if-else forests across
the compiler. Full per-file inventory with line numbers, cross-PR
pattern analysis, and design directions.

Shifts CM from incremental ratchet fixes to holistic model design.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@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 (INVARIANTS: 2, MODELING: 1+/1-, ROADMAP: 1✓/1!)

INVARIANTS — Violations (2)

MODELING — Strengths

  • src/v2/04_emit_info.dag FunctionSignature and CapabilitySignature at least factor repeated emitter field-plucking into explicit products instead of making each backend rediscover the same tuple of facts.

MODELING — Improvements

  • src/v2/04_emit_info.dag ServiceFieldSet would be more compositional if it were derived from a transport-capability structure rather than flattened into four booleans.

ROADMAP — Verified

  • CM full analysis: The new roadmap pointer is backed by this diff because src/v2/CM.md is added and contains the promised heuristic inventory and design notes.

ROADMAP — Incomplete

  • M2 Boundary Sufficiency: The new emit boundary is still not fail-closed or single-authority because item identity is duplicated and Rust emit still fabricates on missing enum summaries.

The PR improves CM documentation and factors some emitter inputs upward, but it still adds duplicate item modeling and a new Rust fail-open path, so it does not yet meet the invariant bar for M2.

Comment thread src/v2/04_emit_info.dag Outdated
// TypedItemKind — enriched item classification precomputed during reconcile.
//
// Eliminates post-classification re-interrogation of connective and uses:
// TypeDef → split into Struct / Enum (no connective re-check)

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.

Invariant violation: TypedItemKind introduces a second closed item-classification authority alongside the existing item model, so this change adds a parallel representation instead of fixing the upstream item identity root cause, violating No duplicate representations / Root-Cause Depth.

Comment thread src/v2/05_emit_rust.dag Outdated
if (kind == TypedItemStruct) {
let type_params = emit_type_params(params: item.params, source_index: env.source_index)
emit_struct_from_children(name: item_text, type_params: type_params, children: item.children, recursive_types: emit_info.recursive_type_set, rc_types: rc_types, env: env, emit_info: emit_info)
} else if (kind == TypedItemEnum) {

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.

Invariant violation: This None => false branch fabricates unit_only = false when the enum summary boundary is missing, so Rust emit repairs a broken boundary downstream instead of failing closed, violating No fallbacks that fabricate / Explicit boundary contracts.

…eFieldTemplates)

Resolve conflicts by taking main's .dag and stage0 versions — main's
architecture diverged (TypedItemTypeDef, shared_types rename, data-driven
service fields). cm-track's unit_only wiring for Go/Python is deferred
to holistic CM work tracked in src/v2/CM.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@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 (INVARIANTS: 0, MODELING: 0+/0-, ROADMAP: 1✓/1!)

ROADMAP — Verified

  • CM full analysis: The new ROADMAP reference is supported by the diff because src/v2/CM.md is added and contains the promised heuristic inventory and design directions.

ROADMAP — Incomplete

  • PR #322 M2 + CM structural type knowledge / ownership threading: The diff is documentation-only, so it does not implement structural type knowledge or ownership-threading changes in the compiler files named by that scope.

The diff usefully documents the CM problem space, but it does not land the broader M2 and ownership work implied by the PR scope.

@briansrls

briansrls commented Apr 6, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I reviewed the attached diff, not the live GitHub PR page. The uploaded patch is docs-only: ROADMAP.md plus a new src/v2/CM.md. There are no .dag changes in the diff, and I do not see any ownership-threading implementation in the attached patch.

Overall: good doc addition, no executable invariant violation introduced by this diff, but I’d leave a few comments before merge.

Main findings

Medium

  1. src/v2/CM.md:75-83 — I would not make TypeSummary.repr the authority for non-emit consumers.

That would invert the boundary: TypeSummary.repr is an emit-facing summary, while lookup, types, and complexity should consume an upstream structural fact, not an emit product. Per the invariants around explicit boundary contracts and “emission is translation, not decision-making,” the cleaner shape is: define a neutral upstream fact (TypeShape or equivalent), then let emit-info derive from it.

  1. src/v2/CM.md:122-126 and 284-286 — “string dispatch is a missing enum” is too strong as written.

Sometimes the missing thing is not a compiler enum; it is declaration-driven authority in .dag (std/algebra.dag, LanguageSpec, etc.). AlgebraMethodKind is reasonable as a bridge, but it should be explicitly described as either:

  • derived from .dag authority, or
  • temporary, with a delete trigger.
  1. As written, it risks turning declaration-driven algebra back into compiler-owned knowledge, which is the opposite of the M4 direction.
  2. ROADMAP.md:519-523 — priority wording conflict.

The surrounding prose still says this section is for “Theory, long-horizon, and items that land after root-cause tracks complete,” but the heading now says CM is the primary focus. Those two signals conflict. Either move CM out of that long-horizon bucket or keep it framed as a continuous/parallel track.

Low

  1. src/v2/CM.md:44-48 — option (b) needs more guardrails.

“Let consumers pattern-match on the structural facts directly” can easily preserve the current re-derivation problem under a different spelling. If each stage writes its own raw-node predicates, you still have multiple classification forests. Even if you reject taxonomies, you still need one shared boundary contract / shared structural query layer.

  1. src/v2/CM.md:217-238 — open PR / recent commit examples will stale fast.

Useful today, but brittle in a long-lived design doc. I’d move that section to a dated appendix or branch-review log.

  1. src/v2/CM.md:103-126 — good concrete bug inventory, but it should hook into the roadmap more directly.

The nullary-call section is one of the most actionable parts of the doc, especially the Go/Python note. Since the roadmap already has call/reference-syntax work, I’d cross-link this explicitly rather than leaving it only in CM.md.

Invariant check

I do not see a direct invariant violation introduced by this patch, because the patch is documentation only.

In fact, the strongest part of the PR is that src/v2/CM.md:264-290 is very well aligned with the repo invariants:

  • no fail-open fallbacks,
  • carry facts structurally,
  • name keys are identity proxies,
  • emitter semantic decisions belong upstream.

That said, the doc should be tighter wherever it proposes new intermediate authorities. Per INVARIANTS.md, a new boundary/wrapper/fact layer is only acceptable if it is exact, single-authority, and actually consumed end-to-end. The current wording around ClassifiedItem, TypeShape/TypeSummary.repr, and AlgebraMethodKind leaves a little too much room for parallel-authority implementations.

Compositional modeling quality for .dag changes

N/A for this diff. No .dag files changed.

For the modeling itself, though, the MM-1 / MM-2 / MM-3 decomposition is good. The new doc does a strong job of collapsing a lot of scattered symptoms into a small number of missing concepts. The principles section is the best part of the patch.

Roadmap alignment

Directionally, this is aligned. The CM summary points at the same family of problems the roadmap already cares about: structural identity, declaration-driven algebra, name-proxy deletion, and moving semantic authority out of emit.

What is missing is explicit mapping from the new MM buckets to existing roadmap lanes. Right now the new section is a good summary, but it still reads more like design prose than a roadmap node. I’d want a small mapping such as:

  • MM-1 → D6 / structural identity / item boundary
  • MM-2 → type/algebra authority / shared emit boundary
  • MM-3 → call/reference semantics / method authority / backend parity

Without that, “primary focus” risks becoming parallel narrative instead of decomposition of current milestones.

General code review

Since this diff is docs-only, I don’t see a new runtime regression in the patch itself.

The one broader note is scope signaling: the PR title mentions structural type knowledge, concept modeling, and ownership threading, but the attached diff only contains docs. If that is intentional, fine. If not, the uploaded diff may be incomplete.

My merge read: good doc, no blocking code issue in the attached patch, but I’d leave comments on the authority/layering wording in CM.md and the priority wording in ROADMAP.md.


View conversation

briansrls and others added 2 commits April 5, 2026 23:23
- CM moves from Layer 3 (deferred) to active lane in critical path
- Add concrete baseline counts and grep-based acceptance tests that
  can't be gamed by hiding heuristics behind helpers
- MM-1/2/3 each get work items and measurable done criteria
- CM.md gets matching acceptance section with runnable commands
- ROADMAP critical path diagram updated to show Lane 4

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Acceptance criteria are now "this pattern is unrepresentable" not "we
counted zero instances." Each MM criterion is a claim about what types
and module boundaries prevent, verifiable by checking imports/types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@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 (INVARIANTS: 0, MODELING: 0+/0-, ROADMAP: 1✓/2!)

ROADMAP — Verified

  • CM lane scaffolding: ROADMAP now points Lane 4 to src/v2/CM.md, and this diff adds that file with the promised MM-1/MM-2/MM-3 sections plus a heuristic inventory.

ROADMAP — Incomplete

  • CM ratchet baselines: The new CM ratchet is not mechanically grounded yet: the documented commands on the current tree yield 45 structural-interrogation sites, 25 method-name dispatch sites, and 13 classify_* hits, while the side-table grep already returns 0, so the published baselines and acceptance checks are not reproducible.
  • PR #322 ownership threading: The PR title claims M2 structural type knowledge and ownership threading, but this diff only adds roadmap/design docs and does not change 04_infer.dag, 05_emit*.dag, or ownership code to support that milestone progress.

The CM documentation is directionally useful, but this PR is documentation-only and its new roadmap ratchets are not yet grounded in reproducible code-backed measurements.

@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 (INVARIANTS: 0, MODELING: 0+/0-, ROADMAP: 2✓/0!)

ROADMAP — Verified

  • Lane 4 / CM ownership: ROADMAP.md now assigns Lane 4 to compiler concept modeling and this diff adds src/v2/CM.md as the referenced design artifact for that lane.
  • CM heuristic inventory: The new roadmap claim that there is a full CM analysis is supported by the added src/v2/CM.md, which enumerates MM-1/MM-2/MM-3 and the per-file heuristic inventory it points to.

No new invariant violations are introduced in the changed lines; this PR is a documentation/roadmap addition and its new roadmap references are supported by the added CM analysis document.

@briansrls

briansrls commented Apr 6, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I reviewed the uploaded diff. This PR is docs-only: it modifies ROADMAP.md and adds src/v2/CM.md. There are no .dag changes in this patch, so there’s no direct compositional-modeling regression in executable .dag to audit, and no ownership-threading implementation in the diff to verify. The review is really about whether the new CM lane is coherent with the invariants and the existing roadmap.

Overall: the direction is good. The new CM lane correctly names a real root cause: repeated downstream re-derivation of facts that should be structural, which is exactly the territory covered by the invariants around lost structure, fail-open fallbacks, and single authority. The inventory in src/v2/CM.md is useful, especially the callout of fail-open sentinels and the cross-target nullary-call bug. My concern is mostly about plan shape and authority boundaries, not about runtime bugs in this PR.

I’d leave two substantive review comments and a couple of smaller ones.

1. MM-3 is at risk of replacing string dispatch with a new compiler-owned enum, not with data-driven semantics.

ROADMAP.md:595-603 and src/v2/CM.md:302-316 propose AlgebraMethodKind and make emit match on kind instead of method_def.name. That is better than raw string matching, but I don’t think the doc currently explains how this avoids becoming another closed-world enumeration that has to be edited across the compiler when algebra methods evolve. The existing roadmap already distinguishes the remaining method_def.name reads as structural-authority reads coming from the algebra registry, and it still has open work to model callback shape structurally via CallableOf in AlgebraTypeTemplate, rather than by more downstream classification.

My ask here: either explicitly tie AlgebraMethodKind to data declared in std/algebra.dag and explain why adding a new algebra method does not create new downstream edit sites, or change the MM-3 direction to “data-driven method semantics loaded from algebra declarations” rather than “new enum in compiler logic.” As written, this risks violating the same invariant the doc is trying to fix: replacing open-ended string checks with another cross-cutting dispatch surface instead of a single authority for method semantics.

2. MM-2 is under-aligned with the existing TypeRendering/coercion roadmap, so it reads like a parallel plan.

ROADMAP.md:572-581 and src/v2/CM.md:297-300 frame the missing model as “cached connective interpretation,” possibly via TypeShape or TypeSummary.repr. That’s a reasonable local description, but the current roadmap already says the type-rendering authority is build_type_rendering as a stepping stone to coercion-based emission, where target type knowledge comes from TypeCheckpoint / InhabitantDecl and the renderer stops guessing from node shape.

So the issue isn’t that MM-2 is wrong; it’s that it doesn’t explicitly anchor itself to the existing E-track/M5 authority. Right now I can read three competing “final authorities” out of the docs: TypeSummary.repr, a future TypeShape, and TypeRendering/coercion. I’d tighten this so CM says something like: “for emit, MM-2 lands through the existing TypeRendering/coercion boundary; for non-emit consumers, decide whether they share that concept or need a separate structural one.” Without that, CM becomes a second roadmap rather than a cross-cutting diagnosis.

3. MM-1’s design choice is still too open-ended relative to its acceptance criteria.

In src/v2/CM.md:44-48, MM-1 says either:

  • classify once and carry that classification, or
  • stop classifying and let consumers match directly on structural facts.

But ROADMAP.md:555-559 and src/v2/CM.md:270-285 set an acceptance criterion that emit cannot access raw item fields for dispatch and receives pre-resolved facts instead. Those aren’t equivalent architectures. Option (b) is fine in principle, but not for emit if the acceptance criterion is “classification is unrepresentable in emit.”

I’d narrow this. The doc should say which consumers, if any, are allowed to pattern-match on raw structural facts, and which boundary must already carry resolved item facts. Otherwise future work can “satisfy” MM-1 by merely relocating classification rather than deleting the duplicated taxonomies and fail-open side tables it’s calling out.

4. The “How to verify” checks are too import-based to prove the invariant.

ROADMAP.md:612-616 and src/v2/CM.md:277-295 mostly define success as “emit modules don’t import X.” That’s helpful as a grep check, but it’s weaker than the invariant the doc claims to enforce. A helper can still re-derive the same fact one module over.

I’d strengthen the acceptance criteria toward boundary shape, for example:

  • no Map<String, TypedItemKind> / Map<String, FunctionSignature> side tables,
  • emit boundary types make misses impossible rather than hiding them behind defaults,
  • nullary invocation is represented in IR/binding kind rather than inferred from target rendering,
  • method semantics arrive as a total, closed, upstream-owned boundary fact.

That would be much closer to the invariants’ “typed boundaries make bad states unrepresentable” and “no fallbacks that fabricate” standard.

A couple of smaller notes:

  • src/v2/CM.md usefully inventories current heuristic sites, but the exact counts and line-number tables will rot very quickly. The dates help, but I’d still label that section as a snapshot rather than something normative.
  • MM-3 currently groups all method_def.name uses under “string dispatch.” Existing roadmap text already distinguishes some of those as structural-authority reads rather than ad-hoc classification. I’d preserve that distinction so the CM lane doesn’t accidentally target the wrong fix.
  • No .dag changes in this diff, so the “compositional modeling quality for .dag changes” check is effectively N/A here. The proposed modeling direction is mostly strong; the biggest caveat is that MM-3 should stay data-driven rather than turning into another hardcoded semantic enum.

So my merge recommendation would be: good direction, but request doc changes before merge. The two things I’d want fixed are:

  • explicitly align MM-2 with the existing TypeRendering/coercion authority, and
  • either justify AlgebraMethodKind as data-driven and non-duplicative, or reframe MM-3 so it doesn’t hardcode a new closed-world method taxonomy.

View conversation

Classifications (type/function/service) are surface sugar — emergent
compositions of structure, evidence, and morphism. The compiler should
work in terms of the primitives, making classification unnecessary.
Same pattern as recursion dissolving into fold/descend/repeat.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@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 (INVARIANTS: 1, MODELING: 0+/0-, ROADMAP: 1✓/1!)

INVARIANTS — Violations (1)

ROADMAP — Verified

  • CM lane documentation: ROADMAP now points Lane 4 to src/v2/CM.md, and the diff does add that analysis document.

ROADMAP — Incomplete

  • PR #322 M2 + ownership threading: The diff is documentation-only, so it does not substantiate the advertised M2 structural-type-knowledge or ownership-threading progress beyond planning text.

The CM documentation is useful and the roadmap link is backed by the new file, but the MM-1 plan still leaves a non-root-cause classification wrapper in scope and the PR does not evidence the broader M2/ownership progress named in its scope.

Comment thread src/v2/CM.md Outdated
themselves ARE the facts. The four taxonomies are redundant
interpretations that exist because no single taxonomy felt complete.

**Design direction:** Either (a) compute classification once and carry

This comment was marked as resolved.

@briansrls

briansrls commented Apr 6, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I reviewed the uploaded diff rather than the live PR page. This PR is docs-only: ROADMAP.md plus a new src/v2/CM.md. There are no .dag changes in the diff, so the .dag compositional-modeling check is N/A.

My verdict: request changes. I like CM.md as a design note, but I would not merge the roadmap promotion of “Lane 4” as written.

  1. Roadmap alignment is the biggest problem.

At diff lines 9–15, the roadmap adds Lane 4: CM as a peer lane and gives it ownership of MM-1/2/3. Then at lines 74–77 it says M2/CG/CX work is “actually CM problems.” That makes the plan less crisp, because the current roadmap still says Priority Zero is restoring a reproducible stage0 pipeline and that broader lane work resumes only after Bootstrap A–D are stable. As written, this PR reads like a reprioritization, but it never says so explicitly. Either make Lane 4 explicitly design-only / deferred until after Bootstrap D, or keep CM as a supporting design doc instead of a new execution lane with ownership.

  1. CM.md needs explicit invariant guardrails for any new model layer it proposes.

The doc is directionally right about pushing facts upstream, but it repeatedly floats things like ClassifiedItem, TypeShape, TypeSummary.repr as a single authority, and AlgebraMethodKind without stating the invariant test that must govern them: a fact table or boundary is only valid if it is an exact derivation and a real downstream consumer uses it as authority in the same change. The invariants are very explicit about this, and the repo already deleted a prior boundary layer because it introduced unused/lossy fact tables. Without that guardrail written into CM.md, this doc could authorize exactly the kind of speculative metadata the invariants reject.

  1. MM-1 risks replacing many local heuristics with one lossy global classifier.

The strongest warning sign is the combination of CM lines 219–223 (“either carry ClassifiedItem or stop classifying”) with the acceptance text in diff lines 97–101 (“there’s nothing to classify”). That wording nudges the design toward a single classifier object. But the invariants do not want “one big classification enum”; they want boundaries that carry the actual orthogonal facts downstream stages need, and make illegal states unrepresentable. A universal ItemKind-style wrapper is only safe if it preserves every distinction consumers need. Otherwise it is just a cleaner-looking lossy proxy. I would ask the author to say this explicitly. Pasted markdown

  1. Lane ownership now overlaps existing roadmap ownership.

Several things CM claims under MM-2/MM-3 are already owned elsewhere in the roadmap, especially the algebra-fidelity work: partial_function_templates and the missing CallableOf variant are already tracked under Lane 1 Tier 2.5. If Lane 4 now “owns” MM-1/2/3 without reconciling those existing entries, you create duplicate ownership and unclear landing points. I would either cross-link each MM item to its existing milestone/owner, or remove the “Lane 4 owns…” line and frame CM as a cross-cutting design lens.

  1. The acceptance criteria are too syntactic.

The new roadmap acceptance table at diff lines 154–158 mostly says “emit modules don’t import X.” That is a decent grep ratchet, but it is not the real invariant. The real invariant is boundary sufficiency / explicit boundary contracts: emit should receive a type that already carries the needed fact, rather than merely not importing a symbol. I would keep the grep checks as ratchets, but rewrite the claims in terms of boundary types and authority, not import hygiene. Pasted markdown

A few smaller comments:

  • The “Current counts (2026-04-05)” numbers in CM.md will rot quickly. I’d either label them as non-gating snapshots or attach a reproducible script/grep command.
  • The MM-3 nullary-call section is the strongest part of the doc. It identifies a concrete cross-backend bug and gives two plausible structural fixes. That section feels grounded.
  • The line “Go and Python emitters ignore binding_kind today” is a good bug observation, but the doc should be careful not to imply that those backends should ignore the fact. The whole point is that the semantic fact must reach them structurally.

So the short review is:

  • Invariant violations: no immediate code-level invariant break, because this PR changes docs only. But there are design-level invariant conflicts unless CM is constrained by the exact/non-lossy/end-to-end boundary rules.
  • .dag modeling quality: N/A, no .dag files changed.
  • Roadmap alignment: currently weak; the new lane conflicts with the roadmap’s existing Priority Zero sequencing and overlaps existing lane ownership.
  • General review: useful design note, but I would merge CM.md only after toning down the roadmap promotion and adding explicit invariant guardrails.

The cleanest fix would be: keep src/v2/CM.md, but change ROADMAP.md so CM is a deferred cross-cutting design track, not a new active lane owner, and add one short section in CM.md saying any new classifier/fact layer must be exact, non-lossy, and land with a same-PR consumer.


View conversation

- Resolve ROADMAP conflicts with main (CX count, emergent properties
  principle paragraph)
- Reframe CM as cross-cutting design lens, not competing lane owner
- Acceptance criteria rewritten as boundary type claims, not import
  hygiene
- Add invariant guardrail: new fact layers must be exact, non-lossy,
  and land with a downstream consumer in the same change

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@briansrls

briansrls commented Apr 6, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

Reviewed the attached diff. This PR is docs-only: ROADMAP.md plus new src/v2/CM.md. I did not see any .dag changes in the diff, so item 2 is N/A for landed code; I reviewed the proposed modeling direction instead.

My take: the direction is mostly good and much more invariant-aware than the old “move the heuristic upstream” pattern, but I would tighten the MM-1 design before merge.

1. Invariant review

No executable invariant violation lands here, since nothing runnable changed. The risk is doc-level: a few parts of the new CM framing still leave room for an implementation that would violate the invariants.

Main issue: MM-1 is internally inconsistent.

  • In CM.md, MM-1 says either:
    • compute classification once and carry it (ClassifiedItem wrapper), or
    • stop classifying and let consumers pattern-match on structural facts directly (diff lines 228-231).
  • But later, the acceptance criteria say emit must not access raw item structural fields for dispatch, and instead must receive pre-resolved facts at the boundary (diff lines 454-469; roadmap lines 99-103).
  • Then the foundational section says classification is not primitive and the compiler should dispatch on underlying primitives, not sugar categories (diff lines 504-616).

Those three ideas do not currently line up. As written, “option (b)” can be read as permission to keep dispatching on body / transport / uses / properties in emit, which is exactly the kind of boundary-insufficient re-derivation the invariants reject.

The doc needs to pick one target architecture and state it plainly. My recommendation:

  • do not carry a lossy ItemKind-style classification, and
  • do not let emit inspect raw Node item fields,
  • instead carry an exact, lossless item-facts boundary type with only the irreducible facts emit actually needs.

That preserves “classification is not primitive” while also preserving boundary sufficiency.

Second issue: MM-2 may accidentally bless a lossy proxy.

  • MM-2 proposes possibly promoting TypeSummary.repr to the single interpretation authority for all consumers (diff lines 261-267).
  • That is only safe if TypeSummary.repr is expanded to preserve every distinction needed by emit, lookup, types, and complexity. As written it sounds emit-oriented.
  • If it only encodes an emit-facing distinction like struct/enum/leaf, then making it global would recreate the exact “helpful but lossy fact layer” problem the invariants warn about.

I would change the text to say: TypeSummary.repr can only become the single authority if it is proven non-lossy for all consumers; otherwise it stays emit-scoped and a richer shared TypeStructure concept is needed.

Third issue: Structure / Evidence / Morphism is good vocabulary, but risky as metadata.

  • The triad at diff lines 533-548 is useful as analysis language.
  • But if this turns into a new stored label layer on top of fields that already carry the facts, it becomes duplicate representation.
  • The doc should explicitly say these are either:
    • analysis vocabulary over existing structural facts, or
    • future primitives only when they have one authoritative definition and a real same-change consumer.

Right now that part is philosophically strong but operationally under-constrained.

2. Compositional modeling quality

There are no .dag changes in this PR, so there is no landed composition to review.

For the proposed model:

Strongest parts

  • MM-2 is the clearest. Separating primitive connective from consumer interpretation is exactly the right compositional move.
  • MM-3 is also strong. AlgebraMethodKind plus explicit nullary invocation would remove repeated string dispatch, and the doc correctly calls out likely Go/Python parity bugs around nullary function refs (diff lines 295-304).

Weakest part

  • MM-1 is still oscillating between:
    • wrapper classification,
    • direct raw structural matching,
    • deeper primitive decomposition.

That section needs one crisp end-state.

Specific modeling preference

  • For nullary invocation, I would lean toward Option B (ExprVar -> ExprCall normalization, diff lines 298-300) over NullaryCallBinding.
  • Option A is workable, but it feels like another bridge tag that later has to be dissolved.
  • Option B better matches the principle later stated in the doc: the graph should represent semantics, and emit should only render.

3. Roadmap alignment

Mostly good.

What works:

  • The new CM summary belongs in the roadmap.
  • The added invariant guardrail in ROADMAP.md (diff lines 162-167) is exactly the right rule: exact derivation, non-lossy, real downstream consumer in the same change.

What needs cleanup:

  • The roadmap top section says CM is a cross-cutting design lens and “does not own files separately” (diff lines 12 and 17).
  • A few lines later, the section title calls it Lane 4 (diff line 28).

That framing is muddled. Pick one:

  • either CM is a non-owning cross-cutting design track,
  • or it is a real lane with explicit ownership and acceptance gates.

I would not keep both phrasings.

Minor nit:

  • Changing CX from 315 → 0; ratchet at 315, main at 164 to just 164 → 0 (diff lines 9-10) drops useful provenance. Not a correctness issue, but it makes the roadmap less informative.

4. General review / concerns

Because this is docs-only, I do not have runnable bug findings. The main concerns are doc quality and future implementation ambiguity.

A few smaller notes:

  • The heuristic inventory is useful, but hardcoded line ranges will rot quickly. I would prefer function names first, line numbers second.
  • The PR title sounds broader than the actual diff. I did not see ownership-threading implementation here beyond brief references.

Bottom line

Good direction overall. The new CM writeup is much closer to the repo’s invariants than the old “push the heuristic around” approach, and the roadmap guardrail is especially good.

I would still ask for a revision before merge to resolve the MM-1 ambiguity and to clarify that TypeSummary.repr cannot become a global authority unless it is explicitly proven non-lossy for every consumer.


View conversation

@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 (INVARIANTS: 1, MODELING: 0+/0-, ROADMAP: 1✓/1!)

INVARIANTS — Violations (1)

ROADMAP — Verified

  • CM lane / src/v2/CM.md: The new CM lane entry is backed by the addition of src/v2/CM.md in the same diff.

ROADMAP — Incomplete

  • M4 Tier 2.6 / MM-3: src/v2/CM.md still leaves nullary invocation as NullaryCallBinding versus ExprVar->ExprCall alternatives, so function application is not yet committed to the IR-node model the roadmap says should dissolve the heuristic.

The CM roadmap promotion is supported by the new document, but the design still preserves a downstream nullary-call workaround instead of fixing the expression-level root cause.

Comment thread src/v2/CM.md
`foo` distinction. Target languages need `()`. Currently the emitter
re-derives this from type names or registry lookups (`04_emit_rust.dag`
lines 1685-1750). Inference already knows at `04_infer.dag:970-977`:
`binding_kind = FunctionValueBinding` + `fsig.params |> count == 0`.

This comment was marked as resolved.

@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 (INVARIANTS: 3, MODELING: 0+/0-, ROADMAP: 2✓/1!)

INVARIANTS — Violations (3)

ROADMAP — Verified

  • CM heuristic inventory: The new roadmap reference to src/v2/CM.md is supported by the added file in this diff.
  • CX (164 → 0): The updated critical-path label matches the roadmap’s current ratchet count of 164 complexity violations.

ROADMAP — Incomplete

  • Lane structure: The roadmap now introduces CM as Lane 4, but the Layer 2 intro still says only “Lanes 1–3 run in parallel,” so the lane model is not updated consistently.

The PR adds useful CM inventory, but it still proposes new duplicate semantic authorities and mis-models compilation as evaluation, so it is not yet invariant-aligned.

Comment thread src/v2/CM.md Outdated
| Normal form | Fully evaluated — no more redexes (= emitted target code) |
| fold/descend/repeat | **Rewrite strategies**: the order in which reductions are applied |
| Termination proofs | Standard rewrite-termination via ranking functions (already in termination.dag) |
| Compilation itself | **Reduction to normal form** in the target language |

This comment was marked as resolved.

Comment thread src/v2/CM.md Outdated

**Design direction:** The connective primitives stay — they're
foundational. What's missing is a cached interpretation layer. Options:
- `TypeShape` (Product/Coproduct/Scalar) computed once per type

This comment was marked as resolved.

Comment thread src/v2/CM.md Outdated
they destructure with `_` and emit bare identifiers. They likely have
the same bug for nullary functions.

**Design direction for method dispatch:** Add `AlgebraMethodKind` enum

This comment was marked as resolved.

@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 (INVARIANTS: 2, MODELING: 0+/0-, ROADMAP: 1✓/1!)

INVARIANTS — Violations (2)

ROADMAP — Verified

  • CM design reference: The roadmap’s new src/v2/CM.md reference is supported by the added src/v2/CM.md and companion inventory file in this diff.

ROADMAP — Incomplete

  • CM as an active lane: This PR only adds analysis docs, so the new claim that CM informs lanes 1-3 is not yet backed by any same-diff compiler boundary or consumer changes.

The PR adds useful CM documentation, but it also introduces new duplicate-authority modeling proposals and promotes CM in the roadmap faster than the code changes support.

Comment thread src/v2/CM-inventory.md Outdated
**Modeling implication:** Field-presence assertions (category 3) dissolve
directly with the Node decomposition. Instead of checking `body != none`
and `transport != none` separately, consumers check `has_reduction?` and
`reduction_kind?` (internal/external). Name-based checks (category 1)

This comment was marked as resolved.

Comment thread src/v2/CM-inventory.md Outdated

**Modeling implication:** Method name dispatch (category 1) dissolves
when methods carry an AlgebraMethodKind or a RewriteRuleKind. The
"fold" special cases in ownership.dag dissolve when fold is a

This comment was marked as resolved.

@briansrls

briansrls commented Apr 6, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I reviewed the attached diff against INVARIANTS.md. This PR is docs-only: it changes ROADMAP.md and adds src/v2/CM.md plus src/v2/CM-inventory.md. There are no .dag changes in the diff, so item 2 is N/A for landed code. My overall take: the direction is strong, but I would ask for a revision before merge because MM-1 is still architecturally ambiguous enough to permit an invariant-breaking implementation.

1. Invariant review

No executable invariant violation lands in code here, because nothing runnable changed. The risk is at the design-doc level: the new CM framing still leaves one of the key boundaries underspecified.

The main issue is MM-1. In CM.md, the MM-1 design direction says either:

  • compute classification once and carry it structurally, or
  • stop classifying and let consumers pattern-match on structural facts directly.

But later, the acceptance criteria say emit must not access raw item structural fields (body, transport, uses, type_annotation, properties) for dispatch, and must instead receive pre-resolved item facts at the boundary. Then the final “classification is not primitive” section says the compiler should dispatch on deeper primitives rather than surface categories. Those three positions do not currently resolve to one clear end-state. If “pattern-match on structural facts directly” is read as “emit can inspect raw Node fields,” that would recreate exactly the kind of downstream re-derivation the invariants reject: boundary layers must be exact and non-lossy, and emit is supposed to translate, not make semantic decisions. INVARIANTS

I would tighten MM-1 to say one thing plainly: emit must receive an exact, lossless item-facts boundary type and must not re-open raw item structure to rediscover semantics. That matches the repo’s boundary-sufficiency rule, the “always enrich the boundary” rule, and the existing requirement that the wrong question should be unaskable by type shape.

A second invariant risk is MM-2. The document floats “make TypeSummary.repr the single authority” as one option. That is only invariant-safe if repr is made non-lossy for all downstream consumers, not just emit. If it collapses distinctions that lookup, types, complexity, or ownership still need, then it becomes the kind of lossy fact table the invariants explicitly reject. The docs should say this outright instead of leaving it implicit.

One thing I do like: the new roadmap guardrail that any new fact layer must be exact, non-lossy, and consumed by a real downstream user in the same change is exactly the right rule. It is aligned with the invariant language on end-to-end boundaries and speculative metadata. INVARIANTS

2. Compositional modeling quality for .dag changes

There are no .dag changes in this PR, so there is no landed composition to review.

For the proposed modeling direction, MM-3 is the strongest section. Moving method dispatch away from method_def.name and toward an AlgebraMethodKind-style closed concept is well aligned with the repo’s anti-string-dispatch direction. The invariants are very explicit that open-ended lists keyed by strings are the smell, while closed structural or typed dispatch is the target.

On the nullary-call subproblem, I would lean toward the more semantic option: normalize nullary invocation into the IR rather than leaving it to per-backend rendering logic. That fits the document’s own principle that the graph should represent semantics and emission should only render. It is not a blocker that the doc leaves both options open, but it is the better compositional direction.

MM-2 is promising but under-constrained. “Interpret connective once” is the right instinct. The only missing piece is making the shared concept precise enough that it is not just an emit-flavored proxy.

MM-1 is the weakest part because it currently oscillates between three models:

  • carry a classification,
  • let consumers inspect raw structure,
  • dissolve classification into deeper primitives.

That is too many end-states for a design doc that is supposed to tell later PRs what “correct” looks like.

One smaller conceptual concern: the Structure / Evidence / Morphism vocabulary is useful as analysis language, but it should stay either:

  • a way to talk about existing structural facts, or
  • a future primitive with one authoritative producer and an immediate consumer.

If it turns into another stored metadata layer, it runs into the repo’s “annotations are not facts” rule. INVARIANTS

3. Roadmap alignment

Mostly good.

The PR’s CM summary is aligned with the repo’s current direction that the real problem is fact loss and downstream re-derivation, not isolated local heuristics. That matches both the invariants and the broader “fact composition” work already described elsewhere in the repo.

The part I would change is the framing. In ROADMAP.md, CM is described at the top as a cross-cutting design lens that “does not own files separately,” but a few lines later the section heading calls it Lane 4. Those are different governance models. I would pick one:

  • either CM is a cross-cutting lens with no ownership,
  • or it is a real lane with owned files, gates, and acceptance criteria.

Right now it reads as both, which will create churn later when someone asks whether a CM item can block merge on its own.

A smaller roadmap issue: changing the CX summary from 315 → 0; ratchet at 315, main at 164 to just 164 → 0 removes useful provenance. Not wrong, but it makes the dashboard less informative.

4. General review — bugs, edge cases, concerns

A few non-blocking review notes:

CM-inventory.md is useful as a dated audit, but the many hardcoded site counts and line-number references will rot quickly. I would lean more on function names and conceptual buckets, and treat the counts as a snapshot rather than something expected to stay exact.

CM.md names open PRs and recent commits in the “cross-cutting patterns” section. That is fine for a working note, but it will stale fast if this file is meant to be durable architecture guidance.

The PR title mentions ownership threading, but the diff is overwhelmingly about structural type knowledge and concept modeling. I do not see a comparable amount of ownership-threading design here. That is a naming/expectation issue more than a content issue.

Also worth noting: the repo already classifies “emit repairs semantics downstream” as an invariant violation. That makes it even more important that MM-1/MM-2 not leave room for “just let emit inspect the fields directly” as an implementation path. INVARIANTS

Bottom line

Good direction, not merge-ready as written.

The single biggest fix is to make MM-1 choose one invariant-safe architecture. My recommendation is:

  • no lossy ItemKind-style proxy as the long-term authority,
  • no raw item-field dispatch in emit,
  • one exact, lossless item-facts boundary type consumed as authority downstream.

I would also clarify that TypeSummary.repr can only become the single authority if it is proven non-lossy for every consumer, not just emit. Once those two points are tightened, the rest of the CM writeup looks much more solid.


View conversation

briansrls and others added 2 commits April 6, 2026 10:42
Add Signal/Algebra/Reduction ontological framing to CM.md with:
- Three foundational categories and working candidate (Reduction)
- Node/DAG as derived structure (theorem, not axiom)
- Validation: every heuristic forest maps to S/A/R categories
- Known gaps: Naming/Reference, Multiplicity, Maps-between-structures
- Compilation is translation (functor), not reduction to normal form

Fix invariant violations from review:
- Remove NullaryCallBinding as option; commit to ExprVar→ExprCall
- Remove TypeShape proposal; consume connective/TypeSummary.repr
- Remove AlgebraMethodKind proposal; surface existing method_def
- Remove ClassifiedItem proposal; consume existing Node fields
- Add practical principle: consume existing authorities, never duplicate
- Reframe all design directions: "surface existing X" not "add new Y"

Add CM-inventory.md companion with ~150 heuristic sites catalogued
across all compiler .dag files, mapped to ontological categories.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ROADMAP: CM is a cross-cutting retrospective discipline, not Lane 4.
After each feature lands, check for new modeling gaps. Modeling gaps
reveal themselves through the work, not in advance.

Add "consume existing authorities" principle to ROADMAP CM section.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@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 (INVARIANTS: 3, MODELING: 0+/0-, ROADMAP: 1✓/0!)

INVARIANTS — Violations (3)

ROADMAP — Verified

  • CM lane documentation: The diff adds src/v2/CM.md and src/v2/CM-inventory.md, so promoting CM from a deferred note to an explicit roadmap lane is supported by the change.

The CM docs resolve several prior root-cause issues, but the roadmap and inventory still reintroduce duplicate semantic authorities for method and item identity.

Comment thread ROADMAP.md Outdated

**Acceptance:** Connective interpretation is unrepresentable in emit.
Emit modules do not import `Connective` / `Conj` / `Disj` /
`NoConnective`. They receive a resolved type structure and dispatch on

This comment was marked as resolved.

Comment thread ROADMAP.md Outdated
**Acceptance:** Connective interpretation is unrepresentable in emit.
Emit modules do not import `Connective` / `Conj` / `Disj` /
`NoConnective`. They receive a resolved type structure and dispatch on
that. Type rendering is an exhaustive match on a sum type.

This comment was marked as resolved.

Comment thread src/v2/CM-inventory.md Outdated
| Lines | Heuristic | Cat | Question | With ontology |
|-------|-----------|-----|----------|---------------|
| 83-112 | `inferred_to_outputs`: connective + name checks | A | How many output fields? | Algebra (Product: expand fields, Coproduct: wrap) |
| 114-131 | `item_kind`: 7-branch priority chain | R | What emission category? | Node decomposition: `has_reduction? what_kind?` replaces 7 branches |

This comment was marked as resolved.

ROADMAP MM-1/2/3: rewrite work items and acceptance criteria to
consume existing authorities (body/transport/connective, TypeSummary.repr,
method_def/AlgebraFieldTemplate) — no new enums or classification types.

CM-inventory: replace all AlgebraMethodKind/RewriteRuleKind/has_reduction
references with "surface existing X" language.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@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 (INVARIANTS: 2, MODELING: 0+/0-, ROADMAP: 1✓/0!)

INVARIANTS — Violations (2)

ROADMAP — Verified

  • CM cross-cutting lens: The roadmap's new CM entry is supported by this diff because it adds both src/v2/CM.md and src/v2/CM-inventory.md as the referenced design artifacts.

This diff fixes most of the previously flagged CM design regressions, but it still leaves MM-1 pointed at hiding or carrying item classification instead of exposing the existing structural authority directly.

Comment thread src/v2/CM.md
- Serde attributes pass through three-layer fallback chain

**Not imported but should be:**
- Transport protocol contracts (TransportRequest/Response shapes in std/types.dag)

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.

Invariant violation: The MM-1 acceptance text says emit should not access the existing item fields directly, which contradicts Boundary sufficiency's rule to enrich boundaries by surfacing the real authority rather than hiding it behind a new form.

Comment thread src/v2/CM-inventory.md

**Ontological fix:** Direct dissolution. Node decomposition into
Signal/Algebra/Reduction makes classification a pattern match:
`{connective: NoConnective, body: present, transport: absent}` → FnItem.

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.

Invariant violation: Saying item classification should be computed once and carried structurally reintroduces a second item-identity authority instead of consuming body, transport, and connective directly, violating No duplicate representations and Root-Cause Depth.

Honest assessment: ~3 of ~39 fail-open sites are modeling gaps (all
trace to bare_map_node, confirming M2 diagnosis). Defensive sites
are structurally eliminable at the type-system level (phase-indexed
Nodes, exhaustive match on finite product space) but not via data
modeling. Runtime behavior choices are irreducible.

Principle: every defensive guard is a place the type system can't
prove what the programmer knows. Push the proof into structure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@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 (INVARIANTS: 1, MODELING: 0+/0-, ROADMAP: 1✓/0!)

INVARIANTS — Violations (1)

ROADMAP — Verified

  • CM analysis docs: The new ROADMAP CM section links to src/v2/CM.md and src/v2/CM-inventory.md, and both documents are added in this diff.

The diff resolves most of the previously flagged duplicate-authority design proposals, but it still overreaches by introducing a new parallel foundational ontology in CM.md.

Comment thread src/v2/CM.md

## Foundational ontology

The concept DAG (computation.dag §LAYERS) has two foundational

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.

Invariant violation: The new Signal/Algebra/Reduction “foundational ontology” introduces a parallel foundation for the compiler instead of grounding the analysis in the repo’s existing truth-valued foundation, violating Modeling Faithfulness and Root-Cause Depth.

@briansrls

Copy link
Copy Markdown
Contributor Author

ChatGPT review in progress... (view conversation)

briansrls and others added 2 commits April 6, 2026 11:48
CM.md:
- Resolve MM-1 contradiction: "emit cannot access raw fields" vs
  "fields ARE the authority." One clear end-state: existing structural
  data flows through boundaries intact. Reading a field IS reading
  the authority, not re-derivation.
- Add governing constraint: no new classification types, no lossy
  boundaries, one clear end-state per MM.
- Add §Arity boundaries: Node field combinatorics (empty service,
  classifier disagreement, intent erasure) + container arity edges
  (silent under/over-parameterization, optional collapse, callable
  mismatch).
- Clarify S/E/M as analysis vocabulary, not stored metadata.
- MM-2: TypeSummary.repr only safe if proven non-lossy for ALL
  consumers, not just emit.

ROADMAP.md:
- Soften child_inferred_or_empty checkbox (partial, not complete).
- One clear end-state in CM acceptance table.
- TypeSummary.repr non-lossy constraint explicit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CM section trimmed to: per-lane diagnosis table, unowned files gap,
arity boundaries pointer. MM-1/2/3 detail points to CM.md as
definitive source. Lane diagnosis shows highest-leverage fix per lane.

Note: CM.md will fold into MODELING.md when stable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@briansrls
briansrls merged commit 10c05a1 into main Apr 6, 2026
1 check passed
@briansrls
briansrls deleted the cm-track branch June 1, 2026 18:41
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