[object Object]

← back to Costa Rica

cycle 10 docs: YOLO_NOTES ledger — plaid.js fetch bound + uncaught-throw/false-verified fixes + global unhandledRejection net

5c5fc34afddb7815b1167cc38b307e893f005beb · 2026-09-23 20:38:24 -0700 · Steve

Records the Plaid audit, the Cody-found holes inside the same function (bare
pool.query throws, getAuth-swallow persisting a false-verified bank), the global
crash net, and schedules the systemic per-route asyncHandler refactor for next cycle.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TouFkmUGKHtwqpZwgReVic

Files touched

Diff

commit 5c5fc34afddb7815b1167cc38b307e893f005beb
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Sep 23 20:38:24 2026 -0700

    cycle 10 docs: YOLO_NOTES ledger — plaid.js fetch bound + uncaught-throw/false-verified fixes + global unhandledRejection net
    
    Records the Plaid audit, the Cody-found holes inside the same function (bare
    pool.query throws, getAuth-swallow persisting a false-verified bank), the global
    crash net, and schedules the systemic per-route asyncHandler refactor for next cycle.
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01TouFkmUGKHtwqpZwgReVic
---
 YOLO_NOTES.md | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/YOLO_NOTES.md b/YOLO_NOTES.md
index 1f2145b..a5bb718 100644
--- a/YOLO_NOTES.md
+++ b/YOLO_NOTES.md
@@ -257,3 +257,23 @@ Canonical apply order now: `004_marketplace → 005_apple → 006_contacts → 0
 **Cost:** $0 (local tests + one Cody pass — Cody grep-verified the whole chain + corrected my severity + found the race I'd have missed).
 
 **Backlog:** the approval-enforcement decision is on Steve's desk (default-off flag pre-written, one APPROVE away). Provider-honored idempotency key still the only live-only money-path item. Next cycle: continue the coverage/audit sweep (routes/webhooks.js has only 2 test refs; routes/build.js, lib/plaid.js, lib/apple.js are thin) or a fresh Cody audit for a new issue class.
+
+## /yoloforever CYCLE 10 (2026-09-23, yf-costa) — lib/plaid.js audit → bounded fetch + fixed a process-crash class
+
+**Audited `lib/plaid.js`** (Plaid ACH bank-linking for foreign hosts; the actual ACH payout is NOT wired — payouts.js throws in live mode, so plaid.js is link/verify only).
+
+**FINDING A — last unbounded live fetch (fixed):** `_post` used raw `fetch()` with no timeout. Routed through the shared `fetchT` (bounds connect+headers AND body read). Every live provider call in the codebase is now bounded.
+
+**FINDING B — uncaught async throw crashes the whole server (fixed for this path):** the Plaid routes had no try/catch; this router has NO error middleware (Express 4.22) + no asyncHandler + Node 26 → a live Plaid throw is an `unhandledRejection` that **crashes the process**, taking down the marketplace for one route's error. Wrapped `/host/plaid/link-token` + `/host/plaid/exchange` → clean 502 (504 on `PROVIDER_TIMEOUT`).
+
+**Cody gate — FIX FIRST: found 2 more holes in the SAME function + 1 free net, all fixed this cycle (not split):**
+1. `/host/plaid/exchange`'s two `pool.query` calls were still bare `await` below my fix — a DB throw crashed the process identically. Wrapped → 502.
+2. `getAuth().catch(()=>({accounts:[]}))` swallowed a verification failure, then persisted the payout method **`verified=TRUE` with a NULL account_id/last4** — a silently-verified bank with no payout destination. Now `verified = !!acct.account_id`; an unverified method is `is_default=FALSE` and is NEVER set as the host default.
+3. Client errors echoed Plaid's `error_code` + the plaid.com URL (CWE-209). Now: log full detail server-side, return a generic message.
+4. Added a global `process.on('unhandledRejection')` net in `server.js` (log + stay up) so an uncaught throw in ANY of the ~21 still-unwrapped async routes fails that ONE request instead of crashing the whole server — a cheap net closing the systemic exposure tonight.
+
+**Tests (+9, suite 151 → 160):** plaid-lib-timeout.test.js (3: stalled→PROVIDER_TIMEOUT, 4xx fail-closed, sandbox no-fetch); plaid-routes.test.js (6: link-token 502 + no-leak, timeout 504, exchange 502 no-persist, getAuth-fail→verified=FALSE+not-default, getAuth-ok→verified=TRUE+default, DB-throw→502).
+
+**Cost:** $0 (local tests + one Cody pass — Cody found 2 holes inside my own diff's blast radius that I'd have shipped as "done").
+
+**Backlog / NEXT CYCLE (scheduled):** the SYSTEMIC fix — wrap all ~23 async routes in an asyncHandler that forwards to a global Express error handler, so an uncaught throw returns a clean 500 AND the request doesn't hang (the unhandledRejection net keeps the server up but the offending request still never responds). This is a review-worthy, Cody-gated change of its own. Plus: the approval-enforcement decision still on Steve's desk; provider-honored idempotency key still live-only.

← 8c3bc3c costa-rica: bound Plaid fetch + fix uncaught-throw/false-ver  ·  back to Costa Rica  ·  costa-rica: wrap all sub-router async routes in an error-for 16c0a2b →