Rōvn · Investor Room
AI agent: checking…
All sections
Technical & Architecture

AI Governance Engine

Diligence noticeWorking state of Rōvn as of 2026-06-24 · Pre-launch by designSee 09 for receipts →
AI Diligence Console

AI Governance Engine

Date: 2026-05-14 Scope: The system that enforces Rōvn's doctrine, "AI operates, humans decide." Posture: LIVE for executor + advisor ledger schema, vendor BAA matrix, truth-tier CHECK constraints, and per-decision human-actor enforcement. PARTIAL on per-tenant policy controls UI and complete ai_runs call-site coverage.


1. The doctrine, in code

Rōvn's product doctrine has one non-negotiable: humans are the actor on every credentialing, privileging, hiring, and clinical decision. AI operates time and surfaces signal; AI never adjudicates.

The AI Governance Engine is the set of code-level, schema-level, and process-level controls that make that doctrine enforceable, not merely promised.

It has four layers:

Layer Mechanism LIVE?
Schema CHECK constraints + immutable columns LIVE
Gateway ai_gateway.py policy enforcement LIVE
Ledger ai_runs + audit_log hash-chain LIVE schema; PARTIAL coverage
Process Replay + policy controls + vendor BAA matrix LIVE matrix; PARTIAL controls UI

2. The governance loop

        ┌─────────────────────────────────────────────────────────┐
        │                  Human-facing surface                   │
        │   (facility workflow layer committee, Passport reviewer, Admin)         │
        └────────────────────────┬────────────────────────────────┘
                                 │
              ┌──────────────────▼──────────────────┐
              │  AI proposes (executor + advisor)   │
              │  Written to: ai_runs                │
              │  Output: advisory recommendation +  │
              │          confidence + sources       │
              └──────────────────┬──────────────────┘
                                 │
              ┌──────────────────▼──────────────────┐
              │  Human reviews                      │
              │  Surface: facility workflow layer packet UI or      │
              │           Passport reviewer queue   │
              └──────────────────┬──────────────────┘
                                 │
         ┌───────────────────────┼─────────────────────────┐
         │                       │                         │
   ┌─────▼──────┐         ┌──────▼──────┐          ┌───────▼──────┐
   │ APPROVE    │         │   REJECT    │          │   ESCALATE   │
   │ + rationale│         │ + rationale │          │ to senior    │
   └─────┬──────┘         └──────┬──────┘          └───────┬──────┘
         │                       │                         │
         └───────────────────────┼─────────────────────────┘
                                 │
              ┌──────────────────▼──────────────────┐
              │  Write decisions row                │
              │  actor_user_id = THIS HUMAN         │
              │  ai_advisory_id = FK to ai_runs row │
              │  decision_rationale = required text │
              └──────────────────┬──────────────────┘
                                 │
              ┌──────────────────▼──────────────────┐
              │  Hash-chain append to audit_log     │
              │  actor_kind = 'human'               │
              │  payload includes both decision +   │
              │  reference to AI advisory           │
              └─────────────────────────────────────┘

Three writes per decision, every time: 1. ai_runs row (the AI's advisory) 2. decisions row (the human's act) 3. audit_log row (the hash-chained event)

The AI cannot skip step 2. The decision row has no path from an AI actor, the schema rejects it.


3. Layer 1: Schema enforcement

Decision-row actor constraint

decisions has an enum constrained actor_kind column. Only the value 'human' is allowed for any decision type in the privileging / credentialing / hiring / clinical class. 'ai_advisory' is allowed for the separate privileging_recommendation_log table (an advisory log, not a decision). 'system' is allowed only for system-triggered events like cadence expirations or source-adapter retries.

If the application code attempts to insert a decisions row with actor_kind != 'human', the database rejects it. This is not a service-side check that can be bypassed by a buggy service; it is a CHECK constraint at the data layer.

Truth-tier CHECK constraint

On worker_trust_records (tiers 1-5: imported → attested → processed → source-verified → approved):

CHECK (
  (tier <  4)
  OR
  (tier >= 4 AND source_receipt_id IS NOT NULL
              AND last_verified_at IS NOT NULL
              AND last_verified_at > NOW() - INTERVAL '<source TTL>')
)

No code path, including AI extraction, can promote a fact to tier 4 (source-verified) without a valid source receipt within the source's TTL. The AI extractor literally cannot mark a license source-verified; the only way that bit flips is through the source-adapter rail.

Immutable audit columns

audit_log has triggers that block UPDATE and DELETE on every row. The deploy IAM role does not have DELETE or UPDATE privileges on this table. The audit bucket in S3 is in Object Lock COMPLIANCE mode, even AWS root cannot delete during the 7-year retention window.


4. Layer 2: Gateway enforcement (ai_gateway.py)

Every AI call goes through app/services/ai_gateway.py. The gateway enforces:

  1. Vendor BAA matrix check. The model name (e.g., claude-3-5-sonnet) must be present in ai_vendor_baa_matrix with baa_active = TRUE and zdr_active = TRUE. If a developer attempts to call a non-registered model, the gateway raises and writes a policy_violation event to audit_log.

  2. Per-tenant policy controls. Tenants can declare: - require_human_review_for_phi_extraction (default: ON for hospital tenants) - block_ai_committee_response_drafts (default: OFF; some buyers require ON) - require_advisor_for_low_confidence (default: ON for clinical credentials) - daily_token_budget_usd These rows live in ai_policy_controls.

  3. PHI scrubber. Identifiers that don't need to leave the perimeter are tokenized. The model sees <patient_token_a3f9>; the app rehydrates on return. The scrubber is a default-deny allow-list, fields not on the allow-list don't reach the model.

  4. Idempotency key. Required on every call. (hash(tenant_id, purpose, input_hash, model)). Replay is deterministic: same key returns the cached ai_runs row, not a new model call.

  5. ai_runs write. Every call produces exactly one ai_runs row, with token cost, latency, model, prompt hash, output hash, advisor calls (if any), and the requesting user.

