Files
alkgen/tasks/implementation/review-wave-1.md
T
glm-5.3-flash 0a4aa1eefe chore(tasks): wave-1 review gate passes green
- Landed core verified against core.md's six components and
  ADR-002/003/004/005/008/009 postures, checked in code and tests
  rather than prose
- All four wave-1 interpretations confirmed: alktype removal (ADR-009
  decision 1, tree-verified), context-build arms absent by design
  (ADR-008), render-name rule via set-level bookkeeping, naming
  validation by tests only
- Verification set re-run clean: cargo test (27), clippy -D warnings,
  fmt, doc, wasm release build, taskgraph validate (14)
- Gate verdict green: wave-2 decomposition unblocked; three
  non-blocking reminders carried forward (freeze-inventory
  non_exhaustive decision, standing wasm pin, ADR-009 CI matrix)
2026-11-06 20:11:25 +00:00

9.9 KiB

id, name, status, depends_on, scope, risk, impact, level
id name status depends_on scope risk impact level
review-wave-1 Wave 1 gate: the core surface completed
w1-manifest
w1-error-model
w1-registry-construction
w1-render-entry
w1-engine-fixtures
narrow low phase review

Description

The cheap-place gate. The registry construction surface, the render entry semantics, and the error enum are one-way doors in practice: every later task implements against them, and the published crate freezes the public API. A shape error found here costs a task revision; found after consumers integrate it costs churn. The gate reads the landed surface against the architecture line by line and disposes of the wave-1 interpretations recorded in the plan.

Acceptance Criteria

  • Landed core checked against core.md's component map (registry construction, template assets, context conventions, helper policy, render entry point, error model); no unrecorded divergences
  • ADR postures verified in code: ADR-002 (strict mode forced, typed fallible registration, embedded assets, one registry per set), ADR-003 (sync, no filesystem, deterministic), ADR-004 (typed contexts, kind mapping in builders exercised by the fixtures), ADR-005 (escaper per registry)
  • The four wave-1 interpretations each receive a disposition: alktype removal (confirmed against ADR-009 or overturned), context-build error arms, partial-not-render-target enforcement, template naming validation
  • Conventions audit: no unwrap/expect/panics in src/, no unsafe, no async, no filesystem access, doc comments only on public API, no em dashes in prose
  • Verification set: cargo test, cargo clippy --all-targets -- -D warnings, cargo fmt --check, cargo doc --no-deps, cargo build --target wasm32-unknown-unknown --release, taskgraph validate; all clean
  • Gate verdict recorded in Notes: wave-2 decomposition unblocked, or blockers + booked findings listed

References

  • docs/architecture/core.md (the wave's spec)
  • docs/plans/implementation.md (wave 1 section: the interpretations to disposition)
  • docs/architecture/decisions/002-handlebars-substrate-strict-mode.md
  • docs/architecture/decisions/003-core-posture-sync-wasm-deterministic.md
  • docs/architecture/decisions/004-typed-contexts-builders-not-templates.md
  • docs/architecture/decisions/005-escape-strategy-per-template-set.md
  • docs/architecture/decisions/008-template-set-ownership.md
  • docs/architecture/decisions/009-feature-gated-template-sets.md

Notes

Gate verdict: GREEN. Wave-2 decomposition unblocked. No blockers, no booked findings, no inline fixes required; the landed surface matches the architecture on every point read. Gate review performed 2026-11-06 over the four implementation commits (c678615, 02037c4, 22f32e6, e361b41, 14d8a49) by reading the full diff of the landed surface (src/lib.rs, src/error.rs, src/escape.rs, src/registry.rs, tests/, Cargo.toml, the task notes) against core.md and ADR-002/003/004/005/008/009.

Component map check (core.md): all six components present and shaped as specified. Registry construction: TemplateSet wraps one handlebars registry per set (ADR-002 decision 6), strict mode set unconditionally inside the constructor with no API parameter (pinned by an enforcement test), fallible typed registration for templates and partials, &str-only API so no filesystem is reachable by construction. Template assets: fixtures are include_str!/inline text versioned in-repo with goldens from day one. Context conventions: typed Serialize structs built by Rust builders in both fixtures, kind mapping (writer_call, rust_struct_name, SectionKind) lives in builder code, templates condition on flags only. Helper policy: seam exists, zero default helpers (pinned by the missing-helper typed-error test), purity stated as a documented convention. Render entry: both sinks, deterministic (pinned across repeated renders and across a rebuilt registry registering in opposite order), strict errors typed. Error model: one public enum, two variants, no catch-all, substrate errors reachable through the source chain (pinned by downcast tests). No unrecorded divergences found.

ADR posture check (in code, not in prose):

  • ADR-002: strict mode forced and unparameterizable; registration propagates parse failures as Error::Registration; assets embedded (dir_source/script_helper provably absent: cargo tree inspection shows zero walkdir and zero rhai hits); one registry per set; partials first-class. Verified.
  • ADR-003: no async, no threads, no std::time/std::env/std::fs anywhere in the source; determinism pinned by tests including the registration-order independence row; wasm build of the landed dep set passes.
  • ADR-004: typed contexts; kind mapping in builders (exercised by both fixture builders); document order driven by insertion-order arrays, with the preserve_order feature itself pinned active by a test. Verified.
  • ADR-005: escaper is an explicit per-set construction-time choice (EscapePolicy::{Html, NoOp}), not swappable through TemplateSet; the Html posture leaves the substrate default untouched and NoOp registers no_escape; both postures pinned by rendering tests. Verified.
  • ADR-008: caller-supplied String text registers through the identical methods, pinned by test; no second-class consumer path. Verified.
  • ADR-009: bast-codegen = [] declared, gates nothing; alktype absent from the tree; package metadata moved to the text-generation framing; version stays 0.1.0. Verified.

Interpretation dispositions:

  1. alktype removal (vs optional-behind-feature): CONFIRMED against ADR-009. ADR-009 decision 1 mandates default features ship the core only with no alktype, and with no engine-owned set in scope an optional = true entry would sit behind a never-enabled feature (plus the auto-created implicit alktype feature): the same dead entry with more moving parts, exactly as the recorded interpretation argues. ADR-009 item 4 anticipated the move as implementation work, and the re-add shape is already pinned by the task notes (bast-codegen = ["dep:alktype"] at target activation). Dep tree verified clean. No overturn.
  2. Context-build error arms: CONFIRMED (absent, correctly). No engine-owned template set ships in v0.1.0 and consumer builders own their errors (ADR-008), so there is no failure the arm could represent; it lands additively with the first engine-owned set, pre-publish. The #[non_exhaustive] question is deliberately open and recorded in the error-model task notes; the gate adds a reminder below for the wave-3 freeze inventory to decide it explicitly.
  3. Partial-not-render-target enforcement: CONFIRMED. Set-level bookkeeping was the right call: the substrate's register_partial is literally register_template_string, so convention-plus-tests would have left the render entry unable to enforce core.md's render-name rule. The behavioral rejection (partial name and unknown name both rejected as typed Error::Render before the substrate is consulted) is pinned in both sinks, from the unit tests and from the consumer-shaped ssr fixture test. The mechanism is documented on the type.
  4. Template naming validation: CONFIRMED. Tests-only is correct: validating names at registration would bake alkgen's house style into a consumer-blind API (ADR-001) and contradict ADR-008 machinery equality (consumers would get rejections the core has no mandate to police); "one name per kind" is semantic, not mechanical, per the registry task's recorded reasoning. Fixture kinds follow convention 9 and are reviewed like source.

Conventions audit: zero unwrap/expect/panics/unsafe/async/ filesystem/time/env in non-test lib code (all expect hits are inside #[cfg(test)] modules, permitted); zero inline // comments in src/; doc comments on all public items; no em dashes in src/, tests/ , docs/, tasks/, README, or commit messages (the plan's grep command in AGENTS.md matches its own pattern text, a self-reference, not a prose violation; vendored .opencode/node_modules/ is out of scope per convention 12). serde_json preserve_order untouched and explicitly pinned active by a test. Deterministic rendering holds (no HashMap iteration order reaches output; the registry bookkeeping is name-resolution only).

Verification set (all green, re-run by the gate on the landed tree): cargo test (19 lib + 5 code-fixture + 3 ssr-fixture passed), cargo clippy --all-targets -- -D warnings, cargo fmt --check, cargo doc --no-deps (warning-free), cargo build --target wasm32-unknown-unknown --release, taskgraph validate (14 tasks valid), plus the ADR-009 tree inspection (cargo tree: zero walkdir/rhai/alktype; handlebars resolves 6.4.4).

Reminders carried forward (non-blocking): (a) the wave-3 freeze inventory decides the enum's #[non_exhaustive] posture explicitly; (b) the wave-2 conformance battery should keep pinning the wasm build standing rather than relying on ad-hoc gate runs; (c) ADR-009's CI feature matrix (core, core+bast-codegen, wasm of both) lands when the first feature starts gating something.

Summary

Wave-1 gate passed green. The shipped core surface (EscapePolicy, TemplateSet, Error) matches core.md's six components and the ADR-002/003/004/005/008/009 postures on every point read; strict mode, typed registration, deterministic two-sink rendering, escaper policy, and the consumer machinery-equality path are all pinned by tests rather than asserted. All four wave-1 interpretations confirmed: alktype removal against ADR-009 decision 1 (tree-verified), context-build arms absent by design, render-name rule via set-level bookkeeping, naming by tests only. Conventions audit and the full verification set clean; 27 tests pass, wasm release build clean. Wave-2 decomposition unblocked, no blockers. Three non-blocking reminders carried forward (noted above).