Skip to content

fix(check-payer-extraction): tolerate trailing JSON prose, extract branch deposit fronts - #467

Open
Clarion1631 wants to merge 1 commit into
mainfrom
fix/check-payer-extraction-robustness
Open

fix(check-payer-extraction): tolerate trailing JSON prose, extract branch deposit fronts#467
Clarion1631 wants to merge 1 commit into
mainfrom
fix/check-payer-extraction-robustness

Conversation

@Clarion1631

Copy link
Copy Markdown
Owner

Two bugs found in prod today

Only 1 of 18 filed check/deposit images had ever been extracted with a payerName. Investigating found two independent bugs in scripts/extract-check-payers.mjs.

1. parseModelJson threw on trailing text after the JSON object

Gemini's response for bank reference 26236015002403 (a $25,000 cashier's check, payer Christensen) had prose after the closing }. JSON.parse threw SyntaxError: Unexpected non-whitespace character after JSON at position 132, so this image — a $25k check — never got a payerName.

Fix: after fence-stripping, if a straight JSON.parse fails, extract the first balanced top-level {...} object (brace depth tracked with string-literal/escape awareness so a {/} inside a string value can't miscount) and parse that. If no balanced object exists, the original parse error is rethrown — the function stays pure and exported.

2. DEFAULT_KINDS silently skipped DEPOSIT_SLIP

DEFAULT_KINDS was ["CHECK_FRONT", "DEPOSIT_PHOTO"]. But scripts/post-bank-images.mjs (line ~101) assigns the front image of every branch deposit (one with no check number) the kind DEPOSIT_SLIP, not DEPOSIT_PHOTO — for a branch deposit, that front image IS the substitute-check page that names the payer. A default extraction run therefore silently extracted nothing for every branch deposit: exactly the images that carry the payer.

Fix: DEFAULT_KINDS = ["CHECK_FRONT", "DEPOSIT_SLIP", "DEPOSIT_PHOTO"], with the header comment and inline comment updated to explain the post-bank-images pairing. No other behavior changed — privacy scrubbing (scrubField/scrubExtraction) is untouched.

Tests

Added to tests/extract-check-payers.test.ts (existing file, matched its style):

  • trailing prose after the JSON object
  • leading prose before the JSON object
  • fenced (```json) response with trailing text
  • nested braces inside string values (doesn't miscount depth)
  • no-object input still throws
  • DEFAULT_KINDS includes DEPOSIT_SLIP (with a comment on the post-bank-images pairing)

Mutation check: reverted the parseModelJson fallback (back to a bare JSON.parse(text)) and reran — 3 of the new tests failed as expected (trailing prose, fenced+trailing, nested braces), confirming the tests actually exercise the fix. Restored before committing.

Verification

  • npx tsx --test tests/extract-check-payers.test.ts — 38/38 pass
  • npm run test:bank-ledger — 577 pass, 1 pre-existing skip, 0 fail
  • npm run test:unit — 985/985 pass
  • npm run typecheck — clean

🤖 Generated with Claude Code

https://claude.ai/code/session_018k7m2FBp6gsBvwUZ24s3jC

…i JSON and extract branch deposit fronts

Two prod-observed bugs in scripts/extract-check-payers.mjs:

1. parseModelJson threw on a Gemini response that had trailing text after
   the JSON object (SyntaxError: Unexpected non-whitespace character after
   JSON at position 132), so bank reference 26236015002403 (a $25,000
   cashier's check, Christensen) never got a payerName. Fixed by falling
   back to extracting the first balanced top-level {...} object (brace
   depth tracked with string-literal awareness) when a straight JSON.parse
   fails, and rethrowing the original error when no object is found.

2. DEFAULT_KINDS omitted DEPOSIT_SLIP, but scripts/post-bank-images.mjs
   assigns the FRONT image of every branch deposit (no check number) the
   kind DEPOSIT_SLIP — that front image IS the substitute-check page
   carrying the payer's name. A default extraction run therefore silently
   skipped every branch deposit's payer. Fixed by adding DEPOSIT_SLIP to
   DEFAULT_KINDS.

Added unit tests for both (tests/extract-check-payers.test.ts): trailing
prose, leading prose, fenced+trailing text, nested braces in string values,
no-object-input still throws, and DEFAULT_KINDS includes DEPOSIT_SLIP.
Mutation-checked: reverting the parseModelJson fallback fails 3 of the new
tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018k7m2FBp6gsBvwUZ24s3jC
@vercel

vercel Bot commented Sep 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
probuild Ready Ready Preview Sep 3, 2026 9:09pm UTC

Request Review

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

No blocking defects found. The production cases are fixed, DEPOSIT_SLIP classification matches the ingest path, and privacy scrubbing remains intact.

Non-blocking

  • The fallback only tries the first {...} candidate. Braced prose before valid JSON could still cause extraction to fail; scanning subsequent candidates would improve robustness.
  • CI was still running at review time; Vercel had passed.

VERDICT: APPROVE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant