2026-09-27·by Sijie Wang#standmeet#architecture#design#events

events-test-plan

Test plan for the event bus

Parent: events

Status: released in v0.1.76 (2026-09-27) — design and as-built record in docs/design/event-bus-outbox-webhooks.md in the StandMeet repo. The full-suite acceptance below passed on 2026-09-27.

Internal mechanism is proven by UTs on a real Postgres, external behaviour by black-box e2e, and every phase re-runs the affected existing specs before it may close. UTs use real Postgres and httptest endpoints; no mocked database.

UT: what exists

SuiteCovers
River conformance (~27)the Jobs / Inspector / Runtime contract: lifecycle, attempts, snooze, discard, unique-by-args, inspection, wait; run against River now and against any future implementation unchanged
Events relay / trigger / recorder (~26)row claiming; interleaved commits lose nothing; batch size; poison marking; concurrent relays never fan out twice; a non-coalescing subscriber gets every event of a subject; every watched column emits and no-op updates do not; undeclared types error
Saturation suitepool exhausted; disk full with relay backoff; 429 cooldown; Meili down, then the backlog drains; backlog surge alert; waiter cap; queue starvation; job timeout (saturation-degrades-gracefully)
Registry-driven idempotency (cmd/server/wire)every registered subscriber gets the same event twice and has one effect; it fails for a subscriber it does not know how to drive
Event-type registryevery type declared once, named noun-then-verb, with a description and a subject pattern, and not left at the zero Exposure by accident
Per-use-case event couplingeach producing use case records its event in the same transaction as its write
Webhook signing, classification, scopethe Standard Webhooks test vector; every status and transport error → retryable / snoozed / discarded; raw never leaves, published slice, code denials, embed scope
Embed hook upsertthe embed's update_hook_url creates or updates its attached endpoint
Schema parityTestMigrationsAddNothingToASchemaSQLDatabase; TestSQLPathSegmentMatchesGo

The interleaved-commit case comes from message-loss-guarantees; the registry-driven idempotency test from no-bypass-by-structure.

New e2e: what exists

PhaseSpecWhat it proves
P1events-index-via-busan entry created through MCP corpus.create is searchable at once; an update and a delete show at once, and the receipt says so; a write during a Meili outage returns a receipt, is indexed once Meili is back, and survives a backend restart in between
P1events-bulk-import-boundimported notes are all searchable, with at most N + slack index jobs and none discarded
P1tasks-panel, tasks-panel-morethe 12 Tasks panel items in tasks-panel, through the real UI
P1upgrade-events-outboxan instance born before the bus upgrades by restart: the migration and River's migrator run at boot, an existing note edited afterwards is indexed, periodic jobs run on River
P2webhooksa signed event arrives and verifies; the published slice only (sentinel form); raw never leaves; 500 × 2 then success, received once; 429 with Retry-After spends no attempt; 410 discarded, then re-delivered; send_test; secret rotation; a disabled endpoint receives nothing; a private address is refused
P2webhook-event-typeseach exposed type, produced by a real action, reaches a * endpoint
P2events-fault-injectionan endpoint slower than the timeout is retried, then delivered; a refused connection turns retryable and starts the cooldown; after a Postgres restart an edit still reaches the receiver and search
P3embed-update-hookthe embed form's hook attaches an endpoint and an edit arrives signed; scope is the code's (sentinel form); saving the same URL keeps the endpoint and shows no new secret; a delete carries the last known subject; cards carry updated_at
P4events-side-effects-durablean access-request notification that fails once still arrives; approval goes sending → sent and is marked replied only after the mail; a permanently failing relay shows failed and is not marked replied; a notification queued before a restart is delivered after it; a booking made during a restart still notifies the owner
P4events-build-settleda build that settles after a backend restart still reaches the open preview
  • The webhook sink is a set of routes on the external mock (mock-stack/job-board/webhook_sink.go), with /__mock/set_delay for slow receivers.
  • Existing specs changed only in when they look, never what they assert (completion-hooks). The norm-outward-toolset golden gained the tasks.*, events.*, webhooks.* and jobs.fetch_result tools.
  • Gates are not e2e and keep no self-test script: each of the 7 was shown red once on a planted sample in a scratch copy (no-bypass-by-structure).
  • Dropped from the plan: a scheduled job-source fetch (not built, by decision) and webhook debouncing (webhooks never coalesce).

Regression

  • Each phase: the affected existing specs (embed, corpus, access, booking, microsite, obsidian, jobs, monitor, mail, search, supplier, calendar, upgrade, …) with REPEAT=5 to rule out flakes.
  • Order: each component's UTs first; each acceptance e2e written first and shown red on the unchanged code (make test-asis); then the implementation.

Final acceptance: every test in this repo green (passed 2026-09-27)

CommandCovers
make lintsecrets, env, backend (every check-*.sh gate, including the 7 of this plan), no-mock, app, sdk, e2e, im-bridge, verify-items
make backend-testGo tests, including the new UTs
make test-unitfrontend and SDK unit tests
make im-bridge-testim-bridge
make stack-testwhole-stack tests
make dsh-plugin-testevery block installed into a real dsh and run
make test-freshthe full e2e suite from an empty volume, proving schema.sql and the migrations agree
make eval-*evaluations on the real agent loop (blocks, owner-mcp, ghost, summary, …)

One pass, no rerun-to-green. All of the above must be green in one pass. A failure is read from its logs and its mechanism found; it is never re-run until green. Only then: merge to main, release, upgrade sijie.xyz, deploy standmeet.com, and run the P3 real-environment acceptance, recorded under docs/real-env-verification/. Phase status is in events-roadmap.

about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →