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

# FUA/FUI Follow-Up Measures — Integration

> Integration contract for the two NCQA HEDIS substance-use follow-up measures — consumer contracts, registry registration, and Part 2 segmentation.

**Spec:** CL-29-EN-66 — FUA & FUI Follow-Up Measures · **Status:** spec `draft`, human-merge (regulated CL/SUD core)
**Companion trace:** DS4P label propagation is documented separately in
[CL-29-EN-66-DS4P-PROPAGATION.md](./CL-29-EN-66-DS4P-PROPAGATION.md) — this doc does **not** restate it.
**Regulatory:** NCQA HEDIS FUA/FUI (MY2025 + MY2026), CMS Medicaid Adult Core Set / SUPPORT Act §5001,
42 CFR Part 2, HIPAA 45 CFR 164, AHCCCS DAP, Information Blocking (21st Century Cures).
**Sign-off:** [`specs/cl/reviews/CL-29-EN-66-COMPLIANCE-SIGNOFF.md`](../../../specs/cl/reviews/CL-29-EN-66-COMPLIANCE-SIGNOFF.md) (Approved with Conditions).

This is the integration picture for the two NCQA HEDIS SUD follow-up measures —
**FUA** (Follow-Up After ED Visit for Substance Use) and **FUI** (Follow-Up After
High-Intensity SUD Care) — each computed as a 7-day and a 30-day rate. CL-29-EN-66 is a
**measures-only** spec: it emits an at-risk cohort to CL-35 and owns no outreach, and it
extends the shipped EN-65 FUH/FUM substrate rather than standing up a parallel surface.

> **Honest status:** the measure engine, substrate, RLS, ADT chokepoint, MY-versioned
> persistence, payer-export gate, and DS4P fail-close are built and tested on branch
> `feat/cl-29-en-66-fua-fui`. The **runtime invoker** that computes the FUA/FUI set under a
> resolved PF-96 Measurement Year and drives the persist / cohort-emit / CL-51 registration
> is the future **CL-51 eCQM runner / PM-03 canonical path**, which has **not landed** —
> several typed service wrappers (`fuaAdtIngest.ts`, `hedisMeasurePersist.ts`) intentionally
> have **no production call site yet** and are exercised by integration tests. Four external
> compliance gates ship **fail-closed** and remain **human-verify-open** (see §7).

***

## 1. PF-108 Contexture ADT consumer contract

Out-of-network ED-for-SUD visits are not visible in `pm_encounters` (the patient was seen at
another facility), so FUA's denominator needs an external admit/discharge/transfer (ADT) feed.
That feed is **PF-108 Contexture HIE**. EN-66 consumes it into a dedicated table,
`cl_fua_adt_events` — the sanctioned FR-7 exception (ADT shape ≠ aftercare-plan shape).

* **Ingest path.** The sanctioned write surface is the SECURITY DEFINER RPC
  `cl_ingest_fua_adt_event(...)` (typed wrapper `src/cores/cl/services/fuaAdtIngest.ts`). It
  re-asserts tenancy server-side (`cl_has_org_access` → `42501`; chart∈org → `42501`) because
  DEFINER bypasses RLS. A `NULL auth.uid()` (service-role feed) is the accepted-risk H-2 path,
  mirroring PM-75 — the feed runs as `service_role`, not as an end user.
* **Direct-write chokepoint.** The table is also directly writable (RLS only checks
  `cl_has_org_access(organization_id)`), so **two BEFORE-row triggers fire on every write path**
  (direct PostgREST, service-role feed, and the RPC) and cannot be bypassed:
  * `cl_fua_adt_events_derive_biu()` derives `sud_indicated` **fail-closed** — an absent /
    indeterminate / unparseable SUD signal resolves to `true` (presumed SUD, maximum Part 2
    protection) — and sets `ds4p_confidentiality_code := 'R'` for SUD rows. It also enforces the
    chart∈org chokepoint (`42501`).
  * `cl_fua_adt_events_ds4p_label_biu()` fail-closes `ds4p_security_label` (see §5 / the DS4P
    trace doc).
* **SUD derivation is never a hardcoded code list.** `sud_indicated` is derived from
  dx / CL-62 episode metadata + instrument NOMs domains, never an inline F10–F19 list (the CL-69
  lesson; the SUD flag is also the RLS read-gate key).
* **Planning-stub caveat.** PF-108 is a **planning stub, not a live feed.** The chokepoint,
  fail-close, and RLS isolation are proven by tests; **live end-to-end ADT ingest is
  human-verify-open** (gate, §7).

## 2. CL-51 measure-spec registration

The four measure variants — **`FUA-7`, `FUA-30`, `FUI-7`, `FUI-30`** — are registered as
MY-stamped snapshots in `cl_quality_measure_periods` via the hardened RPC
`cl_persist_hedis_measure_period(...)` (typed wrapper
`src/cores/cl/services/hedisMeasurePersist.ts`; `measureId` is the variant key).

* **MY selected from PF-96 at evaluation time.** The active Measurement Year ruleset
  (`MY2025` vs `MY2026`) is read from PF-96 `ComplianceRules.active_measurement_year_version` at
  evaluation time — **never** `new Date().getFullYear()` (AC-2). MY2025 applies the
  principal-position SUD-dx denominator rule; MY2026 applies any-position SUD dx and counts peer
  support + residential as qualifying follow-up. The measure-spec loader
  (`src/cores/cl/utils/fua-fui-measure-spec.ts`) builds all params from PF-96.
* **No hardcoded NCQA OIDs (NFR-config-1).** The loader carries **no** NCQA value-set codes.
  Per-MY value-set OIDs are expected to be loaded into the CL-51 measure-spec registry from the
  licensed NCQA portal — that acquisition is **gate 6, human-verify-open** (§7). The engine
  encodes only the *documented* MY2025/MY2026 ruleset shape; the codes themselves come from the
  registry, not from source.

## 3. Denominator sourcing — interim proxy decision (PM-03 pending)

The canonical `pm_encounters.encounter_type` enum
(`outpatient | iop | php | crisis | group | telehealth | evaluation | residential_daily`) has
**no ED or acute-inpatient value**. Until PM-03 lands canonical encounter classes, EN-66 uses an
**EN-65-consistent interim proxy**, entirely behind PF-96 config:

* **FUA denominator** → `crisis` / `evaluation` encounters **with a SUD indication** (plus the
  PF-108 ADT out-of-network ED events from §1).
* **FUI denominator** → `residential_daily` encounters. The NCQA-default high-intensity scope is
  residential + acute-inpatient SUD; the PF-96 opt-in `fui_high_intensity_expansion` adds PHP/IOP
  (`FUI_HIGH_INTENSITY_EXPANSION_TYPES`) — see the admin guide for the benchmarkability trade-off.

The canonical PM-03 path is explicitly stubbed `TODO(PM-03)` in code. **This is a known interim
decision**, the same approach shipped and approved in EN-65; correctness is refined when PM-03
delivers canonical encounter types. The FUA/FUI denominator also enforces an explicit age floor —
`FUA_MIN_AGE = FUI_MIN_AGE = 13` (`src/cores/cl/types/discharge.ts`) — closing sign-off residual
item 4 (NCQA SUD measures are 13+).

## 4. CL-35 care-gap emit

EN-66 is downstream of CL-35 for outreach: a member who is **in the FUA/FUI denominator but has no
qualifying follow-up within the 7- or 30-day window** is surfaced to CL-35 as a care gap rather
than acted on by EN-66 itself. The intended emit shape writes `cl_care_gaps` with
`gap_type = 'follow_up_not_scheduled'` (a real CL-35 care-gap type) and a `source_rule` naming the
measure/window (e.g. `EN-66-FUA-7DAY`, `EN-66-FUI-30DAY`). EN-66 owns no work-list UI — CL-35's
care-gap work list, clinician panels, and supervisor view consume the gap. As with §2/§3, the
emit is driven by the not-yet-wired CL-51/PM-03 eCQM runner (the cohort capability is built and
tested; the production call site lands with the runner).

## 5. DS4P leg (cross-link, not restated)

SUD ADT rows in `cl_fua_adt_events` are DS4P-labeled fail-closed at the DB chokepoint
(`ds4p_confidentiality_code = 'R'`, `ds4p_security_label = '42CFRPart2,ETH|NORDSLCD'`), and that
label's redisclosure obligation is **operationalized as BLOCKING before any payer export** by the
T4.1 consent gate (`cl_fua_payer_export_gate`). The full propagation chain, the TS↔DB SSOT
drift-trap test, the trigger fire-order, and the CL-63 boundary are documented in
[CL-29-EN-66-DS4P-PROPAGATION.md](./CL-29-EN-66-DS4P-PROPAGATION.md). **A SUD row cannot reach a
payer destination without active 42 CFR Part 2 consent.**

## 6. T4.3 hardening-audit evidence

Read-only audit of every new DB security object on the branch. Columns: `SD?` = `SECURITY
DEFINER`; `sp?` = `SET search_path = public`; `own?` = `OWNER TO postgres`; `rev?` = `REVOKE
EXECUTE FROM anon, PUBLIC`; `org-guard?` = server-side tenancy re-assert raising `42501`.

| Object                                                    | Migration        | SD?                  | sp?                      | own? | rev?                                                    | org-guard (42501)?                                                               | Notes                                                                                                                                                      |
| --------------------------------------------------------- | ---------------- | -------------------- | ------------------------ | ---- | ------------------------------------------------------- | -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cl_derive_fua_sud_indicated(uuid)`                       | `20260701000017` | ✅                    | ✅                        | ✅    | ✅ (`PUBLIC, anon, authenticated`)                       | N/A                                                                              | Internal-only STABLE helper; no direct caller (REVOKEd from all roles); enumerates **no** ICD/NCQA value sets; tenancy enforced by its callers.            |
| `cl_fua_adt_events_derive_biu()` *(trigger fn)*           | `20260701000017` | ✅                    | ✅                        | ✅    | ✅ (`PUBLIC, anon, authenticated`)                       | ✅ chart∈org → `42501`                                                            | Universal BEFORE-write chokepoint (H-1); sets `sud_indicated` fail-closed + `ds4p_confidentiality_code := 'R'`.                                            |
| `cl_ingest_fua_adt_event(...)` *(RPC)*                    | `20260701000017` | ✅                    | ✅                        | ✅    | ✅ (`PUBLIC, anon`; GRANT `authenticated, service_role`) | ✅ `cl_has_org_access` + chart∈org → `42501`                                      | Sanctioned ADT ingest. `NULL auth.uid()` = service-role feed (accepted-risk H-2, per PM-75).                                                               |
| `cl_persist_hedis_measure_period(...)` *(RPC)*            | `20260701000019` | ✅                    | ✅                        | ✅    | ✅ (`PUBLIC, anon`; GRANT `authenticated, service_role`) | ✅ `cl_has_org_access` → `42501`                                                  | MY-versioned snapshot upsert (NULLS NOT DISTINCT unique index); preserves prior-MY row, no silent overwrite (NFR-integrity-1).                             |
| `cl_fua_payer_export_gate()` *(trigger fn)*               | `20260701000020` | ✅                    | ✅                        | ✅    | ✅ (`anon, PUBLIC`; GRANT `authenticated, service_role`) | ✅ org-guard + chart∈org + `cl_check_sud_consent` + payer-disabled, all → `42501` | THE Part 2 payer-export chokepoint; writes `cl_redisclosure_log` only on the allowed-payer path; no PHI in any RAISE.                                      |
| `cl_fua_adt_events_ds4p_label_biu()` *(trigger fn)*       | `20260701000021` | ✅                    | ✅                        | ✅    | ✅ (`PUBLIC, anon, authenticated`)                       | N/A                                                                              | Label-only fail-close; fires AFTER the derive trigger (trigger-name order); no cross-tenant read, so tenancy is enforced by the co-located derive trigger. |
| `cl_fua_payer_export_requests_immutable()` *(trigger fn)* | `20260701000020` | **No (intentional)** | ✅ (`public, pg_catalog`) | ✅    | ✅ (`anon, PUBLIC`; GRANT `authenticated, service_role`) | N/A                                                                              | Append-only guard: unconditional RAISE on UPDATE/DELETE. A RAISE-only guard needs no DEFINER and no org-read.                                              |

**Per-object verdict:** all seven objects are **hardened to the CL/SUD regulated bar.** Every
SECURITY DEFINER object carries `search_path = public` + `OWNER postgres` + a REVOKE that removes
the repo baseline's auto-`EXECUTE` from `anon`/`PUBLIC`. The four DEFINER objects that read or
write cross-tenant data (the derive trigger, the ingest RPC, the persist RPC, and the export gate)
each re-assert tenancy server-side and raise `42501`. The two label/derive-only triggers and the
immutability guard are correctly marked **org-guard N/A** (no cross-tenant read — tenancy is
enforced by their callers or co-located triggers). The immutability guard is **intentionally not
DEFINER** (a RAISE-only trigger needs no elevated privilege).

**Substrate anon-grant note:** the Phase-1 substrate (`20260701000016`) copied a non-Part-2
sibling's `GRANT ALL ON TABLE cl_fua_adt_events TO anon`; the very next migration
(`20260701000017`) `REVOKE ALL ON TABLE public.cl_fua_adt_events FROM anon`, so the net state is
no anon access to the SUD ADT table.

**Redisclosure-log immutability — verified, not recreated.** The append-only immutability trigger
for the payer-export-request ledger, `cl_fua_payer_export_requests_immutable()` /
`trg_cl_fua_payer_export_requests_immutable`, **already exists in `20260701000020`** and is **not
recreated** by any later migration. The CL-11 `cl_redisclosure_log` itself is owned by CL-11;
`20260701000020` only **INSERTs** into it on the allowed-payer path and does not redefine the
table or its CL-11 immutability trigger.

**Denominator-bridge VIEW — `security_invoker` confirmed.** `cl_hedis_fuh_fum_summary` is created
`WITH (security_invoker = 'true')` in both `20260701000016` (substrate) and `20260701000018`
(denominator bridge) — the cross-tenant PHI-leak guard (the CL-69 lesson) is preserved across the
recreate.

## 7. Human-verify-open compliance gates

Four external gates ship **fail-closed** and remain **human-verify-open** (same bar as PM-75 / CL-69;
see [`CL-29-EN-66-COMPLIANCE-SIGNOFF.md`](../../../specs/cl/reviews/CL-29-EN-66-COMPLIANCE-SIGNOFF.md)
items 6 / 10a-b / 10c / 8):

1. **Gate 6 — NCQA value-set OID acquisition (sign-off item 6).** Ships: a measure-spec loader
   that hydrates OIDs from the CL-51 registry with **zero** NCQA codes inline (NFR-config-1).
   Human must verify: per-MY (MY2025 + MY2026) value-set OIDs acquired from the licensed NCQA
   portal and loaded into the CL-51 registry **before denominator logic ships to prod**.
2. **Gate 10a-b — CL-11 Part 2 export consent (sign-off item 10a-b).** Ships: `cl_fua_payer_export_gate`
   fail-closes any payer-facing SUD export at the DB unless active `cl_check_sud_consent()` and an
   explicitly-enabled org payer-export flag, writing `cl_redisclosure_log` on every permitted
   redisclosure; internal org-scoped computation is allowed, **payer-facing export disabled until
   live**. Human must verify: a valid TPO consent / individual authorization / QSOA covers the
   disclosure purpose, and ADT-derived events are not stored with identifiable SUD dx absent active
   Part 2 consent.
3. **Gate 10c — DS4P label-propagation trace vs CL-63 (sign-off item 10c).** Now **documented** —
   the T2/T4.2 trace [CL-29-EN-66-DS4P-PROPAGATION.md](./CL-29-EN-66-DS4P-PROPAGATION.md) proves the
   DB fail-close, the TS↔DB SSOT agreement, and BLOCKING-before-payer-export. Human must verify:
   **live PF-108 / Contexture feed end-to-end propagation** (PF-108 is a planning stub).
4. **Gate 8 — AHCCCS DAP per-year measure weighting (sign-off item 8).** Ships: per-MY weighting
   externalized to PF-96 (no hardcoded weights). Human must verify: direct AHCCCS QM-team
   confirmation of whether FUA/FUI feed DAP for a given AZ payment year, recorded in the tracker
   **before the first DAP submission** that uses platform-generated rates.

**Closed residual:** the FUI age-floor (≥13, sign-off residual item 4) is **enforced** in code
(`FUI_MIN_AGE = 13`; `FUA_MIN_AGE = 13`).
