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
- Introduce typed stable IDs and assign them during program assembly.
- Replace string-concatenated endpoint joins with
EndpointID lookups.
- Define a lossless source-reference/source-map boundary so post-lowering validation does not require duplicate raw endpoint models.
- Extract
ServerPlan from appgen's current backend adapter projection.
- Extract corresponding static/client/audit projections as those consumers change.
- 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.
Summary
internal/gwdkir.Programis described as the stable single compiler handoff, but it currently combines several different abstraction levels: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
GoEndpointexists because normalizedEndpointis explicitly lossy and validation still needs the raw kind, method, and source spans.Program, increasing coupling among unrelated compiler consumers.Proposed model
Move toward explicit compiler stages:
The semantic layer should use stable typed identities, for example:
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
EndpointIDlookups.ServerPlanfrom appgen's current backend adapter projection.gwdkir.Programto semantic facts shared by multiple targets.Acceptance criteria