[object Object]

← back to Costa Rica

cycle 9 docs: YOLO_NOTES ledger — admin.js audit, TOCTOU race fix, gated approval decision

0e2af37857c2b790c5066830d793562640bb4d67 · 2026-09-23 20:04:58 -0700 · Steve

Records the routes/admin.js coverage add, the Cody-verified unenforced-approval
finding (with corrected severity: attributed-recipient not paid, since
createPayoutForBooking has zero callers), the directly-fixed TOCTOU
silent-overwrite race, and the gated REQUIRE_HOST_APPROVAL decision memo.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TouFkmUGKHtwqpZwgReVic

Files touched

Diff

commit 0e2af37857c2b790c5066830d793562640bb4d67
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Sep 23 20:04:58 2026 -0700

    cycle 9 docs: YOLO_NOTES ledger — admin.js audit, TOCTOU race fix, gated approval decision
    
    Records the routes/admin.js coverage add, the Cody-verified unenforced-approval
    finding (with corrected severity: attributed-recipient not paid, since
    createPayoutForBooking has zero callers), the directly-fixed TOCTOU
    silent-overwrite race, and the gated REQUIRE_HOST_APPROVAL decision memo.
    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 3cbb6c1..1f2145b 100644
--- a/YOLO_NOTES.md
+++ b/YOLO_NOTES.md
@@ -237,3 +237,23 @@ Canonical apply order now: `004_marketplace → 005_apple → 006_contacts → 0
 **Cost:** $0 (local tests + one Cody pass, which included Cody running its own empirical Node scripts to verify a claim before ruling — not just reading code).
 
 **Backlog:** Provider-honored idempotency key is the only remaining money-path item, live-only (CR-KYC blocked). Safe local money-path work is now genuinely exhausted across 5 cycles. Next cycle pivots to a non-money reversible item — standing UX rules (sort+density, admin created-date) already confirmed compliant in cycle 7, so the search should widen: test coverage gaps, docs, or a fresh Cody-driven codebase audit for a new class of issue.
+
+## /yoloforever CYCLE 9 (2026-09-23, yf-costa) — routes/admin.js audit → found + fixed a TOCTOU race, gated an auth decision
+
+**Pivot:** money-path hardening exhausted → audited `routes/admin.js` (previously ZERO test coverage). Added +7 baseline tests (stats/claims/claim-decision/bookings).
+
+**Finding (Cody-verified end-to-end, grep-confirmed):** the admin **approve/reject** workflow writes `place_hosts.claim_status`, but **nothing on the money path reads it.** `/host/listings` (which sets `place_booking.host_id`, the payout recipient) gates on claim ROW EXISTENCE, not `claim_status='approved'` — so a `pending`/`rejected` host can list + become the attributed recipient with NO admin approval. `/host/apply` + `/host/claim` are zero-check self-serve. `hosts.kyc_status` is also dead (read in zero conditionals).
+
+**Severity — corrected by Cody (I had overstated):** `lib/payouts.js createPayoutForBooking` has **ZERO callers** (no route/cron — grep-confirmed) → money does NOT move yet. Correct framing: the wrong host becomes the **attributed payout recipient of record** (true today), NOT "gets paid" (a real leak only once someone wires the payout function to a trigger — one cron away).
+
+**Cody found a SHARPER, separate bug in the same guard block — the TOCTOU race:** the guard SELECT + the `place_booking` upsert are separate statements, no lock. Two hosts racing the same unlisted place both read `current_host=NULL`, both pass, both upsert — and the old unconditional `ON CONFLICT DO UPDATE SET host_id=EXCLUDED.host_id` let the second **silently overwrite** the first and still return **200** (last-commit-wins; loser never told). 
+
+**SPLIT the two per Cody:**
+1. **TOCTOU race = pure correctness, fixed directly (commit `002feea`, NO gate):** added `WHERE place_booking.host_id = EXCLUDED.host_id OR place_booking.host_id IS NULL` to the DO UPDATE → the single statement is atomic; a racing non-owner matches no row → route returns **409**, not a false 200. Host-deleted (NULL) re-list path preserved. Real-DB test proves the ownership can't be silently overwritten; a route test proves the empty-RETURNING→409.
+2. **Approval enforcement = customer-facing onboarding decision, GATED to Steve:** drafted `~/.claude/yolo-queue/pending-approval/2026-09-23-TK-10346-costa-host-claim-approval-unenforced-DECISION.md` with a pre-written **default-OFF `REQUIRE_HOST_APPROVAL`** flag (so an unattended deploy with no active approver isn't bricked) + APPROVE/REVISE/BLOCK. Not applied — awaits Steve.
+
+**Tests (+12 across the cycle, suite 139 → 151):** admin-routes.test.js (7), host-listing-approval-gap.test.js (3 incl. the race-fix 409), host-listing-race.test.js (2 real-DB atomicity proofs).
+
+**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.

← 002feea costa-rica: fix TOCTOU silent-overwrite race in /host/listin  ·  back to Costa Rica  ·  costa-rica: bound Plaid fetch + fix uncaught-throw/false-ver 8c3bc3c →