Scanner Decision HTTP Runtime¶
Date: 2026-05-20
Status: - draft reference contract - non-normative - intended for local runtime validation and deployment review
Purpose¶
The scanner-decision HTTP runtime is the narrow service edge that scanner clients call at scan time. It adapts HTTP requests to the scanner-decision service and reads only the verifier cache plus runtime-safety provider state.
It is not an authority service. It must not decide issuer enrollment, destination policy publication, key custody, or governance delegation from source tables during a scan. Those decisions are made upstream and projected into verifier-cache state before the scanner asks for a decision.
Runtime Endpoints¶
GET /healthz¶
Returns a small readiness response for load balancers and smoke tests.
Example response:
{
"service": "qrtrust-scanner-decision-runtime",
"status": "ok",
"verifier_id": "verifier:reference-http-runtime",
"decisions_endpoint": "/scanner/decisions"
}
POST /scanner/decisions¶
Accepts a QR payload and returns a scanner-decision.schema.json response.
Example request:
{
"payload": "https://acme.example/pay",
"issuer_hint_host": "acme.example",
"observed_at": "2026-05-20T18:02:00.000Z"
}
Rules:
payloadis required and must be a non-empty string.issuer_hint_hostis optional and should be the host implied by a trusted caption, app context, or generator hint when available.observed_atis optional and must be an ISO-8601 timestamp when supplied.- Both snake-case and camel-case field names are accepted for scanner clients that cannot easily normalize request JSON.
Source-of-Truth Boundary¶
The runtime reads:
qr_trust.verifier_cache_entriesthrough the verifier-cache port- runtime-safety provider observations through the runtime-safety port
The runtime writes:
- scanner decision rows through the persistence port
- scanner decision events through the event-bus port
The runtime must not:
- query root, delegated-authority, issuer, or destination-policy source tables during a scanner request
- publish source governance artifacts
- enqueue NATS propagation events as part of the request path
- treat Redis or NATS as authoritative trust state
Postgres remains the durable authority for trust-network state. NATS is a propagation path. Redis may be a hot-path optimization, but a Redis miss cannot be treated as a governance decision.
Failure Posture¶
The HTTP adapter should fail closed at the transport boundary:
- malformed JSON returns
400 - missing or invalid request fields return
400 - syntactically malformed destinations return
422 - unexpected runtime failures return
500
The scanner-decision service should still preserve the paper's user-visible discipline:
- unknown or unavailable trust state maps to orange, not green
- explicit destination mismatch, block state, or an expired envelope
(
freshnessblock, causeobject-expired) maps to red - runtime safety unavailable must not produce a strong green state
- positive green decisions require issuer legitimacy, destination binding, runtime safety, and acceptable verifier-cache freshness
Environment¶
The reference runtime uses these inputs:
QRTRUST_NETWORK_DATABASE_URL=postgres://publisher:publisher@127.0.0.1:5432/qrtrust
QRTRUST_SCANNER_DECISION_HOST=127.0.0.1
QRTRUST_SCANNER_DECISION_PORT=8090
QRTRUST_SCANNER_VERIFIER_ID=verifier:reference-http-runtime
The production verifier ID should identify the scanner fleet or verifier cache profile whose derived state is being used.
Verification¶
Run the deterministic HTTP smoke without Postgres:
Run the Postgres-backed scanner decision drill:
That target resets the disposable QR Trust schema, publishes the reference
governance artifacts, materializes verifier-cache state, then exercises both
the direct scanner-decision service and the HTTP runtime. It verifies
GET /healthz, a valid POST /scanner/decisions, a malformed-destination
422, and the persisted scanner-decision/event-outbox evidence.
Run the local packaged runtime against a configured network database:
cd network && QRTRUST_NETWORK_DATABASE_URL=postgres://publisher:publisher@127.0.0.1:5432/qrtrust npm run scanner-decision:runtime:dev
The deployment readiness bundle fingerprints this contract so operators can review the scanner-facing runtime boundary beside the readiness report, evidence map, production environment template, and runbook.