> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# PF-111 Unified AI Gateway Integration

> Integration stub for PF-111, the unified AI gateway consolidation in Platform Foundation.

# PF-111 — Unified AI Gateway Integration

**Spec:** [PF-111 Unified AI Gateway Consolidation](https://github.com/Encore-OS/encoreos/blob/development/specs/pf/specs/PF-111-unified-ai-gateway.md)
**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

| Field           | Value                                                                                                                                                                                                     |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Provider        | Vercel AI Gateway                                                                                                                                                                                         |
| Protocol        | HTTPS, OpenAI-compatible (`/v1/chat/completions`)                                                                                                                                                         |
| Model selection | `"provider/model"` strings; ordered list → gateway-native fallback                                                                                                                                        |
| Auth            | Bearer token, single `AI_GATEWAY_API_KEY` Edge Function Secret (read via `requireEnv` in `vercel-gateway.ts`; Edge Function Secret per PM-15-P2 — `vault.decrypted_secrets` not service\_role-accessible) |
| Data retention  | Zero-Data-Retention (confirmed 2026-05-29)                                                                                                                                                                |
| BAA             | In place with Vercel (confirmed 2026-05-29)                                                                                                                                                               |

## Consumers (16 edge functions)

All AI-calling edge functions import only `supabase/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`, optional `tools`, `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 throws `PhiLaneNotConfiguredError` for any module that does not. As of 2026-05-29, the clinical (`cl`) and practice management (`pm`) modules are enabled on the PHI lane with `anthropic/claude-sonnet-4.6` (primary) and `openai/gpt-4o` (fallback) — both BAA-covered through the Vercel AI Gateway. All other modules continue to fail closed on `lane: 'phi'`.

## PHI lane routing

The PHI lane is **fail-closed by default**. Any module that calls `resolveModels(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:

| Module                            | Primary                       | Fallback        |
| --------------------------------- | ----------------------------- | --------------- |
| `cl` (Clinical, CL-36)            | `anthropic/claude-sonnet-4.6` | `openai/gpt-4o` |
| `pm` (Practice Management, PM-64) | `anthropic/claude-sonnet-4.6` | `openai/gpt-4o` |

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.

```ts theme={null}
// supabase/functions/_shared/ai/models.ts
export const PHI_MODELS: Record<string, string[]> = {
  cl: ['anthropic/claude-sonnet-4.6', 'openai/gpt-4o'],
  pm: ['anthropic/claude-sonnet-4.6', 'openai/gpt-4o'],
};
```

## 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`).

| Field                         | Value                                                                                                                                                                                                                                                                                                                                                                                        |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Provider                      | Langfuse Cloud SaaS                                                                                                                                                                                                                                                                                                                                                                          |
| Production endpoint (default) | `https://cloud.langfuse.com` (EU) — set by `DEFAULT_BASE_URL` in `tracing.ts` when `LANGFUSE_BASE_URL` secret is absent                                                                                                                                                                                                                                                                      |
| Recommended endpoint          | `https://us.cloud.langfuse.com` (US) — see residency recommendation below                                                                                                                                                                                                                                                                                                                    |
| Dev MCP tool                  | `https://us.cloud.langfuse.com/api/public/mcp` (registered in `.mcp.json`)                                                                                                                                                                                                                                                                                                                   |
| BAA                           | Not executed — not required under the current metadata-only posture                                                                                                                                                                                                                                                                                                                          |
| PHI posture                   | **Metadata-only invariant**: prompt and completion content are never attached to observations on any lane (including `phi`). Only model name, token usage, latency, lane, module, finish reason, sanitized error text, and JWT-derived correlation IDs (userId/sessionId) are transmitted. Live-verified 2026-06-03: `input`/`output` null on every trace including `ai.chat:cl` (PHI lane). |
| Backstop                      | `tracing-mask.ts` `mask()` passed to `LangfuseSpanProcessor` — redacts SSN/email/phone/CC from any attribute value before transmission. Defense-in-depth only; not a HIPAA de-identification engine.                                                                                                                                                                                         |

**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:

1. Execute a Langfuse BAA.
2. Rotate `LANGFUSE_BASE_URL` to `https://hipaa.cloud.langfuse.com` (or a self-hosted instance).
3. Update [AI\_SUBPROCESSOR\_BAA\_POSTURE.md](/compliance/AI_SUBPROCESSOR_BAA_POSTURE) and the REGULATORY\_COMPLIANCE\_TRACKER row.

Full posture documentation: [AI\_SUBPROCESSOR\_BAA\_POSTURE.md](/compliance/AI_SUBPROCESSOR_BAA_POSTURE).

## Open items

* Confirm `"provider/model"` ids (incl. an embedding model for `generate-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](../../../specs/pf/specs/PF-111-EN-01-ai-usage-audit-ledger-cost-governance.md)
**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-28

#### Producer / Consumer Matrix

| Role                     | Core / Module                                                                     | Surface                                                                                                                                                                                                |
| ------------------------ | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Producer                 | PF — AI gateway (`_shared/ai/usage.ts`)                                           | Writes one `pf_ai_usage_logs` row per gateway completion (success / error / throttled), carrying agent/session/task dimensions when the caller is an agent principal                                   |
| Producer                 | PF — PHI-access path (`_shared/ai/agent-usage.ts` + `pf_record_agent_phi_access`) | Writes one `pf_agent_phi_access_log` row per agent PHI touch (read or write), fail-closed                                                                                                              |
| Consumer (alert sink)    | PF-10 — Notifications                                                             | `pf-check-ai-usage-anomalies` edge function (scheduled hourly) emits deduplicated `ai_usage_anomaly` notifications via `createNotification()` on anomaly detection                                     |
| Consumer (budget source) | PF-43 — Tenant Resource Quotas                                                    | The gateway reads per-org soft / hard budget limits and grace window to evaluate the spend cap before dispatch (FR-5); absent PF-43 entry degrades gracefully (no cap, cost still logged)              |
| Attribution source       | PF-30-EN-01 — AgentPrincipal                                                      | `agent_principal_id` UUID is the identity stamped on ledger rows and PHI-access rows; loose ref (no FK)                                                                                                |
| Run context source       | PF-125 — Durable Runs / Tasks                                                     | `session_id` ≡ PF-125 `run_id`; `parent_task_id` ≡ PF-125 `task_id`; run policy supplies per-agent / per-task budget limits fed into FR-9                                                              |
| Governance source        | PF-126 — Per-action Governance                                                    | `governance_approval_id` is a soft ref to `pf_agent_action_approvals.id`; required for every PHI write (FR-12); validated via `to_regclass` guard (no-op until PF-126 deploys)                         |
| Consumer (fleet reads)   | PF-130 — Agent Fleet Control Tower                                                | Calls `pf_agent_usage_rollup(org, since)` RPC for per-agent / per-session cost, token, latency, and PHI-touch aggregates; owns no schema here                                                          |
| Indirect producers       | CL, PM, GR, FA, HR, CE, and other domain cores                                    | Every edge function calling `AIProvider.chat()` / `chatWithTools()` / `stream()` / `embed()` triggers a ledger row as a side effect; the `module` column carries the core slug (e.g. `cl`, `pm`, `gr`) |

#### 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 direct `createNotification()` 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):**

| Field              | Value                                                                          |
| ------------------ | ------------------------------------------------------------------------------ |
| `notificationType` | `ai_usage_anomaly`                                                             |
| `channel`          | `in_app` (plus email and Slack fan-out per `pf_ai_usage_alert_configs`)        |
| `title`            | `AI Usage Alert: <config.name>`                                                |
| `body`             | `<metric_type>: <value> (threshold <comparison> <threshold>)` — no PHI content |
| `priority`         | `high` when `metricValue > threshold * 2`; `normal` otherwise                  |
| `actionUrl`        | `/platform/settings/ai-usage`                                                  |
| `referenceType`    | `pf_ai_usage_alert_configs`                                                    |
| `metadata`         | `{ metric_type, metric_value, threshold }` — no PHI values                     |

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)**

```sql theme={null}
pf_record_agent_phi_access(
  p_organization_id        UUID,
  p_agent_principal_id     UUID,
  p_authorizer_user_id     UUID,
  p_operation              TEXT,            -- 'read' | 'write'
  p_resource_table         TEXT,
  p_resource_ref           UUID DEFAULT NULL,
  p_session_id             UUID DEFAULT NULL,
  p_parent_task_id         UUID DEFAULT NULL,
  p_governance_approval_id UUID DEFAULT NULL,  -- required for 'write' (FR-12)
  p_phi_category           TEXT DEFAULT NULL,  -- e.g. 'clinical' | 'sud_part2'
  p_correlation_id         TEXT DEFAULT NULL
) RETURNS UUID
```

Grants: `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)**

```sql theme={null}
pf_agent_usage_rollup(
  p_organization_id UUID,
  p_since           TIMESTAMPTZ DEFAULT (now() - interval '30 days')
) RETURNS TABLE (
  agent_principal_id UUID,
  session_id         UUID,
  calls              BIGINT,
  total_tokens       BIGINT,
  total_cost_usd     NUMERIC,
  total_latency_ms   BIGINT,
  phi_touches        BIGINT
)
```

Gated on `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_usage_rollup(p_organization_id, p_billing_month)
RETURNS TABLE (billing_month, consumer_module, model_used, total_tokens, estimated_cost_usd)
```

Not yet materialized. Depends on `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. Evaluates `task → agent → org` hard 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 }>` — calls `pf_record_agent_phi_access` via RPC; throws `PhiAccessLogError` on 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 to `pf_ai_usage_logs` is planned (FR-2) but not yet wired.

**Gateway pre-dispatch spend-cap — planned (FR-5 / FR-9)**

When wired into `_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

| Column                      | Type                                  | Notes                                                                        |
| --------------------------- | ------------------------------------- | ---------------------------------------------------------------------------- |
| `id`                        | UUID PK                               |                                                                              |
| `organization_id`           | UUID NOT NULL → `pf_organizations.id` | Tenant isolation anchor; RLS-gated                                           |
| `module`                    | TEXT                                  | Core slug (e.g. `cl`, `pm`, `gr`, `fa`, `hr`, `ce`)                          |
| `model`                     | TEXT                                  | Model used                                                                   |
| `feature`                   | TEXT (nullable)                       |                                                                              |
| `prompt_tokens`             | INT (nullable)                        | Count only — no content                                                      |
| `completion_tokens`         | INT (nullable)                        | Count only — no content                                                      |
| `total_tokens`              | INT (nullable)                        | Count only — no content                                                      |
| `cost`                      | NUMERIC (nullable)                    | Estimated cost USD; NULL when model not yet in pricing table                 |
| `success`                   | BOOLEAN                               |                                                                              |
| `error_type`                | TEXT (nullable)                       | Sanitized error class; no PHI                                                |
| `duration_ms`               | INT (nullable)                        |                                                                              |
| `metadata`                  | JSONB                                 | No PHI values                                                                |
| `user_id`                   | UUID → `pf_profiles.id`               | Human caller; `service-role` path uses NULL                                  |
| `created_at` / `updated_at` | TIMESTAMPTZ                           |                                                                              |
| `agent_principal_id`        | UUID (nullable)                       | FR-8: soft ref to PF-30-EN-01 AgentPrincipal; NULL for human-initiated calls |
| `session_id`                | UUID (nullable)                       | FR-8: ≡ PF-125 `run_id`                                                      |
| `parent_task_id`            | UUID (nullable)                       | FR-8: ≡ PF-125 `task_id`                                                     |
| `agent_role`                | TEXT (nullable)                       | FR-8: sanitized label; never content                                         |

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`

| Column                   | Type                                  | Notes                                                                                       |
| ------------------------ | ------------------------------------- | ------------------------------------------------------------------------------------------- |
| `id`                     | UUID PK                               |                                                                                             |
| `organization_id`        | UUID NOT NULL → `pf_organizations.id` |                                                                                             |
| `agent_principal_id`     | UUID NOT NULL                         | Soft ref to PF-30-EN-01 AgentPrincipal (no FK)                                              |
| `authorizer_user_id`     | UUID NOT NULL → `pf_profiles.id`      | The human the agent acts for                                                                |
| `operation`              | TEXT CHECK IN ('read','write')        |                                                                                             |
| `resource_table`         | TEXT                                  | Soft ref — e.g. `cl_assessments` (no FK; any-core record)                                   |
| `resource_ref`           | UUID (nullable)                       | Soft ref — touched record id; never a PHI value                                             |
| `session_id`             | UUID (nullable)                       | ≡ PF-125 `run_id`                                                                           |
| `parent_task_id`         | UUID (nullable)                       | ≡ PF-125 `task_id`                                                                          |
| `governance_approval_id` | UUID (nullable)                       | Soft ref to PF-126 `pf_agent_action_approvals.id`; required for `write` by CHECK constraint |
| `phi_category`           | TEXT (nullable)                       | Sanitized label only (e.g. `clinical`, `sud_part2`) — never a PHI value                     |
| `correlation_id`         | TEXT (nullable)                       |                                                                                             |
| `occurred_at`            | TIMESTAMPTZ                           |                                                                                             |
| `created_at`             | TIMESTAMPTZ                           |                                                                                             |
| `created_by`             | UUID (nullable) → `pf_profiles.id`    |                                                                                             |

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)

| Column              | Type        | Notes |
| ------------------- | ----------- | ----- |
| `provider`          | TEXT        |       |
| `model`             | TEXT        |       |
| `input_per_1k_usd`  | NUMERIC     |       |
| `output_per_1k_usd` | NUMERIC     |       |
| `effective_at`      | TIMESTAMPTZ |       |

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 on `organization_id`; org-member reads; gateway / service-role writes. No content columns: `prompt_tokens`, `completion_tokens`, `total_tokens` are 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. `SELECT` requires both `pf_has_org_access` and the `pf.audit.phi_access.view` permission (compliance / admin readers only). `INSERT` is exclusively via the `pf_record_agent_phi_access` SECURITY DEFINER RPC. `UPDATE` is revoked from `authenticated`; no `DELETE` policy. Append-only audit by construction.
* **`pf_agent_usage_rollup`** — SECURITY DEFINER function; `pf.audit.phi_access.view` gated; 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_ref` are soft (text + UUID) references, enabling PHI-touch audit of any-core records without a DB-level FK. `agent_principal_id` / `session_id` / `parent_task_id` are 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.md` must exist before `pipeline_status` may advance to `compliance_reviewed` (governed spec; regulated PHI-adjacent audit trail).

#### Open Items

| ID          | Status    | Description                                                                                                             |
| ----------- | --------- | ----------------------------------------------------------------------------------------------------------------------- |
| OQ-Ext-1    | P0 — open | Reconcile `pf_ai_usage` (spec body name) vs `pf_ai_usage_logs` (live table) — rename/alias decision deferred            |
| OQ-Ext-2    | Open      | Source of per-agent / per-task budget limits (PF-125 run policy vs PF-126 vs PF-43 sub-entitlement) — not yet pinned    |
| OQ-Ext-3    | Open      | PHI-touch detection seam — explicit per-tool call vs central enforcement point in PF-125 / PF-127 data layer            |
| FR-2        | Planned   | Persist `pf_ai_usage_logs` row per gateway completion from `usage.ts`; `buildUsageRecord()` exists but does not persist |
| FR-3        | Planned   | `pf_ai_model_pricing` table and deterministic `estimated_cost_usd` computation                                          |
| FR-4        | Planned   | `pf_ai_usage_rollup` per-org billing rollup view + RPC                                                                  |
| FR-5 / FR-9 | Planned   | Pre-dispatch spend-cap wiring in `usage.ts`; `AiBudgetExceededError` class not yet declared                             |
| OQ-Ext-4    | Open      | Whether per-agent spend spikes extend `pf-check-ai-usage-anomalies` or are owned by PF-130 dashboards                   |

### PF-111-EN-02 — AI Eval / Observability Quality Gate

**Spec:** [PF-111-EN-02 AI Eval / Observability Quality Gate](../../../specs/pf/specs/PF-111-EN-02-ai-eval-observability-quality-gate.md)

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, the `supabase/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.
