Give the e2e-server a real v2-primary lane and delete the /api/send shadows (rebuild W3 PR-F)#141
Merged
Conversation
…hadows (rebuild W3 PR-F)
The e2e-server hand-rolled an /api/send shadow that omitted the idempotency
key, so a Playwright "Retry" passed while production 409'd forever. This
replaces the shadows with the production surface so the browser suite
exercises what ships.
- v2-primary lane: real sqlite.Store + blob store over a temp dir, a
bridge.Registry of scripted fake adapters declaring TextSender/MediaSender
capabilities, the real v2wire services, the production /api/v1 routes, and
a PrimaryNotifier over the fake Events. The web options set
V2Primary: true and Reads: v2read.New(store) exactly as serve.go does, so
GET /api/status reports v2_primary:true, the frontend routes sends to
/api/v1/outbox/messages, and reads come from the v2 path (RR-2 reactions
included) rather than the legacy shadow. Legacy fixtures migrate into the
v2 store so conversation/message reads keep working on native v2 ids.
- Shadows deleted: /api/send and /api/drafts/send are gone. Fixture controls
live only under /_e2e/* (POST /_e2e/bridges/{account}/next-result drives
scripted send outcomes).
- Structural guard: a test fails if the e2e-server registers any /api route
itself. It walks every .go file in the package and strips an optional
METHOD prefix before the check, so a re-added "POST /api/send" mux pattern
is caught, not just a bare "/api/..." literal.
- Fake-bridge round-trip test: next-result uncertain -> submit -> the outbox
row lands uncertain via the real dispatcher, a repeat HTTP submit dedupes
(same outbox_id, deduplicated:true) with dispatch count exactly one.
- Playwright send tests point at /api/v1/outbox/messages; the two that mock
/api/status advertise v2_primary:true so their send-request counters
observe the route the frontend now uses.
Owner
Author
|
Updated after the primary-lane reconciliation: the suite now validates v2-primary honestly — locally 91 passed / 9 skipped / 0 failed in 53s (was: 20-min CI timeout). The 9 skips are |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rebuild W3 PR-F — real v2-primary e2e lane + delete /api/send shadows
The e2e-server's hand-rolled
/api/sendshadow omitted the idempotency key, so a Playwright "Retry" passed while production409'd forever (the A4 trap). This replaces the shadows with the production surface so the browser suite validates what ships.The review catch that made this correct
First build mounted the v1 routes but left the lane at
v2_primary=false— so the frontend (which routes onstatus.v2_primary) kept posting legacy/api/send, the four Playwright mock flips were dead, and the lane validated the legacy path while claiming v2. Opus review flagged it BLOCKER; confirmed by grep (noV2Primary/Readsin the lane) and curl (v2_primary:false). Fixed: the lane now setsV2Primary:true+Reads: v2read.New(store)mirroringserve.go, migrates legacy fixtures into the v2 store, and the two status-mocking specs advertisev2_primary:true.Factual gate (verified outside the sandbox)
Built the e2e-server and curled it directly:
GET /api/status→v2_primary: true(wasfalse)POST /api/v1/outbox/messages→ HTTP 200 with a realoutbox_id+state:queuedSo the browser now genuinely exercises the production v1 handler. CI's Web E2E job (real Playwright + real e2e-server) is the end-to-end gate on the four flipped tests.
Also
/api/send+/api/drafts/sendshadows deleted; fixture controls confined to/_e2e/*..gofile in the package and strips an optionalMETHODprefix, so a re-addedmux.HandleFunc("POST /api/send", …)is caught (the review showed the original guard missed exactly this idiom).next-result:uncertain→ durableuncertainrow via the real dispatcher; repeat submit dedupes (sameoutbox_id, dispatch count == 1).Verification
Independent full
GOWORK=off go test -race ./...outside the sandbox: 32/32 packages, exit 0 includingcmd/e2e-server. Scope:cmd/e2e-server/**+e2e/ui.spec.jsonly; no production handler/storage changes.🤖 Generated with Claude Code