- strict-mode matrix: missing variables (top-level, in {{#each}},
in {{#if}} then and else branches) fail typed through both
sinks, never silent; the write sink's no-atomicity contract
pinned by its row
- error-surface completeness: six failure paths each mapping to
exactly one typed variant; registrations never half-survive;
hostile context values render clean through both sinks and both
escape policies with no panic paths
- two-sink correctness: byte-identical output over the ssr-shaped
and code-shaped fixture postures, re-exercised over the proof
fixture files (goldens stay pinned by the proof binaries)
- AGENTS.md: the wasm release build becomes standing and
unconditional; the feature-matrix coincide-today posture and the
handlebars feature-inspection posture documented honestly
(ADR-003, ADR-009)
Verification: cargo test (all green), cargo test --all-features
(identical), clippy -D warnings clean, fmt clean, doc clean, wasm
release build clean, handlebars tree features default-only,
taskgraph validate clean
- code-shaped fixture set: writer + validator template kinds over one
composed partial, no-op escaper, strict mode, all public API
- ADR-004 mappings in builder Rust (kind->call names, struct name,
string-kind flag, source-quoted literals); templates stay dumb
- document order (not sort/hash/reverse) drives rendered order;
reordered arrays render in the array's new order
- determinism: byte-identical across repeated renders, registry
rebuilds, differing registration orders, fresh contexts, and both
sinks (render vs render_to_write)
- banner stays an emit-layer obligation; no banner assertions in the
proof (gap recorded in task Notes, honestly)
Verification: cargo test (38 passed), cargo clippy --all-targets --
-D warnings, cargo fmt --check, taskgraph validate
- full consumer-shaped fixture set registered from the test binary via
register_template/register_partial only (ADR-008 machinery equality
in three caller-supplied text shapes: fixtures, runtime String,
inline literal)
- page composes fragment partials; the card fragment registers as its
own template, renders directly by name, and composes via include
- exact goldens pin html-escape posture (hostile data escaped, = and '
escapes, raw-output {{& }} slot verbatim)
- strict-mode render failure maps consumer-side to an error page built
from the typed Error's data, panic-free; source chain reachable
- determinism pinned across repeats, registry rebuilds, fresh
contexts, and both sinks (byte-identical, ADR-003)
- posture-B hygiene rows: no banner, no filesystem; no core changes
required (stop-and-book: nothing to book)
- 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
- ssr double: page template composing header/footer partials under the
HTML escaper, typed context built by a builder fn per ADR-004; golden
pins for composition, escaping of hostile interpolation, the trusted
{{& }} slot, and render-by-partial-name rejection
- code double: struct-writer template under the no-op escaper, typed
context built from a schema document with kind mapping and
source-escaped literals in the builder; golden pins for document-order
arrays and the active preserve_order feature
- fixture assets are include_str! files under tests/fixtures/; fixture
modules are per-test-binary so wave-2 proofs can grow them
- task file updated to completed with Notes and Summary
Verification: cargo test green (19 lib + 8 fixture tests), clippy
-D warnings clean, cargo fmt --check clean
- public TemplateSet::render (String sink) and
TemplateSet::render_to_write (io::Write sink), synchronous and
deterministic, both surfacing the wave-1 Error enum
- render-name rule enforced behaviorally: the entry resolves names
against the set-level bookkeeping before the substrate is
consulted, so a partial's name or an unknown name is a typed
Error::Render (substrate TemplateNotFound reason), never a
rendered partial
- strict-mode missing variable is a typed error in both sinks,
never silently-empty output; the write sink's streaming
(non-atomic) semantics on mid-render failure documented
- determinism pinned by tests: byte-identical repeated renders,
byte-identical output across registry rebuilds in opposite
registration order, and byte-for-byte agreement between sinks
Verification: cargo test (19 passed), cargo clippy --all-targets
-- -D warnings, cargo fmt --check, cargo doc --no-deps, and
cargo build --target wasm32-unknown-unknown --release all green.
- TemplateSet: one strict handlebars registry per template set; strict
mode forced at construction, unparameterizable; enforcement test pins
missing-variable renders as Error::Render, never empty output
- EscapePolicy::{Html, NoOp}: explicit per-set escaper choice; Html
leaves the substrate default html_escape, NoOp registers
handlebars::no_escape; both postures pinned by golden render tests
- typed fallible registration of templates and partials; malformed
text is Error::Registration, never a panic; failed registration
leaves bookkeeping untouched
- set-level bookkeeping of template vs partial names (decision 1,
flagged for the gate): the substrate's register_partial is identical
to template registration, so the render-name rule cannot delegate to
it; TemplateSet::is_template exposes the tracking for the
w1-render-entry rejection
- per-set helper registration seam; zero custom helpers by default,
pinned by test (unknown helper is a typed render error)
- naming conveventions enforced by tests only, not at registration
(decision 2, flagged for the gate): consumer-facing engine API
stays naming-neutral per ADR-001/008
Verification: cargo test (15 pass), clippy -D warnings, fmt --check,
wasm32-unknown-unknown release build
Verification: cargo test (15 pass), clippy --all-targets -D warnings, cargo fmt --check, wasm32-unknown-unknown --release
- src/error.rs: pub enum Error via thiserror with Registration
(#[from] TemplateError) and Render (#[from] RenderError) variants;
substrate errors stay reachable through the source chain
- src/lib.rs re-exports alkgen::Error per convention 10
- six unit tests pin variant mapping, source-chain reachability, and
operation-naming Display strings
- no catch-all; no context-build arm in this scope (recorded
interpretation, flagged for the wave-1 gate)
Verification: cargo test, clippy -D warnings, fmt --check, cargo doc,
wasm32-unknown-unknown release build, taskgraph validate (14 tasks)
all green
- pin handlebars = "6.4" on default features; tree verified free of walkdir and rhai
- remove alktype from deps: no consuming code in v0.1.0, so an optional
entry would be a dead feature; re-add lands with bast-rust-codecs as
bast-codegen = ["dep:alktype"] (flagged for the wave-1 gate)
- declare [features] bast-codegen = [] (name reserved per ADR-009, gates nothing)
- package metadata to the text-generation framing (ADR-001): description,
keywords, and the src/lib.rs crate doc; version stays 0.1.0
Verified: cargo test, clippy -D warnings, fmt --check,
wasm32 release build, taskgraph validate, dep-tree inspection
Five implementation tasks plus the gate, per the plan's decomposition
record. Deliberately sequential logistics: all tasks edit the same
small module tree and lib.rs re-exports, each consuming the previous
task's surface.
- w1-manifest: dep pins (handlebars 6.4 default features, thiserror),
alktype removal, bast-codegen feature name declared
- w1-error-model: the one public enum (registration/parse/render)
- w1-registry-construction: set builder, forced strict mode, escaper
policy, typed registration, helper seam; two decisions to record
- w1-render-entry: both sinks, deterministic, strict errors
- w1-engine-fixtures: ssr-shaped + code-shaped doubles, golden-pinned
- review-wave-1: the cheap-place gate; dispositions the four recorded
interpretations
Four interpretations flagged for the gate (alktype removal vs
optional-behind-feature, context-build arms, partial render-target
enforcement, naming validation); recorded in the plan.
Verification: taskgraph validate clean (14 tasks), waves + deps
acyclic, em-dash grep clean