One of you is

WRONG

a technical teardown

You record a petty argument. An AI judge decides which one of you is wrong, and says so in character.

This page is the part the App Store listing leaves out: what happens in the thirty seconds between tapping record and hearing the verdict, and the small design decisions that made it cheap, safe, and hard to break.

Trace a verdict Meet the judges
0
judge personas
0ms
backend cold start
3045s
record to verdict
0
servers to patch

No lawyers required. Results in under a minute.

The user sees three steps. Each one hides a piece of the system this page takes apart. Read the small print under each tap.

01

Choose your judge

Pick from 21 personas, from ancient dragons to chronically online teens to passive-aggressive butlers. Each has its own voice and verdict style.

under the hood: each judge is one JSON file. Adding a judge is a data change, not a code change.
02

Record the debate

Both people state their case, interruptions included. The app records one audio file and uploads it with the identity token it already holds.

under the hood: upload once, then poll. The request returns in about 200ms; the slow work runs on a queue.
03

Get the verdict

The judge names who is wrong, flags the rhetorical moves each side used, and on paid tiers reads it aloud and fact-checks the claims.

under the hood: structured JSON, not free text. Techniques, per-speaker scores, verdict line, then voice.

Trace a verdict, stage by stage

The client uploads once, gets a job id back in 202, then polls roughly once a second. Everything slow happens on a queue worker off to the side. Press play, or step through it yourself.

elapsed 0.0s

Structured output, not a paragraph

The judge does not just write a sentence. It returns a verdict line, a per-speaker scorecard, and the rhetorical techniques each side used, repaired into valid JSON before anything trusts it. The app renders that JSON; on paid tiers the verdict is also read aloud.

verdict line per-speaker scores logical fallacies manipulation tactics voice playback
The app verdict screen: who is wrong, who is right, and the reasoning, with audio playback
The verdict and reasoning
The argument scorecard: per-speaker claim, evidence, and engagement scores plus detected logical fallacies and manipulation tactics
The scorecard and detected techniques

Five layers, and most of them are managed

Read it top to bottom. The client holds the product. The edge gives it a domain and a cache. Two Lambdas do the work. State lives in three managed stores. Everything past the first row is somebody else's pager.

layer 01Client
iOS app Swift / SwiftUI SwiftData local history StoreKit 2 subscriptions Sign in with Apple / Google
layer 02Edge
CloudFront api.oneofyouiswrong.com Lambda Function URL no API Gateway
layer 03Compute
Handler Lambda accept + poll + ack Worker Lambda SQS consumer, batch=1 metrics-daily status-watcher
layer 04State
DynamoDB one table: users, jobs, idempotency S3 staging + results SQS FIFO + dead letter queue
layer 05External AI
Deepgram transcribe AssemblyAI fallback xAI Grok verdict Anthropic fallback Perplexity fact check ElevenLabs voice
on device our code (Lambda) managed state third-party model

Every dependency has an answer to one question

If this provider dies right now, does the verdict stop, or ship degraded? Each external call has a decided answer, a fallback where one actually helps, and a place to land when it does not.

Every outbound call sits behind a circuit breaker and exponential backoff, so one slow provider cannot stall the rest.

The backend is mostly defined by what is not in it

An earlier version had a VPC, Aurora, API Gateway, Cognito, and a web frontend. Every one of them got cut, and each cut was written down with the number that justified it. That habit is the point: a deletion you can defend with a figure ages better than a service you kept out of caution.

Six decisions that travel to other projects

None of these are specific to judging arguments. Each started as an annoying edge case and turned into a small rule. Tap a card for the mechanism and the payoff.

The argument is the prompt, so the argument is the attack surface

Whatever two people say gets transcribed and handed to a model. Someone will eventually try to talk the judge into ignoring its instructions. A working copy of the input-safety gates runs right here in your browser. Type a fake transcript and watch which gate stops it.

Every request also hides a one-time marker, for example [INTERNAL-a1b2c3d4], in the system prompt. If that string ever shows up in the model's answer, the injection worked, and the verdict is thrown away before anyone sees it.

Clean transcript. This would proceed to the judge model.

Meet your judges

Every judge is a JSON file: a system prompt, a voice id, tone settings, catchphrases, and the tier that unlocks it. The pipeline treats them all the same. Filter by the tier a judge unlocks at.

Verification you can trust because it is honest about its gaps

A two-person app lives or dies on whether the two clients behave the same and whether the pipeline can be tested without spending real money on real models. The process is built around those two facts.

cross-platform parity

One app is the source of truth, the other is graded against it

A test rig drives iOS and Android through the same scripted flows and captures three views of every step: a screenshot, the accessibility tree, and the network transcript. A later phase scores how far the target drifts from the reference.

  • Record once, replay paired. Backend responses are recorded to committed cassettes so both platforms replay byte-identical answers.
  • Anti-gaming by ownership. The agent that edits an app may not edit the scorer, the labels, or the cassettes in the same change.
cost-bounded tests

The expensive part is mocked, on purpose

Transcription, judging, fact check, and voice are all paid per call. Tests run against recorded responses, and the few live runs are capped so a single end-to-end verdict stays well under a fixed cent budget.

  • Golden masters are committed. A response that changes is a reviewable diff, not a flaky test.
  • Live smoke stays small. One paired live run confirms the contract still holds against the real services.
CI that knows what it cannot check

Path-filtered, and loud about the gaps

Android CI runs only when a pull request touches Android paths. An iOS-only or test-only change triggers zero Android jobs, by design. The team treats a check that did not run as expected, not as missing.

  • iOS has no CI. A local Xcode build is the only gate, so it runs before every iOS change ships.
  • Android needs JDK 21. A local build on the wrong JDK is a tooling mismatch, never reported as a code failure.
working rule

Run the check before claiming the tool is missing

The standing instruction for anyone working in the repo, human or agent: do not state that a tool or environment is unavailable until you have run the command. Verified build and test commands live in the repo guide so nobody guesses.

  • Secrets stay in Parameter Store. API keys are never in code; the worker reads them at runtime and caches them.
  • Failures retry, then quarantine. A bad job retries three times on the queue, then lands in a dead letter queue that pages on depth over zero.