All work

Project 02

Aainaआईना

You already know more than you think.

Ninety-one questions and no score at the end. What you get instead is every place your own answers contradict each other, quoted back to you.

An open receipt drawer showing “what this is built on — satisfaction, 30%, from 5 answers”, with the reader’s own words quoted back, beneath a banner explaining reduced mode.
Open any sentence and it shows its working: which dimension, which score, how many answers, and your own words quoted back at you.

A friend sent me one of those relationship quizzes. It told her she was "78% compatible" with someone she had been with for two years. I went looking for where that number comes from and found the answer is: nowhere. In 2017 three researchers threw over a hundred measures at exactly this question across thousands of couples and found that the compatibility part — the bit that is about these two specific people — predicted almost none of the variance. The number on the screen is decoration.

So I built the version that refuses. Aaina will not score you. What it does instead is hold your own answers against each other and show you where they disagree. You say you are allowed to take up space; you also say your needs come after everyone else's. It does not resolve that for you — it puts both sentences next to each other, with the questions they came from, and lets you sit with it.

The hard part was not the psychology. It was stopping the language model from being charming. Ask any model for relationship feedback and it produces horoscope prose that people rate as *more* accurate the moment you tell them it was written for them. So the model in Aaina is not allowed to think. Every number, every contradiction, every verdict is computed in TypeScript first; the model receives a sealed bundle of that evidence and may only write the connective sentences — and any paragraph whose citations do not resolve is thrown away in three separate places on the way to your screen.

Why it was hard

The easy product is a quiz that returns "you are 72% compatible". That number is the industry standard and it is fabricated: Joel, Eastwick and Finkel threw over a hundred measures at dyad-specific compatibility in 2017 and predicted none of the variance. So the problem I set myself was producing a reading that is specific and emotionally weighty while structurally refusing the one claim everybody wants. The second problem is worse. Ask a language model for relationship feedback and it will hand you a horoscope — and the research is blunt about what happens next: the same paragraph is rated as more accurate the instant somebody is told it was written for them personally.

How it actually works

  • The model is not allowed to think. Every number and every contradiction is worked out in ordinary code first; the model only gets to write the joining sentences.

    I made genericness inexpressible rather than discouraged. Every number, contradiction and verdict is computed in TypeScript; the model receives a closed evidence bundle and may only write connective prose.

    1 receipt
    • derive.ts:28One deterministic, fingerprinted function is the sole authority — no component recomputes.
  • A paragraph that cannot point back at your own answers is thrown away three separate times on its way to your screen — once on the server, once in the browser, and once more at the moment of drawing it.

    Any paragraph whose citations do not resolve is discarded in three independent places — in the serverless function, in the client orchestrator, and at the component, which renders nothing for unresolvable evidence.

    2 receipts
    • write.ts:139Server-side allowlist built per request from that reader’s own findings.
    • Claim.tsx:48“A guard that exists in one place is a guard the second call site will bypass.”
  • It writes from the places where you disagree with yourself. You said you are allowed to take up space. You also said your needs come after everyone else’s.

    The report is written from contradictions, not scores — collisions between a person’s own answers, such as rating “I am allowed to take up space” high while rating “my needs come after everyone else’s” low.

    1 receipt
  • Wanting to stay and being unable to leave are not the same feeling, so they get two separate axes. That split is the only reason it can ever say: this is being held together by what leaving would cost.

    I measure Pull and Hold on separate axes, because Rusbult and Martz found that what predicted staying in abusive relationships was investment and poor alternatives — not satisfaction. That separation is what lets the report reach “this is being held in place by what leaving would cost.” Safety is orthogonal and never moves a number.

    2 receipts
    • axes.tsQuality, Pull, Hold and Safety computed independently.
    • sources.tsRusbult, Martz & Agnew 1998 cited with the load it bears.
  • Disagree with something it said, press the cross, and it does not simply grey the line out — it rebuilds everything that was leaning on it.

    Rejecting a claim recomputes the plan. A reader’s ✗ on a finding is treated as new evidence: the finding is dropped and everything leaning on it is rebuilt.

    1 receipt
    • derive.ts:170“A claim the reader has rejected must not still be holding up a verdict three sections later.”
  • Two people can compare answers with no server involved anywhere. Both halves ride inside the link itself, and anything either of you said about safety is physically blocked from travelling.

    Couple mode has no backend at all. Both halves travel in the URL fragment, which is never sent to a server, and every safety answer is hard-blocked from travelling in either direction — with a test that poisons a link and asserts the disclosure comes out missing.

    2 receipts
