WorkProofBack to the start page

Evidence for judges

WorkProof is for City of Espoo talent events. A professional does a short real task from an Espoo company instead of sending a CV. A named person at the company reads the work without the name, scores it from 1 to 5 on each of the task's skills, writes a reason, and chooses Meet or Not now. The name appears only after the professional accepts. AI drafts tasks; it never scores or ranks a person. Tested: 0 of 79 planted identity details reached a reviewer.

Made for Espoo's talent events for highly educated professionals, where a degree from abroad too often goes unread. Built for the City of Espoo challenge, Junction 2026. Demo data. All people and companies are invented. Numbers checked on 2026-11-14.

0 of 79 planted identity details reached a reviewer. 69 of 72 identity forms hidden in a harder second case set; the 3 misses are another spelling of the author's own name, an employer that is on no list, a third person's name in running text.

Check it in 2 minutes

  1. /try: Do a 2-minute task on a phone and see the blind proof a company would read.
  2. /table: Invite that proof with a two-sentence reason, then accept on the phone: only now the name shows on the big screen.
  3. /city: See the answers each employer still owes, and 0 automated decisions.

Shaped at the Espoo booth

On 13 November we asked City of Espoo staff if a work task could replace the CV. They had thought of something similar "on a smaller scale" and named three risks. Our answers:

  • A company hires only a few. With consent, one proof can reach a second employer with the same core skills (Second look), after 48 hours without an answer or after a Not now.
  • Friction must stay low. No login, no account, no CV. The demo challenges take 10 or 15 minutes. The stated length is capped at 30.
  • AI can do the task. AI is allowed. Two follow-up questions ask about the person's own choices, and the meeting starts from the work.

The challenge in the City of Espoo's words

How can recruitment and matchmaking events organized by City of Espoo help companies and talent relevantly find and connect with each other, despite AI-generated job search materials and AI-assisted recruitment processes are becoming common?
…solutions that help create stronger signal and less noise throughout the process of registering and attending an event…
…automated profiling or automated decision-making about individuals without human involvement should not be a part of the solution.

How WorkProof meets each criterion

CriterionWhat we builtWhere to see itWhere in codeEvidence
Impact & Relevance (45%)Companies register with a short real challenge in one of four formats (Choose, Make, Fix, Read); people answer with work and think aloud while working; a person reviews with known personal details removed and every recorded decision carries a written reason; the city sees each step from challenge taken to scored, invited, talked, follow-up agreed and hired, and the work still waiting on each challenge.
  • src/lib/service/views
  • src/lib/service/decisions.ts
  • src/lib/service/meetings.ts
Flow eval: every step from task to a meeting both sides confirmed passes (evals/flow.eval.ts).
Innovation & User Experience (35%)A task instead of a CV; the blind proof with a slider between what was written and what the company reads; the name shown only after the person accepts; Second look shares a proof with a second employer with the same skills, with consent; a 1-minute guided tour and a Show me demo in each view; a 2-minute task on a phone.
  • src/lib/blind
  • src/lib/matching/second-look.ts
  • src/components/proof/blind-compare.tsx
Story eval: every story stage rebuilds the visitor's own demo event (evals/story.eval.ts); end-to-end run on a 390x844 screen (evals/e2e).
Responsible & Feasible Execution (20%)AI never scores or ranks people: a guard checks every AI output; known personal details are removed by rules before review; every decision needs a registered reviewer name and written feedback (not verified without sign-in); runs with no keys; request limits; Docker build.
  • src/lib/guard
  • src/lib/blind
  • src/app/api/decisions/route.ts
  • src/lib/http/limits.ts
  • Dockerfile
Guard: 70 of 70 planted judging phrases rejected; 575 of 575 text fields of drafted tasks and follow-up questions pass; blind layer: 0 of 79 planted identity strings reach a reviewer; 0 automated decisions.

The brief's recurring pains

Pain named in the briefWhat WorkProof doesWhere in codeEvidence
Companies struggle to describe their needs clearly and early enough.One sentence becomes a task with 3 to 5 core skills; extra wishes are set aside; a person approves it.
  • src/app/company/need-step.tsx
  • src/app/company/draft-step.tsx
  • src/lib/ai/scripted
Task generator eval: 20 of 20 drafts have 3 to 5 core skills; 3 of 3 planted biased wishes set aside.
CVs and messages are generated and analysed with AI, so matching rests on synthetic representations.No CV. The person hands in work, then answers two follow-up questions about their own choices; the meeting starts from the work.
  • src/lib/ai/scripted/follow-ups.ts
  • src/lib/service/submissions.ts
Flow eval: two follow-ups about the answer; follow-ups read only the redacted answer (privacy eval).
Companies are overwhelmed by large volumes of irrelevant approaches.Each proof is work on the company's own task; the queue is in arrival order and holds blind proofs only.
  • src/lib/service/views/queue.ts
