← All guides

Deploying an adjudicator (the frozen verifier container)

The specific case of deploying an application: taking a trained domain off-platform as a read-only container that answers claims with the same verdicts, a policy disposition and a signed evidence package. Use it when a system must verify claims without reaching the platform, or when an auditor wants an artifact whose identity they can pin. It is a standalone verifier (earl-verify), not the persistent runtime: it has no memory, no planning, no observation, and it never learns.

When to deploy one

1. Freeze

POST /tuning-runs/{id}/freeze-domain
{"codename": "journal-entry-review-v1", "description": "…", "runtime_port": 8410}

Requires training_succeeded. The package (~98 MB) holds the grounded KB, the trained checkpoint, the earl-verify binary for the container platform, a small FastAPI server, the policy active at that moment and its evaluator, and identity.json: the substrate identity, a sha256 over the engine release and commit, the exact binary, the KB fingerprint, every checkpoint file and the policy hash. Editing the policy afterwards never changes a frozen package. Frozen packages are listed by GET /frozen-domains.

2. Deploy

POST /deployments   {"name": "journal-entry-review-live", "frozen_domain_package_id": 1, "runtime_port": 8410}

The platform extracts the package and runs docker compose up --build -d for it. Poll GET /deployments/{id} until status is running (about 20 s) or failed (operation_log carries the build output). GET /deployments/{id}/health and the container's own GET /identity both answer with the substrate identity. Stop, start and tail logs with the /deployments/{id}/… routes in the API walkthrough §11.

To run the container elsewhere, download the package (GET /deployments/{id}/download) and docker compose up it on the target host; no platform is needed there.

3. Adjudicate

Directly against the container:

curl -X POST http://host:8410/verify -H 'Content-Type: application/json' \
  -d '{"candidate_text": "A manual entry requires a controller approval"}'

The field is candidate_text; one claim per line. Each row carries verdict, endpoints, endpoints_asserted, predicate, passive, negated, asserted_by, asserted_source, grounding, contradictions, demotion_reason and the policy disposition with its matched rules — the same fields the SDK path reports, so a verdict is checkable, not just a label.

Through the platform (POST /deployments/{id}/verify, same body, your bearer token) you get the container's reply unchanged, substrate_identity_mismatch, and a signed evidence package for the exchange; add expectations and the platform reports expected-versus-actual per claim.

4. Verify evidence offline

curl -s https://platform/api/evidence/public-key            # key_id to pin
curl -s https://platform/api/evidence/verifier > verify_evidence_package.py
python verify_evidence_package.py evidence-<id>.json --pin-key <key_id>

Ten checks (format, signature, key, issuer pin, payload hash, candidate-text hash, identity record); exit 0 only when all pass. A package with one altered character fails. See evidence packages and policy for what a signature does and does not establish: integrity and attribution, never the truth of the evidence.

5. Operate

What it does not do

No memory, no planning, no observation, no learning, no authority beyond the policy baked into it. The verdict is a directed, typed assertion check against the frozen corpus, not truth; the register states per capability what is qualified and what is not (evidence.evaluate is not qualified for unattended approval decisions).