Conversation
… rollups page every event, exports never orphan objects
…s, owner toggles are idempotent, replays re-sign media, silent failures are logged
…v integers, adapter logs through pino, closed container fails loudly
… csrf cookie lifetime, oauth cancel redirects
…nding, certificate year and verify link follow the deployment, leaderboard stops at its ceiling
…ws serialize, replies to deleted posts 404, reposts refresh counts, feed test no longer flakes
… mentioned, kicks and joins are atomic, edits re-record mentions, failures are logged
… and raised caps and skip ended events, portfolio totals span every event, invite caps hold under concurrency
…room, flag and role writes lock their rows, owner takedowns keep their meaning, exports report what they could not deliver
…n session, strict layer and batch args, demo seeder matches the live write paths
…h window, bounced contacts stop routing, bounces redrive, sanitizer keeps spaces and decodes entities once
…ecipients whose bell failed
…ension refuses deleted users; audit actions are typed
… host lists page on microsecond keysets
…emovals never downgrade a ban
…, sanitizer checks the href a browser reads
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.
What changed
Correctness fixes across the API and the media worker, found by the campaign audit and hardened by an adversarial review pass. Silent failures now log or retry instead of disappearing; lists page without skipping or repeating rows; host registration, waitlists, exports and broadcasts keep their counts straight under concurrency; admin mail stops routing to bounced city addresses; the media worker retries its own infrastructure faults instead of rejecting people's uploads. Nothing is removed from any response a client relies on.
Before you start
media_assets.upload_etag, catalog-only) and 0185 (new small tableinbound_bounce_attempts).APNS_PRODUCTIONis now parsed strictly and required in production once all APNs credentials are set; accepted values are true/t/yes/y/on/1 and false/f/no/n/off/0. Malformed integer settings (for example15s) now fail boot instead of silently using a default. Staging proves only staging's values.Verify
[Web]
[Mobile]
[Admin]
Regression
Filing reports with photos — [Web] [Mobile]
Chat — [Web] [Mobile]
Feed and notifications — [Web] [Mobile]
Events and RSVPs — [Web]
Host messaging — [Web]
Admin mail — [Admin]
Findings addressed
Grouped by package; IDs are campaign ledger IDs (
.campaign/backend/ledger.json, not in this repo). About 150 items were fixed, some partly; the rest are refuted, already fixed, or listed under decisions.Decisions for the reviewer
APNS_PRODUCTIONis strict (list above) and defaults to the production gateway;SHUTDOWN_DRAIN_MSkeeps its lenient reading on purpose (a boot failure over shutdown timing would be worse).joinednow means the caller RSVP'd: an org owner or admin who never joined sees Join, and keeps host powers. A guest RSVP the registration refuses now answers an error with a reason code, and a refusal that is certain from public event state (access code needed, registration or sales closed) is answered before a code is sent.User-visible copy changes
{ "ok": true }(was 204, matching the registry).Tests changed
Existing tests whose expectation changed because the fix changes the behavior they pinned (no test was skipped, deleted or loosened; each is listed in the campaign reports with its reason):
test/unit/feed-ranked-service.test.ts,test/unit/host/cleanup-duplicate.test.ts: flaky tests fixed at the root (unseeded random order; two clock reads).test/unit/home-turf-routes.test.ts: a same-address resubmit answers 200 without a second confirmation (was 429 after the staff email went out).test/unit/guest-rsvp-service.test.ts: a sold-out verify is refused (it pinned the silent success).test/unit/storage-r2-proxy.test.ts,test/unit/adapters-push-classification.test.ts: every storage client now carries a timeout handler; invalid-argument pruning is decided per batch.test/unit/host-export-csv.test.ts,test/unit/host-export-lifecycle.test.ts,test/unit/host-reminders.test.ts,test/unit/host/announcement-pipeline.test.ts,test/unit/host-broadcast-send-correctness.test.ts: export keys carry the run token; a cancellation retry re-plans; cursors carry the instant as text; the budget refund is a decrement.test/unit/admin-moderation-correctness.test.ts,test/unit/admin-user-correctness.test.ts,test/unit/admin-event-correctness.test.ts,test/unit/admin-report-correctness.test.ts: owner takedown folding;FOR NO KEY UPDATElocks.test/unit/chat-room-fanout-failures.test.ts(rewritten against the real notification service),test/unit/chat-room-notifier-wiring.test.ts,test/unit/post-unrepost-unreadable.test.ts,test/unit/ws-socket-lifecycle.test.ts,test/unit/admin-mail.test.ts,services/media-worker/test/unit/maintenance.test.ts,services/media-worker/test/unit/pg-boss-jobs.test.ts.test/unit/inbound-html-sanitizer-linear-time.test.ts: a long space run inside an href is cleaned in under 500 ms (6 s before the last commit), and edge trimming still applies.Verification
pnpm typecheck,pnpm lint,pnpm build,pnpm check:sql, prettier check: pass.FFPROBE_PATH/FFMPEG_PATH): 300 passed, 2 failed. Both failures are the known ffprobe-helper environment issue fixed in Backend test safety net: SQL transcripts, CSRF pairing, authz and characterization tests #92, which this stack does not contain.*-pgfiles) are written but not run locally (no Docker by rule). CI runs only on PRs based on main, so it starts here when the PRs below this one merge and GitHub retargets this one to main; merge it only after that run is green.Staging checks
https://api.civfix.dev/readyzanswers ready after the deploy (migrations 0184 and 0185 applied).GET https://api.civfix.dev/v1/reports/search?cursor=2026-02-30T00:00:00Z|00000000-0000-4000-8000-000000000001answers 200 with the first page (not 500).Not covered
APNS_PRODUCTIONand integer settings are not readable here; confirm them before a release.🤖 Generated with Claude Code