The question moved and the architecture did not
For most of the last decade, buying document AI meant choosing an engine. The evaluation was a bake-off: same 200 pages, three vendors, count the field errors, pick the winner. That comparison still has a winner, but the gap between the credible options narrowed to the point where it rarely decides anything, and the failures that hurt in production moved elsewhere. A pipeline goes down because a schema changed and nobody versioned it. A tenant's month goes sideways because a batch import of 80,000 pages consumed the capacity that the interactive queue needed. A compliance review stalls because nobody can state which model version produced a field eleven months ago. An invoice is paid twice because a webhook retried and the receiver was not idempotent.
None of those is a reading failure. Each one is a control failure — a decision that was made implicitly, by whichever component happened to be holding the job at the time, with no record that a decision was made at all. The engine is fine. What is missing is the layer that decides how the engine is used.
Networking solved this shape of problem a long time ago by splitting the data plane from the control plane. The data plane moves packets; the control plane decides where packets go. The split is useful precisely because the two change at different rates and for different reasons — the data plane is optimised for throughput and almost never changes, and the control plane changes every time a policy changes, which is constantly. Document AI has exactly the same split available and mostly has not taken it. The data plane is the workers that classify, extract, validate and deliver. The control plane is everything that tells them which of those to do, in what order, under what limits, for whom.
What a control plane actually owns
The word gets used loosely enough to mean "an admin screen," so it is worth being concrete. A document AI control plane is a versioned, queryable store of the decisions the pipeline needs to make, plus the resolver that answers "for this document, from this tenant, right now, what applies?" It owns nine things. Teams that build one usually start with two or three and discover the rest by outage.
| Registry | The decision it holds | What it prevents |
|---|---|---|
| Models | Which model, at which version, for which stage and document type — and the fallback when it is unavailable. | Silent upgrades that change extraction behaviour with no record and no rollback path. |
| Schemas | The output contract per document type, versioned, with the migration state of each consumer. | A field rename that breaks three downstream systems on a Tuesday afternoon. |
| Routing | Which path a document takes — cheap single pass, full loop, template, human-first. | Running the expensive path on everything, or the cheap path on the documents that decide money. |
| Queues | Priority classes, concurrency per tenant, backpressure rules, what a bulk import may starve. | One tenant's backfill turning every other tenant's real-time job into a timeout. |
| Quotas | Rate limits, page ceilings, spend caps, and the behaviour at the limit — queue, degrade or reject. | An unbounded retry loop discovered on the invoice at the end of the month. |
| Retention | How long each artifact class lives, where it lives, and what deletion actually removes. | Files kept past their contractual window because retention was a bucket setting nobody owned. |
| Webhooks | Endpoints, signing keys, retry policy, dead-letter destination, replay authority. | Silent delivery failures, duplicate side effects, and no way to replay a lost day. |
| Review | What escalates, to which queue, under what SLA, and what a reviewer is allowed to change. | A review queue that grows without limit because nothing defines who owns which exception. |
| Cost | Metering per tenant and document type, budget alerts, and the enforcement action. | Unit economics discovered from the provider bill instead of the system that caused it. |
The list looks like nine features. It is closer to one feature with nine faces, because the value is not in any single registry — it is in all of them resolving through the same mechanism, at the same moment, in a way that can be inspected afterwards. A model registry with no connection to the cost registry cannot express "route to the cheaper model when this tenant is over budget." A retention registry with no connection to the schema registry cannot answer "which fields must be purged when a document type is deprecated." Scattered, each one is a setting. Together, they are a policy.
Models: version the thing that changes the answers
Extraction quality is a function of a model version, and model versions move. A provider deprecates a snapshot, a new one benchmarks better, a cheaper option becomes good enough for a subset of document types. Every one of those is a change to extraction behaviour, and without a registry the change happens by editing a string in a worker and deploying. The registry makes the same change an auditable event: which model, for which document type and stage, pinned to which version, with a fallback, effective from when, requested by whom. That record is what makes it possible to answer the question a regulator or a customer eventually asks — what produced this field, in the same spirit as an AI bill of materials for the rest of the stack. The registry is also where the boring operational wins live: canary a new version on 5% of one document type, compare against the incumbent on the same pages, promote or roll back with a configuration change rather than a deploy.
Schemas: the output contract is a versioned artifact
The output schema is the interface between the pipeline and every system that consumes it, which makes it the most under-managed critical artifact in a typical document stack. Fields get added because someone needed one, renamed because the old name was wrong, made optional because a document type sometimes lacks them — and each of those is a breaking change to somebody, delivered without a version number. The schema registry treats the contract the way an API is treated: versions are explicit, compatibility rules are stated, consumers declare which version they read, and a deprecation has a date attached rather than a hope. This is the data-contract discipline applied at the point where documents become structured records, and it is the difference between a schema change being a planned migration and a schema change being an incident.
Queues: priority is a policy, not a side effect
Every document pipeline has priority. Most of them have it accidentally — determined by arrival order, worker count and whichever tenant happened to submit first. Accidental priority works until the day a customer uploads a year of archives and a different customer's real-time approval waits behind 80,000 pages. Making priority explicit means naming the classes (interactive, batch, backfill, retry), setting per-tenant concurrency so one account cannot consume the pool, defining what backpressure does when the queue is full, and stating which classes may be starved. In a multi-tenant deployment this stops being an efficiency question and becomes an isolation guarantee — the thing a tenant is actually buying when they ask whether the platform is shared.
Quotas and cost: the limit and the meter belong together
Quotas and cost governance are the same registry viewed from two directions. A quota is a limit expressed before the work runs; cost is the same work measured after. Keeping them apart is how teams end up with per-minute rate limits that say nothing about spend, and monthly spend reports that arrive too late to change anything. Held together, the useful behaviours become expressible: cap a tenant at a page volume and a spend, alert at 80%, and at 100% choose deliberately between queueing, degrading to the cheaper route or rejecting with a clear error. The degradation choice is the one worth designing carefully, because it is where cost per successful task is actually decided — a cheaper model that raises the escalation rate can cost more per completed document than the expensive one it replaced.
Retention: deletion is a pipeline behaviour, not a bucket setting
A document pipeline produces more artifacts than the document: page images, intermediate crops, extracted text, structured output, review annotations, trace records, evaluation samples. Retention policy that covers only the original file leaves the rest to whatever default the storage layer had. The registry's job is to make each artifact class an explicit entry — how long it lives, in which region, what a deletion request removes and what it provably cannot, because removing a document's influence from a fine-tuned model is a different problem from deleting a file. Stating the boundary in the control plane means the answer to a deletion request is a query rather than an investigation.
Review and webhooks: the edges where automation meets people
The last two registries govern what leaves the pipeline. Review policy decides what a machine is allowed to finish alone — which is a per-field, per-document-type judgement about the cost of being wrong, not a single confidence threshold applied platform-wide. Webhook policy decides how the result reaches the system that acts on it: the endpoint, the signing key, the retry schedule, the dead-letter destination, and who may replay. Both are unglamorous and both are where money is lost — a review queue with no ownership rules grows until it is abandoned, and a webhook with no idempotency contract eventually pays an invoice twice.
A setting that lives in one service's environment variables is not policy. It is a decision that happens to be written down somewhere, which is why nobody can tell you what it was six months ago.
Policy resolves along two axes, not one
The design mistake that makes control planes collapse under their own weight is treating policy as a single-axis problem. Most implementations start per tenant, because tenancy is the obvious boundary — every customer gets a configuration, and the configuration applies to their traffic. Then someone points out that the same customer's passport scans and their bulk delivery notes have nothing in common: different models, different validation strictness, different review thresholds, different retention, different value per error. So a second dimension gets bolted on, usually as special cases inside the tenant record, and within a year the configuration is unreadable.
Policy in document AI genuinely varies along two axes, and the plane should model both from the start:
- Tenant — commercial and legal terms: quota, spend, residency, retention window, isolation level, which model providers are permitted, which regions the work may run in.
- Document type — technical and risk terms: schema version, extraction route, validation strictness, review threshold, which fields are allowed to auto-release.
The resolution rule that survives contact with production is a layered default: platform baseline, overridden by document type, overridden by tenant, overridden by the tenant's policy for that specific document type. Four layers, resolved deterministically, with the effective policy computable and inspectable before a job runs. The two properties that matter most are that the resolved policy is logged with the job — not merely derivable, but recorded, so a job processed under last week's policy is explainable next year — and that the resolver is a pure function of the registries, so the same document under the same policy resolves the same way in staging and in production.
That logged resolution is also the connective tissue to observability. A trace that says "this document took 4 attempts and cost $0.31" is useful; a trace that also says "under policy version 47, which pinned model B and set the review threshold at 0.92" is diagnosable. This is the same argument as tracing a multi-step extraction pipeline, extended one level up: the trace records what happened, and the control plane records why it was allowed to happen.
Four ways it gets built wrong
Control planes fail in recognisable ways, and three of the four failures come from building the plane before understanding what varies.
Building the plane before the variation exists. A nine-registry policy engine serving one tenant and two document types is a hobby. The registries earn their cost at the point where the same question is being answered differently in more than one place — when a model version is pinned in two workers, when a retention rule exists in both a bucket policy and a cron job. Until then, a documented configuration file is a control plane with an acceptable amount of honesty about its scale.
Making the plane a runtime dependency of every job. A pipeline that cannot process a page because the policy service is down has traded one outage for a worse one. The plane should resolve policy at admission, attach the resolved policy to the job, and let workers run from the attached copy. Resolution is a control-path operation; it does not belong in the hot loop, and the plane's availability should never gate throughput.
Letting the plane be edited without a version. The entire point of centralising decisions is that they become auditable, and a registry that can be edited in place through a dashboard with no version, no author and no effective date is a faster way to make unreviewable changes. Policy changes deserve the treatment code changes get: proposed, reviewed, versioned, dated, reversible. The pipeline that can roll back a bad model pin in 30 seconds is running a different operation from the one that redeploys.
Confusing configuration with control. A settings page that exposes 200 toggles and resolves none of them is not a control plane; it is configuration sprawl with a UI. The distinguishing property is resolution — the plane must be able to answer, for a specific document at a specific moment, what the effective policy is and where each part of it came from. If that question requires a person to read four screens and reason about precedence, the decisions are still scattered. They just moved.
The overhead nobody puts in the diagram
A control plane is real engineering cost, and the honest version of the argument states it. There is a schema for policy itself, a resolver with precedence rules, versioning and rollback, an audit log of policy changes, a permission model for who may change what, a testing story for policy changes that is separate from the testing story for code, and a migration path every time a registry gains a dimension. None of that extracts a single field. It is all overhead in the strict sense, and on a small deployment it is overhead that buys nothing — two document types and one customer do not have a policy problem, they have a settings file, and building the plane first is how a team spends a quarter on infrastructure for variation that never arrives.
The cost lands the other way as the surface grows, and it lands quietly. Not as an outage, usually, but as a slow loss of the ability to answer questions: which model version handled this, why did that tenant's job go to the slow queue, what is our margin on this document type, what happens to these files in 18 months, who approved the threshold change. Each answer is individually retrievable by someone reading code and commit history. The compounding problem is that the retrieval cost is paid every time, by whoever is asking, and it grows with every tenant and every document type. The control plane converts that recurring investigation into a query, which is the whole return.
The threshold worth watching is the second axis. One tenant with many document types is manageable in configuration. Many tenants with one document type each is manageable in configuration. Many tenants times many document types is a matrix, and matrices held in code and environment variables are where the ability to explain the system goes to die. That crossing point is when the plane pays, and it is also, awkwardly, the point at which building it means migrating decisions that are already scattered across a running system — which is why the teams that do this well tend to build the registries early and thin rather than late and complete.
What this means for document AI specifically
Three consequences are worth stating plainly, because they change how a platform is bought and operated, not just how it is built.
Procurement questions move from accuracy to control. The evaluation that mattered was field accuracy on a sample. The evaluation that matters now includes whether model versions are pinned and auditable, whether schemas are versioned, whether quotas are enforceable per tenant, whether retention is configurable per artifact class, and whether the platform can state which policy produced a given result. Those are control-plane questions, and a vendor that cannot answer them is asking the buyer to accept that the pipeline's behaviour is whatever it currently happens to be. The same shift is visible in how buyers consolidate document AI vendors — the platform that holds the policy is the one that is hard to replace.
The plane is where agentic pipelines get their limits. An agentic reader that can loop, retry, correct and escalate is more capable than a single pass and more capable of spending money. The budgets that keep the extraction loop terminating — maximum attempts, token ceilings, wall-clock limits, the escalation threshold — are control-plane entries, not constants in a worker. This is the practical link between autonomy and governance: the loop is allowed to be adaptive precisely because the boundary it operates inside is declared somewhere a person can read and change, which is the same argument that governs the lifecycle of any deployed agent.
The audit trail gets a second half. Most document platforms log what happened to a document — the stages it passed, the values extracted, the reviewer who approved. The half that is usually missing is what the system was permitted to do at that moment. A record that a field auto-released at 0.94 confidence is incomplete without the record that the threshold was 0.92 under policy version 47, set on a date, by a named approver. Together they answer the question an auditor actually asks, which is never "what did the model say" but always "why was that allowed to be enough" — the difference between logging outputs and holding an evidentiary record.
Closing thought
The model is the part everybody evaluates and the part that has stopped being the differentiator. What separates a document pipeline that scales from one that quietly becomes unexplainable is whether the decisions around the model live somewhere — versioned, resolvable, logged, changeable by a person who can be named — or whether they are distributed across workers, buckets, cron jobs and environment variables as accidents of implementation. Both pipelines extract fields. Only one of them can tell you why.
At Cogneris we build document AI with the policy layer explicit: tenant-configurable classification and extraction, versioned output contracts, per-tenant limits, tamper-evident audit metadata and contract-specific retention — so the question "why was this document processed this way" has an answer that does not require reading our code. If you are running document AI across more than a handful of tenants and document types, and the configuration has started living in places nobody wants to inventory, see how the API models these boundaries, the pricing page, or talk to our team. A pipeline that cannot explain its own policy is a pipeline you are operating on trust.