Files
Lumina-MSK/proj_level_reading/ARCHITECT/SOFTWARE_ARCHITECTURE_SPEC.md
2026-07-07 15:54:17 +07:00

34 KiB

Software Architecture Specification — VKIST MSK Platform

Scope: Sprint 1-2 (FR-25 Synovitis Grading + Multi-Modal NLP Integration)
Parent: SOLUTION_ARCHITECTURE_SPEC.md, SPRINT_1_2_ARCHITECTURE_SPEC.md
Workflow: Understand → Model (C4) → Specify → Decompose → Plan


1. Problem Statement

Build a reproducible, air-gapped-first musculoskeletal ultrasound analysis platform that performs automated synovitis grading (FR-25) with Vietnamese-language NLP explanations, auditable RAG citations, and HITL finalization — deployable on a single-hospital K3s cluster under ≤10 Mbps LAN constraints, with ≤150 MB idle app bundle and ≤1.5 s inference latency.


2. Requirements

Functional (Sprint 1-2)

  • FR-25: Load knee DICOM → segment joint structures → measure synovium thickness → grade synovitis 0-3
  • Grad-CAM overlay on primary viewport (zero extra clicks)
  • Circuit-breaker Socratic dialogue (radiologist challenges AI grade before finalizing) across 3-tier LLM system (Edge Gemma → Gemini → MedGemma)
  • BERT drift monitor against baseline MOH corpus
  • RAG-Referee validates every LLM-generated explanation against top-k retrieved MOH guideline chunks (mandatory for cloud tiers, lightweight for edge)
  • Decree 13 PII scrubbing on all outbound text (client-side + FastAPI middleware)
  • ladybugDB ontology traversal for anatomical entity disambiguation
  • 3-model LLM consult system: Edge Gemma (browser WebLLM local), Gemini (GCP Vertex AI, orchestration/translation), MedGemma (Modal, clinical deep-reasoning) with MOH guideline citations and cost guarding (<20% MedGemma usage)
  • Circular 46/2018 PDF report generation
  • Immutable audit log append (NFR-17) and HITL digital signature gate (NFR-19)

Non-Functional (Critical)

  • NFR-4: 150 MB idle app bundle
  • NFR-5: ≤1.5 s inference (on-prem Triton); cloud tiers targeted at <30s median
  • NFR-7: ≤200 ms TTFT token streaming; progressive streaming with 25s timeout for cloud responses
  • NFR-8: Fault-tolerant across Wi-Fi drops (state preserved)
  • NFR-10: Automated Generative Safety Guardrails: <90% verification prohibited, 100% of LLM-generated patient text explanations must pass verification. 3-tier guardrail: prompt rules + BERT edge detection (Tier 1) → Vertex AI safety filters (Tier 2) → RAG-Referee mandatory validation (Tier 3)
  • NFR-11: Onboarding ≤ 45 minutes
  • NFR-12: Zero-Friction Explainability Integration
  • NFR-13: Spatial Layer-Activation Mapping
  • NFR-14: No client-side GPU/neural accelerator required
  • NFR-15: Circular 46 EMR compliance
  • NFR-16: Air-gapped primary; NFR-16a PoC fallback with redaction/consent/audit for cloud LLM tiers (Gemini + MedGemma)
  • NFR-16a: Emergency Cloud Fallback with Redaction (PoC-SCOPE). Cloud LLM API (GCP Vertex AI Gemini + Modal MedGemma) invoked ONLY when browser-side WebLLM (Edge Gemma) is unavailable or orchestrates cloud task. FastAPI Redaction Middleware MUST strip all Decree 13 PII fields before egress. GCP CSEK + 30-day lifecycle + 1-year auto-delete. Audit-log commit + consent before egress. MedGemma usage <20% target with alerting. NFR-16a retired upon PoC sign-off.
  • NFR-17: Immutable audit log
  • NFR-18: 100% LLM text cites MOH protocol via RAG. Mandatory RAG pre-processing for all 3 tiers (not optional tool-calling). RAG-Referee validates MedGemma output.
  • NFR-19: HITL digital signature before FINALIZED/ARCHIVED

3. Constraints & System Context

  • On-prem: K3s on Dell PowerEdge (single hospital, ≤10 Mbps LAN)
  • Model: GemmaE2B-Q4 (~1.3 GB) distributed via intranet CDN → GCP CDN fallback → WASM local (WebLLM) or cloud MedGemma on Vertex AI (NFR-16a) → MOH templates
  • Data: Postgres + pgvector, Redis (5 constrained data types), MinIO, IndexedDB client prefs
  • Auth: Keycloak + RBAC inside K3s; GitLab/Jira on cloud VM (NFR-16a exception)
  • CI/CD: Jenkins inside K3s → cloud GitLab via SSH
  • Failover: NGINX + Keepalived VIP (≤2s switch)

4. C4 Models

4.1 Context Diagram (Tier 1)

See master: SOLUTION_ARCHITECTURE_SPEC.md §8.1
Actors: Radiologist (UP5), Senior Expert (UP1), Support (UP4), Admin
External: PACS, EMR/HIS, Triton, ladybugDB, pgvector, GemmaE2B/MedGemma, EmbeddingGemma

4.2 Container Diagram (Tier 2)

@startuml "VKIST_MSK_Software_Architecture_Containers"
!include <C4/C4_Container>

title C4 Container Diagram - VKIST MSK Platform Software Architecture

Person(radiologist, "Diagnostic Radiologist (UP5)", "Primary user: loads DICOM, reviews grading, finalizes reports.")
Person(admin, "System Administrator", "K3s ops, model updates, observability, failover.")
Person_Ext(senior_expert, "Healthcare Senior Expert (UP1)", "Clinical protocol validation, threshold approval.")
Person_Ext(support_staff, "Support Staff (UP4)", "Patient registration, case queue.")

System_Boundary(hospital_lan, "Hospital LAN (Air-Gapped, ≤10 Mbps)") {
    Container(pwa, "React PWA Frontend", "React 18, TypeScript, Zustand, LiteRT, MediaPipe, Dexie.js", "View-angle validation via WASM; DICOM preview; Grad-CAM overlay; Decree 13 scrubber; IndexedDB for encrypted sessions and user prefs.")
    Container(nginx, "Active-Passive Gateway", "NGINX + Keepalived", "SSL termination, VIP load balancing, instant failover (≤2s).")

    System_Boundary(k3s_cluster, "K3s Orchestration Cluster") {
        System_Boundary(edge_servers, "Application Server Cluster") {
            Container(edge_inference, "Edge Inference Service", "FastAPI (Python 3.12, Uvicorn)", "DICOM ingest, 3-step ML pipeline orchestration, Grad-CAM generation, report assembly, consult SSE streaming.")
            Container(cloud_llm_gateway, "Cloud LLM Gateway", "FastAPI (Python 3.12, Uvicorn)", "Routes orchestration/translation to Gemini (GCP) and clinical deep-reasoning to MedGemma (Modal); NFR-16a redaction, consent, audit enforcement; consult_mode state machine extension; cost guarding for MedGemma usage.")
            Container(rag_svc, "RAG & Knowledge Service", "FastAPI (Python 3.12, asyncpg)", "pgvector top-k retrieval, ladybugDB ontology wrapper, RAG-Referee validation for MedGemma output, mandatory RAG pre-processing for all tiers.")
            Container(audit_svc, "Audit & EMR Service", "Node.js / FastAPI Worker", "Immutable append-only audit events; HL7/FHIR EMR push with outbox retry.")
            Container(api_gw, "API Gateway", "Envoy", "TLS termination, rate limiting, routing, OIDC validation pass-through.")
            Container(auth_svc, "Identity & Access", "Keycloak", "OIDC, RBAC, realm vkist-msk.")
            Container(obs_stack, "Observability Stack", "Prometheus + Grafana", "Metrics scrape, dashboards, alerting.")
        }
    }

    System_Boundary(db_vm, "Database VM") {
        ContainerDb(postgres, "PostgreSQL + pgvector", "PostgreSQL 16 + pgvector", "EMR records, spatial markers, MOH guideline HNSW index, session embeddings, audit ledger.")
        ContainerDb(redis, "Redis Cache", "Redis 7 (AOF + RDB)", "JWT sessions, MOH guideline chunks, DICOM metadata, consult_mode state, rate-limit counters.")
        ContainerDb(minio, "MinIO Object Store", "MinIO S3-compatible", "DICOM payloads, segmentation overlays, Grad-CAM heatmaps, report PDFs, model weight staging.")
    }
}

System_Ext(triton, "Triton Inference Server", "NVIDIA Triton, ONNX/TensorRT, gRPC 8001", "3-step ML pipeline (angle → inflammation → segmentation) + EmbeddingGemma RAG embeddings.")
System_Ext(emr, "Hospital EMR / HIS", "HL7/FHIR", "Finalized report storage, prescription sync, ground-truth records.")
System_Ext(pacs, "PACS / Ultrasound Device", "DICOM/C-MOVE", "Image capture and retrieval.")
System_Ext(gcp_cdn, "GCP CDN Emergency Fallback", "Signed-URL Cloud CDN (ap-southeast1)", "Non-clinical model weight distribution when intranet CDN unreachable.")
System_Ext(vertex_ai, "GCP Vertex AI (Gemini)", "Gemini via REST", "PoC-only NFR-16a inference tier: orchestration, translation, UI planning; redacted payloads only.")
System_Ext(modal_medgemma, "Modal MedGemma", "FastAPI + Transformers (T4 GPU)", "PoC-only NFR-16a clinical deep-reasoning endpoint; redacted payloads with RAG-Referee validation; keep-warm instances for latency budget.")

