TL;DR
A review is hundreds of calls across several stages, so an outage lands mid-document. What separates a demo from a product is whether finished work survives.
Something, always — because a contract review is not one model call. It is hundreds, across several stages, over minutes. Anything that long-running meets an outage eventually.
What separates a demo from a product is not whether it fails. It is whether the work already done survives.
Why does a review get interrupted at all?
Because of its shape. A single call either succeeds or fails and you retry it. A contract review is a pipeline — extract the playbook rules, match clauses against them, score each passage, analyse the ones that matter — and each stage makes many calls.
That produces two properties that decide the architecture:
- The failure surface is large. Hundreds of opportunities to hit a rate limit, a timeout, or a provider incident.
- The failure lands in the middle. Not before you start and not after you finish — partway through a document, with some clauses analysed and some not.
A system designed around the happy path treats that as an error and starts again. A system designed for production treats it as normal and resumes.
Why is retrying immediately the wrong instinct?
Because most failures at this scale are load, and an immediate retry adds load.
A rate limit means the provider is asking you to slow down. Answering it by trying again straight away — and doing that from every parallel worker at once — turns a brief throttle into a sustained one. You can convert a provider's small problem into your own large one in about ten seconds.
There is a second, subtler error: treating every failure the same. A timeout and a malformed request are not the same event. One deserves patience; the other will fail identically forever, and retrying it just spends money and time before arriving at the same place.
So the design question is not "should we retry" but "what kind of failure is this, and who should handle it."
What does a two-tier design look like?
Two independent layers, each covering what the other cannot. This is how ours is built:
| Tier | What it handles | Why it is separate |
|---|---|---|
| Inside the worker | A handful of attempts with growing gaps between them | Absorbs the transient case — a throttle, a blip — without anyone hearing about it |
| The queue itself | The message becomes visible again and is picked up afresh | Survives the worker dying, which no in-process retry can |
The second tier is the one people leave out, and it is the one that matters when a container is recycled or a task is killed mid-review. In-process retries die with the process. A message on a queue does not.
And failure is only final when both are exhausted. A job marked permanently failed after one tier is usually a job that would have succeeded.
When should the system stop trying entirely?
When the provider is down rather than busy — and the mechanism for telling the difference is a circuit breaker.
It has three states and the middle one is the point:
- Closed — normal. Calls go through.
- Open — enough consecutive failures have happened that the system stops calling at all for a set period. It fails fast instead of queueing work against a dead service.
- Half-open — after the pause, one probe. Success closes the circuit; failure re-opens it.
Without this, an outage produces a pile of jobs all timing out slowly, consuming capacity, spending money, and delaying the recovery once the provider returns. With it, the system notices, waits, and tests.
The threshold and the recovery window are the two settings worth arguing about — too sensitive and normal variance trips it; too tolerant and it never fires when it should.
Does swapping providers solve it?
Partly, and less than the marketing suggests.
Abstracting the provider behind one interface is worth doing — it means a model change is a configuration decision rather than a rewrite, and it lets different stages of the pipeline use different models where that makes sense. We build it that way.
But it does not make an outage free, for two reasons people discover late:
- Failover mid-document changes the reviewer. A contract half-assessed by one model and half by another is internally inconsistent in a way that is hard to see and harder to explain. Consistency within a document usually matters more than finishing it a few minutes sooner.
- The second provider needs the same governance. Data residency, retention, and whether the model is hosted where your legal team has already approved. A failover route nobody approved is not a failover route — it is an incident waiting to be discovered by an auditor.
Our position: abstract the provider, but fail over between runs rather than inside one. Finish the document consistently or resume it consistently. Do not mix.
This is how Paralegent AI is built — two retry tiers, a circuit breaker, provider abstraction, and failover between runs rather than inside one. It is Cognilium's contract-review app in its family of AI optimization apps for Microsoft Dynamics 365, and we build systems this way for customers on their own stack.
What must never happen?
A partial review that presents itself as complete. Everything above exists to prevent this one outcome.
Three rules, and they are ours:
- A review that could not finish says so on its face. Not in a log — on the document a reviewer opens.
- Clauses that were never assessed are marked never assessed, never defaulted to acceptable. A gap caused by an outage must read exactly like a gap caused by a missing rule: unresolved.
- A failed write is never replaced by a read. If the system could not record a result, it must not substitute something it fetched instead and report success. This is the most dangerous pattern in agent design, because the output looks entirely normal.
The stakes are specific here. If a term from this review reaches a purchase agreement, it prices real orders — and agreement prices override trade agreements. A silently incomplete review is not an inconvenience. It is a commercial exposure.
About Cognilium Cognilium builds AI optimization apps for Microsoft Dynamics 365 — companion apps that optimize the pricing, inventory, warehouse and planning decisions your ERP manages but can't optimize. Dynamics is your system of record. Cognilium is your system of intelligence. https://cognilium.ai · https://www.linkedin.com/company/37180269/
Legal AI Ops. We transform legal workflows with agentic AI, copilots, agentic workflows and decision intelligence — built into core workflows rather than beside them, to raise productivity and cut operational overhead. Contract Review Copilot is the contract-review app in that family. It ships as Paralegent AI, in production today. How we build Legal AI Ops — custom AI capabilities on top of legal work, against your playbook and your Dynamics 365.
Bring your reliability requirements to a 15-minute call — retry behaviour, provider governance and what a partial review must never do.
Sources
Sources and fact-check
| # | § | Claim | Tier | Source | Verdict |
|---|---|---|---|---|---|
| 1 | 1 | A review is many calls across several stages, so failure lands mid-document | T2 — capability, describing our own pipeline's shape. No call count published | Paralegant_TECHNICAL_PROFILE.md §2 | PASS |
| 2 | 2 | Immediate retries worsen load failures; failure classes differ | T2 — ours, an engineering argument | Internal definition | PASS |
| 3 | 3 | Two independent retry tiers, in-process and queue-level, final only when both exhaust | T2 — capability, our own design | Same profile, §5.5 | PASS — load-bearing |
| 4 | 3 | In-process retries cannot survive the process dying | T2 — ours, and it is why tier two exists | Same profile, §5.2 | PASS |
| 5 | 4 | Circuit breaker with closed / open / half-open states and a probe on recovery | T2 — capability, our own design. Threshold and timeout values deliberately not published | Same profile, §5.6 | PASS |
| 5b | 4a | Provider abstraction is a configuration boundary, not an outage cure | T2 — capability + ours | Same profile, §5.7 provider abstraction | PASS |
| 5c | 4a | Mid-document failover produces internal inconsistency; the second provider needs the same governance | T2 — ours, a design position stated as ours | Internal definition | PASS |
| 6 | 5 | A partial review must never present as complete; unassessed is not acceptable | T2 — ours, a design position | Same profile, §11 | PASS |
| 7 | 5 | A failed write must never be replaced by a read | T2 — ours | Same profile, §7.3 instruction set | PASS |
| 8 | 5 | Agreement prices override trade agreements, so a term from this review prices real orders | T1 | purchase-agreements, fetched 2026-09-10 | PASS |
Tier summary: 1 × T1, 9 × T2 — 0 × T4.
Figures deliberately withheld. The technical profile records exact retry counts, the circuit-breaker failure threshold and its recovery timeout. None is published here. They are our own configuration values and our own performance surface; the mechanism is described without them, which is the shape that survives PUBLISHING-CONTRACT.md §1.
Disclosure: no client, no outage story, no measured reliability claim. The article describes design, never results.
