case study · 2026
Fieldwork
Interview prep that can't invent your experience.
- Role
- Solo: product, build and evals
- Year
- 2026
- Resume extraction
- 8 / 8 evals
- Job import
- 7 / 8 evals
- Preparation plan
- 2 / 3 evals
Import a resume into an experience bank you confirm line by line, check each job description against it requirement by requirement, and turn the gaps into a reviewed preparation plan.
- Next.js
- TypeScript
- OpenAI Agents SDK
- Ollama
- Supabase RLS
- Zod

01 / The problem
Interview prep works best when it's grounded in what you've actually done. A model can draft that material quickly, but it also invents ownership, shifts dates and turns a team result into a personal one. Fieldwork makes every one of those interpretations visible and reviewable before it becomes evidence.
02 / How it works
- 01Experience bank. Upload a resume PDF (parsed in the browser) or paste text, inspect the extracted text, then review and confirm each drafted role.
- 02Applications. Import a job from its URL or pasted text; the extracted company, role and description are editable before saving.
- 03Fit analysis. A bounded agent marks each requirement met, partial or gap and links it to the evidence behind it.
- 04Preparation plan. Questions, answer outlines and a schedule built from the gaps, edited and activated by the user.
Storage and inference are independent: browser storage or a Supabase account with row-level security, and a local Ollama model or OpenAI. Every model call has a deadline, makes one attempt and has no paid fallback.
03 / Hard problems
Fetching untrusted job pages safely
The server fetches a public listing on the user's behalf, which is a classic SSRF risk. Every redirect is re-checked, private and reserved addresses are denied, and the validated DNS result is pinned to the socket so a second lookup can't point somewhere else. Bytes, time and redirects are all bounded, and oversized pages are rejected rather than truncated.
Never trusting the model's output
Every response is validated with Zod, and each requirement and evidence ID is checked against the inputs the model was given. The plan schema only accepts link keys that exist. Drafts stay drafts until the user confirms them, so nothing the model invents becomes evidence for the next step.
Retries that can't create duplicates
Confirmations carry stable batch and item IDs. Browser storage validates the whole batch before one write; Supabase inserts it in a transaction with a per-user lock and uniqueness constraints. A failed save keeps the review open, and retrying it never overwrites or duplicates records.
04 / Measured, not assumed
Labelled synthetic cases run against the local model, scored by deterministic checks that CI tests against canned outputs. They're heuristics, so raw outputs are reviewed before a number is quoted.
| Eval | Passed | Median latency |
|---|---|---|
| Resume extraction | 8 of 8 | 3.8 s |
| Job import | 7 of 8 | 6.8 s |
| Preparation plan | 2 of 3 | 37.6 s |
as of nov 2026
The evals found real bugs. Injected text in a job page once set the company to “EvilCorp”; a prompt change plus a field guard now keeps injected values out of the draft. Resume bullets were sometimes split into fake projects; they're now merged back into their role with a warning.
05 / What's next
- Plans for several jobs at once can skip question practice; that case still fails.
- Very tight weekly budgets leave some gaps unscheduled.
- Fit analysis has a 20-case eval for OpenAI that hasn't been run yet.
Want to talk through how it’s built?