← The agent platform Work wiki

Design decisions

The full set of platform-level decisions both products inherit, with the reasoning, and with the two that were reversed.


Both product specs carry a numbered decision table. These are the ones that belong to the platform (every project inherits them), written here with the why, because the why is the part that survives a rewrite.

Standing

DecisionWhy
LLMs extract, deterministic code decides. Presence, comparison, completeness, escalation, prioritisation are code. Models produce structured inputs: classifications, values, confidences.Any conclusion with legal weight has to be explainable to an auditor and stable across model versions. A model proposes evidence; a rule decides. The essay.
One shared platform, many orchestrators. shared/ holds tools, schemas, generic sub-agents. Each use case is a thin deterministic orchestrator composing them.The products are the same shape. Sharing avoids two document-store integrations, two vision clients, two fetch engines. Domain difference lives in config and orchestration, not plumbing.
The one import rule. shared/ imports nothing from any project. Projects import shared/ and themselves, never each other.This is what lets two products ship on independent schedules from one repo.
Every conclusion carries a citation. A document, page and region, or a database reference. No citation → rendered as an unverified suggestion.A reviewer signing off a legal placement or a verification must be able to see why.
Domain logic is versioned config, not code. Required-document sets, exception rows, comparison policies, thresholds, decision tables, keyword maps: YAML, validated by Pydantic, versioned with the pipeline.Business owners revise rules without a release. Every rule is auditable and diffable.
The fetch registry is the SQL allow-list. Detail.No model- or user-derived string ever reaches SQL.
Structured outputs everywhere. JSON-schema response format, Pydantic-validated, retried once, then dead-lettered.Free text is where hallucinations hide and where parsers die.
Confidence-gated triage. Low confidence anywhere marks the component review rather than presenting a shaky pass or fail.Protects the hard floors on false-accept and false-pass.
Deterministic orchestration on the batch path. No LLM routing. An interactive agent exists only as a colleague’s front door.Batch behaviour has to be predictable, replayable and cheap to reason about.
Fail closed on every safety-critical check. Missing or low-confidence input defaults to the non-passing state; a model-matched document needs an explicit human tick.A false “verified” or “complete” is a compliance or data-breach event. The essay.
Exceptions are explicit config, never inferred. “This seller’s accounts have no statements” is a row, not a model’s observation.Prevents both false fails on legitimate exceptions and false passes from assumed universal rules.
One work item, one idempotency key. hash(subject, use_case, pipeline_version); check before work; a claim table with in-progress / completed / failed.Queues redeliver. Replays must be safe.
The flakiest dependency is isolated. Session reuse, retries with backoff and jitter, a circuit breaker, a defined degraded state.The document store fails; the queue must not stall. Its auth model is changing; only its client should know.
Managed Identity to every dependency. Models, document reader, warehouse, queue, vault. Key Vault for residual secrets only; one fail-fast resolver at startup.Least privilege per resource, and no credential in an environment variable that outlives the migration.
Governed retention. TTLs and automated purge on landing, artefacts, cache, dead-letter; only the audit log and the warehouse records retain long-term. A failed purge alerts.Page images of customer correspondence are not something to keep by accident.

Reversed

One decision in the first design did not survive contact with reality, and the reversal is worth recording.

A dense three-axis rule cube. The records product’s required-document model was first drawn as product × seller × jurisdiction, fully populated. The production rules export showed the real data was sparse (one axis mattered for one document type, another for one seller family) and the model became a state map with a small overlay. Detail. The lesson generalises: design the config shape after you have the data, or at least be ready to throw the first shape away.

Watched, not yet decided

Whether high-confidence passes can eventually clear without a human (post-pilot, on override data); whether the interactive agent should ever be allowed to call a write tool (currently no); and how much of the evaluation harness moves from merge-blocking to shadow-only as the golden set matures.