EHR quality-governance packet builder
You are handed a prompt plus a machine-readable output contract
(input/payloads/answer_template.json) and a read-only EHR governance API. Your
job is to gather evidence from the API, apply the normalization/reconciliation
rules below, and emit one JSON object that exactly conforms to the template —
no prose, no markdown fences, no fields the template does not define.
The task differs run to run, but the machinery is always the same. Do not
hard-code any values you may have seen before: every ID, key, code, provider,
disposition, and count must be re-derived live from the environment for the
current case.
0. Orient
- Read the prompt and pull out the case objects: patient id(s), duplicate
candidate id (
DUP-…), referral id (REF-…), batch id, ServiceRequest id
(SR-…), recipient/receiving provider id (PRV-…), and the target
service line (cardiology, orthopedics, …).
- Read
input/payloads/ in full — the answer_template.json is the spec
(top-level keys, enums, ordering rules, required constant values such as a
task_id). Read any other payload files too (e.g. a *_request.json that
lists the requested outputs). Treat every enum/allowed_values list in the
template as the only legal vocabulary for that field.
- Identify which task family this is from the template's top-level keys and
match it to a recipe in
reference/playbooks.md:
merge / merge_decision / clinical_unions → duplicate merge-readiness packet
referral_code_set / referral_letter_fields → referral coordination packet
handoff_encounters / risk_flags → care-transition packet
duplicate_review + service_request + sbar_coverage → duplicate + ServiceRequest review
invalid_or_out_of_range_code_referrals / action_plan / summary_counts → batch audit
1. Connect to the environment
- The base URL is the
GDPEVO_ENV_BASE_URL value in environment_access.md
(substitute it for any <TASK_ENV_BASE_URL> placeholder in the prompt).
No credentials. Every allowed endpoint is GET. Only call endpoints
listed in environment_access.md.
- List endpoints return
{"<plural_name>": [ ... ]} (e.g. {"patients":[…]},
{"referrals":[…]}). Detail endpoints (.../{id}) return the object directly.
A missing resource returns HTTP 404 with {"error":…, "status":404} — treat
that as "not found" (e.g. an ICD-10 lookup 404 ⇒ unknown/invalid code).
- Do not trust query-string filters. Some are honored, some are silently
ignored (a
?batch_id= filter returned the whole collection). Fetch the full
collection and filter locally by the field you care about, then sanity-check
the row count.
- The full endpoint catalog and response field shapes are in
reference/api_reference.md — read it before writing queries.
2. Universal normalization rules
These hold across every task family:
- Normalized keys are the currency. Condition / medication / allergy records
each carry a
normalized_key. Build "active key" sets from normalized_key
values, de-duplicated, including only records whose status == "active".
Records with status of inactive, entered-in-error, resolved, etc. are
distractors — route them to the template's excluded_* / distractor buckets,
never into the active sets.
- Sort every set-typed array ascending (alphabetical for strings, by the
key/id the template names) unless the template explicitly says otherwise.
When the template says a list "is treated as a set," ordering won't be scored,
but sort anyway for stability.
- Authoritative source = live patient endpoints, not previews. When a
duplicate candidate ships a
merge_preview, the patient
condition/medication/allergy endpoints override it. Reconciliation fields
("…added_from_active_endpoints") = keys present in the live active endpoints
but missing from the preview.
- Emit every required key, even when empty (
[], null, false). Never
invent keys the template doesn't list.
- Enums are exact strings from the template. Dates are
YYYY-MM-DD.
- Providers: fetch the full contact block from
/api/providers/{id}
(name, role, service_line, facility, phone, fax). The PCP is on the patient
detail (primary_care_provider). Pick the specialist by the case's service
line / receiving provider / ServiceRequest performer.
- ICD-10 validation (
/api/icd10/{code}): the record gives chapter,
requires_laterality, and expected_terms. Use it for code validity (404 ⇒
invalid/unknown), chapter-range checks, narrative match, and laterality checks.
See reference/api_reference.md for the exact mismatch definitions.
3. Build the answer
Follow the matching recipe in reference/playbooks.md. Each recipe maps template
sections to the endpoints and decision rules that populate them. General guidance
that recurs:
- Merge disposition follows the candidate
status + the patients'
canonical_status/canonical_patient_id: a source patient whose
canonical_status == "duplicate" and canonical_patient_id == the preferred
target, on an open candidate with matching identity signals, is merge-ready;
a needs_review candidate with null preferred target is a manual-review hold
with null merge target/source.
- Match/conflict signals come straight off the duplicate candidate object.
Demographic matches/conflicts are derived by comparing the two patient
detail records field-by-field (dob, insurance_id, phone, sex,
primary_care_provider_id, given_name, address). Same street written two ways ⇒
an address/abbreviation conflict; nickname vs full name ⇒ a given-name variant.
- Evidence selection is exclusionary. Merge packets cite only
identity / external-continuity documents (e.g. identity verification, external
specialty notes) with
status == "final"; routine chart_summary / ehr_export
documents are distractors. Encounter/handoff selection keeps the most
relevant records for the transition and excludes stale or unrelated ones —
relevance beats raw recency, and randomly-hashed IDs are usually distractors
next to sequential case IDs.
- Readiness / blocking / follow-up derive from referral fields
(
authorization_status, status, urgency, documents_received) and
document presence. E.g. missing office note ⇒ records-request queue; auth not
approved ⇒ authorization queue / hold.
4. Self-verify before returning
- Re-read the template and confirm every required top-level key is present
with the right type and that no extra keys leaked in.
- Confirm every enum value you used appears verbatim in the template's
allowed_values.
- If the template has a
summary_counts (or similar) block, recompute each
count from your own arrays and make them consistent — mismatched counts are
the most common failure.
- Confirm each emitted id/key/code actually exists in the environment evidence
you fetched, and that every set array is sorted.
- Output only the JSON object. No commentary, no code fences.
1---2name: ehr-governance-packet-53description: Produce the normalized JSON deliverable for an EHR quality-governance task against a read-only EHR/referral API. Use whenever a prompt gives one or more case objects (patient IDs, a duplicate-candidate ID, a referral ID or batch ID, a ServiceRequest ID, and/or a recipient provider ID), points at an EHR environment base URL, and asks for JSON that conforms to a supplied `answer_template.json`. Covers duplicate-chart merge-readiness packets, referral coordination packets, care-transition handoff packets, duplicate + ServiceRequest quality reviews, and referral-batch audits.4---56# EHR quality-governance packet builder78You are handed a prompt plus a machine-readable output contract9(`input/payloads/answer_template.json`) and a read-only EHR governance API. Your10job is to gather evidence from the API, apply the normalization/reconciliation11rules below, and emit **one JSON object that exactly conforms to the template** —12no prose, no markdown fences, no fields the template does not define.1314The task differs run to run, but the machinery is always the same. Do not15hard-code any values you may have seen before: every ID, key, code, provider,16disposition, and count must be re-derived live from the environment for the17current case.1819## 0. Orient20211. Read the prompt and pull out the **case objects**: patient id(s), duplicate22 candidate id (`DUP-…`), referral id (`REF-…`), batch id, ServiceRequest id23 (`SR-…`), recipient/receiving provider id (`PRV-…`), and the target24 **service line** (cardiology, orthopedics, …).252. Read `input/payloads/` in full — the `answer_template.json` **is the spec**26 (top-level keys, enums, ordering rules, required constant values such as a27 `task_id`). Read any other payload files too (e.g. a `*_request.json` that28 lists the requested outputs). Treat every enum/`allowed_values` list in the29 template as the *only* legal vocabulary for that field.303. Identify which **task family** this is from the template's top-level keys and31 match it to a recipe in `reference/playbooks.md`:32 - `merge` / `merge_decision` / `clinical_unions` → duplicate merge-readiness packet33 - `referral_code_set` / `referral_letter_fields` → referral coordination packet34 - `handoff_encounters` / `risk_flags` → care-transition packet35 - `duplicate_review` + `service_request` + `sbar_coverage` → duplicate + ServiceRequest review36 - `invalid_or_out_of_range_code_referrals` / `action_plan` / `summary_counts` → batch audit3738## 1. Connect to the environment3940- The base URL is the `GDPEVO_ENV_BASE_URL` value in `environment_access.md`41 (substitute it for any `<TASK_ENV_BASE_URL>` placeholder in the prompt).42 **No credentials.** Every allowed endpoint is `GET`. Only call endpoints43 listed in `environment_access.md`.44- List endpoints return `{"<plural_name>": [ ... ]}` (e.g. `{"patients":[…]}`,45 `{"referrals":[…]}`). Detail endpoints (`.../{id}`) return the object directly.46 A missing resource returns HTTP 404 with `{"error":…, "status":404}` — treat47 that as "not found" (e.g. an ICD-10 lookup 404 ⇒ unknown/invalid code).48- **Do not trust query-string filters.** Some are honored, some are silently49 ignored (a `?batch_id=` filter returned the whole collection). Fetch the full50 collection and filter locally by the field you care about, then sanity-check51 the row count.52- The full endpoint catalog and response field shapes are in53 `reference/api_reference.md` — read it before writing queries.5455## 2. Universal normalization rules5657These hold across every task family:5859- **Normalized keys are the currency.** Condition / medication / allergy records60 each carry a `normalized_key`. Build "active key" sets from `normalized_key`61 values, **de-duplicated**, **including only records whose `status == "active"`**.62 Records with `status` of `inactive`, `entered-in-error`, `resolved`, etc. are63 **distractors** — route them to the template's `excluded_*` / distractor buckets,64 never into the active sets.65- **Sort every set-typed array ascending** (alphabetical for strings, by the66 key/id the template names) unless the template explicitly says otherwise.67 When the template says a list "is treated as a set," ordering won't be scored,68 but sort anyway for stability.69- **Authoritative source = live patient endpoints, not previews.** When a70 duplicate candidate ships a `merge_preview`, the patient71 condition/medication/allergy endpoints override it. Reconciliation fields72 ("…added_from_active_endpoints") = keys present in the live active endpoints73 but missing from the preview.74- **Emit every required key**, even when empty (`[]`, `null`, `false`). Never75 invent keys the template doesn't list.76- **Enums are exact strings** from the template. Dates are `YYYY-MM-DD`.77- **Providers**: fetch the full contact block from `/api/providers/{id}`78 (`name, role, service_line, facility, phone, fax`). The PCP is on the patient79 detail (`primary_care_provider`). Pick the specialist by the case's service80 line / receiving provider / ServiceRequest performer.81- **ICD-10 validation** (`/api/icd10/{code}`): the record gives `chapter`,82 `requires_laterality`, and `expected_terms`. Use it for code validity (404 ⇒83 invalid/unknown), chapter-range checks, narrative match, and laterality checks.84 See `reference/api_reference.md` for the exact mismatch definitions.8586## 3. Build the answer8788Follow the matching recipe in `reference/playbooks.md`. Each recipe maps template89sections to the endpoints and decision rules that populate them. General guidance90that recurs:9192- **Merge disposition** follows the candidate `status` + the patients'93 `canonical_status`/`canonical_patient_id`: a source patient whose94 `canonical_status == "duplicate"` and `canonical_patient_id ==` the preferred95 target, on an `open` candidate with matching identity signals, is merge-ready;96 a `needs_review` candidate with null preferred target is a manual-review hold97 with null merge target/source.98- **Match/conflict signals** come straight off the duplicate candidate object.99 **Demographic** matches/conflicts are derived by comparing the two patient100 detail records field-by-field (dob, insurance_id, phone, sex,101 primary_care_provider_id, given_name, address). Same street written two ways ⇒102 an address/abbreviation conflict; nickname vs full name ⇒ a given-name variant.103- **Evidence selection is exclusionary.** Merge packets cite only104 identity / external-continuity documents (e.g. identity verification, external105 specialty notes) with `status == "final"`; routine `chart_summary` / `ehr_export`106 documents are distractors. Encounter/handoff selection keeps the most107 *relevant* records for the transition and excludes stale or unrelated ones —108 relevance beats raw recency, and randomly-hashed IDs are usually distractors109 next to sequential case IDs.110- **Readiness / blocking / follow-up** derive from referral fields111 (`authorization_status`, `status`, `urgency`, `documents_received`) and112 document presence. E.g. missing office note ⇒ records-request queue; auth not113 approved ⇒ authorization queue / hold.114115## 4. Self-verify before returning116117- Re-read the template and confirm **every** required top-level key is present118 with the right type and that no extra keys leaked in.119- Confirm every enum value you used appears verbatim in the template's120 `allowed_values`.121- If the template has a `summary_counts` (or similar) block, **recompute each122 count from your own arrays** and make them consistent — mismatched counts are123 the most common failure.124- Confirm each emitted id/key/code actually exists in the environment evidence125 you fetched, and that every set array is sorted.126- Output **only** the JSON object. No commentary, no code fences.