Repository navigation
API sweep + cron pass: billing keys, Stripe webhook, AI not-configured, child savings, unsent email reported sent - #619
Merged
Conversation
scripts/api-audit calls every method of every app/api route (155 in 147 files) against a local production build, as signed out, a child, a parent and a super admin, with no body, an empty JSON object and a body that is not JSON. First sweep: 24 FAIL. After these fixes: 0 FAIL, 30 BLOCKED (an honest 503 for a provider this build has no key for), 11 reviewed. - Google Calendar connect: with no Google credentials the link threw a blank 500; it now returns the parent to the calendar with a toast. - Billing: portal, cancel and change-plan read STRIPE_SECRET_KEY alone, ignoring the key Super Admin -> Stripe Setup saves and checkout uses. All four now resolve it the same way and answer 503 "billing isn't set up" with no key; checkout reads the body before building a client. - Stripe webhook: read STRIPE_WEBHOOK_SECRET alone and built a client with getStripe() just to verify, so with the key in Stripe Setup every real event was answered "signature invalid". It now uses the Setup secret first and Stripe's keyless static verifier. - AI routes: nine let the provider's "not configured" throw become a 500, four a 502 "temporarily unavailable"; each now asks isAIConfigured() first. health/coach checked only the environment and missed a key saved in Admin -> AI Engine. - /api/ai/savings answered a child with advice built from the family's transactions, budgets, bills and subscriptions, which the finance service and the privacy export keep for adults. Now 403. Each fix has a test that fails against the old code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01776xJyhVe8xJQvTGeNfT9T
142 API rows move from NOT STARTED to IN PROGRESS with the sweep's per-caller statuses, verdict and fix; the eleven already in progress get the result appended; two routes the inventory missed are added. Register B: 14,228 items, 13,688 NOT STARTED, 525 IN PROGRESS. Records the open High finding API-SWEEP-06: finance tables are readable by a child at the database while the app treats them as adults-only. PRODUCTION READY: NO. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01776xJyhVe8xJQvTGeNfT9T
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01776xJyhVe8xJQvTGeNfT9T
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Running every scheduled job on a local build, /api/cron/weekly-digest
reported {"sent":4} with no mail provider. sendEmail/sendReactEmail
answer { ok: true, skipped: true } without RESEND_API_KEY, a contract
the contact form relies on, so each caller that read only `ok` turned
"nothing sent" into "sent": the invite, welcome, referral and admin
re-send flows told the person their email had gone, and the weekly
digest and chore reminders counted skips as sends.
Each caller now reads `skipped`: the four person-facing flows answer
their existing "couldn't send" message (the referral rolls back its
record), and the crons count a skip as a skip. A guard holds every
caller that reads the result to read `skipped` too; a behavioural test
drives the invite route through the real lib/email.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01776xJyhVe8xJQvTGeNfT9T
Every job in vercel.json run on a local build with and without its secret: 27/27 refuse without it (401) and run with it (200, zero failures). 25 JOB rows move to IN PROGRESS, one is appended, and the unregistered /api/cron/library-feeds is added. Register B: 14,229 items, 13,663 NOT STARTED, 551 IN PROGRESS. PRODUCTION READY: NO. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01776xJyhVe8xJQvTGeNfT9T
NewWorldVenture
marked this pull request as ready for review
September 27, 2026 22:40
…t keeps both top entries and recounts Register B Both sides added a dated entry at the top (the MAIN reconciliation, the API sweep) and both edited the Session B counts. The rows merged cleanly, so the header is recounted from them: 14,229 = 13,663 NOT STARTED + 535 IN PROGRESS + 21 FIXED + PASS + 9 BLOCKED + 1 FAIL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXw2nu25BjyRfA6Fg3YiMS
Owner
Author
|
I pushed a merge of How the conflict was resolved:
Checks on the merged tree:
If you push again, please pull first. Generated by Claude Code |
…unted from rows #623 moved sixteen public-site MAIN rows to FIXED + PASS. The rows merged cleanly; the header is recounted: 14,229 = 13,663 NOT STARTED + 519 IN PROGRESS + 37 FIXED + PASS + 9 BLOCKED + 1 FAIL (0.26%). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXw2nu25BjyRfA6Fg3YiMS
NewWorldVenture
pushed a commit
that referenced
this pull request
Sep 27, 2026
…folded #619 and this branch fixed the same routes from two sweeps. Main's versions are kept where they overlap, because they cover this branch's cases and more: billing reads the key saved in Stripe Setup (half of PAY-002) and answers "billing isn't set up" with a 503; the Google link answers gcal=not_configured and now also logs the missing variable, as this branch wanted. This branch's tests hold the merged routes to the same statuses, with the merged messages. finalaudit: rows both sweeps wrote keep main's cells with this branch's evidence in Notes; the two routes both registered keep main's IDs, with this branch's (API-B5A3C675E789, API-4E51E2B204A7) folded in as aliases. Recounted: 14,229 = 13,663 NOT STARTED + 520 IN PROGRESS + 37 FIXED + PASS + 9 BLOCKED + 0 FAIL. A note under PAY-002 records what #619 fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01776xJyhVe8xJQvTGeNfT9T
NewWorldVenture
pushed a commit
that referenced
this pull request
Sep 28, 2026
#619's API-SWEEP-04 checks isAIConfigured() before the provider call in the relationship and weekly-briefing routes; B11's P-25 answers a failure during the call with 503. Both are kept, and the two route tests mock both helpers. P-25's list of eighteen further routes is withdrawn in finalaudit.md, superseded by API-SWEEP-04. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TRY21ZKsFrfB3qtoP972A4
NewWorldVenture
pushed a commit
that referenced
this pull request
Sep 28, 2026
…24 to P-26 are B11's, so B14's findings are P-27 to P-31 B11 (#624) recorded its own P-24, P-25 and P-26 while B14 ran. B14's five findings are renumbered P-27 to P-31 in its section, its batch row and the three MAIN rows that cite them; the code and tests carry no P number. Both sections are kept, B11 first. Register B recounted from its rows: 14,229 = 13,663 / 511 / 45 / 9 / 1 (0.32%). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXw2nu25BjyRfA6Fg3YiMS
NewWorldVenture
pushed a commit
that referenced
this pull request
Sep 28, 2026
…fixes kept #619 ran the same API sweep and cron pass as this branch, in parallel, and landed first. Where both fixed the same defect (Google connect with no credentials, billing's Stripe key source, the webhook secret, unsent mail reported as sent), main's version is kept: every overlapping route is main's file. This branch's duplicate fixes are dropped, as is its Google test, whose case main's covers with a better answer (`gcal=not_configured`). What this branch still adds: - SEC-001: 0459, its probe, the E2E spec and the CSP change (unchanged). - API-SWEEP-08: /api/email/invite evaluated its family-wide limit on the member's session, which rate_limit_hit (0179) refuses, so every invite answered 429. The limit now runs on the service client, and main's invite test gets the matching mock export. - Driven tests that pass against main's fixes, kept as extra coverage: the no-key answer for all four billing routes, invite/welcome/referral/admin re-send, the no-provider digest counts, and the rate-limit key guard. finalaudit.md: main's API/JOB rows and sweep section are kept, and API-SWEEP-08 is added to its table. This branch's duplicate SWEEP-001..003 and PAY-002 findings are removed (main's tally stands: FIXED 122). The top entry records the duplication, SEC-001, the page-board reconciliation and the Next 16 re-crawl. Register B, recounted: 14,229 = 13,180 + 1,003 + 37 + 9 + 0 FAIL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
NewWorldVenture
pushed a commit
that referenced
this pull request
Sep 28, 2026
…ions agree session_01776xJyhVe8xJQvTGeNfT9T merged main into this PR branch at 78eac27 while this session merged main into its later head. Both kept main's route fixes. Taken from theirs: the Google connect route's log line naming the missing variable and this branch's Google test, which asserts it; and the API rows, which keep main's cells with this branch's sweep evidence folded into Notes, with the two duplicate route rows folded in as aliases. Kept from this side: the top entry, the headers and everything after 78eac27 (SEC-001, API-SWEEP-08, the page-board reconciliation, the Next 16 re-crawl). Notes that cited this branch's retired IDs now name main's: SWEEP-001 is API-SWEEP-01, 002 is 02, 003 is 07 and 004 is 08. Register B recounted: 14,229 = 13,180 + 1,003 + 37 + 9 + 0 FAIL. The full unit suite passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
NewWorldVenture
pushed a commit
that referenced
this pull request
Sep 28, 2026
… already has it ab77291 merged main at 8f6155a into this branch at ff08933. This side had merged the same main, plus everything after 78eac27. No code differs. In finalaudit.md, its only extra lines are this branch's own superseded sweep entry and older row text, so this side's ledger is kept whole. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
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 this is
This covers Register B's API rows, which nobody had claimed.
scripts/api-auditfinds every method of everyapp/api/**/route.tson disk: 155 route methods in 147 files. It calls each one against a local production build and a local Supabase with all migrations through 0458, as four callers:childmemberEach call sends the input a careless or hostile client would: no body,
{}, and a body that isn't JSON. That is 1,008 calls in total. The summariser sorts each response into FAIL, BLOCKED (an honest 503 saying "not set up"), REVIEW or OK.Fixes (each has a test that fails against the old code)
/dashboard/calendar?gcal=not_configuredwith a translated toast.STRIPE_SECRET_KEYonly. With no key anywhere, all four answered 500, and checkout built its Stripe client before reading the body.STRIPE_WEBHOOK_SECRETonly and calledgetStripe()just to verify the signature. With the keys held only in Stripe Setup, every real event was refused as "signature invalid".health/coachchecked only the environment, so it missed a key saved in Admin → AI Engine.isAIConfigured()before the provider. A guard test enforces this for every provider caller except three deliberate fallbacks./api/ai/savingsanswered a child with advice built from the family's transactions, budgets, bills and subscriptions.Recorded as open, not fixed here (API-SWEEP-06, High):
transactions,budgets,billsandsubscriptions_trackedare readable by any family member, children included, andsubscriptions_trackedis writable by any member.finalaudit.md
Checks
tscclean and lint clean on the changed files; the i18n gate is clean.node-version-is-pinned,stream-cancellation-runtime); this container runs Node 22.🤖 Generated with Claude Code
https://claude.ai/code/session_01776xJyhVe8xJQvTGeNfT9T
Generated by Claude Code