Machine-readable companion to the demo verification report. Paste the block below to your AI, or fetch this URL directly. Human version has the screenshots.

# SoundCheck demo verification run (machine-readable)

Date: 2026-07-15
Runner: Kenn Jordan (ElmsPark), independent of the builder
Repo: ElmsPark/soundcheck (fork of donjjjordan/soundcheck), commit c0f48b1
  = the exact commit audited by the round-2 review (soundcheck-review-r2-x7k4)
Purpose: resolve the round-2 claims-table row "The live demo already exists,
  3-minute quickstart", which was PARTLY CHECKED (audit machine had no Postgres).
Result: VERIFIED END TO END, with one config-level blocker found and worked
  around (no product code changed). Details and repro below.

## Environment

- M5 MacBook Pro, macOS 27.0, Node v24, npm cache warm
- No Postgres of any kind installed before the run (checked: no formula, no
  service, port 5432 free)
- Installed: postgresql@16 16.14 via Homebrew bottle (initdb trust auth,
  cluster owner = local user)
- Browsers: manual pass in Chromium, scripted pass in Playwright (headless
  Chromium), fresh contexts per role

## Setup timing (README "Getting started (for Kenn)", followed exactly)

| step                                   | seconds |
|----------------------------------------|---------|
| brew install postgresql@16 + start     | 7       |
| git clone                              | 3       |
| cp .env.example .env + set DATABASE_URL| <1      |
| createdb soundcheck (keg-only prefix)  | 1       |
| npm install (warm cache)               | 4       |
| npm run db:migrate                     | 2       |
| npm run db:seed                        | <1      |
| npm run dev -> "Ready in 1772ms"       | ~3      |

Total ~14s of command time against the README's "about 3 minutes".
Seed output: "Seeded 6 acts, 4 reviews, 2 venues." Popular demo date printed:
2026-08-01 (a Saturday; acts #1 Brass Tacks and #4 Midnight Sax Trio are
pre-booked on it, so search filtering is demonstrable).

## Tour steps and observed results

1. SEARCH: /search?date=2026-08-01&postcode=SW1A+1AA -> "4 bands available on
   Sat, 1 Aug 2026". Correct: 6 seeded acts minus the 2 booked-out. All-in
   prices shown incl. travel + VAT. PASS.
2. ACT PAGE (The Velvet Kings): 5.0 stars (2 booking-verified reviews),
   PLI GBP 10m / PAT / ID badges, 16-Saturday availability grid, breakdown
   1450 + 1.80 travel (4 mi from N1 7GU) + 290.36 VAT = 1742.16, deposit
   348.43. PASS. (Cosmetic: genres render as raw enums "SOUL_MOTOWN,
   FUNK_DISCO" here; search cards prettify them.)
3. BOOK as chloe@example.com / "password", mock provider:
   - FIRST ATTEMPT ON SHIPPED .env: FAILS. See finding V1.
   - AFTER WORKAROUND (blank 3 STRIPE_* lines): booking SC-2026-0005 created,
     status Confirmed, chip "Venue check pending", deposit 348.43
     "payment protected", contract auto-generated, availability slot BOOKED.
     PASS.
4. CONTRACT: signed as client, then as act (hello@thevelvetkings.co.uk /
   "password"). Status walked sent -> client signed -> fully signed; booking
   advanced CONFIRMED -> CONTRACT_SIGNED. Act dashboard shows budget, venue,
   payout 1306.80, commission 145 disclosed. PASS.
5. TOKENISED VENUE LINK: shown on the booking page (email is mocked), format
   /venue/<24-hex-token>. Opened in a fresh cookie-less context: loads with no
   login, names the venue, says which act and date it is helping. Exactly 16
   visible inputs. PASS.
   NOTE: the link only exists when the booking's venue postcode does NOT match
   a seeded venue. SW1A 1AA and GL54 1AA carry CONFIRMED cached setups, so
   booking with those reuses the Venue Database entry and skips outreach (by
   design). This run used a new venue "The Verification Rooms", SW1A 2AA.
6. INTAKE SUBMITTED: indoor, stage 6x4 m, 3 sockets, level load-in, parking
   yes, curfew 23:30, limiter fitted, 85 dB, A-weighted, reset authority
   "Sarah (duty manager)" 07700 900123, contact "Vera Manager". Thank-you page
   immediately shows the plain-English readout and "Readiness: RED (1 note
   flagged to the act)". PASS.
7. RED VERDICT: client dashboard chip flips to "Venue: problem to fix" (past
   bookings stay green "Venue ready"). Booking page shows the same chip plus
   flag "Limiter at 85 dB will not allow this band's live drums.
   Electronic-kit line-up or a different venue needed." and an amber ULEZ
   note. Venue Pack prints: "85 dB, A-weighted. Live drums not advisable.
   Electronic kit or cajon line-ups recommended. Reset authority: Sarah (duty
   manager), 07700 900123." plus stage fit 6x4 vs 5x3 needed, curfew, contacts.
   PASS, wording verbatim from src/domain/limiter.ts.

