Skip to content

Split gwdkir.Program into semantic IR and target-specific plans #668

Description

@cssbruno

Summary

internal/gwdkir.Program is described as the stable single compiler handoff, but it currently combines several different abstraction levels:

  • parsed/source-oriented page, component, layout, block, and raw-body records;
  • normalized routes and endpoints;
  • standalone raw Go endpoint declarations;
  • resolved backend bindings;
  • templates and parsed view nodes;
  • contracts, realtime subscriptions, invalidations, and audit specs;
  • client behavior and asset records;
  • accumulated diagnostics.

Generators then build additional parallel projections, notably BackendAdapterIR, by copying endpoint metadata into registrations, action/API/fragment adapters, decoders, calls, responses, and fallbacks.

Architectural warning signs

  • GoEndpoint exists because normalized Endpoint is explicitly lossy and validation still needs the raw kind, method, and source spans.
  • Several records preserve both raw source bodies and parsed representations.
  • Endpoint bindings are rejoined in app generation using composite string keys rather than stable semantic identities.
  • New generated-output work is encouraged to add fields to the global Program, increasing coupling among unrelated compiler consumers.
  • A change for one target can expand the shared schema used by every other target.

Proposed model

Move toward explicit compiler stages:

Lossless AST/CST
    -> SemanticProgram / HIR
    -> StaticSitePlan | ServerPlan | ClientPlan | AuditProjection
    -> target generation

The semantic layer should use stable typed identities, for example:

type PageID string
type EndpointID string
type ComponentID string
type SourceID string

Source fidelity should remain in the lossless tree or a source-map service. Target plans should reference semantic IDs instead of repeatedly copying complete endpoint registrations.

This can be migrated incrementally; it does not require replacing every consumer at once.

Suggested phases

  1. Introduce typed stable IDs and assign them during program assembly.
  2. Replace string-concatenated endpoint joins with EndpointID lookups.
  3. Define a lossless source-reference/source-map boundary so post-lowering validation does not require duplicate raw endpoint models.
  4. Extract ServerPlan from appgen's current backend adapter projection.
  5. Extract corresponding static/client/audit projections as those consumers change.
  6. Narrow gwdkir.Program to semantic facts shared by multiple targets.

Acceptance criteria

  • Pages, components, routes, and endpoints have stable typed identities across compiler stages.
  • App generation no longer joins bindings through concatenated string keys.
  • Exact source spelling and spans needed for diagnostics are obtained from a lossless source model or source map, not a second raw semantic entity.
  • Target-specific generation decisions live in explicit target plans rather than the global shared IR.
  • Adding a field needed by only one generator does not require adding it to the shared semantic program.
  • Golden tests continue to pin AST, semantic IR, target plans, and emitted artifacts at clear stage boundaries.
  • The architecture documentation defines invariants for each stage and which package owns validation before and after lowering.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions