chore(tasks): decompose wave 1 into implementation tasks
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
This commit is contained in:
1 parent
04e961d689
commit
b154b65bed
6 files changed
+446
No files matched your search
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: review-wave-1
|
||||
name: "Wave 1 gate: the core surface"
|
||||
status: pending
|
||||
depends_on: [w1-manifest, w1-error-model, w1-registry-construction, w1-render-entry, w1-engine-fixtures]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: phase
|
||||
level: 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 fills this with the verdict, booked findings, and the
|
||||
> dispositions of the interpretations above.
|
||||
|
||||
## Summary
|
||||
|
||||
> Gate fills this on completion.
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
id: w1-engine-fixtures
|
||||
name: "Wave 1: engine fixture doubles (ssr-shaped and code-shaped sets)"
|
||||
status: pending
|
||||
depends_on: [w1-render-entry]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: component
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Land the minimal in-crate fixture doubles that every wave-2 proof runs
|
||||
through (the alkssh wave-1 doubles move: the deep harness lands wave
|
||||
2; the doubles land now). They are the first full-round-trip exercise
|
||||
of the shipped core: typed context in, rendered text out, through the
|
||||
public API only.
|
||||
|
||||
- **ssr-shaped fixture set**: a small page template composing fragment
|
||||
partials (header/footer shape), registered through the public API,
|
||||
HTML escaper active, typed context (derived `Serialize`) built by a
|
||||
Rust builder function (the ADR-004 shape: kind mapping and structure
|
||||
decisions live in builder code, templates stay dumb conditionals
|
||||
over context flags). Golden render tests pin the output (AGENTS.md
|
||||
convention 7 discipline starts here: changing a fixture template
|
||||
changes the pinned expectations, deliberately).
|
||||
- **code-shaped fixture set**: a small set with the no-op escaper and
|
||||
a typed context whose arrays are document-ordered: `serde_json`'s
|
||||
`preserve_order` is load-bearing (convention 5); the fixture proves
|
||||
insertion order drives rendered order (an ordered list context, not
|
||||
a map, exercising the array path handlebars iterates).
|
||||
- Fixture placement per the wave-1 conventions: fixtures live in the
|
||||
repo as pinned code assets (`include_str!` files or inline
|
||||
literals), versioned, never throwaway strings; test binaries own
|
||||
their fixture modules so wave-2 proofs can grow them without
|
||||
single-writer collisions.
|
||||
- Establish the naming convention for fixture template kinds
|
||||
(convention 9 posture, consistent with whatever the registry task
|
||||
decided).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] ssr-shaped set renders through the public API with HTML
|
||||
escaping; page composes registered fragment partials; golden
|
||||
tests pin output
|
||||
- [ ] code-shaped set renders with no-op escaping; document-order
|
||||
arrays render in insertion order (the `preserve_order` test)
|
||||
- [ ] both sets use typed contexts built by Rust builder functions
|
||||
per ADR-004
|
||||
- [ ] fixtures are embedded code assets, goldens committed and
|
||||
asserted
|
||||
- [ ] `cargo test`, `cargo clippy --all-targets -- -D warnings`,
|
||||
`cargo fmt --check` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/core.md §Context conventions, §Template assets
|
||||
- docs/architecture/decisions/001-one-core-template-set-targets.md
|
||||
(the generality claim these fixtures will help prove)
|
||||
- docs/architecture/decisions/004-typed-contexts-builders-not-templates.md
|
||||
- docs/architecture/emit.md (postures B and A: the shapes these
|
||||
fixtures model)
|
||||
- docs/plans/implementation.md (wave 2 consumes these doubles)
|
||||
|
||||
## Notes
|
||||
|
||||
> Agent fills this during implementation.
|
||||
|
||||
## Summary
|
||||
|
||||
> Agent fills this on completion.
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
id: w1-error-model
|
||||
name: "Wave 1: the public error model"
|
||||
status: pending
|
||||
depends_on: [w1-manifest]
|
||||
scope: single
|
||||
risk: low
|
||||
impact: project
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Land the crate's one public error enum (core.md §Error model; this is
|
||||
the contract every later task and every consumer maps against):
|
||||
|
||||
- `pub enum Error` in `src/error.rs`, via thiserror (AGENTS.md
|
||||
convention 2), covering the engine-owned operations core.md names:
|
||||
registration, template parsing, and rendering. A malformed template
|
||||
(registration-time parse failure) and a failed render are data:
|
||||
typed variants wrapping the substrate's `handlebars::TemplateError`
|
||||
and `handlebars::RenderError`. No panics, no `unwrap`/`expect`
|
||||
outside tests.
|
||||
- No catch-alls: every variant names the operation that failed, and
|
||||
every engine-owned failure path maps to exactly one variant. No
|
||||
lossy flattening: the underlying substrate error stays reachable
|
||||
(source chain via thiserror `#[from]`/`#[source]`), for consumers
|
||||
that need detail (alkforge maps render failure to an error page).
|
||||
- **No context-build arms in this scope**: no engine-owned template
|
||||
set ships in v0.1.0, and consumer context builders own their errors
|
||||
(ADR-008). The arm lands additively with the first engine-owned
|
||||
set. Recorded interpretation, flagged for the wave-1 gate.
|
||||
- `src/lib.rs` re-exports the enum per convention 10; doc comments on
|
||||
the public surface (no inline `//` comments per convention 1).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `pub enum Error` with registration/parse and render variants
|
||||
wrapping `TemplateError`/`RenderError`; the substrate error
|
||||
stays reachable through the source chain
|
||||
- [ ] no catch-all variant; registration, parse, and render failures
|
||||
each map to exactly one variant
|
||||
- [ ] no `unwrap`/`expect` in `src/`; no panics
|
||||
- [ ] re-exported from `src/lib.rs`; doc comments on public items
|
||||
- [ ] `cargo test`, `cargo clippy --all-targets -- -D warnings`,
|
||||
`cargo fmt --check` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/core.md §Error model
|
||||
- docs/architecture/decisions/002-handlebars-substrate-strict-mode.md
|
||||
(decision 3: typed fallible registration)
|
||||
- docs/architecture/decisions/008-template-set-ownership.md
|
||||
(consumer builders own their errors)
|
||||
- docs/plans/implementation.md (the context-build-arms interpretation)
|
||||
|
||||
## Notes
|
||||
|
||||
> Agent fills this during implementation.
|
||||
|
||||
## Summary
|
||||
|
||||
> Agent fills this on completion.
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
id: w1-manifest
|
||||
name: "Wave 1: manifest landing (dep pins, alktype removal, feature graph)"
|
||||
status: pending
|
||||
depends_on: []
|
||||
scope: single
|
||||
risk: low
|
||||
impact: project
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Land the dependency posture everything else in the crate builds
|
||||
inside. This is the ADR-002/ADR-009 manifest landing; no other wave-1
|
||||
task starts before it.
|
||||
|
||||
- Pin the substrate: `handlebars = "6.4"` from crates.io on the
|
||||
substrate's default features. The crate's `default = []` posture
|
||||
means `dir_source` and `script_helper` are off-limits (filesystem,
|
||||
rhai; ADR-002 decision 4, ADR-003) and must stay un-enabled:
|
||||
verify no `walkdir` / `rhai` enters the dependency tree (`cargo
|
||||
tree`), rather than assuming it.
|
||||
- `serde` + `serde_json` with `preserve_order` stays as is
|
||||
(load-bearing, AGENTS.md convention 5), `thiserror = "2"` for the
|
||||
error model task.
|
||||
- **Remove alktype from `[dependencies]`**: it is listed
|
||||
unconditionally on main today, but ADR-009 decision 1 ships it only
|
||||
behind the `bast-codegen` feature, and no engine-owned template set
|
||||
ships in v0.1.0 (the bast-rust-codecs activation is queued behind
|
||||
ssr-html and wgsl-jit; see `docs/plans/implementation.md` scope
|
||||
authority). A dep behind a feature that gates nothing is a dead
|
||||
entry; the optional alktype dep and the feature's payload land
|
||||
together at the target's activation. This interpretation is
|
||||
recorded in the plan and flagged for the wave-1 gate.
|
||||
- Declare the feature graph: `[features] bast-codegen = []` (name
|
||||
reserved per ADR-009; gates nothing yet; the first consuming code
|
||||
arrives with the bast-rust-codecs set, a future wave).
|
||||
- Update package metadata to the text-generation framing (ADR-001):
|
||||
the description and keywords currently read "codegen over BAST
|
||||
documents"; the crate's honest v0.1.0 description covers the text
|
||||
engine. Keep `version = "0.1.0"` (the publish task verifies, never
|
||||
bumps).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `handlebars` pinned `6.4`; `cargo tree` shows no `walkdir` and
|
||||
no `rhai` (off-limits features provably not pulled in)
|
||||
- [ ] `alktype` absent from the dependency tree; `bast-codegen`
|
||||
declared under `[features]` gating nothing
|
||||
- [ ] package description/keywords updated to the text-generation
|
||||
framing; version still 0.1.0
|
||||
- [ ] `cargo build --target wasm32-unknown-unknown --release` passes
|
||||
on the landed dep set (ADR-003 validation posture)
|
||||
- [ ] `cargo test`, `cargo clippy --all-targets -- -D warnings`,
|
||||
`cargo fmt --check`, `taskgraph validate` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/plans/implementation.md (scope authority; the alktype
|
||||
interpretation)
|
||||
- docs/architecture/overview.md §Dependencies
|
||||
- docs/architecture/decisions/002-handlebars-substrate-strict-mode.md
|
||||
- docs/architecture/decisions/003-core-posture-sync-wasm-deterministic.md
|
||||
- docs/architecture/decisions/009-feature-gated-template-sets.md
|
||||
(especially decision 1 and item 4)
|
||||
- docs/architecture/decisions/010-library-only-no-cli.md
|
||||
|
||||
## Notes
|
||||
|
||||
> Design: the task removes alktype rather than leaving it behind
|
||||
> `optional = true`: with no consuming code, `optional = true` + an
|
||||
> auto-created implicit `alktype` feature (or a `bast-codegen` alias
|
||||
> to nothing) is the same dead entry with more moving parts. The
|
||||
> re-add lands with the bast-rust-codecs template set as
|
||||
> `bast-codegen = ["dep:alktype"]`. Flagged for the wave-1 gate to
|
||||
> confirm against ADR-009 item 4.
|
||||
|
||||
## Summary
|
||||
|
||||
> Agent fills this on completion.
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
id: w1-registry-construction
|
||||
name: "Wave 1: registry construction (strict mode, escaper policy, typed registration)"
|
||||
status: pending
|
||||
depends_on: [w1-error-model]
|
||||
scope: narrow
|
||||
risk: medium
|
||||
impact: project
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Land the set builder, the first and most contract-heavy component of
|
||||
the core (core.md §Registry construction; ADR-002 decision 6):
|
||||
|
||||
- **One registry per template set**, constructed through alkgen's API:
|
||||
the builder takes a set's identity options and wraps one handlebars
|
||||
registry scoped to that set. Strict mode, escape policy, and the
|
||||
partial namespace are registry-scoped properties; the one-registry-
|
||||
per-set rule is what makes them enforceable rather than advisory
|
||||
(ADR-002 decision 6). **Strict mode is forced on** at construction,
|
||||
never parameterizable. A test pins the enforcement (a registry
|
||||
built through the API cannot render missing variables as silent
|
||||
empty output).
|
||||
- **Escaper as an explicit per-registry choice** (ADR-005): the build
|
||||
parameter covers the two shipped postures: handlebars HTML escaping
|
||||
for ssr-shaped sets and a no-op identity posture for code sets.
|
||||
Decide the mechanism against handlebars 6.4's escape-fn surface
|
||||
(`register_escape_fn` vs disabling built-in HTML escape) and record
|
||||
it in Notes. Both postures get a rendering test pinning their
|
||||
behavior.
|
||||
- **Typed fallible registration**: register templates and partials by
|
||||
name + text. Malformed template text produces the wave-1 error
|
||||
enum's registration variant, never a panic (ADR-002 decision 3).
|
||||
Registration accepts externally supplied `&str` either as inline
|
||||
literals or caller text (ADR-008 consumer path: consumers register
|
||||
through the same machinery; no filesystem access anywhere, so
|
||||
`dir_source` is unreachable by construction).
|
||||
- **Helpers**: the registration seam exists (per-set helper
|
||||
registration pass-through), but the core registers none by default
|
||||
(core.md §Helper policy): helpers see text, are pure and
|
||||
deterministic, and are owned by their template sets; the purity
|
||||
statement is a documented convention, not runtime enforcement.
|
||||
- **Decide + record (both flagged for the wave-1 gate)**:
|
||||
1. How the render-name rule ("the name argument resolves to a
|
||||
registered template, never a bare partial"; core.md) is enforced,
|
||||
given handlebars' registry is a single namespace (registering a
|
||||
partial is template registration under the hood). Choose set-
|
||||
level bookkeeping (a set type that knows which registered names
|
||||
are templates) or convention plus tests, and pin it.
|
||||
2. Whether template naming conventions (AGENTS.md convention 9:
|
||||
lowercase kebab/snake, one name per template kind) are validated
|
||||
at registration or enforced by tests only.
|
||||
- `src/lib.rs` re-exports the public surface.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] set builder with forced strict mode; an enforcement test proves
|
||||
a missing variable renders as a typed error, never empty output
|
||||
- [ ] escaper choice explicit per registry (HTML and no-op postures),
|
||||
each pinned by a rendering test
|
||||
- [ ] template and partial registration fallible and typed; malformed
|
||||
template text yields the error enum, never a panic
|
||||
- [ ] externally supplied text registers identically (the ADR-008
|
||||
consumer path exercised)
|
||||
- [ ] helper registration seam exists; zero helpers registered by
|
||||
default
|
||||
- [ ] the two decisions recorded in Notes; both flagged in the task
|
||||
Summary for the gate
|
||||
- [ ] `cargo test`, `cargo clippy --all-targets -- -D warnings`,
|
||||
`cargo fmt --check` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/core.md §Registry construction, §Template assets,
|
||||
§Helper policy
|
||||
- docs/architecture/decisions/002-handlebars-substrate-strict-mode.md
|
||||
(decisions 3, 5, 6)
|
||||
- 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/plans/implementation.md (the partial-enforcement and naming
|
||||
interpretations)
|
||||
- /workspace/@alkdev/alkminer/reference/alkminer-v1/src/compute/
|
||||
kernel.rs (the strict-registry precedent)
|
||||
|
||||
## Notes
|
||||
|
||||
> Agent fills this during implementation. The two decisions (partial
|
||||
> enforcement mechanism, naming validation posture) must be recorded
|
||||
> here.
|
||||
|
||||
## Summary
|
||||
|
||||
> Agent fills this on completion.
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: w1-render-entry
|
||||
name: "Wave 1: the render entry point (both sinks, deterministic, strict)"
|
||||
status: pending
|
||||
depends_on: [w1-registry-construction]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: project
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Land the render entry point (core.md §Render entry point), the
|
||||
component every consumer actually calls:
|
||||
|
||||
- **Synchronous and deterministic**: render a registered template by
|
||||
name over a serde-serializable context. Same registry contents plus
|
||||
same context produce byte-identical text (ADR-003): test-pinned
|
||||
here (repeated renders over cloned and rebuilt registries), deepened
|
||||
by wave 2's battery. No I/O, no time reads, no hash-map iteration
|
||||
order leaking into output.
|
||||
- **Two sinks**: render into a String, and render into an
|
||||
`io::Write` target (both wasm-clean; the substrate exposes both,
|
||||
`render` and `render_to_write`; the core passes them through so a
|
||||
large page or large generated file need not force intermediate
|
||||
allocation). Strict errors through both sinks surfacing the
|
||||
wave-1 error enum.
|
||||
- **Templates are the render targets**: rendering by a partial's name
|
||||
is rejected per the wave-1 registry task's recorded mechanism
|
||||
(bookkeeping or convention plus tests; whatever landed there, the
|
||||
render entry is where the behavior is visible and tested).
|
||||
- **Strict errors**: a missing context variable in strict mode is a
|
||||
typed error through the public enum, never silent-empty output
|
||||
(ADR-002 decision 2).
|
||||
- `src/lib.rs` re-exports the surface.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] String-sink and `io::Write`-sink render entry points, both
|
||||
surfacing the public error enum
|
||||
- [ ] determinism pinned by tests (byte-identical repeated renders,
|
||||
including across registry rebuilds)
|
||||
- [ ] strict-mode missing-variable render is a typed error in both
|
||||
sinks, never empty output
|
||||
- [ ] render-by-partial behavior matches the registry task's recorded
|
||||
decision and is pinned by a test
|
||||
- [ ] `cargo test`, `cargo clippy --all-targets -- -D warnings`,
|
||||
`cargo fmt --check` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/core.md §Render entry point
|
||||
- docs/architecture/decisions/002-handlebars-substrate-strict-mode.md
|
||||
- docs/architecture/decisions/003-core-posture-sync-wasm-deterministic.md
|
||||
- docs/architecture/emit.md §Cross-posture obligations (the
|
||||
determinism row every posture leans on)
|
||||
- /workspace/@alkdev/alkminer/reference/alkminer-v1/src/compute/
|
||||
kernel.rs (render-then-compile precedent: purity for downstream
|
||||
caching)
|
||||
|
||||
## Notes
|
||||
|
||||
> Agent fills this during implementation.
|
||||
|
||||
## Summary
|
||||
|
||||
> Agent fills this on completion.
|
||||
Reference in new issue
Block a user