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.

Platform Ambient Transcription & AI Note Generation โ€” Integration Contract

Owner: PF (Platform Foundation) Status: ๐Ÿ“‹ Specification Spec: specs/pf/specs/PF-100-platform-ambient-transcription-and-note-generation.md Last Updated: 2026-04-22
Cross-core integration contract for PF-100. Captures the boundary between PF (capture, STT, LLM, template engine, evidence map, lifecycle) and consuming cores (CL, PM, HR, GR, CE, RH). All cross-core consumption is via @/platform/transcription โ€” no direct module imports.

1. Pattern

This is a Pattern 1 (Platform Integration Layer) + Pattern 2 (Event Contracts) integration.
  • Layer: @/platform/transcription exposes hooks, components, types.
  • Events: pf.transcription.* event family published; cores subscribe via PF-66 realtime + edge-function subscriptions.
  • Tables: pf_transcription_* owned by PF; cores own their domain tables (e.g. cl_progress_notes, hr_meeting_summaries) and link via session_id UUID column (no cross-core FK except CL โ†’ PM encounter per ADR-002).

2. Scope of contract

Owned by PF (PF-100)Owned by consumer core
Capture (browser/mobile/bot/external/upload/dictation)Choosing the recording_purpose and template
Consent gate + revocation cascadeSubject-of-record CRUD
STT vendor routing + adaptersโ€”
LLM vendor routing + adaptersโ€”
Template engine + evidence mappingPer-core templates (registered under platform builtins, or per-tenant custom)
Audio storage + retention + lifecycleDomain-record retention (clinical record vs HR record vs GR record)
pf_transcription_* tablesDomain tables (cl_progress_notes, hr_meeting_summaries, gr_meeting_minutes, ce_call_outcomes, rh_resident_interactions)
BAA matrix + vendor-call auditโ€”
PF-91 evidence emission for Part 2 / consent / retention controlsDomain-specific compliance (e.g. CL-04-EN-66 Policy 940)

3. Public API surface (@/platform/transcription)

See PF-100 spec ยง8.1 for full hook list. Core consumer pattern:
import {
  useStartTranscriptionSession,
  useReviewQueue,
  useAttestDraft,
} from '@/platform/transcription';

// CL example (encounter-linked)
const start = useStartTranscriptionSession();
await start.mutateAsync({
  module_key: 'cl',
  recording_purpose: 'cl_individual',
  encounter_id,
  subject_of_record_type: 'patient',
  subject_of_record_id: patient_id,
  source: 'browser',
});

// HR example
await start.mutateAsync({
  module_key: 'hr',
  recording_purpose: 'hr_one_on_one',
  subject_of_record_type: 'employee',
  subject_of_record_id: employee_id,
  source: 'browser',
});
Cores MUST NOT import from @/platform/ai directly for transcription concerns; the PF-100 layer wraps PF-27/PF-59 internally.

4. Event Contracts

All events published on the platform realtime + outbox pattern. Subscribers register via PF-66 (frontend) or via a database-trigger-driven edge subscription (backend).
EventPublisherSubscribersPayload
pf.transcription.session.createdPF-100CL-36 (link to encounter), PM-08 (charge prep), PF-91 (evidence){ session_id, organization_id, module_key, recording_purpose, source, subject_of_record_type, encounter_id? }
pf.transcription.session.consent_verifiedPF-100CL-11 (audit), PF-91{ session_id, consent_record_id, jurisdiction_profile_id, is_part2_program }
pf.transcription.session.consent_revokedPF-100All consumers โ€” STOP downstream processing{ session_id, revoked_by, revoked_at }
pf.transcription.session.cancelledPF-100All consumers{ session_id, reason }
pf.transcription.draft.readyPF-100CL-36 (review queue surface), HR/GR/CE/RH UIs, PF-10 (notify reviewer){ session_id, draft_id, template_id, generation_latency_ms }
pf.transcription.draft.attestedPF-100Consumer core (write domain record), PF-91 (evidence), PF-04 (audit){ session_id, draft_id, reviewer_id, attested_at, attested_content_sha256, module_attest_payload }
pf.transcription.audio.deletedPF-100PF-91, PF-04, subject-of-record portal (notify subject){ session_id, deleted_at, retention_policy }
pf.transcription.deletion_requestedPF-100Operator alert, PF-91{ session_id, requested_by, requested_at, scope }
pf.transcription.deletion_completedPF-100PF-91, subject portal{ session_id, completed_at, scope }
pf.transcription.policy.violationPF-100PF-91 (evidence), PF-10 (notify admin){ session_id, violation_type, blocked_at }

Consumed events

  • pf.consent.cl_consent.revoked (CL-11) โ€” triggers session-revocation cascade for any active CL session referencing the consent
  • pf.encounter.created (PM) โ€” optional auto-link encounter for a clinical session in pre-record state
  • pf.encounter.cancelled (PM) โ€” cancels any in-progress capture for that encounter

5. Cross-core FK rules (ADR-002 compliance)

Per ADR-002 and constitution ยง5.2.7:
  • pf_transcription_sessions.encounter_id โ€” UUID column with no FK constraint to pm_encounters.id at the database level (cross-core FK exception is reserved for CLโ†’PM, not PFโ†’PM).
    • Validation is enforced at the application layer (edge function pf-transcription-start-session rejects sessions whose encounter_id does not resolve to an existing pm_encounters.id in the same organization_id at session start).
    • No trigger-enforced FK is created; an earlier draft of spec ยง7.1 implied a trigger โ€” that has been corrected.
  • pf_transcription_sessions.subject_of_record_id โ€” polymorphic UUID; no FK.
  • CL projection layer (Phase 3): cl_ambient_sessions becomes a VIEW over pf_transcription_sessions WHERE module_key='cl'. The CLโ†’PM FK from CL-36-EN-01โ€™s existing schema is preserved independently on the CL side (via a separate cl_ambient_session_encounters materialization or a CL-owned trigger that enforces the FK only when module_key='cl' AND encounter_id IS NOT NULL). PF-100 itself does not own the CLโ†’PM FK; the CL DX team retains that responsibility per ADR-002.

6. Vendor adapter contract

Each STT or LLM adapter implements a strict TypeScript interface in supabase/functions/_shared/transcription-vendors/. PF-100 spec ยงFR-2.3 defines the STT contract; the LLM adapter contract mirrors PF-27/PF-59.
VendorTierBAAAdapter file
Deepgram Nova-3 Medicalprimary STTrequired (enterprise)_shared/transcription-vendors/deepgram-nova3-medical.ts
AssemblyAI Universal-3 Pro + Medical Modefailover STT, EU residencyself-serve_shared/transcription-vendors/assemblyai-u3.ts
AWS Transcribe Medicalalternate STTAWS BAA_shared/transcription-vendors/aws-transcribe-medical.ts
AWS HealthScribe (bundled STT+LLM)alternate end-to-endAWS BAA_shared/transcription-vendors/aws-healthscribe.ts
Azure AI Speechalternate STTMicrosoft BAA_shared/transcription-vendors/azure-speech.ts
OpenAI Whisper / gpt-4o-transcribealternate STT (ZDR)OpenAI BAA_shared/transcription-vendors/openai-whisper.ts
Self-hosted WhisperXhigh-sensitivity STTn/a (on-prem)_shared/transcription-vendors/whisperx-self-hosted.ts
Anthropic Claude (Bedrock)primary LLMAWS BAA_shared/transcription-vendors/claude-bedrock.ts
Azure OpenAI GPT-4oalternate LLMMicrosoft BAA_shared/transcription-vendors/azure-openai.ts
Google Vertex Gemini 2.5 Proalternate LLMGoogle BAA_shared/transcription-vendors/vertex-gemini.ts
Self-hosted Llama 3.3 70Bhigh-sensitivity LLMn/a_shared/transcription-vendors/llama-self-hosted.ts
Recall.aimeeting botRecall.ai BAA_shared/transcription-vendors/recall-bot.ts
Plaud Developer Platformexternal recorderPlaud BAA_shared/transcription-vendors/plaud-device.ts
Vendor BAA expiry monitor (pf-transcription-vendor-baa-monitor cron) emits PF-91 evidence + alerts at 30 / 14 / 7 day thresholds.

7. CL-36 migration contract (Phase 3)

Non-breaking. Sequence:
  1. cl_ambient_sessions continues writing through CL-36 hooks; PF-100 hooks are added in parallel and wrap the same vendor calls.
  2. CL backend swap: cl_ambient_sessions becomes a VIEW over pf_transcription_sessions WHERE module_key='cl'; cl_ambient_transcripts similarly over pf_transcription_segments.
  3. CL-36 attribution overlay (cl_ai_note_attributions) consumes pf.transcription.draft.attested event with module_attest_payload.cl_progress_note_id.
  4. CL-36 hooks become deprecated shims; deletion in next major release per constitution ยง8.4 deprecation policy.
The CL-36-EN-01 deferred Phase 2 (group sessions, multi-language) is delivered through PF-100 Phase 2 (group de-identification) and Phase 2/3 (multi-language templates).

8. PF-96 jurisdiction profile extension contract (PF-96-EN-RECORDING)

PF-100 requires PF-96 enhancement adding a new top-level recording_rules JSONB DEFAULT '{}' NOT NULL column to pf_jurisdiction_profiles (the policy_json column referenced by an earlier draft does not exist; the actual JSONB columns on the table are clinical_rules, billing_rules, compliance_rules, metadata). All recording-policy keys live under recording_rules.*. Keys (see PF-100 spec ยง7.2 for the authoritative list):
  • recording_consent_model
  • wiretap_class_severity
  • recording_max_retention_days_part2
  • recording_max_retention_days_general_clinical
  • recording_max_retention_days_hr
  • recording_max_retention_days_gr
  • external_recorder_allowed
  • external_recorder_forbidden_for_part2
  • mental_health_record_retention_years
  • requires_visible_recording_indicator
  • requires_per_participant_verbal_affirmation
  • recording_pause_resume_consent_threshold_seconds
Tracked as a PF-96 enhancement in specs/cross-cutting/MULTI-STATE-COMPLIANCE-ENHANCEMENT-CATALOG.md and authored at specs/pf/enhancements/PF-96-EN-RECORDING-recording-consent-jurisdiction-fields.md. PF-100 Phase 0 includes the corresponding migration.

8A. PF-71 dependency contract (patient-name list lookup)

Spec ยงFR-3.4 (co-attendee de-identification) requires a server-side patient-name list lookup to verify that AI-generated draft text does not leak names of patients who are NOT the subject of record (e.g. group-session co-attendees). Expected API (PF-71 to provide; consumed by pf-transcription-generate-note edge function):
// supabase/functions/_shared/pf-71/patient-name-list.ts (PF-71 owned)
export async function pf71PatientNameList(args: {
  organization_id: string;
  encounter_id?: string;          // when present, returns names of all patients linked to the encounter
  group_session_id?: string;      // when present, returns names of all attendees of the group session
  context: 'draft_redaction';
}): Promise<{ names: string[]; phonetic_variants: string[]; }>;
Behavior:
  • Returns first/last/preferred names + phonetic/common-misspelling variants for every patient in scope.
  • Excludes the subject-of-record (caller passes subject_of_record_id separately).
  • Server-side only โ€” never invoked from the browser.
  • Names are used solely for redaction matching; PF-100 MUST NOT log returned names. Edge function logs only counts ({ matched_count: N }).
Status: PF-71 currently exposes patient-context primitives but not this exact list-lookup. PF-100 Phase 0 includes a sub-task to either (a) confirm an existing PF-71 RPC is sufficient, or (b) scope a small PF-71 enhancement to add pf_71_patient_name_list(). Tracked in PF-100-TASKS.md Phase 0 prerequisites.

9. PF-91 evidence emission contract

For every attested session, PF-100 emits structured evidence:
  • Part 2 control evidence (is_part2_program=true only): consent record id + version, segregation hash (Part 2 KMS alias confirmation), retention proof, deletion proof.
  • All-party consent control evidence: per-participant consent acknowledgment timestamps, jurisdiction profile id, recording-indicator-shown proof.
  • Retention control evidence: applied retention policy, scheduled deletion date, actual deletion timestamp.
  • BAA-coverage control evidence: vendor id, BAA evidence id, model version, call counts.
Evidence rows are written to pf_compliance_evidence (PF-91) with source='pf-100-transcription' and evidence_kind per row above.

10. Audit & enforcement

  • npm run audit:integration-contracts โ€” verifies this file is referenced from PF-100 spec
  • npm run audit:permissions โ€” verifies all keys in PF-100 ยง6 are seeded
  • npm run audit:routes-navigation โ€” verifies any new routes (e.g. /platform/transcription/sessions, /platform/transcription/review) are registered


Activating a Vendor (Runbook)

Until these four steps are completed for at least one STT vendor, every call to pf-transcription-stt-stream returns 409 vendor_baa_inactive. LLM note generation works today via Lovable AI Gateway (no BAA gate).
  1. Sign the BAA โ€” paper artifact between the org and the vendor (Deepgram / AssemblyAI / AWS). Cannot be code-completed.
  2. Register the BAA row in pf_transcription_vendor_baas:
    INSERT INTO pf_transcription_vendor_baas
      (organization_id, vendor_id, status, baa_signed_at, baa_expires_at)
    VALUES ('<org>', '<vendor_id>', 'active', now(), now() + interval '1 year');
    
    Use the Settings โ†’ Transcription โ†’ Vendors UI (VendorBaaTable) instead of raw SQL when possible.
  3. Add the API key to PF-76 vault under the credential name expected by the adapter (e.g. deepgram_api_key). The router calls pf_retrieve_credential(org_id, name); missing keys surface as vendor_baa_inactive with reason: 'missing_credential'.
  4. (Optional) Add a routing rule in pf_transcription_jurisdiction_routing so a specific (jurisdiction_code, recording_channel) resolves to this vendor instead of the org default.
The JurisdictionRoutingDialog shows a live resolver preview so admins can confirm routing before saving. The VendorBaaTable displays a green/amber/red status dot per BAA so live status is visible at a glance.