Skip to content

Phase 3+4: unify TCO and service rendering across Python/Go - #407

Merged
briansrls merged 8 commits into
mainfrom
bright-koi-465
Apr 12, 2026
Merged

briansrls merged 8 commits into
mainfrom
bright-koi-465

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Summary

  • Phase 3: Unified TCO rendering — emit_unified_tco_expr + emit_unified_tco_body replace 16 per-language wrapper functions. Match/pattern renderers stay as language-specific callbacks.
  • Phase 4: Unified service/transport orchestration — emit_unified_service_def, emit_unified_operation_method, emit_unified_transport_dispatch replace per-language dispatch and method rendering. New ServiceSyntax type on LanguageSpec parameterizes method signatures (self_param, receiver, error return wrapping). Transport implementations (REST/shell/file/local) stay per-language.
  • Net: 20 per-language functions deleted, 5 shared functions added, ServiceSyntax (6 fields) added to LanguageSpec.

Test plan

  • cargo test --workspace --exclude v2-compiler-tests — 20 passed
  • cargo test -p v2-compiler-tests — 401 passed
  • cargo clippy --all-targets -- -D warnings — clean
  • cargo test -p v2-compiler-tests strict_compile_diagnostic_count -- --ignored — 0 diagnostics (ratchet stable)

🤖 Generated with Claude Code

@briansrls

briansrls commented Apr 12, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I’d request changes before merge.

Directionally, this PR is moving the codebase the right way: the thesis explicitly prefers collapsing parallel mechanisms into one shared mechanism, and the roadmap says Track 13 Phase 3–4 is exactly shared TCO/block plus shared service/transport unification. So the intent is thesis-aligned. The problems are in two places where the new shared layer still breaks “zero bugs by construction” discipline instead of fully enforcing it. chatgpt-review-50986074-fe83-45…

chatgpt-review-6628f7e9-7ace-4f…

  1. The new shared transport dispatcher is still fail-open. In the new emit_unified_transport_dispatch, anything that is not recognized as REST, shell, or file falls through to local: else { render_local(op_name, depth) }. In a causal engine, that is the wrong default: an unsupported or misclassified transport should stop compilation, not silently become a different transport. This violates the invariants against fabrication fallbacks and against emit-time guessing, and it is especially risky here because the PR centralizes that behavior so one classification miss now affects both Go and Python instead of just one backend. The root-cause fix is to pass a structural transport kind/variant into emit and exhaustively match it; local should be one explicit case, never the catch-all. chatgpt-review-8d6cafa8-a460-48…

chatgpt-review-ac91d315-265a-4a…

  1. ServiceSyntax is the wrong shape for the fact it is trying to model. The PR adds a new compiler-local syntax record with raw string fragments like self_param, receiver_prefix, receiver_suffix, return_open, and return_close. That is a closed semantic space encoded as punctuation strings. It is also only a partial authority: signature shape moves into ServiceSyntax, but receiver usage inside transport bodies still lives in backend code (self/c conventions), so one fact is now split across two places. That is exactly the kind of duplicate/partial representation the invariants warn about. The stronger pattern already exists in the reference language model: LanguageSpec already carries structural service-call semantics as a sum type in std-library.dag. I’d rather extend that single authority with a structural “service method strategy” coproduct than introduce a second fragment DSL in src/v2/languages.dag. chatgpt-review-8d6cafa8-a460-48…

chatgpt-review-ac91d315-265a-4a…

  1. Assuming the repo still commits generated stage0 outputs, this diff looks incomplete. It changes src/v2/05_emit.dag, 05_emit_go.dag, 05_emit_python.dag, and languages.dag, but the diff does not include the corresponding generated src/v2/stage0/... emitter updates. The roadmap says stage0 freshness is a blocking CI gate, and the invariants are explicit that generated code must not become a parallel implementation that drifts from the .dag source. So unless the project has stopped checking in stage0 artifacts, this should be regenerated in the same PR. chatgpt-review-8d6cafa8-a460-48…

chatgpt-review-6628f7e9-7ace-4f…

  1. The test update is too weak for the risk surface. The only test change in the diff is source_audit.rs, and even that mainly ratchets on helper names. For a refactor that changes shared TCO and shared service emission across two backends, I’d expect at least one behavioral compiler test per backend: a Go and Python tail-recursive function that proves the unified TCO path emits valid target syntax, plus a Go and Python service case that proves method signature/receiver/async placement still match target expectations. The invariants do allow source-audit tests as a narrow exception, but they also say tests should be behavioral where possible. Right now the diff gives you architectural grep coverage, not semantic regression coverage. chatgpt-review-8d6cafa8-a460-48…

chatgpt-review-d9d8edba-efec-4e…

I do not see an obvious control-flow bug in the TCO extraction itself. The emit_unified_tco_expr/body factoring looks mechanically faithful, and keeping only pattern/match rendering plus init-statement rendering backend-specific is the right residual split for this phase. So my review is not “the unification is wrong”; it is “the unification still carries one unsound fallback, introduces a partial second authority for service syntax, and is under-tested for the amount of backend behavior it moves.” chatgpt-review-50986074-fe83-45…

chatgpt-review-8d6cafa8-a460-48…

ROADMAP.md is not modified in this diff, so there is no roadmap-text drift to flag. Directionally, the work matches Track 13 Phase 3–4; it just needs to land in a way that preserves the stronger fail-closed and single-authority rules the thesis requires. chatgpt-review-6628f7e9-7ace-4f…

References: PR diff, std-library.dag, THESIS.md, INVARIANTS.md, ROADMAP.md


View conversation

@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: 9e03356ddc

