PF-111 — Unified AI Gateway Integration
Spec: PF-111 Unified AI Gateway Consolidation Status: Planned (stub — completed during Phase 1 implementation) Owner: Platform Foundation (PF) Last Updated: 2026-05-29
Integration with an external system (Vercel AI Gateway), not a cross-core integration. Listed here for the external-integration catalog; not added to CROSS_CORE_INTEGRATIONS.md (no core-to-core surface).
External System
Consumers (16 edge functions)
All AI-calling edge functions import onlysupabase/functions/_shared/ai and call the AIProvider interface:
ai-assistant, ai-skill-execute, ai-document-analyze, ai-generate-template,
ai-categorize-transactions, ai-match-transactions, ai-match-benefits-employees,
generate-report-narrative, generate-embeddings, chatbot-message,
ce-extract-document-data, extract-document-text, hr-ai-import-assist,
messaging-summarize-conversation, messaging-translate-message, org-data-sync-consumer.
Contract (to be finalized in Phase 1)
- Request: OpenAI-compatible chat-completions body (
model,messages, optionaltools,tool_choice,temperature,max_tokens,stream). - Response (non-stream): normalized to
{ content, toolCalls?, usage?, modelUsed }. - Response (stream): SSE passthrough, OpenAI-compatible frames (consumed by
src/platform/ai/utils/encoreOpenAiSseChatTransport.ts). - Errors:
{ error: { code, message } }, sanitized; 429 retried with backoff; 402/401 non-retryable; ≥500 retryable. - PHI lane:
lane: 'phi'resolves to BAA-covered models for modules with a PHI-lane configuration, and throwsPhiLaneNotConfiguredErrorfor any module that does not. As of 2026-05-29, the clinical (cl) and practice management (pm) modules are enabled on the PHI lane withanthropic/claude-sonnet-4.6(primary) andopenai/gpt-4o(fallback) — both BAA-covered through the Vercel AI Gateway. All other modules continue to fail closed onlane: 'phi'.
PHI lane routing
The PHI lane is fail-closed by default. Any module that callsresolveModels(module, 'phi') without an explicit BAA-confirmed entry raises PhiLaneNotConfiguredError. As of 2026-05-29, with Vercel AI Gateway BAA + ZDR confirmed, the following modules are enabled on the PHI lane:
All other modules (for example
gr, hr, fa, ce) continue to throw PhiLaneNotConfiguredError on the PHI lane and must use the standard lane until a per-module entry is added to PHI_MODELS. To enable a new module, add it to supabase/functions/_shared/ai/models.ts with a BAA-covered primary plus fallback.
Trace store (Langfuse)
All AI calls routed through the gateway are instrumented with Langfuse tracing at the single_shared/ai seam (tracing.ts, withTracing decorator, wired into createAIProvider).
Retention caveat: Langfuse Cloud SaaS has no configurable server-side retention cap (EE-gated; Encore does not have a Langfuse EE license). This is acceptable only while no PHI content is ever sent to Langfuse.
Residency recommendation (ops, no code change): Rotate
LANGFUSE_BASE_URL Edge Function Secret to https://us.cloud.langfuse.com to align production trace storage with the US region and eliminate the mismatch with the MCP dev tool. Command: supabase secrets set LANGFUSE_BASE_URL=https://us.cloud.langfuse.com --project-ref <ref>.
Gate before enabling content capture: If input/output are ever attached to Langfuse observations (any lane), the following must happen first — in order — before deployment:
- Execute a Langfuse BAA.
- Rotate
LANGFUSE_BASE_URLtohttps://hipaa.cloud.langfuse.com(or a self-hosted instance). - Update AI_SUBPROCESSOR_BAA_POSTURE.md and the REGULATORY_COMPLIANCE_TRACKER row.
Open items
- Confirm
"provider/model"ids (incl. an embedding model forgenerate-embeddings) against the live catalog. - Finalize request/response examples once the gateway is wired (Phase 1).
PF-111-EN-01 — AI Usage/Audit Ledger + Cost Governance
Spec: PF-111-EN-01 Status: Partially implemented — ledger table + agent dimensions + PHI-access audit shipped; spend-cap pre-dispatch wiring, pricing table, and per-org rollup view are planned. ADR: ADR-029 (platform-wide AI governance posture) Last Updated: 2026-06-28Producer / Consumer Matrix
Event Contract
PF-111-EN-01 does not define typed domain events in the pub/sub sense. The anomaly surface emits PF-10 notifications via directcreateNotification() invocation. No entries in EVENT_CONTRACTS.md are required.
PF-10 notification shape emitted by pf-check-ai-usage-anomalies (runs hourly via pg_cron):
Deduplication is keyed on
(alert_config_id, organization_id) via pf_ai_usage_alert_history cooldown check.
API / RPC Surface
pf_record_agent_phi_access(...) — SECURITY DEFINER, fail-closed PHI-access writer (FR-10/FR-11/FR-12)
authenticated, service_role. A write without governance_approval_id raises check_violation. If the insert fails the caller (TypeScript recordAgentPhiAccess()) throws PhiAccessLogError and MUST block the PHI operation — the audit is a precondition, not fire-and-forget.
pf_agent_usage_rollup(p_organization_id, p_since) — SECURITY DEFINER, read-only fleet rollup (FR-13)
pf.audit.phi_access.view permission. Joins pf_ai_usage_logs (agent rows) + pf_agent_phi_access_log (PHI touches) via FULL OUTER JOIN on (agent_principal_id, session_id). Content-free. PF-130 is the exclusive read consumer.
pf_ai_usage_rollup(...) — per-org billing rollup view + RPC (FR-4) — planned
pf_ai_model_pricing (also planned). To be defined in spec PF-111-EN-01 FR-4.
TypeScript helpers (Deno edge runtime, _shared/ai/agent-usage.ts):
checkAgentBudget(input: AgentBudgetInput, projectedCost: number): AgentBudgetVerdict— pure, synchronous budget-decision function. Evaluatestask → agent → orghard caps independently; returns{ throttled: true, dimension, limit, used }on a hard breach and{ throttled: false, warn: true }on an org soft-limit breach. Not yet wired into the gateway dispatch path.recordAgentPhiAccess(rpc: UsageRpcClient, input: PhiAccessInput): Promise<{ recorded: true; id: string }>— callspf_record_agent_phi_accessvia RPC; throwsPhiAccessLogErroron failure; caller MUST re-throw to block the PHI operation.buildUsageRecord(module, result): AIUsageRecord(in_shared/ai/usage.ts) — builds a PHI-safe token record; persistence topf_ai_usage_logsis planned (FR-2) but not yet wired.
_shared/ai/usage.ts, the gateway will evaluate checkAgentBudget() plus the per-org PF-43 entitlement before every provider call. A hard breach throws AiBudgetExceededError (error class planned; not yet declared in codebase) and records a status='throttled' ledger row without dispatching to the provider. A soft-limit breach warns and proceeds.
Data / FK Contract
pf_ai_usage_logs — live, shipped
The last four columns were added by migration
20260630000008_pf111_en01_agent_phi_access_audit.sql (additive, nullable; existing rows stay NULL). Indexes on (organization_id, agent_principal_id, created_at) (filtered, agent rows only) and (organization_id, session_id) (filtered). No cross-core FK on any column.
pf_agent_phi_access_log — new, shipped via migration 20260630000008
No PHI value columns by construction.
resource_table + resource_ref are soft (text + UUID) references — not FKs — so any-core records can be named without violating the no-cross-core-FK rule (constitution §1). Append-only: UPDATE revoked from authenticated; no UPDATE/DELETE RLS policy.
pf_ai_model_pricing — planned (not yet materialized)
To be defined in spec PF-111-EN-01 FR-3. Drives deterministic
estimated_cost_usd computation; unknown model logs at zero cost (never blocks the call).
pf_ai_usage_alert_configs / pf_ai_usage_alert_history — live, shipped
Config-driven anomaly detection consumed by the pf-check-ai-usage-anomalies scheduled function. Metric types: daily_cost_usd, hourly_call_count, failure_rate_pct, per_org_daily_cost_usd, per_model_daily_cost_usd. Cooldown deduplication keyed on (alert_config_id, organization_id).
PHI / RLS / Tenant-Scoping Notes
pf_ai_usage_logs— RLS onorganization_id; org-member reads; gateway / service-role writes. No content columns:prompt_tokens,completion_tokens,total_tokensare integer counts only. The table has no column capable of holding prompt or response text (NFR-1 enforced by schema, not policy).pf_agent_phi_access_log— deny-by-default RLS.SELECTrequires bothpf_has_org_accessand thepf.audit.phi_access.viewpermission (compliance / admin readers only).INSERTis exclusively via thepf_record_agent_phi_accessSECURITY DEFINER RPC.UPDATEis revoked fromauthenticated; noDELETEpolicy. Append-only audit by construction.pf_agent_usage_rollup— SECURITY DEFINER function;pf.audit.phi_access.viewgated; returns only aggregated counts and costs — no content, no per-row PHI exposure.- SUD category handling — PHI touches on 42 CFR Part 2 records set
phi_category='sud_part2'; the access event is recorded here, but the protected SUD content itself is governed by CL / PF-27-EN-01. This table records the access event identifier, not the content. - No cross-core FKs —
resource_table/resource_refare soft (text + UUID) references, enabling PHI-touch audit of any-core records without a DB-level FK.agent_principal_id/session_id/parent_task_idare loose UUID references to PF-30-EN-01 and PF-125 entities (same-platform, no FK declared). - Compliance gate —
specs/pf/reviews/PF-111-EN-01-COMPLIANCE-SIGNOFF.mdmust exist beforepipeline_statusmay advance tocompliance_reviewed(governed spec; regulated PHI-adjacent audit trail).
Open Items
PF-111-EN-02 — AI Eval / Observability Quality Gate
Spec: PF-111-EN-02 AI Eval / Observability Quality Gate PF-111-EN-02 formalises ownership and run-mode governance for the three-layer eval harness (L1 JSONL deterministic / L2 self-hosted Langfuse observability / L3 Promptfoo LLM-judge) that rides the AI gateway established by PF-111. This enhancement introduces no new cross-core contracts or external integration surfaces — it operates entirely within the existing Vercel AI Gateway surface, thesupabase/functions/_shared/ai consumer interface, and the metadata-only Langfuse trace pipeline already documented in this file. PHI guardrails remain unchanged: Langfuse traces stay metadata-only pending a signed BAA and US-residency confirmation, and real-trace eval-candidate capture remains deferred per the same PHI policy inherited from the parent spec.