docs(hemx): add diagnostics guide
Document the v1 diagnostics story for common template, derive, form, result-handler, and runtime/deploy mistakes. The guide names expected user-facing diagnostics and recurring verification gates without exposing raw ids/selectors as the beginner path. req: diagnostics/001 req: diagnostics/002 req: diagnostics/003 req: failure/004 req: failure/005 req: public_api/005 req: test/003
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# Diagnostics guide
|
||||
|
||||
hemx diagnostics should tell a Rust developer which template fact, generated
|
||||
helper, or handler shape is wrong, and what to change next. They should not teach
|
||||
raw ids, selector targeting, runtime opcodes, or Cargo internals in the normal
|
||||
path. req: diagnostics/001 req: diagnostics/002 req: diagnostics/003
|
||||
|
||||
Use this guide as the v1 checklist for common mistakes in beginner and
|
||||
production-shaped apps.
|
||||
|
||||
## Where errors happen
|
||||
|
||||
- **Template/build diagnostics** come from `hemx_build::app().run()` while reading
|
||||
`.heml` files and CSS. Fix the template or generated-surface convention.
|
||||
- **Derive/compile diagnostics** come from `#[hemx::surface]`, `#[hemx::form]`,
|
||||
`#[hemx::handler]`, `#[hemx::component]`, and `#[hemx::app]`. Fix Rust code so
|
||||
it matches the generated surface.
|
||||
- **Runtime diagnostics** come from the tiny browser runtime when a deployed page
|
||||
and response are incompatible or a target cannot be applied. Fix deployment or
|
||||
recover with a full page response. req: failure/005
|
||||
|
||||
## Common mistakes and fixes
|
||||
|
||||
| Mistake | Diagnostic shape | Fix |
|
||||
| --- | --- | --- |
|
||||
| Handler has no matching template handle | `unknown hemx handle \`save\`; add \`data-hemx-handle="save"\`` | Add the handle to the template, rename the function, or put the handler in the matching component. |
|
||||
| Component is missing a generated handler | `#[hemx::component] missing handler implementation(s): delete` | Add a `#[hemx::handler] fn delete(...)` in that component, or remove the template handle. |
|
||||
| Handler name is ambiguous across components | `ambiguous generated handle name(s): save` | Scope the component with `#[hemx::component("todos")]` or rename handles so the generated path is unique. |
|
||||
| Handler misses generated params | `hemx handler \`show\` is missing generated param argument(s): mode` | Add typed handler arguments for every `data-hemx-param-*` fact generated by the template. |
|
||||
| Form handler omits the form argument | `handles a generated form and must accept a typed form argument` | Accept `Form<NewThing>`/`hemx::Form<NewThing>`/integration equivalent and derive `#[hemx::form("...")]` for the type. |
|
||||
| Form struct misses a control | `hemx form \`new_todo\` is missing field \`title\`` | Add a Rust field matching the form control name, or rename the template control. |
|
||||
| Required/multiple form control has wrong Rust shape | `required ... must not be Option<_>` or `accepts multiple values and must be Vec<_>` | Match HTML required/multiple semantics with `T`, `Option<T>`, or `Vec<T>` as appropriate. |
|
||||
| Form field type cannot parse submitted values | compiler mentions `T: FormValue` / `T: hemx::FormValue` | Implement `FromStr`/the expected form value trait for the domain newtype, or use a parseable domain type. |
|
||||
| Generated resources are unavailable | `could not find generated hemx module` / `could not find generated hemx symbols` plus `add hemx_build::app().run()? to build.rs` | Add or fix `build.rs`, then rerun `cargo check`; do not copy `$OUT_DIR` paths into app code. |
|
||||
| Unknown `data-hemx-*` attribute | `unknown hemx attribute ... check the spelling or use a non-hemx data-* attribute` | Fix the spelling, use the supported hemx attribute, or rename app metadata to a non-hemx `data-*` attribute. |
|
||||
| Selector-style targeting | ``data-hemx-target` is selector-style targeting; hemx uses generated resources` | Put `data-hemx-slot` on the local target and return a generated slot/page/form effect. |
|
||||
| Generated target appears in a loop without a stable key | `inside an h-for without h-key; add a stable h-key="item.id"` | Add a stable `h-key` to the owning loop; use generated keyed helpers for row updates. |
|
||||
| Page/SSE attributes are on the wrong element | `expected a real <a href=...>` / `expected placement on the same element as data-hemx-root` | Keep page navigation on anchors and put root-scoped runtime attributes on the root element. |
|
||||
| Result handler error type is not mappable | compiler reports the error type does not satisfy `IntoHandlerFailure` | Implement `IntoHandlerFailure` for the app error, or keep expected validation as generated UI effects instead of `Err`. req: failure/004 |
|
||||
| Old page talks to a new server/runtime | runtime refuses the partial update on fingerprint mismatch | Serve a self-consistent release or fall back to full page reload/navigation. See `docs/recipes/deploy-versioning.md`. req: abi/004 |
|
||||
| Missing runtime target | runtime emits a missing-target diagnostic in development and fails/no-ops according to target kind | Fix the template/generated helper mismatch; do not retarget with selectors. req: failure/001 |
|
||||
|
||||
## What a good diagnostic should include
|
||||
|
||||
A v1-quality diagnostic should include:
|
||||
|
||||
- the user-facing name: handle, form, slot, key, param, class, event, or template
|
||||
- the source area: template path, Rust item, or deployment/runtime boundary
|
||||
- the concrete expected shape, not an internal representation
|
||||
- one next action that preserves generated helpers and the tiny runtime
|
||||
|
||||
Avoid beginner-facing messages that suggest `ResourceId`, `ResourceRef`, raw
|
||||
`Effect`, manual registries, selector strings, or runtime opcodes. If an advanced
|
||||
escape hatch is genuinely required, say that it is advanced and name the safer
|
||||
normal path first. req: public_api/002 req: public_api/005
|
||||
|
||||
## Verification anchors
|
||||
|
||||
Current recurring checks cover the most common classes:
|
||||
|
||||
- `cargo test -p hemx-build` covers template/build diagnostics such as unknown
|
||||
hemx attributes, selector-style targeting, invalid runtime attribute values,
|
||||
missing keys, and invalid page/SSE placement.
|
||||
- `cargo test -p hemx-derive --test compile_fail` covers derive/compile
|
||||
diagnostics for missing handlers, form mismatch, params, missing generated
|
||||
files, unknown scoped components, ambiguous handles, and generated resource
|
||||
lookup.
|
||||
- `cargo test -p hemx-js` covers root-scoped runtime behavior, selectorless
|
||||
targeting, fingerprint mismatch refusal, SSE application, and recoverable
|
||||
runtime events.
|
||||
- `cargo test -p hemx-test --test examples_contract` keeps public examples from
|
||||
teaching forbidden normal-path constructs.
|
||||
|
||||
Before claiming the diagnostics story is closed for v1, run those gates plus
|
||||
`cargo run -p hemx-xtask -- test`, `cargo check --workspace`, and
|
||||
`redgate health --strict` on a clean tree. req: test/003 req: test/004
|
||||
Reference in New Issue
Block a user