Scripted probe pass (Playwright): 13/13 exact-string assertions found
(contract "fully signed"; venue page name + "no account needed" + "You are
helping The Velvet Kings"; thanks "is confirmed" + "Live drums not advisable"
+ "RED"; dashboard chip; booking chip + limiter flag; pack "85 dB" +
"Live drums not advisable" + "Sarah (duty manager)").

DB ground truth after the tour:

  reference   |     status      | venueReadiness |   contract   | client_signed | act_signed
--------------+-----------------+----------------+--------------+---------------+------------
 SC-2026-0005 | CONTRACT_SIGNED | RED            | FULLY_SIGNED | t             | t

          name          | confirmation | confirmedBy  | thresholdDb |       verdict
------------------------+--------------+--------------+-------------+---------------------
 The Verification Rooms | CONFIRMED    | Vera Manager |          85 | ELECTRONIC_KIT_ONLY

Screenshots (untouched Playwright captures):
https://elmspark.com/assets/soundcheck-verify-x7k4/
  01-contract-fully-signed-act-view.png
  02-venue-intake-top.png
  03-venue-form-filled.png
  04-venue-thanks-readout.png
  05-client-dashboard-red.png
  06-booking-red-verdict.png
  07-venue-pack.png

## Findings

### V1 (BLOCKER): shipped .env placeholders crash the Book step
- Repro: cp .env.example .env; set DATABASE_URL only (the README's only .env
  instruction); npm run dev; attempt any booking while signed in.
- Observed: POST /book/<actId> -> 500.
  Server log: "Internal error: Error: Invalid API Key provided: sk_test_..."
  at node_modules/stripe/esm/RequestSender.js:100:31.
- Cause: .env.example ships STRIPE_SECRET_KEY="sk_test_..." (non-empty
  placeholder); src/server/payments/index.ts paymentsProvider() returns the
  mock provider only when the key is FALSY, so any non-empty string selects
  the real Stripe provider; makeStripeProvider() constructs new Stripe(key)
  unvalidated and createCheckoutSession() throws on the live API.
- Contradicts: README "Stripe runs in a built-in mock mode by default, so
  nothing is needed from anyone to run the full flow end to end", and
  .env.example's own comment "Leave blank to use the built-in mock provider"
  (the shipped values are not blank).
- Workaround used in this run (config only): set the three STRIPE_* values to
  "" and restart the dev server. Everything downstream then passed first time.
- Suggested fix (either, one line): ship the three values empty in
  .env.example; or in paymentsProvider() treat the literal placeholder
  (e.g. /^sk_test_\.\.\.$/ or endsWith("...")) as unset.

### V2: round-2 F7 observed live (HELD-date leak on failed checkout)
- The createBooking transaction commits (booking row + slot HELD) BEFORE the
  provider call, so the V1 crash left booking SC-2026-0005 stuck at
  AWAITING_PAYMENT and The Velvet Kings' 2026-08-01 slot HELD on the very
  first attempt. The date became unbookable (availability guard rejects
  non-AVAILABLE slots) and nothing cleans it up; this run reseeded to
  continue.
- Evidence: SELECT on AvailabilitySlot showed status HELD for that act/date
  immediately after the 500.
- Implication: any abandoned or failed real-Stripe checkout leaks the same
  way. Suggest an expiry on HELD (or release-on-failure) ahead of other
  Phase-3 work.

### V3 (friction): booking details discarded across the sign-in redirect
- Repro: fill the booking form signed out (venue name, postcode, guests),
  submit, sign in when redirected.
- Observed: back on the form with venue name, postcode and guest count blank
  (redirect next-URL preserves only actId + date); travel drops out of the
  total until retyped. The pre-login banner says "Your details and price are
  kept exactly as shown", which currently over-promises.
- Suggested fix: carry the form fields through the login round-trip (e.g.
  serialise into next), or reword the banner.

### V4 (cosmetic): act page shows raw genre enums
- /acts/<id> header renders "SOUL_MOTOWN, FUNK_DISCO"; search cards render
  "Soul / Motown". Align the act page with the search-card prettifier.

## Fix list (suggested order)

1. V1: blank or guard the Stripe placeholders (unblocks every fresh clone).
2. V2/F7: release HELD slots on failed/abandoned checkout, or expire them.
3. V3: preserve booking-form details across sign-in, or soften the banner.
4. V4: prettify genre enums on the act page.

## Demo-script notes

- Use the seeded Saturday 2026-08-01 so availability filtering is visible.
- Give the booking a venue postcode that is NOT SW1A 1AA or GL54 1AA, so the
  tokenised outreach link appears (those two postcodes demo the cached Venue
  Database path instead).
- Submit only the 85 dB limiter as the problem so the RED flag reads clean
  (avoid also breaching curfew/stage, which would stack flags).
- Blank the STRIPE_* lines before demoing until V1 is fixed.

## Cross-references

- Human version of this report (with screenshots):
  https://elmspark.com/soundcheck-demo-report-x7k4/
- Round-2 code audit: https://elmspark.com/soundcheck-review-r2-x7k4/
- Round-2 machine-readable: https://elmspark.com/soundcheck-review-r2-md-x7k4/