# Architecture This page maps the deadline example as built: the layers, the data path from a form submission to a stored capture, the runtime singleton, and the boundaries between browser, example server, and engine. ```text docs/build/examples/deadline-app ``` ## The data path One request travels eight steps. Each step is one module with its own exports, listed in the table below; nothing is shared between requests except the model handle described after it. 1. **Form.** The page shows four fields — the event date, the period length in days, an optional candidate end date, and the legal time — and the browser posts them to the example call. 2. **Validate.** The raw fields are checked and turned into a typed form input, or the request is rejected before any engine call runs. 3. **Facts.** The adapter turns the validated form into canon facts and a case input. It stamps its own version (`1.0.0`) so a capture records which mapping produced it. 4. **Query.** Two questions are built: a collect query that computes the end date and a truth query that checks the candidate. Both carry the legal time, the `Europe/Berlin` time zone, and the deadline policy `urn:de:corpus:clir:bgb-fristen#BGB_FRISTEN_TAG`. (Time zone, calendar data, and counting policy are three separate context elements — see the facts chapter.) 5. **Engine.** The questions run against the open model, which returns the raw answer documents. 6. **Read.** Each answer is reduced to one of four kinds: a value, a claim, not computed, or unknown. 7. **View.** The reduced answer becomes the shape the page and the API response render, including the inconclusive shapes. 8. **Capture.** The case, the pins, and the answer are stored with the canonical document bytes and their checksum. Replay later reproduces the answer and detects edited bytes; a separate step maps a report of missing premises to follow-up questions. The command line runs the same steps without the server: `evaluate` computes and stores, `replay` reproduces from a capture. ## Module table | Step | Module | Exports | Role | |---|---|---|---| | 1 | `public/index.html` | the form | collect the four fields: `eventDate`, `durationDays`, `candidateEnd?`, `legalTime` | | 2 | `src/input-schema.ts` | `validateFormInput`, `validateDraftInput`, `FormInput`, `DraftInput` | reject bad forms and drafts before compute | | 3 | `src/to-case.ts` | `ADAPTER_VERSION`, `toFacts`, `toCaseInput`, `toDraftCaseInput` | map fields to facts and case input | | 4 | `src/query.ts` | `buildCollect`, `buildTruth` | build the collect and truth questions | | 5 | `src/runtime.ts` | `openModel`, `evaluateCollect`, `evaluateTruth`, `explainWhy`, `explainDraft` | hold the model; run questions | | 6 | `src/read-result.ts` | `readCollect`, `readTruth`, `AppResult` | reduce answers to `value`, `claim`, `not-computed`, `unknown` | | 7 | `src/to-view.ts` | `toViewModel` | render any `AppResult` for display | | 8 | `src/capture.ts` | `CAPTURE_FORMAT`, `captureEvaluation` | archive captures as `deadline-app.capture/1` with `documentBase64` and `sha256` | | 8 | `src/replay.ts` | `replayCapture`, `verifyCaptureIntegrity` | reproduce answers; check document bytes | | 8 | `src/missing.ts` | `ASKABLE`, `missingFacts` | turn `whyNot` blockers into questions | | — | `src/batch.ts` | `runBatch` | stream many cases to a line report | | — | `src/check-contract.ts` | `APP_PREDICATES`, `checkContract` | test whether a model serves this app | | — | `src/server.ts` | `handleRequest`, `createServer` | serve the form and the three API calls (evaluate, replay, capture download) | | — | `src/cli.ts` | `evaluate`, `explain`, `batch`, `check-contract`, `replay` | run the flow without the server | | — | `python/deadline.py` | the same flow | mirror the flow in Python | ## The runtime singleton `openModel` opens the model once and hands the same handle to every caller: ```text open('de.bgb.fristen@0.1.0', { offline: true }) ``` The version pin makes answers reproducible; `offline: true` keeps execution local (`via` is `local`) with no network in the call path. Each evaluation builds a fresh case input per request through `toCaseInput`, so one request cannot see another request's facts: state isolation comes from fresh inputs, not from locks. Execution is sequential per request: each handler awaits its engine calls in turn. The server makes no concurrency claim beyond what `node:http` with `await` gives — requests interleave only where the runtime yields, and no request mutates state another request reads. ## Trust boundaries in words Three zones, two crossings: - **Browser.** Holds the form and the rendered answer. It is untrusted input: values may be missing, mistyped, or hostile. Nothing the browser sends reaches the engine unchecked. - **Example server.** Holds validation, the adapter, query building, the model handle, reading, view shaping, and captures. It checks the form first (`validateFormInput`), maps only the four fixed fields, and pins the model version, the policy, the time zone, and the calendar data itself — none of those cross over from the browser. - **Engine.** Holds the canon and the evaluation. It sees only typed facts and questions; it answers with statuses, proof, and hashes. The first crossing (browser to server) carries the four-field JSON request in and a view plus a capture id out; a separate download carries the full stored capture out for one id. The second crossing (server to engine) carries facts and questions in and answer documents out. Captures never cross back into the engine as trusted input: replay re-runs the pinned case and compares, and `verifyCaptureIntegrity` fails closed on edited bytes. ```text browser --(4 fields)--> server --(facts + questions)--> engine browser <--(view + capture id)-- server <--(answer documents)-- engine browser <--(stored capture file)-- server ``` ## The Python mirror `python/deadline.py` follows the same eight steps against the same pinned model. Statuses and values match the TypeScript path; the result hash and document bytes do not, so a capture is replayed by the SDK that saved it. Where a step needs `questions`, `unfold`, or `focused_truth`, the Python path reads the manifest the TypeScript side produced at author time. ## Next - [Testing: what the suite checks](/build/application/testing/)