A page headed “Why there is no compatibility percentage”, citing Joel 2017, Montoya 2008 and Joel 2020.
It devotes a whole chapter to explaining why it will not give you the number you came for.
A report paragraph reading “You are 69% committed to this lasting, and 30% satisfied… here they have separated”, each paragraph tagged with a receipt count.
The writing comes from contradictions between your own answers — not from a score.
A couple-mode section showing a prediction marked correct, then the line “You read them correctly — and the two of you are still 50 points apart”.
Couple mode runs with no server: both halves travel inside the link itself, and safety answers are blocked from travelling at all.
The Aaina landing page headed “You already know more than you think”, with a Company School painting of a green parrot beside it, credited to the Cleveland Museum of Art, and a button reading “Start — two minutes”.
The first screen makes the promise the rest of it has to keep: two minutes, no sign-up, no email, nothing saved to any server of mine. Every painting in it is public-domain Company School or Ragamala work, credited where it sits.

The numbers

183
items in the bank, 145 of them scored
counted from source
receipts
29
measured dimensions
receipts
71
cited sources, each stating what it is load-bearing for
receipts
  • sources.ts:23A registry test fails on any citation that does not resolve, and on any source nothing cites.
74
phrases banned server-side, plus every predictive claim
receipts
27
named published interventions, not advice
receipts
9
test personas — two built to be nearly identical, on purpose
receipts
  • audit.ts:21The transplant problem has to be solved for the hard case, not the obvious one.

The part most people would have skipped

I refused to reproduce copyrighted instruments. Rather than administering published scales verbatim, it names the published construct and its interpretation rules and writes its own item text. MBTI, the Five Love Languages, the Dyadic Adjustment Scale and the HITS screen I considered and rejected in writing, with my reasons recorded.

What it can't do

  • The current version replaced an earlier careless-responding detector I had built; it now surfaces dwell time and answer revisions instead, and says plainly that no self-report assessment is fake-proof.
Built with
  • Vite 8
  • React 19
  • TypeScript
  • Tailwind 4
  • Zustand
  • one serverless function
  • Groq
  • Vitest
  • Playwright

On a phone

All of it, on a 412-pixel phone.

Not a shrunken desktop with a hamburger bolted on — the reading measure, the receipt drawers and the couple-mode comparison all re-set for a thumb. Most people who take this will take it in bed on a phone, so that is the size it was designed at.

  • The Aaina landing screen at phone width, with the headline and the start button stacked above a painting.The door
  • The science chapter at phone width, explaining why there is no compatibility percentage.Why no score
  • The plan screen at phone width, listing what the assessment will do and how long it takes.The plan
  • A generated report at phone width, with paragraphs each tagged by a receipt count.The report
  • The solo self-assessment report at phone width.On your own
  • The couple-mode report at phone width, showing a prediction marked correct.Both of you
  • A receipt drawer open at phone width, quoting the reader’s own answers back with their scores.Open a receipt
  • The jhalak screen at phone width, showing a short early glimpse of the findings.A glimpse

Not one stock image

Every picture in it is a real painting.

Ten of them, all Indian, all CC0, all named — Company School bird studies from Calcutta and Lucknow, a Rajput falcon, Ragamala miniatures from Mewar and Amber. Each one carries its museum and its accession number inside the app, because an uncredited image is the same failure as an uncited sentence. Click any of them to open the museum's own record.

The Antennae Galaxies

Two galaxies colliding — and the collision is what makes the new stars.

Almost none of the stars hit anything. It is the gas clouds that collide, and the shock of it triggers the brightest star formation in our neighbourhood. The interesting thing is never either galaxy on its own.

The Antennae Galaxies · NASA, ESA and the Hubble Heritage Team (STScI/AURA) · CC BY 4.0