QR Trust Network Contracts¶
Date: 2026-05-17
Status: - draft reference contracts - non-normative - intended for implementation planning and local validation only
Purpose¶
These contracts turn the paper's trust model into a concrete implementation surface without pretending to define a final standard. They are the bridge between the current PoC fixtures and a production-reference QR trust network.
The core artifact chain is:
root manifest
-> delegated authority manifest
-> issuer record
-> destination policy and status event
-> verifier cache entry
-> scanner decision
Events notify verifiers that durable state changed. Events are not themselves the trusted artifacts. Consumers should fetch and verify the referenced signed artifact by ID, hash, version, and scope.
Contract Set¶
root-manifest.schema.jsondelegated-authority.schema.jsonissuer-record.schema.jsondestination-policy.schema.jsonrevocation-status-event.schema.jsonverifier-cache-entry.schema.jsonscanner-decision.schema.jsonruntime-safety-observation.schema.jsondeployment-readiness-report.schema.jsondeployment-readiness-bundle.schema.jsonverifier-profile.schema.jsonscanner-fleet-evidence.schema.jsonios-provider-profile-evidence.schema.jsoncross-surface-qr-evidence.schema.jsonreference-network-adoption-stage.schema.jsonsigning-custody-audit-export.schema.jsonworker-operations-evidence.schema.jsonrestore-automation-evidence.schema.jsonpackaged-deployment-approval-evidence.schema.jsonoperator-evidence-index.schema.jsonproduction-evidence-requirements.schema.jsonevent-envelope.schema.jsonkey-rotation-policy.mdsigner-recovery-runbook.mdmanaged-signing-custody-deployment-policy.mdsigning-custody-audit-export.mdartifact-publication-runbook.mdpostgres-migration-deployment-policy.mdreference-postgres-schema.sqlnats-subjects.mdscan-time-validation-sequence.mdruntime-safety-provider-deployment-policy.mddeployment-readiness-operator-guide.mdscanner-decision-http-runtime.mdverifier-profile-distribution.mdscanner-fleet-evidence.mdios-provider-profile-evidence.mdcross-surface-qr-evidence.mdreference-network-adoption-stage.mdworker-operations-evidence.mdrestore-automation-evidence.mdpackaged-deployment-approval-evidence.mdoperator-evidence-index.mdproduction-evidence-requirements.mdproduction-evidence-private-handoff.mdproduction-evidence-closure-bundle.mdproduction-adoption-gap-map.mddeployment-readiness.evidence.example.jsondeployment-readiness.production.env.examplereference-network-adoption.evidence.example.jsonreference-network-adoption.production.env.example
Design Rules¶
- Issuer identity is root-scoped:
(root_program_id, delegated_authority_id, issuer_id). - Domain validation proves destination control. It is not business identity by itself.
- Lack of enrollment is not proof of maliciousness.
- Positive scanner decisions require issuer legitimacy, destination binding, runtime safety, and acceptable cache freshness.
- Runtime safety unavailable or stale must not produce a strong green state.
- Scanner decisions should expose user-facing color, reason codes, domain fingerprint, and a short decision path.
- Deployment readiness should stay explicit: reference drills may warn on
operator-owned controls, but production mode must block until source-of-truth,
propagation, custody, runtime safety, persistence, and runbook ownership are
represented. Local readiness reports should be generated under
local/and treated as environment-specific operator handoff artifacts, not committed network contracts.deployment-readiness-operator-guide.mddefines the current review rule and environment inputs for that handoff.deployment-readiness.evidence.example.jsonshows the evidence-reference shape required for production pass checks: each passing control must have a reviewable label, URI, owner, and review date.deployment-readiness.production.env.exampleis intentionally fail-closed: sourcing it without replacing values should still produce a blocked production report.deployment-readiness-bundle.schema.jsondefines the machine-readable handoff manifest that fingerprints the local readiness report, Markdown summary, production env template, evidence map, operator guide, scanner decision runtime contract, scanner-fleet evidence packet, cross-surface QR evidence packet, worker-operations evidence packet, and restore-automation evidence packet, plus the packaged-deployment approval evidence packet. It also fingerprints the operator-evidence index packet that maps the readiness controls to reviewed public-safe or operator-owned evidence refs. It requires evidence packets, not only contract prose, so a readiness handoff cannot omit either the native/browser scanner fixture matrix or the same-QR evidence chain across fixture, worker, web lab, backend scanner decision, and iOS scanner surfaces. It also cannot omit the always-on worker boundary, recoverable source-of-truth evidence, or the explicit release approval chain for packaged deployment.verifier-profile.schema.json,scanner-fleet-evidence.schema.json,ios-provider-profile-evidence.schema.json, andcross-surface-qr-evidence.schema.jsonmake the deployed-scanner boundary schema-backed: the active profile fingerprint, scanner-decision endpoint, minimum green/orange/red fixture matrix, native provider-profile import and settings states, hold-to-open evidence, cross-surface decision consistency, and privacy posture are now validated examples rather than prose-only promises. The scanner profile, scanner-fleet evidence, provider-profile evidence, and cross-surface evidence packets are also exercised bynpm run verifier-profile:distribution-smoke,npm run scanner-fleet:evidence-smoke,npm run ios-provider-profile:evidence-artifacts-status, andnpm run cross-surface:evidence-smoke, which prove profile distribution, profile binding, fixture coverage, native provider-profile evidence readiness, hold-to-open rules, shared artifact consistency, and redaction fail closed before native capture automation exists. Usenpm run ios-provider-profile:evidence-artifacts-checkonly when the native provider-profile screenshots and accessibility traces are expected to be present. The bundle is a review index, not independent proof that a deployment remains production-ready.reference-network-adoption-stage.schema.jsonis the claim-language guard: stage 0 is local proof, stage 1 is a single-operator pilot, stage 2 is a multi-authority reference, and stage 3 is an ecosystem candidate. Required stage boundaries block missing claims, future-stage gaps warn inreference_onlymode, andproduction_candidatemode cannot carry warnings. Stage 1 now requires a publication-worker-backed signing custody audit export so custody evidence is public-safe and reviewable, while managed KMS/HSM signing custody remains a stage 3/product-candidate obligation. Generate the local adoption-stage handoff withmake network-adoption-stage-report; the output belongs underlocal/because it reflects the current environment and evidence set, not a committed network contract. Usereference-network-adoption.production.env.exampleas the fail-closed input template for stage 3 checks, andreference-network-adoption.evidence.example.jsonas the canonical evidence map shape for a production-candidate drill. Adoption-stage boundaries now expose anevidence_tier:reference_backedfor repository docs/tests,operator_backedfor operator-ownedops://qrtrust/evidence, andunattachedfor missing evidence.make network-adoption-stage-production-drillproves the gate can produce a clean production-candidate report only when every modeled boundary is explicitly enabled, operator-backed, and covered byexamples/operator-evidence-index-production-candidate.json.production-adoption-gap-map.mdmaps each paper layer to the current reference surfaces, production obligations, and evidence required before a deployment can be treated as more than a local PoC. - Worker operations evidence should keep the always-on runtime boundary
reviewable.
worker-operations-evidence.schema.jsonbinds the artifact publication worker, event-outbox worker, verifier-cache read-model worker, and scanner decision runtime to their authority boundaries, smoke scripts, monitoring references, and replay/recovery drills. A reference drill may use docs-backed evidence, but a production candidate must mark every componentproduction_readyand must not include private material markers. - Restore automation evidence should stay separate from general operator
confidence prose.
restore-automation-evidence.schema.jsonbinds scheduled backup creation, scratch restore completion, migration rollback rehearsal, and operator failover handoff to explicit command refs, evidence refs, backup artifact metadata, and scratch-only guardrails. A reference drill may cite committed docs and smoke scripts, but a production candidate must cite operator-ownedops://qrtrust/evidence and must not expose secrets or destructive restore shortcuts. - Packaged deployment approval evidence should stay separate from readiness
booleans.
packaged-deployment-approval-evidence.schema.jsonbinds the deployable artifact fingerprint, contract smoke result, release-owner approval, security review, operations review, and rollback acceptance to explicit refs. A reference drill may cite committed docs and smoke scripts, but a production candidate must cite operator-ownedops://qrtrust/approvals, provenance, promotion logs, and rollback records. - Production evidence requirements should describe minimum proof obligations,
not carry the proof itself.
production-evidence-requirements.schema.jsonnames the twelve required operator controls, minimum review roles, retention posture, and artifact classes for a production-candidate claim. Actual production evidence remains in operator-ownedops://qrtrust/stores and is referenced later by operator evidence indexes, readiness handoffs, or release packets. - The production evidence collection template should turn those obligations
into operator-fillable slots without pretending the public repo contains
production proof.
make network-production-evidence-collection-templatewrites a local JSON and Markdown checklist with one placeholder per required artifact class. Operators replace those placeholders with reviewedops://qrtrust/refs in their private evidence store before updating a production-candidate operator evidence index. - Production-candidate operator evidence refs must carry the review role that
satisfies the matching requirement. The gap report counts only
ops://qrtrust/refs whosereview_rolematches the control'sminimum_review_role; public-safe reference-drill refs remain useful for demos, but they cannot satisfy a production-ready claim. Theoperator-evidence-index.schema.jsoncontract mirrors this boundary:production_candidateindexes require every control to beoperator_backed, every evidence ref to use theops://qrtrust/scheme, and every evidence ref to name its reviewer role. - The reference-network handoff bundle fingerprints the generated production evidence collection template and gap report alongside adoption, readiness, and operator evidence indexes. That makes missing operator-owned refs visible during review without converting a public local report into production proof. The handoff keeps the general reference operator evidence packet separate from the production-candidate operator evidence packet and verifies that the collection template matches the production requirements and that the production evidence gap report matches the production requirements plus that production-candidate index. A stale collection template, stale gap report, or mismatched evidence index should fail before a reviewer receives the bundle.
- The production evidence intake report is the final pre-review gate for the operator packet. It rejects incomplete gap reports, stale template or gap inputs, placeholder refs, duplicate evidence URIs, and unsatisfied role-qualified controls. Passing intake means the packet is ready for human review; it is not a production approval.
- The private production evidence handoff is the operator-owned workflow for
filling the missing
ops://qrtrust/refs outside this repository.make network-production-evidence-private-templatewrites an ignored starter template, andmake check-network-production-evidence-private-indexvalidates a configured private operator evidence index while omitting ref URIs and evidence bodies from its output. The public repo owns the contract and checker; operators own the evidence store, retention, access control, and production approval. - The production evidence closure bundle is the final public-reference operator
handoff. It combines the requirements, collection template, gap report, and
intake report into a local JSON/Markdown bundle that lists the remaining
private
ops://qrtrust/refs to collect. It does not contain production evidence and cannot satisfy vendor KMS/HSM, restore, broker, or release approval obligations by itself. - Managed signing must be auditable without exporting secrets.
signing-custody-audit-export.schema.jsonandsigning-custody-audit-export.mddefine the public-safe evidence boundary for custody-backed artifact signing. The export records artifact hashes, signer/key scope, managed provider references, provider audit IDs, automation identity, and publication result counts while rejecting private material markers and fixture-only secret references. - One-time and reusable QR usage policies are different. Replay blocking should apply only when policy requires one-time use.
- Root and delegated-authority signer keys are scoped records. A verifier should resolve the signer to an active key, accepted algorithm, and expected governance scope before accepting a status artifact.
- Destination policy publication should be gated by issuer-scoped domain-control
proof for every named approved host. Owning
example.comdoes not silently authorizecheckout.example.comunless the policy explicitly permits subdomain inheritance.
The reference service package now includes an executable domain-proof boundary
for the issuer_domain_proofs table. The boundary can say that a verified DNS,
.well-known, delegated platform, enterprise-directory, payment-processor, or
manual-review proof supports destination binding for an approved host. It also
proves the negative rule: domain control cannot make an inactive issuer
legitimate, cannot rescue a host outside destination policy, and cannot be
presented as business identity by itself. A Postgres-shaped domain-proof store
now reads issuer-scoped proof rows from issuer_domain_proofs and feeds that
same boundary, so the table contract is exercised before live enrollment
automation exists.
A destination-policy publication gate now sits above that boundary. It checks
whether an active issuer has verified domain-control evidence for every host in
the policy before the policy is publishable. The gate is intentionally stricter
than scan-time lookup: pending, expired, or missing proofs block publication;
verified parent-domain proof supports subdomain publication only when the
destination rule explicitly allows subdomains. This keeps enrollment automation
from turning domain control into identity proof while still making destination
binding operational. The gate is now enforced by a guarded destination-policy
publisher, not only by a standalone evaluator: a blocked policy does not write
an artifact and does not emit a publication event. The publisher also fails
closed when the issuer enrollment namespace and destination-policy namespace do
not match exactly. Generic artifact-publication queue workers should wrap their
base publisher with the destination-policy-aware publisher before processing
destination_policy work items. In that mode, non-policy artifacts still flow
through the generic publication path, but destination-policy rows are decoded
back into their projection, resolved against issuer enrollment plus domain-proof
context, and marked failed without an artifact or event if the gate rejects
them.
The reference Postgres context resolver makes that queue path concrete: it
loads issuer enrollment from issuers, loads issuer-scoped domain proofs from
issuer_domain_proofs, and fails closed when the issuer row is missing before
the guarded publisher is allowed to evaluate the policy.
Implementation Use¶
Phase 1 should validate the existing governance fixtures against these schemas. Phase 2 should generate signed artifacts from service state and validate those same artifacts before publication.
The governance publisher now has an explicit artifact-input planning boundary:
planReferenceGovernancePublication returns the ordered root manifest,
delegated authority manifest, issuer record, and destination policy publication
inputs before any store, queue, or event bus is touched. That keeps the
authority decision about what should be published separate from the transport
mechanism that publishes it.
The Postgres governance publication source makes the same boundary concrete for
durable state: makePostgresGovernancePublicationSource reads one active
root/delegated-authority/issuer/destination-policy bundle from Postgres and
turns it into the same ordered artifact inputs. Postgres remains the authority;
publication workers and NATS still only transport the resulting artifacts.
The authority publication service is the first source-to-publication facade on
top of that boundary. makeAuthorityPublicationService asks the Postgres source
for the active governance bundle, publishes the root manifest, delegated
authority manifest, issuer record, and destination policy in order, and returns
the artifact IDs plus event types as operator evidence. It does not introduce a
new source of trust; it only connects durable authority rows to the existing
artifact publication surface.
Run the draft contract smoke check with:
make check-network-contracts
make check-network-adoption-stage
make check-network-signing-custody-audit-export
make check-network-worker-operations-evidence
make check-network-restore-automation-evidence
make check-network-packaged-deployment-approval-evidence
make check-network-operator-evidence-index
make check-network-production-evidence-collection-template
make check-network-production-evidence-closure-bundle
make check-network-production-evidence-intake
make check-network-reference-handoff-bundle
That check now validates the deployment-readiness examples semantically, not
only by required fields. A report cannot claim production readiness while still
listing blocking checks, reference reports cannot hide production warnings,
production pass checks must carry evidence references, and non-pass checks must
carry remediation text.
The handoff bundle example is also semantically checked: it must identify
itself as an operator handoff, summarize a valid readiness-report status, carry
the canonical file roles exactly once, fingerprint every file entry, and include
review notes for the operator.
The adoption-stage example is also semantically checked: it must keep the
canonical stage-gate boundary order, match stage number to stage name, keep
blocking and warning summaries synchronized with boundary statuses, require
evidence references on passing boundaries, and fail closed when a stage or
production-candidate claim is overstated.
The worker-operations example is semantically checked as well: it must keep the
canonical worker order, preserve Postgres/NATS/cache/scanner authority
boundaries, require monitoring signals and replay/recovery drills, reject unsafe
evidence refs, reject misbound signal evidence, and fail closed if a
production-candidate packet includes reference-only workers.
The restore-automation example is semantically checked too: it must keep the
canonical drill order, prove backup, scratch restore, rollback rehearsal, and
operator failover handoff references, reject private material, enforce
scratch-only restore targets, and require operator-owned refs for production
candidate packets.
The packaged-deployment approval example is also semantically checked: it must
keep the canonical approval-gate order, prove artifact fingerprinting, contract
smoke success, release/security/operations approval, rollback acceptance,
evidence refs, and reviewer ownership, reject private material, and require
operator-owned refs for production candidate packets.
The operator-evidence index example is semantically checked: it must enumerate
the canonical readiness controls in order, keep every evidence ref public-safe,
require reviewed evidence dates, and require ops://qrtrust/ refs before a
production-candidate claim. The production-candidate operator index fixture also
anchors the adoption-stage production drill by covering every
reference-network-adoption.evidence.example.json ref.
The reference handoff smoke keeps the final reviewer bundle honest: it rebuilds
the production-drill handoff, then proves that a reference-only operator index
and stale production evidence collection template or gap report are rejected
before the bundle can be handed to reviewers.
The production evidence intake smoke checks the same pre-review boundary more
directly: it blocks the current example packet while the gap report is
incomplete, accepts a synthetic complete packet, and rejects placeholder,
duplicate, or stale evidence inputs before any reviewer handoff.
The first service package should treat these schemas as the shared boundary between:
- Postgres source-of-truth records
- artifact publication workers
- verifier cache sync
- scanner decision APIs
- iOS and browser scanner clients
reference-postgres-schema.sql is a draft source-of-truth schema for the
network services. It is idempotently applyable through
make apply-network-reference-schema for local shared-infra and small-network
reference deployments. The preferred local deployment command is
make apply-network-migrations, which records the applied checksum in
qr_trust.schema_migrations and fails on drift. After applying it, use
make check-network-migrations as the read-only pre-worker gate; it verifies
the ledger, migration checksums, and expected table inventory without mutating
the database. postgres-migration-deployment-policy.md defines the current
reference posture for those controls: additive/idempotent migrations, checksum
drift detection, backup-before-apply, read-only status gates, and
restore-or-roll-forward rollback instead of destructive down migrations. These
commands remain non-normative; production deployments still need packaged
migration ownership, approval, backup execution, and operator-owned restore
automation evidence. The
reference schema exists so the service design can be reviewed against durable
root, authority, issuer, policy, cache, runtime, decision, and event-outbox
tables before implementation.
The schema keeps public contract identifiers as text, not generated UUIDs.
Examples include artifact_id, status_event_id, event_id, and scanner
decision_id. Internal row IDs may still use UUIDs, but durable trust-network
references must round-trip with the JSON contracts.
The first TypeScript persistence boundary is intentionally driverless. It builds SQL statements and values in the order a later Postgres transaction should use: published artifacts, derived status rows, event outbox rows, verifier-cache projections, and scanner decisions.
The artifact_publication_work_items table is the first Postgres queue
contract for source artifact publication. Rows carry the canonical artifact
JSON plus the event metadata needed to publish through the artifact publication
port. Workers claim rows with FOR UPDATE SKIP LOCKED, write immutable
artifacts, emit the publication event through the event-bus boundary, and mark
each source row completed or failed. This keeps source artifact publication
separate from downstream event-outbox propagation.
That queue now has a deployable supervisor/runtime boundary. In runtime mode,
artifact publication uses a Postgres-backed event bus that enqueues publication
events into qr_trust.event_outbox instead of relying on in-memory delivery.
Publication event IDs are deterministic from artifact ID, hash, type, and
version, so a retry after a post-publication marking failure does not create a
second logical event for the same immutable artifact.
artifact-publication-runbook.md defines the current operator sequence for
schema apply, worker startup, propagation handoff, queue inspection, failure
review, and safe retry.
The first verifier-cache materialization boundary now turns a verified artifact chain into a schema-shaped cache entry: root manifest, delegated authority manifest, issuer record, destination policy, and active status event. The cache entry remains derived state. Source artifacts and their hashes stay the auditable authority, while the materialized issuer and destination-policy projections feed scanner decisions and the Postgres persistence mapping.
The first verifier-cache read-model worker boundary consumes those already published artifact refs, fetches the source artifacts through the artifact-store port, materializes the cache entry, and persists only derived read-model rows: verifier-cache entries and optional scanner proof decisions. This keeps source publication, queue propagation, and cache derivation as separate operational steps.
The verifier_cache_work_items table is the first Postgres queue contract for
that derived read model. Queue rows contain only verifier ID, source artifact
refs, materialization time, and optional scanner probes. Workers claim rows with
FOR UPDATE SKIP LOCKED, write derived verifier-cache/scanner-decision rows,
then mark the queue row completed or failed. The queue does not authorize source
trust state and does not make NATS or Redis authoritative.
The first Postgres-shaped artifact-store adapter is also driverless. It uses the
same published_artifacts table contract for artifact upserts and artifact ID
lookups, so publication and verifier-sync code can keep depending on the
ArtifactStore port before a live database driver is introduced.
The first live Postgres driver boundary now adapts pg clients and pools to the
same statement, artifact lookup, and transaction ports. It still uses local
smoke tests rather than a running database, but the transaction contract is now
explicit: begin, write/read, commit on success, rollback on failure, and release
the client in both paths.
The first Postgres trust-key registry adapter stores signer scope, algorithm, public verification material, and key lifecycle status behind the same registry port used by the signature-verification service. This keeps signed key revocation and rotation in durable trust state instead of treating verifier key lookups as local fixture data.
key-rotation-policy.md defines the first operational policy for root and
delegated-authority key rotation. It is intentionally executable in the
TypeScript reference package so planned overlap, emergency revocation, and
verifier-cache refresh behavior stay testable rather than becoming prose-only
guidance.
signer-recovery-runbook.md defines the first operational response path for
root, delegated-authority, issuer, and signing-service compromise. It keeps the
blast radius scoped, requires durable recovery artifacts before verifier cache
mutation, and maps unresolved recovery state to scanner-visible orange or red
instead of exposing raw key ceremony detail to ordinary users.
managed-signing-custody-deployment-policy.md defines the first deployment
boundary for KMS/HSM or managed-key signing. It keeps private keys outside
normal verifier and worker processes, requires scope and lifecycle checks before
signing, and treats provider audit IDs as operator evidence rather than scanner
state.
An optional live Postgres smoke can now apply reference-postgres-schema.sql to
a disposable database, seed the minimum reference source rows, persist the
governance publication batch, and read the root artifact back through the same
artifact-store port. It is not part of the default checks because it resets the
qr_trust schema.
The first NATS propagation boundary is also driverless. It maps published event envelopes to subject names, JetStream stream names, idempotency headers, and envelope-only payloads before a live broker adapter sends anything.
A live JetStream publisher port now wraps that same boundary without adding
NATS as an authority. The port takes an injected broker publisher, sends the
already-normalized subject and envelope payload, passes the Nats-Msg-Id
idempotency header, and records only accepted messages. Durable state and retry
ownership still belong to Postgres plus qr_trust.event_outbox.
A local JetStream broker smoke now creates or updates the three reference
streams and publishes the deterministic reference event set through the real
broker. The matching live worker smoke persists those events into
qr_trust.event_outbox, claims them from Postgres, publishes them to JetStream,
and verifies the durable rows are marked published.
An event-outbox publisher boundary now accepts Postgres-shaped outbox rows, validates the embedded event envelope, publishes valid rows through the same JetStream sink, and reports per-row outcomes.
An event-outbox worker boundary now sits above that publisher. The worker
claims pending rows or stale publishing rows with for update skip locked,
sets a bounded claim expiry, calls the publisher only after the source
transaction has committed, marks accepted rows published, and marks malformed
rows failed for operator review. This keeps replay, retry, and failure
ownership in Postgres while keeping NATS in the propagation role.
The live authority-publication outbox drill now closes the source-to-transport
seam for governance state. It starts from live Postgres source-of-truth rows,
publishes root, delegated-authority, issuer, and destination-policy artifacts,
persists the artifact rows, enqueues four qr_trust.event_outbox rows, and then
uses the live outbox worker to propagate envelope-only governance messages to
NATS JetStream. This keeps artifact bodies in the authority store and treats
NATS as distribution, not source of truth.
make check-network-live-authority-outbox
This target is intentionally opt-in and reset-guarded. It drops and reapplies
the disposable qr_trust schema in the configured QR Trust database.
The live verifier-cache read-model drill now closes the next seam: it starts
from the same live authority-published governance artifacts, adds a signed
issuer-status artifact, queues one verifier-cache work item, claims it through
the Postgres-backed read-model queue, and writes derived
qr_trust.verifier_cache_entries plus qr_trust.scanner_decisions rows. The
worker records source artifact hashes and does not republish source artifacts
or enqueue additional outbox events. This keeps verifier cache as derived state,
not authority.
make check-network-live-verifier-cache
This target is also opt-in and reset-guarded. It drops and reapplies the
disposable qr_trust schema in the configured QR Trust database.
The live scanner-decision drill closes the scanner-side seam. It starts from
the same authority-published governance artifacts, materializes one
verifier-cache entry through the read-model worker, then creates scanner
decision services whose cache ports read only
qr_trust.verifier_cache_entries. The direct service path and the packaged
HTTP runtime both use that derived cache plus runtime safety observations. The
drill asserts that scanner decisions do not republish source artifacts or treat
source governance tables as scanner-owned state, and that the HTTP runtime
persists only scanner-decision evidence.
make check-network-live-scanner-decision
This target is opt-in and reset-guarded for the same reason as the live
verifier-cache drill: it resets the disposable qr_trust schema in the
configured QR Trust database. It verifies GET /healthz, a valid
POST /scanner/decisions response, malformed-destination rejection, the
persisted scanner-decision row, and the scanner-decision event-outbox row.
The scanner-decision HTTP runtime packages that cache-read seam into a
scanner-facing service boundary. POST /scanner/decisions accepts a QR payload
and returns the scanner-decision contract, while GET /healthz exposes only a
small runtime readiness response. The runtime reads verifier-cache state and
runtime-safety observations; it does not query source governance tables or
publish authority artifacts during a scan.
make check-network-scanner-decision-http-runtime
verifier-profile-distribution.md documents how scanner clients receive the
managed trust profile that binds them to a root program, verifier cache,
scanner-decision endpoint, runtime safety policy, and freshness rules. The QR
payload is not allowed to supply those values by itself.
verifier-profile.schema.json and
examples/verifier-profile-reference.json provide the current
machine-readable reference shape.
scanner-fleet-evidence.md documents the evidence packet expected before a
scanner population is treated as deployment-ready: app build, active profile
fingerprint, endpoint fingerprint, fixture matrix, green/orange/red traces,
hold-to-open evidence, history evidence, and decision records without secrets.
scanner-fleet-evidence.schema.json and
examples/scanner-fleet-evidence-reference.json provide the current
machine-readable reference shape. The smoke checker enforces the minimum
scanner fixture matrix, row-to-fixture consistency, active profile fingerprint
binding, non-green hold-to-open evidence, non-empty reason codes, compact
redacted domain fingerprints, screenshot/history/accessibility references,
unique evidence artifact references, red-outcome no-open behavior, and a
no-secrets privacy posture. npm run scanner-fleet:evidence-artifacts-status
reports whether the referenced native evidence files are present; the strict
npm run scanner-fleet:evidence-artifacts-check gate is reserved for the point
where the iPhone capture package is expected to be complete.
An event-outbox metrics boundary now exposes the minimum operational evidence needed before running that worker continuously: pending propagation lag, publishing rows with expired claims, failed-row counts, retryable failed rows, maximum attempts, and a bounded failed-row sample for operator review.
An event-outbox supervisor boundary now wraps the worker and metrics ports. It does not own Postgres or NATS directly. It repeatedly calls the worker with bounded polling, stops on idle limits or shutdown signals, aggregates publish counts, and returns the latest metrics health so an operator surface can show whether propagation is healthy, degraded, or blocked.
The running Python verifier now exposes a narrow operator bridge for that same
outbox telemetry. When QRTRUST_NETWORK_DATABASE_URL is configured,
/verifier/status includes the outbox health, status counts, lag, failed rows,
and database label. If the network database is absent or unreachable, the
endpoint reports unavailable instead of failing the verifier runtime status.
The first signature-verification boundary now signs and verifies status-event artifacts with Ed25519 over canonical JSON bytes. Signature transport metadata is excluded from the signed payload, so changing status, reason, target, signer, or scope after signing invalidates the event. A status event can mutate verifier cache state only when its signer resolves to an active root or delegated authority trust-key record with accepted algorithm, matching scope, public-key material, and a valid signature.
Status events may also target trust_key records. Verifiers must apply those
key-lifecycle events only after the status event itself passes signature
verification; after application, a suspended, revoked, or expired key must no
longer authorize future verifier-cache mutations.
nats-subjects.md maps durable state changes to event subjects. It keeps the
event bus in the propagation role: useful for verifier synchronization, but not
authoritative trust state.
scan-time-validation-sequence.md describes the online verifier path from a
decoded QR payload to the scanner-visible decision returned to browser and iOS
clients.
The PoC /scanner/decisions response now includes a contract projection that
matches the scanner-visible decision contract shape: decision color, risk score,
reason codes, hold-to-open requirements, cache freshness, destination
fingerprint, and the four-layer trust path. The surrounding API response remains
UI-friendly, while contract is the handoff artifact for acceptance checks,
review packets, and future service integration.
runtime-safety-provider-deployment-policy.md defines the deployment boundary
for live redirect, reputation, safe-browsing, and TLS/HTTPS inspectors. Runtime
safety is scan-time evidence only: it may downgrade or block a decision, but it
cannot enroll issuers, approve destinations, or make an unknown issuer green.
runtime-safety-observation.schema.json defines the persistable provider
verdict shape for scan-time destination evidence. It is intentionally not a
source-of-truth artifact: each observation records provider identity,
destination fingerprint, verdict, reason codes, privacy posture, and a
source_of_truth: false decision role before scanner decisions combine it with
issuer, destination, and cache state.
The first runtime-safety examples now cover the two important non-green verified-issuer cases:
- runtime risk: issuer and destination binding pass, but present-time safety reports elevated risk, so the scanner returns orange with hold-to-open.
- runtime block: issuer and destination binding pass, but present-time safety blocks opening, so the scanner returns red.
- provider observations: clear, risky, blocked, and unavailable runtime verdict examples that can be stored or audited without granting trust by themselves.
Destination binding remains terminal. A mismatched destination must not be rescued by a later runtime signal.