Skip to content

fix(api): grade resumes that pdf.js cannot parse - #38

Draft
lautaropaske wants to merge 1 commit into
mainfrom
fix/grade-unparseable-pdf
Draft

lautaropaske wants to merge 1 commit into
mainfrom
fix/grade-unparseable-pdf

Conversation

@lautaropaske

@lautaropaske lautaropaske commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

 /api/grade
   parseResume(pdf)
-    throws → 400 InvalidPDFException         # resume never graded
+    throws → warn, author = undefined, keep going
   generateObject(gemini, raw pdf bytes)      # never used pdf.js
   catch
+    pdf.js failed AND gateway 400 → 400 InvalidPDFException
     gateway 402 | 429 | ≥500 → 503 GradingUnavailable   # unchanged
     else → 500 GradingError                  # incl. a 400 on a PDF that parsed

pdf.js only supplies info.Author for getSysPrompt, which just checks whether the author is "silver". With no author we use the generic prompt.

InvalidPDFException keeps its exact string. candidate-portal's GradeAshbyResumes cron matches on it to store its placeholder C grade.

Evidence

  • Before: a PDF pdf.js rejects (UnknownErrorException: Command token too long: 128, from the cron on Oct 9) → 400, never graded.
    After: the same kind of file (handmade garbled.pdf), POSTed to a local dev server, logs the pdf.js error as a warning and reaches the AI Gateway. There's no key locally, so it stops at GatewayAuthenticationError.
  • Tests: bun tsc clean, vitest 80/80.
    pdf.js throws, model grades     → 200, system prompt = getSysPrompt(undefined)
    pdf.js throws, gateway 400      → 400 InvalidPDFException
    pdf.js parses, gateway 400      → 500 GradingError
    
  • Not verified: the real gateway response for a document Gemini can't read. No local gateway key, and Dash0 has no past example. The check matches on statusCode === 400 rather than a class or message, because the gateway's error classes don't follow the status code (the budget error came back as GatewayInternalServerError with status 402). If Gemini answers unreadable documents with a 5xx instead, those return 503 and the cron retries them.

Merge Danger

Door: two-way

Revert to roll back. Nothing is persisted.

Blast Radius: grading

Files pdf.js rejects now cost a model call and may get a real grade instead of the cron's placeholder C. The cron already skips files with no %PDF- header (candidate-portal #1047), so only files that look like PDFs reach this path.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

pdf.js only supplies the PDF author for the prompt; Gemini reads the raw
bytes itself. A parse failure (e.g. "Command token too long: 128") now logs a
warning, grades with no author, and only answers 400 InvalidPDFException
when the gateway also rejects the document with a 400.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
open-silver Ready Ready Preview Oct 9, 2026 11:36pm UTC

Request Review

This branch was successfully deployed

1 active deployment
Preview — 6c7ad382 Deployed Oct 9, 2026 by vercel[bot]
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