Skip to main content

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.

Feature ID: CL-36
Status: πŸ“‹ Specification
Spec Reference: CL-36-ai-assisted-clinical-documentation.md
Last Updated: 2026-03-31
Last Verified: β€”

Table of Contents


Overview

CL-36 provides platform-level AI documentation capability across note types (CL-04 progress notes, CL-14 group notes, CL-24 telehealth notes). It creates AI session audit records (cl_ai_documentation_sessions) and per-note attribution records (cl_ai_note_attributions). AI vendor calls are made exclusively from edge functions β€” no PHI flows client-side to AI vendors. Org-level opt-in is required; 42 CFR Part 2 consent gate (CL-11) is enforced before any AI vendor call.

Quick Reference

ItemValue
Core tablescl_ai_documentation_sessions, cl_ai_note_attributions
Settings columnscl_ai_documentation_enabled, cl_ai_ambient_vendor, cl_ai_data_residency, cl_ai_policy940_enforcement on cl_module_settings
Permission keyscl.ai_documentation.use, cl.ai_documentation.admin
42 CFR Part 2 gatecl_check_sud_consent(chart_id, 'ai_documentation', auth.uid()) from CL-11 (three-argument signature; edge: use p_requesting_user from JWT)
AI platform layer@/platform/ai (PF-27) when available; edge function adapter otherwise
Session lifecycleinitiated β†’ draft_generated β†’ attested (or cancelled)

Integration Points

FromToPatternNotes
CL-36CL-04Data write (adds cl_ai_note_attributions linked to progress note)Phase 1
CL-36CL-14Data write (same attribution pattern for group notes)Phase 3
CL-36CL-24Data write (same attribution pattern for telehealth notes)Phase 3
CL-36CL-11Function call (cl_check_sud_consent)Before every AI vendor call
CL-36PF-27 (Platform AI)Platform LayerIf/when PF-27 available; interim: direct edge function
CL-36PF-02 / PF-30Platform Layer (auth, RBAC, audit)Permission gate on cl.ai_documentation.use
CL-36pm_encountersFK / Data Lookupcl_ai_documentation_sessions.encounter_id β†’ pm_encounters.id (ADR-002)
CL-36External AI VendorsAPI (edge function only; Phase 3 for ambient)BAA required; API keys in Supabase Vault

Data Contracts

cl_ai_documentation_sessions (audit log β€” immutable)

ColumnTypeDescription
iduuid PK
organization_iduuidTenant anchor (RLS)
user_iduuid β†’ pf_profilesClinician who initiated
chart_iduuid β†’ cl_chartsPatient chart
encounter_iduuid β†’ pm_encountersLinked encounter
note_iduuidPolymorphic; see note_type
note_typetext CHECK'progress_note' | 'group_note' | 'telehealth_note'
statustext CHECK'initiated' | 'draft_generated' | 'cancelled' | 'attested'
draft_sourcetext CHECK'structured_data' | 'ambient_voice'
ai_vendortextVendor slug (ambient only); null for structured-data
session_started_attimestamptz
session_ended_attimestamptznull if cancelled
attestation_attimestamptzPopulated on attestation
attestation_byuuid β†’ pf_profiles
custom_fieldsJSONB
created_at, updated_at, created_by, updated_byaudit

cl_ai_note_attributions

ColumnTypeDescription
iduuid PK
organization_iduuidTenant anchor (RLS)
note_iduuidMatches cl_ai_documentation_sessions.note_id
note_typetext CHECKSame values as sessions
ai_session_iduuid β†’ cl_ai_documentation_sessions
ai_assistedboolean
attribution_labeltext'Drafted with AI assistance' (default)
ai_attestation_attimestamptzUpdated on attestation
ai_attestation_byuuid β†’ pf_profiles
custom_fieldsJSONB
created_at, updated_at, created_by, updated_byaudit

Canonical AI Draft Interfaces (Clarification #13)

The edge function uses canonical request/response interfaces for testability and minimum-necessary PHI enforcement. Vendor adapters map these to vendor-specific payloads.
interface AiDraftRequest {
  diagnosisCodes: string[];        // ICD-10 codes only
  assessmentScoreSummaries: string[]; // Numeric scores, not raw responses
  treatmentPlanGoalText: string[];
  priorNoteSummary: string | null; // AI-generated summary, not full text
  noteType: 'progress_note' | 'group_note' | 'telehealth_note';
  serviceType: string;
  encounterDate: string;           // ISO date
}

interface AiDraftResponse {
  draftText: string;
  confidenceMetadata?: Record<string, unknown>;
  tokenUsage?: { promptTokens: number; completionTokens: number };
}

PHI Inclusion/Exclusion Lists (Clarification #19)

Included (minimum necessary): diagnosis codes (ICD-10), assessment instrument scores (numeric only), treatment plan goal summaries, prior note summary (AI-generated, not full text), service type, encounter date. Excluded (never sent): patient name, DOB, SSN, address, phone, email, insurance IDs, financial data, photo/biometric data, SUD-specific identifiers beyond CL-11 consent gate. Edge function enforces both lists.

API Key Model (Clarification #11)

Hybrid β€” platform-level default key with per-tenant override. Edge function checks AI_VENDOR_{TENANT_ID}_API_KEY first (where TENANT_ID is derived from verifiedOrgId), falls back to AI_VENDOR_DEFAULT_API_KEY. Tenant resolution uses verifiedOrgId from the verified JWT/user profile only. Any organization_id, organizationId, or similar field in the request body is ignored server-side to prevent tenant spoofing; clients must not rely on body org for tenancy or key selection.

Concurrency Control (Clarification #16)

One active session per note at a time; multiple notes can generate concurrently. Edge function checks for existing session with (note_id, note_type) where status = 'initiated' within the timeout window; rejects with user-friendly message if in-flight.

Session Update Scope (Clarification #14)

Only lifecycle fields may be updated after INSERT: status, attestation_at, attestation_by, session_ended_at, updated_at, updated_by. All other columns are immutable. Phase 1: application logic; Phase 2: trigger-based guard.

Data Residency (Clarification #20)

Phase 1 (US only): contractual via BAA. Phase 3 (when EU added): edge function selects vendor’s region-specific API endpoint based on cl_ai_data_residency. Adapter pattern supports per-vendor endpoint mapping.

Event Contracts

CL-36 does not publish events in Phase 1 or 2. Phase 3 consideration: if AI draft generation failure needs to notify the clinician asynchronously, a cl_ai_draft_failed event may be added. No contract defined yet.

Edge Function Contracts

cl-ai-generate-draft (Phase 2)

Generates a note draft from structured encounter data. Called from the browser via authenticated Supabase client; does not send raw PHI to the AI vendor without first invoking cl_check_sud_consent. Request (from browser β†’ edge function): JSON body includes note context only. Do not send organization_id for tenancy β€” the edge function derives org from the authenticated session (verifiedOrgId).
{
  "chart_id": "uuid",
  "encounter_id": "uuid",
  "note_id": "uuid",
  "note_type": "progress_note | group_note | telehealth_note"
}
Response:
{
  "session_id": "uuid",
  "draft": "string (AI-generated note text)",
  "attribution_label": "Drafted with AI assistance",
  "model_used": "vendor:model-slug"
}
Error cases:
  • 403 SUD_CONSENT_NOT_CLEARED β€” 42 CFR Part 2 gate triggered
  • 403 AI_DOCUMENTATION_DISABLED β€” org opt-in not enabled
  • 503 AI_VENDOR_UNAVAILABLE β€” graceful degradation; app continues without draft
Edge function standards:
  • Deno.serve() only
  • getCorsHeaders(req.headers.get('origin')) from _shared/cors.ts
  • createLogger from _shared/logger.ts; no PHI in log messages
  • JWT verified on every request; use verifiedOrgId from JWT/profile for RLS, session rows, and AI_VENDOR_{TENANT_ID}_API_KEY resolution β€” ignore any org id in the request body

Security and RLS

  • Both tables have RLS enabled via cl_check_ai_session_access(session_org_id) SECURITY DEFINER function
  • No DELETE policy on either table (immutable audit records)
  • AI vendor API keys stored in Supabase Vault; accessed only from edge functions
  • No PHI stored in cl_ai_documentation_sessions beyond FKs; note text is never persisted to the audit log
  • cl_check_sud_consent() from CL-11 must be invoked before every AI vendor call

External Vendor Integration (Phase 3)

Ambient voice vendors (Nabla, Nuance DAX, Abridge, Suki) integrated via a common adapter pattern in a single edge function (cl-ai-ambient-draft). The vendor is determined by cl_ai_ambient_vendor on cl_module_settings. Each vendor implements the adapter interface:
interface AiVendorAdapter {
  healthCheck(): Promise<boolean>;
  generateDraft(context: EncounterContext): Promise<AiDraftResult>;
}
  • healthCheck(): Each adapter must implement healthCheck() returning true when the vendor API is reachable, false otherwise. Used to fail fast before sending PHI.
  • Edge function behavior: Before calling generateDraft(context), the edge function must call adapter.healthCheck() (adapter selected from cl_ai_ambient_vendor via factory). If healthCheck() returns false, respond with 503 AI_VENDOR_UNAVAILABLE instead of relying solely on exception handling; do not call generateDraft in that case. generateDraft implementations remain unchanged.
  • Adapter factory: Any factory or selection code that returns adapters must ensure returned adapters implement the full interface including healthCheck.
Vendor SDK imports are confined to the edge function; no vendor SDKs in React components.

Common Mistakes

MistakeMitigation
Sending PHI to AI vendor from browserAll vendor calls must be in edge functions only
Not invoking cl_check_sud_consent before AI callRequired; hard block on failure
Skipping BAA with AI vendorBAA must be in place before any PHI flows to vendor
Using note_type as an unvalidated stringAlways use CHECK constraint values
Allowing note finalize without attestationcl_ai_note_attributions.ai_attestation_at must be non-null before finalize