ℹ️ 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/05_emit_go.dag Outdated
let use_tco = is_tco_eligible(name: name, body: body, registry: registry, source_index: si)
if use_tco {
let body_str = emit_go_typed_tco_body(texpr: body, fn_name: name, params: params, registry: registry, scope: body_scope, depth: 1)
let body_str = emit_unified_tco_body(

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 Import shared helpers before using them in Go emitter

This module now calls emit_unified_tco_body, emit_unified_service_def, and emit_unified_transport_dispatch, but those symbols are not added to the import v2.compiler.emit { ... } list. Because this file uses explicit named imports, compiling the .dag sources for bootstrap/stage1 will hit unresolved-name diagnostics at these call sites instead of generating code.

Useful? React with 👍 / 👎.

Comment thread src/v2/05_emit_python.dag Outdated
let use_tco = is_tco_eligible(name: name, body: body, registry: registry, source_index: si)
if use_tco {
let body_str = emit_py_typed_tco_body(texpr: body, fn_name: name, params: params, registry: registry, scope: body_scope, depth: depth + 1)
let body_str = emit_unified_tco_body(

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 Import shared helpers before using them in Python emitter

This file was switched to emit_unified_tco_body/service unification calls, but the new shared symbols are not included in import v2.compiler.emit { ... }. With named-import semantics, that leaves these references out of scope and causes compile-time unresolved-name failures when the .dag source is bootstrapped.

Useful? React with 👍 / 👎.

Phase 3: TCO unification
- Create emit_unified_tco_expr + emit_unified_tco_body in shared emitter
- Delete 16 per-language TCO wrapper functions (8 Python + 8 Go)
- Keep only language-specific match/pattern renderers as callbacks
- Rust TCO untouched (deferred to Phase 6, ownership complexity)

Phase 4: Service/transport orchestration unification
- Create emit_unified_service_def, emit_unified_operation_method,
  emit_unified_transport_dispatch in shared emitter
- Add ServiceSyntax type to LanguageSpec (self_param, receiver,
  return wrapping, class vs top-level methods)
- Delete emit_py_operation_method, emit_py_transport_call,
  emit_go_operation_method, emit_go_transport_call
- Rewrite emit_py_service_def and emit_go_service_def as thin
  adapters wiring callbacks to unified orchestration
- Transport implementations (REST/shell/file/local) stay per-language

Net: 20 per-language functions deleted, 5 shared functions added.
Per-language emitter files shrink; shared emitter grows as authority.

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

briansrls commented Apr 12, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I’d request changes before merge.

Directionally, this PR is moving in the right thesis direction. The thesis explicitly prefers collapsing parallel mechanisms into one shared mechanism when they are structurally the same, and Track 13 says Phase 3–4 is exactly shared TCO/block plus shared service/transport unification. So the goal is aligned with “zero bugs by construction.” chatgpt-review-f8c0a255-91f1-42…

chatgpt-review-6628f7e9-7ace-4f…

What blocks merge for me is that the new shared layer still leaves one fail-open path, one real Python codegen bug, and one modeling choice that looks like a second partial authority rather than a clean extension of the existing language-spec model.

  1. emit_unified_transport_dispatch is fail-open.

In the new shared dispatcher, the final else routes any transport that is not recognized as REST, shell, or file to render_local(...). In a causal engine, that is the wrong default. An unsupported or misclassified transport should fail closed, not silently become a different transport. That conflicts with the invariants around explicit boundary contracts, no fabrication fallbacks, and “emission is translation, not decision-making.” The invariant doc is very explicit that transport should arrive at emit as a structurally classified boundary, not as something the emitter still has to guess about. chatgpt-review-3f0853c3-5aa9-42…

chatgpt-review-3f0853c3-5aa9-42…

The root-cause fix is to pass a closed transport kind or lowered transport variant into shared emit and exhaustively match it. local should be one explicit structural case, never the catch-all.

  1. There is a concrete Python service-rendering bug in the new shared path.

emit_unified_service_def builds methods_str by joining all rendered methods with "\n\n", then, for class-style languages, it prefixes make_indent(1) only once before the entire joined string. That means only the first method is indented inside the class. The second and later methods start at column 0, so a multi-operation Python service will emit invalid class layout.

This is not just a modeling concern; it is a real codegen bug from the refactor. A minimal fix is to indent each rendered method before joining, or join on "\n\n" + make_indent(1), or make emit_unified_operation_method return already class-indented declarations for significant-whitespace targets.

  1. ServiceSyntax is the wrong modeling shape.

The new LanguageSpec.service_syntax is a punctuation bundle: self_param, receiver_prefix, receiver_suffix, return_open, return_close, methods_inside_class. That encodes a closed semantic space as raw string fragments. It is also only a partial authority: signature shape moved into ServiceSyntax, but receiver/body conventions still remain in backend transport renderers, so one fact is now split across multiple places.

That clashes with the modeling/invariant guidance:

  • closed sets should be modeled structurally, not as strings,
  • data tables should be single-authority,
  • new semantic boundaries must land end-to-end,
  • the shared emitter should read facts, not invent them. chatgpt-review-ac91d315-265a-4a…

chatgpt-review-3f0853c3-5aa9-42…

chatgpt-review-3439aebf-71c3-46…

The reference pattern in the std library is already better. LanguageSpec there models service-call differences structurally via a coproduct (AwaitQuestion, AwaitPrefix, MultiReturnError) rather than punctuation fragments. I’d rather extend that same style with a structural “service method declaration strategy” coproduct than introduce a second fragment DSL in compiler-local languages.dag. See std-library.dag.

  1. The test update is too weak for the risk surface moved by this PR.

The only test change in the diff is source_audit.rs, and it checks for helper presence like emit_unified_tco_expr, emit_unified_tco_body, and emit_py_tco_match. That is architectural grep coverage, not behavioral coverage. The thesis and roadmap both treat emission verification as a core consequence of the model, and the current test suite already has patterns for exercising emitted real-program output end to end. chatgpt-review-f8c0a255-91f1-42…

chatgpt-review-6628f7e9-7ace-4f…

chatgpt-review-d9d8edba-efec-4e…

For this PR I would expect at least:

  • a Python multi-operation service regression test, which would catch the indentation bug above,
  • a Go and Python TCO smoke test proving the shared TCO path still emits valid backend syntax,
  • a negative test proving an unknown transport does not silently route to local.

What looks good: the TCO extraction itself seems mechanically faithful. Lifting the orchestration into shared helpers while leaving backend-specific match/block rendering in Go and Python is the right shape for Phase 3. Also, the diff does include regenerated stage0 mirrors, so I do not see a stage0-freshness omission here.

ROADMAP.md is not modified in this PR, so there is no roadmap-text drift to flag. Directionally, though, this is aligned with Track 13’s stated next steps: Phase 3 is TCO/block unification and Phase 4 is service/transport unification. My objection is not to the phase choice; it is that the implementation still leaves one unsound fallback and one non-structural service model, which cuts against the thesis requirement that emitted code be the mechanical consequence of validated facts. chatgpt-review-6628f7e9-7ace-4f…

chatgpt-review-3439aebf-71c3-46…

References: PR diff, std-library.dag, THESIS.md, INVARIANTS.md, MODELING.md, ROADMAP.md


View conversation

…sures

The .dag compiler generates Rust closures without type annotations.
When closures are stored in `let` bindings or passed through callback
chains, Rust's type inference fails (E0282). Also fixes Rc<dyn Fn>
vs impl Fn mismatches (E0277) when callbacks pass through callbacks.

Fixes:
- Add missing imports: authored_name in 05_emit.dag, unified TCO +
  service functions in Python/Go emitter imports
- Restructure TCO match callbacks: match functions reconstruct
  recurse_expr locally (call emit_py_typed_expr / emit_go_typed_expr
  directly) instead of receiving it as a callback-through-callback
- Add unified_tco_recurse named helper to avoid let-binding closure
  type inference failure
- Add emit_py_typed_tco_body / emit_go_typed_tco_body as named
  wiring functions (avoids let-binding closures at call sites)
- Add emit_py_transport_body / emit_go_transport_body to avoid
  deeply nested closure chains in service rendering

Stage0 regenerated and fixed-point verified.

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.

cursor · composer-2 · 1b5368b8

Review (INVARIANTS: 3, MODELING: 2+/2-, ROADMAP: 0✓/0!)

INVARIANTS — Violations (3)

ROOT CAUSE ANALYSIS

  • src/v2/05_emit.dag TypeEnv’s field name and carrier type were not migrated in src/v2/04_env.dag (and call sites that build TypeEnv) before emit started emitting source_index → literals and accessors refer to a non-existent field → the compiler cannot prove the graph from env construction to emission sound; fix by atomically renaming and retyping TypeEnv (single NewlineIndex? vs per-file map is a modeling choice) and updating authored_name/every env builder in one change set, aligned with M4 (avoid string-keyed maps as identity proxies only after Node/span authority is explicit).
  • src/v2/00_core.dag Upstream authored_name_at and derived *_at APIs still assume a file-keyed Map<String, NewlineIndex> → emit was retargeted to a single optional index without updating those definitions → every downstream _at call is ill-typed; fix by either (a) implementing authored_name_at(source_index: NewlineIndex?, node: Node) (and threading module identity from Node/source graph) or (b) keeping Map<String, NewlineIndex> in TypeEnv and passing env.source_indices everywhere, then deleting the half-migration.
  • src/v2/05_emit.dag Dispatch was extracted without threading the same inputs as the old per-target emit_*_transport_call functions → either registry was needed for parity and dropped, or the parameter is speculative; remove registry from the unified signature and all call sites, or pass it into render_rest/render_shell if those backends still need item lookup—preserve single-authority data flow per INVARIANTS “no duplicate representations.”

MODELING — Strengths

  • src/v2/languages.dag ServiceSyntax extends LanguageSpec with the same pattern as RecordLitSyntax / TcoSyntax, parameterizing receiver and error-return shape so Python/Go share orchestration instead of parallel method templates—matches THESIS concept unification and M4 (emit reads declared language facts).
  • src/v2/05_emit.dag emit_unified_tco_expr / emit_unified_service_def centralize TCO and service control flow for Python/Go with callbacks for patterns and transports—reduces “no parallel implementations” drift between backends.

MODELING — Improvements

  • src/v2/languages.dag rust_spec and dag_spec now carry service_syntax strings that 05_emit_rust.dag does not consume (Rust service emission remains backend-specific per comments), risking a second authoritative description of Rust service signatures; either drive Rust from service_syntax or omit Rust/dag entries until consumed so LanguageSpec stays a single authority.
  • src/v2/05_emit.dag Collapsing Map<String, NewlineIndex> to NewlineIndex? removes string keys (M4 direction) but must be modeled as an explicit “compilation unit source context” fact carried with TypeEnv/InferScope so cross-module ident_span recovery is either impossible by construction or still sound; document that tradeoff as a type field, not only comments in order_typed_call_args.

ROADMAP — Unclaimed

  • M4 / shared emission direction: This PR materially shares TCO and service orchestration across Python/Go and adds ServiceSyntax to LanguageSpec, advancing the mechanical-emission story, but ROADMAP.md is not updated to record that partial step toward spec-driven emission.

Strong intent—unifying Python/Go TCO and service emission behind LanguageSpec aligns with “zero bugs by construction” and anti-parallel-implementation—but the PR must land atomically with the core/source-index API migration or it breaks the build and splits authority between specs and Rust.

Comment thread src/v2/05_emit.dag Outdated
fn empty_emit_scope() -> InferScope {
InferScope {
type_env: TypeEnv { bindings: empty_map(), recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: empty_map() },
type_env: TypeEnv { bindings: empty_map(), recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_index: none },

This comment was marked as resolved.

Comment thread src/v2/05_emit.dag Outdated
ExprError { kind: _, message: message } =>
emit_error_expr(message: message, target: target)
ExprVar { binding_kind: _ } => emit_ident(name: expr_var_name_at(texpr: expr, source_indices: source_indices), target: target)
ExprVar { binding_kind: _ } => emit_ident(name: expr_var_name_at(texpr: expr, source_index: source_index), target: target)

This comment was marked as resolved.

@briansrls

Copy link
Copy Markdown
Contributor Author

Violations (could not place on specific lines):

  • src/v2/05_emit.dag:509 Invariant violation: emit_unified_transport_dispatch takes registry: Map<String, ItemInfo> but the new body never uses it, adding dead surface on the causal path from registry to emitted transport.

…urce_indices

Review feedback from PR #407:

1. ServiceSyntax → structural coproducts (not string fragments):
   - ServiceMethodStrategy = SelfInParams | ExternalReceiver
   - ServiceReturnStrategy = ArrowReturn | ErrorTupleReturn
   Emitter dispatches structurally (like VisibilitySpec pattern).

2. Transport dispatch fail-closed:
   - Explicit is_local_transport check before local fallback
   - Unrecognized transport → emit_error_expr (not silent local)

3. source_index → source_indices alignment:
   - Bulk rename to match main's Map<String, NewlineIndex> API
   - Fixes 268 stale parameter references across 3 emitter files

Stage0 regenerated, fixed-point verified, ratchet passes (≤421).

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

Copy link
Copy Markdown
Contributor Author

cursor · composer-2 · 1b5368b8

Review (INVARIANTS: 3, MODELING: 2+/2-, ROADMAP: 0✓/0!)

INVARIANTS — Violations (3)

ROOT CAUSE ANALYSIS

  • src/v2/05_emit.dag TypeEnv’s field name and carrier type were not migrated in src/v2/04_env.dag (and call sites that build TypeEnv) before emit started emitting source_index → literals and accessors refer to a non-existent field → the compiler cannot prove the graph from env construction to emission sound; fix by atomically renaming and retyping TypeEnv (single NewlineIndex? vs per-file map is a modeling choice) and updating authored_name/every env builder in one change set, aligned with M4 (avoid string-keyed maps as identity proxies only after Node/span authority is explicit).
  • src/v2/00_core.dag Upstream authored_name_at and derived *_at APIs still assume a file-keyed Map<String, NewlineIndex> → emit was retargeted to a single optional index without updating those definitions → every downstream _at call is ill-typed; fix by either (a) implementing authored_name_at(source_index: NewlineIndex?, node: Node) (and threading module identity from Node/source graph) or (b) keeping Map<String, NewlineIndex> in TypeEnv and passing env.source_indices everywhere, then deleting the half-migration.
  • src/v2/05_emit.dag Dispatch was extracted without threading the same inputs as the old per-target emit_*_transport_call functions → either registry was needed for parity and dropped, or the parameter is speculative; remove registry from the unified signature and all call sites, or pass it into render_rest/render_shell if those backends still need item lookup—preserve single-authority data flow per INVARIANTS “no duplicate representations.”

MODELING — Strengths

  • src/v2/languages.dag ServiceSyntax extends LanguageSpec with the same pattern as RecordLitSyntax / TcoSyntax, parameterizing receiver and error-return shape so Python/Go share orchestration instead of parallel method templates—matches THESIS concept unification and M4 (emit reads declared language facts).
  • src/v2/05_emit.dag emit_unified_tco_expr / emit_unified_service_def centralize TCO and service control flow for Python/Go with callbacks for patterns and transports—reduces “no parallel implementations” drift between backends.

MODELING — Improvements

  • src/v2/languages.dag rust_spec and dag_spec now carry service_syntax strings that 05_emit_rust.dag does not consume (Rust service emission remains backend-specific per comments), risking a second authoritative description of Rust service signatures; either drive Rust from service_syntax or omit Rust/dag entries until consumed so LanguageSpec stays a single authority.
  • src/v2/05_emit.dag Collapsing Map<String, NewlineIndex> to NewlineIndex? removes string keys (M4 direction) but must be modeled as an explicit “compilation unit source context” fact carried with TypeEnv/InferScope so cross-module ident_span recovery is either impossible by construction or still sound; document that tradeoff as a type field, not only comments in order_typed_call_args.

ROADMAP — Unclaimed

  • M4 / shared emission direction: This PR materially shares TCO and service orchestration across Python/Go and adds ServiceSyntax to LanguageSpec, advancing the mechanical-emission story, but ROADMAP.md is not updated to record that partial step toward spec-driven emission.

Strong intent—unifying Python/Go TCO and service emission behind LanguageSpec aligns with “zero bugs by construction” and anti-parallel-implementation—but the PR must land atomically with the core/source-index API migration or it breaks the build and splits authority between specs and Rust.

@briansrls

briansrls commented Apr 12, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I’d request changes before merge.

Directionally, this is the right move. The thesis explicitly says parallel mechanisms should collapse when they are really the same mechanism, and Track 13 calls out Phase 3 as TCO/block unification and Phase 4 as service/transport unification. So the goal is thesis-aligned. chatgpt-review-f8c0a255-91f1-42…

chatgpt-review-3439aebf-71c3-46…

What blocks merge for me is:

  1. There looks to be an incomplete source_index / source_indices migration inside the touched emitters.

In the diff, some new/shared call sites switch to singular forms like tm.type_env.source_index, frame.scope.type_env.source_index, and even TypeEnv { ... source_indices: none }, while other new code in the same hunk still reads env.source_indices and scope.type_env.source_indices. The attached compiler test context still constructs TypeEnv { source_indices: ... }, not a singular field. That makes this look like either a compile break or an incomplete boundary migration, not a pure refactor. This is the kind of boundary inconsistency the invariants call out: the stage boundary should be sufficient and stable, not half-migrated in consumers. chatgpt-review-cb197540-fedc-40…

  1. The new shared Python service path still breaks on multi-operation services.

emit_unified_service_def builds methods_str by joining rendered methods with "\n\n", then prefixes make_indent(level: 1) only once before the entire joined string. For SelfInParams targets, only the first method stays indented under the class body; the second and later methods start flush-left. In Python that produces invalid class layout for services with more than one operation.

This may be inherited behavior, but this PR now centralizes it into the shared path, so the blast radius is larger. I’d treat this as a real blocker. The fix is to indent each rendered method before joining, or have the operation-method helper return already class-indented output for significant-whitespace targets.

  1. The new .dag modeling is mostly good, but it is only partially authoritative.

Adding ServiceMethodStrategy and ServiceReturnStrategy as closed coproducts is the right modeling direction. MODELING says closed sets should be enums/sum types, not strings, and that predicates/dispatch should be structural. So this is a net improvement over ad hoc syntax fragments. chatgpt-review-ac91d315-265a-4a…

The issue is that those facts are only consumed for Python and Go right now. Rust still keeps backend-specific service emission, while languages.dag now also declares Rust service-method and service-return facts. That creates a second, currently-unused authority for Rust semantics, which cuts against the thesis rule against duplicate representations. I would either keep these fields scoped to the targets that actually consume them today, or add a very explicit follow-up constraint that Rust must move onto the same authority before those values are treated as canonical. chatgpt-review-f8c0a255-91f1-42…

chatgpt-review-cb197540-fedc-40…

  1. The transport refactor is improved, but it still is not at “reads data, never decides.”

One thing this PR gets right: the new shared dispatcher now fails closed on an unknown transport instead of silently falling through, which is better than the old pattern. But it still classifies transport inside emit by calling is_rest_transport / is_shell_transport / is_file_transport / is_local_transport on a raw node. That means emit is still deciding from structure-at-consumption-time rather than consuming a fully lowered transport boundary.

I would not block merge on that by itself, because it is clearly moving in the right direction. But it does mean this PR does not fully satisfy Track 13’s “single emitter reads data, never decides” end state yet. The invariants are explicit that when emit still has to branch on proxy facts, the upstream boundary is still insufficient. chatgpt-review-3439aebf-71c3-46…

chatgpt-review-cb197540-fedc-40…

  1. The test update is too weak for the surface area moved.

The diff only strengthens source_audit.rs textual checks for helper presence. That is not enough for a refactor that moves shared behavior across both Go and Python. The modeling docs explicitly describe service verification as layered and mechanically derivable across type, operation, service, and workflow levels, and the roadmap still treats emitted-behavior verification as an open gate. A change like this needs at least one behavioral regression test, not just grep coverage. chatgpt-review-e065aa05-3ee5-45…

chatgpt-review-6628f7e9-7ace-4f…

The minimum set I’d want:

  • a Python service with at least two operations, to catch the indentation bug,
  • one Go and one Python TCO smoke case that exercises the shared helper path,
  • ideally a negative test for unknown transport classification failing closed.

A smaller note: the local go_source_extension() wrapper now reintroduces a file-local producer for something that already exists in scaffold data. It is not as bad as the old duplicate constant problem, because it delegates to the scaffold, but it is still a small step away from single-authority hygiene.

What looks good:

  • The TCO extraction itself looks mechanically faithful. I do not see an obvious semantic regression in the shared TCO path from the diff alone.
  • ServiceMethodStrategy / ServiceReturnStrategy is the right shape for this phase.
  • The unknown-transport case now fail-closes, which is thesis-consistent.

ROADMAP.md is not modified in this diff, so there is no roadmap-text drift to flag. Directionally, though, this PR is clearly aligned with the next stated Track 13 steps. My merge recommendation is “not yet” because of the incomplete source_index migration signal, the concrete Python service bug, and the lack of behavioral coverage for code that just moved into the shared emitter. chatgpt-review-3439aebf-71c3-46…

References: PR diff, std-library.dag, THESIS.md, INVARIANTS.md, MODELING.md, ROADMAP.md


View conversation

1. Remove unused registry param from emit_unified_transport_dispatch
   and its callers (emit_py_transport_body, emit_go_transport_body).
   Dead surface on the causal path from registry to transport emission.

2. Fix TypeEnv construction: source_indices: none → empty_map().
   TypeEnv declares source_indices: Map<String, NewlineIndex>, not optional.

3. Align remaining source_index → source_indices mismatches from rebase.

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.

codex · gpt-5.4 · 56fc38b2

Review (INVARIANTS: 4, MODELING: 1+/1-, ROADMAP: 0✓/1!)

INVARIANTS — Violations (4)

ROOT CAUSE ANALYSIS

  • src/v2/04_env.dag TypeEnv still defines one authority, source_indices, but the refactor renamed only some emitter consumers to source_index; that boundary split propagates into backend wrappers as mixed field reads and helper calls. Fix it upstream by keeping one canonical field or accessor on TypeEnv and updating all emit consumers atomically, which is the M2 single-authority fix instead of more downstream patches.
  • src/v2/00_core.dag ExprFieldAccess already carries structural authority through FieldSummary and FieldAccessStyle, but this emit path ignores it and re-derives call-vs-field from binding heuristics; that gap propagates into stage0 as ordinary value receivers being rewritten as thunks. Fix it upstream by having both simple and typed field emission consume one receiver-kind authority from the IR, which is the M8 and No parallel implementations fix.
  • src/v2/05_emit.dag The shared service path models nested blocks as raw String payloads from render_transport_body and render_service_fields instead of compositional block fragments, so indentation is patched downstream one line at a time and Python loses structure. Fix it upstream by returning List or a BlockEmitState-like fragment and letting the shared emitter assemble indentation from BlockSyntax, which is the M1 and Track 13 compositional fix.

MODELING — Strengths

  • src/v2/languages.dag ServiceMethodStrategy and ServiceReturnStrategy turn receiver placement and result shape into closed LanguageSpec data, which composes with VisibilitySpec and ItemKeywords and moves backend decisions out of per-language emitter code.

MODELING — Improvements

  • src/v2/languages.dag SelfInParams { self_param: String } and ErrorTupleReturn { error_type: String } still store rendered tokens like &self and error; model receiver mode and result carrier shape structurally so Track 13 Phase 5-6 borrow work composes instead of hiding in strings.

ROADMAP — Incomplete

  • Track 13 Phase 3-4: The diff clearly centralizes TCO and service/transport orchestration, but the mixed source_index boundary and string-based Python block rendering mean Phase 3-4 are not mechanically correct end-to-end yet.

ROADMAP — Unclaimed

  • Track 13 Phase 3-4: This PR is the roadmap's stated next work for Track 13, but ROADMAP.md still says Phase 3-4 are only ready / Next.

The PR moves Track 13 in the right direction, but it still violates single-authority boundaries and relies on downstream string and heuristic emission patches, so it does not yet meet the thesis's zero-bugs-by-construction bar.

Comment thread src/v2/05_emit_go.dag Outdated
let ret_type = emit_node_type(n: inferred, target: Go, source_indices: scope.type_env.source_indices)
let body_scope = build_params_scope(scope: scope, params: params)
let si = scope.type_env.source_indices
let si = scope.type_env.source_index

This comment was marked as resolved.

Comment thread src/v2/05_emit_python.dag Outdated
let ret_str = emit_py_inferred(inferred: inferred, source_indices: scope.type_env.source_indices)
let body_scope = build_params_scope(scope: scope, params: params)
let si = scope.type_env.source_indices
let si = scope.type_env.source_index

This comment was marked as resolved.

Comment thread src/v2/stage0/src/v2_compiler_emit.rs Outdated
} else {
v2_rt::concat(v2_rt::concat(emit_simple_expr(&b, &target, &source_indices), ".".to_string()), emit_ident(f.clone(), target.clone()))
{
let base_is_fn = match (*b.expr_data.clone()).clone() {

This comment was marked as resolved.

Comment thread src/v2/05_emit.dag
let eff_transport = effective_operation_transport(op_node: op_node, fallback: fallback_transport)
let body = render_transport_body(eff_transport, op_text, si, method_depth + 1)
let sig = concat(spec.items.async_prefix, spec.items.func_keyword, " ", receiver_str, method_name,
"(", all_params, ")", ret_str)

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: For significant-whitespace targets, emit_unified_operation_method pastes a multi-line transport body behind a single make_indent(...), so Python service methods lose indentation after the first newline and emitted code becomes structurally invalid.

@briansrls

Copy link
Copy Markdown
Contributor Author

codex · gpt-5.4 · 56fc38b2

Review (INVARIANTS: 4, MODELING: 1+/1-, ROADMAP: 0✓/1!)

INVARIANTS — Violations (4)

ROOT CAUSE ANALYSIS

  • src/v2/04_env.dag TypeEnv still defines one authority, source_indices, but the refactor renamed only some emitter consumers to source_index; that boundary split propagates into backend wrappers as mixed field reads and helper calls. Fix it upstream by keeping one canonical field or accessor on TypeEnv and updating all emit consumers atomically, which is the M2 single-authority fix instead of more downstream patches.
  • src/v2/00_core.dag ExprFieldAccess already carries structural authority through FieldSummary and FieldAccessStyle, but this emit path ignores it and re-derives call-vs-field from binding heuristics; that gap propagates into stage0 as ordinary value receivers being rewritten as thunks. Fix it upstream by having both simple and typed field emission consume one receiver-kind authority from the IR, which is the M8 and No parallel implementations fix.
  • src/v2/05_emit.dag The shared service path models nested blocks as raw String payloads from render_transport_body and render_service_fields instead of compositional block fragments, so indentation is patched downstream one line at a time and Python loses structure. Fix it upstream by returning List or a BlockEmitState-like fragment and letting the shared emitter assemble indentation from BlockSyntax, which is the M1 and Track 13 compositional fix.

MODELING — Strengths

  • src/v2/languages.dag ServiceMethodStrategy and ServiceReturnStrategy turn receiver placement and result shape into closed LanguageSpec data, which composes with VisibilitySpec and ItemKeywords and moves backend decisions out of per-language emitter code.

MODELING — Improvements

  • src/v2/languages.dag SelfInParams { self_param: String } and ErrorTupleReturn { error_type: String } still store rendered tokens like &self and error; model receiver mode and result carrier shape structurally so Track 13 Phase 5-6 borrow work composes instead of hiding in strings.

ROADMAP — Incomplete

  • Track 13 Phase 3-4: The diff clearly centralizes TCO and service/transport orchestration, but the mixed source_index boundary and string-based Python block rendering mean Phase 3-4 are not mechanically correct end-to-end yet.

ROADMAP — Unclaimed

  • Track 13 Phase 3-4: This PR is the roadmap's stated next work for Track 13, but ROADMAP.md still says Phase 3-4 are only ready / Next.

The PR moves Track 13 in the right direction, but it still violates single-authority boundaries and relies on downstream string and heuristic emission patches, so it does not yet meet the thesis's zero-bugs-by-construction bar.

@briansrls

briansrls commented Apr 12, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I reviewed the PR diff against the thesis and the attached docs.

The direction is right: Track 13 explicitly wants shared TCO and shared service/transport traversal, and the thesis wants emission to be mechanical translation from declared target facts rather than per-backend logic. The new ServiceMethodStrategy / ServiceReturnStrategy coproducts are a good move in that direction. But I would not merge this as-is, because it still breaks the project’s “zero bugs by construction” bar in a few load-bearing places.

  1. Blocker: the PR edits generated stage0 files directly, without matching .dag authorities.

In this diff, src/v2/stage0/src/v2_compiler_parse.rs, src/v2/stage0/src/v2_std_core.rs, src/v2/stage0/src/v2_compiler_emit.rs, and src/v2/stage0/src/v2_compiler_emit_rust.rs are changed directly. Those edits add real language/emission facts: a new reserved/config key (transport_headers_key), REST-header parsing, changed REST-body omission semantics for optional fields, and a new base_is_fn field-access heuristic. But the corresponding source authorities are not changed in this PR: there are no matching 00_core.dag, 02_parse.dag, or 05_emit_rust.dag edits.

That is a straight source-of-truth violation. The roadmap says stage0 is a derived artifact from .dag source and only compiler_tests.rs is intentionally non-generated; it also sets the direction as “Single emitter reads data, never decides.” The invariants explicitly say stage0 should be generated, not hand-maintained, and that parallel implementations will drift.

Under the thesis, once stage0 and .dag disagree about the language, emission is no longer a mechanical consequence of validated intent. You now have two compilers with different facts. chatgpt-review-92e85b0f-6149-4f…

What I’d do instead: land the source-side authorities first, regenerate stage0, and let the generated Rust reflect them. For this PR specifically, that means:

  • transport_headers_key and REST-header parsing belong in source compiler modeling, not only stage0.
  • the REST body omission behavior belongs in source emit logic, or better, in a structural wire-format model.
  • the base_is_fn behavior should not exist only in generated Rust.
  1. Blocker: the source_index / source_indices change looks like a real compile break.

The shared and backend emitters now use tm.type_env.source_index / scope.type_env.source_index in multiple places, while other code in the same PR still uses env.source_indices and input.scope.type_env.source_indices, and the surrounding codebase still uses source_indices as the authoritative field name. Unless there was a simultaneous rename outside this diff, this looks like a partial rename/typo and likely won’t compile.

This is exactly the kind of broken causal link the thesis is trying to make impossible: not a modeling disagreement, just a refactor introducing an inconsistent boundary name. chatgpt-review-92e85b0f-6149-4f…

  1. The new service strategy modeling is directionally good, but still under-modeled.

ServiceMethodStrategy and ServiceReturnStrategy are the right kind of change: they turn an open-ended backend convention into closed coproducts, which matches the modeling guidance to use sum types for fixed sets and to keep dispatch structural. chatgpt-review-d38107ee-3854-45…

But emit_unified_operation_method still hardcodes Go syntax in the shared emitter:

  • receiver syntax is synthesized with concat("(", v, " *", service_name, ") ")
  • Go error returns are synthesized with concat(" (", ret_type, ", ", et, ")")

So the shared emitter is still deciding target syntax instead of just reading it. That cuts against both the roadmap goal that codegen decisions become spec-referenced lookups and the invariant that emission should translate annotated structure rather than branch on target-specific syntax in code.

I would treat this as “good refactor shape, incomplete factoring.” The next step is to push one level farther:

  • model receiver syntax as a real language-spec fact, not just ExternalReceiver { var_name }
  • model service return syntax as a real formatter/template, not just ErrorTupleReturn { error_type }

Right now the PR has moved the classification into LanguageSpec, but the rendering is still partly hardcoded in shared emit.

  1. The new REST/body behavior is still a downstream heuristic, not a declared transport fact.

The stage0 Rust emitter now special-cases optional record fields in request bodies: required fields go into the initial JSON object, optional fields are only inserted when the value is Some(...). That may be desirable for some APIs, but it is a wire-format policy decision. The roadmap already calls out this entire class of problem: wire/text-vs-JSON behavior and shell channel behavior should become explicit structural facts rather than being inferred from type shape or field names.

Under the invariants, this is a textbook Root-Cause Depth issue: if the emitter needs to know whether None means “omit field” versus null, that fact belongs upstream in the transport model, not guessed from Optional at the leaf.

Related concern, lower confidence but still worth flagging: the new base_is_fn patch in stage0 shared emit looks over-broad. It treats almost any ExprVar that is not a match-bound or variant-value binding as callable and rewrites field access to base().field, plus .clone() in Rust. Unless the reconcile/emit boundary now guarantees that only function-valued refs reach that path, this is another downstream heuristic compensating for an ambiguous boundary. The invariants already call out function-as-value handling as a live semantic-boundary debt.

  1. Minor: there is still some unnecessary interface drag.

emit_unified_operation_method accepts registry but does not use it, and emit_unified_service_def threads it through anyway. Small issue, but it’s the kind of “pass more than you read” interface shape the invariants try to avoid. chatgpt-review-04d8bd3b-04d4-45…

A couple of positives:

  • extracting shared TCO/service traversal is exactly the right roadmap direction for Phase 3/4.
  • emit_unified_transport_dispatch now fails closed on unrecognized transport instead of silently falling into a fallback path, which is better aligned with “no fallbacks that fabricate.” chatgpt-review-04d8bd3b-04d4-45…

Net: good directional refactor, not merge-ready.

My merge blockers are:

  • manual stage0/source divergence
  • the probable source_index typo/partial rename
  • the fact that the shared emitter still hardcodes Go method/return syntax instead of fully reading LanguageSpec
  • the new wire-format/function-call heuristics landing in emit rather than being modeled upstream

If those are fixed, the underlying Phase 3/4 extraction looks worth landing.


View conversation

…trap

Fix remaining source_index → source_indices field accesses in emitter
files (TypeEnv.source_index → .source_indices, empty_map() for
TypeEnv construction). Bootstrap stage0 with new ServiceMethodStrategy
and ServiceReturnStrategy coproduct type imports.

Also fixes: go_source_extension missing () call in generated languages.rs.

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

briansrls commented Apr 12, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I reviewed the PR diff against the thesis and attached docs.

Overall: the direction is right. This PR removes parallel Go/Python implementations by extracting shared TCO and shared service/transport rendering into 05_emit.dag, which is exactly the kind of consolidation the thesis and invariants want: fewer parallel mechanisms, more mechanical translation from declared facts. Track 13 explicitly says Phase 3/4 is shared TCO/block unification plus service/transport unification, so this is roadmap-aligned. chatgpt-review-c6b1f0a7-5b6a-4d…

chatgpt-review-4f2b7385-3463-4d…

I would still push back on one design issue before merge, and call out two follow-up concerns.

  1. The new ServiceMethodStrategy is only half-closed.

languages.dag adds ServiceMethodStrategy / ServiceReturnStrategy, which is the right modeling shape: a fixed design-time set should be an enum, not a string. chatgpt-review-55e1e370-13c7-4b…

But the PR then uses dag_spec.service_method = SelfInParams { self_param: "" }, and emit_unified_operation_method branches on sp == "" to mean “actually no self param.” That reintroduces a hidden third case through a string sentinel. Under the modeling rules, this is exactly the thing the enum was supposed to eliminate. The real closed set is not just SelfInParams | ExternalReceiver; it is at least SelfInParams | NoSelfParam | ExternalReceiver. Using "" as structure is a modeling leak.

I would fix that in this PR by making the no-self form explicit, not encoded as an empty string.

  1. The shared emitter still makes Go-specific rendering decisions.

The new shared layer is a good extraction, but emit_unified_operation_method still hardcodes Go method syntax:

  • external receiver is rendered as (<var> *<Service>)
  • Go error returns are rendered as (<ret>, error_type)

That means the PR centralizes backend logic, but it does not yet meet the stronger invariant that emission is a pure translation from (annotated graph + LanguageSpec) and that adding a target should require data, not new logic. The invariants are explicit that emit should read LanguageSpec, not hardcode target syntax, and the roadmap’s target state is “single emitter reads data, never decides.” chatgpt-review-31be40db-1433-47…

chatgpt-review-4f2b7385-3463-4d…

I would not call this a functional bug in the narrow sense, because it preserves the old Go behavior. But it is important architectural truth-in-labeling: this PR is a good Phase 3/4 consolidation, not full thesis completion for Track 13.

  1. Transport dispatch improves fail-closed behavior, but it needs coverage.

emit_unified_transport_dispatch is better than the old per-backend else => local fallback. Making “unknown transport kind” an explicit emission error is aligned with “no fallbacks that fabricate.” Pasted markdown

But because the old Go/Python helpers treated the catch-all as local, this is also a behavior change. That is good only if every intended local path is already structurally represented as a real local transport. The repo docs already call out transport/service modeling as an area where heuristics still need to become structural facts. chatgpt-review-ba1c1f33-cd59-4f…

chatgpt-review-31be40db-1433-47…

The problem is that the only test change I see is source_audit.rs, and it checks TCO symbol placement, not service-method shape or transport behavior. Given the thesis bar and the fact that L4 semantic emission verification is still not implemented, this refactor needs stronger regression tests than symbol-presence audits. chatgpt-review-c6b1f0a7-5b6a-4d…

At minimum I’d want one representative emitted-output test per backend covering:

  • Python method signature includes self
  • Go method signature includes receiver + (ret, error)
  • explicit local transport still renders the intended call path
  • unknown transport fails closed
  1. Minor invariant nit: registry is threaded where it is not used.

emit_unified_operation_method accepts registry, but the shared helper does not read it. That is small, but it violates the repo’s “minimal information per interface” preference: pass only what the function actually consumes. chatgpt-review-04d8bd3b-04d4-45…

  1. No roadmap-drift issue here.

I do not see ROADMAP.md modified in this PR, so there is no roadmap-alignment drift to review. The change is directionally aligned with Track 13 and RE-3’s “emitter heuristics should become structural facts,” but it does not finish that work. chatgpt-review-4f2b7385-3463-4d…

chatgpt-review-ba1c1f33-cd59-4f…

Net: good refactor, right direction, not quite at the thesis bar yet.

My recommendation:

  • fix the empty-string sentinel by making the no-self case structural
  • land this as “shared extraction” rather than “fully data-driven service rendering”
  • add emitted-service regression tests before merging or immediately alongside it

View conversation

1. Add TODO comments on hardcoded Go receiver syntax and error tuple
   format in emit_unified_operation_method — tracked as Phase 5 items
   for receiver_template and return_template on LanguageSpec.

2. Document the M5 codegen gap: the .dag compiler does not generate
   `use` statements for new coproduct types used in match arms. The
   bootstrap imports for ServiceMethodStrategy/ServiceReturnStrategy
   are manually added with a comment explaining why.

3. Fix go_source_extension() missing parens in generated languages.rs.

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.

codex · gpt-5.4 · 78dc26ca

Review (INVARIANTS: 3, MODELING: 1+/1-, ROADMAP: 0✓/2!)

INVARIANTS — Violations (3)

ROOT CAUSE ANALYSIS

  • src/v2/languages.dag Upstream gap: the compiler-local LanguageSpec still lacks a single structural authority for service method headers and returns, so 05_emit.dag introduces ServiceMethodStrategy and ServiceReturnStrategy and then finishes the job with hardcoded Go syntax; project the existing std.languages function, error, and type syntax into v2.compiler.languages, or add one ServiceDefinitionSyntax in std/, so shared emission only instantiates declared templates (M1, M9).
  • src/v2/05_emit_rust.dag Upstream gap: .dag-to-Rust import derivation is still losing type dependencies needed by generated match-arm code, which forces a downstream hand-edit in src/v2/stage0/src/v2_compiler_emit.rs; fix import emission at the generator, regenerate, and keep stage0 free of manual bootstrap exceptions.
  • src/v2/05_emit.dag Upstream gap: the refactor abstracted transport rendering behind callbacks but preserved the old backend-shaped signature, so a global registry bag still propagates through shared service orchestration and obscures the real dependency set; remove registry from emit_unified_operation_method and emit_unified_service_def, and let backend closures capture it only if a transport renderer actually needs it.

MODELING — Strengths

  • src/v2/languages.dag ServiceMethodStrategy and ServiceReturnStrategy model the current backend split as closed coproducts instead of open string flags, which is the right M4 shape for a finite strategy set.

MODELING — Improvements

  • src/v2/languages.dag These new compiler-local types are only a partial proxy for function, error, and service syntax already grounded in dsl/std/languages.dag; a more compositional model would project that existing authority, or add one ServiceDefinitionSyntax in std/, so 05_emit.dag composes templates instead of branching on bespoke service enums (M1, M9, layer alignment).

ROADMAP — Incomplete

  • Track 13 Phase 4: The PR clearly advances service and transport unification, but hardcoded pointer-receiver and error-tuple syntax in 05_emit.dag mean Phase 4 still falls short of Track 13's LanguageSpec-driven end state.
  • Bootstrap: The manual bootstrap imports added in src/v2/stage0/src/v2_compiler_emit.rs contradict ROADMAP.md's claim that stage0 content is generated from .dag source except for compiler_tests.rs.

ROADMAP — Unclaimed

  • Track 13 Phase 3: The diff introduces emit_unified_tco_expr and emit_unified_tco_body and moves Python and Go through the shared non-pattern TCO path, but ROADMAP.md still says Phase 3 is only next work.

The PR moves real Python and Go TCO and service logic into shared paths, but it still breaks the thesis at two root points: shared service emission is not yet pure LanguageSpec translation, and stage0 bootstrap is still being repaired downstream by hand.

Comment thread src/v2/05_emit.dag Outdated
let method_depth = match spec.service_method {
SelfInParams { self_param: _ } => 1
ExternalReceiver { var_name: _ } => 0
}

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_unified_operation_method hardcodes pointer-receiver and error-tuple syntax in shared emit code, violating Emission is translation, not decision-making and No duplicate representations.

@@ -33,7 +33,9 @@ pub use crate::v2_compiler_infer::{InferScope, build_params_scope, extend_scope}
pub use crate::v2_compiler_infer_emit_info::{TypeSummary, EmitGraphInfo};
pub use crate::v2_compiler_artifact::{RenderTarget};
use crate::v2_compiler_artifact::RenderTarget::{Rust, Python, Go, 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 bootstrap-only manual imports in a generated stage0 file violate No parallel implementations; stage0 should compile because the generator emitted the right imports, not because the artifact was patched.

Comment thread src/v2/05_emit.dag
target: RenderTarget,
registry: Map<String, ItemInfo>,
env: TypeEnv,
render_transport_body: fn(Node, String, Map<String, NewlineIndex>, Int) -> String

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_unified_operation_method keeps registry in the shared service API even though the new shared path never reads it, violating Minimal information per interface.

@briansrls

Copy link
Copy Markdown
Contributor Author

codex · gpt-5.4 · 78dc26ca

Review (INVARIANTS: 3, MODELING: 1+/1-, ROADMAP: 0✓/2!)

INVARIANTS — Violations (3)

ROOT CAUSE ANALYSIS

  • src/v2/languages.dag Upstream gap: the compiler-local LanguageSpec still lacks a single structural authority for service method headers and returns, so 05_emit.dag introduces ServiceMethodStrategy and ServiceReturnStrategy and then finishes the job with hardcoded Go syntax; project the existing std.languages function, error, and type syntax into v2.compiler.languages, or add one ServiceDefinitionSyntax in std/, so shared emission only instantiates declared templates (M1, M9).
  • src/v2/05_emit_rust.dag Upstream gap: .dag-to-Rust import derivation is still losing type dependencies needed by generated match-arm code, which forces a downstream hand-edit in src/v2/stage0/src/v2_compiler_emit.rs; fix import emission at the generator, regenerate, and keep stage0 free of manual bootstrap exceptions.
  • src/v2/05_emit.dag Upstream gap: the refactor abstracted transport rendering behind callbacks but preserved the old backend-shaped signature, so a global registry bag still propagates through shared service orchestration and obscures the real dependency set; remove registry from emit_unified_operation_method and emit_unified_service_def, and let backend closures capture it only if a transport renderer actually needs it.

MODELING — Strengths

  • src/v2/languages.dag ServiceMethodStrategy and ServiceReturnStrategy model the current backend split as closed coproducts instead of open string flags, which is the right M4 shape for a finite strategy set.

MODELING — Improvements

  • src/v2/languages.dag These new compiler-local types are only a partial proxy for function, error, and service syntax already grounded in dsl/std/languages.dag; a more compositional model would project that existing authority, or add one ServiceDefinitionSyntax in std/, so 05_emit.dag composes templates instead of branching on bespoke service enums (M1, M9, layer alignment).

ROADMAP — Incomplete

  • Track 13 Phase 4: The PR clearly advances service and transport unification, but hardcoded pointer-receiver and error-tuple syntax in 05_emit.dag mean Phase 4 still falls short of Track 13's LanguageSpec-driven end state.
  • Bootstrap: The manual bootstrap imports added in src/v2/stage0/src/v2_compiler_emit.rs contradict ROADMAP.md's claim that stage0 content is generated from .dag source except for compiler_tests.rs.

ROADMAP — Unclaimed

  • Track 13 Phase 3: The diff introduces emit_unified_tco_expr and emit_unified_tco_body and moves Python and Go through the shared non-pattern TCO path, but ROADMAP.md still says Phase 3 is only next work.

The PR moves real Python and Go TCO and service logic into shared paths, but it still breaks the thesis at two root points: shared service emission is not yet pure LanguageSpec translation, and stage0 bootstrap is still being repaired downstream by hand.

@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.

codex · gpt-5.4 · 8636e09e

Review (INVARIANTS: 4, MODELING: 1+/1-, ROADMAP: 1✓/1!)

INVARIANTS — Violations (4)

ROOT CAUSE ANALYSIS

  • src/v2/05_emit.dag Missing upstream service-call boundary fact: the new shared transport contract drops op_node/params before rendering begins -> local transport renderers only know a name and must fabricate zero-arg calls -> pass the operation node or rendered argument list through render_transport_body/emit_unified_transport_dispatch so local transport emission translates the declared signature mechanically instead of guessing (MODELING.md M8/M9).
  • src/v2/05_emit.dag Missing upstream service-signature authority: LanguageSpec now distinguishes SelfInParams vs ExternalReceiver and ArrowReturn vs ErrorTupleReturn, but it still does not declare how those forms render -> 05_emit.dag fills the gap with target-specific string assembly -> move receiver and service-return rendering into declared LanguageSpec/std.languages syntax data and have emit_unified_operation_method apply templates mechanically (MODELING.md M7/M9).
  • src/v2/stage0/src/v2_compiler_emit.rs Missing upstream import derivation in the .dag->Rust generator for coproduct variants used in generated match arms -> the generated Rust artifact needs hand-maintained use lines to compile -> teach the generator to derive those imports from the referenced type definitions, then regenerate and delete the manual patch so stage0 remains a pure consequence of source (MODELING.md M7/M9).

MODELING — Strengths

  • src/v2/languages.dag ServiceMethodStrategy models receiver placement as a closed coproduct in LanguageSpec, which composes better than branching on target names in the emitters.

MODELING — Improvements

  • src/v2/languages.dag ServiceReturnStrategy is too thin to be the authority: per M9 it should compose from existing function/error language facts or a richer service-signature product, because the current model still leaves 05_emit.dag hardcoding receiver and Go tuple syntax.

ROADMAP — Verified

  • Track 13 Phase 3: The diff adds emit_unified_tco_expr and emit_unified_tco_body and rewires Go/Python TCO entry points to use them, so TCO recursion did move into the shared emitter.

ROADMAP — Incomplete

  • Track 13 Phase 4: Service/transport orchestration moved into 05_emit.dag, but shared service emission is not yet mechanically complete because receiver syntax, Go error-tuple syntax, and local-transport argument forwarding are still missing from the upstream language contract.

ROADMAP — Unclaimed

  • Track 13 progress: This PR materially advances Track 13 beyond Phase 3-4 ready, but ROADMAP.md was not updated to record the landed Phase 3 work and the remaining Phase 4 gaps.

The PR moves Track 13 forward, but it still violates zero-bugs-by-construction where the shared emitter makes target decisions from missing upstream facts instead of translating a complete declared model.

Comment thread src/v2/05_emit.dag
target: RenderTarget,
registry: Map<String, ItemInfo>,
env: TypeEnv,
render_transport_body: fn(Node, String, Map<String, NewlineIndex>, Int) -> String

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_unified_operation_method hands transport renderers only (transport, op_name, source_indices, depth), so local transport emission cannot forward the operation's declared parameters, violating Explicit boundary contracts.

Comment thread src/v2/05_emit.dag Outdated
// rendering template so the shared emitter reads, never decides.
let receiver_str = match spec.service_method {
SelfInParams { self_param: _ } => ""
ExternalReceiver { var_name: v } => concat("(", v, " *", service_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 shared emitter hardcodes Go receiver syntax as "(" + var + " *" + service_name + ")" instead of reading declared language data, violating Emission is translation, not decision-making.

Comment thread src/v2/05_emit.dag Outdated
let ret_type = emit_node_type(n: resolved_type(n: op_node), target: target, source_indices: si)
let ret_str = match spec.service_return {
ArrowReturn => concat(spec.items.return_arrow, ret_type)
ErrorTupleReturn { error_type: et } => concat(" (", ret_type, ", ", et, ")")

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 shared emitter hardcodes Go's "(T, error)" return form instead of deriving it from the language contract, violating Emission is translation, not decision-making.

Comment thread src/v2/stage0/src/v2_compiler_emit.rs Outdated
pub use crate::v2_compiler_artifact::{RenderTarget};
use crate::v2_compiler_artifact::RenderTarget::{Rust, Python, Go, Dag};
pub use crate::v2_compiler_languages::{LanguageSpec, TestConventions, ServiceFieldTemplates, BlockSyntax, TcoSyntax, ExpressionSemantics, IfValueForm, VisibilitySpec, NamingCase, ReservedWordStrategy, StringInterpSyntax, InterpStyle, EscapePair, RecordLitSyntax, ImportRule, language_spec_for_target, is_string_like, test_conventions_for_target, target_keyword, binop_symbol, wrap_shared_type, TestNameStyle, ImportTrigger};
// Bootstrap: ServiceMethodStrategy + ServiceReturnStrategy imports are added

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 generated stage0 file now advertises manual bootstrap imports for coproduct variants, violating No parallel implementations.

@briansrls

Copy link
Copy Markdown
Contributor Author

codex · gpt-5.4 · 8636e09e

Review (INVARIANTS: 4, MODELING: 1+/1-, ROADMAP: 1✓/1!)

INVARIANTS — Violations (4)

ROOT CAUSE ANALYSIS

  • src/v2/05_emit.dag Missing upstream service-call boundary fact: the new shared transport contract drops op_node/params before rendering begins -> local transport renderers only know a name and must fabricate zero-arg calls -> pass the operation node or rendered argument list through render_transport_body/emit_unified_transport_dispatch so local transport emission translates the declared signature mechanically instead of guessing (MODELING.md M8/M9).
  • src/v2/05_emit.dag Missing upstream service-signature authority: LanguageSpec now distinguishes SelfInParams vs ExternalReceiver and ArrowReturn vs ErrorTupleReturn, but it still does not declare how those forms render -> 05_emit.dag fills the gap with target-specific string assembly -> move receiver and service-return rendering into declared LanguageSpec/std.languages syntax data and have emit_unified_operation_method apply templates mechanically (MODELING.md M7/M9).
  • src/v2/stage0/src/v2_compiler_emit.rs Missing upstream import derivation in the .dag->Rust generator for coproduct variants used in generated match arms -> the generated Rust artifact needs hand-maintained use lines to compile -> teach the generator to derive those imports from the referenced type definitions, then regenerate and delete the manual patch so stage0 remains a pure consequence of source (MODELING.md M7/M9).

MODELING — Strengths

  • src/v2/languages.dag ServiceMethodStrategy models receiver placement as a closed coproduct in LanguageSpec, which composes better than branching on target names in the emitters.

MODELING — Improvements

  • src/v2/languages.dag ServiceReturnStrategy is too thin to be the authority: per M9 it should compose from existing function/error language facts or a richer service-signature product, because the current model still leaves 05_emit.dag hardcoding receiver and Go tuple syntax.

ROADMAP — Verified

  • Track 13 Phase 3: The diff adds emit_unified_tco_expr and emit_unified_tco_body and rewires Go/Python TCO entry points to use them, so TCO recursion did move into the shared emitter.

ROADMAP — Incomplete

  • Track 13 Phase 4: Service/transport orchestration moved into 05_emit.dag, but shared service emission is not yet mechanically complete because receiver syntax, Go error-tuple syntax, and local-transport argument forwarding are still missing from the upstream language contract.

ROADMAP — Unclaimed

  • Track 13 progress: This PR materially advances Track 13 beyond Phase 3-4 ready, but ROADMAP.md was not updated to record the landed Phase 3 work and the remaining Phase 4 gaps.

The PR moves Track 13 forward, but it still violates zero-bugs-by-construction where the shared emitter makes target decisions from missing upstream facts instead of translating a complete declared model.

@briansrls

briansrls commented Apr 12, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I reviewed PR #407 diff against the thesis first.

Against the project thesis, the direction is correct: this PR removes parallel Go/Python mechanisms and pushes more emission behavior into shared paths and LanguageSpec, which is exactly the kind of unification the causal-engine model wants. The thesis says emitted code should be a mechanical consequence of validated intent, not an interpretation layered on afterward, and it explicitly treats concept unification and “coercion = emission” as architectural wins, not refactors of convenience. chatgpt-review-54134ce3-423c-41…

My verdict: good direction, but I would request changes before merge.

What this PR gets right

This is clearly aligned with Track 13’s next steps. The roadmap says Track 13 Phase 3 is TCO/block unification and Phase 4 is service/transport, with the target being a single emitter that reads LanguageSpec data instead of deciding in backend code. That is exactly what this PR is trying to do. chatgpt-review-96957224-17a4-4d…

chatgpt-review-04d8bd3b-04d4-45…

The new ServiceMethodStrategy and ServiceReturnStrategy in languages.dag are also the right modeling shape: fixed design-time sets should become closed sum types, not open strings. That matches the modeling guidance that closed sets should be enums and dispatch should be structural. chatgpt-review-87ab0494-7697-43…

I also like that transport dispatch is now more fail-closed. The shared transport helper no longer silently defaults everything unknown to “local”; it checks local transport explicitly and emits an error for unrecognized transport kinds. That is much closer to the invariants’ “no fallbacks that fabricate” bar. chatgpt-review-04d8bd3b-04d4-45…

Main issue 1: ServiceMethodStrategy is only half-modeled

The biggest modeling problem is that the new enum is immediately undercut by a string sentinel.

In languages.dag, dag_spec() now sets:

  • service_method: SelfInParams { self_param: "" }

And shared emission then branches on sp == "" to mean “actually there is no self parameter”.

That means the real design space is not:

  • SelfInParams
  • ExternalReceiver

It is at least:

  • SelfInParams { self_param }
  • NoSelfParam
  • ExternalReceiver { var_name }

Encoding that third case as "" reintroduces the very kind of hidden open-ended convention the enum was supposed to eliminate. Under the modeling rules, this should be structural, not stringly. Closed sets belong in coproducts, and predicates/dispatch should operate on structure rather than string extraction. chatgpt-review-87ab0494-7697-43…

chatgpt-review-87ab0494-7697-43…

This matters under the thesis because “zero bugs by construction” depends on making illegal states unrepresentable. An empty string is not a representation of “no self”; it is a loophole inside “self exists”. chatgpt-review-04d8bd3b-04d4-45…

Requested fix: add an explicit NoSelfParam variant and delete the sp == "" branch.

Main issue 2: the shared emitter still makes backend decisions

This PR centralizes code, but it does not yet fully centralize facts.

emit_unified_operation_method still hardcodes Go syntax in the shared emitter:

  • external receiver syntax is assembled inline as (<var> *<Service>)
  • Go error-tuple returns are assembled inline as (<ret>, <error_type>)

That is still target-specific rendering logic living in shared emit code. The invariants are very explicit here: emission should be a pure function from annotated graph + LanguageSpec to text, and if adding a target requires new emission logic instead of new data declarations, the emitter is still deciding instead of translating. chatgpt-review-96957224-17a4-4d…

chatgpt-review-96957224-17a4-4d…

So I would describe this PR as:

  • successful Phase 3/4 extraction
  • but not yet “single emitter reads data, never decides”

That distinction matters because the roadmap’s M4 target is stronger than “shared helper exists”; it is specifically “reads data, never decides”. chatgpt-review-04d8bd3b-04d4-45…

I would not reject the whole idea on this basis, but I would absolutely flag it in review. The current implementation moves decisions upward into shared code; it does not dissolve them into spec data yet.

Main issue 3: manual stage0 edits are still being introduced

There is an explicit manual stage0 workaround in this PR.

The stage0 shared emitter mirror adds a comment saying the ServiceMethodStrategy / ServiceReturnStrategy imports are added manually because the .dag compiler does not yet generate use statements for coproduct types used in match arms.

That is a direct hit on the “no parallel implementations” / generated-stage0 discipline. The invariants say stage0 should be generated from .dag source and the escape hatch is hand-editing generated code; the fix is making regeneration the only write path. chatgpt-review-31be40db-1433-47…

chatgpt-review-96957224-17a4-4d…

The roadmap’s process direction is even stricter: “adding a Node field requires zero manual stage0 edits”. This PR is not adding a Node field, but it is still normalizing a manual stage0 patch as part of feature work, which pulls against that same direction. chatgpt-review-ba1c1f33-cd59-4f…

I would treat this as real invariant debt, not just a bootstrap annoyance.

Main issue 4: tests are too narrow for what changed

The only test changes I see are source-audit ratchets around TCO unification. That is not enough coverage for what this PR actually changed.

This PR materially changes:

  • TCO orchestration paths
  • service method rendering paths
  • transport dispatch paths
  • stage0 mirrors of all of the above

But there are no new emitted-output tests covering service signatures or transport behavior across Python and Go.

That matters more here because the thesis still has a live verification gap: L4/L5 semantic correctness and cross-language equivalence are not implemented yet, so emitter refactors need stronger regression coverage, not weaker. chatgpt-review-c6c417cb-d77b-4b…

And the testing invariants say source-audit tests are a narrow exception; they are fine as architectural ratchets, but they should not become a substitute for behavioral checks. chatgpt-review-96957224-17a4-4d…

At minimum I would want one regression per backend for:

  • Python service method signature shape
  • Go service method signature shape, especially receiver + error tuple
  • explicit local transport still rendering the intended path
  • unrecognized transport failing closed

Minor issue: unnecessary interface drag

emit_unified_operation_method takes registry but does not use it.

Small issue, but it does violate the repo’s “minimal information per interface” principle: pass what the function reads, not whatever the caller happens to have. chatgpt-review-04d8bd3b-04d4-45…

No roadmap-drift issue

ROADMAP.md is not modified in this PR, so there is no claim inflation to audit inside the roadmap itself.

Directionally, though, the change is consistent with the current roadmap language: Track 13 says Phase 3/4 are ready and specifically names TCO/block unification plus service/transport as next work. chatgpt-review-96957224-17a4-4d…

Recommendation

I would leave this as request changes with three concrete asks:

  1. Replace the empty-string sentinel with an explicit NoSelfParam variant.
  2. Either move the remaining Go-specific method/return formatting fully into LanguageSpec, or label this PR honestly as partial extraction rather than full data-driven service rendering.
  3. Remove the manual stage0 import workaround before merge, or at least isolate it behind a generator fix in the same change.

Once those are addressed, the overall direction looks good and thesis-aligned.


View conversation

briansrls and others added 2 commits April 12, 2026 01:03
Move ServiceMethodStrategy/ServiceReturnStrategy dispatch into accessor
functions in languages.dag (service_self_param, service_receiver_str,
service_method_depth, service_methods_inside_class, service_return_str).

The emitter calls accessors instead of importing + pattern-matching the
coproduct types directly. This eliminates the stage0 bootstrap import
gap — no manual stage0 edits needed, freshness check passes cleanly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The .dag compiler generates data-constant references without call
syntax in struct literals (go_source_extension vs go_source_extension()),
causing a Rust type mismatch. Inline the string literal ".go" directly
in go_spec's scaffold to avoid the codegen gap.

Stage0 regenerated, fixed-point verified.

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

briansrls commented Apr 12, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I reviewed this PR against the thesis first, not just against local style. The bar here is “mechanical translation from validated intent,” not merely “less duplicated backend code.” The thesis explicitly collapses coercion into emission and says target specs should determine the output; the roadmap and invariants sharpen that into “the emitter reads specs and never decides.” chatgpt-review-045e5713-4361-4e…

chatgpt-review-9604e653-fff7-4a…

chatgpt-review-ad86e4b5-e7cc-4d…

Net: the TCO half is directionally good. The service half is not thesis-clean yet. I would request changes before merge.

1) Invariant violations

A. languages.dag reintroduces a duplicate authority for Go source extension

In the diff, go_spec() changes from source_file_extension: go_source_extension to source_file_extension: ".go", while 05_emit_go.dag drops the extdep import and adds a local helper that reads the scaffolded extension back from LanguageSpec.

That is not just a minor cleanup choice; it is an exact reintroduction of a documented invariant violation. The invariants already call out inline ".go" in languages.dag as a No duplicate representations failure and prescribe the opposite fix: repair constant-import emission, then keep go_source_extension as the single authority. chatgpt-review-ad86e4b5-e7cc-4d…

Why this matters under the thesis: duplicate representations are exactly how “mechanical translation” degrades into “whichever copy happened to be updated.” chatgpt-review-045e5713-4361-4e…

What I’d change:

  • Revert source_file_extension: ".go" back to the extdep authority.
  • Fix the Rust import-emission casing bug that previously made importing that data constant awkward, as the invariant note already suggests. chatgpt-review-ad86e4b5-e7cc-4d…

B. The new shared service path still makes target-language decisions

The new shared path is better factored than the old per-backend copies, but it still violates Emission is translation, not decision-making.

Concretely, the diff adds:

  • service_receiver_str(...) with a TODO saying Go receiver syntax "(c *Name) " is still hardcoded there.
  • service_return_str(...) with a TODO saying Go error-tuple syntax "(T, error)" is still hardcoded there.

That means the “unified” layer still contains backend-specific syntax logic; it has just moved from 05_emit_go.dag into languages.dag helper code. The roadmap’s stated target is stronger: specs in .dag data, emitter reads them, no inline target knowledge in compiler logic. chatgpt-review-9604e653-fff7-4a…

This is the core thesis mismatch in the PR. It improves duplication, but it does not yet achieve the intended unification.

What I’d change:

  • Make receiver rendering and return rendering pure LanguageSpec data/templates.
  • Let shared emit compose those templates, not branch on strategy and reconstruct syntax.

2) Compositional modeling quality (.dag changes)

The right place for these facts is languages.dag; MODELING treats it as the emission-layer vocabulary, so moving service-method facts there is directionally correct. chatgpt-review-91f348f2-5124-46…

The problem is the model itself: ServiceMethodStrategy currently conflates multiple orthogonal facts.

SelfInParams { self_param } is being used to mean all of these at once:

  • receiver is spelled as a formal parameter,
  • methods live inside a class-like body,
  • indentation depth is 1,
  • receiver-prefix string is empty.

That happens to fit Python. It does not fit Rust, yet Rust is also populated with SelfInParams { self_param: "&self" }. So the abstraction is already semantically false for one of the specs it claims to model.

It gets worse: dag_spec() uses SelfInParams { self_param: "" }. That is an empty-string sentinel standing in for “no receiver.” In this repo, empty-string sentinels are exactly the kind of fabrication the invariants warn against. chatgpt-review-ad86e4b5-e7cc-4d…

This is the modeling fix I’d want:

  • split receiver syntax from method placement from return convention.
  • For example, separate concepts like:
    • MethodPlacement = InsideTypeBody | FreeFunction
    • ReceiverSyntax = ParamReceiver { text } | ExternalReceiverTemplate { ... } | NoReceiver
    • ReturnSyntax = ArrowReturn | TupleReturnTemplate { ... }

That would make the model compositional instead of overfit.

3) Roadmap alignment

ROADMAP.md is not modified, so there is no roadmap drift to flag.

Directionally, this PR is aligned with the roadmap:

  • TCO/block unification is exactly the next stated Track 13 step.
  • service/transport unification is also explicitly the next shared-emitter step.
  • keeping Rust-specific ownership logic out of this refactor is consistent with LS-4 still blocking Rust’s later phases. chatgpt-review-9604e653-fff7-4a…

But it does not reach the roadmap’s intended end-state yet, because the roadmap says Track 2/13 succeeds when target-language facts are modeled as .dag data and the emitter reads them rather than deciding. The new service helpers still decide. chatgpt-review-9604e653-fff7-4a…

So my alignment verdict is:

  • TCO part: aligned.
  • service part: partial alignment only.

4) General code review

C. Possible behavior change in transport fallback

Old Go/Python transport dispatch ended with an implicit else { local_call(...) }.

The new shared dispatcher is:

  • rest
  • shell
  • file
  • local
  • else => emit_error_expr("unrecognized transport kind", ...)

That is safer if effective_operation_transport(...) always materializes a real local-transport node that is_local_transport(...) recognizes.

If that guarantee is not airtight, this PR changes behavior from “unknown falls through to local” to “unknown hard-fails.” That might be correct, but it deserves either:

  • an invariant comment saying the fallback transport is always explicit local, or
  • a regression test proving it.

I would not block solely on this, but I would ask for confirmation.

D. The tests added here are too implementation-shaped for the scope of the refactor

The only visible test change in the diff is the source-audit check moving from Python-local TCO function names to shared emit_unified_tco_* names. That is useful as an architectural ratchet, but it is not enough for a refactor whose whole claim is “shared emission is mechanical and behavior-preserving.”

The invariants explicitly say behavioral tests are preferred, and source-audit tests are only a narrow exception. chatgpt-review-ad86e4b5-e7cc-4d…

I’d add at least:

  • one Go compile/output test that exercises a service with each transport shape through emit_unified_transport_dispatch,
  • one Python compile/output test for the same,
  • one TCO behavioral smoke per backend covering if + match + let/block through the shared path.

E. Positive note: the TCO extraction looks like a real unification

I did not find a thesis-level complaint about the shared TCO extraction itself.

emit_unified_tco_expr / emit_unified_tco_body genuinely remove duplicated Go/Python orchestration while leaving only the language-specific match/pattern rendering local. That is the kind of “new concept becomes an instance of an existing mechanism” move the thesis wants. chatgpt-review-045e5713-4361-4e…

Bottom line

I’d summarize the PR this way:

  • Good: real progress on shared TCO orchestration.
  • Not good enough yet: service rendering is centralized, but not yet reduced to authoritative spec data.
  • Concrete blocker: the PR reintroduces the already-documented ".go" duplicate-authority violation.
  • Modeling blocker: ServiceMethodStrategy is under-factored and already false for Rust / sentinel-based for Dag.

So my recommendation is: keep the TCO consolidation, rework the service/languages part before merge.


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.

codex · gpt-5.4 · 128de513

Review (INVARIANTS: 2, MODELING: 1+/1-, ROADMAP: 0✓/0!)

INVARIANTS — Violations (2)

ROOT CAUSE ANALYSIS

  • src/v2/languages.dag The upstream gap is that dsl/std/languages.dag still has no first-class service-definition syntax authority, so this PR adds compiler-local helpers that reconstruct receiver and return forms from strings; that missing lower-layer fact propagates into emit_unified_operation_method, which stays "shared" only by calling compiler logic instead of reading extdep data. Add a service-definition syntax model in dsl/std/languages.dag (or extend FunctionSyntax/TypeDefinitionSyntax/ErrorHandlingSyntax), populate it in language extdeps, and let 05_emit.dag do lookup-only translation per M1/M9 and the layer model.
  • src/v2/languages.dag The upstream gap is still the bootstrap/import path for extdep data constants, so the PR patches over the missing authority by copying the extension into go_spec; that duplicate then propagates through scaffold_for_target() into every Go path computation. Fix import emission so extdep data constants remain single-authority, then delete the inline literal per M2/M7.

MODELING — Strengths

  • src/v2/languages.dag ServiceMethodStrategy uses a closed coproduct instead of target-name branching, which is the right M4/M9 shape for method-form variation.

MODELING — Improvements

  • src/v2/languages.dag dag_spec currently uses SelfInParams { self_param: "" }, which shows the model is missing a NoReceiver case; add that variant and move service-definition syntax into dsl/std/languages.dag/extdeps so absence is structural, not a string sentinel.

ROADMAP — Unclaimed

  • Track 13 Phase 3-4: The diff clearly advances the planned TCO and service/transport unification, but ROADMAP.md still says Phase 3-4 are only "ready/next" instead of reflecting this as in-progress or partial work with remaining blockers.

The PR moves Phase 3/4 work toward a single emitter, but it still violates the zero-bugs-by-construction thesis where service-definition syntax and Go scaffold facts are reconstructed in compiler code instead of flowing from single-authority language data.

Comment thread src/v2/languages.dag
fn service_receiver_str(spec: LanguageSpec, service_name: String) -> String {
match spec.service_method {
SelfInParams { self_param: _ } => ""
ExternalReceiver { var_name: v } => concat("(", v, " *", service_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: service_receiver_str/service_return_str still encode Go receiver and (T, error) syntax with string concatenation in compiler code rather than declared language data, violating Emission is translation, not decision-making and No duplicate representations.

Comment thread src/v2/languages.dag
manifest_file: "go.mod",
module_init_file: null,
source_file_extension: go_source_extension,
source_file_extension: ".go",

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: go_spec.scaffold.source_file_extension is re-hardcoded as ".go" even though extdeps.languages.go.emit.go_source_extension already defines that fact, violating No duplicate representations.

@briansrls

Copy link
Copy Markdown
Contributor Author

codex · gpt-5.4 · 128de513

Review (INVARIANTS: 2, MODELING: 1+/1-, ROADMAP: 0✓/0!)

INVARIANTS — Violations (2)

ROOT CAUSE ANALYSIS

  • src/v2/languages.dag The upstream gap is that dsl/std/languages.dag still has no first-class service-definition syntax authority, so this PR adds compiler-local helpers that reconstruct receiver and return forms from strings; that missing lower-layer fact propagates into emit_unified_operation_method, which stays "shared" only by calling compiler logic instead of reading extdep data. Add a service-definition syntax model in dsl/std/languages.dag (or extend FunctionSyntax/TypeDefinitionSyntax/ErrorHandlingSyntax), populate it in language extdeps, and let 05_emit.dag do lookup-only translation per M1/M9 and the layer model.
  • src/v2/languages.dag The upstream gap is still the bootstrap/import path for extdep data constants, so the PR patches over the missing authority by copying the extension into go_spec; that duplicate then propagates through scaffold_for_target() into every Go path computation. Fix import emission so extdep data constants remain single-authority, then delete the inline literal per M2/M7.

MODELING — Strengths

  • src/v2/languages.dag ServiceMethodStrategy uses a closed coproduct instead of target-name branching, which is the right M4/M9 shape for method-form variation.

MODELING — Improvements

  • src/v2/languages.dag dag_spec currently uses SelfInParams { self_param: "" }, which shows the model is missing a NoReceiver case; add that variant and move service-definition syntax into dsl/std/languages.dag/extdeps so absence is structural, not a string sentinel.

ROADMAP — Unclaimed

  • Track 13 Phase 3-4: The diff clearly advances the planned TCO and service/transport unification, but ROADMAP.md still says Phase 3-4 are only "ready/next" instead of reflecting this as in-progress or partial work with remaining blockers.

The PR moves Phase 3/4 work toward a single emitter, but it still violates the zero-bugs-by-construction thesis where service-definition syntax and Go scaffold facts are reconstructed in compiler code instead of flowing from single-authority language data.

@briansrls
briansrls merged commit 5ba214b into main Apr 12, 2026
1 check passed
@briansrls
briansrls deleted the bright-koi-465 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