Files
boc/QUIXZOOM_EVIDENCE_GRAPH.md
T
Bernt bae705aa97 ARCHITECTURE: NFC roadmap, edge AI, audit logging
- Add NFC ePassport roadmap (ICAO 9303, eIDAS)
- Add TensorFlow.js edge face detection (BlazeFace)
- Add structured audit logger (GDPR-compliant)
- Risk scoring support

Part of KYC Apple Native UX v1.1.0
2026-06-29 16:24:48 +00:00

8.9 KiB
Raw Blame History

quiXzoom — Evidence Graph & Verified Claim

Beslutad: 2026-06-17. Ägare: Erik Svensson. Bygger på: QUIXZOOM_VISION.md, QUIXZOOM_VERIFIED_REALITY.md, QUIXZOOM_AVO_MASTERPROMPT_V2.md


Enheten är utsagan — inte bilden, inte evidenspaketet

Det ni säljer, lagrar, fakturerar och kan bli stämda över är påståendet:

"Livbojen vid kaj 14B existerade och var i korrekt skick 2026-06-17 kl 12:22 UTC."

Det är en verified_claim. Allt annat — frames, OCR, gyrodata, liveness — är evidens för utsagan.


Claim-schemat

{
  "claim_id": "clm_9f3a8c1b",
  "claim_type": "object_existence_and_condition",
  "claim_text": "Livbojen vid kaj 14B existerar och är i korrekt skick.",
  "control_point": "lifebuoy_kaj14b",
  "knowledge_pack_id": "maritime_safety_v2",

  "trust_threshold": 0.92,
  "trust_achieved": 0.961,
  "decision": "verified",

  "evidence_bundle_id": "evb_7d2f1a9e",
  "evidence_bundle_hash": "sha256:a3f8b2...",

  "zoomer_id": "z_9981",
  "device_id": "dev_ios_xyz",
  "session_id": "sess_abc123",

  "geo": { "lat": 59.334, "lng": 18.063, "accuracy_m": 4 },
  "timestamp_start": "2026-06-17T12:20:41Z",
  "timestamp_decision": "2026-06-17T12:22:04Z",

  "signature": "ed25519:9f3a...",
  "immutable": true
}

trust_threshold ägs av kunskapspaketet — per claim-typ, aldrig globalt. decision är append-only. Korrektion sker som ny claim som refererar bakåt.


Sufficiency-funktionen — förtroende-ackumulator

Systemet samlar evidens tills trust_achieved ≥ trust_threshold. Sedan stannar det.

trust_achieved = Σ (weight_i × confidence_i × liveness_factor)

Varje evidenselement bidrar med viktad konfidens:

Element Vikt (example) Bidrar till
Visual coverage frame 0.15 Objekt existerar
OCR serial match 0.25 Objekt identifierat
Liveness Score >90 0.20 Observation äkta
GPS match ±15m 0.15 Objekt på rätt plats
App Attest valid 0.10 Enhet omodifierad
Challenge passed (per st) 0.08 Anti-spoofing
Reference match 0.07 Korrekt skick

Vikterna och trösklarna ägs av kunskapspaketet, inte av AVO-koden.

Konsekvensen

Ibland räcker 4 frames och 2 challenges. Ibland krävs 40 frames och 5 challenges. Systemet vet när det är klart — Zoomern vet det aldrig förrän det är grönt.

Sufficiency kan misslyckas

Om systemet inte når tröskeln inom:

  • Max scan-tid (konfigurerbart, default 120s)
  • Max challenges (default 5)
  • Max frames (default 600)

decision: insufficient_evidence → eskalera till manuell granskning.

Aldrig: tvinga fram ett svagt godkännande för att undvika eskalering.

{
  "claim_id": "clm_4b2e9d7a",
  "decision": "insufficient_evidence",
  "trust_achieved": 0.71,
  "trust_threshold": 0.92,
  "limiting_factor": "liveness_score_too_low",
  "escalation": "manual_review",
  "photographer_directive": null
}

Evidence Bundle — schemat

Det fullständiga, signerade paketet som claim:en refererar till:

{
  "bundle_id": "evb_7d2f1a9e",
  "claim_id": "clm_9f3a8c1b",
  "created_at": "2026-06-17T12:22:04Z",

  "liveness": {
    "score": 97,
    "signals": {
      "gyro_natural": true,
      "parallax_verified": true,
      "focus_changes": 4,
      "gps_match": true,
      "app_attest": true,
      "stream_continuous": true,
      "challenges_issued": 3,
      "challenges_passed": 3
    }
  },

  "evidence_elements": [
    {
      "element_id": "e1",
      "type": "visual_frame",
      "frame_index": 142,
      "timestamp_ms": 3820,
      "confidence": 0.97,
      "weight": 0.15,
      "contribution": 0.1455,
      "hash": "sha256:f1a2b3..."
    },
    {
      "element_id": "e2",
      "type": "ocr_extraction",
      "frame_index": 198,
      "timestamp_ms": 5180,
      "confidence": 0.94,
      "weight": 0.25,
      "contribution": 0.2350,
      "extracted_value": "SE-4821-9938-01",
      "hash": "sha256:c4d5e6..."
    },
    {
      "element_id": "e3",
      "type": "challenge_response",
      "challenge_issued_at_ms": 6200,
      "challenge_directive": "Gå ett steg bakåt",
      "challenge_class": "liveness",
      "response_detected_at_ms": 8100,
      "confidence": 0.96,
      "weight": 0.08,
      "contribution": 0.0768
    }
  ],

  "trust_accumulation": [
    { "after_element": "e1", "trust_so_far": 0.1455 },
    { "after_element": "e2", "trust_so_far": 0.3805 },
    { "after_element": "e3", "trust_so_far": 0.4573 }
  ],

  "bundle_hash": "sha256:a3f8b2...",
  "signature": "ed25519:9f3a...",
  "immutable": true
}

