A concept review layer for medicine procurement: AI agents do the work, humans review it, and autonomy is gated on what each act invented, not on confidence.
Impact
- Agent decisions modelled: 13 in the synthetic decision log to 13 of 13, across 8 review shapes
- Prototype surfaces: a decision log, no interface to 17 live routes, no backend, 24 to 27 August 2026
- Spec tasks applied: 193 specified across 3 OpenSpec changes to 182 applied
Summary
A concept review layer for medicine procurement: AI agents do the work, humans review it, and autonomy is gated on what each act invented, not on confidence.
- Role: Product designer, research to prototype
- Team: Solo project. I did the research, design and build, using Claude Opus 5 to produce the documents and the code against my direction.
- Timeline: August 2026, commits from 24 to 27 August
- Domain: Healthcare procurement: AI agent review for a medicine marketplace
- Problem: A reviewer cannot tell an agent that checked from one that guessed. The only signal, confidence, scored the one wrong decision 0.93, and that error had already corrupted a $448,000 award.
My contribution
- Investigated a 13-decision agent log and wrote 17 working documents, from problem map to autonomy matrix.
- Designed the review model: provenance on every field, a three-question autonomy gate and three triggers for catching errors.
- Built a 17-route clickable prototype in Next.js and TypeScript, specifying every surface in OpenSpec before code.
Outcome
- Agent decisions modelled: 13 in the synthetic decision log to 13 of 13, across 8 review shapes
- Prototype surfaces: a decision log, no interface to 17 live routes, no backend, 24 to 27 August 2026
- Spec tasks applied: 193 specified across 3 OpenSpec changes to 182 applied
Key decisions
1. Hide the confidence score and show where each value came from: read, derived or assumed.
Instead of: A confidence column, badge or translated score, the signal the agents already emit.
Because: In the log, the wrong decision scored 0.93 and a glare-damaged photo scored 0.41 and was only hard to read. The reviewer knows pack sizes cold but has no basis to judge a score.
Result: The word confidence appears on no screen. An Inputs column reads 1 assumed on the wrong decision, which a reviewer can check against the document.
2. Gate autonomy on each act with three questions: did you invent an input, who does this land on, what would it cost to undo.
Instead of: Autonomy granted per agent, as the log did, or an authority ladder with spend thresholds.
Because: Per-agent autonomy let a normalisation step invent its divisor and run alone, while a $0 catalogue match waited for a human. No approval hierarchy was ever stated, so a spend ladder would have been an invented org chart.
Result: All 13 records resolve into four verdicts. The bad decision stops because it invented an input, which was knowable at the time.
3. Order the queue by irreversibility, then buyer visibility, then exposure, then age.
Instead of: Sorting by money, the default for a procurement tool.
Because: Sorting by value puts a $448k award that waits until Thursday above a $0 supplier email leaving in twelve minutes.
Result: The console leads with what is about to become permanent. Amount is a filter, never a sort order.
4. Catch the bad decision with three independent triggers that work from the record alone.
Instead of: Reading the log's known_error and how_it_surfaced fields, or relying on a reviewer opening the right record.
Because: Those two fields are the answer key. A design that reads them has been told, not caught anything. Today the error was noticed by accident, two days later.
Result: Two triggers are built. The unread-evidence audit is specified, not built, and labelled that way on screen. Correcting the error re-opens the award it fed.
5. Cut a derived reliability score after it was built.
Instead of: Shipping a ninth console column that scored each decision from checkable facts.
Because: Three independent reviews, told to default to refusing it, all refused. The $448,000 award scored clean on the proposed inputs, so the column would have inverted the queue on the exact case it existed to catch.
Result: Only the one new input survived, as a Rests on column that points at the decision a value came from.
What was unclear at the start
The starting material was one synthetic working day: 13 decisions from seven procurement agents that read supplier documents, match products to a catalogue, normalise prices, check compliance and split awards. One decision was wrong. Nobody had reviewed it, and it had already corrupted a $448,000 award recommendation.
What was open was where the line sits: which acts an agent may take alone, and how a reviewer spots a bad one fast. The log offered confidence scores as the obvious answer. My first move was to test that answer against the data. The wrong decision scored 0.93. A phone photo with glare across the price column scored 0.41 and was merely hard to read.
That narrowed the problem to one sentence: a reviewer cannot tell an agent that checked from an agent that guessed, because confidence is highest in the second case. Autonomy was also granted per agent, not per act, so the error ran unreviewed while a $0 catalogue match waited for a human.
Process
Read the log before designing
I started with the data, not the screens. Reading all 13 records gave six findings, each checkable against the log. Confidence tracks detected ambiguity, not correctness. The reversible flag lies. Exposure sits on the wrong record. Lineage already links decisions and nothing reads it. The agent_question field is empty on exactly the five decisions taken without asking. That absence became a signal.
Define the reviewer, cut the org chart
I defined the reviewer as a procurement operations analyst: deep knowledge of pack sizes, incoterms and lead times, and no basis to judge whether 0.72 is a good score. That asymmetry became the design spine. Writing it down also killed an authority ladder with spend limits. No approval hierarchy was ever given, and designing to an invented one is the failure the product exists to catch.
The reviewer's uneven knowledge, all of it stated as an assumption. Reconstructed from the reviewer definition document.
Gate on the act, not the agent
Fourteen How Might We questions and two Crazy 8s rounds led to the gate: three questions asked of every act. Did it invent an input? Who does it land on? What would it cost to undo? Four verdicts follow: acts alone, acts and tells someone, acts on a hold, or must stop. A first version with four vectors produced mush. The three questions resolved all 13 records.
Explore on artboards, correct against the data
I explored the console on HTML artboards before building. The passes named five row types, retired Confidence and Risk as columns, and replaced them with Inputs, Reach and Undo. Two reversals came from checking the data. An invented reference format gave way to the log's own tender reference. A swap from award to RFQ was undone by counting: award appears four times in the log, RFQ zero.
Make every input legible
Each decision page leads with the verdict, then what changes if it stands, then what it rests on. Every field says whether it was read, derived or assumed, with its source one click away. The reasoning is split in two: why the agent concluded what it did, and what it did not check. Eight review shapes replace one template, because a currency dispute is not a catalogue merge.
Catch the error without the answer key
The log includes fields that mark the wrong decision and describe how it surfaced. I never imported them. Three independent triggers work from the record alone: consequence out of proportion, peer price deviation and unread evidence. The unread-evidence audit is specified, not built, and shown that way on screen. Correcting the error walks the lineage and re-opens the award, which lands as a three-way split, not a dramatic win.
Let the reviewer tailor the agents
A reviewer who can only approve and reject has a workload that grows with the fleet. So autonomy is set per skill, never per agent: the skills are the action types the log shows each agent performing, and each opens on the strictest verdict the gate ever gave it. The orchestrator governs the handoff between agents, where both ends of the failure passed their own gate.
Specify, build, then let review cut
Every surface went through OpenSpec before code: proposal, design, specs, tasks, apply. Each stage of the work had to survive a written artifact before the next inherited it, and that sent work back three times. The biggest cut came after building: three parallel reviews refused a derived reliability score, and I removed it from the console.
Proposal: why → Design: how, and what it will not do → Specs: behaviour as scenarios → Tasks → Apply
Outcome
A live clickable prototype with 17 routes in Next.js and TypeScript, modelling all 13 decisions across 8 review shapes. Nothing calls a model: every behaviour is real UI state or marked specified, not built.
193 tasks specified across 3 OpenSpec changes, 182 applied. The open ones need a conversation with whoever owns the agents.
17 working documents, three of which changed a decision already made.
The prototype makes the argument concrete: a reviewer with no calibration intuition can be given checkable facts instead of a score. It also names the assumption that could break it. The log self-reports an assumed value on 2 of 13 records; I extended that to all 13, and validating it with engineering is the first step.
What I would do differently
- Validate the read versus assumed assumption with whoever owns the extraction agent before building on it. The whole design rests on it, and it is still unchecked.
- Work backwards from real email threads and a real analyst, instead of a reviewer I assumed.
- Scope tighter. The core surfaces carried the argument; the refinement passes, the 17 documents and the write-up ran well past them and could have waited.
What was left out, and why
- Confidence as a visible signal. The reviewer has no calibration intuition. A number they cannot judge is noise.
- An authority ladder or spend cap. No approval hierarchy was ever stated. Inventing one and designing to it is the failure the product exists to catch.
- An assistant that recommends an outcome. Ask about this returns context and history, never a recommendation. A reviewer checking work should not get a second opinion to defer to.
- A live agent anywhere. In a demo about not trusting agents, a faked agent teaches the wrong lesson.
- Specified, not built: the unread-evidence audit, critic coverage across all layers, the herd test, overnight re-derivation and pre-commitment falsifiers.
Open items
- The provenance assumption. Unvalidated and load-bearing. If agents cannot report which values they read and which they supplied, the design needs rebuilding, not tuning.
- Case versus decision as the unit of review. The documents argue for the case; the console lists decisions, with cases as a lens. The build is the better call: a case-level list would hide D-1042 inside a case headlined by the award.
- Tailoring controls. They record a proposal and hold for the session. Nothing else reads them yet, and both screens say so.
What I would do next
- Build the unread-evidence audit. It is the only trigger that catches this class of error without a downstream consequence looking suspicious first.
- Validate the provenance assumption with whoever owns the extraction agent.
- Measure calibration per agent and per field type, and let well-calibrated agents earn a quieter surface.
Highlights
- Hide the confidence score and show where each value came from: read, derived or assumed.
- Gate autonomy on each act with three questions: did you invent an input, who does this land on, what would it cost to undo.
- Order the queue by irreversibility, then buyer visibility, then exposure, then age.
Capabilities
AI product design, Interaction design, Information architecture, Prototyping
Tools
Next.js, TypeScript, Tailwind CSS, React Flow, OpenSpec, Claude