Queues in arrival order: yes (no-automated-decisions eval).
Companies assume there are no suitable candidates in the city's pool.The city makes a challenge from a company's job ad, and people do it before the company opens it. In the demo, Kide Silicon's challenge already has 20 pieces of work. The company's home data also counts proofs handed in for tasks that ask for the same skills. Counts only, never a list of people.
  • src/lib/service/views/employer.ts
  • src/components/city/make-challenge.tsx
Unit tests in src/lib/service/views/employer.test.ts.
Matching should not reinforce bias by nationality, language, education or career path.Known names, contacts, places, schools, employers and residence status are removed by rules before review, and some can remain; tasks cannot ask for protected attributes.
  • src/lib/blind
  • src/lib/guard/protected.ts
0 of 79 planted strings reach the reviewer; 54 of 54 and 69 of 72 identity forms hidden.
No automated profiling or automated decision-making about individuals.WorkProof has no automated decision feature: a decision is recorded with a registered reviewer's name, the reviewer's own points for each core skill and a written reason; a guard blocks scores and ranks in AI output; every decision is in the audit log.
  • src/lib/guard/no-judgement.ts
  • src/app/api/decisions/route.ts
  • src/lib/service/decisions.ts
  • src/lib/domain/scoring.ts
70 of 70 planted judging phrases rejected; 0 automated decisions in the audit log.
Few hires per company, and a company may not answer.Nothing forces an answer, so the city sees the answers each employer still owes. After 48 hours without an answer, or after a not now, the proof can go to another employer whose task shares at least 2 core skills, if the person allowed it (Second look).
  • src/lib/matching/second-look.ts
  • src/lib/service/sharing.ts
Flow eval: company B sees the proof through Second look; company C without shared skills cannot.
The city cannot measure whether events lead to meetings.Both sides confirm a meeting took place; the city sees answers given, reply time, meetings confirmed and answers owed per employer.
  • src/lib/service/views/city.ts
  • src/lib/service/views/insights.ts
  • src/app/api/meetings
Flow eval: both sides confirm the meeting; city totals change and show 0 automated decisions.
The event platform may crash when everyone logs in at the start.Work is done over the days before the event, with no login rush; request rate and body size limits.
  • src/lib/http/limits.ts
  • src/lib/service/capacity.ts
  • src/lib/service/views/insights.ts
Privacy eval: the body cap answers HTTP 413 and the rate limit HTTP 429.
International recruitment adds language, permit and relocation questions.Facts the company writes about the job (a work language, a language level, a licence) are kept in fixed forms under "Good to know" on the draft. Each demo company also records its work language, whether Finnish is needed, permit support and relocation help.
  • src/lib/guard/job-facts.ts
  • src/components/proof/company-facts.tsx
  • src/lib/seed/companies.ts
Set for all 10 demo employers (src/lib/seed/companies.ts).
Solutions should minimise personal data processing.No account and no CV; the person's key stays in the browser; accepting shows the name to that company only, and the organiser sees slots and labels, never names; WorkProof stores only the text of a spoken answer.
  • src/lib/client/local.ts
  • src/lib/service/meetings.ts
  • src/lib/voice
0 of 37 public responses carry a talent id; identity hidden until accepted.

Limits

  • Company and city actions have no sign-in. Any caller can act as any company or as the city in the demo; a pilot needs sign-in and ownership checks.
  • Pictures are not analysed. The person confirms that the picture shows only the work, and a reviewer can report one; a reported picture is removed for every reader. Nothing checks what a picture shows automatically.
  • AI-written work is not solved. Our untested assumption: follow-up answers about a person's own choices, and a meeting that starts from the work, make AI-only answers easy to notice. This is not measured yet. The product cannot prove who typed an answer.
  • Impact is not measured yet. Every outcome in the demo is invented data; the first real test is a pilot event.
  • Reviewing takes employer time. A task takes 5 to 30 answers, but reading still takes a person's time.
  • Nothing forces an employer to answer. Every recorded decision needs a written reason, and unanswered work stays visible to the city.
  • The blind layer is rules, not a guarantee. It misses a lowercase name with no cue word, a bare name with no introduction, another person's name, another spelling of the author's name, and part of an employer name that is not on the list. It over-hides a one-word capitalised sign-off and a capitalised value after "name:" outside a code block.
  • Video upload is off in the demo; seed proofs carry sample clips, visitors answer in writing, by voice or with a photo.
  • No ESCO skill ids yet; skills come from the project's own vocabulary.
  • No Tavata or Brella integration. The meeting list exports as a CSV file; nothing connects to an event tool directly.
  • The demo store is in memory, one private copy per visitor, reset after 12 hours.
  • Live AI runs only with an API key; without one the scripted task designer is used.

What the AI does and never does

Does

  • Drafts a task from a company's one-sentence need, with 3 to 5 core skills. A person approves every company task. Practice tasks are generated without approval and go to no company.
  • Writes two follow-up questions about the person's own choices in their answer.
  • Every AI output passes the no-judgement guard; on any failure the scripted designer is used.

Never does

  • Scores, ranks, rates or recommends a person.
  • Receives a person's name or contact field. Text is redacted by the same rules before it reaches a model. The built-in designer runs without any model. Rules can miss some details in free text.
  • Decides Meet or Not now. WorkProof has no automated decision feature; a decision carries a registered reviewer's name and written feedback.
  • Analyses a voice or a face. A spoken answer becomes text in the browser or once on the server, and WorkProof stores only the text.

