Estimate: 18m · Depends on: 1.6.5
The Story-closing E2E proves the runtime + the patterns + the dashboard hold together end-to-end against a forced failure. Same shape as Story 1.5.6 — a Playwright spec that drives the user-visible flow, plus a Vitest integration spec for the cross-job invariants.
Spec at tests/e2e/jobs-flow.spec.ts covers:
succeeded row); the dev-console email provider logs the email body.lib/email.ts's dev-console provider throw deterministically for a specific recipient email pattern; invite that email → confirm the run appears as failed with attempts climbing to 3 → confirm a row lands in the DLQ tab → confirm the DLQ tab badge increments.job_run row appears as succeeded → confirm the DLQ row shows a non-null replayed_at → confirm the email body now logs to the dev console./settings/workspace/jobs while workspace B is active → confirm zero runs visible even though workspace A has many. This catches RLS misses the Vitest tests can't (they run with a single connection).Vitest integration spec at tests/jobs/integration.test.ts covers the cross-cutting invariants that don't surface via the browser:
system.daily-health-check scheduled job, manually fired via the in-process harness, writes the expected synthetic-event job_run row.email.send event twice with the same idempotency key results in exactly one job_run row and exactly one sendEmail invocation.Story-level verification recipe (manual, ≤12 minutes): pull main; pnpm install && pnpm dev + npx inngest-cli dev; walk the spec's scenarios interactively in the browser, spot-checking that the Inngest dev UI shows the same runs the dashboard does (the two surfaces should agree on every visible run).
If any scenario fails: fix in this Subtask if it's a Story-level regression; log a finding if it points at a deeper service-layer issue (per mistake #27).
tests/e2e/jobs-flow.spec.ts covers every bullet in the scenario list; each scenario is its own test() block.lib/email.ts's dev-console provider throw deterministically; the flag scope is per-spec, not global.replayed_at changes from null to a timestamp, AND a fresh succeeded job_run appears.tests/jobs/integration.test.ts covers: scheduled job firing; idempotency dedup across duplicate sends; DLQ replay vs idempotency-window interaction (with the documented workaround).tests/e2e/workspace-flows.spec.ts + jobs-dashboard.spec.ts — existing patterns to mirrortests/e2e/_helpers/db-reset.ts + email-capture.ts — the reset + email-inspection helperslib/jobs/*, the serve route, the dashboard page, the email job)