CAMPUX learn / ai / 07
Project 07 of 09
PHI never reaches the model.

Care Gap Report

An agent for Campux Health that reads patient records for overdue screenings, redacts every identifier before it thinks, logs every decision, and lets a person decide who actually gets contacted.

build time
6 to 8 hours
cost
Under $8 if torn down the same day4
services
Foundry Agent Service, Azure AI Language (PII detection, Text Analytics for health), Azure SQL Database, Entra ID, Azure Monitor
assumes
Project 01. You can explain managed identity and role assignment, and you have read the HIPAA note below before you touch real data.
exams
Overlaps AI-103, AI-200
vocabulary
PHI, de-identification, quality measure, care gap, re-identification, audit trail, covered entity

The problem

Campux Health, a fictional regional primary care network and Campux LLC's other portfolio company, runs a quarterly chart review: which patients are overdue for a mammogram, a colorectal screening, an HbA1c test.

Right now it is four nurses and a spreadsheet, and the spreadsheet has patient names in it, emailed between reviewers. The compliance officer does not want a faster spreadsheet. She wants a system where a name only appears on a screen after someone has actually approved contacting that person, and where every decision the system made can be pulled up and defended eighteen months later if a regulator asks.

definition
Care gap. A preventive service a patient is due for, based on age, condition, and time since the last one, that has not happened. Finding gaps closes them; finding them wrong erodes trust in the whole program.

The architecture

Seven parts. The agent only ever sees a patient with the name taken out first.

Care Gap Report architecture: patient notes are redacted by Azure AI Language PII detection, mined by Text Analytics for health, judged by an agent in a Microsoft Foundry project against measure specs, logged, and reviewed by a compliance officer who alone can re-identify one row; the identity mapping sits with the records under its own role. the agent never sees a name. Only an approved row gets one back. RECORDS DE-IDENTIFY AND EXTRACT MICROSOFT FOUNDRY PROJECT HUMAN REVIEW · COMPLIANCE OFFICER Patient recordsroster + notes Identity mappingown table, own role PII detectionAzure AI Languageredact first Clinical entitiesText Analyticsfor health Agent · Foundry Agent Servicecites only extracted values Measure specsfile search · age bands · windows Audit logevery decision, pseudonymous ID Population reportcounts only, no names Approve to re-identifyone row at a time, logged Microsoft Entra ID · split rolesagent: redacted data only · reviewer: report only · compliance officer: one-row re-identification, logged · no keys 1 2 3 4 5 6 7 8
livepress play to follow one patient note through the system
Figure 3 Redaction happens before the Foundry boundary, not after. The identity mapping sits with the records under its own role, and only the review tier can reach it.
  1. Redact. Every note goes through Azure AI Language PII detection before it is stored anywhere the agent can read.
  2. Extract. Text Analytics for health pulls screening dates and lab values out of the redacted note.
  3. Judge. The agent gets a pseudonymous ID and extracted facts, never a name.
  4. Look up the measure. File search returns the spec: age band, lookback window, exclusions.
  5. Log it. Each verdict and the exact value it relied on go to an append-only audit table.
  6. Report. The population report is built from the log: counts and percentages, no names.
  7. Review. The compliance officer picks one pseudonymous row to act on.
  8. Re-identify, once. That row alone is joined back to a name, and the access is itself logged.
Service map, for readers coming from AWS
JobAWS versionThis buildSame idea?
ModelBedrock modelFoundry model deploymentYes
Agent runtimeBedrock AgentFoundry Agent ServiceYes
PHI redactionComprehend Medical PHI detectionAzure AI Language, PII detectionYes
Clinical extractionComprehend Medical entitiesText Analytics for healthYes
Measure specsKnowledge baseFile search over measure PDFsYes
Audit trailCloudTrail + a ledger tableAzure Monitor + an append-only log tableYes
IdentityIAMEntra ID + managed identity, split rolesDifferent. Read the trade-offs below

The build

In this order. Steps 3 and 4 are the ones a demo skips and a regulator asks about. Use synthetic data throughout; nothing here should ever touch a real patient record.

  1. Foundry project and model

    Create a Foundry project, deploy gpt-5-mini, confirm it against the Learn page for the day; naming and quota behave the same as Project 01.

    The model answers in the playground.
  2. Synthetic patient data

    Build twenty fake patients in Azure SQL: age, sex, condition flags, and a short free-text visit note per patient that sometimes mentions a screening date and sometimes a name, a relative, or a phone number, on purpose.

    Note for patient row 12:
    "Seen for follow-up. Pt states her sister Maria had a BRCA-positive
    result in 2024. Last mammogram was March 2023 per pt report.
    Call back number on file: patient's own, not a relative's."
    Twenty rows, each note between 30 and 80 words, at least six containing a name that is not the patient's.
  3. Measure documents

    Write three short PDFs, one per quality measure: breast cancer screening (mammogram within 27 months, ages 50 to 74), colorectal cancer screening (within 10 years for a colonoscopy, ages 45 to 75), and diabetes HbA1c testing (within 12 months for anyone with a diabetes flag). Upload to a file search vector store.

    The vector store shows three files indexed.
  4. Redact before anything else runs

    Create an Azure AI Language resource. Run Text PII detection over every note. Store the redacted note next to the structured fields; store the original note and the name-to-pseudonym mapping in a separate table with its own, tighter role assignment.

    Pull up a redacted note and confirm every name, phone number, and date of birth is replaced with a placeholder. Confirm the mapping table is not reachable by the identity the agent runs as.
  5. Extract the clinical facts

    Run Text Analytics for health over the same redacted notes. Pull out any mentioned screening type and date as structured entities, and merge them with the structured fields from step 2.

    For patient row 12, the extracted entity is a mammogram date, March 2023, attached to the pseudonymous ID, with no name attached anywhere in this table.
  6. The agent

    Create an agent with the file search tool over the measure specs. Instructions: for each patient, using only the structured fields and extracted entities provided, decide per measure whether the patient is due, overdue, or not applicable, and cite the exact date or value used. Never infer a screening from context that is not an extracted date or a structured field.

    Run it against patient row 12 for the breast cancer measure. It should say overdue, using March 2023 as the last mammogram, since more than 27 months have passed, and it should not mention Maria.
  7. Audit every decision

    Log each agent decision to an append-only table: pseudonymous patient ID, measure, verdict, the date or value cited, and a timestamp. Nothing in this table is ever a real name.

    After a full run, the audit table has one row per patient per measure, and you can answer "why did you flag row 12" by reading one row.
  8. Human review, then re-identification

    Build the population report from the audit table: counts and percentages by measure, no names. Give the compliance officer role a separate view that, for a specific pseudonymous ID they select, joins back to the mapping table from step 4 and shows the real name, only for that one row, only after they select it.

    A second, lower-privileged role can see the population report and cannot open a single record. The compliance officer role can, one row at a time, and that access is itself logged.
  9. Identity

    Three separate roles: the agent's managed identity (structured and extracted data only, no mapping table), the reviewer role (population report only), the compliance officer role (population report plus one-row re-identification). Remove any key used while building.

    grep -ri key .env* returns nothing. Signing in as the reviewer role and attempting to read the mapping table fails.
  10. Tear it down
    azd down

    Then check the resource group by hand, including the Azure AI Language resource, which azd down may not own if you created it separately.

    The resource group is empty. Today's cost is under $8.

Where it breaks

Cause each one on purpose. This is the section a compliance officer will actually ask you about.

The trade-offs

