Command: cat projects/exam-radar.md
Exam intelligence that shows its math
My own internal tool for deciding which civil-service exam is worth producing material for: it ranks exams by a score made of five parts, extracts each exam board's pattern from past exams and estimates what is likely to be asked, always with the math written next to the number. It runs on a single machine, with the database in one file. It is a working prototype, with no business results to show.
open the demoa simulation of the system with fictional data · 5 screens
- Role
- Sole author, from product to tests
- Period
- Aug 2026 – present
- What I did
Me: Product, architecture, data model, the score formula, the incidence engine and how it is blended with the model's estimate, the human approval gate, the screens, the tests and the CI.
Private project, described without identifying the client, product or company.
Diagram
The inputs are pasted text of exam notices and past exams and a research manifest checked by a contract. The Next.js app runs on localhost only, with no login and SQLite in one file. Inside it are an incidence engine made of plain arithmetic, a score with explainable parts and a provider router per task; the router calls free providers, a local model and the paid one, which has a cap. The estimate combines what the model proposes with what the arithmetic checks and writes the math next to the number, and generated material becomes input only after the human gate approves it.
Context
Before writing a single lesson, you have to decide which exam is worth producing for, and what to study first within it. That decision usually comes from gut feeling and lists of hot topics with no source. This tool prepares it for the study platform, in a way that can be checked.
What I built
- Opportunity radar. It imports reviewed research, with official sources, dates, confidence and eligibility, and ranks exams by a score from 0 to 100 made of five parts, each shown next to its maximum.
- Archive and board pattern. Past exams pasted as text become questions classified by subject and topic. On top of them, a pure-arithmetic engine computes frequency and trend and builds each exam board’s pattern: how it writes a question, the traps it repeats and what it asks most.
- What is likely to be asked. With the exam notice pasted in, the language model proposes topics and probabilities. The notice gate zeroes anything that is not in the text, the historical baseline corrects the estimate, and the justification writes out the math, citing the questions used as evidence.
- Cost in plain sight. Ready providers, calls, failures, tokens, latency and the day’s spend are on one screen, along with the paid provider’s cap.
- A human gate. Generated material starts as “to review” and only becomes input after an approval with confirmation.
Status
A working prototype for internal use, running on one machine. There are no business results and no measure of how accurate the predictions are: the tool shows where every number comes from and does not promise what will be on the exam.
What I would do differently
I would write the self-test for the formulas before the screens. It was the self-test that exposed score parts that did not add up, and a setup script that never created the database went unnoticed for six days.
Constraints
- Zero budget for daily use, with free providers, a local model and the paid one behind a cap.
- One person and one machine, with no server to run.
- No number without an explanation. Every estimate shows where it came from.
- Input is pasted text from exam notices and past exams, with no scraping.
- Nothing generated becomes product material until a person approves it.
Decisions
One SQLite file, no login, local machine only
- Context
- The tool serves one person, who decides what to produce. A server with accounts and a managed database would be cost and attack surface with nobody to serve.
- Choice
- SQLite in a file, an app reachable only on the local address and no login, as a recorded decision.
- Gains
- Nothing is exposed to the network, and a backup is copying one file.
- No infrastructure to run.
- Costs
- Opening it to another person would take authentication and a different database.
The model proposes, arithmetic checks
- Context
- Asking a language model what will be on the exam returns confident numbers with no evidence behind them.
- Choice
- An incidence engine that is pure arithmetic (recency weighting with a four-year half-life, a linear-regression trend and shrinkage toward the middle when the sample is small). The final probability blends the model's estimate with that baseline, and the history's weight grows with the archive, up to 60% with six past exams or more. A topic that is not in the exam notice is set to zero.
- Gains
- Every number can be recomputed by hand from the written justification.
- A small sample pulls the estimate toward the middle, not toward 99%.
- Costs
- Predictions sound less confident and are only worth something with an archive of past exams.
An explainable score, kept apart from source confidence
- Context
- A single opportunity number hid how it was built, and a missing data point dragged the score down without warning.
- Choice
- Five parts, each shown with its maximum (audience, money, urgency, search and room), a declared floor for missing data, and source confidence and eligibility shown separately. The screen says that no number there is a probability of sales.
- Gains
- You can disagree with one part without throwing the rest away.
- The self-test checks that the parts add up to the total.
- Costs
- The weights are still my judgment, only now it is visible.
A provider router with a spending cap
- Context
- Free providers hit rate limits, go down and return malformed JSON, and the paid one must never turn into a surprise bill.
- Choice
- A queue per task across five providers. Rate limits, server errors and timeouts move on to the next one; credential errors do not. The paid provider only joins with a daily cap above zero, and every attempt is recorded with tokens, cost and latency.
- Gains
- Daily use costs nothing, and the cost is shown on screen.
- One provider going down does not stop the work.
- Costs
- Answer quality varies with whichever provider answered.
Stack and why
- Next.js 15 and React 19
- Eleven server-rendered screens, with no separate API to maintain.
- TypeScript
- Types from the database to the screen in the formulas that change numbers.
- Prisma with SQLite
- A database in one file, with migrations and 13 models.
- zod
- The contract for the imported research manifest.
- Tailwind CSS
- A dark theme with checked contrast on labels and the main button.
- GitHub Actions
- Dependency audit, logic checks, type-checking and build on every push.
Results
11 screens in 8 modules, 13 data models and about 6.2k lines of TypeScript.
audited private repositoryRepository count(Audit of the private repository, Sep 2026)CI with a dependency audit, a dedicated database, logic checks, type-checking and build, with actions pinned by SHA.
audited private repositoryThe repository's workflow(Audit of the private repository, Sep 2026)140 assertions on the pure logic, with no API key and no internet. The self-test caught six bugs that changed numbers on screen, including score parts that did not add up to the total in 22.9% of cases.
self-reportedThe project's test log
Security angle
Attack surface
- Pasted text from exam notices and past exams, which goes on to the language model.
- The imported research manifest, with links to sources.
- Provider keys stored on the machine.
Controls in place
- The app listens only on the local address and the database is a file, with nothing exposed to the network.
- The manifest is validated against a versioned contract, with size and candidate limits and only official HTTPS links.
- An import is written in a single transaction, and repeating it creates or changes nothing.
- The import neither calls a model nor opens the links it receives.
- The paid provider only runs under a daily cap, and every call is recorded with its cost.
- Generated material starts unapproved and only becomes input after an approval with confirmation.
What I would test today
- A malicious instruction hidden in the pasted text of an exam notice or a past exam.
- The app binding to every interface by mistake and becoming reachable from the local network.
- Concurrent calls blowing through the paid provider's daily cap.
Evidence
- audited private repositoryAudited private repository(Audit of the private repository, Sep 2026)