The guard is in src/lib/guard/no-judgement.ts. WorkProof has no automated decision feature. A decision is recorded with the name of a reviewer registered for the company and a written reason. This demo has no sign-in, so the name is not verified.

Evals

On 2026-11-14: npm test ran 1936 unit tests in 129 files, 1936 passed. npm run eval ran 63 eval tests in 7 files, 63 passed. No API keys are needed for either.

SuiteCheckResultFile
Task generatorDrafts with a title, a brief, 3 to 5 core skills, minutes and a review guide20 of 20 drafts in shapeevals/task-generator.eval.ts
Task generatorPlanted biased wishes set aside (age, native speaker, top university)3 of 3 baited drafts set it asideevals/task-generator.eval.ts
Task generatorPlanted identity strings in published task cards0 planted strings found in 47 published cards from 47 needsevals/task-generator.eval.ts
Blind reviewPlanted identity strings that reached the reviewer payload0 of 79 planted strings foundevals/blind-review.eval.ts
Blind reviewIdentity forms hidden, first case set54 of 54 cases fully hiddenevals/blind-review.eval.ts
Blind reviewIdentity forms hidden, second case set69 of 72 cases fully hidden, 3 known limitsevals/blind-review.eval.ts
No automated decisionsPlanted judging phrases rejected by the guard70 of 70 judging phrases rejectedevals/no-automated-decisions.eval.ts
No automated decisionsNeutral task phrases let through by the guard33 of 33 neutral phrases passedevals/no-automated-decisions.eval.ts
No automated decisionsText fields of drafted tasks and follow-up questions that pass the guard575 of 575 text fields from 32 designer outputs (20 drafts, 12 follow-up sets)evals/no-automated-decisions.eval.ts
No automated decisionsHTTP status of 2 decisions sent without a reviewer or feedback; stored decisions with a named reviewerrefused: HTTP 400 for a decision without a name, HTTP 400 without feedback; 34 stored decisions all namedevals/no-automated-decisions.eval.ts
No automated decisionsAutomated decisions in the city totals and the audit log0 automated decisions; 0 decision audit lines by a non-humanevals/no-automated-decisions.eval.ts
No automated decisionsDecisions signed by software or by a name the company has not registeredrefused: HTTP 400 for "AI bot", HTTP 403 for an unregistered name, HTTP 400 for a bot as reviewer; accepted after the explicit step: HTTP 200evals/no-automated-decisions.eval.ts
Table screenNames, emails and numbers typed on phones that reach the public big screen0 of 10 names, emails and numbers found; extra fields: noneevals/table.eval.ts
Consent and privacyPublic responses that carry a talent id0 of 37 talent ids found in company and city responsesevals/privacy.eval.ts
Consent and privacyHTTP status for 5 bad pictures, then for 2 clean JPEGs; the description runs through the blind layerrefused: HTTP 400, HTTP 400, HTTP 400, HTTP 400, HTTP 400 for EXIF, a /demo path, PNG, video, 1 byte over 300 kB; accepted: HTTP 200 at 300 kB, HTTP 200 cleanevals/privacy.eval.ts
FlowFull API flow from task to a meeting both sides confirmed28 of 28 stepsevals/flow.eval.ts
Demo storyStory stages rebuild the visitor's own demo event6 of 6 stepsevals/story.eval.ts

Try it in 2 minutes

Architecture

One Next.js app. Pages and the JSON API call the service rules. The rules pass work through the blind layer before anyone reads it (rules remove known personal details; some can remain), check every AI output with the guard, and keep each visitor's demo copy in memory.

Browser to Next.js routes to service rules; the service rules use the blind layer, the no-judgement guard and the AI adapter, and read and write the sandbox store.BrowserPhone or laptopNext.js routesPages and src/app/apiService rulessrc/lib/serviceBlind layersrc/lib/blindNo-judgement guardsrc/lib/guardAI adapterScripted, Claude, GeminiSandbox storeOne copy per visitor

Data and privacy

  • No account and no CV. The person's private key is kept in their own browser.
  • Reviewers and AI models read work only after the blind layer: known personal details are removed by rules, and some can remain. Responses to companies and the city carry no talent id.
  • Accepting shows the name and contact to that company only. The organiser sees slots and labels, never names.
  • Second look is off until the person turns it on, and can be withdrawn.
  • Voice is turned into text; WorkProof stores only the text. Pictures are re-encoded in the browser and the server refuses a JPEG that still carries EXIF data.
  • Each visitor's demo copy lives in memory and is dropped after 12 hours.

Synthetic data statement

Every person, company, task, proof and decision in the demo is invented, including Olena Kovalenko and the ten employers of “Espoo Talent Day”. Email addresses use example.org and phone numbers are placeholders. Any likeness to a real person or company is accidental. The seed is in src/lib/seed.

A plain-text summary for language models is at /llms.txt.