- Define the fragment-rendering convention: render targets are registered templates composing partials; partials are composition units (core.md, emit.md posture B) - Define template kind; trim/restage inline rationale with ADR citations (core.md) - Amend ADR-008: wgsl set ownership resolved engine-owned via OQ-05's 2026-11-06 resolution - Add OQ-09: consolidate the untracked bast-rust-codecs detailed-spec residue (projection, error shape, writer survey) with paired tracker task - Fix oq-05 tracker name to match the corrected unblocking condition - Add reviewed-transition rule: deferred OQs with tracker tasks do not block reviewed; flip six spec docs draft -> reviewed Verification: taskgraph validate (8 tasks valid), em-dash grep zero hits, cargo doc --no-deps clean
8.6 KiB
status, last_updated
| status | last_updated |
|---|---|
| reviewed | 2026-11-06 |
alkgen Architecture: Overview
Purpose
alkgen is the text-generation engine of the alk* stack. The core takes typed contexts, templates, and partials and produces text. Targets differ only in the template set, the context shape, and the posture by which the text is consumed. Everything underneath that is shared, and the shared part is what this architecture specifies.
This framing is a decision, not a description of intent. Phase 0 began with "codegen over BAST documents" and generalized through three real consumers until the general claim held: HTML is handlebars' native case, Rust codecs were validated end-to-end by the reader POC, and WGSL is proven by alkminer-v1's ShaderBuilder (three data points, one shape). ADR-001 records the decision and its constraint: shared core types must not bake reader/writer, HTML, or WGSL assumptions in.
The consumers, one shape
| Consumer | Output text | When |
|---|---|---|
| alkforge (family ADR-002) | HTML fragments and pages, rendered in-process | first, active now |
| alkjs | WGSL shader text feeding a render-then-compile cache | second, near term (OQ-05) |
| alkcall channels, via BAST codec templates | Rust reader/writer/validator modules, emitted at build time | queued later; POC-validated |
A fourth consumer class (call-protocol handlers, the static counterpart
of alkhttp's from_openapi / from_jsonschema adapters) is deferred
until the codec templates converge; see targets.md and OQ-04. Beyond
the named consumers, the layering is what unlocks downstream
composition: a dev utility generating OpenAPI- or BAST-derived code
builds contexts from its schema source, reuses or registers a template
set, renders through the same entry point, and applies its own emit
handling. Nothing in the core assumes a particular schema source or
emit target for that composition (ADR-001, ADR-010).
The queue order is alkforge's need, not a preference: the SSR branch is the simplest consumer and the generality test, and the WGSL branch follows because alkjs's GPU end builds on the same core (its requirements are consumer-readable only once that work starts; OQ-05). If the core renders HTML cleanly with no target-specific exceptions, the codegen paths are not overfitted.
Engine model
inputs: BAST document, or page data
│
▼
context builder template set
(Rust code; typed (templates, partials,
contexts out) helpers, escaper)
│ │
▼ ▼
contexts ───────────────► registry
│
▼
render (sync, deterministic)
│
▼
text artifacts (one per template kind)
│
▼
emit posture (see emit.md)
The vertical layers in this diagram are the crate's three concerns (two terms from sibling crates appear in the pipeline: a BAST document is alktype's binary abstract syntax tree document model, the wire schema format of the alk* stack; and plans are alktype's runtime walk structures over such documents, from which offset, size, and dispatch semantics are read out):
- Shared core (spec: core.md): registry construction (strict mode, first-class partials, per-registry escape policy, where an escaper is the function handlebars applies to interpolated output), context conventions, a deterministic synchronous render entry point, and the typed error model. All wasm-clean.
- Template sets (spec: targets.md): the per-target assets and their context shapes. Engine-owned sets ship in alkgen behind features (ADR-008, ADR-009); consumer-owned sets (alkforge page templates) live in the consumer.
- Emit postures (spec: emit.md): how rendered text reaches its consumer: build-time static files, in-process runtime render, or a render-to-compile feed.
Context building straddles 1 and 2: the conventions (typed structs, document order, mapping logic in Rust) are core; the actual context shapes are per-target.
What alkgen is not
- Not an interpreter. alktype walks BAST documents at runtime and owns
dynamic-schema semantics; alkgen is the compile-time counterpart for
the static case (phase-0 OQ-GN-03). The two are complements, and the
measured interpreter-vs-generated gap is codegen's value: roughly
1.9x at the
Valueoutput contract, 15 to 20x at the typed contract the POC validated. - Not a validator. Generated validators are a branch-1 (bast-rust-codecs) template-set concern (OQ-03); the core has no validation vocabulary.
- Not a web framework. SSR consumers get rendering; routing, headers, lifecycle, and caching are theirs (ADR-006).
- Not a CLI. v1 is library-only; build scripts integrate by documented pattern (ADR-010).
Dependencies
| Dependency | Role | Notes |
|---|---|---|
| handlebars 6.4 | render substrate | strict mode, partials, per-registry escaper; pinned to 6.4 from crates.io; the vendored /workspace/handlebars-rust checkout is reading material and an emergency patch source only |
| serde, serde_json | context serialization, schema documents | preserve_order is load-bearing: schema-JSON key order determines packed byte order downstream |
| alktype 0.4 | BAST document model and plans | used by codec template sets; feature-gated (ADR-009) so SSR consumers do not pull it |
| thiserror 2 | typed errors | convention 2 posture |
Wasm-cleanliness is validated, not assumed: the skeleton (the exact dep
set above) compiles to wasm32-unknown-unknown release, re-verified
2026-11-06, and handlebars-rust ships its own wasm playground. The
optional handlebars features dir_source and script_helper are
off-limits in lib code (filesystem access, rhai scripting).
Inherited constraints
The crate conventions in AGENTS.md bind all architecture work: no
comments in code, thiserror-only error handling, no async, wasm-clean,
preserve_order, strict template mode, templates as pinned code assets,
generated-code hygiene, standard naming, one module per file, zero
unsafe, no em dashes in prose. Where a convention is load-bearing for
the architecture, the relevant spec references it explicitly (strict
mode and error posture in core.md; banner and determinism in emit.md).
The family security posture (family ADR-002 decision 5) applies downstream-facing constraints here: minimal dependency surface for consumers (ADR-009 exists for this), deterministic output safe to cache and hash, and typed errors instead of panics on hostile or malformed input, since alkcall accepts BAST from arbitrary peers.
Design Decisions
All design decisions are documented as ADRs in decisions/.
| ADR | Decision | Summary |
|---|---|---|
| 001 | One core, targets as template sets | The generalized text engine; no target assumptions in core types |
| 002 | handlebars 6.4, strict mode, embedded templates | Substrate and registration posture |
| 003 | Sync, wasm-clean, deterministic | Core platform posture |
| 004 | Typed contexts, mapping in builders | Context conventions |
| 005 | Escaper per registry | HTML-escape for SSR sets, no-op for code sets |
| 006 | In-process SSR library | alkforge links alkgen; fragments and pages |
| 007 | Typed direct codecs | Branch-1 output contract from the POC debrief |
| 008 | Template set ownership | Engine-owned sets in-crate; consumer page templates outside |
| 009 | Feature-gated template sets | Default features ship core only |
| 010 | Library-only v1 | Build-script integration pattern, no CLI |
Open Questions
Open questions are tracked in open-questions.md. The ones shaping this overview's scope:
- OQ-04: call-protocol handler template set scope (deferred(scope))
- OQ-05: WGSL template set requirements (deferred(scope))
- OQ-06: template-JIT core requirements (deferred(scope))