If any of these checks fail, the AI call is refused. The gateway is the single entry point, there are no side-channel AI calls in the codebase (enforced by lint rule: import anthropic is allowed only inside ai_gateway.py).


5. Layer 3: Ledger (ai_runs + audit_log)

The two ledgers serve different purposes:

Ledger Purpose Hash-chained? Retention
ai_runs Every AI call: model, prompt, output, cost, latency No (per-row hashes only) 7 years
audit_log Every decision + every consequential event YES (chained SHA-256) 7 years (S3 Object Lock)

When a human approves a privileging packet, three things happen: - An ai_runs row already exists (the advisory the human reviewed). - A decisions row is written with the human as actor. - An audit_log event is written, hash-chained, referencing both rows.

This separation lets an auditor ask two distinct questions:

  • "What did the AI tell the human at the moment of decision?"ai_runs (immutable per-row hash; we can prove the advisory has not been edited).
  • "What did the human decide, and was the chain tampered with?"audit_log (replay the chain; verify entry_hash against prev_hash || payload).

6. Layer 4: Process (replay, policy controls, vendor matrix)

Replay

Every AI run is replayable: - idempotency_key lets us recall the exact ai_runs row. - prompt_hash lets us prove the prompt has not changed. - output_hash lets us prove the output has not changed. - With the same model name, same prompt, same input, the model would (within model-provider determinism guarantees) reproduce the output. For Anthropic, we additionally store full prompt JSON and full output JSON in ai_runs so replay does not depend on third-party determinism.

This makes "show me what the AI said and what the human decided on 2026-03-14 at 14:32:09 UTC" a one-query operation.

Per-tenant policy controls

ai_policy_controls is the per-tenant config table. Hospital procurement teams often ask: "Can we disable the AI from drafting committee responses?", the answer is yes, flip the toggle, and the gateway will refuse to invoke executor on that route for that tenant. The toggle write is itself audit-logged. UI for self-serve toggle management is PARTIAL.

Vendor BAA matrix

ai_vendor_baa_matrix holds the canonical list of AI vendors authorized to receive PHI traffic. Each row has: - vendor (anthropic, aws_bedrock) - model (claude-3-5-haiku, claude-3-5-sonnet, claude-opus-4-7-advisor) - baa_active (boolean) - baa_expiration - zdr_active (boolean) - notes

A vendor not in this matrix cannot receive PHI traffic. Adding a row is an admin-role action that writes to audit_log. This is how we make "BAA discipline" enforceable rather than aspirational.


7. Failure modes and what happens

Failure Engine response
Model API down Block the decision flow. Do NOT auto-approve. Surface "AI advisory unavailable, proceed manually" to the human.
Low confidence Escalate to advisor; if still low, escalate to senior reviewer queue.
Cross-source disagreement Hold worker_trust_records.tier = 3 (processed); block source-verified (tier 4) promotion until human resolves the conflict.
AI gives different answer on replay output_hash mismatch → audit alarm fires; the canonical output is the stored ai_runs row, not the replay.
Vendor BAA matrix entry expires Gateway refuses calls to that model; audit alarm fires.
Policy violation attempt policy_violation audit event written; ops paged.

No failure mode auto-approves a decision. No failure mode hides itself from the audit chain.


8. What an auditor can do today

Procurement and compliance auditors evaluating Rōvn can perform these checks against the LIVE system:

  1. Read chain head. GET /audit/chain-head returns the latest entry hash.
  2. Replay recent events. GET /audit/events/recent?since=... returns events; verify each entry hash against prev_hash || payload_hash.
  3. Inspect any decision. Every decisions row carries actor_user_id, decision_rationale, and (when applicable) ai_advisory_id. The auditor can verify that AI never appears as the actor.
  4. Inspect any AI call. ai_runs rows expose model, prompt, output, token cost, latency. Auditors can sample any decision and demand "what did the AI say here?"
  5. Verify vendor BAA matrix. Every AI vendor is in the matrix with BAA + ZDR status; an auditor can confirm the matrix matches the BAAs on file in the compliance folder.

9. What this engine does not claim

  • We do not claim "no AI hallucination is possible." We claim that hallucinations cannot move a tile to source-verified, and cannot become a decision row.
  • We do not claim per-tenant policy UI is fully self-serve, PARTIAL (admin-applied today).
  • We do not claim 100% of routers have ai_runs coverage today, PARTIAL.
  • We do not claim the audit log is immune to source-data manipulation upstream of Rōvn (e.g., a state Board of Nursing publishing wrong data). We claim the receipt captures what the source said at that timestamp, and our chain is tamper-evident from that point forward.

10. Why this is a moat, not overhead

Buyer procurement teams have asked us, repeatedly: "How do we know your AI isn't quietly making decisions?" The honest answer is structural. The schema does not let it. The gateway does not let it. The audit log does not let it.

That structural answer is what underwrites the words "AI Trust Layer" on the marketing site. It's not a logo, it's a CHECK constraint.

End of memo.

Ask the AI agent about this section, the raise, compliance posture, or any cross-document question. Grounded in Rōvn's deep context, with on-page source citations.

AI queries route through AWS BedrockAI provider chain07.3 AI Architecture · AWS Bedrock under BAA → Anthropic Claude Haiku 4.5 under BAA → Rōvn ECS under BAA · Anthropic Claude (Haiku 4.5)Model identity07.3 AI Architecture · Haiku 4.5 chosen for cost + latency + BAA chain under BAA · zero-data-retention posture · no PHI in prompts.