- 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
5.3 KiB
id, name, status, depends_on, scope, risk, impact, level
| id | name | status | depends_on | scope | risk | impact | level | |
|---|---|---|---|---|---|---|---|---|
| w1-error-model | Wave 1: the public error model | completed |
|
single | low | project | 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 Errorinsrc/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'shandlebars::TemplateErrorandhandlebars::RenderError. No panics, nounwrap/expectoutside 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.rsre-exports the enum per convention 10; doc comments on the public surface (no inline//comments per convention 1).
Acceptance Criteria
pub enum Errorwith registration/parse and render variants wrappingTemplateError/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/expectinsrc/; no panics - re-exported from
src/lib.rs; doc comments on public items cargo test,cargo clippy --all-targets -- -D warnings,cargo fmt --checkpass
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
Design: two variants total. Registration and template parsing are one variant because the substrate's
register_template_stringparses at registration time and returnsResult<(), TemplateError>; there is no substrate operation that can fail as "registration but not parse".Registrationnames the operation and its doc comment states that parse failures surface under it, so the core.md three-operation list (registration, parsing, rendering) is fully covered. No#[non_exhaustive]: the plan records the enum's evolution policy (the context-build arm lands additively pre-1.0, and the freeze inventory carries the policy post-publish), and#[non_exhaustive]would tax every consumer match arm for a guarantee the plan does not call for. Revisit at publish review if the freeze inventory wants it.
Summary
Agent fills this on completion.
Landed 2026-11-06. src/error.rs holds the one public enum (core.md
§Error model), src/lib.rs re-exports alkgen::Error (convention
10):
Error::Registration(#[from] handlebars::TemplateError): template and partial registration failure, including the registration-time parse failure. Doc comment points to the substrate error carrying reason, template name, and position.Error::Render(#[from] handlebars::RenderError): render failure, e.g. a missing context variable under strict mode. Doc comment points to the substrate error carrying the originating template.
The no-catch-all and one-variant-per-failure criteria hold by construction (only the two substrate error types exist on the two engine-owned paths). No context-build arm in this scope, per the recorded interpretation, flagged for the wave-1 gate.
Findings for later tasks:
- The substrate's
TemplateErrorderivesstd::error::Errorwith its reason as a plain field, soTemplateError::source()isNone; the reason is reachable through thereason()accessor instead. The crate's source chain still satisfies the no-lossy-flattening rule:Error::source()returns the substrate error itself (tests pin this via downcast), whoseDisplayembeds the reason text. RenderError::source()returns theRenderErrorReason; the substrate's strict-mode missing-variable reason isMissingVariable, with its detail in the reason'sDisplay.RenderError::newis deprecated since substrate 5.0; tests useRenderError::strict_errorfor constructing substrate errors.
Tests (unit, in src/error.rs): malformed template maps to
Registration with the substrate error, name ("bad"), and reason
reachable through the source chain; strict-mode missing variable maps
to Render with the reason reachable; substrate detail (the
unclosed beta) survives on the render error; Display for both
variants starts with the failing operation's name.
Verification: cargo test (6 passed), cargo clippy --all-targets -- -D warnings, cargo fmt --check, cargo doc --no-deps, and
cargo build --target wasm32-unknown-unknown --release all green.
No unwrap/expect outside tests, no panics in lib code, no em
dashes.