trust_accumulation loggar hur förtroendet byggdes upp steg för steg. Vid återgranskning kan man se exakt varför beslutet fattades — och vid vilken evidens tröskeln passerades.


Challenge-direktivets vokabulär

Designkrav: Zoomern kan aldrig avgöra om ett direktiv är guidning eller liveness-challenge.

"Flytta kameran 30 cm åt vänster."     ← kan vara guidning (framing_ok)
                                         eller challenge (liveness, kräver parallax)

"Höj kameran lite."                    ← kan vara guidning (angle_ok)
                                         eller challenge (liveness, kräver rörelse)

"Visa objektets nedre del."            ← kan vara guidning (coverage)
                                         eller challenge (liveness, kräver ny vinkel)

Samma fras, samma röst, samma UI. Challenge-klassen är intern — aldrig exponerad.

{
  "directive": "Gå ett steg bakåt",
  "directive_class": "liveness_challenge",    INTERN, visas aldrig för Zoomer
  "expected_signal": "zoom_out + parallax_change",
  "timeout_ms": 8000
}

Korrektion av en verified_claim

En verifierad utsaga är immutable. Korrektion sker som ny claim som refererar bakåt:

{
  "claim_id": "clm_4c7f2b8d",
  "claim_type": "correction",
  "corrects_claim_id": "clm_9f3a8c1b",
  "correction_reason": "Manuell granskning: serienummer OCR-fel, korrekt värde SE-4821-9938-02",
  "corrected_by": "reviewer_human_012",
  "timestamp": "2026-06-17T15:33:11Z",
  "signature": "ed25519:7b2c...",
  "immutable": true
}

Originalclaim:en finns kvar. Granskningskedjan är komplett.


Kunskapspaketet äger tröskeln

{
  "object": "lifebuoy",
  "claim_type": "existence_and_condition",
  "trust_threshold": 0.92,
  "evidence_weights": {
    "visual_frame": 0.15,
    "ocr_serial": 0.25,
    "liveness_score_component": 0.20,
    "gps_match": 0.15,
    "app_attest": 0.10,
    "challenge_response": 0.08,
    "reference_match": 0.07
  },
  "min_liveness_score": 80,
  "max_scan_seconds": 120,
  "compliance": "maritime_safety"
}
{
  "object": "passport",
  "claim_type": "identity_document_authenticity",
  "trust_threshold": 0.97,
  "evidence_weights": {
    "mrz_validation": 0.30,
    "photo_match": 0.25,
    "tamper_detection": 0.20,
    "liveness_score_component": 0.15,
    "challenge_response": 0.10
  },
  "min_liveness_score": 95,
  "max_scan_seconds": 60,
  "compliance": "regulated"
}

Passet kräver 97% förtroende och minst 95 i liveness. Livbojen kräver 92% och minst 80 i liveness. Samma motor — olika parametrar. Aldrig hårdkodad logik.


Persistens och juridisk hållbarhet

Krav Implementation
Immutability Append-only storage (S3 Object Lock / DynamoDB Streams)
Signering Ed25519 per claim och per bundle
Återgranskningsbarhet trust_accumulation-log i varje bundle
Temporal binding Timestamp signerat med bundle-hash — kan inte backdateras
Separation Bundle sparas separat från claim — kan granskas oberoende

Samma mönster som ledger: en post ändras aldrig. Korrektion = ny post med bakåtreferens.


Vad AVO v2-kontraktet fortfarande styr

Evidence Graph och Verified Claim är ett lager ovanpå AVO v2 — inte en ersättning.

Smart Scan (insamling)
    ↓
AVO Fas A — Liveguidning (on-device, per frame)
    ↓
AVO Fas B — Slutanalys (server, per exponering)
    ↓
Sufficiency-funktion (ackumulerar trust mot claim-tröskel)
    ↓
Evidence Bundle (signerat paket)
    ↓
Verified Claim (persisterad, immutable utsaga)
    ↓
QuickSum (summary till uppdragsgivare)

Öppna frågor

  1. Vem äger kunskapspaketen? quiXzoom sätter defaults — kan uppdragsgivare överskriva? Sätt ett golv.
  2. Juridisk beviskraft — ed25519-signatur + immutable storage: räcker det i EU-rätt för försäkringsärenden? Behöver vi en ackrediterad tidsstämpel (RFC 3161)?
  3. RFC 3161 trusted timestamp — binds claim-hashen till en extern tidsstämpelserver ger oberoende temporalt bevis. Troligtvis nödvändigt för regulated-klassen.
  4. Liveness-score för offline — App Attest kräver nät. Offline-scanning ger lägre liveness-score. Accepteras av knowledge_pack?
  5. Granskningsgränssnitt — hur ser det ut när en försäkringshandläggare öppnar ett bundle 6 månader senare? UI behöver designas för människa, inte för AVO.