Project 07
Uruthiஉறுதி
Every candidate you send, confirmed.
A hiring manager who has never met you, will never log in, and has excellent reasons to doubt you. Ten seconds on a phone to change that.

Here is a problem software usually cannot touch. An Indian staffing agency sends candidates to a hiring manager who has never met them, will never log into the agency's tool, and has excellent reasons to be sceptical — this is a market with fake job postings that harvest résumés and people who send someone else to the interview. The agency says "this person has five years of Java". The manager thinks "sure you do".
You cannot fix that with a nicer dashboard. The only thing that moves it is making the claim checkable by a stranger, on a phone, in ten seconds, without an account. So Uruthi sends one link. On it, every requirement is marked Met, Partial or Not met — and each mark carries the exact line from the résumé it came from. A Met with nothing quoted behind it automatically downgrades itself to unverified. You cannot show a green tick with nothing under it.
Then I stamped it. When a lineup is sent, the app fingerprints exactly what the client will see, and the receipt page recomputes that fingerprint every time it loads — so if anything changed afterwards, the page says so out loud. I am careful about what that does and does not prove: there is no third party and no private key, so it is tamper-evident, not cryptographic. It means the agency cannot *quietly* change a profile after you have seen it. That is the actual problem, and I would rather describe it exactly than dress it up.
The part I am most pleased with is the ranking, because of what it does not have. It sorts candidates and then throws the score away. You get reasons in words — "5 of 5 must-haves in profile", "notice 90 days, cap 30" — and a test that fails if any reason string ever contains the word "score", a percentage or the word "points". Nobody can dismiss it as a black box, because there is no box.
Why it was hard
A hiring manager will never log in to an agency tool, never sign up, and has good reason to distrust what an agency sends — résumé-harvesting fake postings and proxy interviews are a real problem in this market. So the product has to make a claim checkable by a stranger, on a phone, in about ten seconds, with no account. That forces three things at once: a fingerprint over exactly what the client was shown, a consent record that cannot be bypassed, and a ranking with no score in it that anyone could dismiss as a black box. On top of that it handles candidate personal data under India's DPDP Act, so consent, purpose limitation and erasure had to exist on day one rather than be retrofitted.
How it actually works
Every requirement gets a tick, a half tick or a cross — and a tick with nothing quoted underneath it downgrades itself automatically. You cannot show a green tick with nothing behind it.
Every requirement is marked Met, Partial or Not met — and a Met row without a quoted proof line collapses automatically to "unverified". The grid cannot show a green tick with nothing behind it.
1 receipt
- see it liveOpen the sample lineup and read any profile: each must-have carries its status and the résumé line it came from.
The moment a shortlist goes out, the app takes a fingerprint of exactly what the client will see. The page works that fingerprint out again on every single load, so if anything was changed afterwards, the page says so out loud.
When a lineup is sent, the app takes a SHA-256 fingerprint of exactly the fields the client will see — the requirement, the candidate details, the evidence rows, the consent status. The receipt page recomputes that fingerprint on every load and tells you plainly if it no longer matches.
1 receipt
- see it liveThe receipt page prints the full 64-character hash and either "Seal verified on this load" or an explicit mismatch.
Nobody can dismiss this ranking as a black box, because there is no box. A test fails the build if a single reason it gives ever contains the word score, a percentage, or the word points.
The candidate list is ranked without ever showing a score. It sorts internally, then throws the number away and shows only reasons in words — "5 of 5 must-haves in profile", "notice 90 days, cap 30". A test asserts no reason string can ever contain "score", "%" or "points", and anyone with zero must-have hits is dropped from the list rather than displayed as a weak match.
1 receipt
- see it liveThe Find screen shows reason chips and an order, and no number anywhere.
A candidate who has not consented cannot be sent to a client. Not “the button is greyed out” — there is no sequence of clicks in the entire app that gets there.
Consent is enforced inside the state machine, not on a button. The transition from draft to sent is refused outright when consent is absent, so no code path can send an unconsented profile. A candidate who withdraws consent from their own link disappears from the client's lineup and from the export.
1 receipt
- see it liveThe candidate link offers Confirm and Withdraw; withdrawing removes the person from the live lineup.
The AI suggests; a person confirms. Anything not yet confirmed wears a visible “proposed” tag, and the send button stays shut until a human has been through all of it.
An AI proposes the evidence rows; a human ticks every one before anything can be sent. Unconfirmed rows carry a visible "proposed" chip, and the send gate refuses while any remain. With no API key the model layer reports itself as off and the grid is filled in by hand — the app is fully usable either way.
1 receipt
- see it liveEvery AI-touched surface carries a mode badge naming which engine produced it, or that it is off.
You can delete a candidate completely — and it warns you, beforehand, that doing so breaks the seal on every shortlist they ever appeared in. Most tools hide that. It is simply what deleting someone honestly costs.
Erasure is implemented, and its consequence is stated out loud rather than hidden: erasing a candidate breaks the fingerprints on every lineup they appeared in. The interface says so. Breaking a seal is the honest outcome of deleting the thing it described.
1 receipt
- see it liveThe candidate sheet shows the DPDP erase control alongside what it will and will not undo.




The numbers
receipts
- see it liveThe state machine is the spine of the product; every stage change is logged.
receipts
- see it liveSending without consent is refused at the function level.
receipts
- see it livePrinted in full on every receipt page.
receipts
- see it liveEvery screen is captured at 1440px and 390px with no-console-error and no-horizontal-scroll assertions.
receipts
- see it liveMulti-tenant from the first migration rather than bolted on.
receipts
- see it liveFixture mode renders every screen and disables writes behind a visible badge.
The part most people would have skipped
I will not call this cryptographic proof, because it is not. The fingerprint is computed and stored by the agency's own server, so an operator with database access could alter a record and its hash together. What it actually buys you is that the agency cannot *quietly* change a profile after the client has seen it — which is the real-world problem — and the product's copy says exactly that and nothing more. The same discipline runs through the rest: the client link is a bearer token and the documentation calls it one rather than implying authentication, and the trust panel lists named checks instead of awarding a badge, with a test asserting the word "verified" never appears on it.
What it can't do
- The repository is private, so the links here go to the running demo rather than to source. Everything in it is a fictional agency with fictional candidates, and it resets nightly.
- The seal is tamper-evident, not cryptographic proof: no private key, no third-party timestamp. The agency's own server computes and stores it.
- The client link is a bearer credential — whoever holds it can open it. The documentation calls it that rather than implying authentication.
- The model still occasionally grades a row Partial with a proof line that reads as Met, which is why a human confirms every row before anything is sealed.
- No real agency has used it. Every journey has been walked by a test or by me, not by a recruiter, and there are zero real placements behind it.
- Security is at a demo tier by design — no email verification, no two-factor. Before any real agency stores strangers' résumés in it, that needs a proper audit.
- Next.js 16
- React 19
- TypeScript
- Tailwind 4
- Supabase Postgres
- Row-level security
- Server Actions
- Groq (optional)
- Vitest
- Playwright
