Files
hemx/docs/versioning.md

174 lines
7.5 KiB
Markdown

# v1 versioning and upgrade policy
hemx v1 should be boring to upgrade: beginner apps can rely on the generated
helper and handler model, while advanced escape hatches remain explicitly named
and easier to audit. This policy defines what must be stable for v1 and how to
ship breaking changes without hiding incompatibility behind runtime magic. req: abi/001 req: public_api/001
## Stability tiers
### Stable beginner API
These are the v1 normal path and require semver-major treatment for breaking
changes:
- `#[hemx::surface]`, `#[hemx::app]`, `#[hemx::component]`, `#[hemx::handler]`,
and `#[hemx::form]`
- generated component helpers for slots, keyed partials, forms, handles, page
targets, page-boundary rendering, class tokens, and events
- `hemx::page(...)` only at explicit server shell boundaries
- tuple `IntoEffect` composition
- `Result<impl IntoEffect, E>` handlers with `IntoHandlerFailure`
- generated form commands such as `clear`, `reset`, `error`, and `focus`
- generated keyed commands such as `append`, `replace`, and `remove`
A change is breaking if a production-shaped app like `examples/saas` must rewrite
normal handler/template code that was using those APIs correctly. req: examples/001 req: canonical_authoring/006
### Stable compatibility contract
These must remain explicit and fail closed when incompatible:
- Surface schema version consumed by `hemx_build`
- generated symbols and deterministic resource allocation inputs
- EffectBatch wire/schema ABI
- JavaScript runtime ABI
- build fingerprint inputs and mismatch behavior
An incompatible wire/runtime change must bump the relevant ABI version and cause
old pages or old runtimes to refuse partial updates rather than silently applying
wrong effects. req: abi/002 req: abi/003 req: abi/004 req: failure/005
### Supported compatibility matrix
The v1 support claim is deliberately narrow:
| Boundary | Supported | Fails closed when |
|---|---|---|
| Rust toolchain | stable Rust, workspace edition 2021 | an unsupported compiler cannot build the workspace |
| Browser/WASM | Firefox browser suite plus the generated real-WASM path | WASM/bootstrap cannot load or bind |
| Effect wire | ABI `1` only | decoding preserves the version, `is_compatible()` is false, and runtimes refuse application |
| Generated resources | one matching build fingerprint | a stale fingerprint receives reload recovery instead of mutation |
| Durable sync | schema `1`; legacy flat schema-1 records upgrade in place | unknown schema or malformed projection is rejected |
| Runtime set | same-tree `hemx-js`, `hemx-wasm`, generated bindings, and framework sync runtime | mismatched assets have no compatibility guarantee |
| Canonical examples | `v0`, Kanban, client-local, and SaaS workspace packages | an example no longer builds or its focused proof fails |
No support claim is made for untested browser engines, future wire/schema versions, or arbitrary cross-release runtime mixing. req: abi/001 req: abi/003 req: public_api/003 req: v1_release/007
### Advanced escape hatches
These are public but advanced. They may evolve faster, but every change still
needs a migration note and must not leak into beginner docs:
- raw effects and batches
- manual registries
- low-level resource ids and raw targets
- raw HTML/render/target construction
- runtime hooks and SSE internals
- island internals and custom integration glue
Advanced APIs are for integration crates, tests, migrations, or explicit leaf
boundaries. They are not a second beginner API. req: public_api/002 req: public_api/005
## What counts as breaking
Breaking for the beginner API:
- renaming generated helper methods or changing their return contracts
- requiring manual registry wiring for canonical apps
- requiring user-authored JavaScript or selector targeting for ordinary forms,
partial swaps, page swaps, or SSE/polling
- moving validation/error UI off generated form helpers
- changing handler argument inference so existing valid handlers stop compiling
- changing `Result<impl IntoEffect, E>` mapping so app errors no longer map at
the integration boundary
Breaking for compatibility:
- changing effect wire encoding without an ABI bump
- changing runtime target lookup semantics without a fingerprint/ABI bump
- changing generated id allocation inputs without a fingerprint change
- allowing mismatched server/runtime builds to apply partial updates
Not breaking:
- improving diagnostics while keeping spans and fixes user-facing
- adding generated helpers that are aliases around existing behavior when they
remove real friction
- adding new advanced escape hatches that are clearly named and isolated
- adding production recipes for providers outside core
- changing examples to better express the canonical path, when the documented API
remains compatible
## Upgrade note template
Every release with public API, generated ABI, runtime, or recipe changes should
include upgrade notes with this shape:
````md
## Upgrade to hemx X.Y.Z
### Who is affected
- Beginner app code: yes/no
- Generated helpers: yes/no
- Wire/runtime ABI: yes/no
- Advanced escape hatches: yes/no
- Recipes/examples only: yes/no
### Required actions
- Regenerate generated code with `cargo check` or your normal build.
- Deploy server and the helper-provided runtime asset from the same release if
ABI/fingerprint changed.
- Update any renamed helpers or advanced calls listed below.
### Compatibility behavior
- Old page + new server: reload/fail closed/compatible
- New page + old server: reload/fail closed/compatible
- Rolling deploy requirement: sticky release routing / normal routing
### Migrations
- Before: ...
- After: ...
### Verification
```sh
cargo run -p hemx-xtask -- test
cargo check --workspace
redgate refs
```
````
## Release checklist
Before tagging a v1-compatible release:
- `examples/v0`, `examples/client_local`, `examples/kanban`, and `examples/saas`
compile and their package tests pass; v0 and SaaS remain the canonical public
surface examples without raw ids, raw effects,
selector targeting, manual registries, raw render/lower calls, or user-authored
UI JavaScript in the normal path. req: examples/004 req: examples/005
- `docs/diagnostics.md` describes any new common error class in user language.
req: diag/001 req: diag/002
- The canonical local release gate is `cargo run -p hemx-xtask -- test`; there
are no separate `public-api` or `ownership-check` xtask subcommands.
- `docs/recipes/deploy-versioning.md` remains accurate for runtime asset and
fingerprint behavior.
- Any incompatible generated ABI/runtime change bumps the relevant ABI/fingerprint
inputs and has tests for fail-closed behavior. req: abi/005
- The checked-in ABI-v1 byte fixture in `hemx-core/tests/effect_batch.rs`, the
legacy flat durable-record browser migration, and canonical example package
tests all pass. req: abi/001 req: abi/003 req: v1_release/007
- Advanced APIs touched by the release are still named as escape hatches in docs.
- Upgrade notes state whether users must regenerate code, redeploy the
helper-provided runtime asset, or change app code.
## Policy for v1 cutover
v1 is ready to cut only when the normal path can stay stable for the canonical
SaaS tutorial: hemplate templates, typed handlers, generated helpers, tuple
effects, result error mapping, page/push shape, explicit provider adapters,
plain CSS, and one island boundary. If stabilizing one of those surfaces would
require adding runtime negotiation, selector retargeting, a client state store, or
provider-specific core code, defer the feature or keep it advanced instead of
weakening the v1 contract. req: runtime/003 req: runtime/004 req: laws/004