These are the things that would make a Monday launch fail on day one, independent of code quality.
| Type | Problem | What actually happens | Evidence |
|---|---|---|---|
| OPS P0 | Invoice intake is silent everywhere | Last invoice email processed anywhere: Jul 30, 8:54 PM UTC. CLLAL has had nothing for 9.2 days (222 hours). The four DFW inboxes (DALDL, DFWCE, DFWXY, DFWXF) were activated Jul 30 and have never received a single email. Either mail routing is broken or nobody is sending; nothing is watching, because the monitor script exists in the repo but is not deployed as a scheduled job. | ap_intake_log; ap_intake_liveness(); scripts/ap-intake-health.mjs present on main, absent from live scripts dir |
| OPS P0 | Posting switch is off, so approvals dead-end | The AP_ALLOW_LIVE_POST secret is not set in the edge runtime (28 secrets checked, none AP related). Every approval will queue forever instead of creating a QuickBooks bill. Exactly 1 bill and 1 payment ($649.50) have ever gone live, on Jul 31, as a pilot. Worse, the approval response claims posting was queued when it never happens, so the UI reports success on a no-op. | Supabase secrets API 2026-08-02; ap_bill_postings; ap-approve/index.ts:904-915 vs ap-post-bill/index.ts:922,997-1002 |
| BUG P0 | Today's perf change hides the portfolio from the AP queue | Reproduced live with one session: at 5:16 PM CT the queue showed all 36 bills across 14 properties. After the 5:17 PM CT deploy of "perf(ap): remove blocking queue round trips", the same login sees only HOURP (11 bills), the property dropdown lists just two options, and the "All properties" label still claims it is showing everything. An accountant would conclude 25 properties have no payables. CLLAL's 13 live bills, including 4 approved and awaiting payment recording, become invisible. | reproduced 2026-08-02 22:16Z vs 22:30Z, same JWT; commit e22b034 resolvePropertyScope refactor in _shared/ap-utils.ts; deploy run completed 22:17:59Z (gh run list) |
| OPS P1 | A real $649.50 check is stuck mid-print | Check run RPP-HOURP-20260731-332773 has sat in status "printing" since Jul 31, 6:50 PM UTC. The QuickBooks BillPayment (9924) already exists, but no check number was recorded and the run was never released or reconciled. If the physical check never printed, QuickBooks says the bill is paid and reality disagrees. | ap_check_runs; ap_qbo_payment_run_payments, qbo_print_status='NeedToPrint' |
| OPS P1 | 31 invoices are aging in human queues | 15 in accounting review (oldest 10.8 days), 12 ready for approval (oldest 12.2 days), 4 approved and waiting on payment recording since Jul 31 ap_invoices, last touch 2026-07-31 21:20 UTC. This is not an error pile, it is throughput near zero. 13 open invoices still need GL codes and 3 need vendor setup (PEPSICO among them, raised Jul 28). Launch week starts with a catch-up, not a clean slate. | ap_invoices status counts 2026-08-02; vendor requests seen live in UI (PEPSICO, 4d old) |
Findings from three independent review passes (backend, frontend, live browser testing), each verified against the actual code with file and line. Severity reflects launch impact.
| Severity | Bug | Failure scenario | Where |
|---|---|---|---|
| Blocker | Double payment race in QBO check runs | Two clicks (double-click, or two tabs) resuming the same payment run can each create a BillPayment in QuickBooks. The database rejects the second bookkeeping write only after both QBO payments exist, leaving one payment invisible to RPP. The bill-posting path already solves this correctly with a compare-and-set; the payment path skipped it. A ten-line fix. | ap-qbo-payment-runs/index.ts:845-877, 654-657; contrast ap-post-bill/index.ts:1132-1148 |
| Blocker | Check-run dialog never resets, second run unreachable | After preparing and mailing one check run, the dialog keeps showing the old completed run forever. Selecting new bills and clicking "Prepare check run" reopens the stale run. Only a full page reload escapes. Breaks the core weekly payment loop on its second use. | ApQboPaymentRunDialog.tsx:119; mounted permanently at ApAccountingLedger.tsx:908-917 |
| High | Approval note leaks onto the wrong bill | A note typed on bill A can silently attach to bill B's audit trail when flipping between bills with next/prev, because the note field is not reset per bill. Wrong data in an approval audit trail during launch week is a trust killer. | ApBillLifecycleDetail.tsx:72; missing key at ApApproval.tsx:993-1006 |
| High | Approve and co-sign failures are silent | If an approval or co-sign is rejected by the backend (for example a version change race), the confirm dialog shows no error at all; the spinner ends and nothing happens. The error renders behind the modal. This is the highest-stakes button in the module failing without feedback. | ApApproval.tsx:524-526; ApConfirmDialog.tsx:19-101 has no error display |
| High | GL coding silently read-only for some accounting logins | Reproduced live: an accounting-role login without per-property AP assignments gets a 403 from the GL accounts lookup, and every GL dropdown renders disabled with no message. The user cannot recode lines and is never told why. At minimum it needs a visible explanation; if such users should be able to code, it is an authorization bug. | reproduced 2026-08-02: rpc/get_ap_coding_accounts returned 403 twice, dropdowns disabled; grant chain in migrations 327/328/332/338 |
| High | Tracked-only payment RPC skips the payment-recorder gate | Any accounting-role user can call the single-payment database function directly and record a tracked-only payment for a property they are not the assigned payment recorder for. The edge function and batch path enforce the narrower capability; the single RPC forgot to. Bookkeeping-only exposure (no money moves), but it violates the stated control contract. | migration 413:235-238 and 447-452 vs edge check in ap-record-non-qbo-payment/index.ts:124-144 |
| Medium | Three AP functions missing from the CI deploy list | ap-vendors, ap-document-rotate, and qbo-ap-backfill are not in the deploy workflow. qbo-ap-backfill runs nightly and feeds the duplicate gate; a stale manual deploy silently weakens duplicate detection. Three one-line additions. | .github/workflows/deploy.yml:103-126; nightly cron in migration 405:191-231 |
| Medium | Malformed email vanishes without a trace | The intake worker has no top-level error handling. An email that fails parsing bounces to the sender but leaves zero record in RPP, so a GM's "I sent it" and RPP's "never saw it" are both true and nobody can prove what happened. | workers/ap-intake/src/index.js:359-360 |
| Medium | Double-submit can duplicate ACH payment records | For non-check payments without a user-entered reference, the auto-generated reference is unique per submission, so the dedupe key can never fire. A double-clicked $100 partial ACH records twice. Checks are safe (check number is the reference). | migration 415:528-534 vs unique key in 413:136 |
| Medium | Blocker codes render as raw jargon | The expected steady-state blockers ("qbo_total_mismatch", "gl_code_missing" and 7 more) are missing from the label map and render as "Qbo total mismatch" style text to accounting staff. The action buttons are plain English; the headline labels are not. | src/lib/apLifecycle.ts:52-80 vs codes emitted in _shared/ap-qbo-posting.ts:391 |
| Medium | Payment dialog wipes typed data on background refresh | Leave the non-QBO payment dialog open 5+ minutes (for example while sending the ACH at the bank), come back, and every typed date, reference, and note resets to defaults. The tracked-check dialog already snapshots correctly; this one does not. | ApNonQboPaymentDialog.tsx:57-74 vs snapshot pattern at ApAccountingLedger.tsx:374 |
| Medium | "Outstanding" number overstates what is owed | The KPI sums full totals for every unpaid lane, ignoring partial payments and including bills still in review that may be rejected. An accounting figure that does not match the checkbook. | ApAccountingLedger.tsx:133-134 vs correct remaining_balance use in ApOperationsLedger.tsx:48-50 |
| Medium | History is hard-wired to the year 2026 | Date filters validate and clamp to 2026 only. On Jan 1, 2027 the history ledger cannot show any new record. A time bomb, not a launch-day issue. | ApApproval.tsx:84, 356-357; ApHistoryLedger.tsx:271-286 |
| Medium | iPad: merge radio looks dead, review loses side-by-side | Below 1280px the duplicate-merge radio appears unselected when tapped (two same-name radio groups fight), and the invoice-vs-PDF compare stacks vertically forcing constant scrolling. The team reviews on iPads; this deserves a deliberate pass. | ApInvoiceDetail.tsx:1109-1114 (radios), :1564 (xl breakpoint), ApInlineDocumentPreview.tsx:85 |
| Low | Smaller items | Stale extraction states have no automatic recovery or monitor; QBO token refresh can strand a rotated token (forces a visible reconnect, fail-closed); shared links to bills outside the current view show a wrong empty state; "Junaid" is hard-coded in vendor-page copy; dead code (unused ApQueueTable, unreachable co-sign branch); history pagination flashes; 20-bill print runs fetch PDFs one at a time. | ap-extract/index.ts:797-815 + scripts/ap-extract-run.mjs:64; qbo-client.ts:73-91; ApApproval.tsx:422; ApVendors.tsx:475,1320; useApApproval.ts:1072-1240 |
Backend review covered all 14 AP edge functions, the shared QBO client, the Cloudflare intake worker, AP migrations 405-433, and the release-gate fixture suite. Frontend review covered both AP pages, all 17 AP components, both hooks, and routing guards. Live testing signed into production as the QA test account (temporarily granted an accounting role, reverted after, change logged below), walked the queue, invoice detail, blocked view, accounting ledger, history, and vendors pages, and captured every failing network call. Database checks were strictly read-only SELECTs against production. No approve, post, or payment action was triggered; one accidental draft line-type edit was reset with the built-in Reset control before ever being submitted, which incidentally proved the correction-versioning guard works.
In order. Items 1-4 are the actual gate; the rest hardens the launch. Effort estimates are engineering judgment, not measurements.
e22b034. Until then, accounting cannot see the portfolio. (hours)ap-intake-health.mjs monitor as a cron with alerting so silence pages someone. The DFW aliases have never processed one email, so their first proof is part of launch. (half a day, mostly verification)AP_ALLOW_LIVE_POST for the QBO hotels, decide manual-post-from-UI as the flow (that is what the code actually does), and fix the response that falsely reports posting was queued. (small, but it is the go-live decision itself)Honest read: once the queue bug is fixed and intake is flowing, this launches well. The daily loop is genuinely fast, the language is mostly human, and the scary parts (paying money twice, posting the wrong total) are protected by real controls. The risks to sentiment are the silent failures and the backlog they inherit on day one.
Will like: a routine single-line invoice is 6 clicks across two people (4 accounting, 2 approver), and the trusted-vendor batch path amortizes to 4 click-path traced through ApInvoiceDetail/ApBillLifecycleDetail by frontend review. Blocked bills say what to do next on the button itself ("Choose duplicate outcome", "Code additional tax GL"). Corrections auto-create a new version that someone else must approve, which protects them. Check printing has stock reservation, a "HOLD: do not sign or mail" banner until verification, and print-then-attest reconciliation. The 2026 history ledger (437 records, page 1 of 5 seen live) with direct QuickBooks links answers "did we already pay this" in seconds.
Will hate: the second check run of the week hitting a dead dialog; an approval failing with zero feedback; typed payment details wiped by a background refresh; developer jargon in blocker headlines; and day one starting with 31 aged invoices, 18 of them past due ap_invoices counts; live UI. Fix list above addresses all of these.
Will like: forwarding an email is the whole intake job, duplicates are caught automatically (5 caught to date, zero false intake failures ever ap_intake_log outcomes: 88 created, 5 duplicate, 4 no_attachment), and their approval screen is two clicks with a typed-total confirmation only over $2,500 ap_policies org_cosign_threshold=2500.
Will hate: "I emailed it and it never showed up." That is exactly the current state: nothing has arrived since Jul 30, and a malformed email leaves no trace to investigate. Until intake is proven live and monitored, do not announce this to GMs; one lost invoice in week one defines the product for them.
Will like: the money controls are real. A bill cannot post unless printed lines plus explicit tax equal the total, enforced independently in the app layer and the database; every posted bill, attachment, and payment is read back from QuickBooks and verified field by field; tracked-only entities (BCS, DFW) are hard-blocked from ever touching QuickBooks; and posting requires a fresh MFA session. One bill and one $649.50 payment went through the full pipeline end to end and reconciled ap_bill_postings readback 2026-07-31; strengths verified by backend review.
Should know: AP development is running hot: three perf commits shipped straight to production this afternoon without review, during this audit, and one of them caused the queue regression. Speed is the house style, but AP is the one module where a bad deploy means missed or double payments. A minimum bar of "reviewed before deploy" for AP-touching commits during launch week is cheap insurance.