standup
Standup — 2026-08-02
Ten PRs merged across two days.
▶ Watch the 43s summary — Daily standup — Standup 2026-08-02
Daily standup for 2026-08-02. What shipped:
Ten PRs merged across two days. The window was busy.
Dunning grace window bounded. #905 closes a gap where a past_due subscription could hold Pro indefinitely. A new reconcile_dunning_grace phase in the daily Stripe sweep cancels any subscription past_due beyond 7 days — the ceiling ADR-0012 ratified but never implemented. The sweep makes no entitlement write; it fires customer.subscription.deleted and the existing webhook path handles the downgrade, notice, and mirror update. The dunning marker rides cancellation_details.comment on the cancel call itself rather than subscription metadata, so a marker can’t orphan on a subscription that recovers.
Multisite provisioning fixed; ADR-0043 filed. #898 fixes network activation seeding only the activating subsite and leaving the rest keyless. Every subsite now provisions itself lazily on first admin load. #943 files ADR-0043, which amends the original proposed decision on three of five items: network activation is allowed (not refused), Free module gating is dropped (cost clears with an order of magnitude to spare at $0.13/tenant at 1k), and identity settlement is tracked as #942 rather than blocking.
Gateway IDs resolved to names. #934 — MemberPress stores a generated six-character instance ID in the gateway column, so the HEARTBEAT and site_lookup were showing sd6h2p where a name belongs, and the gateway filter matched nothing. The connector now resolves each ID through MeprOptions::payment_method() and emits gateway_type + gateway_label alongside the unchanged raw gateway. Every read path falls back label → type → raw id.
Platform axis vocab and editor. #945 fixes two gaps that each do nothing alone: PLATFORMS now derives from KNOWN_PLATFORMS | {"wordpress"} so a connector slug is taggable the day its module ships, and platform joins the editor allowlist and list-axes so authors can actually set it. The admin picker gets the axis too. A Python parity test scans admin/src/lib/taxonomy.ts for every slug the backend accepts, so a future connector can’t ship without reaching the editor UI.
Email fixes. Two issues in the KPI snapshot email (#947): SiteStats was read with an unordered .first() after a 60-day backfill, so customers could receive figures from an arbitrary day in the past two months; and the four change-delta slots were hardcoded to empty strings. Deltas now use the wow() helper so the two surfaces sharing week-over-week math can’t drift. A ↑ arrow was also hardcoded regardless of sign — a loss was rendering as ↑ -9.1%.
Security and admin. #948 notifies the previous address when an admin changes a user’s email — the out-of-band channel that makes an illegitimate change detectable. The send sits after db.commit() with its own try/except, so a rollback can’t announce a change that didn’t happen and a failed notice doesn’t skip the verification send. #938 adds an “Erase by email” action to the contact-submission detail page, driving the GDPR erase endpoint that previously required devtools. An optional reason field flows into the audit trail; a counsel first-pass cleared it for staging with two conditions before production reliance.
Dark mode fix and CI guard. #944 removes a route allowlist that was silently force-lighting any page nobody remembered to add — Contact Submissions was the last holdout. #946 adds Playwright browser-level CI coverage, because 242 unit tests passed the whole time the dark mode bug existed: jsdom couldn’t see computed styles.
Notable. The dunning fix caught that ADR-0012 had ratified a 7-day grace window years ago that the codebase had simply never implemented. The sweep makes it hold regardless of whatever the Stripe dashboard’s dunning end-behavior is set to — which Seth still needs to confirm and write down before the first apply=true sweep runs in production.
Window: 2026-07-31T13:00
→ 2026-08-02T14:39.680Z · Sources: memberintel @ 98189d5, memberpress-intel @ adc6879