Files
hemx/docs/versioning.md
T
slhx agent 1fbeeb52b8 docs(hemx): define v1 versioning policy
Add a compact semver and upgrade policy for v1: stable beginner APIs, stable wire/runtime compatibility, advanced escape-hatch tier, breaking-change rules, upgrade-note template, and release checklist.

req: abi/001

req: abi/002

req: abi/003

req: abi/004

req: abi/005

req: public_api/001

req: public_api/002

req: public_api/005

req: runtime/003

req: runtime/004
2026-06-05 09:49:30 +02:00

5.8 KiB

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, class tokens, and events
  • hemx::page(...) for page-boundary rendering
  • 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

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:

## 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 `/hemx.js` 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 health --strict
```

Release checklist

Before tagging a v1-compatible release:

  • examples/v0 and examples/saas compile and test 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: diagnostics/001 req: diagnostics/002
  • 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
  • Advanced APIs touched by the release are still named as escape hatches in docs.
  • Upgrade notes state whether users must regenerate code, redeploy /hemx.js, 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