A synthesis that checks its own work.
AI can turn fifteen interview transcripts into findings in minutes. It also invents quotes, overstates confidence, and hides what it dropped. Motif is an agentic loop that produces the findings, then tries to knock them down — and shows you what survived. I designed the loop, built it, measured it against a human baseline, and shipped it.
Consent given today cannot promise what happens to data years from now
Researchers across disciplines flag that one-time consent cannot capture unknown future uses of archived qualitative data, and argue for ongoing or dynamic consent mechanisms rather than a single sign-off.
- confidence
- high 4 participants · no counter-evidence
- sources
- jamie · jim · kelly · michelle
- opportunity
- Template consent language and a process for periodic re-contact or withdrawal after embargo, rather than treating initial consent as a permanent, one-off decision.
Research synthesis is the slowest step in discovery and the one AI does worst: fast, fluent, and unaccountable. A design team can’t act on a finding whose evidence it can’t check.
A loop, not a prompt. Synthesis produces; a critic with readable rules checks against the transcripts; revision repairs; the loop stops on a pass, on no progress, or after three rounds — and the report says which.
Fast, fluent, and unaccountable
After a round of interviews, someone reads everything, codes it, clusters it, and writes findings. It takes days. Single-prompt AI does it in minutes and produces something that looks like the same document — with quotes that don’t exist, patterns built from one person, “high confidence” resting on two, and the dissenting participant quietly dropped.
The tools that sell this step — Dovetail, Notably, FigJam AI — compete on speed. None of them visibly verify a citation, run an adversarial check, or tell you what the reviewer still objected to.
A finding a designer can’t trace is a finding they can’t act on. The output has to carry its own evidence, name its own confidence honestly, and show its own dissent. That’s a design brief for the shape of the output, before it’s an engineering brief for the thing that makes it.
The product is trust in the output, not speed of producing it.
A loop is agentic when it can tell it’s wrong
A chain is a fixed sequence of prompts. A node graph is a pipeline a human wired. Neither checks itself. A loop is agentic when the model plans, acts, evaluates its own output against criteria it can read, and decides when to stop. The critic and the stop condition are what make Motif a loop rather than a chain.
- 01No hidden judgementEvery rule the critic applies is a paragraph of plain language in a config file a team can edit.
- 02No silent approvalA critic that returns nothing fails the check. This rule was learned, not designed — section 05.
- 03No deletion as repairAn insight the critic objects to is fixed or downgraded, never quietly removed.
Before the tool, the answer key
Fifteen real interviews from a University of Sheffield study of researchers’ attitudes to open data — ethically cleared, CC-BY-NC, public. Before any code, I hand-synthesised five of them the way I would at work: 74 evidence items, 11 insights, each with cited evidence, sources, confidence, counter-evidence, and an opportunity. Two hours fifty. Then I read the researchers’ own report from all fifteen.
- 01Nine of my eleven matched theirsA five-transcript pass validated against the full corpus.
- 02Five themes lived in transcripts I hadn’t readCopyright, political economy, the arts vocabulary gap, DMP templates. A full-corpus run has to find those.
- 03Twelve trapsPlaces the corpus invites a bad synthesis: one private-sector voice, one dissenter on deletion, a concept the researchers introduced that the participants didn’t.
- 04The codebook didn’t existThe dataset readme promised one; it was never deposited. Ground truth was built from the report plus the manual pass instead.
| id | theme | found by |
|---|---|---|
| T-01 | Context doesn't travel | both |
| T-02 | Process transparency is the tractable half | both |
| T-03 | Consent to an unknowable future | both |
| T-04 | Anonymisation: costly, never complete | both |
| T-05 | Awareness low; navigation is the barrier | both |
| T-06 | Reproducibility framing rejected | both |
| T-08 | Reuse is aspirational, not practised | both |
| T-10 | Openness is externally driven | Eric only |
| T-11 | Deletion experienced as waste | Eric only |
| T-12 | Political economy, extraction, scooping | report only |
| T-13 | Copyright and ownership unclear | report only |
| T-14 | 'Data' vocabulary doesn't fit the arts | report only |
| id | trap | fail | pass |
|---|---|---|---|
| P-01 | Penni is the only private-sector voice | state as pattern | single-source, low |
| P-02 | Michelle: deletion is integrity, not waste | T-11 with no counter | surface the dissent |
| P-03 | Penni wants qual more like validated quant | unanimous rejection | surface Penni |
| P-08 | 'Re-renderability' is the researchers' term | participants said it | attribute to authors |
| P-10 | Bruce re-coded his own data | 'nobody reuses' | reuse vs reanalysis |
| P-12 | T-01 and T-04 are different findings | one merged insight | two, cross-referenced |
Four roles, two kinds of rule, one unit of evidence
Intake reads one transcript and maps its topics with turn references. Synthesis reads all of them and writes eight to fourteen insights. The critic reads the insights, the exact text of every cited turn, and the full transcripts, and reports failures against the rules. Revision repairs. A controller runs check → revise until the critic passes, the failures stop changing, or three rounds are up.
Every transcript is split into numbered turns — michelle:0028 — and a turn ID is the only thing an insight may cite. That makes “unsupported” a check, not a vibe: the critic is handed the literal text behind every citation.
- 01Deterministic, in codeThe cited turn exists; the speaker is a participant, not the interviewer; the verbatim receipt appears in the turn; confidence matches the source count — high needs four participants and no counter-evidence. Free, instant, can’t hallucinate.
- 02Model-judgedThe turn supports the claim as stated; a dissenting participant is missing; two findings are merged; a theme present in three or more transcripts has no insight. The critic reads for these.
A rule the fixer can’t satisfy is a bug in the rule. Anything you can compute, don’t ask the model for.
The loop approved things nobody had checked
The critic spent its whole output budget thinking and returned no verdict. My fallback treated “no failures found” as a pass. The loop declared the synthesis clean; no one had read it.
The synthesis hit its output cap and returned nothing. The critic looked at an empty list, found nothing wrong with nothing, and passed in five seconds. The loop approved an empty report.
A deterministic rule flagged “sources without cited turns” three rounds running. The model counted counter-evidence participants as sources; my rule didn’t. Three rounds arguing about a definition neither side could see.
- 01Silence failsA critic with no verdict, a synthesis with no insights, an empty list — all hard failures. Every layer.
- 02ReceiptsEach citation carries a verbatim quote, checked against the transcript in code. Deterministic failures on round one went from three to zero. The synthesis writes more carefully when it knows the check exists.
- 03Confidence is arithmetic“Overconfident” was whack-a-mole until the threshold was a number in the config.
- 04Sources are computedNot asked for.
A checker’s absence must never read as approval.
Precision up, coverage down
Three conditions on the same five transcripts, three runs each: single prompt, intake plus synthesis, full loop. Nine reports anonymised, headers and critic flags stripped, scored against the ground truth — theme coverage, trap failures, four evidence spot-checks per report, confidence calibration. AI-assisted rating reviewed by me.
- 01Unsupported claims halved1.7 to 0.7 per four checked.
- 02Confidence errors went to zeroThe numeric threshold did that, not the model.
- 03Trap failures fell2.3 to 1.3.
- 04Coverage dropped eighteen points75% to 57%. Reuse, a core theme, was absent from every loop run and present in five of six others.
- 05Intake alone changed nothingThe map isn’t the value; the checking is.
The critic only checked what was on the page. The reviser’s cheapest fix for an objection was to delete the insight. Nothing in the loop watched for what went missing.
Teach the critic to look at the corpus
- 01A recall ruleThe critic now receives the intake topic maps and must flag any topic present in three or more transcripts with no insight covering it. The intake step, which had made no measurable difference, became the input to the check that recovered coverage.
- 02No silent deletionThe reviser must list anything it drops, with a reason; a vanished insight without one is a failure.
- 03Profiles for the criticSector, career stage, method — with an instruction to look hardest at the outlier.
- 01Coverage recovered51% to 69%, against 75% for a single prompt.
- 02Reuse went from 0 of 3 runs to 3 of 3The recall rule, doing exactly what it was built for.
- 03Precision heldUnsupported claims unchanged at 0.7; confidence errors 0.7.
- 04Nothing was silently deletedIn three runs.
- 05The best single report of any condition in either evalNine of twelve themes, zero unsupported, zero miscalibrated.
What the critic actually catches
Round one cited Bruce with a real quote from bruce:0035. The receipt check passed: the words exist. The critic failed it: read whole, the turn says the opposite. Selective quotation, caught by a reader, not a regex. One revision fixed it.
I-01 Decontextualised reuse is epistemically risky
- confidence
- high
- evidence
- michelle:0028 · stephen:0022 · bruce:0035
- counter
- david:0040
missing_counterexample — Bruce's full turn is the counterexample.
overconfident — one of three sources is miscited and cuts the other way.
I-01 Decontextualised reuse is epistemically risky
- confidence
- medium
- evidence
- michelle:0028 · stephen:0022
- counter
- david:0040 · bruce:0035 · michelle:0107
I-01 Decontextualised reuse is epistemically risky
- confidence
- medium
- evidence
- michelle:0028 · stephen:0022
- counter
- david:0040 · bruce:0035 · michelle:0107
One command, fifteen transcripts, thirty minutes
pip install, an API key, and motif ./transcripts --out report.md. The full fifteen-transcript corpus — 101,000 words — runs in one synthesis call: thirty minutes, $4.53, twenty insights. Fourteen of the sixteen ground-truth themes, including four only reachable beyond the five I read by hand. Six findings the ground truth didn’t contain at all, each with receipts a team can open.
Teams and freelancers who synthesise in FigJam with transcripts in a folder — no research platform, just stickies — and who’ve been burned by a confident AI summary. The engine is written to sit under any surface; an MCP server is the next build — one server that reaches Claude Code, Cursor, FigJam, and Miro.
The loop controller, run logger, LLM client, and config loader are a small reusable core. Motif is the first tool on it. The next — a design critique loop — reuses all of it.
Honest ledger
Two days, twenty-three runs, two evals, one honest result.
The v3 evaluation
Addendum to this page at /tools/motif/case-study/ — appended 2026-09-06, three months after the loop above shipped.
Part 1 ended on a named failure, above: the model was taking one finding per turn and stopping, so themes cited constantly for one thing never surfaced as a claim in their own right. Eval 2 confirmed it — two ground-truth themes, T-11 (deletion as waste) and T-15 (method hierarchy), absent from all six reports while the turns carrying them were cited in all six for something else. That, plus a duplication problem, an outlier-dissent trap that kept failing, and two unanswered questions about the critic model and the iteration cap, became the v3 eval.
Eval 3 tested four conditions against the same five transcripts (33,870 words), the same ground truth, and condition C only: control, the frozen instrument unchanged; all-v3, control plus five candidate changes (second_finding, duplicate_insight, duplicate_receipt, critic_citation, dissent_at_intake); opus-critic, control with Opus 5 as the critic; cap5, control with max_iterations: 5. Ten runs — three each on control and all-v3, two each on opus-critic and cap5, chosen so the eval fit its $25–40 budget with a working margin. All ten valid; none crashed, none re-run. Scored blind by one rater, AI-assisted, four evidence spot-checks per report at fixed positions chosen before scoring began.
The tag is v2.1-eval, commit 3675228, cut before any v3 code was written: v2-eval as scored in Eval 2 plus exactly one deterministic change, the counter-receipt handling of 2026-09-05. That “exactly one” was verified, not asserted — every commit touching the instrument since the Eval 2 runs was read, diffed, and tabulated. A freeze is only worth something if the claim is checked; checking it took one git log -p over four paths.
Ten pass/fail bars were written into the eval spec, with their Eval 2 baseline arithmetic beside them, before the first paid run.
| # | bar | result | verdict |
|---|---|---|---|
| 1 | Second finding: T-11 and T-15 each ≥ 0.5 in ≥ 2 of 3 all-v3 runs | T-11: 1.0, 1.0, 1.0. T-15: 1.0, 1.0, 1.0 — 3/3 each at full credit, against 0/3 in Eval 2 | PASS |
| 2 | No coverage loss: all-v3 mean over T-01…T-10 ≥ 7.83 | 8.5, 8.0, 8.5 → 8.33, identical to the v2 baseline | PASS |
| 3 | No precision loss: unsupported and miscalibrated each ≤ 1.00 | 0.0 and 0.0 | PASS |
| 4 | Dedupe: 0 near-duplicate pairs across the 3 all-v3 runs | 0 pairs — but duplicate_insight never fired, in any run | PASS, unattributed |
| 5 | Outlier dissent: P-03 passes in ≥ 2 of 3 all-v3 runs | 3/3 — but control also passed 2/3 | PASS, not attributable |
| 6 | Opus critic: adopt if coverage +≥1.0 or precision −≥0.5, and cost < $5.00/run | coverage 8.67 → 10.25 (+1.58); $3.83/run. Precision could not fall; it was already 0 | Rule says adopt |
| 7 | Iteration cap: adopt cap 5 if critic_pass in ≥1 of 3, or coverage +≥1.0 with bar 3 held | critic_pass 0 of 2; coverage +0.58 | Do not adopt |
| 8 | critic_citation: 0 interviewer turns reach the reviser, every strip recorded | fired once (R4), stripping bruce:0026, michelle:0073 and david:0049 from two objections before revision; warn recorded | PASS |
| 9 | duplicate_receipt: 0 in each all-v3 final output | fired 1, 1, 3; final count 0, 0, 0. Control finished with 1, 1, 0 and cap5’s R1 with 3 | PASS |
| 10 | Unevaluated recommendations sections named in the verdict | not run — the flag is off in all four configs and no live critique_document pass was made; covered by offline tests only | NOT RUN |
These are decision rules, not significance tests: with three runs and a binary outcome, 2/3 against a 0/3 baseline is not significant at any conventional level (Fisher exact ≈ 0.4), and a one-point theme-sum move is inside the rater consistency Eval 2 recorded. Bars 1, 4 and 5 are worth acting on because the baseline is never rather than sometimes. Bars 2 and 3 are guard rails against a recall change that costs precision, not claims of improvement. Bars 6 and 7 rest on two runs, not three, and cannot report a rate.
second_finding asks, for each turn a report cites, whether that turn carries a distinct finding no insight uses. It fired 8, 8 and 9 times across the three all-v3 runs and nowhere else — 25 firings, all inside one condition. In iteration 1 of all three runs it named david:0022 and penni:0031 by turn id and said what second finding each carried. Both themes ended present as claims in all three reports, scored by a rater who did not know the rule had fired.
| condition | david:0022 cited | T-11 scored | penni:0031 cited | T-15 scored |
|---|---|---|---|---|
| control (n=3) | 1 of 3 | 0, 0.5, 0 | 3 of 3 | 0, 0, 0.5 |
| all-v3 (n=3) | 3 of 3 | 1.0, 1.0, 1.0 | 3 of 3 | 1.0, 1.0, 1.0 |
| opus-critic (n=2) | 2 of 2 | 0, 0.5 | 2 of 2 | 0.5, 0.5 |
| cap5 (n=2) | 1 of 2 | 0, 0 | 2 of 2 | 0.5, 1.0 |
penni:0031 was cited in 10 of 10 reports and reached a claim in only the three all-v3 ones. Coverage rose without precision falling: all-v3 gained 1.8 theme points over control and 2.2 over Eval 2’s v2, on 5.3 more insights per report, with unsupported and miscalibrated both at zero. The other two changes that earned their place are both deterministic and cost nothing: duplicate_receipt fired 5 times across the three all-v3 runs and every instance was fixed before the final output; critic_citation caught the exact failure it was written for — the critic sending the reviser to an interviewer turn — and stripped it silently but reported it.
Citing a turn was never the problem. Reading it twice was.
Three of the five v3 changes ship in the default config: second_finding, critic_citation, duplicate_receipt. dissent_at_intake and duplicate_insight stay off — recorded as unproven this round, not deleted. Shipped in the 0.4.0 release, tag v3, commit 7be2813: PyPI etot-motif 0.4.0, the MCP registry entry and the hosted engine both updated, /healthz reporting 0.4.0.
A bar can pass and prove nothing, and saying so is the finding.
dissent_at_intake. Bar 5 passed: P-03 passed in 3 of 3 all-v3 runs. So did 2 of 3 control runs, and 4 of 4 opus and cap5 runs — 9 of 10 reports overall. The rule cannot be credited when the condition without it fixed the same thing. Ruling: stays off. Re-test it against the closed baseline, or drop it; it costs intake output tokens for an effect this eval cannot see.
duplicate_insight. Bar 4 passed: zero near-duplicate pairs at the rater’s judgement across the three all-v3 runs. But the rule never fired, in any run, at its 0.55 threshold, and the rater found no pairs for it to fire on — Eval 2’s R4 duplication was not reproduced, so there was nothing to catch. It stays off for this release too, alongside dissent_at_intake, recorded as untested rather than shipped on faith: it is cheap and deterministic, and the failure it guards — over-splitting under missing_theme pressure — is a live risk now that second_finding is adding insights, which makes it a strong v4 candidate rather than a shipped rule this round.
The rule that did ship is a deviation from the spec worth recording, because it changed the cost: the spec asked for a “deterministic-plus-model pass after revise”; it was built instead as a deterministic critic rule — Jaccard over title and claim vocabulary, threshold 0.55 — that the existing reviser acts on like any other failure. That saves one Sonnet call per iteration, about $0.18 per run and $0.55 across the condition.
Stated as the results file states it: P-03, Penni’s pro-validation dissent, passed in 9 of 10 reports overall, against 1 of 6 in Eval 2 — and dissent_at_intake cannot be credited, because the condition without it fixed it too. This stays open: the likely cause is the one deterministic change in v2.1-eval (counter-evidence receipts now print, so counter-evidence is cheaper to state correctly) or model drift between 2026-09-03 and 2026-09-06, and neither was isolated. The honest reading is that the Eval 2 open item closed on its own, for a reason nobody has confirmed.
Both cap5 runs went the full five rounds, stop_reason: max_iterations, without ever reaching critic_pass or triggering no_progress. Rounds 4 and 5 cost about $1.10 and 7 minutes per run and bought +0.58 theme points on average, inside rater noise. critic_pass was reached in 0 of 10 runs, at cap 3 and at cap 5, and no_progress never fired. Every run stopped on the ceiling with objections outstanding — raising the cap does not converge the loop, it buys more rounds of the same. Eval 2’s open item, whether the cap is a ceiling or a stopping rule the loop reaches, is answered in the negative.
Opus as critic clears its own decision rule: coverage 8.67 → 10.25, +1.58, at $3.83 a run against a $5.00 ceiling. Its strongest report beat every report produced under any condition in any of the three evals. But the bar is running on two runs, and opus-critic’s two-run range overlaps control’s three-run range. Ruling: make it the documented option for a high-stakes run, not the default, and re-test at n=3 if it is ever proposed as the default.
Per run: control $2.23, all-v3 $2.51 (+13% for +1.8 theme points), opus-critic $3.83 (+72%), cap5 $3.31 (+48% for +0.58). Every condition came in under its projection.
Combined project API spend after Eval 3: $72.2047. Local spend $66.4209 across 42 runs/*/meta.json; hosted spend (part 3, on the Fly volume) $5.7838.
- Eval 1
- $13.3645
- Eval 2
- $6.8362
- Eval 3
- $28.4963
- non-eval/dev
- $17.7239 (discarded and development runs)
- local total
- $66.4209 · 42 runs
- hosted (part 3)
- $5.7838
- combined
- $72.2047
Source: docs/case-study-notes.md, 2026-09-06; Motif commit 341c544.