What's real, what's mocked, and what we can't do
One of the things this competition is judged on is honesty. It is also the cheapest thing in the world to get right, so here is everything, including the parts that make us look worse.
Real and working
- The landing experience you just came from, in 13 languages: server-rendered static HTML, no framework, no images, no webfont, no external stylesheet. Every locale is one HTTP request under 26 KB gzipped. The only script is 1.5 KB that adds the Listen button to the page itself.
- The 80-reason rejection catalogue, written from published EPFO circulars, each reason with a worked before/after example of what the record actually looks like. 61 of them are enforced by the engine; 20 are quarantined and listed as gaps, because a rule we cannot cite is a rule we will not run.
- Read-aloud in all 13 languages. A spoken summary per language is pre-rendered to an audio file and fetched only when you tap Listen, so it costs nothing until you want it. Sections further down the page use your phone's own voice where it has one.
- The name-reconciliation logic as a set of named, explainable transformations.
- Reading documents with a vision model, measured rather than claimed. A photograph of an Aadhaar card, a PAN card or a passbook is read into structured fields by
gemini-3.5-flash, and those fields go into the same engine as everything else. Measured against the kit's own ground truth — we generated the documents, so we know exactly what is printed on them — across crisp scans, simulated phone photos (rotated, dim, JPEG-compressed) and badly underexposed images: 126 of 126 fields read exactly, no invented values. Run it yourself withnode scripts/read-accuracy.mjs. - Documents generated on demand, not precomputed. A specimen has always been a pure function of the case and its seed, which is how the build writes 147 of them deterministically. The studio calls the same functions per request — a document is drawn in well under a millisecond and is byte-identical to the one the build produced, which CI asserts. The 42 templates are discovered by introspection rather than listed, so a template cannot exist and be invisible.
- The division of labour that makes that safe. The model reads; it never decides. It is never shown a rule, never asked whether a claim will succeed, and never sees a verdict. Every field it returns carries its own confidence, anything below 0.75 becomes unknown rather than a value, and a field a document cannot physically carry is refused however confidently it comes back. An Aadhaar card does not print a parent's name, so a parent's name from one is an invention — and the check for that is a whitelist, not a prompt.
- The build refuses to ship: it fails if any locale exceeds its byte budget, if the script grows past 1.8 KB, or if a locale is missing text. A separate check drives a real browser at five screen sizes and fails on horizontal overflow, an unnamed landmark, a tap target under 44 px, a dead link, or a page that renders in the wrong script.
How the 13 languages were made, exactly
English is the source. Every word of it is written by hand.
The other twelve are machine translation, produced by gemini-3.5-flash from the English source. No native speaker has reviewed them. Every one of those twelve pages says so in a banner at the top, before you read anything else, because a confidently wrong sentence about someone's money is worse than an admitted gap.
Two things are protected from the translator on purpose:
- Record values are never translated. Names, dates, IFSC codes and account numbers are held back and written through byte-for-byte. The entire argument of this site is that two records differ by a character, so a translated name would destroy the very thing being shown.
- Digits stay Western. 13 is 13 in every locale, never redrawn in the local numeral set, so a figure never changes shape between languages.
A checker re-reads all twelve locales and fails on script contamination (the translator once spliced Devanagari into the middle of a Tamil sentence, which is invisible unless you read Tamil), on native numerals, on an altered record value, and on any string left in English. It repairs only the broken strings rather than re-running a whole language.
The audio was generated once by gemini-3.1-flash-tts-preview from the translated text and encoded to Opus and AAC. It is a fixed file, not a live call: nothing is sent anywhere when you press Listen.
Specified but not yet built
Five entries have been removed from this list because they became false, which on this page is the worst kind of stale. On 2026-08-19: the rule engine runs with a test suite, and the journey's three main screens are built. On 2026-08-20: the packet's hash and QR code, the statutory clock, and the upload button. They are named here rather than quietly deleted.
- Voice input: speaking your answers instead of typing them.
- The statutory clock has no scheduler. The four-rung ladder, the periods, the breach arithmetic and the escalation letter it drafts are built and tested. What is mocked is reconciliation: it runs over an in-memory list when asked, so nothing keeps ticking once the process stops. A cron would be a deployment, not a function.
- Upload works, but only where there is a server. /start takes photos, scans and PDFs, identifies each one, reads it and computes what is still missing — and it does that by posting to a process that holds an API key. The 8 worked examples and every other screen are static files that need no key and no network, which is what makes them work on 2G and with the network off. So the upload is real and the offline property is real, and they are not the same page on purpose.
- Getting the EPFO side of the Mirror from a photograph. It cannot be done, and this is a limit rather than a gap. A Mirror compares your documents against what EPFO holds, and no picture of your own papers can tell you what is in somebody else's database. Half of every comparison needs the record itself. Kosh names those fields as unavailable instead of inferring them.
- Read-aloud of the full page in every language. What ships is a spoken summary per language plus device-voice narration for each section; most phones have no voice for most Indian languages, so on those phones the section buttons do not appear rather than appear and do nothing.
- Native-speaker review of the twelve machine-translated languages. This is the most important thing still missing.
- Picture-first mode for non-readers.
- The operator console and the aggregate view.
Mocked on purpose, and how
| Thing | How it's faked |
|---|---|
| OTP | Fixed 123456, printed on the screen that asks for it. |
| Government records | Three synthetic personas in a local file. No live system is ever contacted. |
| Aadhaar / PAN | Deliberately invalid, never Verhoeff-valid, shown only as masked tokens. |
| e-Sign | Not implemented at all. |
| Filing and grievances | Dry-run only. The payload is displayed; nothing is transmitted. |
Languages
English is written by hand and is the source every other locale is translated from. The other twelve are machine translation and no native speaker has reviewed any of them, including Hindi, so all twelve carry the unreviewed banner. One string, the hero paragraph, has since been hand-edited in all thirteen; that is recorded per locale in _meta.handEdited.
Things we cannot fix, and won't pretend to
- An employer who has ceased to exist. We route you to the field-office alternative, but we cannot make a dead company sign anything.
- A genuinely ineligible claim. If a rule says no, Kosh says no.
- An employer who never deposited your contributions. That is labour enforcement, not a data problem.
- Accessibility beyond automated checks. Full validation needs testing with real assistive technology and expert review, and we have not done that.
An open question we closed
This section used to say that two of our sources disagreed on the parameter numbering in the Joint Declaration SOP, and that no generated form would carry a parameter number until we had read the primary circular ourselves. We have now read it: SOP No. JD/2024/1 Version 2.0, which sets out eleven parameters, with nationality at 10 and Aadhaar at 11. It also settles the documentary requirement, two documents for a minor correction and three for a major one, which corrected two of our rules that were asking for too few.
The reason it had gone unread is duller than it sounds: the document is a PDF, and the tool we fetch pages with refuses PDFs. Reading it took a command-line download and a text extractor. Worth recording, because "we could not get the source" turned out to mean "we had not tried hard enough", and that is the more common version of the problem.