🧩 Module Spec · M9 AUCM · Audit · Compliance · Guardrails (Cross-Cutting) · MediEco · 26 April 2026
← Modules M9 · AUCM DETAIL · Phase 1 FIRST Sprint 1.1 · 11 May - 24 May 2026 ⊕ CROSS-CUTTING

M9 — Audit · Compliance · Guardrails

5-layer foundation untuk seluruh eco. Wajib ON sebelum apa-apa modul lain. PDPA filter · clinical safety gate · hallucination guard · HITL approval · audit trail. MOH-ready · 7-yr retention · zero compromise.

1. 📌 Overview & Purpose

Goal: Foundation guardrails yang melindungi pesakit + klinisin + ALESA. Tiada modul lain boleh deploy ke production sebelum M9 LIVE. Build sprint 1.1 (week 1-2) supaya semua sprint selepas dibungkus dlm guardrail layer.

Cross-cutting: M9 ada code yang dipanggil oleh M1, M4, M5, M7 (semua agent). Bukan microservice berasingan, tapi library/middleware yang ditarik ke semua app.

Compliance scope: PDPA 2010 · MOH CPG alignment · MMC scope of practice · 7-yr audit retention · breach notification <72h · DSAR (Data Subject Access Request) 30-day SLA · right to erasure cascade.

2. 🛡️ 5 Guardrail Layers

LAYER 1
🔴 CRITICAL · HARDEST
Clinical Safety Gate

Block list untuk tindakan high-risk yang AI propose tanpa explicit consultant approval. Default OFF — owner enable per-modul per-ward.

Block list: controlled drug order · paeds dose >2× standard · transfusion · DNR override · narcotic refill · surgery scheduling without approval · contraindicated combination
LAYER 2
🟠 PDPA
PII Filter

Semua input ke LLM lalu PII stripper. IC, nama penuh, alamat, no telefon, email, MRN ditukar dgn token. Output detok at UI layer hanya.

Coverage: 12 PII types · regex + NER hybrid · per-tenant key · <50ms latency · vault-stored mappings
LAYER 3
🟣 HALLUCINATION
Hallucination Guard (Source-Citation)

Setiap dx · dose · CPG cadangan WAJIB cite source. Tiada source = tiada paparan. UI tunjuk citation card setiap kali (bukan cuma footnote).

Sources: NPRA drug index · MOH CPG · WHO guideline · per-hospital SOP · published cohort data · vector retrieval scored
LAYER 4
🔵 HITL
Human-in-the-Loop Approval

Agent propose, doktor/farmasis approve. Tiada auto-execute pada clinical actions. Timeout default reject · 1-tap UI approve/reject/modify.

Pattern: proposed_action card · approve/reject/modify/reason · timeout_default = REJECT · audit per click
LAYER 5
🟢 OBSERVABILITY
Audit & Observability

Setiap tool call · LLM call · HITL approve · feature flag toggle — log lengkap, queryable. MOH-ready audit trail. 7-yr retention. Anomali alert real-time.

Stack: structured JSON log (Loki) · OpenTelemetry traces · per-tenant retention · queryable timeline UI · MOH report template

3. ✅ Functional Requirements

