Skip to content

Testing — Domain (L0)

Testing domain — L0

Purpose

Posthaste tests are executable behavior contracts. They prove that provider observations, local reconciliation, live query updates, API invalidation, and frontend state converge to the expected user-visible model. A test must assert expected behavior, not snapshot a current implementation quirk.

This domain exists because Posthaste’s hardest bugs — missed view updates, over-broad cache invalidation, sync-convergence races, provider projection mismatches — are difficult to reproduce by hand. A disciplined, layered harness with shared support code is the only economical way to catch them before release and to let coding agents verify fixes reliably. It supersedes the legacy testing-spec framing.

Coverage is by behavior boundary, not file count

Tests are organized by the boundary whose behavior they prove, not by source file. The boundaries, from the network edge inward:

  • Provider observation — raw remote observations become the canonical local model (Gmail labels as mailboxes, shared Message-ID copies, MODSEQ/VANISHED, JMAP cannotCalculateChanges).
  • Store reconciliationSyncBatch application is atomic, account-scoped, projection-safe, and event-complete.
  • Live query update — mutations and sync deltas bump the store generation and converge every affected query; no missed invalidation, no over-broad refetch.
  • API boundary — error mapping, pagination, the SSE event stream, command responses.
  • Frontend state — React Query invalidation, surface routing, overlay stacking.
  • Live-provider parity — JMAP and IMAP projections agree on the same seeded real server fixture.

The detailed observation matrix and per-boundary rules live in L1.

Layering stakes

Each layer catches a different bug class and costs a different amount to run. Skipping a layer leaves a blind spot; running only the expensive layer is too slow to iterate on.

  1. Unit/integration contracts (Rust) prove domain, store, sync, API logic.
  2. Frontend logic contracts (Bun) prove cache invalidation, routing, adapters.
  3. Live-provider parity (Rust, gated) proves the app’s real sync path against a seeded real Stalwart.
  4. Agent-driven full-app scenarios (planned) prove multi-step, multi-message convergence through a headless driver and declarative fixtures.

The shared posthaste-testkit crate standardizes the harness, fixtures, and assertions across the lower layers so each test catches wide and reports clearly. Its contract is L1; declarative TOML fixtures have landed — the remaining forward contract (the headless driver for agent-driven scenarios) is in docs/eph/PLAN-L2-testkit-roadmap.md.

Assertions

IDSev.Assertion
behavior-not-current-codeMUSTTests assert expected protocol/domain behavior, not implementation quirks
layered-coverageMUSTCoverage spans provider, store, live-query, API, frontend, and parity boundaries rather than one layer
shared-testkitMUSTLower-layer tests share harness, fixtures, and assertions through posthaste-testkit instead of ad-hoc per-crate copies
red-firstSHOULDNew behavior coverage is developed red-first or justified as already covered
spec-linked-coverageSHOULDTests for SPECial assertions link to the assertion with a spec: comment