Inspiration

AI sounds exactly as confident when it's sure as when it's guessing. There's no tell. Fine for trivia, bad for anything with money attached. A missing Oxford comma in a Maine overtime statute cost a dairy company $5 million because a court couldn't agree what the sentence meant, and if a federal appeals court can split on a clause, an AI reading it once and handing you one clean answer is hiding something. Municipal contracts made it click: cities sign agreements full of undefined terms like "commercially reasonable efforts" and "material delay," and that's exactly where disputes start.

What it does

Dissent sends the same clause to several models from different families. No assigned sides, nobody told to argue, identical prompt, and each one has to commit to a verdict instead of hedging. It then breaks their answers into individual claims and checks who agrees and who contradicts, and a small decision tree I trained scores each claim as solid, disputed, or weakly supported. You get one answer with the disputed parts marked in redline and a quote from each model showing where it landed.

How we built it

Render Workflows runs the pipeline, with each model's read as its own task, so when a provider rate-limits me it retries on its own instead of killing the run. Models come from Featherless and Groq across different families (DeepSeek, Kimi, Llama) because same-family models agree too easily and you need real architectural diversity or the disagreement means nothing.

The arbitration layer is a depth-4 decision tree trained on labeled claims from real runs. It's 1.7 KB and scores in 60 microseconds. I could have used another LLM call, but then the thing deciding what to trust would itself be unauditable, which is a strange position for a legal tool. Frontend is Flask and one HTML page, styled like a marked-up contract.

Challenges we ran into

Featherless gated me behind an approval queue, then capped model switching at four per minute, which is rough when fanning out is the whole product. Spreading across two providers fixed it and made the project better.

The bigger problem was that my first working run had zero disagreement. I'd used a cleanly drafted clause, and models converge on those, so I had to go find language that caused actual litigation. Even then the models kept hedging, listing both readings and refusing to decide, so their answers came out as identical mush. Forcing each one to commit to a verdict and name its own weakest point is what finally surfaced the split.

Accomplishments that we're proud of

The trained model, not because a decision tree is impressive, but because I could have made this an API wrapper and didn't. Something in the pipeline is mine, it's 1000x smaller than the alternative, and I can defend every decision it makes. Getting real disagreement to surface took three separate fixes and none of them were the one I expected: the extraction prompt wasn't the problem, the analyst prompt was.

What we learned

Models allowed to say "it depends" all say the same thing and you learn nothing. Small models earn their place when auditability matters more than raw capability, because nobody reviewing a contract accepts "the model said so." And picking the right test case is real engineering work, not setup: my pipeline looked broken for an hour when it was working correctly on input that had nothing to find.

What's next for Just Me

Claim extraction sometimes splits a model's verdict from its reasoning, so a model can appear on both sides of related claims, and that needs a stricter pass tying each claim to one stated position. Past that: whole documents instead of single clauses with a risk map of which sections have the most disagreement, more training data for the arbiter, and a fourth label, since a claim only one model mentioned currently gets called "unreliable" when silence isn't contradiction. It should be "unverified."

Built With

Share this project:

Updates