Files
hemx/PLAN.md
T
slhx agent 1d194e0f23 test(kanban): prove server-first asset isolation
req: performance/006
2026-07-13 15:50:35 +02:00

13 KiB

Hemx v1 implementation plan

Authority: REQUIREMENTS.md. Product evidence: docs/v1-product-evidence.md. This file is an execution cursor, not requirement authority or release permission. Publishing, deployment, artifact upload, and package-registry mutation are out of scope.

Product boundary

Hemx v1 keeps server-rendered HTML and ordinary Rust as the default. Generated resources and the versioned EffectBatch are the one UI contract. Client-local WASM and durable sync are optional execution layers, not a component framework. Hemplate remains the rendering/Surface foundation; application auth, persistence, encryption, retention, backup, and deployment policy remain host concerns.

Slice 1 — one real client-local handler

  • User value: a Rust author marks one high-frequency handler local and gets immediate browser behavior without app-authored JavaScript or a request.
  • State: Done. hemx-build validates same-origin client module metadata and generates the WASM import, initialization, handler registration, fingerprint, and ready marker. Client handlers receive versioned ClientEvent/root-owned ClientState; incompatible input is rejected before handler execution, reports an actionable hemx:client-error, restores pending UI, and invokes an explicitly declared server fallback. Real WASM applies the ordinary generated-target EffectBatch with zero request on valid input.
  • Build: add the smallest optional hemx-wasm boundary for #[hemx::handler(client)]; export only opted-in handlers; generate typed event/state ABI glue; run one existing generated-target interaction through the ordinary EffectBatch interpreter; preserve an explicit native/server fallback.
  • Refusals: no VDOM, component lifecycle, global store, sync queue, second effect protocol, or generic WASM framework.
  • Requirements: client_local/001-010, security/001, security/005-006, performance/003, v1_release/001.
  • Proof: cargo test -p hemx-wasm --test browser client_handler_applies_effect_batch_without_network -- --exact serves only generated template HTML, the ordinary runtime, and generated client bootstrap; it visibly updates a generated target through real WASM, keeps the resource count unchanged for valid input, and proves invalid state diagnostics, pending restoration, and one declared fallback request. Formatting, workspace tests, strict all-target Clippy, and wasm-target build pass.

Slice 2 — direct manipulation that survives interruption

  • User value: Kanban drag/reorder follows the pointer immediately, remains keyboard operable, and cannot apply stale work after cancellation or root removal.
  • State: Done. The canonical Kanban client board is rendered through Hemplate and generated resources, then reordered by its real WASM handler for drag/drop and Arrow-key interaction. Client-local runs use validated latest/drop policy; stale/unmounted completions cannot apply effects; moved-card focus, live status, reduced-motion state, root cleanup, and a measured sub-100 ms local response are browser-proven.
  • Build: use the client handler in the canonical Kanban path; add cancellation/supersession, root-owned state cleanup, keyboard equivalent, focus/status behavior, reduced-motion behavior, and measured response/frame budgets.
  • Refusals: no persistence, collaboration, or animation framework yet.
  • Requirements: client_local/011-014, accessibility/001-007, operations/002-003, performance/001, performance/003, milestone/001.
  • Proof: cargo test -p hemx-wasm --test browser kanban_reorder_has_pointer_keyboard_focus_and_reduced_motion_parity -- --exact covers real-WASM pointer and keyboard reorder, focus/status, reduced motion, and the 100 ms response budget; the client-handler browser proof covers cancellation, removal, error recovery, zero-request behavior, and root cleanup.

Slice 3 — durable offline command log

  • User value: an opted-in Kanban mutation remains available after network loss and browser reload without storing DOM patches as truth.
  • State: Complete — the app-owned reorder_card command is transactionally persisted with schema, actor, session, causal id, and app payload before projection; an app-owned service worker caches only the generated shell/resources, and reload restores the projection after the fixture server is stopped and proven unreachable. Native recovery controls export a versioned credential-free command envelope, delete queued commands while preserving actor/causal identity, and reset command data, identity, cache, and registration behind explicit confirmation. Unknown schemas and malformed current-schema records stop before projection with explicit recovery diagnostics. Transaction conflicts and injected quota exhaustion neither project nor emit durability claims and remain recoverable through export/delete/reset. Replay is preflighted before effects, capped by the app at 64 commands, and measured against a 100 ms browser budget. A programmatic queued/busy state appears within the 100 ms direct-interaction budget before blocked persistence completes. The ordinary server-first route loads only the fingerprinted base runtime and creates no client root, service worker, or IndexedDB database; PWA/WASM policy remains app-owned and opt-in.
  • Build: add an optional durable command-log adapter around platform transactional storage; persist versioned command ids and app payload before projection; restore projection after reload; expose queue state, export/delete/reset, quota/corruption failure, and migration refusal.
  • Refusals: no server reconciliation, CRDT, mandatory IndexedDB, credential storage, or policy hidden in core.
  • Requirements: local/001-004, sync/009, sync/014-015, sync/020, security/007, accessibility/004, client_local/013, performance/003, performance/005-006.
  • Proof: cargo test -p hemx-wasm --test browser kanban_command_persists_before_projection_and_restores_after_reload -- --exact proves transactional persist-before-project ordering, app-owned shell caching, current-version replay after a real Firefox reload with the fixture server unreachable, stable identity metadata, and explicit unknown-schema refusal through real WASM. cargo test -p hemx-wasm --test browser kanban_command_export_delete_and_reset_are_recoverable -- --exact proves accessible export/delete/reset entry points, versioned credential-free export, confirmation before destructive actions, preserved identity after queue deletion, and fresh identity/baseline projection after reset. cargo test -p hemx-wasm --test browser kanban_persistence_failure_does_not_project_and_recovers -- --exact proves transactional failure does not project or emit kanban:command-persisted, reports non-payload stage/code diagnostics, and recovers through the ordinary deletion path. cargo test -p hemx-wasm --test browser kanban_corrupt_command_refuses_projection_and_recovers -- --exact proves strict current-schema validation, no partial projection, visible non-payload diagnostics, raw versioned export for recovery, and ordinary deletion recovery. cargo test -p hemx-wasm --test browser kanban_replay_is_bounded_and_within_budget -- --exact proves 64-command preflight/replay within the 100 ms browser budget, zero partial projection at 65 commands, and export/delete recovery. cargo test -p hemx-wasm --test browser kanban_quota_failure_is_fail_closed_and_recoverable -- --exact proves quota-specific fail-closed behavior, no false durability event, transactional metadata rollback, and export/delete/reset recovery. cargo test -p hemx-wasm --test browser kanban_queued_status_precedes_durable_projection_within_budget -- --exact proves queued/busy feedback within the performance/003 and client_local/013 100 ms budget while persistence is blocked, followed by durable projection only after commit. cargo test -p hemx-kanban-example --test browser_e2e server_first_route_does_not_load_optional_client_assets -- --exact proves the server-first route loads only its fingerprinted base runtime and creates no optional client root, PWA/WASM request, service worker, or IndexedDB database.

