Merge Smoke Checklist
Use this checklist before merging branches that change checkout, webhook persistence, pledge management, inventory, settlement, or supporter broadcasts.
This version is tuned for the current checkout and Worker business-logic behavior on main.
Scope For This Branch
These behaviors changed intentionally and should not be treated as regressions during smoke testing:
- Magic links are order-scoped instead of email-scoped.
/checkout-intent/startnow reserves scarce limited inventory before payment confirmation, and successful persistence confirms that reservation.- Legacy
GET /checkoutis disabled. - Settlement only marks a campaign fully settled when no active pledges were skipped.
Environment
Set these for the operator shell before starting:
export STAGING_SITE_URL="https://pool-staging.example.com"
export STAGING_WORKER_URL="https://pledge-staging.example.com"
export ADMIN_SECRET="..."
If the staging site and Worker share the same domain pattern in your setup, use the real staging URLs instead of the placeholders above.
If no staging environment exists, point these variables at local dev instead:
export STAGING_SITE_URL="http://127.0.0.1:4000"
export STAGING_WORKER_URL="http://127.0.0.1:8787"
export ADMIN_SECRET="..."
In that case, run ./scripts/dev.sh --podman first and record in the sign-off that merge relied on the automated gate plus local smoke coverage because no staging environment exists.
Local Rehearsal
Before a staging pass, or instead of one when no staging exists, you can rehearse most of the flow locally with:
./scripts/dev.sh --podman
That script starts:
- Jekyll on
http://127.0.0.1:4000 - the Worker on
http://127.0.0.1:8787 - Stripe CLI webhook forwarding to the local Worker
Use local rehearsal to sanity-check checkout, webhook delivery, manage-link behavior, and admin endpoints before running the same flow against staging.
For dashboard-heavy branches, open the local dashboard at http://127.0.0.1:4000/admin/. The dev stack seeds the bootstrap admin defaults documented in README.md and worker/README.md; user-management changes made in the dashboard save to local Worker KV and are reset with local KV state.
For local-only pledge management checks, use the smoke-editable campaign. It is defined as test_only: true, so it shows up in local development when _config.local.yml enables show_test_campaigns, while staying excluded from the production homepage and production /api/campaigns.json.
Recommended local setup for modify/cancel smoke:
curl -s -X POST http://127.0.0.1:8787/test/setup \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","campaignSlug":"smoke-editable"}' | jq
Or run the end-to-end local mutate/cancel check directly:
./scripts/smoke-pledge-management.sh
Test Data Setup
Prepare or identify:
- One live staging campaign with:
- at least one standard tier
- one limited tier
- one threshold-gated tier if available
- at least one support item if available
- One supporter email inbox you can receive mail in.
- One second supporter email inbox for multi-pledge and inventory checks.
- Seeded pledges for settlement testing:
- one active pledge with valid Stripe customer/payment method
- one active pledge intentionally missing
stripeCustomerId
- A campaign with enough supporters to cross pagination boundaries, if available.
Pass / Fail Rule
Treat any of these as merge blockers:
- checkout succeeds but persists the wrong pledge shape
- modify/cancel breaks pledge totals, stats, or tier inventory
- a single magic link can still enumerate or modify another order
- settlement marks a campaign complete while active pledges still need attention
- milestone, diary, or announcement sends miss supporters or duplicate unexpectedly
Checklist
1. Checkout Start
- Open a live staging campaign page.
- Add a normal tier and proceed to checkout.
- Confirm the browser reaches the on-site Stripe payment step successfully, or the hosted fallback path if that mode is intentionally enabled.
- Expected result:
- no console errors on the campaign page
- the checkout summary matches the selected tier, support items, custom amount, and tip
- if the selected tier is scarce and near exhaustion, checkout start can hold it immediately
2. Checkout Completion
- Complete a real staging/test checkout for a single pledge.
- Verify the success page loads.
- Verify the pledge exists in the Worker-backed data and the supporter can open the manage link from email.
- Expected result:
- webhook persists the pledge once
- stored tier/add-on/custom amount match the actual checkout session
- stats endpoint reflects the new subtotal
Helpful checks:
curl -s "$STAGING_WORKER_URL/stats/<campaign-slug>" | jq
curl -s "$STAGING_WORKER_URL/inventory/<campaign-slug>" | jq
3. Magic Link Scope
- Create or identify two pledges for the same supporter email.
- Open the manage link from the first pledge email.
- Attempt to view or act on the second pledge from that same session/link.
- Expected result:
- the link can manage only its own order
- other pledges on the same email are not listed or modifiable through that token
4. Modify Flow
- Modify an uncharged pledge:
- change the base tier if allowed
- adjust quantity if allowed
- add or remove support items
- add or remove custom support
- Verify the updated totals in the manage UI and in stored data.
- Expected result:
- subtotal, tax, tip, and final amount update coherently
- pledge history records the modification
- stats and inventory reflect the new pledge state
5. Cancel Flow
- Cancel an uncharged pledge through its own manage link.
- Re-check stats and inventory.
- Expected result:
- pledge moves to cancelled state
- subtotal is removed from campaign stats
- limited inventory is released
6. Limited Inventory Behavior
- Start checkout for a limited tier but do not complete payment.
- From a second browser/profile, start checkout for the same last-unit limited tier.
- Expected result:
- the second checkout is blocked or sold out while the first reservation is still active
- public inventory remains the projection of committed claims, so the user-facing sold-out behavior may lead the public claimed count briefly
- successful webhook persistence confirms the held reservation instead of re-claiming against a separate truth source
7. Threshold-Gated Tier Behavior
- Try to purchase a threshold-gated tier before the threshold is met.
- If possible, repeat after seeding enough support to cross the threshold.
- Expected result:
- before threshold: selection is rejected/disabled
- after threshold: selection succeeds normally
8. Settlement Dry Run
- Run a settlement dry run for a funded test campaign.
- Verify the response shows supporters and skipped records accurately.
- Expected result:
- active pledges missing Stripe customer data are surfaced as skipped/needing attention
- no completion marker is created by dry run
Example:
curl -s -X POST \
-H "Authorization: Bearer $ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{"dryRun":true}' \
"$STAGING_WORKER_URL/admin/settle/<campaign-slug>" | jq
9. Settlement Live Run
- Run live settlement on seeded staging data or a dedicated test campaign.
- Inspect the response and follow-up status.
- Expected result:
- campaigns with skipped active pledges do not get a final
campaign-chargedmarker - campaigns with no unresolved work do mark as settled
- successful charges send the expected post-charge emails
- campaigns with skipped active pledges do not get a final
Preferred endpoint for larger campaigns:
curl -s -X POST \
-H "Authorization: Bearer $ADMIN_SECRET" \
"$STAGING_WORKER_URL/admin/settle-dispatch/<campaign-slug>" | jq
10. Customer Backfill
- Run customer backfill for a campaign with known missing
stripeCustomerIdvalues. - Expected result:
- all qualifying pledges across KV pagination are updated
- rerunning settlement after backfill reduces or clears skipped customer records
curl -s -X POST \
-H "Authorization: Bearer $ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{}' \
"$STAGING_WORKER_URL/admin/backfill-customers/<campaign-slug>" | jq
11. Broadcast and Pagination Checks
Run these against a campaign with enough supporters to test pagination if possible.
- Announcement dry run.
- Diary check or diary broadcast.
- Milestone check or milestone broadcast.
- Expected result:
- recipient counts include the full supporter set
- no obvious truncation to a first page of results
- no duplicate milestone send from a repeated or overlapping check
Examples:
curl -s -X POST \
-H "Authorization: Bearer $ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{"campaignSlug":"<campaign-slug>","subject":"Smoke Test","body":"Dry run","dryRun":true}' \
"$STAGING_WORKER_URL/admin/broadcast/announcement" | jq
curl -s -X POST \
-H "Authorization: Bearer $ADMIN_SECRET" \
"$STAGING_WORKER_URL/admin/milestone-check/<campaign-slug>" | jq
12. Admin Dashboard Smoke
Run this section when the branch changes dashboard UI, admin Worker routes, campaign configuration, add-ons, uploads, reporting, analytics, supporters, marketing tools, or user management.
- Sign in to
/admin/with an authorized admin email. - Verify the main tabs render without horizontal overflow at desktop, tablet, and mobile widths.
- In Settings, confirm publishable sections show a disabled
Publishbutton until a real change is made. Confirm Users, Secrets & credentials, and Runtime diagnostics do not show an unused publish action. - In Settings -> Users, create or edit a campaign user, save, and confirm the change takes effect without a GitHub publish flow.
- In Campaigns, switch campaign subtabs and verify content, tiers, campaign add-ons, diary entries, and decisions load for the selected campaign only.
- In Content and Diary Entries, add/edit a content block, verify WYSIWYG preview behavior, and confirm
Save Draftonly enables when the local draft differs from the saved value. - In Add-ons and campaign Add-Ons, verify physical products show shipping preset / package fields, digital products hide shipping fields, and product/variant IDs derive from names/labels for new entries.
- In Analytics, Reports, and Supporters, verify the default
Allview only shows campaigns available to the current admin, dollar amounts show exact cents where applicable, and CSV export matches the visible rows. - In Marketing, save/edit/delete a referral code, verify the URL builder clears after save/refresh, and confirm the embedded campaign builder still works.
- For
/es/admin/, verify translated tab labels and tablet/mobile navigation do not overflow.
Sign-Off Template
Record the smoke result in the PR or release notes:
Smoke completed on <date> in <staging|local>.
- Checkout start/completion: pass
- Magic link scope: pass
- Modify/cancel: pass
- Limited inventory behavior: pass
- Threshold gating: pass
- Settlement dry/live: pass
- Backfill: pass
- Broadcast pagination/milestones: pass
- Admin dashboard smoke, if relevant: pass
Notes:
- <any intentional behavior observed>
- <any non-blocking staging caveats>
- <note that no staging environment exists, if applicable>