MUSTFR-9.1 PII detector: regex 8 patterns (IC NRIC · phone · email · address · postcode · MRN · DOB · plate) + NER fallback (Malay name model)
MUSTFR-9.2 Tokenizer/detokenizer: deterministic per-tenant token map · vault-stored · reverse only at UI render
MUSTFR-9.3 Citation enforcer: middleware yang reject LLM response without ≥1 citation pada clinical claim · auto-retry up to 2× before fallback to "saya tidak pasti"
MUSTFR-9.4 HITL gate library: Python decorator @requires_approval · stores proposed action · suspend agent · UI prompt · resume on approve/timeout
MUSTFR-9.5 Audit log writer: async non-blocking · structured JSON · request_id correlation · 7-yr partition · WORM-style (write once, immutable)
MUSTFR-9.6 Audit log query API: filter by user · patient · ts range · action · agent · tenant — return paginated JSON
MUSTFR-9.7 Feature flag service: per-tenant per-flag · enable/disable · default OFF for new clinical features · audit each toggle
MUSTFR-9.8 Clinical safety block list: hardcoded + extensible · agent attempt → REFUSE + log incident
MUSTFR-9.9 Consent management: per-action consent record · grant/withdraw · scope · expiry
MUSTFR-9.10 RBAC enforcement: middleware ke setiap API endpoint · 6 roles (super_admin · clinic_admin · doctor · pharmacist · receptionist · patient) · per-tenant scope
MUSTFR-9.11 Breach detection: anomaly rules (cross-tenant access · bulk export · failed login spike) → PagerDuty alert · auto-lock account
MUSTFR-9.12 DSAR endpoint: patient-initiated request → 30-day SLA · machine-readable export (FHIR Bundle)
MUSTFR-9.13 Right to erasure: patient delete request → cascade soft-delete + audit retain (MOH 7-yr exception)
SHOULDFR-9.14 Audit timeline UI: Filament admin page · per-patient view · per-staff view · search + filter
SHOULDFR-9.15 MOH report generator: quarterly compliance summary · CSV/PDF export · standard format

4. ⚙️ Non-Functional Requirements

AspectTargetNotes
PII strip latency<50ms p99Critical path · pre-LLM
Audit log writeasync <200msNon-blocking · queue (Redis stream → PostgreSQL)
Audit log retention7 tahunMOH requirement · partitioned monthly
Audit log query<2s for 30-day windowIndexed by ts + user + tenant
HITL approval round-trip<1s UI renderDoctor sees prompt fast
Feature flag check<5msCached in Redis · invalidate on toggle
Citation retrieval<500mspgvector HNSW · top-3 match
Breach alert latency<30sReal-time anomaly detect
DSAR export≤30 days SLAPDPA requirement · async batch OK
RBAC overhead<10ms per requestCached · revalidate on role change
Audit log immutabilityWORMNo update/delete · only insert · cryptographic chain optional
Coverage for clinical actions100%Every prescribe · order · sign-off audited

5. 🗄️ Data Model

5a. Audit Log (PostgreSQL · partitioned monthly)

CREATE TABLE audit_log (
  id              BIGSERIAL,
  ts              TIMESTAMPTZ DEFAULT now(),
  request_id      UUID,                    -- correlates across spans
  tenant_id       UUID NOT NULL,
  user_id         UUID,                    -- staff (null for patient/system)
  patient_id      UUID,                    -- subject (null for non-patient ops)
  agent_id        VARCHAR(20),             -- M1, M4, M5, M7, M9, system
  action          VARCHAR(80) NOT NULL,    -- e.g. "rx.create", "soap.sign_off"
  resource_type   VARCHAR(40),             -- e.g. "prescription", "encounter"
  resource_id     VARCHAR(80),
  before_state    JSONB,                   -- mutation diff
  after_state     JSONB,
  metadata        JSONB,                   -- agent metadata, citations, confidence
  ip_address      INET,
  user_agent      TEXT,
  geo_country     CHAR(2),
  outcome         VARCHAR(20),             -- success, blocked, failed
  PRIMARY KEY (id, ts)
) PARTITION BY RANGE (ts);

-- monthly partitions auto-create
CREATE INDEX idx_audit_ts ON audit_log (ts DESC);
CREATE INDEX idx_audit_user_ts ON audit_log (user_id, ts DESC);
CREATE INDEX idx_audit_patient_ts ON audit_log (patient_id, ts DESC);
CREATE INDEX idx_audit_action ON audit_log (action, ts DESC);
CREATE INDEX idx_audit_tenant_ts ON audit_log (tenant_id, ts DESC);

5b. Other Tables

TableKey fieldsPurpose
feature_flagsflag_key, tenant_id, enabled, set_by, set_at, reason, scope (modul/ward), default_valuePer-tenant toggles
consent_logpatient_id, action_type, consented_at, scope_json, expires_at, withdrawn_at, withdrawn_reasonPer-action consent
hitl_pendingid, agent_id, proposed_action_json, requires_role, requested_at, expires_at, status (pending|approved|rejected|timeout), responder_id, response_at, response_reasonHITL queue
pii_token_maptenant_id, token, original_value (encrypted), pii_type, created_atReversible mapping
incident_logid, severity, type (jailbreak|breach|safety_block), agent_id, user_id?, details_json, detected_at, resolved_at, post_mortem_urlSecurity incidents
dsar_requestsid, patient_id, request_type (access|export|delete), status, requested_at, completed_at, export_urlFR-9.12/13
citation_libraryid, source_type (cpg|npra|who|sop), title, version, content_text, embedding (vector), published_atHallucination guard source
block_listid, action_pattern, severity, requires_role_to_override, reason, added_at, added_byClinical safety gate

6. 🔌 API + Middleware

6a. Audit Query API

GET    /api/v1/audit/logs
       Query: from, to, user_id, patient_id, action, agent_id, tenant_id, limit, cursor
       Returns: paginated audit entries · super_admin/clinic_admin only

GET    /api/v1/audit/logs/{id}
       Detail single entry

GET    /api/v1/audit/timeline/patient/{patient_id}
       Patient lifecycle view (intake → encounter → RX → adverse → discharge)

GET    /api/v1/audit/timeline/staff/{user_id}
       Staff activity audit (today/week/month)

GET    /api/v1/audit/incidents
       Security/safety incidents only · severity filter

6b. HITL API

POST   /api/v1/hitl/request
       Body: { agent_id, proposed_action, context, requires_role, expires_in_sec }
       Returns: { hitl_id, expires_at }

GET    /api/v1/hitl/pending                 # for current user role
POST   /api/v1/hitl/{id}/respond
       Body: { decision: "approved|rejected|modified", reason, modified_action? }

GET    /api/v1/hitl/{id}/wait
       Long-poll for agent · returns when responded or timeout

6c. Feature Flag API

GET    /api/v1/flags                          # all flags for current tenant
GET    /api/v1/flags/{flag_key}               # specific
PUT    /api/v1/flags/{flag_key}               # toggle (admin only)
       Body: { enabled, reason }
       → triggers audit log + Redis cache invalidate

6d. PDPA / DSAR API

POST   /api/v1/pdpa/dsar                       # patient initiates request
       Body: { request_type: "access|export|delete", justification }
GET    /api/v1/pdpa/dsar/{id}                  # status check
GET    /api/v1/pdpa/dsar/{id}/export           # download FHIR Bundle ZIP
DELETE /api/v1/pdpa/data/{patient_id}          # cascade soft-delete (admin only)
POST   /api/v1/pdpa/breach                     # internal breach declaration
       → triggers MOH/PDP notification workflow

6e. Middleware (Laravel + Python)

Laravel:
  app/Http/Middleware/PIIStrip.php          (request body sanitise)
  app/Http/Middleware/AuditWriter.php       (response wrap · log async)
  app/Http/Middleware/RBACEnforcer.php      (route gate · per-tenant)
  app/Http/Middleware/FeatureFlagGate.php   (route enable check)
  app/Http/Middleware/RateLimiter.php       (per-user · per-endpoint)

Python (agents/medieco/guardrails/):
  pii_filter.py         (regex + NER · 50ms target)
  citation_enforcer.py  (LLM response validator · retry logic)
  hitl_gate.py          (decorator @requires_approval)
  block_list.py         (clinical safety gate)
  audit_emitter.py      (structured event → Redis stream)

7. 🎚️ Feature Flags Catalog

Default OFF untuk semua clinical AI features. Owner enable bila ready.

Flag KeyModuleDefaultPurpose
m1.selfcare_adviceM1OFFEnable AI self-care advice (otherwise just escalate)
m1.whatsapp_channelM1OFFWAHA WhatsApp intake channel
m1.voice_inputM1OFFWebRTC voice symptom intake
m1.photo_symptomM1OFFPhoto upload (rash · luka)
m4.ambient_scribeM4OFFWebRTC audio capture · auto SOAP
m4.cdss_activeM4OFFAI DDx suggestion panel
m4.auto_icd10M4OFFAuto ICD-10 coding suggest
m4.history_searchM4OFFSemantic patient history Q
m5.ddi_blockingM5OFF (warn-only)Block dispense on MAJOR DDI vs warn-only
m5.halal_filterM5OFFHalal pharma filtering
m6.cross_clinic_shareM6OFFAdverse reaction share across network
m7.einvoice_lhdnM7OFFAuto e-Invoice submission
m7.noshow_predictM7OFFAI no-show prediction + intervention
m8.cross_clinic_continuityM8OFFPatient data follow patient
m9.cloud_burst_llmM9OFFAllow cloud LLM (gpt-4o-mini) for peak overflow
m9.audit_log_immutableM9ONWORM audit log enforcement
m9.breach_auto_lockM9ONAuto-lock account on breach signal
global.maintenance_modeOFFReject all writes (read-only)

8. 📜 Audit Event Schema

Standard Event Format

{
  "ts": "2026-05-26T10:45:23.412Z",
  "request_id": "req_abc123def456",
  "tenant_id": "klinik_pilot_001",
  "user_id": "doctor_007",
  "patient_id": "patient_2026-001245",
  "agent_id": "M4",
  "action": "rx.create",
  "resource_type": "prescription",
  "resource_id": "rx_xyz789",
  "before_state": null,
  "after_state": {
    "items": [{ "drug_code": "AMX500", "dose": "500mg PO TDS x 5/7" }],
    "ai_suggested": true,
    "doctor_modified": false
  },
  "metadata": {
    "model_used": "llama-3.1-70b-q5",
    "tokens_total": 845,
    "latency_ms": 312,
    "citations": ["MOH CPG URTI 2019"],
    "confidence": 0.84,
    "hitl_id": "hitl_pqr",
    "approved_at": "2026-05-26T10:45:18.123Z",
    "approver_id": "doctor_007"
  },
  "ip_address": "10.0.1.45",
  "user_agent": "Mozilla/5.0...",
  "geo_country": "MY",
  "outcome": "success"
}

Common Action Types

auth.login                           consent.granted          rx.create
auth.logout                          consent.withdrawn        rx.sign
auth.failed                          patient.create            rx.dispense
auth.locked                          patient.update            rx.cancel
encounter.create                     patient.access            order.create
encounter.brief_received             patient.delete            order.send
encounter.scribe_start               patient.export (DSAR)     ddi.block
encounter.scribe_stop                                          allergy.alert
encounter.soap_draft                 audit.query               feature_flag.toggle
encounter.soap_edit                  hitl.request              hitl.approve
encounter.sign_off                   hitl.reject               hitl.timeout
referral.create                      pii.strip                 citation.miss (refused)
billing.claim_submit                 pii.detok                 incident.detected
billing.einvoice_submit              breach.declared           safety_block.refused

9. 🎨 UI / Dashboards

Filament 3 admin panel at /admin/audit dgn:
  • Audit Timeline (per-patient + per-staff)
  • HITL Queue (pending approvals · respond inline)
  • Feature Flags page (toggle dgn audit reason)
  • Incident Log (security/safety events)
  • Breach Dashboard (anomaly trend · alerts)
  • DSAR Inbox (patient requests · status workflow)
  • MOH Report Generator (quarterly compliance summary export)
Doctor/Pharmacy/Admin embedded HITL prompts: modal overlay bila agent propose action requiring approval. 3 buttons (Approve · Reject · Modify) + reason field. Timeout countdown visible.
Patient-facing consent UI: per-action consent screen (intake · share clinic · share research) · withdraw button always accessible.
Citation card pattern: small expandable card next to every clinical claim showing source title · year · excerpt link. UI consistent across M1/M4/M5.

10. ✔️ Acceptance Criteria

  • AC-9.1: 100% clinical actions audited (test: 50 sample actions traced end-to-end)
  • AC-9.2: PII strip detect 95%+ of 12 PII types in 100 sample messages (regex + NER)
  • AC-9.3: Citation enforcer rejects LLM responses without citation in 100% test cases
  • AC-9.4: HITL gate blocks 30 jailbreak attempts (auto-RX · auto-order) → 0 success
  • AC-9.5: Audit log query 30-day window returns <2s for typical patient
  • AC-9.6: Feature flag toggle reflects in <5s across all instances (cache invalidate)
  • AC-9.7: DSAR export generates valid FHIR Bundle for sample patient · machine-parseable
  • AC-9.8: Right-to-erasure soft-deletes patient data · audit retain · cross-table cascade tested
  • AC-9.9: Breach simulation (cross-tenant access attempt) → alert <30s · account auto-lock
  • AC-9.10: Audit log immutability — attempt UPDATE/DELETE returns DB-level error
  • AC-9.11: Q5 PDPA self-audit pass · DPO sign-off documented
  • AC-9.12: All other modules (M1, M4, M5, M7) pass through M9 middleware in test suite

11. 🧪 Test Plan

TierCasesCoverage Target
UnitPII regex (12 types) · token round-trip · citation validator · HITL state machine · feature flag cache≥90%
IntegrationMiddleware chain (PIIStrip → AuditWriter → RBACEnforcer) · audit log write/query · HITL request/respond cycle100% middleware paths
E2EEnd-to-end patient journey (M1 intake → M4 encounter → M5 RX → M7 billing) — verify every action logged1:1 audit trail
Security30 jailbreak attempts · 20 cross-tenant access · 10 token reuse attacks · OWASP Top 10 scan0 high/critical
PDPA simulation3 DSAR scenarios · 2 erasure scenarios · 1 breach scenario · MOH report generationAll pass
Load1000 audit writes/sec · 50 HITL requests concurrent · feature flag check 10K/secNo drop
ChaosAudit DB outage (must fail-safe to local queue) · vault outage (PII fallback) · LLM down (fall back to deterministic rules)Graceful degrade
Compliance auditExternal pen-test simulation · MOH-style audit walkthroughPass

12. 🔗 Dependencies & Integration

  • Hard: NONE — M9 first to build (Sprint 1.1)
  • External: Vault (Hashicorp) atau equivalent for PII token store · PostgreSQL 16 · Redis 7 · Loki/Grafana stack
  • Library reuse: Laravel Sanctum · Spatie Permissions · Laravel Audit package as base · custom extensions
  • Downstream consumers: M1, M4, M5, M7 — semua import M9 middleware/decorators
  • Compliance reference: PDPA 2010 · MOH CPG library · MMC scope of practice docs

13. 🏃 Sprint Allocation

Sprint 1.1 · 11 May - 24 May 2026 (2 minggu) — FIRST SPRINT
  • Day 1-2: Repo init · CI/CD scaffold · base auth (Sanctum) · RBAC seed
  • Day 3-4: Patient 11-section model + migrations (canonical · shared dgn M1/M4)
  • Day 5-6: PII filter (regex + NER) + token map · vault integration
  • Day 7-8: Audit log (PostgreSQL partition + Redis stream) + middleware
  • Day 9-10: HITL gate library (Python + PHP) · UI prompt component
  • Day 11: Feature flag service · admin UI
  • Day 12: Citation enforcer + library · clinical safety block list
  • Day 13: Integration test · 100% audit coverage check
  • Day 14: Sprint demo · ALESA Preflight Q1 prep · merge ke develop
Capacity: 3 backend (Laravel + Python + DB) · 1 frontend (admin UI) · 1 security/compliance reviewer · ALESA Founder oversight daily

14. ⚠️ Module-Specific Risks

RiskLikelihoodImpactMitigation
Audit log write fail (DB outage) → action lostLow-Med🔴 Compliance gapRedis stream buffer · local disk fallback queue · daily reconciliation · DR drill
PII strip miss (NER false negative)Med🔴 PDPA breachRegex + NER hybrid · 95% target · monitoring · quarterly improvement loop
HITL gate bypass (UI-only enforcement)Low🔴 Inappropriate actionServer-side enforcement · decorator wraps tool call · 30-prompt jailbreak suite
Citation library outdatedMed🟠 Wrong adviceQuarterly CPG refresh · version metadata · alert on stale source
Audit log volume costMed🟢 BudgetCompression · archive to S3 cold storage after 1-yr hot · partition pruning
Feature flag cascade (toggle wrong order)Med🟠 Feature instabilityDependency graph · disable cascade · staged rollout · rollback procedure
RBAC complexity (6 roles × per-tenant × per-modul)Med🟠 Permission bugSpatie Permissions baseline · matrix test (role × resource × action) · per-PR security review
DSAR export performance (large patient history)Low🟢 SLA missAsync background job · email notify on ready · 30-day SLA generous