Skip to content

Alpha Loop Verification (venue seed + two-account loop + offer round-trip) - Test Plan โ€‹

FieldValue
Branch / PRfeat/alpha-venue-seed-and-loop (session PR TBD)
EnvDEPLOYED dev (dev.ourlantern.app, admin.dev.ourlantern.app) + dev Firebase
Driversheadless Playwright (app loop) + Admin SDK/ADC (seed + data assertions); Agent Probe admin
Coordinatesportal-polish session owns the merchant + offer side; this session owns venue + user side
Date2026-08-08 (scenarios 1-2); scenario 3 re-run live 2026-08-16

North star โ€‹

Validate the core alpha loop works LIVE on deployed dev: a user finds a venue, lights a lantern, waves, connects, chats; and a merchant's approved offer on that venue is discovered + claimed by the user. This is the December-2026 alpha's whole premise, so a null discovery on broadest-audience targeting is a real bug, not a soft pass.

Scenarios โ€‹

1. Seed the alpha venue (data) โ€‹

  • Do: create a dedicated SD alpha venue via createManualVenue against dev (source:'manual', server geohash + nameLower + activeLanternCount:0).
  • Expected / Verify: venue doc exists in dev venues with a real geohash, activeLanternCount: 0, source: 'manual'; note its id + name.
  • Then: signal portal-polish (name + id), cc PM, so merchant provisioning + venue association can start.
Result:    [x] pass   [ ] fail   [ ] blocked
Actual:    Seeded via createManualVenue against dev (also live-validates yesterday's venue-creation path).
Evidence:  id v9jQLgRn8sZ3jrTpncGw, "Lantern Alpha Venue", geohash 9mudjfzj1u, 32.7113,-117.1595, source:manual, ALC 0. portal-polish signaled.

2. Two-account user loop (deployed dev, headless) โ€‹

  • Do: account A + B (test numbers), both geolocated to the seeded venue. A lights a lantern; B sees it; B waves A; A accepts; they exchange a chat message.
  • Expected: each step succeeds; connection formed; message delivered (assert via Admin SDK: connection doc + message subcollection).
Result:    [x] pass   [ ] fail   [ ] blocked
Run on:    2026-08-16, deployed dev (re-run; see the 2026-08-08 original below)
Actual:    `npm run e2e:alpha-loop` GREEN: A+B lit at the alpha venue, B waved, A accepted, A messaged.
Evidence:  connection cCIS2X9jcCCrbI14Mz2z exists, messages=1, A active lantern at venue=true.
Why re-run: wave, accept and chat have taken multiple merges and deploys since 2026-08-08, so a run
           today could genuinely fail. It is a coverage gap closed, not a timestamp refreshed. It was
           also NOT exercised by the scenario-3 re-run, which lights A's lantern inside its own
           harness and never invokes this script.

Historical: 2026-08-08, connection l7ZVY05AAu60gznaUFJ0, messages=1, A lit at the venue.

3. Offer round-trip finale (cross-session with portal-polish) โ€‹

  • Do: portal-polish's merchant (provisioned + associated to the seeded venue) publishes an offer -> it holds at pending_review -> admin approves -> it goes active. This session's user A (lantern lit at the venue) fetches nearby active offers and claims it.
  • Expected: the approved offer appears in A's nearby offers (broadest audience) and the claim succeeds. A NULL discovery = real bug (file it).
  • Verify (data): offer status: active; a claim record for A.
Result:    [x] pass   [ ] fail   [ ] blocked
Run on:    2026-08-16, deployed dev
Actual:    Full round trip, every leg driven live. Merchant (real merchant login, NOT an admin)
           published through the offer form -> held at `pending_review`. User A, lit at the venue,
           could NOT see it. Admin approved it through the review queue -> `active`. Same user, same
           venue, now COULD see it, and claimed it.
Evidence:  offer bM6HoXgbQY0N5Pq5MoUg "Half price cold brew"
           publish   POST /merchants/m_KlAXPi6q4RvB/offers -> 201, status=pending_review,
                     moderation={autoOk:true,flags:[]}, createdBy=975QcCiJ... (the merchant)
           hidden    /offers/active returned 2 offers, this one absent (EXPECT=invisible PASS)
           approve   POST /admin/offers/bM6HoXgbQY0N5Pq5MoUg/status -> 200, status=active,
                     reviewedBy=vyRySTF7... reviewedAt=2026-08-16T13:47:09Z
           visible   /offers/active returned 3 offers, this one present (EXPECT=visible PASS)
           claim     HTTP 200 {"status":"claimed","alreadyClaimed":false,"remaining":1};
                     offerClaims/1af5b6a2..._bM6HoXgbQY0N5Pq5MoUg exists, status=claimed
Harness:   `npm run e2e:offer-finale` (OFFER_TITLE + EXPECT=visible|invisible)

Same-offer A/B on the moderation gate. Invisible while pending_review and visible after approval is the same offer, the same user and the same venue minutes apart, so the gate is observed rather than inferred.

Publisher identity decides the branch, and an admin bypasses the queue. resolvePublishStatus (services/api/merchants/src/routes/offers.js) sends an admin publish straight to active with moderation: null, because the admin is the reviewer. A second offer published the same day from the admin's merchant view, BerzA1vhzY20uNFZmble, landed active with moderation: null and never entered the queue. A run driven from the admin portal's merchant view cannot exercise the gate; it needs the merchant credential in ~/.lantern-test-accounts.env (TEST_MERCHANT_*).

Historical: the 2026-08-09 run โ€‹

Recorded here as dated evidence, not as current status. It went green on the build deployed that day, before the moderation close-out (#845, 2026-08-10) and every deploy since, and its harness never reached dev (it landed on feat/alpha-venue-seed-and-loop in e4557ab7 and c6f41226 AFTER PR #816 had squash-merged, so the scenario read as blocked for a week). Offers lk75tOwQYLfakZ2FQ719 (claimed) and gNZj8UX4X9DD6hWwMs6W (deliberately rejected, to exercise the reject branch) are from that run.

What the pairing validated (merchant side, via portal-polish, on this venue) โ€‹

Run live on deployed dev against the seeded Lantern Alpha Venue: merchant provisioning with venue auto-associate (#793), the one-time setup link, merchant set-password, real merchant login, and offer-form validation all GREEN. The single broken link is the publish call (#817), found precisely by running the real flow instead of reading code.

Notes โ€‹

  • App Check blocks the admin PORTAL headless, so admin-side offer approval is portal-polish's coordination point / an operator path; this session drives the user app (deployed dev supports the app loop via the registered App Check debug token) + the data assertions via Admin SDK.
  • Handoff moments are coordinated directly with portal-polish (venue-ready signal; offer-approved signal).

Built with VitePress