Slice 4 — authoritative reconnect and convergence

  • User value: offline and concurrent work reconnects without duplicate mutation, silent loss, stale authorization, or ambiguous conflict.
  • State: Ready — Slice 3 is complete; begin with one idempotent server command and canonical acknowledgement through a real reconnect transport before adding conflicts or multi-tab policy.
  • Build: materialize hemx-sync over an integration transport with idempotent server command processing, snapshot/change cursor, durable acknowledgements, bounded ordered replay, current auth checks, rejection/conflict results, canonical replacement, reconnect jitter/backoff, multi-tab coordination, and redacted diagnostics.
  • Refusals: no default CRDT, transport in core, cached enqueue-time permission, unbounded queue, or silent last-write-wins policy.
  • Requirements: sync/001-023, operations/001-005, security/002-005, performance/004-005.
  • Proof: deterministic browser/server test covers offline → reload → reconnect, duplicate and reordered delivery, authorization revocation, rejection, conflict, missing history/fresh snapshot, two tabs, backpressure, and final convergence.

Slice 5 — local-first multiplayer Kanban milestone

  • User value: the complete north-star app demonstrates SSR-first startup, direct manipulation, offline durability, optimistic projection, reconciliation, and live presence as one comprehensible workflow.
  • State: Blocked by Slice 4.
  • Build: connect the previous slices in the canonical Kanban example; keep native server-rendered fallback; add presence and server-canonical conflict presentation; exercise deploy fingerprint recovery and accessible online/offline/conflict state.
  • Refusals: no demo-only runtime, hidden app JS, proprietary service, or requirement to load collaboration code for server-first apps.
  • Requirements: milestone/001, v1_release/001-002, accessibility/001-007, operations/006, performance/006.
  • Proof: one browser journey covers SSR/no-script fallback, local drag, keyboard reorder, offline/reload, concurrent peer edit, reconnect/convergence, presence, conflict/rejection recovery, mixed-version reload, and optional-asset isolation.

Slice 6 — production integration reference

  • User value: adopters can copy a proven boundary for durable storage, auth, transactions, security controls, observability, and restart recovery without hemx owning vendor policy.
  • State: Ready after public execution/sync contracts stabilize.
  • Build: evolve one existing reference app using ordinary integration adapters; add durable app storage, authenticated/authorized allowed and denied mutations, CSRF/origin checks, transaction rollback, bounded input, structured failures, health/readiness, tracing/metrics hooks, and restart/deploy recovery.
  • Refusals: no built-in database/auth provider, compliance claim, telemetry vendor, deployment system, or repository framework.
  • Requirements: security/001-009, operations/001-008, v1_release/003, existing adapter/*, integration/*, and diagnostics/* contracts.
  • Proof: end-to-end test survives process restart and mixed deployment, proves allowed/denied/rolled-back mutations and redacted diagnostics, and maps each framework-owned ASVS-relevant control to a failing/passing case.

Slice 7 — v1 compatibility and closure

  • User value: maintainers and adopters receive a reproducible, migration-aware v1 with no known material contradiction and no hidden publication side effect.
  • State: Blocked by Slices 1-6 and explicit authority for any missing local audit tool installation.
  • Build: freeze the supported Rust/browser/WASM/integration matrix; reconcile public/generated/Surface/symbol/wire/runtime/persisted-schema compatibility; add migration fixtures; make canonical examples compatibility tests; update the progressive tutorial path; run all local release gates and disposition every P0/P1, advisory, unsafe-code, license, performance, accessibility, and documentation finding.
  • Refusals: no publish, deploy, upload, store submission, speculative feature, or weakening a gate to make it pass.
  • Requirements: v1_release/001-010, versioning/*, test/*, diag/*, performance/*, security/008, and all requirements changed by the preceding slices.
  • Proof: clean-tree formatting, workspace tests, strict all-target Clippy, compile-fail, browser/WASM/offline/multiplayer scenarios, benchmark budgets, approved pinned lockfile audit, requirements proof audit, docs/examples checks, and independent contradiction review all pass with no unresolved P0/P1.