- w2-ssr-proof and w2-code-proof: the two consumer-shaped proofs, parallel by construction (own test binaries, own fixture modules per the wave-1 convention) - w2-conformance-battery: the standing verification set, ordered after the proofs so it consolidates over the final wave-2 tree and absorbs any stop-and-book findings; folds the wave-1 gate's reminder (b) (wasm build standing, not ad-hoc) - review-wave-2: the wave gate, depends on all three - decomposition record added to docs/plans/implementation.md with the logistic-ordering rationale; wave-2 status flipped to decomposed Verification: taskgraph validate (18 tasks valid); em-dash grep clean on all changed files
313 lines
17 KiB
Markdown
313 lines
17 KiB
Markdown
---
|
|
status: open
|
|
last_updated: 2026-11-06 (created at the start of implementation;
|
|
wave 1 decomposed and its gate passed the same day; wave 2
|
|
decomposed immediately after)
|
|
---
|
|
|
|
# alkgen: Implementation plan
|
|
|
|
Wave-based decomposition of the architecture (`docs/architecture/`)
|
|
into units of implementable work. It follows the sibling pattern proven
|
|
on alkssh (`/workspace/@alkdev/alkssh/docs/plans/implementation.md`,
|
|
itself following alkgit/alkstore/alkblobs): decompose a wave, implement
|
|
it, review gate, decompose the next wave. Adopted deliberately as a
|
|
deviation from the SDD process's decompose-everything-upfront step: the
|
|
core wave's surfaces are what every later task and every consumer
|
|
implements against, the unactivated consumers (wgsl-jit,
|
|
bast-rust-codecs, call-handlers) can still reshape the queue, and
|
|
reviews sometimes change things downstream, so decomposing only the
|
|
next wave at a time keeps each session's task set reviewable and avoids
|
|
paying rework on tasks written too far ahead. The crate is smaller than
|
|
alkssh and the waves fewer, but the shape holds: the one-way doors (the
|
|
registry construction surface, the render entry semantics, the error
|
|
enum, and eventually the published API) are exactly the things worth
|
|
gating early.
|
|
|
|
Rhythm: decompose a wave, implement it, pass its review gate,
|
|
decompose the next wave. Task files live in `tasks/implementation/`
|
|
(frontmatter carries the categorical estimates; run `taskgraph
|
|
validate` after touching anything under `tasks/`). Wave boundaries are
|
|
also review boundaries. Each wave's section carries a **decomposition
|
|
record** added when that wave actually decomposes, never written
|
|
upfront.
|
|
|
|
## Scope authority
|
|
|
|
**v0.1.0 publishes the crate**: the shared text-generation core
|
|
(ADR-001), proven fit for its first consumer: ssr-html, per the
|
|
2026-11-06 consumer steer (alkforge SSR jumps the queue and needs
|
|
alkgen now). Concretely, v0.1.0 ships:
|
|
|
|
- the core's six components (`core.md`): registry construction,
|
|
template asset conventions, context conventions, the helper policy,
|
|
the render entry point, the error model; synchronous, wasm-clean,
|
|
and deterministic (ADR-003); strict mode always on (ADR-002);
|
|
escaper choice per registry (ADR-005).
|
|
- the consumer registration path (ADR-008): externally supplied
|
|
template and partial text enters through the public API with
|
|
machinery identical to engine-owned sets.
|
|
|
|
**Engine-owned template sets stay out of these waves.** The activation
|
|
queue (`targets.md`, per the consumer steer) runs ssr-html first, then
|
|
wgsl-jit, with bast-rust-codecs and call-handlers queued behind; none
|
|
of the three is unblocked in this scope: wgsl-jit waits on OQ-05 (the
|
|
alkjs GPU-layer work), bast-rust-codecs carries deferred OQ-01/02/03/09
|
|
plus its consumer integration story, call-handlers waits on OQ-04. The
|
|
`bast-codegen` feature name is declared in the manifest from the first
|
|
commit (ADR-009) but gates nothing until the set lands.
|
|
|
|
**The ssr-html target is proven in-crate, not shipped.** The target's
|
|
template set is consumer-owned (ADR-008): alkforge's page templates
|
|
live in alkforge, and alkforge's web-view design does not exist yet.
|
|
This plan therefore proves the target through consumer-shaped fixture
|
|
sets registering through the public API, the ADR-008 machinery-equality
|
|
path: if the shipped core serves a consumer-shaped set with no core
|
|
exceptions, the generality claim (ADR-001) holds on the real code, not
|
|
just the POC. The real templates and their golden pins land in alkforge
|
|
(family ADR-002 no-deformation rule: alkforge's asks flow in here as
|
|
design input, never as forks).
|
|
|
|
**The assembly stays out.** alkforge's linking of the crate, its page
|
|
design, its eager-cache-vs-render-per-request choice, its error-page
|
|
mapping are downstream composition (ADR-006). The crate ships the
|
|
engine, not a deployment. Library-only (ADR-010): no CLI, no binaries,
|
|
single crate, no workspace split.
|
|
|
|
Version note: the manifest already carries 0.1.0; the publish task
|
|
verifies rather than bumps.
|
|
|
|
## The waves
|
|
|
|
Dependency logic in one line: core foundations (consumer-shaped proofs
|
|
∥ conformance battery) release.
|
|
|
|
| Wave | Contents | Depends on | Status |
|
|
|---|---|---|---|
|
|
| [1](#wave-1-the-core) | The core: manifest landing (dep pins, alktype removal, feature graph); the public error model; registry construction (strict mode, escaper policy, typed registration, helper seam); the render entry point (two sinks); engine fixture doubles | none | decomposed |
|
|
| [2](#wave-2-consumer-shaped-proofs) | The generality proofs on shipped code: the full ssr-shaped (posture-B) fixture through the public API; the code-shaped (posture-A/C) fixture with ordering and determinism invariants; the conformance battery (strict-mode matrix, error surface, two-sink correctness, wasm, feature matrix) | wave 1 | decomposed |
|
|
| [3](#wave-3-validation--release) | Release readiness (README, CHANGELOG, rustdoc, dry-run, freeze inventory); the release gate; the publish | waves 1 + 2 | planned |
|
|
|
|
## Wave 1: The core
|
|
|
|
The consumer-blind contract surface in code: everything later waves
|
|
and every consumer registers and renders through. Nothing here needs a
|
|
real consumer to test.
|
|
|
|
- **Manifest landing** (ADR-002, ADR-009): the dependency set lands
|
|
with implementation start: `handlebars = "6.4"` from crates.io on
|
|
default features (the crate's `default = []`; `dir_source` and
|
|
`script_helper` are off-limits and must stay un-enabled, verified by
|
|
tree inspection), `serde` + `serde_json` with `preserve_order`
|
|
(load-bearing, convention 5), `thiserror = "2"`. **alktype leaves
|
|
the dependency tree**: it is listed unconditionally on main today,
|
|
ADR-009 decision 1 ships it only behind the feature, and no
|
|
engine-owned set lands in v1, so a dep behind a feature that gates
|
|
nothing is a dead entry (the alkssh wave-1 rule: sibling deps land
|
|
with their first consuming wave; interpretation recorded below). The
|
|
feature graph is declared from the first commit: `bast-codegen`
|
|
named, gating nothing. Package metadata (description, keywords)
|
|
updates to the text-generation framing (ADR-001). The landed dep set
|
|
is verified wasm-clean (ADR-003's validation posture, re-landed for
|
|
the new tree).
|
|
- **Error model**: the one public enum for the crate (core.md), via
|
|
thiserror, covering registration, template parsing, and rendering:
|
|
malformed templates and malformed inputs are data (convention 2;
|
|
alkcall accepts BAST from arbitrary peers, alkforge serves hostile
|
|
traffic). No catch-alls; every engine-owned failure maps to exactly
|
|
one variant. Context-build arms wait for the first engine-owned set
|
|
(interpretation recorded below; consumer builders own their errors
|
|
per ADR-008).
|
|
- **Registry construction**: the set builder (ADR-002 decision 6: one
|
|
registry per template set, what makes escaper policy and partial
|
|
namespaces enforceable rather than advisory): strict mode forced on
|
|
(never parameterizable), the escaper as an explicit per-registry
|
|
choice (HTML for ssr-shaped sets, no-op for code sets; ADR-005),
|
|
typed fallible registration of templates, partials (first-class from
|
|
day one, ADR-002 decision 5), and helpers, externally supplied text
|
|
accepted (ADR-008 consumers register through the same machinery), no
|
|
filesystem anywhere (the API takes `&str`; `dir_source` unreachable;
|
|
ADR-003).
|
|
- **Render entry point**: synchronous deterministic render of named
|
|
templates over serde-serializable contexts (core.md): both sinks
|
|
(String and `io::Write`; the substrate exposes both, `render` and
|
|
`render_to_write`), strict errors surfaced as data (a missing
|
|
variable is a typed error, never silently-empty output), templates
|
|
as the only render targets (see the interpretation below),
|
|
deterministic byte-identical output pinned by tests.
|
|
- **Engine fixture doubles**: the minimal in-crate template sets every
|
|
wave-2 proof runs through (the alkssh wave-1 doubles move: the
|
|
harness that exercises them deeply lands wave 2): a small ssr-shaped
|
|
set (page composing fragment partials, HTML escaper, typed context
|
|
built by a Rust builder per ADR-004) and a small code-shaped set
|
|
(no-op escaper, typed context with document-ordered arrays, the
|
|
`preserve_order` exercise). Fixtures are pinned by golden render
|
|
tests from day one (convention 7).
|
|
|
|
The wave-1 review gate is the cheap-place gate: the registry surface,
|
|
the render entry semantics, and the error enum are one-way doors in
|
|
practice (every later task implements against them; the published crate
|
|
freezes the public API). The gate reads the landed surface against
|
|
`core.md`'s component map and ADR-002/003/004/005 line by line.
|
|
|
|
**Decomposition record** (2026-11-06): wave 1 decomposed into five
|
|
task files under `tasks/implementation/` plus the gate. Shape:
|
|
`w1-manifest` first (the dep pin posture, the alktype removal, and the
|
|
feature-graph declaration everything lands inside); then a deliberately
|
|
sequential chain: `w1-error-model` (the public enum over the manifest),
|
|
`w1-registry-construction` (the set builder over the error model),
|
|
`w1-render-entry` (the deterministic strict render over the registry),
|
|
`w1-engine-fixtures` (the two minimal doubles over the shipped entry
|
|
points); then `review-wave-1` (the gate) depending on all five. The
|
|
chain is sequential *logistically*: all tasks edit the same small
|
|
module tree and `lib.rs` re-exports, and each consumes the previous
|
|
task's surface (the registry returns the error enum; the render entry
|
|
rides the registry; the fixtures ride both). Nothing here is parallel
|
|
enough to justify worktree separation.
|
|
|
|
Interpretations recorded (flagged for the wave-1 gate):
|
|
|
|
- **alktype removal vs optional-behind-feature**: ADR-009 item 4 says
|
|
moving alktype behind the feature is an implementation task (of what
|
|
it calls phase 3, the implementation phase now starting); but the
|
|
consumer steer queues bast-rust-codecs activation behind v1, so
|
|
there is nothing for `bast-codegen` to gate in this scope, and a
|
|
feature with no dep behind it is a dead entry. `w1-manifest` removes
|
|
alktype from the tree; the optional dep and the feature's payload
|
|
land together at target activation. Flagged for the gate to confirm
|
|
against ADR-009.
|
|
- **No context-build error arms in the v1 enum**: no engine-owned set
|
|
ships, and consumer builders own their errors (ADR-008). The arm
|
|
lands additively with the first engine-owned set (an additive change
|
|
pre-1.0; post-publish the freeze inventory carries the enum's
|
|
evolution policy). Flagged.
|
|
- **Partials-not-render-targets needs bookkeeping above the
|
|
substrate**: handlebars' registry is a single namespace (registering
|
|
a partial is template registration under the hood), so `core.md`'s
|
|
rule ("the name argument resolves to a registered template, never a
|
|
bare partial") cannot be delegated to the substrate. The registry
|
|
task decides between set-level bookkeeping (a set type that knows
|
|
which names are templates) and convention plus tests, and pins the
|
|
choice. Flagged.
|
|
- **Template naming validation**: convention 9 (lowercase kebab/snake,
|
|
one name per kind) is either validated at registration or enforced
|
|
by tests only; the registry task decides and records. Flagged.
|
|
|
|
## Wave 2: Consumer-shaped proofs
|
|
|
|
The generality claim re-proven on shipped code. Wave 1 landed the core
|
|
and minimal doubles; nothing here opens new engine surface unless a
|
|
proof finds a gap: the stop-and-book rule applies (a needed core
|
|
exception is booked for the gate, never silently absorbed; ADR-001's
|
|
falsifiability discipline).
|
|
|
|
- **The ssr-html proof (posture B)**: a full consumer-shaped fixture
|
|
set through the public API only: consumer-supplied page templates
|
|
and partials registered from outside the crate (the alkforge
|
|
posture, ADR-008 machinery equality), pages composing fragment
|
|
partials, fragments as registered render targets, HTML-escape golden
|
|
pins (interpolated output escaped, deliberate raw-output exercise),
|
|
typed render failure mapped toward the error-page shape (posture-B
|
|
error posture, `emit.md`). No banner, no filesystem; determinism is
|
|
what alkforge's caching rests on (ADR-003).
|
|
- **The code-shape proof (posture-A/C shape)**: a code-shaped fixture
|
|
set exercising the codec/JIT context shape on shipped code: typed
|
|
context with document-ordered arrays (the `preserve_order`
|
|
load-bearing test, convention 5), no-op escaping, and the
|
|
determinism invariant that generated-artifact hygiene rests on:
|
|
byte-identical output across repeated renders and registry rebuilds
|
|
(ADR-003). The DO-NOT-EDIT banner is an emit-layer obligation with
|
|
no engine-owned set to exercise it in v1; the proof notes that gap
|
|
honestly instead of implying coverage (convention 8, `emit.md`
|
|
posture A).
|
|
- **The conformance battery**: the standing verification set for the
|
|
core: the strict-mode behavior matrix (missing variable means a
|
|
typed error in both sinks, never silent output; ADR-002),
|
|
error-surface completeness (every engine-owned failure path maps to
|
|
exactly one typed variant; malformed template text at registration
|
|
and malformed context input at render are data with no panic paths),
|
|
the two-sink correctness rows, the wasm build of the final dep set
|
|
joining the verification list (ADR-003), and the feature-matrix
|
|
posture (`default` and `--all-features`, which coincide today;
|
|
documented honestly and grown when the first feature ships).
|
|
|
|
Wave 2 decomposes after the wave-1 gate, absorbing whatever it
|
|
corrects.
|
|
|
|
**Decomposition record** (2026-11-06, immediately after the wave-1
|
|
gate passed green; that gate absorbed no corrections, so nothing above
|
|
changes): wave 2 decomposes into three implementation tasks plus the
|
|
gate under `tasks/implementation/`. Shape: `w2-ssr-proof` and
|
|
`w2-code-proof` carry the two consumer-shaped proofs and are parallel
|
|
by construction: each lives in its own test binary owning its fixture
|
|
modules per the wave-1 convention, so there is nothing to sequence
|
|
between them and no shared-module collisions. Then
|
|
`w2-conformance-battery` depends on both proofs. The dependency line
|
|
above reads proofs ∥ battery and the wave releases when both groups
|
|
hold; the battery ordered after the proofs is a logistic choice with
|
|
the wave-1 precedent (a chain is sequential *logistically*, not
|
|
necessarily in working time): the battery consolidates the standing
|
|
verification set over the final wave-2 tree (strict-mode matrix,
|
|
error-surface rows, two-sink rows, feature-matrix posture, the wasm
|
|
build joining the verification list), which is only meaningful once
|
|
the proofs it stands beside have landed, and if a proof books a
|
|
finding under the stop-and-book rule, the battery would order itself
|
|
over the corrected surface rather than pin rows twice. Finally
|
|
`review-wave-2` (the wave gate) depends on all three. Carried
|
|
reminders from the wave-1 gate: (b) folds into the conformance task
|
|
(the wasm build becomes a standing, unconditional entry in the
|
|
verification command list rather than an ad-hoc gate run); (a) and
|
|
(c) remain wave-3 concerns and are deliberately unassigned here. The
|
|
stop-and-book rule applies throughout this wave: a proof that finds a
|
|
needed core exception books it for the gate with written rationale
|
|
and never silently absorbs it (ADR-001's falsifiability discipline).
|
|
|
|
## Wave 3: Validation & release
|
|
|
|
- **Release readiness**: public-API rustdoc warning-free; README
|
|
landing (the engine framing, the integration patterns: posture-B
|
|
usage for alkforge, the documented posture-A build-script pattern
|
|
per ADR-010, the posture-C note); CHANGELOG 0.1.0; the feature
|
|
matrix checked and documented (`default` and `--all-features`
|
|
coincide today); publish dry-run with a package file-list check
|
|
(verify the `exclude` list against what actually ships: SDD process
|
|
docs, research, and plans are working documents, not crate payload);
|
|
the freeze inventory recorded for the gate (the public API shape,
|
|
the strict-mode and determinism postures, the error enum, the
|
|
handlebars 6.4 pin's behavior).
|
|
- **review-wave-3**: the release gate, a pure review over the
|
|
readiness task and everything before it. It closes green only when
|
|
the crate is honestly shippable.
|
|
- **w3-publish**: the publish checklist: manifest sanity, the full
|
|
verification set including the wasm build, the dry-run, the
|
|
crate-qualified `alkgen-v0.1.0` tag (the family tag convention), and
|
|
`cargo publish`.
|
|
|
|
Wave 3 decomposes after the wave-2 gate, absorbing whatever it
|
|
corrects.
|
|
|
|
## Plan closure
|
|
|
|
The plan closes at the publish of **`alkgen 0.1.0`**: the publish
|
|
commit, tagged `alkgen-v0.1.0`, pushed to `origin/main`, status flipped
|
|
to `closed`. From the publish, the freeze inventory is one-way: the
|
|
public API shape, the strict-mode posture, the determinism guarantee,
|
|
and the error model are semver events from then on. Engine-owned
|
|
template sets (bast-codegen at its activation, wgsl at OQ-05's) land
|
|
through future waves of this document or a successor plan, each gated
|
|
by its own review.
|
|
|
|
## References
|
|
|
|
- `docs/architecture/`: README (index), overview, core, emit, targets,
|
|
open-questions, decisions/ADR-001 through 010
|
|
- `docs/research/phase-0.md`, `docs/research/reader-poc-summary.md`
|
|
(the POC findings the wave-2 proofs build on)
|
|
- `/workspace/@alkdev/alkssh/docs/plans/implementation.md` (the wave
|
|
pattern this follows)
|
|
- Family ADR-002 (`/workspace/@alkdev/alkfamily/docs/architecture/
|
|
decisions/002-alkforge-gitea-replacement.md`): why this crate
|
|
unpaused; the no-deformation rule
|
|
- `docs/sdd_process.md`: task file format, categorical estimates,
|
|
phases, the deferred-OQ convention
|