fix(clio-probes): review wave - write-probe boundary, rail verdicts, coverage
Independent review of the probe runner: one Critical, three Important, six minors. All applied. CRITICAL - the write probe escaped its own boundary. The billed sub-probe took its candidate from probe 9, which runs against an ARBITRARY live matter (probe 2's first row or --matter-id), not CLIO_PROBE_TEST_MATTER_ID - so the "no-op" PATCH would have landed on a real client's invoiced time entry, contradicting the file's own promise. Worse, a null/withheld note degraded to "", so the no-op could have BLANKED a note on an invoiced record. The sub-probe now runs its own search on the test matter, restricted to the caller's own entries, and skips with an UNANSWERED verdict unless the note is readable (also skips when the caller's Clio user id is unknown, rather than widening to colleagues'). IMPORTANT - inner catches swallowed the safety rails. Probe 3 scored ANY failure as "pass"; probes 6/8 absorbed a blocked DB write or a rate-limit abort into `controlRejected` and carried on issuing requests. Every inner catch now calls rethrowRailErrors first, and probe 3's non-400 branch is "inconclusive" - only an outright rejection answers open question 1. IMPORTANT - the "never initiates OAuth" claim was imprecise: a 401 can still make the shipped client attempt one refresh-token exchange before the (blocked) persist. Reworded to say what is actually true - no authorisation flow ever, and the stored row is never rewritten. client.ts deliberately untouched. IMPORTANT - probe 2 now also exercises the list `query=` search and `status=` filter, the exact surface #71 rebuilt and the one part of the Matters header that had never been called live. Minors: cleanup DELETE sleeps once and retries a single time past a drained rate-limit window (what it is deleting is live data); a billed-edit refusal counts only 401/403/409/422, so a 500 no longer reads as "Clio refuses"; `npm run typecheck:scripts` added to the backend CI job; the readOnlyDb proxy inverted to an ALLOW-list (only a wrapped `from`) after the reviewer showed `schema().from().update()` walks past a deny-list; the contacts selector hoisted into an exported CONTACT_SEARCH_FIELDS in manageTools.ts so the probe tests the shipped string, not a copy; matter-id bound tightened to 15 digits. Also fixed en route: a preflight failure printed "Unknown error" because Supabase rejects with a plain object, not an Error. Verified: tsc --noEmit clean; tsc -p tsconfig.scripts.json --noEmit clean; prettier clean; full backend suite 888 passed / 50 files; --dry-run walks all ten probes; all four refusal paths plus the missing-env path refuse correctly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| Repository | Sloth-ninja/JessicaOSS |
|---|---|
| Author | sloth-ninja <ezanahaddis@gmail.com> |
| Authored | |
| Committed | |
| Parents | aa97f630 |
| Stats | 3 files changed , +264 , -71 |
| Part of | Guard-railed Clio live-probe runner |
Capture this commit into my fork
Download a Markdown prompt that tells Claude how to port this
exact commit into your working tree. Run it via
claude -p < capture-commit-fd29a7b5.md
from inside the repo you want the change in.