{"schema":"viqor.conformance/v1","generated_at":"2026-08-27T00:14:24.681166+00:00","revision":"2d85160111c34f3babe005317fa7b074f0deaf75","conformant":true,"summary":{"total":30,"by_status":{"NOT_IMPLEMENTED":22,"PASS":4,"DEFERRED":4}},"checks":[{"id":"SEC-01","title":"All authorisation flows through a single choke point","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-09","verified_by":null,"trigger":null,"attestation":null},{"id":"SEC-02","title":"The resolver database role cannot write","severity":"BLOCKER","status":"PASS","work_package":"WP-03","verified_by":"tests/integration/test_tenant_isolation.py::TestResolverIsReadOnly","trigger":null,"attestation":null},{"id":"SEC-03","title":"Resolver responses are uniform across not-found states","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-23","verified_by":null,"trigger":null,"attestation":null},{"id":"SEC-04","title":"The passport renderer is injection-proof","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-16","verified_by":null,"trigger":null,"attestation":null},{"id":"SEC-05","title":"Strict CSP on every public surface","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-07","verified_by":null,"trigger":null,"attestation":null},{"id":"SEC-06","title":"MFA cannot be disabled for owner and admin","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-08","verified_by":null,"trigger":null,"attestation":null},{"id":"SEC-07","title":"Secrets never reach the log sink","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-36","verified_by":null,"trigger":null,"attestation":"There is no structured logging pipeline yet, and therefore no log sink a secret could reach through one. The specific leak that was found and fixed -- a configuration failure printing VIQOR_SERIAL_PEPPER into container startup logs -- is covered by SEC-07a and regression-tested."},{"id":"SEC-07a","title":"Startup failures do not print secrets","severity":"BLOCKER","status":"PASS","work_package":"WP-01","verified_by":"libs/viqor_core/tests/test_config.py::TestSecrets","trigger":null,"attestation":null},{"id":"SEC-08","title":"Every tenant-scoped table has forced row-level security","severity":"BLOCKER","status":"PASS","work_package":"WP-03","verified_by":"tests/integration/test_tenant_isolation.py::TestSchemaInvariants","trigger":null,"attestation":null},{"id":"SEC-09","title":"Every route is classified public or tenant-scoped","severity":"BLOCKER","status":"PASS","work_package":"WP-04","verified_by":"tests/integration/test_route_isolation.py::TestEveryRouteIsClassified","trigger":null,"attestation":null},{"id":"ID-01","title":"Serials are opaque and carriers are valid GS1 Digital Links","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-17","verified_by":null,"trigger":null,"attestation":null},{"id":"ID-02","title":"No serial collisions across 10 million generated serials","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-17","verified_by":null,"trigger":null,"attestation":null},{"id":"ID-03","title":"Serials reveal no ordering","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-17","verified_by":null,"trigger":null,"attestation":null},{"id":"INTG-01","title":"Canonicalisation is stable","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-18","verified_by":null,"trigger":null,"attestation":null},{"id":"INTG-02","title":"Signatures verify against an independent implementation","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-18","verified_by":null,"trigger":null,"attestation":null},{"id":"INTG-03","title":"The audit hash chain validates end to end","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-10","verified_by":null,"trigger":null,"attestation":null},{"id":"PER-01","title":"An archived passport still resolves","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-23","verified_by":null,"trigger":null,"attestation":null},{"id":"PER-02","title":"Lifecycle transitions fire at the policy boundary","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-31","verified_by":null,"trigger":null,"attestation":"No retention enforcement worker exists, and no passports exist to enforce against. Retention policies can be stored but not yet attached to a batch. cold_behaviour is CHECK-constrained to ARCHIVED_REACHABLE at the schema level, so the schema cannot express a policy that deletes data even before the worker exists."},{"id":"PER-03","title":"A retention policy below its statutory floor is rejected","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-15","verified_by":null,"trigger":null,"attestation":null},{"id":"GDPR-01","title":"EXIF is stripped before persistence","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-14","verified_by":null,"trigger":null,"attestation":null},{"id":"GDPR-02","title":"Scan telemetry is minimised at capture","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-26","verified_by":null,"trigger":null,"attestation":null},{"id":"CAR-01","title":"QR codes decode from print output","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-22","verified_by":null,"trigger":null,"attestation":null},{"id":"CAR-03","title":"Print packs emit every declared format","severity":"MAJOR","status":"NOT_IMPLEMENTED","work_package":"WP-22","verified_by":null,"trigger":null,"attestation":null},{"id":"API-03","title":"Resolver content negotiation","severity":"MAJOR","status":"NOT_IMPLEMENTED","work_package":"WP-23","verified_by":null,"trigger":null,"attestation":null},{"id":"ENV-01","title":"Non-production passports are marked in their signed payload","severity":"BLOCKER","status":"NOT_IMPLEMENTED","work_package":"WP-16","verified_by":null,"trigger":null,"attestation":"No passports are minted at all yet, so none can be mistaken for production. The environment value is already carried through configuration and refuses to start a production process pointed at the wrong resolver domain (Guard 1). Embedding it in the signed payload and rendering the banner land with WP-16, before any minting exists."},{"id":"ESPR-01","title":"EU DPP Registry registration","severity":"BLOCKER","status":"DEFERRED","work_package":"WP-25","verified_by":null,"trigger":"The EU DPP Registry API becomes available and the delegated act for the product group is in force. Until then RegistryClient returns NOT_REGISTERED and nothing in the mint path assumes otherwise.","attestation":"VIQOR passports are not registered in the EU DPP Registry. Nothing in the product claims they are, the console shows registration as pending, and registry_state is NOT_REGISTERED on every passport. No mint-path decision depends on registration having succeeded."},{"id":"INT-01","title":"An exported tenant archive re-imports with signatures intact","severity":"MAJOR","status":"NOT_IMPLEMENTED","work_package":"WP-33","verified_by":null,"trigger":null,"attestation":null},{"id":"INFRA-01","title":"Object storage moves off local disk","severity":"MINOR","status":"DEFERRED","work_package":"WP-14","verified_by":null,"trigger":"The first real client dataset, or local disk crossing ~40% of the volume. Hetzner Object Storage bills from the moment the first bucket exists, so Stage 0 stays on disk.","attestation":"Media and passport payloads are stored on local disk through the viqor_storage abstraction. No S3 backend exists yet, so no bucket exists and nothing is billed. The interface is in place, so the move is a configuration change plus one backend implementation."},{"id":"INFRA-02","title":"Object lock / WORM retention","severity":"MINOR","status":"DEFERRED","work_package":"WP-14","verified_by":null,"trigger":"An auditor or customer contract requires demonstrable WORM, or the first regulated production batch is minted. Cannot precede INFRA-01, since object lock only exists on the S3 backend.","attestation":"Immutability is enforced by application rule -- append-only tables, no DELETE granted to any role -- and not yet by storage-level object lock. This is a weaker guarantee than WORM and should not be described as WORM to a customer or auditor."},{"id":"INFRA-03","title":"Cloudflare edge","severity":"MINOR","status":"DEFERRED","work_package":"WP-29","verified_by":null,"trigger":"A client's product goes viral (thousands of scans per minute), or clients appear outside Central Europe. Staying off Cloudflare preserves the one-German-processor, no-US-subprocessor posture. If adopted, the Hetzner firewall MUST be locked to Cloudflare's published ranges.","attestation":"TLS terminates at Traefik, DNS is Hetzner, caching is nginx proxy_cache, and DDoS protection is Hetzner's network-level filtering. One German processor, one AVV, no US subprocessor."}],"violations":[],"unverified_in_this_run":["SEC-02: not verified in this run (requires database)","SEC-08: not verified in this run (requires database)"]}