Agent judgment, or a deterministic rules engine?
A rules engine is exact and fully auditable for numeric criteria like age bands and lookback windows, and brittle every time a measure's wording changes. This build lets the agent read the measure PDF and reason in language, but the age and date-window math is done in code, in step 6's instructions, not left to the model to compute.
Redact first, or analyze raw text and redact the output?
Redacting before the model ever sees the text means PHI never appears in a prompt, a model log, or a trace. The cost is losing context, and it is bigger than a name: in our run the redactor masked the word "sister" as well as "Maria", so "her sister was BRCA-positive" came out as "her ****** ***** was BRCA-positive" and the family history was gone. This build always redacts first and accepts that loss, because the alternative puts PHI in front of a model call.
Review every gap, or only the borderline ones?
Reviewing every flagged gap is safest and slowest. Once you have measured the agent's precision against a labeled set, the way Project 03 measures an agent, sampling only low-confidence verdicts is a defensible middle ground. This build reviews everything, because it has no measured precision yet.
Synthetic data here, or a real de-identified export?
This project is built entirely on fabricated patients so anyone can run it without a business associate agreement or an institutional review. A real deployment on real PHI is a different undertaking: it needs a signed BAA with Microsoft, use of only HIPAA-eligible services, and your organization's own compliance sign-off, not this page.
HIPAA, or a non-US reader's framework?
HIPAA is a US law and this page is written for it. Under GDPR, health data is "special category data" under Article 9, needing an explicit legal basis and likely a Data Protection Impact Assessment before this kind of processing starts. The architecture, redact first, log everything, gate re-identification behind a human, travels across frameworks. The specific legal basis you are relying on does not.3

In the interview

"Tell me about a project touching regulated data."

  • decisionA care-gap agent for a fictional clinic network: redact identifiers, extract clinical facts, let the agent judge against measure documents, log every decision, gate re-identification behind a human.
  • reasonThe agent should never see a name, and every verdict should be traceable to a cited value.
  • watchedWhether a lower-privileged role could reach the identity mapping table. It could not, because I tried.

"How did you keep PHI out of the model calls?"

  • decisionAzure AI Language PII detection redacts every note before it is stored anywhere the agent can read, and the identity mapping lives in a separate table with its own role.
  • reasonOnce PHI is in a prompt or a trace, it is in every downstream log by default.
  • watchedRedaction is not perfect; I sampled outputs by hand and added a narrower second pass.

"What happens when the agent gets a gap wrong?"

  • decisionEvery verdict cites a specific extracted date or field, logged in an append-only audit table, and a human reviews every flagged patient before contact.
  • reasonA wrong gap that reaches a patient is a trust problem, not just a bug; the log lets us find and explain it after the fact.
  • watchedWhether the agent ever cited something that was not a real extracted value. It did, once, before I forbade inference from prose.

Evidence

A redacted-note pair
The original synthetic note next to its redacted version, side by side.
One audit log row
A single decision, the cited value, and the timestamp, screenshotted.
The repo
Instructions file, the three measure PDFs, the role assignment script, and a README that states plainly this project uses synthetic data only.
One sentence for the résumé
"Built a document-grounded quality-measure agent that de-identifies clinical text before any model call, cites every decision to a source value, and gates patient re-identification behind human approval and an audit log."

Next

Notes

  1. Checked against Microsoft Learn on 2 September 2026, and the redaction and extraction steps were run on this page’s own sample note in a real subscription on 3 September (Language API version 2024-11-01, PII domain phi). The mammogram date came back as an examination linked to a time, as step 5 expects; the redactor also masked "Pt" as a person, which is harmless and worth knowing. Text Analytics for health is explicitly documented as not a medical device and not for diagnosis; its output, and this project's output, is decision support, always reviewed by a person.
  2. This project uses only fabricated patients. If you adapt it to real patient data, your organization becomes a HIPAA covered entity or business associate handling that data, and Microsoft's HIPAA support only applies once you have a signed Business Associate Agreement in place and are using in-scope, HIPAA-eligible Azure services. Having a BAA does not by itself make a deployment compliant; that responsibility stays with you.
  3. Not legal advice. If you are building this for a non-US organization, get an actual privacy lawyer to confirm the legal basis before you process real health data, not this footnote.
  4. "Under $8" assumes twenty small records, three short measure PDFs, and teardown the same day. Azure AI Language billing and Foundry model tokens are the two line items; either grows with real patient volume.