Rel(radiologist, pwa, "Loads scan, reviews grade, finalizes report, views explanations", "HTTPS 443")
Rel(admin, nginx, "Deploys, monitors, configures", "HTTPS 443 / SSH")
Rel(senior_expert, pwa, "Validates protocols, approves thresholds", "HTTPS 443")
Rel(support_staff, pwa, "Registration, case queue", "HTTPS 443")

Rel(pwa, nginx, "API requests + pre-validated DICOM", "HTTPS 443")
Rel(nginx, api_gw, "Routes upstream", "HTTP 8000")
Rel(api_gw, edge_inference, "Forwards /api/*", "HTTP 8000")
Rel(api_gw, rag_svc, "Forwards /rag/*", "HTTP 8001")
Rel(api_gw, auth_svc, "Validates OIDC tokens", "HTTP 8080")

Rel(edge_inference, triton, "3-step inference + embeddings", "gRPC 8001")
Rel(edge_inference, postgres, "Queries guidelines, writes cases/embeddings/audit", "SQL 5432")
Rel(edge_inference, redis, "Session, rate-limit, consult_mode state", "TCP 6379")
Rel(edge_inference, minio, "DICOM, overlays, reports", "S3 API")
Rel(edge_inference, auth_svc, "Token introspection", "OIDC")
Rel(edge_inference, obs_stack, "/metrics", "HTTP 9090")

Rel(edge_inference, cloud_llm_gateway, "Routes cloud consult", "HTTP 8000")
Rel(cloud_llm_gateway, vertex_ai, "Gemini proxy (NFR-16a redacted)", "HTTPS 443 / REST")
Rel(cloud_llm_gateway, modal_medgemma, "MedGemma proxy (NFR-16a redacted)", "HTTPS 443 / REST")
Rel(cloud_llm_gateway, redis, "Consult mode, consent, rate-limit", "TCP 6379")
Rel(cloud_llm_gateway, postgres, "Audit log append", "SQL 5432")

Rel(rag_svc, postgres, "pgvector HNSW queries", "SQL 5432")
Rel(rag_svc, redis, "Guideline cache, pub/sub invalidation", "TCP 6379")
Rel(rag_svc, minio, "Guideline PDF ingestion staging", "S3 API")
Rel(rag_svc, edge_inference, "RAG + RAG-Referee results", "HTTP")

Rel(audit_svc, postgres, "Appends immutable audit events", "SQL 5432")
Rel(audit_svc, emr, "Finalized report push", "HL7/FHIR")
Rel(audit_svc, redis, "Outbox lock, EMR retry counters", "TCP 6379")

Rel(edge_inference, emr, "Report push (via audit-svc wrapper)", "HL7/FHIR")
Rel(pwa, pacs, "Direct DICOM capture / C-MOVE", "DICOM")

Rel(k3s_cluster, gcp_cdn, "Model weight fetch fallback (non-clinical)", "HTTPS 443 (signed URL)")
Rel(postgres, minio, "Backup checkpoint", "S3 API")

@enduml

Container communication summary:

Source Target Protocol Purpose
PWA NGINX HTTPS 443 All API requests
NGINX Envoy HTTP 8000 Route upstream
Envoy Edge Inference HTTP 8000 /api/*
Envoy Cloud LLM Gateway HTTP 8000 /api/cloud-orchestrate, /api/cloud-consult
Envoy RAG Service HTTP 8001 /rag/*
Envoy Keycloak HTTP 8080 OIDC validation
Edge Inference Cloud LLM Gateway HTTP 8000 Route cloud consult
Cloud LLM Gateway Gemini (Vertex AI) HTTPS 443 / REST Orchestration, translation, UI planning (NFR-16a)
Cloud LLM Gateway MedGemma (Modal) HTTPS 443 / REST Clinical deep-reasoning, report finalization (NFR-16a)
Cloud LLM Gateway Redis TCP 6379 Consult mode, consent, rate-limit
Cloud LLM Gateway Postgres TCP 5432 Audit log append
Edge Inference Triton gRPC 8001 3-step ML pipeline + embeddings
Edge Inference Postgres TCP 5432 SQL + pgvector HNSW
Edge Inference Redis TCP 6379 Session, rate-limit, consult-mode
Edge Inference MinIO S3 API DICOM, overlays, reports
Edge Inference Keycloak OIDC Token validation
RAG Service Postgres TCP 5432 pgvector HNSW
RAG Service Redis TCP 6379 Guideline cache, pub/sub
Audit Service Postgres TCP 5432 Immutable audit ledger
Audit Service EMR HL7/FHIR Finalized report push
K3s GCP CDN HTTPS 443 Signed-URL model weight emergency fetch

4.3 Component Diagrams (Tier 3)

Edge Inference Service (edge-inference-svc)

@startuml
!include <C4/C4_Component>

Container_Boundary(edge_svc, "edge-inference-svc (FastAPI)") {
    Component(api, "API Controller", "REST + SSE", "/api/analyze, /api/cloud-orchestrate redirect")
    Component(stream, "SSE Token Streamer", "FastAPI StreamingResponse", "200 ms TTFT, heart-beat every 30s")
    Component(preproc, "Image Preprocessor", "OpenCV + pydicom", "CLAHE, rescale, DICOM header scrub (client-side pre-check)")
    Component(router, "Inference Router", "consult_mode state", "Tier selection: Edge Gemma (tier_1) → Gemini (tier_2, orchestration) → MedGemma (tier_3, clinical) → Templates (tier_4)")
    Component(breaker, "Circuit Breaker", "pybreaker", "Wrap Triton + EMR + Cloud LLM calls; fail-open to templates")
    Component(pipeline, "ML Pipeline", "gRPC client", "Angle→Inflammation→Segmentation→Measurement")
    Component(gradcam, "Grad-CAM Generator", "OpenCV", "Spatial activation overlay; base64 PNG to PWA")
    Component(report, "Report Builder", "WeasyPrint / ReportLab", "Circular 46 PDF; HITL signature gate before FINALIZED")
    Component(rag, "RAG Service", "pgvector SQL", "Retrieve top-5 MOH chunks; mandatory pre-generation for all tiers; enforce NFR-18 citation")
    Component(referee, "RAG-Referee", "BERT classifier", "Reject MedGemma text if citation confidence < threshold; mandatory for tier_3")
    Component(nlp, "NLP Scrubber", "Microsoft Presidio", "Re-verify edge redaction; refine/clean residual PII; error if unresolvable")
    Component(audit, "Audit Logger", "Append-only writer", "Every tier transition, consent, finalize, override; cloud_llm_escalation events")
}
Rel(api, stream, "delegates", "SSE")
Rel(api, preproc, "validates image", "sync")
Rel(api, router, "selects tier", "sync")
Rel(router, pipeline, "invokes", "gRPC")
Rel(router, api, "redirects cloud consult", "HTTP")
Rel(router, stream, "fallback text", "SSE")
Rel(api, gradcam, "requests overlay", "sync")
Rel(api, report, "generates PDF", "sync")
Rel(api, rag, "queries MOH", "SQL")
Rel(rag, referee, "validates citations", "sync")
Rel(api, nlp, "scrubs output", "sync")
Rel(api, audit, "writes event", "sync")
@enduml

Cloud LLM Gateway

@startuml
!include <C4/C4_Component>

Container_Boundary(cloud_gw, "cloud-llm-gateway (FastAPI)") {
    Component(api, "Cloud API Controller", "REST + SSE", "/api/cloud-orchestrate, /api/cloud-consult, /api/cloud-consult/stream")
    Component(gateway, "Cloud LLM Router", "task_type matcher", "Routes orchestration/translation → Gemini (tier_2); clinical deep-reasoning → MedGemma (tier_3)")
    Component(consent, "Consent Enforcer", "Redis + NFR-16a checklist", "Validates consent token + redaction manifest before egress")
    Component(audit, "Cloud Audit Emitter", "PostgreSQL append-only", "egress_consent, egress_response, cloud_llm_escalation events")
    Component(cost, "Cost Guard", "Redis counter + Prometheus", "Tracks MedGemma usage ratio; alerts if >20% over 24h window")
    Component(referee, "RAG-Referee Trigger", "BERT classifier", "Mandatory validation for MedGemma output before SSE to PWA")
    Component(rag, "RAG Pre-processing", "pgvector SQL", "Mandatory top-k injection before any cloud LLM generation")
}
Rel(api, consent, "verifies", "sync")
Rel(api, gateway, "routes", "sync")
Rel(gateway, rag, "injects chunks", "sync")
Rel(gateway, referee, "validates output", "sync")
Rel(gateway, audit, "logs egress", "sync")
Rel(gateway, cost, "increments counter", "sync")
@enduml

4.4 Deployment Diagram (Tier 3)

@startuml
!include <C4/C4_Deployment>
LAYOUT_LEFT_RIGHT()

Deployment_Node(hw, "Dell PowerEdge (Hospital)") {
    Deployment_Node(k3s, "K3s Cluster") {
        Deployment_Node(pod_edge, "Pod: edge-inference-svc") {
            Container(ci, "FastAPI", "Python 3.12, Uvicorn")
        }
        Deployment_Node(pod_rag, "Pod: rag-svc") {
            Container(cr, "FastAPI", "Python 3.12, asyncpg")
        }
        Deployment_Node(pod_audit, "Pod: audit-svc") {
            Container(ca, "Node.js", "WAL writer")
        }
        Deployment_Node(pod_gw, "Pod: api-gateway") {
            Container(cg, "Envoy", "TLS termination, rate limit")
        }
        Deployment_Node(pod_auth, "Pod: auth-svc") {
            Container(ck, "Keycloak", "OIDC, RBAC")
        }
        Deployment_Node(pod_obs, "Pod: observability") {
            Container(cp, "Prometheus")
            Container(cf, "Grafana")
        }
    }
    Deployment_Node(db_vm, "DB VM") {
        ContainerDb(pg, "PostgreSQL + pgvector HNSW")
        ContainerDb(rd, "Redis")
        ContainerDb(mn, "MinIO")
    }
}
Deployment_Node(triton_node, "GPU Node (Triton)", "NVIDIA A10/T4, 24 GB VRAM") {
    Container(tc, "Triton Inference Server", "ONNX/TensorRT, gRPC 8001")
}
Deployment_Node(ext, "External (NFR-16a governed)") {
    ContainerDb(s3v, "S3 Vectors / GCP CDN / Vertex AI")
}

Rel(ci, pg, "SQL", "TCP 5432")
Rel(ci, rd, "Cache", "TCP 6379")
Rel(ci, mn, "Blobs", "S3 API")
Rel(ci, tc, "Inference", "gRPC 8001")
Rel(k3s, db_vm, "SQL", "TCP")
Rel(ci, ck, "Auth", "OIDC")
Rel(ci, ca, "Audit", "HTTP")
@enduml

5. Component Specifications

5.1 React PWA

Concern Decision
Framework React 18 + TypeScript + Zustand
Styling Tailwind CSS (mobile-first)
DICOM viewer Cornerstone.js + custom canvas layer
Grad-CAM <canvas> overlay; base64 PNG from FastAPI
Local model LiteRT (MediaPipe Tasks Vision) — angle pre-classifier
Client storage Dexie.js over IndexedDB (encrypted sessions, prefs)
Offline Service Worker: cache-first for shell; network-first for API
Bundle Tree-shake Cornerstone extras; split vendor chunk
PHI safety Decree 13 regex scrubber before any network write
Edge guardrail guardrail.worker.ts (WebWorker): Transformers.js BERT for hallucination/mal-intention detection; prompt injection scoring; scope-breach detection. OpenRedaction + pii-filter + js-data-anonymizer run in main thread or dedicated worker for redaction pipeline. Separate from cv.worker.ts (LiteRT) and llm.worker.ts (WebLLM) with no shared WASM memory.

5.2 FastAPI Application (edge-inference-svc)

app/
├── main.py                 # Entry, middleware, lifespan
├── config.py               # Pydantic settings (env-driven)
├── middleware/
│   ├── auth.py             # Keycloak OIDC validation
│   ├── phi_scrub.py        # Microsoft Presidio redaction gate (NFR-16a); refine edge output; error if unresolvable PII
│   └── audit.py            # Append-only event emitter
├── routers/                # FastAPI route handlers (existing + new cloud LLM)
│   ├── analyze.py          # POST /api/analyze (sync 3-step pipeline)
│   ├── pacs.py             # C-MOVE proxy + DICOM upload
│   ├── emr.py              # HL7/FHIR push with outbox
│   ├── admin.py            # Model update, drift review, cache invalidation
│   ├── cloud_orchestrate.py # POST /api/cloud-orchestrate (Gemini proxy for orchestration/translation)
│   └── cloud_consult.py    # POST /api/cloud-consult + GET /api/cloud-consult/stream (MedGemma proxy)
├── services/               # Business logic modules (existing + new cloud gateway)
│   ├── inference_router.py # consult_mode state machine
│   ├── triton_client.py    # gRPC with retry decorator
│   ├── rag.py              # pgvector top-k + citation formatter
│   ├── referee.py          # BERT drift + RAG confidence gate
│   ├── guardrail.py        # Edge BERT violation scoring, session termination, cloud mitigation trigger
│   ├── redaction.py        # Presidio AnonymizerEngine; re-verify edge redaction; refine residual PII; error if unresolvable
│   ├── report.py           # Circular 46 PDF + HITL signature
│   ├── ontology.py         # ladybugDB C++ bindings wrapper
│   ├── audit_writer.py     # WAL append
│   └── cloud_llm_gateway.py # Routes between Gemini (tier_2) and MedGemma (tier_3) based on task_type + consult_mode; NFR-16a consent/redaction/audit enforcement
├── models/
│   ├── dto.py              # Request/response schemas (Pydantic v2)
│   ├── domain.py           # Case, Session, Grade, Embedding entities
│   └── enums.py            # ConsultMode (tier_1..tier_4), Grade, Tier
└── infra/
    ├── cache.py            # Redis client (5 data types only)
    ├── db.py               # SQLAlchemy async engine + pgvector
    └── storage.py          # MinIO S3 client

5.3 Knowledge Service (rag-svc)

Separated from inference to allow independent scaling of RAG queries:

  • Endpoints: POST /rag/query, POST /rag/referee-check, GET /rag/guideline/{version}
  • Reads pgvector only; no Triton dependency
  • Publishes guideline update events to Redis Pub/Sub for cache invalidation

5.4 Data Models (Postgres)

Key tables (migration via Alembic):

guidelines (id, version, title, source_url, embedding vector(768), active_from, retired_at)
sessions (session_hash, radiologist_id, case_id, consult_mode, created_at, closed_at)
cases (case_id, patient_hash, joint_site, dicom_checksum, final_grade, finalized_at, signer_id)
embeddings (id, session_hash, chunk_text, embedding vector(768), source, created_at)
audit_events (id, event_hash, session_hash, actor, action, tier, consent_token, redaction_manifest, payload_hash, ts)
emr_outbox (id, case_id, payload, status, attempts, next_retry_at)
user_prefs (user_id, jsonb, updated_at)   # synced from IndexedDB

Unique constraint: cases.case_id final grade requires signer_id != NULL (NFR-19).

5.5 Redis Keys (Exact Schema)

Key pattern Type TTL Purpose
session:{hash} String + Hash 3600s JWT session validation
guideline:{ver}:{chunk_id} String 604800s (7d) MOH guideline chunk
dicom:{session_hash} String 43200s (12h) Per-session DICOM headers
consult_mode:{session_hash} String 7200s Tier state (tier_1..tier_3b)
rate:{actor_id}:{window} String 30s sliding Rate-limit counter

Key-space invalidation: guideline:{ver}:* deleted on version bump via Postgres NOTIFY listener.

5.6 Triton gRPC Contract

service InferencePipeline {
  rpc Run3Step (DICOMBytes) returns (PipelineResult);
  rpc ExtractEmbedding (TextChunk) returns (EmbeddingVector);
}

message DICOMBytes {
  bytes raw_dicom = 1;
  string session_hash = 2;
  uint32 max_vram_mb = 3;
}

message PipelineResult {
  AngleClass angle = 1;
  InflammationFlag inflammation = 2;
  SegmentationMask mask = 3;
  SynoviumMeasurement measurement = 4;
  Grade grade = 5;
  bytes gradcam_png = 6;
}

Idempotency invariant: identical raw_dicom + session_hash → identical output bytes. No partial state between steps.

5.7 Frontend Guardrail Runtime

WebWorker Topology

Worker Runtime Role Memory Cap
cv.worker.ts LiteRT (WASM) CV inference: angle pre-classifier, image preprocessing Isolated WASM instance
llm.worker.ts WebLLM (WASM) GemmaE2B local generation, Gemma Functions tool-calling Isolated WASM instance (NFR-4 1.5GB heap)
guardrail.worker.ts Transformers.js (WASM/WebGPU) BERT classification: hallucination, prompt-injection, scope-breach scoring Shared Web Worker thread (no WASM memory pool)

Isolation rules:

  1. No SharedArrayBuffer or Atomics between workers — no raw WASM memory sharing.
  2. Communication via postMessage with structured clone (no transferable object reuse for audit integrity).
  3. Unload priority on memory pressure (browser memorywarning event): llm.worker.ts first, then guardrail.worker.ts, then cv.worker.ts.
  4. IndexedDB is the only persistence layer shared across workers; written by main thread or dedicated serializer, never read inside LLM context window.

Edge Guardrail Decision Contract

User Input → OpenRedaction + pii-filter → js-data-anonymizer → BERT Guardrail
                                                                    ↓
                                                  PASS: forward to RAG → LLM
                                                  FAIL: terminate LLM session → cloud mitigate

Server-side FastAPI contracts:

  • POST /api/guardrail-check (internal): accepts BERT score + query hash; returns PASS|MITIGATE.
  • POST /api/redaction-ground-check: accepts client manifest hash + sanitized payload; returns PASS|CLEANED|ERROR. CLEANED = server refined residual PII and continues. ERROR = server unable to clean → client receives structured error.
  • POST /api/consult/stream: now includes X-Guardrail-Version and X-Redaction-Manifest-Hash headers for audit.

IndexedDB Schema Additions

Table Key Columns Invalidation
guardrail_models [model_name, version] artifact_hash, size_bytes, load_timestamp Version mismatch
policy_config [policy_name] version, rules_json, bert_thresholds Admin push
audit_tokens [session_hash, entity_type] token_value, created_at Session expiry

6. Interface Contracts (Selected)

6.1 REST Endpoints

Method Path Auth Request Response Notes
POST /api/analyze JWT multipart DICOM JSON + Grad-CAM PNG Sync, ≤1.5 s target
POST /api/cloud-orchestrate JWT + consent JSON (task_type, prompt) JSON text + tier Gemini proxy; orchestration/translation/UI tasks
POST /api/cloud-consult JWT + consent JSON (task_type, prompt) JSON text + tier MedGemma proxy; clinical deep-reasoning
GET /api/cloud-consult/stream JWT + consent query params SSE text stream MedGemma streaming; 25s timeout, 30s budget
POST /api/emr/push JWT case_id 202 Accepted Outbox if offline
POST /api/admin/models Admin modelZip 200 OK K3s rolling restart
GET /api/rag/citations?q= JWT query string JSON top-5 chunks NFR-18
POST /api/safety/guardrail-check JWT payload GuardrailResult NFR-10 edge guardrail
GET /api/health HealthStatus Liveness
GET /api/model-registry JWT ModelCatalog Model registry
POST /api/models/register Admin modelZip RegistrationResult Model upload

6.2 SSE Consult Stream Contract

event: token
data: {"text":"The","confidence":0.92,"tier":"tier_2"}

event: citation
data: {"source":"MOH guideline 2024 §3.2","page":12,"tier":"tier_2"}

event: tier_change
data: {"from":"tier_1","to":"tier_2","reason":"edge_unavailable"}

event: done
data: {"tier":"tier_2","latency_ms":340,"model":"gemini-2.5-pro"}

7. Build vs Buy Matrix (Sprint 1-2 Specific)

Component Build Buy Decision Rationale
Frontend PWA Build Build Custom DICOM viewer + Grad-CAM layer; thin client requirement
FastAPI backend Build Build Tight Decree 13 + NFR-16a middleware; in-house domain logic
Triton inference Deploy self-hosted Deploy Open-source stack; no SaaS
Ontology (ladybugDB) Build Build Embedded C++; SNOMED-CT mapping custom to MSK
pgvector Postgres extension Use Zero infra overhead
Redis OSS Use Scoped to 5 types; self-hosted
MinIO OSS Use S3-compatible; self-hosted
Auth Build (Keycloak) Auth0/Okta SaaS Build NFR-16: Keycloak on-prem, no SaaS identity
Cloud LLM Gateway Build Build FastAPI service enforcing NFR-16a redaction/consent/audit; routes Gemini/MedGemma based on task_type
Gemini (Vertex AI) GCP PoC Use (NFR-16a) Orchestration, translation, UI planning; PoC only with redaction
MedGemma (Modal) Modal deploy Deploy (NFR-16a) Clinical deep-reasoning; PoC only with redaction + RAG-Referee
EMR integration Build Mirth Connect Build Thin HL7 wrapper FastAPI → EMR; keeps surface area small
CI/CD Jenkins in K3s SaaS GitHub Actions Build Jenkins inside LAN; cloud GitLab via SSH
Issue tracking Self-hosted Jira Atlassian Cloud Build (NFR-16a) Cloud VM, compensating controls

8. Task Decomposition

Phase 1: Foundation (Parallel)

  • T1-A Infra: K3s bootstrap + network policy (S)
    Deploy K3s on Dell PowerEdge; Calico network policies; NGINX + Keepalived VIP; TLS secret automation.

  • T1-B Database VM: Postgres + pgvector + MinIO + Redis (S)
    Install Postgres 16 + pgvector extension; MinIO (4 disk RAID); Redis AOF+RDB; backup cron to MinIO.

  • T1-C CI/CD: Jenkins in K3s + GitLab on cloud VM (M)
    Jenkins agents as K3s jobs; pre-push PII hook; GitLab RDB backup job to MinIO; IP-whitelist IAM.

  • T1-D Auth: Keycloak realm + RBAC (S)
    Realm vkist-msk; roles: radiologist, senior_expert, admin; client pwa, edge-svc, rag-svc.

  • T1-E PWA shell: React + Zustand + PWA manifest (S)
    Offline-capable shell; Dexie.js setup; Service Worker with cache-first for shell only.

Phase 2: Core ML Pipeline

  • T2-A Triton server + 3-step model ensemble (L)
    Angle → Inflammation → Segmentation pipeline; gRPC server on port 8001; TensorRT engines.

  • T2-B FastAPI edge-inference-svc (L)
    /api/analyze endpoint; DICOM ingest; pipeline orchestration; Grad-CAM overlay generation.

  • T2-C Circuit Breaker + consult_mode state machine (M)
    pybreaker around Triton + EMR; consult_mode Redis keys; SSE status push to PWA.

  • T2-D Retry decorators (Triton + EMR) (S)
    Exponential backoff; idempotency enforcement; outbox queue for EMR failures.

Phase 3: NLP & Knowledge

  • T3-A pgvector guideline ingestion pipeline (M)
    Ingest MOH PDFs → chunk → embed (BERT/Writing-Alignment) → HNSW index; Postgres NOTIFY pub/sub.

  • T3-B ladybugDB ontology setup (M)
    SNOMED-CT knee/hip subset; MSK entity relationships; C++ embedded bindings in FastAPI.

  • T3-C RAG service + RAG-Referee (M)
    /rag/query; top-5 retrieval; BERT classifier to validate LLM citations; reject if threshold fail. Mandatory for MedGemma (Tier 3) output; lightweight for Gemini (Tier 2) and Edge Gemma (Tier 1).

  • T3-D 3-Model LLM System: Edge Gemma + Gemini + MedGemma (L)
    Tier 1 (Edge Gemma): Browser WebLLM (GemmaE2B-Q4) loaded via Service Worker from intranet/GCP CDN; runs in dedicated WebWorker.
    Tier 2 (Gemini): GCP Vertex AI (GCP Vertex AI Gemini) for orchestration, translation, UI planning; FastAPI wrapper with streaming + Decree 13 redaction middleware.
    Tier 3 (MedGemma): Modal-deployed MedGemma large-24b for clinical deep-reasoning and report finalization; FastAPI gateway with keep-warm instances, 30s timeout, RAG-Referee validation.
    Tier 4: MOH guideline templates (rule-based fallback).
    Consult mode state machine extended: tier_1tier_2tier_3tier_4.

  • T3-E Decree 13 scrubber (client + server) (M)
    Client: Dexie.js pre-egress regex. Server: FastAPI middleware for NFR-16a redaction; role-hash tokens. Applied to all cloud tiers (Tier 2 + Tier 3).

  • T3-F Cloud LLM Gateway (M)
    FastAPI service (/api/cloud-orchestrate, /api/cloud-consult, /api/cloud-consult/stream); routes based on task_type; enforces consent + redaction + audit before egress; tracks MedGemma usage for <20% cost guard target; extends consult_mode state machine.

Phase 4: Compliance & HITL

  • T4-A Immutable audit log (M)
    Append-only WAL writer (audit-svc); schema per NFR-17; every tier transition + consent + finalize event.

  • T4-B HITL signature gate (S)
    cases.finalized_at + signer_id non-null constraint; digital signature capture (VKI token + timestamp).

  • T4-C Circular 46 PDF report generator (M)
    WeasyPrint template; includes grade, Grad-CAM image, MOH citations, signer block, audit hash.

Phase 5: Observability & Hardening

  • T5-A Prometheus + Grafana dashboards (M)
    Triton VRAM/utilization; inference latency p50/p99; Redis hit rate; circuit-breaker state; K3s node health.

  • T5-A BERT drift monitor (M)
    Weekly batch job comparing current session embeddings vs. baseline; alert admin via Grafana if KL divergence > threshold.

  • T5-C Fallback chain integration test (S)
    Simulate Triton down → verify Tier 3a consent flow + redaction; simulate CDN down → verify GCP CDN signed URL fallback.


9. Execution Plan

Week 1-2: Phase 1

Deliverables: K3s cluster up, DB VM ready, CI/CD pipeline green, PWA shell live.

Week 3-4: Phase 2

Deliverables: /api/analyze end-to-end; Grad-CAM overlay visible in PWA; circuit-breaker handles Triton failure.

Week 5-6: Phase 3

Deliverables: RAG queries return MOH citations; Edge Gemma (WebLLM) primary, Gemini (Vertex AI) for orchestration/translation, MedGemma (Modal) for clinical deep-reasoning; RAG-Referee validates MedGemma output; consult_mode state machine extended to tier_1→tier_2→tier_3→tier_4.

Week 7: Phase 4

Deliverables: Audit log immutable with new event types (egress_consent_gemini, egress_consent_medgemma, cloud_llm_escalation); HITL signature enforces finalization; Circular 46 PDF exports; cost guarding (<20% MedGemma usage) enforced.

Week 8: Phase 5 + Sprint Review

Deliverables: Dashboards (tier transitions, MedGemma usage count, latency p50/p99, consent events), drift monitor, integration tests, demo-ready PWA with 3-model routing status.


10. References