Skip to content
docs
Arxo ↗

Security and privacy

For LLMs8 sections

This page inventories what the deadline example handles, where it rests, and what leaves the machine. The design keeps the surface small: four fixed fields in, a rendered answer and a capture file out, nothing else.

Output
docs/build/examples/deadline-app

The application handles exactly four user-supplied strings:

FieldExampleSensitivity
eventDate2026-03-06a date the user typed
durationDays14a count the user typed
candidateEnd2026-03-20a date the user typed, optional
legalTime2026-09-17the date the law is projected on

There is no account, no session, and no profile. The dates carry no personal detail beyond what the user typed into the form; the application adds the time zone (Europe/Berlin), the deadline policy (urn:de:corpus:clir:bgb-fristen#BGB_FRISTEN_TAG), and the model pin (de.bgb.fristen@0.1.0) itself.

Derived data — facts, queries, answer documents, views, captures — stays on the machine that runs the server or the command line. Nothing is sent to analytics, nothing identifying is placed in the URL, and the engine runs locally (via is local).

The example call accepts the four fields above and nothing else:

Output
POST /api/deadline/evaluate 4 fixed fields only
POST /api/deadline/replay a stored capture id, never a pasted capture
GET /api/deadline/capture the stored file for one capture id

There is no predicate passthrough, no package passthrough, and no URL passthrough: the caller cannot name a relation, pick a canon, or point the server at an address. Unknown fields are refused with 400 — the server never silently drops input it does not understand. The replay call accepts the 12-hex-character id of a capture the server itself stored, re-runs the pinned case from that file, and compares — it does not execute anything the caller hands it. The download call serves the stored file bytes for one id, with the same id check before the id becomes a path segment.

Each exchange below shows the status and error string the handler returns:

Output
POST /api/deadline/evaluate
{"eventDate":"2026-03-06","durationDays":14,"legalTime":"2026-09-17"}
-> 200 {"view":{"headline":"The period ends on 2026-03-20",…},
"captureId":"e2b377c0b255"}
Output
POST /api/deadline/evaluate (one extra field)
{…,"predicate":"frist_ende"}
-> 400 {"errors":["unknown fields: predicate"]}
Output
POST /api/deadline/replay
{"captureId":"e2b377c0b255"}
-> 200 {"integrity":{"ok":true,…},"replay":{"match":true,…}}
Output
POST /api/deadline/replay (id the server never stored)
{"captureId":"0123456789ab"}
-> 404 {"errors":["unknown capture 0123456789ab"]}
Output
POST /api/deadline/replay (capture content instead of an id)
{"captureId":{"format":"deadline-app.capture/1"}}
-> 400 {"errors":["captureId must be 12 hex characters"]}
Output
GET /api/deadline/capture?captureId=e2b377c0b255
-> 200 the stored capture file (format deadline-app.capture/1)
Output
GET /api/deadline/capture?captureId=0123456789ab
-> 404 {"errors":["unknown capture 0123456789ab"]}

The trust boundary is the id: the server reads only files it wrote (captures/<id>.json), and anything that is not a stored id is a client error, never a document to execute.

validateFormInput runs before any engine call. A form with a missing event date, a non-numeric duration, a malformed candidate, or a missing legal time is rejected with a validation error; the adapter, the query builders, and the engine never see it. This order — check, then compute — is what the contract checks in the suite pin down.

Storing on the server and handing the user an archive are two different actions. Each server evaluation is stored automatically — there is no opt-out — while downloads happen only on explicit user action:

ActionComputes?Creates a server file?Hands the user an archive?
POST /api/deadline/evaluateyesyes, always: captures/<random-id>.jsonno — answers {view, captureId}
Form Save summary buttonnono (already stored)downloads the {view, captureId} answer JSON (a summary, not a replayable archive)
Form Download capture buttonnono (already stored)downloads the full stored capture for the latest id
CLI evaluate without --outyesno (no server involved)no — prints the view
CLI evaluate --out fileyesnowrites the full capture to file
POST /api/deadline/replayre-runs, stores nothing newnono — answers {captureId, integrity, replay}

The two form buttons download different things on purpose. Save summary downloads the latest answer payload (view plus id): enough to show, not enough to replay elsewhere. Download capture fetches the full stored archive — frozen case, query, hashes, document bytes — the same file the evaluate call already wrote and the same file replay reads. That archive is portable: copy it to another machine with the pinned dependencies and replay it there with no access to the original server’s store. To keep a capture, keep the file; to drop one, delete the file.

A capture holds the form, the adapter version (ADAPTER_VERSION 1.0.0), the version pins, and the answer, including the canonical document as documentBase64 with its sha256 under CAPTURE_FORMAT deadline-app.capture/1. It is a complete record: enough to reproduce the answer with replayCapture, and enough to audit what was asked.

The server never overwrites a stored capture — recomputing under new pins writes a new file, as the versioning page describes. Ids are random per call (randomBytes), so repeated identical evaluations — supervisor probes included — each leave their own file; there is no deduplication. Point probe traffic at a scratch DEADLINE_APP_CAPTURES directory and rotate it, or accept the growth.

Nothing leaves the machine except by an action the user takes: submitting the form to the local server, downloading or copying a capture file, or running the command line. The application makes no outbound calls in its run path — no registry, no assistant host, no serving endpoint — and the offline page shows how to confirm that with the network disabled.

The example uses no tokens, no passwords, and no API keys. There is nothing to rotate and nothing to place in the environment except the server port. If a deployment wraps the example with authentication or TLS termination, that layer owns its own secrets; the application code reads none.

Log what identifies an answer, not the answer itself:

  • log the capture id, the statuses (COMPUTED, TRUE_ONLY, NEITHER), the rule identifiers that fired, and the three hashes;
  • do not log full answer documents or full captures by default;
  • log validation rejections with the field name and the reason, without echoing hostile payloads at length;
  • log replay mismatches with both hashes (stored and recomputed) so the difference is auditable.

Full documents belong in captures the user chose to keep, not in logs that rotate away.

Documentation for Arxo. Writings — blog.arxo.io.

Anonymous visit counts on stats.arxo.io, no cookies.