Every score, rate, projection and settlement figure mdvin puts on a screen — the question it answers, the logic behind the way it is built, the formula, a worked example in real numbers, and how to check it without taking our word for anything.
A platform that ranks people for clinical outreach and estimates money owed under a contract is making claims about the world. Those claims are worth exactly what the arithmetic behind them is worth, so this document states all of it: not a summary of the approach, but the formula behind each output with the function that computes it named beside it.
Every calculation here is held to three commitments, and they are the reason the engines look the way they do rather than the way a modelling exercise would look:
The worked examples are not illustrations. Each is the engine's own output on the
demonstration population, printed by
Docs/evidence/2026-09/2026-09-24_worked_examples.py and quoted here unchanged.
These are not style preferences. Each was taken for a reason specific to running clinical outreach under a regulated contract, and each costs something — which is why they are stated rather than assumed.
The obvious instinct for risk stratification is gradient boosting. It is the wrong first move here, for three reasons. The output format already demands reasons — the member panel renders each risk factor with its provenance, which a rule engine produces natively and a tree ensemble only ever reconstructs afterwards. A risk tier drives outreach, and outreach is regulated — a score that affects what care somebody is offered must be explainable, disclosed and defensible in discovery. And there is no training data: a synthetic cohort is not a training set, and fitting to it would produce a model whose version string meant nothing. When real longitudinal data exists these rules become the baseline a learned model has to beat, and the factor format they already emit is what makes that comparison possible.
No score in this paper has a column in the database. A persisted priority is stale the moment a clock moves, and it would need its own recompute job that can drift from what the screen shows. The cost is that every page load does the arithmetic; the benefit is that the number on screen is always the number the current facts produce. Risk scores are the deliberate exception: each run is appended as history, so what a score meant last quarter is still recoverable.
Measure specifications, targets, contract terms and SLA lengths are versioned records rather than constants in a source file, so changing one is a data change with an audit row behind it and a measure's numerator can be restated without a release. What stays in code is the logic that must not vary by tenant: what it means for a gap to be open, who may write to a member's record, when an authorization blocks scheduling.
Every recommendation names the endpoint a human would call and calls none of them. The server applies its own guards regardless of what the screen suggested — scheduling stays blocked while a linked authorization is pending, and the refusal is visible rather than pre-empted. The platform connects the workflow; the clinician provides the judgment.
Of the people this plan is responsible for, who is most likely to have an expensive, avoidable year — and why, in terms a clinician can argue with?
Risk is additive across independent signals, each drawn from a different source system, because that is how a clinician reasons about it: a diagnosis list, recent labs, social circumstances, what the hospital sent over, whether the member is actually taking the medication. Each rule that fires contributes its points and records what it saw and where it came from, so the score is never more than the sum of statements you can check one at a time. Only the most severe band per lab fires, so one bad result is counted once rather than twice.
score = the sum of the points of every rule that fires tier = HIGH if score ≥ 60 · RISING if ≥ 35 · MEDIUM if ≥ 15 · else LOW
| Active condition | Points |
|---|---|
Heart failure I50.9 | 14 |
Chronic kidney disease stage 3 N18.3 | 12 |
Coronary artery disease I25.10 | 10 |
Diabetes with hyperglycemia E11.65 | 10 |
Type 2 diabetes E11.9 | 8 |
Hypertension I10 | 5 |
Obstructive sleep apnea G47.33 | 4 |
Hyperlipidemia E78.5 | 4 |
| Three or more chronic conditions | +8 |
| Measured value — latest, 730-day lookback | Points |
|---|---|
HbA1c above 9.0 4548-4 | 18 |
| HbA1c above 8.0 | 10 |
Systolic BP above 160 8480-6 | 14 |
| Systolic BP above 140 | 9 |
Creatinine above 1.5 2160-0 | 10 |
Total cholesterol above 240 2093-3 | 6 |
Only the most severe band per lab fires: an HbA1c of 9.4 scores 18, not 28.
| Social risk — Z-code answered yes | Points |
|---|---|
Homelessness Z59.0 | 10 |
Food insecurity Z59.4 | 8 |
Transportation insecurity Z59.82 | 7 |
Social isolation Z60.2 | 5 |
| Utilisation and adherence — 365-day lookback | Points |
|---|---|
| ED visits, 6 each | capped 18 |
| Inpatient admissions, 10 each | capped 20 |
| Each active medication below 80% PDC | 7 |
| Points | Factor that fired | Source |
|---|---|---|
| 12 | Chronic kidney disease stage 3 (N18.3) | problem_list |
| 10 | Diabetes with hyperglycemia (E11.65) | problem_list |
| 10 | HbA1c above 8% (was 8.9%) | lab |
| 10 | Creatinine above 1.5 (was 1.8 mg/dL) | lab |
| 9 | Systolic BP above 140 (was 148.0 mmHg) | ehr |
| 8 | 3 chronic conditions | problem_list |
| 8 | Food insecurity (Z59.4) | survey |
| 7 | Atorvastatin 40mg adherence 62% (below 80%) | pharmacy |
| 6 | 1 ED visit in 12 months | adt |
| 5 | Hypertension (I10) | problem_list |
| 85 | → tier HIGH (60 or above) | 10 factors, 6 source systems |
For this measure, is this member counted — and if they are counted, have they had the care it asks for?
Four buckets, mutually exclusive, so no member is ever both excluded and counted. The distinction that matters most is between not in the denominator (the measure does not apply to them) and excluded (it would apply, but a clinical exclusion releases them): conflating those two is the error that quietly inflates a rate. Denominator, numerator, exclusions and target all come from the versioned measure package rather than from code, so a specification change is a data change with a version attached.
| Bucket | Rule |
|---|---|
| Not in denominator | Age today outside the package's minimum or maximum, or the package names condition codes and the member has no active condition among them |
| Excluded | In the denominator, but holds an active condition listed in the package's exclusions |
| Compliant | In the denominator, not excluded, and the numerator is met |
| Open gap | In the denominator, not excluded, and the numerator is not met |
Always inside the package's lookback window, 365 days by default:
How is the plan performing on this measure, and how much of that performance is still recoverable this year?
D = members in the denominator and not excluded (denominator) N = of those, the compliant (numerator) X = the excluded (reported, outside D) G = D − N (open gaps) rate% = round(100 × N / D, 1) undefined, shown as a dash, when D = 0
| Measure | D | N | X | Open | Rate | Target |
|---|---|---|---|---|---|---|
| Diabetes: Eye Exam Performed | 6 | 0 | 0 | 6 | 0.0% | 70 |
| Diabetes: HbA1c Control (<8.0%) | 6 | 2 | 0 | 4 | 33.3% | 75 |
| Statin Adherence (PDC ≥ 80%) | 8 | 2 | 0 | 6 | 25.0% | 80 |
| Annual Wellness Visit | 9 | 2 | 0 | 7 | 22.2% | 60 |
| Controlling High Blood Pressure | 10 | 4 | 0 | 6 | 40.0% | 75 |
Eye exam: 100 × 0 / 6 = 0.0%. Blood pressure:
100 × 4 / 10 = 40.0%. In every row N + open = D — the numerator and the open
gaps account for the whole denominator, with the excluded reported separately.
One number for quality, because the contract settles on one number.
composite% = round( mean( rate% of every rated measure ), 1 )
(0.0 + 33.3 + 25.0 + 22.2 + 40.0) / 5 = 120.5 / 5 = 24.1% — the composite the contract is judged against.
Unweighted, because that is the demonstration contract's stated scoring method. A programme that weights its measures would change every number in the opportunity table below, and the weighting would live in the contract terms rather than in code.
There are twenty-nine open gaps and a team that can work a handful this month. Which ones move the number the contract settles on?
“Opportunity” is defined here rather than left to intuition: it is the number of composite points the score would gain if every open gap in that measure closed. That is a real, checkable quantity, and it is what makes the ranking arguable — a measure twenty points below target with two eligible members matters less than one five points below target with thirty. Ranking by “most gaps” or “furthest below target” gets both of those backwards.
With n = the number of rated measures and target = the package's own target percentage:
| Column on screen | Formula |
|---|---|
| Performance | rate% |
| Target | from the versioned measure package; “no target set” when absent |
| Gap to target, in points | round(target − rate%, 1) — positive means short |
| “N members would close it” | max( ceil(D × target / 100) − N , 0 ) |
| Open gaps | G |
| Composite points per gap | round(100 / D / n, 2) |
| Composite points available | round(100 / D / n × G, 2) — from the unrounded points per gap, so this figure and the scenario engine cannot drift apart |
| Opportunity band | Low if at or above target · else High if available ≥ 3.0 · Medium if ≥ 1.0 · else Low |
Why 100 / D / n — two separate facts, one after the other:
closing one gap raises that measure's rate by 100 / D points,
and the composite is the unweighted mean of n measures,
so the composite moves by 1/n of that.
| Measure | D | Open | 100 / D | ÷ n = 5 | On screen | Available |
|---|---|---|---|---|---|---|
| Diabetes: Eye Exam Performed | 6 | 6 | 16.67 | 3.3333 | 3.33 | 20.0 |
| Diabetes: HbA1c Control | 6 | 4 | 16.67 | 3.3333 | 3.33 | 13.33 |
| Statin Adherence | 8 | 6 | 12.50 | 2.5000 | 2.5 | 15.0 |
| Annual Wellness Visit | 9 | 7 | 11.11 | 2.2222 | 2.22 | 15.56 |
| Controlling High Blood Pressure | 10 | 6 | 10.00 | 2.0000 | 2.0 | 12.0 |
Five different numbers from one rule, with no exceptions. A formula that explains only the row being questioned is a rationalisation; one that explains all five is the method. Note also that the ranking is not by open gaps — the wellness visit has the most gaps (7) and is second by opportunity (15.56), behind the eye exam's six gaps (20.0).
D = open ÷ (1 − rate). Eye exam: 6 ÷ (1 − 0) = 6. Wellness
visit: 7 ÷ (1 − 0.222) = 9. Then 100 ÷ D ÷ 5 reproduces the
points per gap. Nothing else is needed, and nothing has to be taken on trust.The contract pays nothing on savings unless quality clears a gate. What is the cheapest route from where we are to where we must be, counted in gaps closed?
Greedy — take the measure with the highest points per gap first, then the next. Greedy is not an approximation here, it is optimal: every gap within one measure is worth exactly the same number of composite points, so taking the highest-value measure first can never cost a cheaper route later. That is a property of the unweighted mean, and it would stop being true under a weighted contract — at which point this function would have to change, and this paper would say so.
gate = contract.minimum_quality_pct shortfall = round(gate − composite, 1) (0 when already met) then, measures sorted by points_per_gap descending: need = min( G , ceil( (shortfall − gained) / points_per_gap ) ) gained += need × points_per_gap rate_after% = round(100 × (N + need) / D, 1) until gained ≥ shortfall projected% = round(composite + gained, 1) achievable = shortfall ≤ 0 or projected ≥ gate gaps_to_close = the sum of need
Current 24.1%, gate 60.0%, shortfall 35.9 points.
| Step | Measure | Close | Of open | Rate after |
|---|---|---|---|---|
| 1 | Diabetes: Eye Exam Performed (3.33 per gap — the richest) | 6 | 6 | 100.0% |
| 2 | Diabetes: HbA1c Control (3.33 per gap) | 4 | 4 | 100.0% |
| 3 | Statin Adherence (2.5 per gap — stops as soon as the gate is cleared) | 2 | 6 | 50.0% |
| Projected composite 62.4% — gate cleared | 12 |
Twelve gaps, not twenty-nine, and the third measure is only partly worked — the plan stops the moment the gate is cleared rather than finishing a measure for tidiness.
If the team commits to closing a specific number of specific gaps, where does that leave the composite, the gate, and the money?
for each measure with k chosen closures, capped at G: rate_after% = round(100 × (N + k) / D, 1) composite_after% = round( mean( rate_after% of every rated measure ), 1 ) gate_met_after = composite_after ≥ gate settlement_after = gross_savings × shared_savings_rate × (1 − quality_withhold_pct) if the gate is met after and gross_savings > 0, else 0 settlement_delta = settlement_after − settlement_before
| Closures | Measure rate | Composite | Gate met after? |
|---|---|---|---|
| Close 1 | 0.0% → 16.7% | 24.1% → 27.4% | No |
| Close all 6 | 0.0% → 100.0% | 24.1% → 44.1% | No |
One closure is worth 3.33 composite points. The screen reports the composite exactly as the live score is computed — each measure's rate rounded to one decimal, then their mean rounded to one decimal — so the eye exam's 16.7% gives (16.7 + 22.2 + 25.0 + 33.3 + 40.0) ÷ 5 = 27.44, shown as 27.4, and the sentence under the result reads “Composite moves +3.3 points”: the difference of the two displayed figures. Six closures move it 20.0, matching the row's stated points available exactly. And even perfect performance on one measure does not clear a 60% gate: that is the honest answer, and it is the one the screen gives.
Against the benchmark this contract set, are we spending less — and does any of that saving actually become money?
Two independent conditions, and the second is the one that surprises people. Savings are real only if spending came in under benchmark, and they are only payable if quality clears the gate. A programme can generate savings and receive nothing. That is why the quality composite is presented as a financial number on the contract screen rather than a clinical one, and why the gate path above exists at all.
member_months = from the cost summary for the current period
actual_pmpm = allowed cost per member per month
variance_pmpm = round(benchmark_pmpm − actual_pmpm, 2)
gross_savings = round(variance_pmpm × member_months, 2)
gate_met = composite ≥ contract.minimum_quality_pct
settlement = round(gross_savings × shared_savings_rate × (1 − quality_withhold_pct), 2)
when gross_savings > 0 and the gate is met; otherwise 0, and the note says which
| Benchmark PMPM | 1,750.00 |
| Actual PMPM | 1,554.32 |
| Variance per member per month | 195.68 |
| Member months in the period | 105.12 |
| Gross savings — 195.68 × 105.12 | 20,569.88 |
| Quality composite against the gate | 24.1% vs 60.0% |
| Estimated settlement — gate not met | 0.00 |
Twenty thousand dollars of real savings, and nothing payable. This is the most useful number on the contract screen: it converts a quality problem into a financial one, and it is why the platform ranks gaps by composite points rather than by clinical severity alone.
A care manager opens the day with thirty-two open tasks and time for eight. Which eight?
The authored priority label is an input, not the ranking. A manual “Critical” is a snapshot of what somebody believed when they created the task; the clinical signals move afterwards. A member discharged yesterday with a contact window closing today outranks a task somebody marked Critical last month — and the earlier weighting, which put the human label at 40 points against 15 for clinical risk, could not express that. The label still counts, because discarding a clinician's judgment would be its own failure, but it can now be outscored by what is actually happening to the member.
The score is the sum of every component that fires, and each component is returned with the sentence that justifies it.
| Component | Points |
|---|---|
| Authored priority — Critical / High / Medium / Low | 20 / 12 / 6 / 2 |
| Member risk tier — HIGH / RISING / MEDIUM / LOW | 22 / 15 / 6 / 0 |
| Worst open gap's priority — Critical / High / Medium / Low | 18 / 12 / 6 / 2 |
| Post-discharge 48-hour contact window still open | 28 |
| Contact window missed, visit window still open | 20 |
| Outreach stalled — sent, nothing back | 14 |
| Ageing after 3 days, one per day | capped 21 |
| Due date and authorization clock | Points |
|---|---|
| Overdue — 35 plus 2 per day late, 10-day cap | 35–55 |
| Due today | 25 |
| Due within 2 days | 18 |
| Due within 7 days | 10 |
| Due later | 3 |
| Authorization past its decision deadline | 30 |
| Decision due within 24h — expedited / standard | 25 / 20 |
| Decision due within 72h — expedited / standard | 18 / 12 |
| On the SLA clock, beyond 72h | 5 |
| Points | Component | Why |
|---|---|---|
| 55 | due | overdue by 60 days — 35 + 2 × 10, at the cap |
| 22 | patient_risk | high-risk patient |
| 18 | gap_priority | critical-priority gap: HbA1c Control |
| 12 | priority | marked High |
| 107 | Total | Complete the health risk assessment |
The care manager sees the composed sentence, not the number: “overdue by 60 days + high risk + HbA1c Control — Glycemic Assessment”. Note that the authored label contributed 12 of 107 — the queue is being driven by the member's situation, which is the whole point of the design.
Which people need me today — including the ones nobody has raised a task for?
A care manager thinks in members, not tickets. Ranking tasks splits one member with three gaps into three small jobs, so the person who needs the most attention can look like three minor items. Worse: a member who needs attention but has no task is not in the queue at all — high risk, several gaps open, nobody raised anything, invisible. This ranks the panel instead, so a member with no task can outrank a member with a stale one. The same engine scores a cohort list, so two screens cannot disagree about how much a member needs attention.
| Signal | Points | Why it carries weight |
|---|---|---|
| Risk tier HIGH / RISING / MEDIUM / LOW | 30 / 20 / 8 / 0 | The strongest single predictor the plan holds |
| Each open gap nobody is working | 8 | Unworked, not merely open |
| Each gap already in flight | 2 | Still present, much quieter |
| Discharge contact window open | 25 | It closes whether or not anybody acts |
| Contact window already missed | 15 | The visit window may still be saved |
| No active coverage | 18 | As hard a block as a pending authorization, and quieter: nothing is pending, so nothing prompts anyone to look |
| Outreach stalled | 14 | Needs a different channel, and nothing else surfaces that |
| Authorization on the clock | 12 | A deadline the plan does not control |
| Medication adherence below 80% PDC | 10 | Precedes the admission it causes |
| High risk and in no programme | 10 | Eligible and unenrolled is a decision nobody made |
| Points | Signal | Why |
|---|---|---|
| 40 | unworked_gaps | 5 open gaps with nothing running × 8 |
| 30 | risk | high risk |
| 10 | adherence | Atorvastatin 40mg adherence 62%, below the 80% threshold |
| 80 | Total — John Doe | next action: start an intervention on the HbA1c gap |
The same member scores 85 on clinical risk and 80 on panel attention — two different questions with two different answers. Risk asks how likely a bad year is; the panel asks how much of that is unattended right now. A high-risk member with everything already in flight scores lower here, and should.
For this population: which member, which action, why them, why now, and who should do it?
Ranked by expected value — how much the gap matters, weighted by the member's risk, discounted by whether anything can actually be done today. A recommendation nobody can act on is noise, and the fastest way to lose a work queue is to fill it with noise. But the score itself never reaches the screen. The customer review's words were that numeric scoring is difficult for users to interpret, and that is not a cosmetic complaint: a recommendation justified by “32.0” is one nobody can argue with and — the part that matters — nobody can catch being wrong. So the arithmetic orders the list, and what a person sees is a band, the reasons with their sources, and the single next step.
impact = 10 × risk_weight × gap_priority_weight risk_weight HIGH 1.6 · RISING 1.3 · MEDIUM 1.0 · LOW 0.8 gap_priority_weight Critical 2.0 · High 1.5 · Medium 1.0 · Low 0.6 score = impact × 1.0 actionable today = impact × 0.9 previous outreach ended unreachable or declined = impact × 0.5 blocked — an authorization is pending order = band first (Critical, High, Medium), then score, then member
The band is derived from the facts, never from a cut point on the score, so the band and the reasons beneath it can never disagree:
Record HbA1c Control — band Critical, because a critical-priority gap on a high-risk member.
impact = 10 × 1.6 (HIGH risk) × 2.0 (Critical gap) = 32.0
score = 32.0 × 1.0 (actionable now) = 32.0 sort key only, never displayed
The eleven reasons the engine returned, each naming the system that asserted it — this is what the user actually reads:
| Open quality gap — HbA1c Control | Care Gap |
| Overdue 97 days | Care Gap |
| Critical priority on the measure package | Care Gap |
| High-risk member | Risk |
| Impacts Diabetes: HbA1c Control (<8.0%) — a tracked VBC quality measure with a 75% target | Quality |
| 1 ED visit in the last 6 months | Utilization |
| Coverage not verified — check eligibility before booking | Eligibility |
| No outreach attempted for this gap yet | Outreach |
| Food insecurity recorded and unaddressed — may prevent attendance | SDOH |
| Enrolled in Complex Care Management | Program/Contract |
| Actionable now | Workflow |
Next step: “No prior authorization is required — this can be scheduled as soon as the member is reached.” That sentence is the answer from the authorization engine, not a guess made on this screen, which is why the two can never contradict each other.
Somebody came out of hospital. How long do we have, and for what?
This is the highest-yield window in value-based care and the one most often missed, because the trigger arrives from outside — an ADT message, not a person's decision. Every window is measured from the discharge date, not from the day the notification arrived: a feed that runs a day late shortens the window, it does not extend it.
| Window | Length | Measured from |
|---|---|---|
| Contact after discharge | 48 hours | the discharge date, not the day the notification arrived |
| Follow-up visit | 7 days | the discharge date |
| Readmission counted in | 30 days | the discharge date |
| A discharge still treated as actionable | 120 days | lookback horizon |
Discharged 2026-09-22, two days ago: contact due by 2026-09-24 — window still open — and the follow-up visit due by 2026-09-29. While that contact window is open it contributes 28 points to every related task in the queue and 25 to the member's panel score, which is how a discharge reorders somebody's morning without anyone re-prioritising anything by hand.
When is this decision due, and what does the platform do as that moment approaches?
decision_due = submitted_at + 72 hours when urgency is expedited = submitted_at + 7 days standard
PA-2026-40188, standard urgency, submitted 2026-09-20 12:29 → decision due 2026-09-27 12:29. Exactly seven days, to the minute, from submission — not from receipt, and not from the start of the next business day.
Configurable per deployment and modelled on CMS-0057-F. Every queue in the product reads this same field, which is why an authorization nearing its deadline lifts its member's task without anybody re-prioritising anything. The API also refuses a denial that does not carry a specific reason code and text.
How do we reach somebody who has not replied — without becoming the plan that harasses its members?
Channels escalate in order of intrusiveness and cost, each with a wait long enough for a real person to have replied. Voice is the last rung, not the first. Consent is checked by a single authority that every channel calls, and a refusal is written to the audit chain before it is raised — so a member who was not contacted still leaves a record of why they were not contacted.
| Rung, in order | Wait before the next |
|---|---|
| 1 · SMS | 2 days |
| 2 · Email | 3 days |
| 3 · Portal | 7 days |
| 4 · Voice | 2 days |
| Limit | Value |
|---|---|
| Contacts allowed per member | 4 |
| within a rolling window of | 7 days |
| Consent disclosure validity | 365 days |
Who should be offered care management, and what is the evidence for saying so?
Four named criteria, each recording its own evidence. The function returns the reasons, never a bare boolean — “eligible” with nothing behind it cannot answer an auditor, a medical director or the member. Before this existed, eligibility was a condition inline in the ranking engine that wrote nothing down, which meant eligible was a state no member could actually be in.
| Criterion | Test | Why the plan considers it |
|---|---|---|
| High-risk member | risk tier is HIGH | The strongest predictor the plan has of the next twelve months |
| Rising risk with open gaps | tier RISING and three or more open care gaps | Rising risk is where care management is cheapest and most effective — before the admission, not after it |
| Recent acute event | an admission or ED visit within 180 days | The strongest short-term predictor of the next admission is the last one |
| Unmet social barriers | two or more unaddressed social needs | No clinical intervention reaches a member who cannot execute the plan |
| Member | Criterion | Evidence recorded |
|---|---|---|
| John Doe | high_risk | risk tier HIGH |
| John Doe | recent_acute | 1 acute encounter since 2026-03-28 |
| Maria Gonzales | high_risk | risk tier HIGH |
| Sam Okafor | recent_acute | 2 acute encounters since 2026-03-28 |
| Linda Tran | rising_with_gaps | 4 open gaps, rising risk |
| Fatima Hassan | rising_with_gaps | 4 open gaps, rising risk |
Two members qualify on two criteria each. Note that Linda Tran and Fatima Hassan are not high risk — they are the rising-risk members the programme exists to reach early, and a HIGH-only rule would have missed both.
We send gap-closure opportunities to attributed providers. Which of them engage, and how fast?
acceptance_rate% = round(100 × accepted / responded) disputed_rate% = round(100 × disputed / responded) evidence_returned% = round(100 × with_evidence / all opportunities) response_median_days = the middle value of the sorted response times overdue = past its due date and not yet settled
Dr. P. Osei currently holds 2 opportunities and has answered neither, so acceptance rate reads as a dash, not 0%. That distinction is the formula doing its job: zero would be a statement about this provider's judgment, and the honest statement is that there is nothing to divide by yet.
We sent this member to somebody else. When should we have heard back, and who finds out if we have not?
due_on = today + sla_days(queue) sla_days = the tenant's setting for that queue, else its default, else 3 days
Per queue, because one queue's standard is not another's — hard-coding three days for all of them is the assumption a customer's operations team overturns on day one. A redirect restarts the clock for the new queue and does not settle the referral; unable to contact does settle it, because a team that tried and could not reach somebody has produced a result worth keeping rather than an absence. The originator is notified on every advance, and a confirmed outcome is appended to the linked intervention's own trail, so the loop visibly closes where it started.
On the current trajectory, where does this metric land at the end of the performance period?
Ordinary least squares through the captured points — deliberately the simplest method that can be checked by hand, because a projection is arithmetic and a forecast is a claim, and this produces the first. What makes it trustworthy is not the fit but the refusals: the function would rather return a sentence than a number it cannot stand behind.
method = ordinary least squares through the captured points slope = Σ(x − x̄)(y − ȳ) / Σ(x − x̄)² intercept = ȳ − slope × x̄ R² = 1 − ss_res / ss_tot projected = slope × (days to the horizon) + intercept
And the three refusals, each returned with its reason in words rather than a number nobody should trust:
| Metric | R² | Projected at 2026-12-31 |
|---|---|---|
| Quality composite | 0.977 | 51.16% |
| Cost PMPM (allowed) | 0.976 | 1,361.69 |
| Open care gaps | 0.961 | 9.68 |
| Measure: HbA1c control | 0.978 | 63.21% |
| Measure: retinal exam | 1.0 | 0.0% |
| High and rising-risk members | 0.893 | 0.93 |
| Attributed members | — | refused: only 1 captured point |
Two rows worth reading together. The retinal measure fits perfectly (R² = 1.0) and projects 0.0% — a flat line through a measure where nothing has ever closed is an excellent fit and a useless forecast, which is why a high R² is a licence to draw the line, not evidence that the future will follow it. And attributed members refuses outright on a single point rather than drawing a line through it.
| Quantity | Rounding |
|---|---|
| Rates and composites | 1 decimal |
| Composite points | 2 decimals |
| Money | 2 decimals |
| Members needed to reach a target | whole, rounded up |
| Percentages of a provider's responses | whole |
Part I explains the calculations that drive the product. This part is the dictionary: 444 values across 25 screens, each with the formula in plain words, why it is computed that way, the function that computes it, and its value in the demonstration tenant. Those demo values are not typed by a person: they are read from the product itself, on a freshly reset demo tenant, by signing in as the persona who sees the screen and calling the same endpoint the screen calls. The demo tenant is reset every day, and this page's values are regenerated on the server from that day's reset, so they match what the demo shows today: values as of 2026-09-24.
The VBC manager, the executive and the platform administrator open this screen as their Dashboard (the care manager's Dashboard is a different screen). It shows six population counts, each linking to the list behind it, and today's priorities: groups of members who share a reason to act now.
Formula
Patient row in the tenant
no attribution filter, no status filter, no panel filterWhy this wayIt answers 'how many people are on file', not 'how many we are responsible for'. That costs a mismatch with Contract Health, whose rows are built over the members attributed in the current contract period, so the two screens can show different member totals on the same day. For a panelled login (a provider) every card counts that login's panel only.
In the demo13 members
Check it yourselfClick the card: it opens Members, and that list has the same number of rows.
app/services/command_center.py · kpis()app/static/app.js · rCommandCenter()Formula
Patient rows whose stored risk_tier, upper-cased, is HIGH or RISING
over every member in the tenantWhy this wayIt reads the tier stored on the member record, which Part I (Clinical risk score and tier) calls a convenience: the score history is the authority, and the tier bands (HIGH 60 or more, RISING 35 or more) are defined there. It is not re-scored at read time. Contract Health's 'High / rising risk members' uses the same two tiers but only over attributed members, so the two can differ; the care manager's Dashboard card of the same name matches the tier without upper-casing. The server also marks this card amber when the count is above zero, but the screen draws a hint only for red, so the amber flag is never shown.
In the demo6 members
Check it yourselfOpen Members and count the HIGH and RISING tier badges; the total matches the card.
app/services/command_center.py · kpis()app/services/risk.py · score_patient()Formula
CareGap rows where gap_is_open(status)
open = status not in CLOSED, EXCLUDED, NOT_APPLICABLE, GAP_CLOSED, RESOLVED, DUPLICATE; a blank status counts as openWhy this wayGaps being worked (IN_PROGRESS, SCHEDULED, AWAITING_AUTH, SERVICE_COMPLETED, REOPENED) still count, because a gap is open until it is closed, not until someone touches it. It counts gap rows, not members, over every member and every measure. Contract Health's 'Open care gaps' counts only attributed members' gaps, so it can be lower. The care manager's Dashboard counts gaps whose status is in the open list; the two agree unless a gap has a blank or unknown status, which this card counts as open and the Dashboard does not.
In the demo29 gaps
Check it yourselfClick the card: Care Gaps opens with the same total in its header, computed by the same gap_is_open rule.
Formula
Why this wayOne definition of a discharge: the card is the last 30 days of the very list it opens (inpatient stays, never a future date), so the card and the list behind it cannot disagree. It counts discharges, not members. For a provider login it counts the provider's panel only.
In the demo1 discharges
Check it yourselfClick the card: Transitions lists the inpatient discharges; count the rows discharged in the last 30 days.
app/services/command_center.py · kpis()app/services/transitions.py · recent_discharges()Formula
Intervention rows whose status is not CANCELLED, COMPLETED, GAP_CLOSED, DECLINED or UNREACHABLEWhy this wayDeclined and unreachable interventions are treated as finished, because nobody is working them. The Interventions list the card opens uses the same five states, so card and list agree. The care manager's Dashboard shows a card with the same label that excludes only GAP_CLOSED, CANCELLED and COMPLETED, so it counts declined and unreachable interventions as active and can be higher.
In the demo1 interventions
Check it yourselfClick the card: Interventions opens with the same total in its header.
app/services/command_center.py · kpis()app/services/worklists.py · interventions()Formula
WorkTask rows whose status is open (any case) and whose due date is before today
today = the US business date, not the server's date; every owner in the tenant, assigned or notWhy this wayA task due today is not overdue until tomorrow. The count is tenant-wide, but the card opens My Work, which starts on the 'Mine' tab: a manager who owns no tasks sees an empty list behind a non-zero card until they switch to 'Team'. The care manager's Dashboard 'Overdue tasks' card uses the same date rule.
In the demo8 tasks
Check it yourselfClick the card, choose 'Team' in My Work, and count the rows marked OVERDUE.
app/services/command_center.py · kpis()app/core/clock.py · business_today()Formula
tone is red; only Tasks overdue sets red, when its count is above 0Why this wayOnly a breached commitment (work already past due) earns the warning. The server also sends amber for High / rising risk, but the screen ignores amber, so that card never shows a hint.
In the demoTasks overdue
Check it yourselfThe hint sits under Tasks overdue and disappears when that count is 0.
app/services/command_center.py · kpis()app/static/app.js · rCommandCenter()Formula
Why this wayAn empty row would read as a metric; its absence reads as 'nothing to do'. The cost is that a detector that raises an error is also skipped silently, so a missing row can mean 'nothing to do' or 'the check failed', and the screen cannot tell the two apart.
In the demo4 clusters
Check it yourselfCount the table rows; it matches the number beside the title.
app/services/command_center.py · priorities()app/static/app.js · rCommandCenter()Formula
CRITICAL = post-discharge follow-up, assessments overdue · HIGH = measure below target, vendor referrals overdue · MEDIUM = duplicate outreach, members we cannot reach
colour: CRITICAL red, HIGH amber, anything else greyWhy this wayThe priority says which kind of clock is running: a window that cannot be reopened (Critical), a commitment already breached (High), or waste that breaches nothing (Medium). It does not grow with the size of the cluster; one member in a closing window outranks a hundred with a missed target.
In the demoHealth risk assessments overdue CRITICAL, Post-discharge follow-up CRITICAL, Diabetic Retinal Exam HIGH, Duplicate outreach MEDIUM
app/services/command_center.py · priorities()app/static/app.js · rCommandCenter()Formula
Critical 0, High 1, Medium 2), then by member count, largest firstWhy this wayThe kind of deadline decides first; size only breaks ties within the same priority. It is not the Work-queue score in Part I (Work-queue ranking): no member-level signal enters it.
In the demoHealth risk assessments overdue, Post-discharge follow-up, Diabetic Retinal Exam, Duplicate outreach
Check it yourselfRead the Priority and Members columns: priorities never go up as you read down, and within one priority the member counts never go up.
app/services/command_center.py · priorities()Formula
Why this wayThis counts people. The 'Why' text beside it often counts something else (encounters, assessment rows, referrals, outreach ladders), so the two numbers on one row can differ and are not meant to match. For a panelled login the members are narrowed to the panel before the count and the example names are taken, so a provider sees only its own members.
In the demoHealth risk assessments overdue 2, Post-discharge follow-up 1, Diabetic Retinal Exam 6, Duplicate outreach 3 members
Check it yourselfClick the row's action button; the list it opens contains these members, among others.
app/services/command_center.py · priorities()app/api/population.py · command_center()Formula
… is added when the cluster has more than 3 membersWhy this wayThe names are there to make a cluster concrete, not to rank anyone: the order is the internal id order, which is arbitrary and changes on every demo reset, so the three names shown for a large cluster are not the most urgent three. The demo value below therefore reports how many names are shown rather than which. Like the count, the names are chosen before the panel filter runs (reported as a defect).
In the demoHealth risk assessments overdue 2 name(s), Post-discharge follow-up 1 name(s), Diabetic Retinal Exam 3 name(s) + …, Duplicate outreach 3 name(s)
app/services/command_center.py · priorities()app/static/app.js · rCommandCenter()Formula
transitions.VISIT_DAYS = 7)
N = those discharged 2 days ago or less (CONTACT_HOURS 48 / 24 = 2.0)
M = E - N, i.e. discharged 3 to 7 days ago · members = distinct members in EWhy this wayThe windows are the ones in Part I (Transition-of-care windows), imported from the transitions module rather than restated. N and M count encounters, not members. 'M inside the 7-day visit window' excludes the N rows, although those are inside the visit window too. The contact window prints as '2.0-day' because it is computed by dividing hours by 24. When N is 0 the text reads only 'E inside the 7-day visit window'. Unlike the Transitions screen, this counts any encounter kind, not only inpatient stays.
In the demo1 inside the 2-day contact window, 0 inside the 7-day visit window
Check it yourselfClick View transitions: the contact window is still open on each discharge counted in N.
app/services/command_center.py · _post_discharge()Formula
Why this wayOne measure is reported, not all of them, so the row is a decision rather than a report. This is NOT the measure rate in Part I (A measure across a population), which is compliant members over eligible members. Here only members who have ever had a gap row are counted: a compliant member who never had a gap is missing from both sides, gaps closed as EXCLUDED or NOT_APPLICABLE count as met, and retired measures are not filtered out. The Quality screen and this row can therefore show different rates for the same measure; in the reset demo tenant they do.
In the demoDiabetic Retinal Exam: 0% against a 70% target — 70.0 points short
Check it yourselfOpen Quality and find the same measure: its rate is computed over the eligible population and will usually differ from this one.
app/services/command_center.py · _measure_below_target()app/services/quality.py · evaluate_tenant()Formula
Assessment rows whose status is not COMPLETED, REFUSED or UNREACHABLE and whose due_on is before today
members = distinct members among themWhy this wayAn assessment the member refused, or that could not be completed because the member was unreachable, is settled rather than late. N counts assessment rows of any kind, not only HRAs. The due date is set when the assessment is raised: 90 days after enrolment for the first, then 365 days after the last settled one. This screen does not raise missing assessments itself, so a member enrolled since the last sweep is not counted until one exists. The sentence 'the denominator is every enrolled member' describes the HRA completion-rate KPI, which the product computes elsewhere but no screen currently shows; this row computes no rate and no denominator, only a count.
In the demo2 past their contractual window
app/services/command_center.py · _assessments_overdue()app/services/assessments.py · ensure_due()Formula
VendorReferral rows whose sla_due_on is before today and whose status is not CONFIRMED, DECLINED, FAILED or CANCELLED
N = number of late referrals · D = the largest today - sla_due_on in days, with that referral's vendorWhy this wayIt calls the same is_overdue rule as the vendor scorecard, so this row and Vendor Performance cannot disagree about which referral is late. N counts referrals; the Members column counts members. The row is absent when nothing is late.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfNothing is late in the freshly reset demo tenant, so the row does not appear. When it does, click Vendor performance: the breaches there are the same referrals.
app/services/command_center.py · _vendor_sla()app/services/vendors.py · is_overdue()Formula
OutreachSequence whose status is not COMPLETED, EXHAUSTED or STOPPED
N = members with 2 or more live ladders · K = the most live ladders any one member hasWhy this wayIt flags members being contacted about several things at once, which the member experiences as being pestered. The text says the ladders come 'from separate programmes', but the code groups by member only and does not check the programme or purpose of each ladder (Part I, Engagement ladder, describes one ladder at a time).
In the demo3 member(s) have more than one live outreach ladder — one has 3
Check it yourselfOpen any listed member's Engagement tab: more than one ladder is live.
app/services/command_center.py · _duplicate_outreach()Formula
OutreachSequence rows with status EXHAUSTED, with no time limit
members = distinct members among themWhy this wayA ladder is exhausted when every usable channel has been tried (Part I, Engagement ladder, wait times and the contact ceiling). N counts ladders; the Members column counts members. Because there is no time limit, a ladder that ran out months ago still counts. This is a different signal from the 'outreach stalled' ranking factor, which reads intervention status.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfNo ladder is exhausted in the freshly reset demo tenant, so the row does not appear. It appears once a ladder has used every channel.
app/services/command_center.py · _unreachable()The Care Manager's "what needs me today" screen (payer personas — VBC Manager, Executive, Platform Admin — get the Command Center under the same menu item instead): eight operational counts, the top of the ranked member panel, three progress strips and the population totals.
Formula
open whose due date (first 10 characters, YYYY-MM-DD) equals today's US business date. Tenant-wide: every owner, not only mineWhy this wayRead against the US business calendar (business_today()), not the server's time zone, so a task due today does not jump to tomorrow at 19:00 Eastern. It counts tasks, not members: one member with three tasks due today adds three. It is a subset of Population "Open tasks".
In the demo16 tasks
Check it yourselfMy Work, Team: sort by Due and count the open tasks dated today.
app/api/vbc.py · summary()Formula
open that have a due date and whose due date (due[:10]) is earlier than today's US business date, compared as ISO text. Tenant-wideWhy this wayA task due today is not overdue until tomorrow. The Command Center's "Tasks overdue" card computes the same idea in a second function (command_center.py · kpis()): it lower-cases the status and parses the date, so a task stored as Open or with a malformed due value is counted on one screen and not the other. On the demo data both show the same number. See Part I, Prioritisation, for how overdue work is ranked.
In the demo8 tasks
Check it yourselfMy Work, Team: sort by Due and count the open tasks dated before today; as VBC Manager, the Command Center's "Tasks overdue" card shows the same number on the demo.
app/api/vbc.py · summary()app/services/command_center.py · kpis()Formula
HIGH or RISING. Tenant-wide, every member row including unresolved duplicatesWhy this wayThe tier is the one stored by the last rescore (see Part I, Population health), not recomputed on read. It equals the High plus Rising bars of the Risk distribution strip on this page. The Command Center card of the same name upper-cases the tier first, so it would also count a tier stored as high; the demo stores upper case and both screens agree.
In the demo6 members
Check it yourselfAdd the High and Rising numbers in the Risk distribution strip lower on the page.
app/api/vbc.py · summary()app/services/risk.py · score_patient()Formula
VISIT_DAYS = 7 days before today (visit window still open). Counts encounters, not distinct membersWhy this wayAnchored to the discharge date, so a discharge we learned about late has less window left, not a fresh one (see Part I, Clocks and windows). It counts every discharge inside the 7-day window whether or not the contact or the visit has already happened: nothing checks a task or an appointment, so the label says more than the count proves. The Transitions screen's "Visit window open" count is the same computation. The Command Center's "Discharges (30d)" is a different number: any encounter kind, 30 days.
In the demo1 discharges
Check it yourselfOpen Transitions: the "Visit window open" card shows the same number.
app/api/vbc.py · summary()app/services/transitions.py · recent_discharges()Formula
SUBMITTED, IN_REVIEW or PENDED) + (members with at least one open gap and no coverage row that is active with effective_from ≤ today ≤ effective_to)Why this wayBoth causes stop the same service, so they share one card; the note under Care gap progress splits them. The units are mixed: authorizations plus members. A member with two pending authorizations, or a pending authorization and no coverage, adds two or more. The authorization half is tenant-wide and does not check the decision timestamp, while the panel's "authorization on the clock" signal also requires that no decision is recorded.
In the demo1
Check it yourselfIt equals the sum of the four numbers in the "Blocking care" note under Care gap progress.
app/api/vbc.py · summary()Formula
OUTREACH, UNREACHABLE or DECLINED. No age condition. Counts interventions, not membersWhy this wayThe same three statuses as the "Outreach stalled" signal in Part I, Prioritisation. Two limits: an outreach started a minute ago counts, because no waiting time is applied; and a member who answered and DECLINED counts, although the paper describes the signal as "sent, nothing back".
In the demo0 interventions
Check it yourselfMy Panel, "all factors": members with an outreach_stalled factor are where these sit; one member can hold several such interventions.
app/api/vbc.py · summary()Formula
GAP_CLOSED, CANCELLED or COMPLETEDWhy this wayAnything not finished counts as active here, including DECLINED and UNREACHABLE. The Command Center card with the same label, and the Interventions worklist it opens, both leave out DECLINED and UNREACHABLE, so this card shows a larger number than those screens as soon as one outreach fails. On the fresh demo there is one intervention (AUTH_APPROVED) and all three show 1.
In the demo1 interventions
Check it yourselfAs VBC Manager, the Command Center's "Active interventions" card and its Interventions worklist show the same number while no outreach has ended declined or unreachable.
app/api/vbc.py · summary()app/services/command_center.py · kpis()app/services/worklists.py · interventions()Formula
CLOSED and a closure date (closed_on, YYYY-MM-DD) on or after the first day of the current US business monthWhy this wayOnly CLOSED counts; EXCLUDED, NOT_APPLICABLE and the other closed states do not. Gaps closed before closure dates were recorded have no date and are reported separately (see "Gaps closed without a closure date") instead of being counted as not this month, which would read as a measured zero. Reopening a gap clears its closure date.
In the demo0 gaps
Check it yourselfMember 360, Care gaps: a gap closed this month shows Closed with this month's closure date; the fresh demo has none closed yet.
app/api/vbc.py · summary()Formula
Why this wayA plain non-zero test with no threshold: the five badged cards are things to do, the other three are things to know. Red is kept for work already past its date.
In the demoTasks due today, Overdue tasks, Discharges to follow up, PA / eligibility blocking care
Check it yourselfEvery badged card shows a number above 0; the unbadged ones never carry the badge.
app/static/app.js · rDash()Formula
limit=8) and the number of members scoring above 0Why this wayThe same ranking as My Panel (see Part I, Prioritisation, My Panel), cut at 8 so the first screenful stays short. My Panel asks for 25, so the two screens show different row counts from one ranking.
In the demo8 members
Check it yourselfCount the table rows; the first 8 rows of My Panel are the same members in the same order.
app/static/app.js · rDash()app/api/population.py · my_panel()app/services/panel.py · panel()Formula
Why this wayVisible means the whole tenant for a care manager and a provider's attributed members for a provider. It is not "my" members: the ranking function's description says it narrows to the members a care manager owns work for, but the code only uses the viewer to set a mine flag, so every care manager sees the same N.
In the demo12 members
Check it yourselfMy Panel lists the same members (up to 25 rows); for the demo's 12 the whole list is on one page.
app/services/panel.py · panel()app/core/scope.py · visible_ids()Formula
open (any owner)Why this wayCounts across all scored members, not only the 8 rows shown, so it can be larger than the number of NO TASK badges visible on this page. These are the members the task queue cannot show, because nobody has raised work for them.
In the demo2 members
Check it yourselfOn My Panel, count the rows with a NO TASK badge.
app/services/panel.py · panel()Formula
Why this wayThree differences between the code and Part I's table. The 25 points apply while the 7-day VISIT window is open, not only the 48-hour contact window, and the extra 15 is added from day 3, so days 3 to 7 score 40. The 10 for "high risk and in no programme" is given only when enrollment is the member's top next-best action, so a high-risk unenrolled member whose top action is a gap gets nothing. Adherence reads a missing or 0.0 PDC as adherent (the risk score reads 0.0 as non-adherent). A declined or unreachable intervention counts its gap as in flight (2), not unworked (8).
In the demo80 points
Check it yourselfMy Panel, open "all factors" on John Doe: +40 + 30 + 10 = 80, Part I's worked example.
app/services/panel.py · panel()Formula
Why this wayOne line, not all of them, so the column stays readable; the full list is on My Panel. For John Doe the 40-point unworked-gaps component outranks the 30-point risk tier. Two text limits: adherence percentages are truncated, not rounded (int(pdc×100)), and a stalled outreach reads "reached out, nothing back" even when the member answered and declined.
In the demo5 open gap(s) with nothing running: HbA1c Control — Glycemic Assessment, Diabetic Retinal Exam, Statin Adherence (PDC >= 80%)
Check it yourselfMy Panel, "all factors": the Reason is the text of the factor with the most points.
app/services/panel.py · panel()Formula
open, whoever owns themWhy this wayIt says only that no task exists. It says nothing about interventions: a member can carry NO TASK while a gap is being worked.
In the demoJon Doe
Check it yourselfOpen the member's 360: the Tasks list has no open task.
app/services/panel.py · panel()Formula
HIGH ≥ 60 points, RISING ≥ 35, MEDIUM ≥ 15, else LOW (see Part I, Population health)Why this wayIt is the tier as of the last rescore, not recomputed on this read. A tier can also be set by hand through the records interface; the demo's duplicate record "Jon Doe" is seeded LOW after the tenant rescore, with no factors behind it.
In the demoHIGH
Check it yourselfMember 360, Risk: the factors listed add up to a score inside that tier's band.
app/services/risk.py · score_patient()app/services/risk.py · rescore()Formula
Start intervention, Try an alternate channel, Track authorization <ref> or Offer care-management enrollmentWhy this wayPart I does not describe the enrollment action: a HIGH-tier member in no enrolled programme gets it, always in band High with score 10 × 1.6 × 0.8 = 12.8. A gap already being worked and not waiting on an authorization gets no action, and dismissed actions are dropped, so the column can show a dash.
In the demoStart intervention
Check it yourselfMy Panel shows the same action for the member; the member 360's Next best action card leads with it.
app/services/nba.py · recommend()app/services/nba.py · _recommend_for_gap()app/services/nba.py · _recommend_enrollment()Formula
; , then cut to the first 90 characters in the browserWhy this wayThree reasons, not the full list of up to eleven, because the full list lives on the member 360. The cut is a plain character count, not a word boundary: John Doe's line is 91 characters, so the screen ends "…measure packag".
In the demoOpen quality gap — HbA1c Control; Overdue 97 days; Critical priority on the measure packag
Check it yourselfMy Panel shows the same reason uncut, and the member 360's Next best action lists the reasons in the same order.
app/services/nba.py · _recommend_for_gap()app/static/app.js · rDash()Formula
no deadline when there is noneWhy this wayThree different clocks can be running, so the reason travels with the date (see Part I, Clocks and windows, for the discharge and authorization clocks). The earliest date may already be past: for John Doe it is a task 97 days overdue. The discharge date is added for any inpatient discharge in the last 120 days, even after its 7-day window closed, and with two such discharges the older one is used.
In the demo97 days before the reset
Check it yourselfMember 360: the earliest date among the member's open tasks, discharge window and pending authorizations is the one shown.
app/services/panel.py · _soonest_due()app/services/panel.py · panel()Formula
OPEN or REOPENED; In progress = IN_PROGRESS, SCHEDULED or AWAITING_AUTH; Closed = CLOSED onlyWhy this waySERVICE_COMPLETED (the member attended, evidence not yet in) is an open state but sits in neither bar, so Open plus In progress can be smaller than the Population "Open care gaps" card on the same page. EXCLUDED, NOT_APPLICABLE and the other closed states are not shown either. On the fresh demo no gap is in those states and the strip adds up to 29. Closed counts gap rows, not the measure numerator in Part I, Quality measurement.
In the demoOpen 28, In progress 1, Closed 0
Check it yourselfOpen + In progress equals Population "Open care gaps" whenever no gap is waiting on evidence.
app/api/vbc.py · summary()Formula
Why this wayEach bar is a share of the three states drawn, not of all gaps, so gaps in states outside the bars do not shorten them. Whole-percent rounding can make the bars total 99% or 101%.
In the demoOpen 97%, In progress 3%, Closed 0%
Check it yourselfDivide each count by the sum of the three and round.
app/static/app.js · rDash()Formula
SUBMITTED, IN_REVIEW or PENDED. Tenant-wide; counts authorizations, not membersWhy this wayAn authorization still on its clock stops the member being scheduled, so it belongs on an operational board (see Part I, Clocks and windows, Prior-authorization decision clock). It does not check whether a decision timestamp is already recorded, while the panel's member signal does.
In the demo0 authorizations
Check it yourselfAuthorizations screen: count the rows at Submitted, In review or Pended.
app/api/vbc.py · summary()Formula
active with effective_from ≤ today ≤ effective_to: no coverage rows at all → no coverage on file; otherwise any row not active → terminated; else → lapsedWhy this wayEach member lands in exactly one bucket, because the three causes need different fixes: a missing record is often an unmerged duplicate, terminated means the member left the plan, lapsed means the dates ran out. Members with no open gap are skipped: nothing is waiting on cover. The same test drives the panel's 18-point "no active coverage" signal.
In the demono coverage on file 1, terminated 0, lapsed 0
Check it yourselfThe demo's 1 is Jon Doe, the unmerged duplicate of John Doe: his 360 has no coverage.
app/api/vbc.py · summary()Formula
CLOSED and no closure dateWhy this wayThe closure date was added later, so older closures carry none. They are counted as closed but left out of "this month" and named here, rather than silently treated as closed in some other month.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfNo gap is closed in the fresh demo, so the note does not appear. It appears once a gap with status Closed has no closure date, for example a record migrated from before closure dates existed.
app/api/vbc.py · summary()Formula
IDENTIFIED, ASSIGNED, OUTREACH, ENGAGED, AWAITING_AUTH, AUTH_APPROVED, SCHEDULED, IN_PROGRESS, COMPLETED, GAP_CLOSED, leaving out UNREACHABLE, DECLINED and CANCELLED. Outreach ≥ OUTREACH, Reached ≥ ENGAGED, Scheduled ≥ SCHEDULED, Completed ≥ COMPLETEDWhy this wayStages are cumulative, so a member already scheduled still counts as reached. Consequences: an intervention waiting on or holding an authorization counts as reached but not scheduled; one that was reached and later declined drops out of every stage; a REOPENED intervention is in none. It counts interventions, not members.
In the demoOutreach 1, Reached 1, Scheduled 0, Completed 0
Check it yourselfThe demo's one intervention is at Auth approved: it counts in Outreach and Reached only.
app/api/vbc.py · summary()Formula
Why this wayEach stage is shown as a share of the Outreach stage, so Outreach is always a full bar when it is above 0 and the others read as conversion from it.
In the demoOutreach 100%, Reached 100%, Scheduled 0%, Completed 0%
Check it yourselfDivide each stage by the Outreach number and round.
app/static/app.js · rDash()Formula
Why this wayThe tier as of the last rescore (see Part I, Population health). It includes hand-set tiers and the demo's unmerged duplicate "Jon Doe", seeded LOW with no factors, so the Low bar holds one member no rule scored.
In the demoHigh 2, Rising 4, Medium 5, Low 2
Check it yourselfThe four numbers add up to Population "Patients"; Patients screen, filter by risk.
app/api/vbc.py · summary()app/services/risk.py · score_patient()Formula
Why this wayA member with no tier shortens all four bars without appearing, so the bars can total under 100%; rounding alone can make them total 99% or 101%. The demo totals 99%.
In the demoHigh 15%, Rising 31%, Medium 38%, Low 15%
Check it yourselfDivide each tier count by Population "Patients" and round.
app/static/app.js · rDash()Formula
Why this wayNot attributed members and not de-duplicated: an unmerged duplicate (the demo's "Jon Doe") counts as a second member. The whole tenant for a care manager; a provider who opens this screen sees the count of their own attributed panel, like every other figure on it.
In the demo13 members
Check it yourselfThe Patients screen lists the same number of rows; the Command Center's "Members" card agrees.
app/api/vbc.py · summary()Formula
OPEN, IN_PROGRESS, SCHEDULED, AWAITING_AUTH, SERVICE_COMPLETED, REOPENEDWhy this wayGap rows, including gaps already scheduled or attended and waiting on evidence. Part I, Quality measurement defines open gaps per measure as denominator minus numerator and totals twenty-nine; this card shows 29 on the demo too. The Command Center card counts any status not in the closed set, which agrees for every known status.
In the demo29 gaps
Check it yourselfAs VBC Manager, the Command Center's "Open care gaps" card and the Open care gaps worklist behind it show the same number.
app/api/vbc.py · summary()Formula
open, any owner. Tenant-wideWhy this wayThe denominator the two task cards come from: Tasks due today and Overdue tasks are subsets of it (Part I, Prioritisation, opens with the same thirty-two). A started task keeps status open, so it stays in this count.
In the demo32 tasks
Check it yourselfMy Work: the Team button carries the same number.
app/api/vbc.py · summary()Care managers open My Work to see their own open tasks, ranked by what is happening to each member and with the reason each task exists. VBC managers use the Team view of the same screen to find everyone's open work, including tasks nobody owns.
Formula
rule_key). 'Open' means status == 'open' exactly, so tasks someone has started are still counted.Why this wayThe title counts what is on screen, while the Mine and Team buttons always count the whole tenant. So when the queue is filtered to one exception (an amber badge names the rule), the title can be smaller than the buttons beside it. That is intended: the filter is visible and 'all work' removes it. Neither view is narrowed by panel or attribution: Team is the whole tenant.
In the demo31 tasks
Check it yourselfcount the rows in the table; with no exception filter the title equals the Mine button in the Mine view and the Team button in the Team view
app/static/app.js · rWork()app/api/vbc.py · my_tasks()Formula
status == 'open' and owner_id equal to the signed-in userWhy this wayThe count is the same whichever view is selected, because both counts come back with every response. That lets the toggle show what is on the other side without a second request. Started (in-progress) tasks are included, because a started task is still open.
In the demo31 tasks
Check it yourselfin the Mine view with no exception filter, the table has exactly this many rows
app/api/vbc.py · my_tasks()Formula
status == 'open', whoever owns them and including tasks with no ownerWhy this wayOne number, printed in three places on this screen. It is tenant-wide, not limited to the signed-in user's panel. The empty state compares it with Mine (team > mine) to tell a care manager with a clear queue that work is waiting in the Team view.
In the demo32 tasks
Check it yourselfswitch to Team: the table has this many rows
app/api/vbc.py · my_tasks()app/static/app.js · rWork()Formula
owner_id. Count: number of open tasks in the tenant with no owner_id, from every source (rule, campaign, transitions sweep, typed by hand)Why this wayA task is unassigned when it was typed in without an owner, or when a rule found nobody to give it to. Rules assign by continuity first (the member's current owner), then to the holder of the target role with the fewest open tasks, and leave the task unowned only when nobody holds that role (see 'Owner' below). The count and the badges describe the same set, so they agree whenever the table shows the whole Team view.
In the demo1 tasks
Check it yourselfswitch to Team and count the amber UNASSIGNED badges; they equal N
app/api/vbc.py · my_tasks()app/services/task_rules.py · _assign()Formula
source != 'manual'. X = number of open tasks in the tenant with source != 'manual'. The sources are rule, campaign and transitions (and manual).Why this wayThe note exists to report how much of the queue came from events rather than from typing. It is honest about the ratio but broader than its wording: a campaign that a person launched also counts as 'raised by a rule from an event' and also gets the AUTO badge. X counts the whole tenant whichever view is shown.
In the demo26 tasks
Check it yourselfswitch to Team and count the blue AUTO badges; they equal X
app/api/vbc.py · my_tasks()app/static/app.js · rWork()Formula
source == 'manual'. Every task has a source (default manual), so X + Z = Team N always.Why this wayReported, not asserted: the note sits beside the claim that work should come from events and rules, so a reader can see how far that is true of this queue.
In the demo6 tasks
Check it yourselfin the Team view, the rows reading 'created by hand' under the member name number Z
app/api/vbc.py · my_tasks()Formula
started_at is set. N = number of open tasks in the tenant with started_at set. Derived, never stored as a status.Why this wayIn progress is not a status. The task stays open, so it stays in the queue and in every open count, and it does not disappear from other screens that filter on open. Pressing Start sets started_at and also claims an unowned task, so two people do not work the same call.
In the demo0 tasks
Check it yourselfzero after a reset. Press Start on any row: the badge appears on that row and N goes up by one
app/api/vbc.py · my_tasks()app/static/app.js · taskStart()Formula
priority. Typed in by hand: the label chosen. Raised by a rule: the rule's own grade where it has one (abnormal lab: Critical at 30% or more outside the range, else High), otherwise the rule's configured priority. A few rules may later raise it one band (see 'Escalated priority').Why this wayThe badge prints the word the record holds, coloured red, amber, blue and green. It is one input to the ranking, worth 20 / 12 / 6 / 2 points, and not the ranking itself (see Part I, Work-queue ranking). So a Medium task can sit above a Critical one.
In the demoHigh
Check it yourselfthe top row's badge. Hover 'score N' under it: the first line is '+points marked <label>'
app/static/app.js · priorityBadge()app/services/task_rules.py · evaluate()Formula
escalate_after_days and escalate_to_role (as shipped: gap.evidence_missing and appointment.not_rebooked, 7 days, vbc_manager): when today − (due date, else the business date it was created) >= 7, the priority moves up one band (Low→Medium→High→Critical; Critical stays Critical) and [escalated to vbc_manager] is added to the reason. It happens once per task, guarded by a task.escalated audit row.Why this wayEscalation adds urgency without taking the task away from its owner: the owner is not changed. Both rules raise their tasks with no due date, so in practice the 7 days run from the day the task was created. The Exception Center's 'Escalated' card describes this as 'raised to a second role', but no reassignment happens; the role appears only as text in the reason.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfnone in a fresh tenant. It appears on a task-rule sweep once an 'evidence missing' or 'missed visit not rebooked' task is 7 days old
app/services/task_rules.py · _escalate_overdue()Formula
Why this wayComputed each time the screen loads and never stored, so the order moves as the calendar does, with no recompute job. Part I says the care manager 'sees the composed sentence, not the number'. In fact the screen shows both: the sentence in the Reason column and the number here. In a freshly reset tenant only five of the eight components can fire; age, the authorization clock and stalled outreach have nothing to act on.
In the demo107 points (top row)
Check it yourselfhover 'score N': the +points in the tooltip add up to N
app/services/ranking.py · rank()Formula
+points why, joined with · , in a fixed order: priority, due, age, member risk, post-discharge window, authorization, gap, engagement. The 'marked <label>' line is always first, even at +0.Why this wayThe tooltip shows the evidence behind the order, so the queue explains its ranking rather than just asserting it. It is in engine order, not sorted by points. The worked example in Part I is sorted by points and shortens the gap line to 'HbA1c Control'. The screen shows the full measure name and adds ', N open in total' when the member has more than one open gap.
In the demo+12 marked High · +55 overdue by 60 days · +22 high-risk patient · +18 critical-priority gap: HbA1c Control — Glycemic Assessment, 5 open in total
Check it yourselfhover the top row's score and compare it word for word
app/static/app.js · rWork()app/services/ranking.py · rank()Formula
Critical 20, High 12, Medium 6, Low 2, any other label 0Why this wayThe human label counts, but it can be outscored by what is happening to the member (see Part I, Work-queue ranking). It used to be the heaviest component at 40.
In the demo12 points (top row)
app/services/ranking.py · rank()Formula
D = due date − today, where today is the US business date (America/New_York). D < 0: 35 + 2 × min(days late, 10), i.e. 37 to 55. D = 0: 25. D = 1–2: 18. D = 3–7: 10. D > 7: 3. No due date, or one that is not a date: no line.Why this wayLateness counts most, and stops adding after 10 days so an ancient task cannot bury today's work. Part I prints the overdue range as '35–55'. The code never gives 35: one day late is already 37. The business-date clock stops the queue from calling today's tasks overdue after 20:00 Eastern, when UTC has already rolled over.
In the demo55 points (top row)
Check it yourselfa task more than 10 days late shows the +55 cap; one 1 day late shows +37, and one 4 days late shows +43
app/services/ranking.py · _due_component()Formula
min(D, 21) points.Why this wayAge breaks ties. It lets low-priority work with no due date eventually surface. Part I says 'after 3 days, one per day', which reads as one point on day 4. The code gives 3 points on day 3 and 21 from day 21.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfa reset creates every task at reset time, so no task is 3 days old yet. The line appears on any task still open 3 days later
app/services/ranking.py · _age_component()Formula
HIGH 22, RISING 15, MEDIUM 6, LOW 0 (no line)Why this wayIt applies to every task of the member, whatever the task is about. The tier itself comes from the clinical risk score (see Part I, Clinical risk score and tier). A task with no member gets only the priority, due and age components.
In the demo22 points (top row)
app/services/ranking.py · rank()Formula
48 // 24): 28 points, open until discharge + 2 days. Otherwise N ≤ 7: 20 points, visit due by discharge + 7. Otherwise: no line.Why this wayThe window closes whether or not anyone acts, so it ranks above almost everything while it is open (see Part I, Transition-of-care windows). It lifts EVERY open task of that member, not only the discharge tasks. The '48 hours' are counted as whole calendar days, so a member discharged just after midnight stays 'open' for almost 72 hours.
In the demo28 points (first row that has it)
Check it yourselfevery row for the member discharged two days before the reset carries +28, including a social-barrier task that has nothing to do with the discharge
app/services/ranking.py · rank()app/services/transitions.py · recent_discharges()Formula
decision_due. H = hours until it (elapsed time, printed whole with the fraction dropped). Past it: 30. H < 24: 25 expedited / 20 standard. H < 72: 18 / 12. Otherwise: 5.Why this wayThis is the regulatory clock the authored priority could never express (see Part I, Prior-authorization decision clock). Only the soonest authorization counts, and it lifts every task of that member, not only the task about the authorization.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfnone of the demo queue's members has an undecided authorization with a deadline, so no line shows after a reset. Submit an authorization for a member with a task, and every task of that member gains the line
app/services/ranking.py · _sla_component()Formula
OPEN, IN_PROGRESS, SCHEDULED, AWAITING_AUTH, SERVICE_COMPLETED, REOPENED), the one with the highest priority: Critical 18, High 12, Medium 6, Low 2. ', K open in total' is added when K > 1.Why this wayIt uses the worst gap's priority, not the number of gaps, because three Low gaps are not one Critical gap. A gap the member has attended but that has no evidence yet (SERVICE_COMPLETED) still counts as open here.
In the demo18 points (top row)
app/services/ranking.py · rank()Formula
OUTREACH, UNREACHABLE or DECLINED. There is no time test.Why this wayIt flags members whose outreach needs a different channel. Part I calls it 'sent, nothing back'. The code has no waiting period: outreach started today already scores 14, and DECLINED is an answer, not silence. It is a different quantity from the rule 'Outreach with no movement' (engagement.stalled), which raises a task only after 21 idle days.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfno queue member has outreach at those statuses after a reset. Press 'Begin outreach' on a member's intervention, and every task of that member gains +14 at once
app/services/ranking.py · rank()Formula
Why this wayThe tie-breaks make the order stable across reloads instead of whatever the database returned (see Part I, Work-queue ranking). The order is the only output; no rank number is shown. It applies to the rows in view, Mine or Team, after any exception filter.
In the demo107, 107, 101, 94, 94 (scores of the first five rows)
Check it yourselfthe first two rows tie on score; the one due earlier is above the other
app/services/ranking.py · rank()Formula
+ . Phrases: the due/age text as-is, 'marked <label>', '<tier> risk', the gap's measure name, 'post-discharge contact window open' / 'overdue', 'authorization on the SLA clock', 'outreach stalled'.Why this wayThe headline says what is true about the member in a few words, not what somebody typed. Three phrases fit a table cell; the tooltip keeps the full list. The grey line under it is the rule's own reason text (see the rows below).
In the demooverdue by 60 days + high risk + HbA1c Control — Glycemic Assessment
Check it yourselfthe three phrases are the three largest +points in that row's tooltip
app/services/ranking.py · priority_reason()Formula
Why this wayKept as a safety net, and effectively unreachable. The authored-priority component always exists and is worth at least 2 for every standard label, so the headline is empty only for a non-standard label. A second helper that would show this value with a tooltip (rankCell) is defined in the page code but never called.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfnever shown in the demo: every row has a composed headline
app/services/ranking.py · top_reason()app/static/app.js · rWork()Formula
due sort before today's date, where today is the US business date (America/New_York). A task due today is not overdue. A due that is not a date never shows the badge.Why this wayIt is the same boundary the ranking uses for its overdue points, so the badge and the '+N overdue by D days' line always agree.
In the demo8 rows badged in the Mine view
Check it yourselfcount the red OVERDUE badges; every one of those rows has an 'overdue by' line in its tooltip, and no other row does
app/api/vbc.py · my_tasks()Formula
rule_key; with no rule: 'campaign' if source == 'campaign', 'transitions sweep' if source == 'transitions', else 'created by hand'Why this wayIt names the rule in a care manager's words ('Post-discharge contact window'), not the mechanism, so the person can see why a task they did not create is in their queue.
In the demoHRA past its contractual window
app/static/app.js · rWork()app/api/vbc.py · my_tasks()Formula
ceil(48h ÷ 24)), + 3 for medication reconciliation and barriers, + 7 for the visit and the assessment. Care gap due soon: the gap's date; today if the gap says 'now', 'overdue' or 'asap'; otherwise today + 14. Abnormal lab: result date + 7. Authorization at risk: the date of decision_due. Appealable denial: decision date + 60. Coverage ending: the coverage end date. SLA breach and HRA: the missed date. Social barrier, enrolment and engagement tasks: the day raised. Evidence missing and missed visit not rebooked: no date.Why this wayDischarge windows count from the discharge date, not from the day the record arrived (see Part I, Transition-of-care windows). A later sweep never re-dates an existing task: one task per rule and trigger. Two known limits. The authorization date is the UTC calendar date, so a late-evening Eastern deadline can show the next day. The task rule rounds the contact hours up, while the Transitions screen rounds its fixed 48 hours down; the two agree at 48 hours but would split if a tenant tuned the rule.
In the demo60 days before the reset
Check it yourselfthe 'Discharged … — follow-up visit due within 7 days' row is due 7 days after the discharge date in its reason
app/services/task_rules.py · _r_transition_contact()app/services/task_rules.py · _transition_step()app/services/task_rules.py · _r_gap_due_soon()app/services/task_rules.py · _r_pa_sla_at_risk()Formula
100 × (value − upper) ÷ |upper|; below: 100 × (lower − value) ÷ |lower|; rounded to a whole percent. Only the latest abnormal result per member per test in the last 30 days. Under 10%: no task. 30% or more: Critical, else High.Why this wayThe lab's abnormal flag has no size, so the rule measures how far outside the range the result is before it interrupts anyone. A result with no reference range is not treated as normal. It still raises a High task, which says the platform could not grade it.
In the demo14 % (highest-ranked lab task)
Check it yourselfevery graded lab task in the demo is below 30% and shows High; the HbA1c with no range says it could not be graded
app/services/task_rules.py · _deviation_pct()app/services/task_rules.py · _r_lab_critical()Formula
SUBMITTED, IN_REVIEW or PENDED: H = hours until decision_due, with the fraction dropped (23.9 prints '23h'). The task is raised when H ≤ 24, and says 'overdue' once H < 0.Why this wayIt warns the UM nurse a day before the regulatory deadline (see Part I, Prior-authorization decision clock). The hours are frozen into the reason when the task is raised; the score tooltip's authorization line is recomputed on every load.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfnone after a reset. Raised by a task-rule sweep within 24 hours of a pending authorization's deadline
app/services/task_rules.py · _r_pa_sla_at_risk()Formula
DENIED authorization: raised while today − decision date ≤ 60; closes on decision date + 60 (the rule's appeal_days)Why this wayIt keeps a denial in front of a care manager while an appeal is still possible. Known conflict: the rule uses a flat 60 days for every line of business, while the appeals engine defaults to 180 days (60 for Medicare Advantage). For a non-MA denial, the task names a closing date 120 days before the appeals engine would close the window.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfnone after a reset. Deny an authorization, run the task rules, and the task appears with the closing date 60 days out
app/services/task_rules.py · _r_pa_denied_appealable()Formula
Why this wayA member in care management who loses coverage drops out of the programme; 30 days leaves time to confirm continuing coverage. Coverage with no end date never raises a task.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfnone after a reset
app/services/task_rules.py · _r_coverage_lapsing()Formula
OUTREACH or IDENTIFIED: N = today − date of its last recorded event; raised when N ≥ 21; due the day raisedWhy this wayThe last event is the last deliberate act on the intervention. Not the same as the '+14 outreach stalled' score line, which has no day count at all (see that row).
In the demo— nothing to show in the fresh demo tenant
Check it yourselfnone after a reset
app/services/task_rules.py · _r_engagement_stalled()Formula
today − the object's due date ≥ 0 (grace 0) and the object is not settled: vendor sla_due_on, referral due_on, provider opportunity sla_due_on (NEW or VIEWED only), social-need follow_up_on, HRA due_on. The task's due date is that same date.Why this wayBecause the grace is 0, a breach task is raised ON the deadline day, not the day after. So a task titled 'Vendor has missed its SLA' can appear while its own row shows 'due today' and no OVERDUE badge, and the provider portal still calls the opportunity not overdue (it uses due < today). The HRA reason prints the assessment's status word, which reads 'and is due' for an HRA two months late.
In the demo3 tasks in the Team view
Check it yourselfthe vendor task in the demo says its SLA was the reset day, yet its row has no OVERDUE badge
app/services/task_rules.py · _r_vendor_sla_breach()app/services/task_rules.py · _r_referral_sla_breach()app/services/task_rules.py · _r_opportunity_unanswered()app/services/task_rules.py · _r_sdoh_follow_up()app/services/task_rules.py · _r_hra_overdue()Formula
SERVICE_COMPLETED, and today − the date it reached that status ≥ 7. Missed visit: the member's most recent appointment is NO_SHOW or CANCELLED, and today − its date ≥ 5. Both are raised with no due date.Why this wayAttendance is not the outcome. A gap stuck at 'attended' stays open on the measure, and a missed visit nobody rebooks is a member falling out of care. With no due date these tasks can never show OVERDUE, and their 7-day escalation clock runs from creation (see 'Escalated priority').
In the demo— nothing to show in the fresh demo tenant
Check it yourselfnone after a reset
app/services/task_rules.py · _r_gap_evidence_missing()app/services/task_rules.py · _r_appointment_not_rebooked()Formula
ELIGIBLE, sorts them by number of criteria met (most first), and proposes the first 5 (max_per_run). A member who already has an offer task still takes one of the 5 places.Why this wayThe rule is rationed because care management has limited capacity, and a queue with every eligible member in it gets scrolled past. The cap is in effect 'the top 5 eligible members each evaluation', not '5 new offers each run'. Ties between members with the same number of criteria keep database order. The eligibility criteria are in Part I, Care-management eligibility.
In the demo1 offer tasks in the Team view
app/services/task_rules.py · _r_enrollment_offer()Formula
Why this wayA member with three care managers effectively has none, so new work joins whoever already has the member. Continuity overrides the rule's target role: an authorization task meant for a UM nurse can go to the member's care manager. Tasks raised by a provider's response (review, dispute, more information) are assigned without a caseload count, so unless continuity applies they go to the lowest-id holder of the role, not the least-loaded one.
In the demoJane Smith
Check it yourselfreassign from the Owner drop-down; the next rule-raised task for that member goes to the new owner
app/services/task_rules.py · _assign()app/services/task_rules.py · _caseload()The Care Manager's first screen: every member who currently needs attention, ranked by a points score that explains itself, with the next best action and what is already running. Below it, a follow-through panel counts what happened to the interventions the signed-in care manager owns.
Formula
> 0, counted BEFORE the top-25 cut.
For a care manager: every member in the tenant. For a provider login: only the provider's attributed members (scope.visible_ids).Why this wayCounted before the cut so the badge says how many members need attention, not how many rows fit on the screen: the table shows at most 25 of them. Despite the title, the list is NOT narrowed to the signed-in care manager. The signed-in user only sets a mine flag on each row, which the screen does not display. A care manager therefore sees the whole tenant's attention list; the Dashboard's Today's priorities shows the same computation with 8 rows and the same total ('of N needing attention').
In the demo12 members
Check it yourselfCount the rows: with fewer than 25 members needing attention the table has exactly this many rows. Open Dashboard: Today's priorities says 'of N needing attention' with the same N.
app/services/panel.py · panel()app/api/population.py · my_panel()app/core/scope.py · visible_ids()Formula
> 0 that have no WorkTask with status open, whoever owns the task. Counted over all members needing attention, not only the 25 rows shown.Why this wayThis is the reason the panel exists: the task queue can only rank work somebody created, so a member who needs attention but has no task is invisible there. Any open task counts, including one owned by another care manager, so the number answers 'has nobody raised anything', not 'have I raised anything'. When more than 25 members need attention, N can be larger than the NO TASK badges visible in the table.
In the demo2 members
Check it yourselfCount the amber NO TASK badges in the Member column; with 25 or fewer rows they equal N.
app/services/panel.py · panel()Formula
WorkTask in status open (has_task is false). Owner and task subject are not considered.Why this wayThe badge is a presence test, not an ownership test: a member whose only open task belongs to someone else shows no badge, and a member whose tasks are all closed shows the badge even when an intervention is running (Derrick Boateng in the demo: an intervention at AUTH_APPROVED, no open task).
In the demoJon Doe, Derrick Boateng
Check it yourselfOpen the member's 360 and look at open tasks: a badged member has none.
app/services/panel.py · panel()app/static/app.js · rPanel()Formula
Patient.risk_tier: HIGH when the risk score is >= 60, RISING >= 35, MEDIUM >= 15, else LOW. See Part I, Population health.Why this wayThe panel reads the tier stored on the member; it does not recompute it. The stored tier is refreshed only when risk is recomputed, and a user with record-edit rights can also set it by hand: a member created by hand carries the model version 'manual entry', and an edit changes the tier without changing the version. Until the next recompute a hand-set tier can differ from the model's latest score, which is what the risk header on Member 360 shows. The tier is worth 30 / 20 / 8 / 0 points in the priority score.
In the demoHIGH (John Doe)
Check it yourselfOpen the member's 360: the risk header shows the model's tier, which matches unless the tier was set by hand since the last recompute.
app/services/risk.py · score_patient()app/services/risk.py · rescore()Formula
30 / RISING 20 / MEDIUM 8; 8 per open gap with no live intervention; 2 per gap already being worked; 25 while the 7-day post-discharge visit window is open, plus 15 more once the 48-hour contact window has passed (days 3–7); 10 if any active medication has PDC below 0.80; 12 if a prior authorization is SUBMITTED, IN_REVIEW or PENDED; 14 if an intervention sits at OUTREACH, UNREACHABLE or DECLINED; 18 if the member has an open gap and no active coverage today; 10 if the member's top recommendation is 'Offer care-management enrollment'. Members scoring 0 are not listed. Computed at request time, never stored. See Part I, My Panel.Why this wayA points table rather than a model, so a care manager can argue with each weight. Three places where the code is narrower or wider than Part I's table reads: (1) the discharge 25 applies for the whole 7-day visit window, not only while the 48-hour contact window is open, so a member discharged 5 days ago scores 40 from discharge; (2) the 'high risk and in no programme' 10 is added only when enrollment is the member's TOP recommendation — in the demo Maria Gonzales is HIGH risk and not enrolled, but her top recommendation is a Critical gap, so she scores 70, not 80; (3) the adherence test reads a PDC stored as 0 as 100%, so a member recorded at 0% earns no adherence points. Adherence, authorization and stalled outreach each count once per member however many medications, authorizations or interventions qualify. This is a different scale from the risk score (Part I's worked example: John Doe 85 on risk, 80 here) and from the My Work task score.
In the demo80 points (John Doe)
Check it yourselfOpen 'all factors' on the row: the + numbers add up to the Priority.
app/services/panel.py · panel()app/services/transitions.py · recent_discharges()app/services/nba.py · recommend()Formula
components.length). One per signal that fired, at most 10.Why this wayIt counts signals, not problems: five unworked gaps are ONE factor worth 40 points. A high count means the attention comes from several independent directions; it says nothing about size.
In the demo3 factors (John Doe)
Check it yourselfOpen 'all factors': it lists exactly this many lines.
app/static/app.js · rPanel()app/services/panel.py · panel()Formula
why text of the single highest-points component. Ties keep a fixed order: risk, unworked gaps, gaps in flight, post-discharge, contact overdue, adherence, authorization, stalled outreach, no coverage, no programme.Why this wayOne sentence, so the reason for the rank is readable at a glance; the rest is one click away. The sentence carries computed values: the unworked-gap sentence counts all unworked gaps but names only the first three; the adherence sentence names the lowest-PDC medication and truncates its percentage (int), where Member 360 rounds it, so the two can differ by one point; the authorization sentence names the first undecided SUBMITTED / IN_REVIEW / PENDED authorization in database order, not the one due soonest.
In the demo5 open gap(s) with nothing running: HbA1c Control — Glycemic Assessment, Diabetic Retinal Exam, Statin Adherence (PDC >= 80%)
Check it yourselfOpen 'all factors': the Why sentence is the first (largest) line.
app/services/panel.py · panel()Formula
+points factor — why.Why this wayThe score ships with its own explanation, so a member's position can be checked rather than trusted. The factor names are the internal keys (unworked_gaps, post_discharge, …), not translated labels.
In the demo+40 unworked_gaps, +30 risk, +10 adherence (John Doe)
Check it yourselfThe + numbers sum to the Priority in the same row.
app/services/panel.py · panel()app/static/app.js · rPanel()Formula
25.Why this wayA name tie-break keeps the order stable across reloads. The order moves by itself as clocks move (a discharge window opening, an authorization going pending) because nothing is stored. The Dashboard's Today's priorities is the first 8 rows of the same ranking, and a cohort's member list is ranked by the same engine restricted to the cohort, so the three cannot disagree about a member.
In the demoJohn Doe 80, Maria Gonzales 70, Linda Tran 62
Check it yourselfOpen Dashboard: Today's priorities lists the same members in the same order.
app/services/panel.py · panel()Formula
500 recommendations. Labels: 'Start intervention', 'Track authorization <ref>', 'Try an alternate channel', 'Offer care-management enrollment'. See Part I, Next best action.Why this wayOne pass for the whole tenant keeps the screen to one read of each table. Deferred or dismissed recommendations are left out. 'Nothing recommended' means every gap is already in hand (for example an intervention running) and the member is not a high-risk unenrolled member. The band that decided the order is not shown on this row.
In the demoStart intervention (John Doe)
Check it yourselfOpen the member's 360: its next-best-action list (same engine, same order) starts with the same action.
app/services/nba.py · recommend()app/services/panel.py · panel()Formula
3 reason texts of that recommendation joined with ; . For an enrollment offer, the fixed sentence 'high-risk member is not enrolled in any care-management program'.Why this wayThree reasons keep the row short; the full reasoning is on the member's 360. The Dashboard shows the same text cut to 90 characters.
In the demoOpen quality gap — HbA1c Control; Overdue 97 days; Critical priority on the measure package
Check it yourselfOpen the member's 360: the first recommendation's reasons begin with the same three.
app/services/nba.py · recommend()Formula
COMPLETED, GAP_CLOSED or CANCELLED.Why this way'In flight' is defined by exclusion, so IDENTIFIED, UNREACHABLE and DECLINED interventions still appear here. The same definition decides whether a gap counts as 'already being worked' (2 points) or 'unworked' (8 points). The Cost Concentration screen's '(N unworked)' uses a different rule: there a COMPLETED intervention still counts as working the gap, so a gap whose intervention completed without closing it is unworked here and worked there.
In the demoDiabetic retinal exam AUTH_APPROVED (Derrick Boateng)
Check it yourselfOpen the member's 360, Care tab: the same interventions are listed as open.
app/services/panel.py · panel()Formula
decided_at empty) and status SUBMITTED, IN_REVIEW or PENDED.Why this wayShown because a pending authorization blocks scheduling. 'First' is database order (the query has no sort), not the one due soonest. The Start button uses a wider idea of 'pending': any undecided authorization linked to the gap's intervention, including a DRAFT. So a DRAFT authorization hides Start with no auth line shown, and a pending authorization not linked to the gap shows here while Start is still offered. See Part I, Prior-authorization decision clock.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfSubmit a prior authorization for a member on the panel; after a reload the line appears and Priority rises by 12.
app/services/panel.py · panel()Formula
BOOKED or CONFIRMED whose business-time date is today or later; the screen prints the first 10 characters of its UTC timestamp.Why this wayOnly live bookings count, so a cancelled or no-show appointment never reads as care arranged. The printed date and the filter use different clocks: the filter uses US business time, the printed date is UTC, so an appointment in the US evening (after midnight UTC) prints the next day's date.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfBook an appointment for a panel member from the 360 Care tab; after a reload its date appears here.
app/services/panel.py · _next_appt()app/static/app.js · rPanel()Formula
CLOSED, all time, with no date window.Why this wayIt tells a care manager what has already been achieved for this member. Gaps retired as not applicable or excluded are not counted, and a closed gap that was later reopened drops out. It counts the member's gaps, whoever closed them; it is not the same number as the follow-through 'Gaps closed' below, which counts the signed-in user's interventions.
In the demo0 closed (John Doe)
Check it yourselfOpen the member's 360, Care tab: count the gaps shown as closed.
app/services/panel.py · panel()Formula
Why this wayAny engagement counts, so an inbound message or a failed send updates it. 'Never contacted' means no engagement is recorded in the platform, not that nobody tried by another route.
In the demonever contacted
Check it yourselfRecord an engagement (a call or a message) for the member; after a reload this line shows today's date.
app/services/panel.py · _last_contact()Formula
vbc.write); the recommendation is actionable (no undecided authorization linked to the gap's intervention, of any status including DRAFT); and the recommendation is for a gap.Why this wayThe screen only offers what the server would accept. An enrollment offer is actionable but is not about a gap, so it never gets a Start button. Starting still runs the authorization-requirement check on the server first.
In the demo10 rows show Start (care manager)
Check it yourselfRows showing 'nothing recommended' or an enrollment offer have no Start button.
app/static/app.js · rPanel()app/services/nba.py · recommend()Formula
Why this wayThe denominator of the follow-through funnel. It is ownership, not authorship: a reassigned intervention moves to its new owner's count. There is no date window; the function accepts a 14-day parameter that is not used.
In the demo0 interventions
Check it yourselfClick Start on a panel row; after a reload this card goes up by one.
app/services/panel.py · follow_through()Formula
IDENTIFIED, ASSIGNED, OUTREACH, UNREACHABLE, DECLINED or CANCELLED, all time.Why this way'Reached' means the member responded, so an intervention that only sent a message does not count. It is defined by exclusion: ENGAGED and every later state (through COMPLETED and GAP_CLOSED) counts, so it always includes 'Service completed'. The Dashboard's engagement funnel 'Reached' counts from a list of states instead, and the two disagree on one: a REOPENED intervention counts as reached here and not on the Dashboard.
In the demo0 interventions
Check it yourselfMove one of your interventions to ENGAGED; this card goes up by one.
app/services/panel.py · follow_through()Formula
COMPLETED or GAP_CLOSED, all time.Why this wayThe service happened. Started ≥ Reached ≥ Completed always holds, so the three cards read as a funnel.
In the demo0 interventions
app/services/panel.py · follow_through()Formula
CLOSED, all time.Why this wayIt counts interventions, not distinct gaps. A gap closes on clinical evidence that can arrive for reasons unrelated to the outreach, which the caveat under the panel says in bold: read it as what happened to the work, not what the work caused. A gap that later reopened drops out. Different from the per-member 'N closed' in the table and from a quality measure's numerator.
In the demo0 interventions
app/services/panel.py · follow_through()Formula
OUTREACH, UNREACHABLE or DECLINED, with no age threshold.Why this wayThese need a different channel or a caregiver contact, and nothing else surfaces them. There is no waiting period, so an intervention moved to OUTREACH today already counts. DECLINED is included and is described as 'reached out, nothing back', although a member who declined did answer. The Dashboard's 'Outreach needing follow-up' uses the same three states for the whole tenant; this note counts only your own.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfIn the fresh demo tenant the care manager owns no interventions, so the note is absent. Start an intervention and move it to OUTREACH: the note appears with N = 1.
app/services/panel.py · follow_through()app/static/app.js · rPanel()The lists behind the Command Center cards (open care gaps, care plans, interventions in flight, referrals, vendors, vendor performance). A VBC manager, executive or administrator opens them by clicking a card; each is a list you can act on, not a report.
Formula
CLOSED, EXCLUDED, NOT_APPLICABLE, GAP_CLOSED, RESOLVED, DUPLICATEWhy this wayThis is the list the Command Center's 'Open care gaps' card opens, and it uses the same rule (gap_is_open), so the card and the list agree. A gap being worked (in progress, scheduled, awaiting authorization) is still open: a gap closes on evidence, not on effort. The list shows at most 200 rows; the count is the full total.
In the demo29 open gaps
Check it yourselfOpen the Command Center, note 'Open care gaps', click it: the header count here is the same number.
app/services/worklists.py · care_gaps()app/services/workflow.py · gap_is_open()Formula
Why this wayThe same missed measure matters more on a high-risk member with a chronic condition, so priority is a lookup rather than a score: two inputs, sixteen fixed answers, nothing hidden. It is re-derived every time the measure is evaluated, so it follows the member's tier. The list is sorted Critical first, then by member name. This priority feeds both ranking engines (Part I, Work-queue ranking and Next best action).
In the demoCritical 6, High 10, Medium 12, Low 1
Check it yourselfOpen a Critical row's member: their risk tier is HIGH and the measure is a clinical one.
app/services/quality.py · gap_priority()app/services/worklists.py · care_gaps()Formula
Why this wayThe sentence is not written for display; it is the evidence the numerator test produced, so it cannot say something the engine did not decide. See Part I, One member, one measure.
In the demolatest Systolic blood pressure 148.0mmHg on 2026-08-25 is above the 140 threshold
Check it yourselfOpen the member and the gap: the lab or procedure history shows exactly what the sentence says.
app/services/quality.py · meets_numerator()app/services/quality.py · evaluate_patient()Formula
ACTIVE care planWhy this wayOne row per active plan. Rows are sorted with overdue reviews first, then by member name, so the plans that need a person come to the top.
In the demo1 plans
app/services/worklists.py · care_plans()Formula
MET:
a goal linked to a care gap is met when that gap is CLOSED or RESOLVED
a goal linked to a vendor referral is met when the referral is CONFIRMED
a goal with no linked work is met only when a person marked it metWhy this wayA goal's status is derived from the work beneath it, so nobody can type 'met' over an open gap; only a goal with nothing linked relies on a person's word. The cost: a goal whose gap closed for an unrelated reason also reads as met.
In the demoJohn Doe: 8 goals, 0 met
Check it yourselfOpen the member's Care plan tab: each goal's status and the gap or referral it is linked to are shown side by side.
app/services/worklists.py · care_plans()app/services/careplan.py · _goal_status()Formula
Why this wayA review date in the past is a commitment already missed, so it is flagged rather than merely shown. Dates are judged on the US business calendar, not the server's clock, so the flag does not flip at the wrong midnight.
In the demo0 overdue reviews
app/services/worklists.py · care_plans()app/core/clock.py · business_today()Formula
CANCELLED, COMPLETED, GAP_CLOSED, DECLINED or UNREACHABLEWhy this wayIn flight means somebody still has something to do. This is the same rule as the Command Center's 'Active interventions' card, which opens this list, so they agree. The care manager's Dashboard card of the same name excludes only GAP_CLOSED, CANCELLED and COMPLETED, so a declined or unreachable intervention counts there and not here.
In the demo1 interventions
app/services/worklists.py · interventions()Formula
IDENTIFIED, OUTREACH, ENGAGED, SCHEDULED, then every other state, then member nameWhy this wayEarliest stage first, because an intervention nobody has contacted yet is the one most likely to stall.
In the demoAUTH_APPROVED 1
app/services/worklists.py · interventions()Formula
Why this wayIt reads the trail in the order entries were written, which is the order things happened, rather than re-sorting by timestamp.
In the demoauthorization approved; ready to schedule
app/services/worklists.py · interventions()Formula
Why this wayAll three kinds of referral in one list, because to the member they are all 'somebody was asked to help'. Sorted overdue first, then by due date.
In the demo3 referrals
app/services/worklists.py · referrals()Formula
Why this wayEach kind keeps its own clock because each is a different promise: a follow-up call, a contract, an internal service level. A referral that has settled is never overdue, however late it settled. See Part I, Referral SLA.
In the demo0 overdue now
Check it yourselfThe header's 'N overdue' chip is the count of red OVERDUE badges in the list.
app/services/worklists.py · referrals()app/services/referrals.py · sla_days()Formula
RESOLVED + vendor CONFIRMED + internal OUTCOME_CONFIRMED
none settled → no percentage, with the reasonWhy this wayThe denominator is settled referrals, not all referrals, so a referral still in progress neither helps nor hurts the rate. Closed means the outcome was confirmed by the plan, not claimed by the vendor. Green at 80% or above. For a login limited to a panel, the list, the overdue count and this percentage are all computed over the panel's referrals; settled is judged per referral kind.
In the demo100 %
Check it yourselfIf nothing has settled yet the badge reads 'closed loop: n/a' and says why.
app/services/worklists.py · referrals()Formula
CONFIRMED, DECLINED, FAILED, CANCELLEDWhy this wayA vendor is a contracted party, so its SLA is a contract term, typed once and read everywhere. Open referrals is everything that has not reached a final state.
In the demo5 vendors; SLA days 3, 5, 14, 7, 5; 2 open referrals
app/services/worklists.py · vendors()app/services/vendors.py · ensure_vendors()Formula
CONFIRMED)Why this wayConfirmed, not delivered: 'delivered' is the vendor's claim, 'confirmed' is the plan's evidence.
In the demoMedRide NEMT 0/1, Nourish Home Meals 1/1, HouseCall Health Assessments 0/1
app/services/vendors.py · performance()Formula
CONFIRMED ÷ settled ), settled = CONFIRMED + DECLINED + FAILED + CANCELLED
no settled referrals → 'n/a' with the reasonWhy this waySame denominator rule as the referrals list: only finished referrals are judged.
In the demoNourish Home Meals 100%
app/services/vendors.py · performance()Formula
Why this wayIt measures the vendor's own turnaround (to delivery), not the plan's confirmation lag. Taking a real observed value rather than averaging the two middle ones keeps it a whole number of days a vendor actually took; the cost is a slight upward lean for an even count.
In the demoNourish Home Meals 4 d
app/services/vendors.py · performance()Formula
Why this wayIt counts breaches that are still live, the ones a person can still chase; a referral that was late but has since been confirmed drops out. It is therefore a current-risk count, not a historical breach rate.
In the demo0 live breaches, all vendors
app/services/vendors.py · performance()app/services/vendors.py · is_overdue()The member roster: every staff role with patient read access (Care Manager, VBC Manager, Executive, PA Coordinator, Auditor, Administrator) sees every member of the tenant here; a Provider sees the same screen as "My Panel" in the sidebar, narrowed to the members attributed to them. It is a lookup list, not a work queue: it counts and classifies, it does not rank.
Formula
GET /vbc/patients: every Patient record in the tenant, then narrowed by scope.filter_patient_rows (a no-op for staff roles, the attributed panel for a provider).
Counted in the browser as rows.length; the search box hides rows but does not change N.Why this wayEvery member record, not only attributed members and not de-duplicated: the demo's unmerged duplicate "Jon Doe" (same date of birth and MRN as John Doe, arriving from the EHR feed) is counted as a second member until someone merges it. No row is dropped for missing coverage or a closed attribution period. The Dashboard's "Patients" card counts the same records and agrees for every staff role; it agrees for a provider too: both the Dashboard card and this list count the provider's panel. Rows are listed in the order the database returns them. The query sets no order, so the list is not ranked by risk or by anything else.
In the demo13 members
Check it yourselfCount the table rows, or download the CSV with the search box empty: same number. As Care Manager, Dashboard > Population > "Patients" shows the same N.
app/api/vbc.py · list_patients()app/core/scope.py · filter_patient_rows()app/static/app.js · rPatients()Formula
PatientAttribution row where provider_id = the signed-in provider, the attribution period is open, and ended_on is empty.
A provider login with no provider binding, or no open period, sees an empty list (never the whole tenant).Why this wayAttribution is by provider identity, not by the free-text PCP name, so the PCP column on this screen does not decide who is on the panel. In the demo every one of Dr. P. Osei's five members shows a different declared PCP (Dr. Sarah Smith, Dr. Robert Jones or Dr. Karen White); the demo seed moves these five attribution rows to Dr. Osei after they were created from the declared PCP. Those rows still read method declared_pcp and "Declared PCP on record: Dr. …", which names a different physician. That is a known inconsistency in the demo data. A member outside the panel is not merely hidden: opening them by link answers not-found rather than forbidden, so a provider cannot learn the member exists. Two things share the name here: the Care Manager's "My Panel" is a different screen (members ranked by a priority score, see the My Panel chapter) and counts something else.
In the demo5 (John Doe, Sarah Martinez, Linda Tran, Ahmed Ali, Rose Chen) members
Check it yourselfSign in as doc@demo.provider: the badge shows the number above and exactly those names. Sign in as the Care Manager: the same screen lists the whole tenant (see "Patients (N)").
app/core/scope.py · visible_ids()app/core/scope.py · _provider_panel()app/api/vbc.py · list_patients()Formula
Patient.risk_tier, printed as-is. When the risk model last scored the member: HIGH if score >= 60, RISING >= 35, MEDIUM >= 15, else LOW. See Part I, Population health.
Colour: HIGH red, RISING amber, MEDIUM blue, LOW green.Why this wayThe list reads the tier stored on the member; it does not rescore. The stored tier is refreshed in only two places: the nightly demo reset, and the recompute call POST /population/risk/recompute (VBC Manager permission). No screen offers that call. New labs, conditions or admissions do not rescore the member on arrival, so the badge can lag the clinical record. A user with record-edit rights can also overwrite the tier by hand. A hand edit does not change the model name stored on the member, so a hand-set tier still carries the model's name. A member no model has scored shows a badge too: the column defaults to LOW. In the demo, "Jon Doe" (the unmerged duplicate) shows a green LOW with no score and no factors behind it. His Member 360 says "No risk model has scored this member" and the list does not. The Dashboard's Risk distribution counts that unscored LOW as a Low member.
In the demoJohn Doe HIGH, Sarah Martinez MEDIUM, Maria Gonzales HIGH, Sam Okafor RISING, Linda Tran RISING, Ahmed Ali RISING, Rose Chen MEDIUM, Derrick Boateng MEDIUM, Elena Petrova MEDIUM, Robert Kim MEDIUM, Fatima Hassan RISING, Grace Nwosu LOW, Jon Doe LOW (never scored)
Check it yourselfOpen a member: the Member 360 risk header shows the score and the factor list, and the tier matches the badge (for a scored member the factors add up to a score inside the band). For Jon Doe the 360 says no model has scored him.
app/services/risk.py · score_patient()app/services/risk.py · rescore()app/api/records.py · update_patient()app/api/vbc.py · list_patients()app/static/app.js · statusBadge()The care manager's record of one member (VBC managers, executives, PA coordinators, providers for their own panel and auditors can open it too). This chapter covers the header, the Overview's service cases, partner activity and recent activity, the care gaps and interventions on the Care tab, the transition badge on the Utilization tab, and coverage and authorizations on the Coverage tab. Figures are shown as the care manager Jane Smith sees them.
Formula
Why this wayWorked out by the server each time the record is read, never stored, because a stored age is wrong on the member's next birthday. Known defect: when the date of birth is missing or unreadable, the age function returns -1 rather than no value, so the header prints '| -1' where it should leave the age out.
In the demo65 years
Check it yourselfThe date of birth is printed two lines below the name. Subtract it from today's date.
app/api/vbc.py · get_patient()app/services/quality.py · _age_on()Formula
male / female / other (any case) shown as Male / Female / Other; anything else is not shown
plan: payer + plan of the member's coverage whose status is active (the dates are not checked); none → 'no active coverage on file'
not recorded: names each of sex, PCP and active coverage that is emptyWhy this wayThe header names a missing fact instead of leaving a blank, because a blank looks like a display fault. The plan line reads the coverage status only, like the summary strip's Coverage card. The Coverage tab's 'Coverage' line uses a different rule (the coverage with the latest end date, whatever its status; see the row on that line below).
In the demoJohn Doe: Male | UnitedHealthcare MA Choice; not recorded: nothing, Jon Doe: (sex not shown) | no active coverage on file; not recorded: sex, active coverage
Check it yourselfOpen Jon Doe (the unmerged duplicate): no sex is shown, the plan line reads 'no active coverage on file' and the header lists both under 'not recorded'.
app/api/vbc.py · get_patient()Formula
Patient.risk_tier), the same field as the Patients list badge. When the risk model sets it: HIGH ≥ 60 · RISING ≥ 35 · MEDIUM ≥ 15 · LOWWhy this waySee Part I, Clinical risk score and tier, and the Patients list row on the risk tier. Known inconsistency on this screen: the Primary risk drivers panel on the Overview prints the tier of the latest scoring run, not this stored field. Editing the tier by hand (Edit patient) changes this badge and not the panel, so the two can show different tiers for one member. They agree in the fresh demo tenant.
In the demoheader HIGH; risk drivers panel HIGH
Check it yourselfCompare the header badge with the badge on the Primary risk drivers panel on the Overview tab.
app/api/vbc.py · get_patient()app/services/member360.py · risk_drivers()app/api/records.py · update_patient()Formula
Why this waySalesforce is the system of record for cases; this panel is a copy, so a care manager does not work the member while a complaint is open without knowing about it. Open or closed depends on the closed date Salesforce sent, not on its status text, so a case sent as status 'Closed' without a closed date reads 'Open'. The count is only as current as the last sync (next row).
In the demo1 open: Transportation complaint (In Progress)
Check it yourselfEach case card below the count says Open or Closed; count the Open ones.
app/api/population.py · member_cases()app/static/app.js · casesPanel()Formula
Why this wayA copied status without the time of the last copy invites a stale answer to be read as current. Known limit: the time is UTC and carries no zone label, so after 8 pm Eastern (daylight time) it already shows the next day's date.
In the demomoves with the clock — read it on screen
Check it yourselfIn the demo it is the time of the nightly reset, in UTC.
app/api/population.py · member_cases()Formula
DELIVERED 'Vendor reports it completed', CONFIRMED 'Completion confirmed by the plan, with evidence', …)
overdue: the SLA due date is before today and the referral is not settled (settled = CONFIRMED, DECLINED, FAILED, CANCELLED)
SLA due date = referral date + the vendor's contracted SLA days (7 when the vendor has none)
colour: red if overdue, FAILED or DECLINED · green if CONFIRMED · grey if otherwise settled (CANCELLED) · blue otherwise
rows: newest last activity first, by full timestampWhy this wayDelivered is the vendor's claim and confirmed is the plan's evidence, so only confirmed turns green. The SLA clock starts at the referral, not when the vendor acknowledges it, so a slow acknowledgement cannot move the deadline. Part I, Referral SLA covers team referrals; vendor referrals use the vendor's own contracted days instead. A vendor with an SLA of 0 days is treated as 7.
In the demoMedRide NEMT: Service scheduled (blue), Nourish Home Meals: Completion confirmed by the plan, with evidence (green), HouseCall Health Assessments: Vendor acknowledged (blue)
Check it yourselfClick 'Closed-loop detail': the Referrals tab's Vendor referrals table shows the same referrals, with the SLA date in red when overdue.
app/services/vendors.py · member_view()app/services/vendors.py · is_overdue()app/static/app.js · p360Tab()Formula
Why this wayOne list across all areas, so the order of events is visible. Known limit: the date has no time of day. Events on the same day are ordered by the kind's name in reverse alphabetical order (tasks, then referrals, provider, pa, interventions, gaps, engagement, encounters, …), not by when they happened. On a busy day the six shown are not the six latest events: in the demo all six of John Doe's are tasks raised today, ahead of care gaps opened the same day.
In the demo2026-09-24 Task raised — Start Intervention, 2026-09-24 Task raised — Close care gap, 2026-09-24 Task raised — Review result with member, 2026-09-24 Task raised — Discuss food insecurity and refer to a community resource, 2026-09-24 Task raised — Complete the health risk assessment, 2026-09-24 Task raised — Assign a care manager and open a care plan
Check it yourself'Full timeline' opens the Timeline tab. Its first six entries are the same six, in the same order.
app/services/member360.py · timeline()app/static/app.js · p360Tab()Formula
OPEN → IN_PROGRESS → AWAITING_AUTH → SCHEDULED → SERVICE_COMPLETED → CLOSED, of 6; not shown for a status outside that chain (REOPENED, EXCLUDED, …)Why this wayThe step is read from the gap's current status. Two inconsistencies on this screen: (1) this count includes closed gaps, while the summary strip's 'Open gaps' counts open ones only, so the two differ once a gap closes. (2) Under 'step N of 6' is the eight-step orchestration bar 'X of Y steps complete' (see the Gap orchestration row in the Patient 360 summary-strip chapter), which includes eligibility and authorization. The same gap therefore shows two progress figures: Derrick Boateng's retinal-exam gap reads 'step 2 of 6' with '5 of 8 steps complete' beneath it, because his authorization was approved while the gap status stayed IN_PROGRESS.
In the demoJohn Doe: 5 gaps, all step 1 of 6, Derrick Boateng, Diabetic Retinal Exam: step 2 of 6; orchestration 5 of 8 steps complete
Check it yourselfOn the Care tab, compare the 'step N of 6' line under a gap's status with the bar directly beneath the row.
app/api/vbc.py · get_patient()app/static/app.js · p360Tab()Formula
Why this wayThe panel is the member's whole history of interventions. The summary strip's 'Active interventions' counts only those still in progress, so the two numbers differ once one finishes or is cancelled. Only five events are shown to keep the card short; the full trail is on the Timeline tab.
In the demoJohn Doe: 0, Derrick Boateng: 1 (Diabetic retinal exam AUTH_APPROVED)
Check it yourselfJohn Doe has none until the demo starts one from a gap. After that, the count here and the strip's Active interventions both read 1.
app/api/vbc.py · get_patient()app/static/app.js · p360Tab()Formula
Why this wayThe member's own record shows how far the transition has got, not only a date. Three things to know. (1) This panel has no look-back limit, while Transitions lists discharges from the last 120 days and the Utilization panel directly below counts the last 180 days. So Grace Nwosu shows a plan for a March discharge while the panel below reports no inpatient admission in 180 days, and Robert Kim's plan (124 days ago) is here and not on Transitions. (2) Green means closed, not successful: a plan that closed with 6 of 7 steps missed is green. (3) Dismissed steps count as completed.
In the demoSam Okafor: discharged 2026-09-22, 4/7 completed (amber) — 3 step(s) still outstanding: Clinical assessment, Follow-up appointment, Visit completion, Grace Nwosu: discharged 2026-03-12, 1/7 completed (green) — closed with 6 missed step(s) on the record
Check it yourselfOpen Sam Okafor, Utilization tab: the badge matches the plan's steps counted by hand (the 30-day watch and the closing step are not counted). Open Grace Nwosu: a green badge above a plan with six missed steps.
app/api/population.py · member_transition()app/services/transitions.py · plan()app/static/app.js · p360Tab()Formula
activeWhy this wayOnly one coverage is active at a time: adding a plan terminates the previous one and sets its end date to today. Known defect: if the coverage request fails, the panel shows 'No coverage on file' and a count of 0 instead of an error. That is a false absence, and coverage is what decides whether a service can be booked.
In the demoUnitedHealthcare MA Choice (active, 2026-01-01 to 2026-12-31)
Check it yourselfCount the table's rows.
app/api/records.py · list_coverage()app/static/app.js · coveragePanelHtml()Formula
Why this wayThe status is printed next to the plan, so a terminated plan says so. It is chosen by a different rule from the header plan line and the summary strip, which use the coverage whose status is active. In the fresh tenant each member has one coverage and all three agree. They can name different plans after a coverage change: terminating a plan sets its end date to today, so a replacement entered with an end date already in the past loses to the terminated plan here.
In the demoUnitedHealthcare · MA Choice (active)
Check it yourselfCompare with the plan line in the header and the Coverage table directly above.
app/api/population.py · member_authorizations()Formula
Why this wayVerification is something done on a date, not a property of the record: 'active' on file is not the payer saying so today. Known inconsistency: the Check eligibility step in each gap's orchestration chain (Care tab) picks the latest check with a tie-break on id and dates it in business time (America/New_York). This line takes the UTC date and has no tie-break. A check run after 8 pm Eastern (daylight time) is dated tomorrow here and today on the Care tab. Two checks in the same second can also be picked differently.
In the demothe reset day
Check it yourselfOpen Derrick Boateng (verified on the reset day). John Doe reads 'never' until someone clicks Check eligibility in the header.
app/api/population.py · member_authorizations()app/services/orchestration.py · gap_chain()Formula
APPROVED; otherwise 'scheduling held' (a denial shows its reason)
green badge by the title = the newest approved authorization
colour: green APPROVED · red DENIED · amber PENDED, IN_REVIEW · blue otherwiseWhy this wayThe member's own record answers whether a service can be booked; the server applies the same rule when booking (see Part I, The method: scheduling stays blocked while a linked authorization is pending). Limits: (1) only an approval unlocks scheduling, so a partial approval reads 'scheduling held'; (2) title case prints IN_REVIEW as 'In_Review' and PARTIALLY_APPROVED as 'Partially_Approved'; (3) the wellness code G0439 used by the demo's Annual Wellness Visit gaps is not on the name list, so it would read 'G0439 PA — …'; (4) the 'Decided' column shows the decision date, or when there is none, the decision-due timestamp unlabelled and unformatted.
In the demoPA-2026-40188: Retinal exam PA — Approved, scheduling unlocked
Check it yourselfOpen Derrick Boateng, Coverage tab: one authorization, approved, with the green headline badge. The Authorizations screen shows the same reference and status.
app/api/population.py · member_authorizations()app/api/population.py · _service_label()app/static/app.js · authorizationsPanel()The care manager's single view of one member. Every figure below is shown for the demonstration member John Doe, as the care manager Jane Smith sees him.
Formula
Why this wayAccountability is a recorded assertion with its method, because the method is the argument when a payer disputes the denominator. The method says how the member came to this provider: 'declared_pcp' when their declared PCP is the provider, 'roster' when they were assigned to the provider's panel (the demo provider's five members), with the overridden PCP kept in the basis.
In the demoDr. P. Osei by roster since 2026-01-01 (basis: Assigned to Dr. P. Osei's panel (synthetic demo roster); declared PCP on record: Dr. Sarah Smith)
app/services/member360.py · summary()Formula
Why this wayThe tier is the risk engine's; see Part I, Clinical risk score. It is kept current by the record, not by whoever remembers: any change to a member's conditions, results, encounters or medications — through ingestion, the API or a feed — re-scores that member when it is saved, and a score is refreshed once a day when time alone moves it (a lab ageing out of its window). A tier set by hand is left as the person set it.
In the demoHIGH, 10 factors
app/services/member360.py · summary()app/services/risk.py · rescore()Formula
Why this wayThe same open rule as every other gap count (gap_is_open), for one member.
In the demo5 open (3 critical, 2 high), 0 closed
app/services/member360.py · summary()app/services/workflow.py · gap_is_open()Formula
Why this waySix months is long enough to show a pattern and short enough to be about now. The big number counts only acute use (inpatient and ED), which is the utilisation a care manager acts on.
In the demo1 acute (0 inpatient + 1 ED) of 2 encounters in 180 days
app/services/member360.py · summary()app/static/app.js · summaryStrip()Formula
IDENTIFIED, OUTREACH, ENGAGED, SCHEDULED, AWAITING_AUTH, AUTH_APPROVED or IN_PROGRESS; hint = those states, or the total when none is activeWhy this wayActive means the intervention is still moving toward its outcome. The worklists and Command Center use a slightly different list of 'not finished' states, so their counts can differ for an intervention in an unusual state.
In the demo0 active of 0
app/services/member360.py · summary()Formula
Why this wayThe member's own queue in one line, so the care manager sees what is due before scrolling.
In the demo8 open, 3 overdue; next: Close care gap
app/services/member360.py · summary()Formula
Why this wayCoverage decides who pays and whether an authorization rule applies. Known inconsistency: this card reads the status alone, while My Panel also requires today to fall between the coverage's start and end dates.
In the demoUnitedHealthcare MA Choice, ends 2026-12-31
app/services/member360.py · summary()Formula
Why this wayOne list across every source, so nothing is only visible on a tab. 'In flight' stops a care manager from starting work that someone else has already started.
In the demo7 items, 4 first, 0 in flight
app/services/attention.py · attention()Formula
Why this wayEvery severity is a written threshold, and each line shows the arithmetic that fired it. Targets are population defaults, not individualised clinical targets, and the panel says so.
In the demohigh: Creatinine above target, high: Diabetic Retinal Exam, high: HbA1c above target, high: Systolic BP above target, medium: Annual Wellness Visit, medium: Social barrier identified, medium: Statin Adherence (PDC >= 80%)
app/services/attention.py · attention()app/services/attention.py · _severely_over()Formula
Why this wayA number without its direction invites the wrong conversation: 8.9% is above target but moving the right way.
In the demo8.9%; improved from 9.4%
app/services/attention.py · _value_phrase()app/services/attention.py · _latest_by_code()Formula
Why this wayThe due date is when the measure year closes, because that is when an open gap becomes a missed one. The PA note comes from the same policy lookup the authorization screens use, so the two cannot disagree.
In the demo1 overdue gap lines
app/services/quality.py · gap_due_on()app/services/workflow.py · pa_required()Formula
Why this wayPDC (proportion of days covered) is a stored pharmacy input, not computed by the platform; 80% is the standard adherence threshold.
In the demoAtorvastatin 40mg adherence 62%, below the 80% threshold
app/services/attention.py · _adherence()Formula
Why this wayEach is a clock the member is on. The discharge line uses a 30-day window, while the Transitions screen keeps a discharge actionable for 120 days.
In the demoRecently discharged from hospital: Discharged 2026-09-22 (2 day(s) ago) from Apex Demo Medical Center.
Check it yourselfShown for Sam Okafor, discharged two days before the reset.
app/services/attention.py · _transition()app/services/attention.py · _authorizations()app/services/attention.py · _coverage()Formula
apex-risk-rules v2)Why this wayA transparent points model, not a statistical one: every point names the fact that earned it. See Part I, Clinical risk score, for every weight. The panel shows the latest stored scoring run, and that run always matches the member's current record: saving a new result re-scores the member, and the score history keeps every earlier run. For John Doe the 9.4% HbA1c band (18 points) gave way to the 8.9% band (10 points) when the September result arrived: 85 points.
In the demo85 points, HIGH, model apex-risk-rules v2
app/services/member360.py · risk_drivers()app/services/risk.py · score_patient()Formula
Why this wayA diagnosis explains the tier but is not something to close, so it gets an explanation rather than a false call to action.
In the demo5 drivers with an action button
app/services/member360.py · _action_for_driver()Formula
Why this wayAn observed change, not a claim about what caused it; the panel says so. No time window, so the whole record on file is compared.
In the demoHbA1c 9.4 → 8.9 (-0.5, improved, target 8.0), Systolic BP 162.0 → 148.0 (-14, improved, target 140.0), Creatinine 1.9 → 1.8 (-0.1, improved, target 1.3)
app/services/outcomes.py · patient_trajectory()Formula
Why this wayThe abnormal flag is the laboratory's statement, kept as sent: re-deriving it from a reference range would put words in the lab's mouth. PDC is a pharmacy input the platform stores, not a figure it computes.
In the demo3 problems, 6 of 6 lab results flagged abnormal, 2 encounters, PDC Atorvastatin 40mg 62%
app/services/ingest.py · promote()app/static/app.js · panelMeds()Formula
Why this wayA progress bar that can never reach the end is one nobody reads, so a service with no authorization requirement has 6 steps, not 8. Each step is derived, never ticked.
In the demoHbA1c Control — Glycemic Assessment: 2 of 6 steps complete, Diabetic Retinal Exam: 2 of 8 steps complete, PA required, Statin Adherence (PDC >= 80%): 2 of 6 steps complete
app/services/orchestration.py · gap_chain()Formula
Why this wayAn eligibility answer goes stale; a 30-day-old check is not evidence of coverage today.
In the demoopen: coverage on file (UnitedHealthcare MA Choice) but never verified with the payer
app/services/orchestration.py · gap_chain()Formula
Why this wayApproval of an authorization never closes a gap; only clinical evidence of the service does. The check is on the evidence supplied with the event.
In the demo0 gaps closed on evidence so far
app/services/workflow.py · evaluate_completion()Formula
Why this wayOne chronology across every system, so the member's story reads in order. Counting before filtering lets a reader see what a filter hides.
In the demo44 events; Clinical 11, Encounters 2, Care Gaps 6, Tasks 8, Referrals 12, Provider 1, Care Plan 1, Engagement 3
app/services/member360.py · timeline()Formula
Why this wayColour marks events that change what should happen next, so a long timeline can be skimmed.
In the demored 7, amber 1, green 1
app/services/member360.py · timeline()The care manager's working tabs on one member: care-management enrolment, the health risk assessment, the care plan, social barriers, appointments and documents (Care tab), team, social and vendor referrals (Referrals tab), and Partner Activity on the Overview. Every figure below is read as the care manager Jane Smith sees it, for John Doe unless another member is named.
Formula
ELIGIBLE, OFFERED, ACCEPTED or ENROLLED
badge = the live status; with nothing live: MEETS CRITERIA when at least one eligibility criterion is met today, else NOT ELIGIBLE
a stage dot is ticked when it is at or before the live status in ELIGIBLE → OFFERED → ACCEPTED → ENROLLED
'Previously declined / disenrolled' = the member's DECLINED or DISENROLLED row for cm-complex, shown only when nothing is liveWhy this wayThe badge is the recorded lifecycle; the criteria are re-evaluated on every view. The two can differ, and the panel shows both rather than choosing: an ENROLLED member who no longer meets any criterion keeps ENROLLED (Sarah Martinez shows ENROLLED above 'does not currently meet the criteria'). A member who declined is shown as declined and is not re-offered automatically; offering again is a person's decision. Two limits. The live row may belong to any programme, while the 'previously' line reads only cm-complex. And the Recommended action card uses a different rule (see the Next best action chapter): it offers enrolment to every HIGH-risk member not yet ENROLLED, so Maria Gonzales, already OFFERED, is still recommended an offer (ranked sixth, so it is below the three cards Patient 360 shows, but it is on the Population list), while rising-risk members who meet the criteria get no offer card.
In the demoENROLLED; stages reached: ELIGIBLE, OFFERED, ACCEPTED, ENROLLED
Check it yourselfOpen John Doe → Care. Sam Okafor shows MEETS CRITERIA with a 'Previously declined' line and an 'Offer again' button.
app/services/enrollment.py · member_view()app/static/app.js · enrollmentPanel()Formula
Why this waySee Part I, Care-management eligibility. The criteria are computed on every view and never stored as a flag, so the reasons are current. The acute test counts encounters by admission date. The social test uses the same barrier classification as this tab's Social drivers of health panel, so a declined referral still counts as unaddressed. Part I's worked example is out of date: the product today finds six members on eight criteria. Maria Gonzales also meets the recent-acute test, and Robert Kim qualifies on it; neither line is in Part I's table.
In the demoHigh-risk member (risk tier HIGH), Admission or ED visit in the last 6 months (1 acute encounter(s))
Check it yourselfOpen John Doe → Care: two lines, 'High-risk member' and 'Admission or ED visit in the last 6 months'. His Utilization tab shows the admission.
app/services/enrollment.py · evaluate()Formula
Why this wayEnrolment can be recorded directly, for example from a payer file or a programme older than the platform. So the platform reports an enrolment with nothing behind it rather than refusing to record it. Known inconsistency: the same panel's note says 'ENROLLED is not settable on its own', and Part I says enrolment assigns a care manager and opens a care plan first. Both are true only for the Start programme button, not for a directly recorded ENROLLED. In the fresh demo tenant, 7 of the 8 ENROLLED members have no care plan and show this badge. John Doe is the exception.
In the demoNOT ACTUALLY STARTED: no active care plan
Check it yourselfOpen Sarah Martinez → Care: ENROLLED, NOT ACTUALLY STARTED, 'no active care plan'. John Doe shows Care manager Jane Smith and no red badge.
app/services/enrollment.py · delivery_state()app/static/app.js · enrollmentPanel()Formula
COMPLETED, REFUSED and UNREACHABLE are settled)
badge = the live status; else COMPLETED if any HRA was completed; else NONE DUE
PAST WINDOW, and a red Due date = due date before today (business date) and not settledWhy this wayThe window is the contract's, so an HRA nobody attempted shows as past its window as plainly as one the member refused. Two limits. A late completion is shown as COMPLETED, with nothing on this screen marking it late; the in-window test exists only in the HRA completion KPI, which no screen renders. And this panel does not know about an in-home HRA referred to a vendor. John Doe shows DUE and PAST WINDOW while his Referrals tab shows HouseCall Health Assessments working an annual in-home HRA for him; the two records are not linked.
In the demoDUE, PAST WINDOW
Check it yourselfOpen John Doe → Care: DUE and a red PAST WINDOW; the row's Due date is red.
app/services/assessments.py · member_view()app/static/app.js · hraPanel()Formula
Why this wayThe clock runs from enrolment, not from when somebody created the record: a window that starts when the plan notices is not a window. A refused or unreachable HRA starts the next annual cycle from its due date, so the member is asked again next year rather than on the next sweep. The 90 and 365 days are constants in code, not tenant settings. The missing HRA rows are created when this panel is read (the read also writes).
In the demo60 days before the reset
Check it yourselfJohn Doe enrolled 150 days before the reset; his first HRA was due 90 days later, so it is 60 days past due.
app/services/assessments.py · ensure_due()Formula
Why this wayThe count of lines on the plan, not a measure of progress. The plan's own summary also computes met and PA-blocked counts, but this panel does not show them.
In the demo8 goals
Check it yourselfCount the rows of John Doe's care plan table.
app/services/careplan.py · read()Formula
Why this wayA plan nobody revisits is a document, not a plan. The 90 days are a constant in code, not a tenant setting. 'Started' is the day the plan record was opened, not the enrolment date. John Doe's plan is opened by the demo reset, so it reads as started on the reset day although he enrolled five months earlier.
In the demo90 days after the reset
Check it yourselfClick Mark reviewed: the date moves to today + 90 days.
app/services/careplan.py · ensure_plan()app/services/careplan.py · review()app/services/careplan.py · read()Formula
Why this wayA typed status can read 'active' over a gap nobody has touched, so a linked goal takes its status from the work and cannot be edited. Hovering the badge shows the basis. MET for a vendor line means CONFIRMED, with evidence, not the vendor's own DELIVERED. Two known defects. (1) Accepting a vendor proposal from this screen loses its vendor link, because the add-goal request has no vendor field. The new line reads OPEN · set by hand, and the same proposal is offered again. The two vendor lines in the demo were seeded with the link and are not affected. (2) For a gap, the plan reads the first intervention it finds for that gap, in no set order. So a gap that has been worked twice can show the older intervention's state.
In the demoComplete retinal screening: OPEN (from the work), Improve diabetes control: OPEN (from the work), Improve blood pressure control: OPEN (from the work), Complete annual wellness visit: OPEN (from the work), Address food insecurity: OPEN (set by hand), Improve medication adherence: OPEN (from the work), Address ride to retinal exam: SCHEDULED (from the work), Address annual in-home health risk assessment: ACTIVE (from the work)
Check it yourselfHover a status: the tooltip names the gap, intervention, authorization or vendor referral it was read from.
app/services/careplan.py · _goal_status()app/services/careplan.py · _vendor_goal_status()Formula
Why this wayA target is shown with the reading and its date, because a target met months ago on a value nobody has taken since is not met today. Three things to know. The test is inclusive while the target text prints a strict '<', so an HbA1c of exactly 8.0 shows 'at target' beside 'HbA1c <8%'. There is no lookback window, unlike What needs attention (400 days). The arrow is always drawn ↓ for improving. That is right for every target the product proposes today, all lower-is-better, but a hand-entered higher-is-better goal would show the wrong arrow. Change over time on the Overview (Part II, the Patient 360 summary-strip chapter) compares latest with first in the same way.
In the demoImprove diabetes control: now 8.9% ↓ (2 readings), Improve blood pressure control: now 148mmHg ↓ (2 readings)
Check it yourselfCompare with the HbA1c and systolic readings in the Clinical tab's Labs & vitals table.
app/services/careplan.py · _progress()app/static/app.js · planProgress()Formula
Why this wayThe platform cannot send a task to a pharmacist or a social worker it has no account for, so it says so instead of pretending to assign the work. Adherence proposals default to Pharmacist, social-barrier proposals to Social Work, vendor proposals to Vendor.
In the demo4 goals
Check it yourselfCount the rows whose Owner column says 'outside this system'.
app/services/careplan.py · read()app/services/careplan.py · add_goal()Formula
Why this wayNothing is invented: each proposal names the fact behind it, and adding it to the plan is a person's decision. Limits. Social proposals come from the attention list, which lists every positive screening answer. It does not merge repeat screenings or check whether the barrier is already referred or resolved, and it treats 'false' and '0' as positive answers, where the social panel treats them as negative. A vendor proposal accepted here is proposed again (see goal Status).
In the demoComplete retinal screening → completed by the gap due date, Address transportation insecurity → Barrier addressed, Complete annual wellness visit → completed by the gap due date, Improve diabetes control → HbA1c <8%
Check it yourselfOpen Sarah Martinez → Care: no plan yet, and the proposals listed here, each with its reason.
app/services/careplan.py · propose()app/services/attention.py · _social()Formula
no, none, negative, no risk, false, 0 or blank is negative and dropped
each barrier: RESOLVED if its latest community referral is RESOLVED · IN PROGRESS if that referral is not settled, or a contracted vendor in the matching category (transport, meals) holds an unsettled referral · else UNADDRESSED, including a DECLINED or UNRESOLVED referral
the three counts add up to the barrier countWhy this wayA member who declined help still has the barrier, so it returns to unaddressed. A barrier a vendor is already working is not reported as ignored. The enrolment criterion and the population views use the same classification. Known defect: negative answers are dropped BEFORE the newest-per-code step. So a later 'no' on re-screening does not clear an earlier 'yes', and the barrier stays counted; the enrolment criterion has the same order. The Clinical tab has a panel with the same title that counts something else (next value).
In the demo1 barrier(s): 1 unaddressed, 0 in progress, 0 resolved
Check it yourselfOpen John Doe → Care or Referrals: one barrier, food insecurity, not addressed.
app/services/sdoh.py · barriers()app/services/sdoh.py · barrier_state()Formula
Why this wayThis is the raw record of screening answers, newest first. It has the same title as the Care tab panel but counts a different thing: a member screened twice, or with a 'no' answer, shows more here than there. Neither panel says what it is counting.
In the demo1 screening answers
Check it yourselfCount the rows of the table; compare with the barrier count on the Care tab.
app/api/population.py · clinical_record()app/static/app.js · panelSdoh()Formula
Why this wayIt shows who holds the barrier, so a care manager does not start a second referral for a ride already booked. Known inconsistency: the badge is computed from the referral, not from the server's barrier state that feeds the counts, and they disagree in two cases. A DECLINED or UNRESOLVED referral shows that status although the header counts it as unaddressed. A declined referral with a vendor now working the barrier shows DECLINED and hides the vendor box, although it is counted as in progress. So counting badges does not always give the header's counts.
In the demoFood insecurity: NOT ADDRESSED
Check it yourselfJohn Doe's food-insecurity barrier reads NOT ADDRESSED, and the header says 1 unaddressed.
app/static/app.js · sdohBarrier()app/services/sdoh.py · barriers()Formula
Why this wayEach step is read from the referral, so the chain shows how far a barrier has really got. A referral here is a record, not a transmission: a person sends it and marks it sent. Limits. 'Overdue' takes precedence over 'done', so an ACCEPTED or UNREACHABLE referral past day 14 shows Follow-up overdue beside 'member reached — accepted the referral'. A referral opened without a resource still shows Intervention chosen as done, with 'no resource chosen yet'. The 14 days are a constant and run from opening, not from sending.
In the demoFinding: done, Intervention chosen: open, Referral made: open, Follow-up: open, Resolution: open
Check it yourselfStart a referral on John Doe's barrier: Intervention chosen turns done, and 'Follow-up due' shows the date 14 days out.
app/services/sdoh.py · _chain()app/services/sdoh.py · start()Formula
Why this wayAttendance is recorded here but does not close a gap: the gap waits at SERVICE_COMPLETED for clinical evidence. Known inconsistency: if the request fails, the panel shows 0 and 'No appointments' rather than saying it could not load, unlike the other panels on this tab.
In the demo0 appointments
Check it yourself0 in the fresh tenant; after booking in Act 3 it reads 1.
app/api/integration.py · appointments()app/static/app.js · p360Tab()Formula
Why this wayA re-upload under the same name is a new version, not an overwrite, and every download re-checks the full SHA-256, so a changed file refuses to serve. Limits: two names that differ only in replaced characters share one version line; and a failed request shows 0 and 'No documents' rather than an error.
In the demoreferral: 0.2 KB, v1, checksum of 16 characters
Check it yourselfOpen Sarah Martinez → Care: one referral letter, 0.2 KB, v1.
app/api/documents.py · upload()app/api/documents.py · list_documents()app/static/app.js · docsPanelHtml()Formula
Why this wayThe member's whole history of hand-offs between teams, not only the open ones; the Due column and the LOOP CLOSED badge say which are still live.
In the demo0 referrals
Check it yourself0 in the fresh tenant; Create referral adds one.
app/services/referrals.py · member_view()Formula
referral_sla setting for that queue, else its default, else 3 days); a redirect resets it to that day + the new queue's SLA
red when due is before today and the referral is not settled (OUTCOME_CONFIRMED, DECLINED, CANCELLED, UNABLE_TO_CONTACT)Why this waySee Part I, Referral SLA. Part I leaves out the typed date: its formula holds only when the Due field is left blank. The typed value is not checked to be a date, so text that is not an ISO date is stored as typed and never turns red.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfCreate a referral to Care Management with Due blank: Due is 3 days out, and it turns red on the fourth day if still open.
app/services/referrals.py · create()app/services/referrals.py · sla_days()app/services/referrals.py · _row()Formula
OUTCOME_CONFIRMED; COMPLETED (the receiving team's own report) does not show it; DECLINED, CANCELLED and UNABLE_TO_CONTACT settle the referral without itWhy this wayA loop that closes on the doer's own word measures effort, not outcome. Only a confirmed outcome with evidence closes it, and that evidence is printed in the same row.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfWalk a referral to COMPLETED: no badge. Confirm the outcome with evidence: LOOP CLOSED appears.
app/services/referrals.py · _row()Formula
Why this wayPartner Activity is a rollup of the same records, so the two numbers cannot differ. Community (social) referrals and team referrals are not included; they have their own panels.
In the demo3 vendor referrals; Partner Activity 3
Check it yourselfJohn Doe: MedRide NEMT, Nourish Home Meals and HouseCall Health Assessments on both tabs.
app/services/vendors.py · member_view()Formula
Why this wayDELIVERED is the vendor's claim and CONFIRMED is the plan's evidence, so they are separate steps. The chain is drawn in full, including the part that has not happened. Known defect: for a DECLINED, FAILED or CANCELLED referral the first marker (SENT) is drawn ○, as if the referral was never sent, because those statuses are not positions on the chain. The row reads ○ ✕ ✕ ✕ ✕ ✕.
In the demoMedRide NEMT ● ● ● ● ○ ○, HouseCall Health Assessments ● ● ○ ○ ○ ○, Nourish Home Meals ● ● ● ● ● ●
Check it yourselfHover a marker: the tooltip names the step.
app/services/vendors.py · chain()Formula
CONFIRMED, DECLINED, FAILED, CANCELLED)
starter contracts: MedRide NEMT 3 · Nourish Home Meals 5 · HouseCall Health Assessments 14 · Regional DME Supply 7 · Bridge Behavioural Network 5Why this wayThe clock starts at the referral, not at the vendor's acknowledgement, so a vendor who is slow to acknowledge gains nothing. It stops only at a settled status, so SCHEDULED and DELIVERED referrals still go red. That includes a booking the plan made itself. John Doe's MedRide ride is booked for two days after the reset, but its 3-day SLA ends on the reset day. From the next day it shows red, and Partner Activity says 'SLA passed … follow up with the vendor'. Vendor SLAs are per contract. They are not the team-referral SLA in Part I (3 days per queue). Referring the member again to the same vendor for the same service returns the live referral, so its SLA does not restart.
In the demothe reset day
Check it yourselfMedRide NEMT was referred 3 days before the reset with a 3-day SLA, so its SLA date is the reset day.
app/services/vendors.py · refer()app/services/vendors.py · is_overdue()Formula
Why this wayRead from the event trail, never from a 'last contacted' field somebody has to maintain. Known inconsistency: the date is the first 10 characters of a UTC timestamp. So an event logged after 8 pm Eastern shows the next day, while every other date on this screen is the Eastern business date.
In the demo1 day before the reset
Check it yourselfThe first row, MedRide NEMT 'Service scheduled', matches the newest event in that referral's trail on the Referrals tab.
app/services/vendors.py · _last_interaction()app/services/vendors.py · member_view()Formula
Why this wayWhat happens next is derived from the record, so it cannot go stale. A passed SLA outranks a booked appointment, because the vendor owes a response. The consequence is described under the SLA date above. The Status column and its colour are in Part II, Patient 360: header, gaps, interventions and authorizations.
In the demoMedRide NEMT: appointment, Nourish Home Meals: 14 meals delivered over two weeks; member confirmed, HouseCall Health Assessments: awaiting: vendor reached the member
Check it yourselfHouseCall Health Assessments reads 'awaiting: vendor reached the member · due …'; Nourish Home Meals shows its recorded outcome.
app/services/vendors.py · _next_step()app/static/app.js · p360Tab()The care manager's view of who is already talking to one member and on what authority: the Coordination line in the member header, the contact lists on the Engagement tab, and the disclosure consent a vendor referral needs on the Referrals tab. Every figure below is shown for the demonstration member John Doe, as the care manager Jane Smith sees him.
Formula
COMPLETED, EXHAUSTED, STOPPED); every programme's ladders are counted together
counted in the browser as the length of the list the server returns; 0 → 'no live outreach'Why this wayOne number across programmes, because each programme could always see its own outreach and none could see the others'. A ladder counts from the moment it is planned, before anything has been sent: in the fresh demo tenant John Doe has three live ladders (all PLANNED) and no contact history yet, so a live ladder means 'somebody intends to reach this member', not 'somebody has'. The ladder rungs and waits are explained in Part I, Engagement ladder, wait times and the contact ceiling.
In the demo3 live outreach ladders
Check it yourselfopen the Engagement tab; the Outreach panel lists the same ladders. A ladder that is completed, exhausted or stopped drops out of the count.
app/services/engagement.py · who_is_engaging()app/static/app.js · coordinationLine()Formula
coordination.decided event in the audit chain for this member (any programme, any age); badge = its decision, hover = its reason, 'with X on D' = what it was combined with
the decision itself is the gate's first matching check, in order: do-not-contact → SUPPRESS; no channel usable → SUPPRESS (permanent) or DELAY (temporary); inside quiet hours → DELAY (ESCALATE if the caller marked it critical); a booked appointment or planned contact about something else within lookahead_days (default 2) → COMBINE; another live ladder about something else → COMBINE; caller marked it urgent or critical → ESCALATE; member at the weekly contact ceiling → DELAY; otherwise PROCEED
no event → 'nothing refused'Why this wayThe header replays the gate's own record rather than recomputing it, so it cannot disagree with what the gate actually did. PROCEED is never written to the audit chain, so the badge only ever shows a decision that stopped, folded or escalated something; 'nothing refused' means no such decision has been recorded, not that the member has never been contacted. The decision is shown however old it is (its date is printed beside it). The contact ceiling it uses (4 contacts in 7 days) is in Part I, Engagement ladder, wait times and the contact ceiling; Part I does not yet describe the gate's order of checks. A campaign's fold into another campaign's task is recorded under the same event, so the badge can show COMBINE with task.
In the demonothing refused
Check it yourselfhover the badge for the reason. Try to send outreach to a member who already has a live ladder: the Outreach coordination window shows the full check chain, and after you choose, the header shows that decision.
app/services/coordination.py · latest()app/services/coordination.py · decide()app/static/app.js · coordinationLine()Formula
overridden → 'proceeded anyway' with the person's recorded reason; combined → 'folded into existing work'; skipped → 'automation skipped this member'; ANY other outcome → 'refused'Why this wayA person may override COMBINE, DELAY or ESCALATE with a reason of at least 3 characters; SUPPRESS (consent) cannot be overridden. Known defect: a campaign that finds another campaign's task owned by someone else creates its own task anyway and records the outcome kept_separate; the browser has no label for that outcome, so the header says 'refused' for work that in fact went ahead.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfnothing to show in the fresh demo tenant: no coordination decision exists after the reset. Override a COMBINE in the Outreach coordination window with a reason; the header then reads 'proceeded anyway' followed by that reason.
app/services/coordination.py · gate()app/services/coordination.py · record_task_combined()app/static/app.js · coordinationLine()Formula
40
the panel is not drawn at all when the count is 0Why this wayOne list across SMS, email, portal and voice, so 'when did we last speak to this person' needs one screen. The count stops at 40 without saying so: a member with 60 contacts shows 40. Known defect: every finished or abandoned voice call is listed twice, once as the call ('Voice') and once as the transcript message the call writes (labelled lower-case 'voice'), so each call adds 2. The Engagement panel lower on the same tab counts the same contacts differently (see the next rows).
In the demo— nothing to show in the fresh demo tenant
Check it yourselfnothing to show in the fresh demo tenant: nothing has been sent yet, so the panel is hidden. Send one outreach from the ladder; the panel appears with 1. Place a simulated call to the end; the count rises by 2.
app/services/engagement.py · history()app/api/engagement.py · history()app/static/app.js · p360Tab()Formula
who == 'member'); the call's outcome is appended when it has one; status is the call's status in lower caseWhy this wayMember turns show whether the member actually engaged or the call rang out. The count is of turns, not minutes or words. The transcript message the same call writes is also listed, separately, as its full text.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfnothing to show in the fresh demo tenant. Run a simulated call from Engagement → Voice and answer twice; the line reads '… 2 member turn(s)'.
app/services/engagement.py · history()app/services/voice.py · _apply_outcome()Formula
15 message records by time, both directions; voice calls themselves are not included, but the transcript message each call writes is
no messages → 'No outreach recorded'Why this wayThe raw message log, with template and status. It is a different count from Contact history on the same tab: capped at 15 rather than 40, and without call records, so the two titles differ for any member with calls or more than 15 messages. Neither says 'of M'. The channel is printed as stored (lower case) and the timestamp without its year.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfnothing to show in the fresh demo tenant (the panel reads 'No outreach recorded'). After one send, both this panel and Contact history show 1; after one finished call, this shows 1 more and Contact history 2 more.
app/api/vbc.py · get_patient()app/static/app.js · p360Tab()Formula
sms · email · phone · portal; a channel is marked '(opted out)' only when the stored opt-in is explicitly falseWhy this wayA quick read of the stored preference. It does not distinguish 'never asked' from 'opted in': both print the bare channel name. The Consent panel at the top of the same tab does distinguish them (NEVER ASKED), so for John Doe the top panel shows phone as never asked while this line shows 'phone' exactly like the channels he agreed to. Outreach itself is enforced on the server, not from this line.
In the demosms · email · phone · portal
Check it yourselfcompare with the Consent panel at the top of the tab: a channel shown NEVER ASKED there is shown without a mark here.
app/static/app.js · p360Tab()app/services/engagement.py · consent_state()Formula
*) authorization, else none
none → never_asked; recorded as declined → refused; expiry date before today → expired (valid through the expiry date itself); expiry not a date → unreadable; otherwise granted
Send referral is enabled only for granted; the server applies the same test again when the referral is sent
a recorded agreement expires 365 days after it was recorded unless another date is givenWhy this waySharing a member's name, address and need with a vendor is disclosure to a third party, a different consent from permission to contact them, so no channel opt-in counts. A category record wins over the blanket one even when it is a refusal or has expired. The window defaults to the first vendor's category (transportation). Known limits: the heading reads 'No disclosure consent on file' for a refusal or an expired authorization as well as for 'never asked' (the reason line underneath says which); the expiry date of a valid authorization is not shown; and an expiry typed in a form is stored without being checked, which is how unreadable arises. Part I's 'Consent disclosure validity 365 days' is this default.
In the demotransportation (never_asked): No disclosure consent on file; Send referral disabled
Check it yourselfopen Create vendor referral for John Doe: the line says no consent on file and Send referral is greyed out. Click 'They agreed'; the line turns to confirmed. Maria Gonzales carries a blanket authorization from the reset and opens confirmed for every need.
app/services/engagement.py · disclosure_state()app/services/engagement.py · record_disclosure()app/api/population.py · disclosure_consent()app/static/app.js · vendorModal()Formula
Why this wayA snapshot of the authorization that let the member's details leave the plan, kept with the referral so a later withdrawal does not rewrite history. Known defect: John Doe's three demonstration vendor referrals are created by the reset without passing the disclosure test and carry the text 'member verbal consent on enrollment call', while his disclosure record is empty for every category; so on the same tab the table says consent was given and the Create vendor referral window says none is on file.
In the demomember verbal consent on enrollment call
Check it yourselfhover 'consent:' on any vendor referral, then open Create vendor referral: for John Doe the two disagree until an authorization is recorded.
app/api/population.py · vendor_refer()app/static/app.js · p360Tab()The recommendation cards on Population (for the VBC manager) and on Patient 360 (for the care manager). Advisory only: nothing happens until a person acts, and every card says why it exists in reasons a care manager can check.
Formula
Why this wayThe score only orders cards within a band and is never shown: a number a care manager cannot interpret is a justification nobody can check. The band and the reasons are what the card shows. See Part I, Next best action.
In the demoJohn Doe — Record HbA1c Control (Critical), John Doe — Complete Diabetic Retinal Exam (Critical), John Doe — Record Blood Pressure Control (Critical), Maria Gonzales — Record HbA1c Control (Critical), Maria Gonzales — Complete Diabetic Retinal Exam (Critical)
app/services/nba.py · recommend()app/services/nba.py · _recommend_for_gap()Formula
Why this wayBands are derived from facts, not cut from a score, so each one comes with the sentence that set it ('critical-priority gap on a high-risk member').
In the demoCritical: critical-priority gap on a high-risk member
app/services/nba.py · _band()app/services/nba.py · _gap_age()Formula
Why this wayEight named inputs, every one checkable on the member's record. The card lists which inputs it used, so a missing input is visible, not silent.
In the demoOpen quality gap — HbA1c Control [Care Gap], Overdue 97 days [Care Gap], Critical priority on the measure package [Care Gap], High-risk member [Risk], Impacts Diabetes: HbA1c Control (<8.0%) — a tracked VBC quality measure with a 75% target [Quality], 1 ED visit in the last 6 months [Utilization]
app/services/nba.py · _reasons()Formula
Why this wayThe next step is the same policy lookup the authorization screens use, so a card can never tell a care manager a service is free of authorization when the policy says otherwise.
In the demoRecord HbA1c Control — No prior authorization is required — this can be scheduled as soon as the member is reached.
app/services/nba.py · _recommend_for_gap()app/services/nba.py · _title()app/services/workflow.py · pa_required()Formula
Why this wayA blocked card still shows (the member still needs the care) but it sinks in the order (stage factor 0.5) and its band falls to Medium, because nobody on the care team can move it until the payer decides.
In the demo0 blocked cards in the top 8
app/services/nba.py · _recommend_for_gap()Formula
Why this wayThe button state asks the same permission system the server enforces, so a button that looks enabled always works, and a disabled one says why.
In the demoas the VBC manager: Start Intervention off (your role is read-only for care work); Launch PA off (your role is read-only for care work); Send to Provider off (your role cannot route work to a provider); Assign off (your role cannot assign w
app/services/nba.py · _actions()Formula
Why this wayWhat is being deferred is an open gap on a real member, so a deferral expires, and a material change in the case brings the card back with the reason.
In the demo0 deferred in the fresh tenant
Check it yourselfDismiss a card for 30 days, then change the member's gap priority: the card comes back with the reason.
app/services/nba.py · dismiss()app/services/nba.py · fingerprint()The care manager's outreach screens: the Engagement page (Voice, SMS, Email, Portal and History tabs), the Outreach ladder on a member's Patient 360 Engagement tab, the coordination window that opens when outreach is held, and the HRA findings line on the Care tab. Everything is shown as the care manager Jane Smith sees it; member-level figures are for John Doe unless a row names another member. Campaigns has its own chapter; the consent table, the Coordination line and Contact history are in Patient 360: coordination; the Care management and HRA status panels are in the Patient 360 care chapter.
Formula
OutreachSequence rows in the tenant, by creation time, of every status (settled ladders included)
then narrowed to the members this login may see; the number is the length of what is leftWhy this wayA sequence is one conversation with one member about one thing, across channels, so this counts conversations, not messages. Two limits. The list stops at 50 without saying '50 of N'. And the 50 are taken before the panel filter, so a panel-scoped login (a provider) can see fewer than 50 rows even when more than 50 of its own members' ladders exist. In the fresh demo the provider sees 5 of the 10.
In the demo10 sequences
Check it yourselfCount the rows in the History table; they match the number in the title.
app/api/engagement.py · sequences()app/static/app.js · engSequences()Formula
can_really_send() is false
can_really_send() is true only when a real messaging provider is configured AND the deployment is not synthetic-onlyWhy this wayBoth conditions are required, so a synthetic-data deployment can never message a real person even if someone configures a provider. The demo is synthetic-only, so the badge always shows. It is one deployment-wide answer: each sequence also carries its own 'any real send' flag, which no screen renders.
In the demoshown on both
Check it yourselfThe amber badge sits beside the History title and beside the ladder title on John Doe's Engagement tab.
app/services/messaging.py · can_really_send()app/api/engagement.py · sequences()app/api/engagement.py · plan()Formula
PLANNED · a send → ATTEMPTED · moved to the next usable channel → ESCALATED · an outcome that means we spoke to the member → REACHED · a real booked appointment → SCHEDULED · REMINDED · COMPLETED (also set when the care gap closes)
STOPPED = the member opted out · EXHAUSTED = no untried channel can ever be used
when nothing is usable now: any untried channel blocked only by quiet hours or the contact ceiling → wait; otherwise → EXHAUSTEDWhy this wayThe rule separates 'not yet' from 'never'. Quiet hours and the contact ceiling are clocks, so a ladder they block waits instead of being written off. Opt-out, no address on file and do-not-contact are walls, and only walls end a ladder. An EXHAUSTED ladder goes back to PLANNED when the task-rule sweep finds a usable channel again. SCHEDULED cannot be set without a real, uncancelled appointment. When the task-rule sweep runs, a stalled ATTEMPTED or ESCALATED ladder whose wait has passed is escalated automatically. Limit: the event written when a ladder waits always says 'quiet hours', even when the contact ceiling is the cause.
In the demoPLANNED 8, REACHED 2
Check it yourselfHistory: count the Status badges; Maria Gonzales and Elena Petrova are REACHED, the other eight PLANNED.
app/services/engagement.py · open_sequence()app/services/engagement.py · reachability()app/services/engagement.py · escalate()app/services/engagement.py · record_outcome()app/api/engagement.py · step()app/services/task_rules.py · _r_engagement_escalate()app/services/task_rules.py · _r_engagement_exhausted()Formula
Why this wayThe ladder starts where the member asked to be reached. Part I (Engagement ladder, wait times and the contact ceiling) disagrees. It prints a fixed order starting at SMS and says 'Voice is the last rung, not the first'. In the code Voice is last only among the channels the member did not choose. Sam Okafor's two ladders start on Email because Email is his stated preference, and a member who prefers phone is called first. A preferred channel that is blocked is skipped, not waited for.
In the demoEmail 2, SMS 7, Voice 1 ladders
Check it yourselfHistory: Sam Okafor's rows read Email; Elena Petrova's reads Voice after SMS was tried.
app/services/engagement.py · channels()app/services/engagement.py · open_sequence()app/services/engagement.py · escalate()Formula
Why this wayOne conversation, several channels: a text on Monday and a call on Wednesday about the same exam are one row, not two. Escalating alone adds nothing to Tried; a channel is added when a send is recorded on it. On this deployment every send is simulated, and the ladder's event says so. A call placed from the Voice tab is not a send on any ladder (see Call status), so it never appears here.
In the demoSMS → Voice · 2 attempt(s)
Check it yourselfHistory: Elena Petrova's row; her Patient 360 ladder's Outreach step reads '2 attempt(s) across SMS, Voice'.
app/services/engagement.py · record_attempt()app/services/engagement.py · _steps()app/static/app.js · engSequences()Formula
Why this wayWaits are Part I's (Engagement ladder, wait times and the contact ceiling). Whether the demanded act has happened is read from the record that would prove it, as in the 'Member said' row. Limit: a PLANNED ladder shows 'retry' plus the day it was opened, although nothing has been sent; there 'retry' means 'first send due'. In the fresh demo all eight PLANNED ladders read 'retry' with the reset day. A wrong number clears the date on purpose, so the escalation rule cannot redial a bad number.
In the demoMaria Gonzales: refer to the contracted transportation vendor; Elena Petrova: book an appointment from an open slot; 8 ladder(s) show a retry date
Check it yourselfHistory: Maria Gonzales and Elena Petrova show amber badges; open their Patient 360 ladders and the 'Member said' line names the same act.
app/api/engagement.py · sequences()app/services/engagement.py · next_trigger()app/services/engagement.py · record_attempt()app/services/engagement.py · record_outcome()Formula
MessageTemplate row in the tenant whose channel is this tab's: every version, locale and status, not only approved ones
the picker lists the same rows as 'key vN — purpose'Why this wayShowing the library per channel makes 'is there an approved text for this' answerable before a send. Three limits. The note 'No approved … template exists' appears only when the list is empty, so a draft would hide the note and be offered in the picker. The picker does not show locale: the demo SMS list has two lines reading 'T-OUTREACH v1', one en-US and one es-US. And the server ignores the version and locale picked. It sends the highest approved version of that key in the member's own locale, falling back to en-US.
In the demosms 4, email 1, portal 0 templates
Check it yourselfOpen each tab: the panel titles read 4, 1 and 0, and the Portal tab says no approved Portal template exists.
app/api/engagement.py · templates()app/static/app.js · engChannel()app/services/messaging.py · resolve_template()Formula
sms
the tab the Send button is on is not sent to the server
text = the approved template for that channel with {first_name} filled in; nothing else is filled in, because the screen sends no other valuesWhy this wayKnown defect, stated plainly: the channel tabs do not choose the channel. A send from the Email tab for John Doe, who prefers SMS, is recorded as an SMS, and the toast says 'Recorded on sms'. A template with no approved version for the member's channel is refused. The screen also sends no values, so the demo SMS is stored with the literal text '{org}' and '{service}' in it. Consent, quiet hours and the coordination gate still apply as for any other contact.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfEngagement → Email → pick John Doe → Send, and choose Proceed separately with a reason in the coordination window. The toast names sms. The message then appears in Patient 360 → Engagement with '{org}' unreplaced.
app/services/messaging.py · send_outreach()app/services/messaging.py · render()app/api/engagement.py · send()app/static/app.js · engChannel()Formula
VoiceCall rows in the tenant, by start time
then narrowed to the members this login may see; the number is the length of what is leftWhy this wayA short recent list, not a call log: it stops at 20 without saying so. As on History, the 20 are taken before the panel filter, so a provider can see fewer than 20 of their own members' calls when the tenant has more. The fresh demo tenant has no calls; each call placed during the demo adds one.
In the demo0 calls
Check it yourselfPlace a call and finish it: the title goes up by one and the call is the top row.
app/api/voice.py · calls()app/static/app.js · rVoice()Formula
IN_PROGRESS when the call starts
when a reply reaches an ending: booked, callback or declined → COMPLETED; escalated → ESCALATED; opted_out → OPTED_OUT; voicemail → VOICEMAIL; no_answer → NO_ANSWER
'Member hangs up' while the call is live → ABANDONEDWhy this wayStatus says how the call ended; Outcome says what it achieved, which is why three different results share COMPLETED. The live badge and the table badge are the same stored field. The code also treats RINGING as a live state, but nothing ever sets it. Every ending, abandoned included, writes the transcript to the member's contact history. A call is a separate record from the member's outreach ladder: booking, declining or opting out on a call does not move the ladder, and the ladder's Outreach step still reads 'not attempted'.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfStart a call for John Doe, answer 'Yes, please' then 'Mornings': the badge turns COMPLETED and the same status appears in the table.
app/services/voice.py · start()app/services/voice.py · respond()app/services/voice.py · hang_up()app/api/voice.py · calls()Formula
Why this wayThe outcome is what the workflow acts on. An opt-out sets the member's phone opt-in to 'no', so Voice then reads 'opted out' wherever consent is shown. 'booked' moves the linked intervention from OUTREACH to ENGAGED only when the call was started from an intervention. The Voice tab starts calls without one, so a booking made here books nothing and changes no intervention; the words 'care team to confirm' mean exactly that.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfEnd a call with 'Stop calling me': the outcome reads 'Member opted out of calls', and John Doe's Voice channel then shows opted out on his Engagement tab.
app/services/voice.py · respond()app/services/voice.py · _apply_outcome()app/services/voice.py · hang_up()app/static/app.js · rVoice()Formula
Why this wayIt counts spoken lines, not question-and-answer exchanges. A call answered twice ('Yes, please', 'Mornings') shows 5. Patient 360's Contact history describes the same call as '2 member turn(s)': it counts member lines only, so the two screens give different numbers for one call. The scripts list also returns a field named turns that means the number of script steps (9 and 7). It is not shown anywhere.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfOpen the call's Transcript: count the Agent and Member bubbles; the total equals Turns.
app/api/voice.py · calls()app/services/voice.py · respond()app/services/engagement.py · history()Formula
IN_PROGRESS nor RINGING → show 'Outcome: …' and Close
otherwise the buttons = the replies of the script step the call is at, in script order, plus 'Member hangs up'Why this wayThe member's side is picked from a fixed list, because a simulated call must not imply speech recognition. The server enforces the same rule the screen draws: a reply that is not on the current step's list is refused, and so is any reply after the call has ended ('call already COMPLETED'). Example: the Care gap outreach script opens with five replies: 'Yes, please', 'Not right now', 'Who is this? I want a person', 'Stop calling me', '(no answer)'.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfStart a Care gap outreach call: five reply buttons appear; answer until the call ends and they are replaced by the outcome and Close.
app/services/voice.py · options()app/services/voice.py · respond()app/static/app.js · rVoice()Formula
{first_name} = the member's name up to the first space · {org} = the tenant's name, or 'your care team' if it has none · {service} = the Service typed at Start call, or 'a check-up'Why this wayThe words come from a versioned script a person approved (v1 of each); the system only fills in names. Only the Care gap outreach greeting uses {service}. Replies are rendered without the typed service, which changes nothing today because no later step uses it. The first-name rule is simple: 'Mary Ann Smith' is greeted as 'Mary'.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfStart a Care gap outreach call for John Doe with Service 'a diabetic eye exam': the greeting reads 'Hello John, this is an automated call from Demo Health ACO … due for a diabetic eye exam'.
app/services/voice.py · _values()app/services/voice.py · _render()app/api/voice.py · start()Formula
Why this wayThe window is the gate's refusal, shown with its working, so a person decides and the decision is recorded. The Coordination line in the member header shows the last one. Every door on these screens sends urgency 'routine', so ESCALATE cannot come from them. The Voice and channel tabs also send no purpose, so any live ladder for the member counts as 'something else'. In the fresh demo, Start call for John Doe opens with COMBINE because three of his ladders are planned for today. When the thing to combine with is a ladder, it is always labelled 'Care Management', whichever programme opened it.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfEngagement → Voice → John Doe → Start call: the window shows COMBINE with 'Future contact scheduled' marked. Choose Proceed separately with a reason and the call starts.
app/services/coordination.py · decide()app/services/coordination.py · gate()app/static/app.js · coordModal()Formula
COMPLETED, EXHAUSTED or STOPPED
none → NONE RUNNING, and no progress barWhy this wayThe panel shows one conversation, the newest one still live. A member with several live ladders shows only one here, and History lists them all. A finished ladder is never shown, so a ladder that just COMPLETED makes the panel read NONE RUNNING, not a full bar.
In the demoPLANNED, one of 3 live ladders
Check it yourselfEngagement → History: John Doe has three rows; his Patient 360 ladder shows one of them.
app/api/engagement.py · plan()app/static/app.js · engagementLadder()Formula
Why this wayKnown limit: a member reached on the first channel has Escalation 'not needed', which still counts in the 7. Only live ladders are shown, and a completed ladder leaves the panel. So a first-channel success tops out at REMINDED: 5 of 7 (71%, amber). A ladder that needed escalation reaches 6 of 7 (86%, green) at the same point, so the member who answered the first text looks less complete. The Transitions plan bar drops 'not needed' steps from its total; this bar does not.
In the demo1 of 7 steps complete, bar 14% (red)
Check it yourselfCount the ticked steps in the chain under the bar.
app/services/engagement.py · plan()app/static/app.js · engagementLadder()Formula
Why this wayThe step after Escalation is named after what the member's answer demands, for example 'Vendor referral', and not always 'Scheduling'. Its done flag is read from the record that proves it. Limit: a PLANNED ladder shows Response as open but with the detail 'waiting until <opening day>', although nothing has been sent (John Doe's reads so on the reset day).
In the demoPreferred channel done, Outreach done, Response done, Escalation not_needed, Vendor referral open, Reminder open, Completion open
Check it yourselfMaria Gonzales, Engagement tab: Escalation shows a dash ('the member answered on the first channel') and Vendor referral is still open.
app/services/engagement.py · _steps()app/static/app.js · engagementLadder()Formula
Why this wayOne rule set for every channel, voice included; see Part I, Engagement ladder, wait times and the contact ceiling. This list asks as automation does, so the ceiling shows as a hold. Part I and the code disagree on the count. The ceiling counts outbound messages PLUS every simulated call, and each finished call also writes an outbound voice message. So one call counts twice. Tested on a fresh tenant, two calls the member hung up on put John Doe at '4 times in 7 days by other programmes', and every channel was held for a week. The coordination service's own 'contacts in the last 7 days' counts the same week as 2; no screen shows that number. The text says 'other programmes' but counts the care manager's own contacts too.
In the demoSMS available, Email available, Portal available, Voice available
Check it yourselfSam Okafor's list reads 'no mobile on file' for SMS; Derrick Boateng's reads 'asked not to be contacted at all' on every channel.
app/services/engagement.py · contactability()app/services/engagement.py · _recent_contacts()app/services/engagement.py · channels()app/services/voice.py · _apply_outcome()Formula
Why this wayThe ladder's own status never vouches for itself: 'appointment booked' is printed only when an appointment row exists. Limit: the benefits check, prior auth and clinical referral tests accept any such record the member has ever had. An eligibility check or authorization from last year marks today's 'Cost concern' or 'PA required' as done; only scheduling, vendor referral and evidence are tied to this ladder.
In the demoTransportation barrier: TRIGGERS VENDOR REFERRAL
Check it yourselfMaria Gonzales: the amber badge and a button to refer her to the transportation vendor; after the referral is sent the badge turns green.
app/services/engagement.py · next_trigger()app/static/app.js · engTriggerBanner()Formula
Why this wayUnlike most values in this paper, the line is a snapshot written once at completion and never recomputed. A referral later closed or refused does not change it. A typed outcome always wins: refused and unreachable HRAs must carry a reason, and that reason is what shows here. Linda Tran's refused HRA shows 'member declined the HRA'. 'D of M' can be below M on purpose: a transport referral needs disclosure consent, and without it the finding is recorded but not actioned.
In the demoREFUSED: member declined the HRA
Check it yourselfComplete John Doe's HRA with two Yes answers: the table's last column shows the one-line summary, and the assessment's event trail carries the same line.
app/services/hra.py · summary()app/services/hra.py · _is_positive()app/api/population.py · assessment_step()app/static/app.js · hraPanel()Formula
Why this wayThe window shows what the answers set off, not only that they were saved: each positive answer opens a referral, a vendor request or a task through that module's own service. A failed action is shown with its reason and the finding stays on the record, so the social-needs rules keep chasing it. An HRA cannot be completed with no answers.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfAnswer Yes to transportation and food and complete: the window lists what started and anything that could not start (for example, a transport referral with no disclosure consent).
app/static/app.js · hraSubmit()app/services/hra.py · extract()app/services/hra.py · generate()The care manager's list of recent hospital discharges, each with its follow-up clocks (contact within 48 hours, a visit within 7 days, readmission watch for 30 days) and a transition plan whose every step is read from the work beneath it.
Formula
Why this way120 days is how long a discharge stays actionable (Part I, Transition-of-care windows). Only inpatient stays count, and the Command Center's 'Discharges (30d)' card counts this same list's last 30 days. For a provider login the list and the cards above it both count the provider's panel only.
In the demo1 discharges
app/services/transitions.py · recent_discharges()app/services/transitions.py · summary()Formula
Why this wayBoth clocks run from the DISCHARGE date, not from when the record reached the platform, so a late feed cannot buy time. A missed window is shown as missed, not as late success: a 48-hour call made on day three is a missed measure.
In the democontact open 1, visit open 1, missed 0
app/services/transitions.py · recent_discharges()Formula
Why this wayCalendar-day deadlines a person can act on. Known inconsistency: these two columns and the KPI cards use fixed 48 h / 7 d, while each plan step's deadline is read from the tenant's own task-rule settings; a tenant that changes its rules changes the plan but not these columns.
In the demodischarged 2 days ago: contact by +2 d, visit by +7 d
app/services/transitions.py · recent_discharges()Formula
Why this wayA per-discharge flag and a count over the 120-day list; it can still rise for a discharge whose 30 days have not passed. This is a different figure from Finance's 30-day readmission RATE, which judges only discharges whose window has fully elapsed.
In the demo0 readmitted
app/services/transitions.py · recent_discharges()Formula
Why this wayThe card that says whether anything has already fallen through, as opposed to what is still due.
In the demo0 plans
app/static/app.js · rTransitions()Formula
Why this wayProgress leaves out the steps nobody can act on (the 30-day watch, the close, a step not needed). A dismissed step counts as settled because someone recorded a decision on it. In the demo: discharge, contact, medication reconciliation and barriers are done, 4 of 7.
In the demo4 of 7 actions completed
app/services/transitions.py · plan()app/static/app.js · transitionPlan()Formula
Why this wayNo step is ticked by hand: each is read from the task, authorization or appointment it depends on, so the plan cannot claim more than has happened.
In the demoDischarge done, Contact done, Medication reconciliation done, Clinical assessment open, Follow-up appointment open, Barriers / transport done, Eligibility / PA not_needed, Visit completion open, Readmission monitoring watching, Transition closed open
app/services/transitions.py · plan()app/services/transitions.py · _step_deadline()Formula
Why this wayTwo different failures: overdue can still be done, missed cannot.
In the demomissed 0, overdue 0
app/services/transitions.py · plan()Formula
Why this wayA transition is not closed at the follow-up visit; it is closed when the member has stayed out of hospital for 30 days, which is what the plan is for.
In the demo28 days left in the window
app/services/transitions.py · plan()The VBC manager's population view: every measure's denominator and numerator, saved cohorts, attribution (who the contract holds you responsible for), where cost and opportunity concentrate, and how each provider group performs.
Formula
Why this wayEligibility is read from the clinical record at request time, never from a stored flag, so a new diagnosis puts a member into the denominator on the next read. The rates are evaluated over every member in the tenant, not only the attributed population. See Part I, One member, one measure.
In the demoDiabetes: HbA1c Control (<8.0%) 6, Diabetes: Eye Exam Performed 6, Statin Adherence (PDC >= 80%) 8, Controlling High Blood Pressure (<140 systolic) 10, Annual Wellness Visit 9
app/services/quality.py · evaluate_tenant()app/services/quality.py · in_denominator()Formula
Why this wayThree kinds of evidence, one rule each, all read from the record. Known defect being fixed: a lab result EXACTLY at the threshold (HbA1c 8.0, systolic 140) currently counts as controlled, although the measure titles say '<8.0%' and '<140'.
In the demoDiabetes: HbA1c Control (<8.0%) 2, Diabetes: Eye Exam Performed 0, Statin Adherence (PDC >= 80%) 2, Controlling High Blood Pressure (<140 systolic) 4, Annual Wellness Visit 2
app/services/quality.py · meets_numerator()Formula
Why this wayExcluded members leave the denominator entirely rather than counting as failures, as measure specifications require.
In the demo0 excluded across all measures
app/services/quality.py · excluded()Formula
Why this wayThe same rate as the Quality screen, from the same function, coloured by the same rule against the same target (the measure package's), so a rate is one colour everywhere it appears.
In the demoDiabetes: HbA1c Control (<8.0%): 4 open, 33.3%, Diabetes: Eye Exam Performed: 6 open, 0.0%, Statin Adherence (PDC >= 80%): 6 open, 25.0%, Controlling High Blood Pressure (<140 systolic): 6 open, 40.0%, Annual Wellness Visit: 7 open, 22.2%
app/services/quality.py · evaluate_tenant()app/static/app.js · rPopulation()Formula
Why this wayA cohort stores its definition, not its members, so its size is re-evaluated on every read and a member enters or leaves as their record changes.
In the demoRising and high risk 6, Diabetes population 6, Diabetes with open gaps 6, Uncontrolled hypertension 6
app/services/population.py · cohort_members()Formula
Why this wayAttribution decides accountability, so each member's method and rationale are shown beside the count. Known inconsistency: this count includes rows that have ended, while the Attribution summary's 'Total attributed' excludes them (they agree today because nothing ends an attribution yet).
In the demo12 members
app/services/population.py · current_period()Formula
Why this wayRemoved is a MEASURED zero, stated as such: no de-attribution path writes an end date yet. Known limit: every attribution is stamped with the period start date, so 'Added this period' currently always equals 'Total'.
In the demototal 12, added 12, removed 0; Dr. P. Osei 5, Dr. Robert Jones 3, Dr. Sarah Smith 2, Dr. Karen White 2
app/services/vbc_manager.py · attribution_summary()Formula
Why this wayThe members nobody is accountable for are the ones most likely to be missed, so they are listed by name with the reason.
In the demoJon Doe (PCP on record but not attributed)
app/services/vbc_manager.py · attribution_summary()Formula
Why this waySpend alone ranks members nobody can help; open gaps alone ignore cost. Multiplying them puts first the members where money is being spent AND something can still be done. A member with no unworked gaps still ranks, on cost alone.
In the demoJohn Doe: $17135.0, Professional / office, 5 unworked, score 154.2, Maria Gonzales: $17135.0, Professional / office, 5 unworked, score 154.2, Sam Okafor: $25550.0, Inpatient, 1 unworked, score 58.8, Linda Tran: $9385.0, Professional / office, 4 unworked, score 58.2
Check it yourselfJohn Doe: 17,135 ÷ 1000 × (1 + 5 × 1.6) = 154.2.
app/services/vbc_manager.py · concentration()Formula
Why this wayBuilt from the same three inputs as the ranking, so the sentence is the ranking's own reason.
In the demo$17,135 spend, 5 gap(s) with no intervention running, high risk
app/services/vbc_manager.py · _concentration_why()Formula
Why this wayThe same PMPM arithmetic as the contract, narrowed to one group's members, so group PMPMs are comparable with the contract's. Closed gaps are counted all-time, so a new period does not reset closure credit.
In the demoDr. P. Osei: 5 attributed, 3 high/rising, 16 open, 0.0% closed, $1091.21 PMPM, Dr. Robert Jones: 3 attributed, 2 high/rising, 6 open, 0.0% closed, $1555.56 PMPM, Dr. Sarah Smith: 2 attributed, 1 high/rising, 5 open, 0.0% closed, $2948.92 PMPM, Dr. Karen White: 2 attributed, 0 high/rising, 1 open, 0.0% closed, $1315.64 PMPM
app/services/vbc_manager.py · provider_performance()The VBC manager's quality screen: every measure's rate against its target, how many composite points each open gap is worth, and a what-if model of closing more gaps before committing a team to the work.
Formula
Why this wayEvery active measure is listed, including one with no eligible members yet, so nothing disappears from the table because it is empty.
In the demo5 measures
app/services/vbc_manager.py · quality_opportunity()Formula
Why this wayThe rate is recomputed from the members every time the screen is read, never stored, so it cannot go stale. See Part I, A measure across a population. The 15-point amber band is a display convention only; it changes no number.
In the demoDiabetes: Eye Exam Performed 0.0% (0 of 6), Annual Wellness Visit 22.2% (2 of 9), Statin Adherence (PDC >= 80%) 25.0% (2 of 8), Diabetes: HbA1c Control (<8.0%) 33.3% (2 of 6), Controlling High Blood Pressure (<140 systolic) 40.0% (4 of 10)
Check it yourselfClick 'Members' on a row: the drill lists the D members and marks the N who meet it.
app/services/quality.py · evaluate_tenant()app/static/app.js · rateBarHtml()Formula
Why this wayTargets come from the versioned measure package, not from this report. A measure with no target still shows its rate and gaps, but no shortfall: comparing a rate with a target nobody agreed would manufacture one.
In the demoDiabetes: Eye Exam Performed 70.0%, Annual Wellness Visit 60.0%, Statin Adherence (PDC >= 80%) 80.0%, Diabetes: HbA1c Control (<8.0%) 75.0%, Controlling High Blood Pressure (<140 systolic) 75.0%
app/services/vbc_manager.py · quality_opportunity()Formula
Why this wayPoints here are percentage points of THAT measure's rate, not composite points; the next column converts to composite points.
In the demoDiabetes: Eye Exam Performed 70.0 pts short, Annual Wellness Visit 37.8 pts short, Statin Adherence (PDC >= 80%) 55.0 pts short, Diabetes: HbA1c Control (<8.0%) 41.7 pts short, Controlling High Blood Pressure (<140 systolic) 35.0 pts short
app/services/vbc_manager.py · quality_opportunity()Formula
Why this wayThe smallest whole number of additional members who must meet the measure for the rate to reach the target. Rounded UP, because a fraction of a member cannot close a gap.
In the demoDiabetes: Eye Exam Performed 5, Annual Wellness Visit 4, Statin Adherence (PDC >= 80%) 5, Diabetes: HbA1c Control (<8.0%) 3, Controlling High Blood Pressure (<140 systolic) 4
Check it yourselfEye exam: D = 6 and target 70%: ⌈6 × 0.70⌉ = 5 members; N = 0, so 5.
app/services/vbc_manager.py · quality_opportunity()Formula
Why this wayCounted by the measure engine from members, not from stored gap records, so it is what the rate implies. The drill behind 'Members' lists the same members, and a guard fails if the two ever disagree.
In the demoDiabetes: Eye Exam Performed 6, Annual Wellness Visit 7, Statin Adherence (PDC >= 80%) 6, Diabetes: HbA1c Control (<8.0%) 4, Controlling High Blood Pressure (<140 systolic) 6
app/services/quality.py · evaluate_tenant()Formula
Why this wayTwo facts in sequence: closing one gap moves that measure's own rate by 100 ÷ D points, and the composite is the plain average of n measures, so it moves by that ÷ n. Small denominators move the composite fastest per gap, which is a property of the contract's scoring method, not a statement about which members matter most. See Part I, Quality opportunity and points per gap.
In the demoDiabetes: Eye Exam Performed 3.33, Annual Wellness Visit 2.22, Statin Adherence (PDC >= 80%) 2.5, Diabetes: HbA1c Control (<8.0%) 3.33, Controlling High Blood Pressure (<140 systolic) 2.0
Check it yourselfEye exam: 100 ÷ 6 ÷ 5 = 3.33.
app/services/vbc_manager.py · quality_opportunity()Formula
Why this wayThe composite points the score would gain if every open gap in that measure closed. Rounded once at the end, so it equals what the scenario engine answers for closing the same gaps (a guard compares the two).
In the demoDiabetes: Eye Exam Performed 20.0, Annual Wellness Visit 15.56, Statin Adherence (PDC >= 80%) 15.0, Diabetes: HbA1c Control (<8.0%) 13.33, Controlling High Blood Pressure (<140 systolic) 12.0
Check it yourselfEye exam: 100 ÷ 6 ÷ 5 × 6 = 20.0 (not 3.33 × 6 = 19.98).
app/services/vbc_manager.py · quality_opportunity()Formula
Why this wayStated thresholds rather than a feeling: a band is a reading aid over the points-available number, and says nothing the number does not.
In the demoDiabetes: Eye Exam Performed High, Annual Wellness Visit High, Statin Adherence (PDC >= 80%) High, Diabetes: HbA1c Control (<8.0%) High, Controlling High Blood Pressure (<140 systolic) High
app/services/vbc_manager.py · _opportunity_band()Formula
Why this wayThe single number the contract settles on: an unweighted mean of the rated measures, computed in one place (quality.composite) and read by every screen that shows it. A measure with no eligible members has no rate and is left out of the mean rather than counted as zero. See Part I, The quality composite.
In the demo24.1 %
app/services/quality.py · composite()app/services/vbc_manager.py · scenario()Formula
Why this wayThe contract engine's own arithmetic with the numerators moved; nothing is stored and nothing is predicted. Denominators do not move and closures are capped at the gaps actually open. The demo value models closing every open gap in the top-opportunity measure.
In the democlose all 6 Diabetes: Eye Exam Performed gaps: 24.1% → 44.1%
Check it yourselfEnter the same closures in the panel and press Model this.
app/services/vbc_manager.py · scenario()Formula
Why this wayIt is the difference of the two cards above it, so it always matches them, even where it differs by 0.1 from (points per gap × closures) because each side was rounded first.
In the democlose one Diabetes: Eye Exam Performed gap: +3.3 points
app/static/app.js · scenarioResult()Formula
Why this wayThe gate is read from the contract, never set on this screen. Clearing it is what turns earned savings into a payment; see Part I, Contract performance and settlement.
In the demogate 60.0%; the gate plan (12 closures) gives 62.4%, clears: yes
app/services/vbc_manager.py · scenario()app/services/finance.py · contract_performance()Formula
Why this wayIt models quality only: the savings already generated are held constant and the question is whether the gate now releases them. It is an estimate; the payer reconciles against run-out claims months later.
In the demowith the gate plan: $0.0 → $9770.69 (change $9770.69)
app/services/vbc_manager.py · scenario()app/services/vbc_manager.py · _rate()Formula
Why this wayYou cannot close more gaps than are open, so a larger request is capped and says so rather than producing a rate above 100%.
In the demoDiabetes: Eye Exam Performed: 6 modelled (capped), 0.0% → 100.0%
app/services/vbc_manager.py · scenario()Formula
Why this wayGreedy is optimal here, not a heuristic: every gap in a measure is worth the same number of composite points, so the highest-yield gaps first is the fewest closures that clear the gate. See Part I, Path to the quality gate.
In the demoDiabetes: Eye Exam Performed 6, Diabetes: HbA1c Control (<8.0%) 4, Statin Adherence (PDC >= 80%) 2
app/services/vbc_manager.py · gate_path()The VBC manager's (and executive's) view of the active value-based contract: is it earning, what is binding it, the path to the quality gate, how each measure is trending, and today's priorities.
Formula
Why this wayA shared-savings contract pays on the members attributed to it, so cost and savings are computed over this population. The Command Center's 'Members' card counts everyone on file, so the two numbers differ by design.
In the demo12 members
app/services/vbc_manager.py · contract_health()app/services/population.py · attributed_patients()Formula
Why this wayA leader's first question is 'which of the two gates is stopping us'. The sentence answers it from the same numbers as the cards below it, so it can never contradict them.
In the demoCost performance is favourable — $20,570 of savings generated — but none of it is earned, because quality is 24.1% against a 60.0% gate. Quality is the binding constraint, not cost.
app/services/vbc_manager.py · _headline()Formula
Why this wayAllowed dollars, not paid, because the contract benchmark is set on allowed cost. Member-months counts partial months, so a member attributed mid-period costs only their share of the denominator. See Part I, Contract performance and settlement.
In the demo$1,554.32 against a $1,750.00 benchmark — under by $195.68
Check it yourselfFinance → Cost: the same PMPM and member-months are shown with the claims behind them.
app/services/finance.py · cost_summary()app/services/finance.py · contract_performance()Formula
Why this waySavings the population generated against the benchmark, before the contract decides how much of it is earned. The per-member variance is rounded to cents before it is multiplied, exactly as it is shown, so anyone can reproduce it from the card: 195.68 × 105.12.
In the demo$20569.88 (Variance against benchmark across 105.12 member-months)
app/services/finance.py · contract_performance()Formula
Why this wayOne definition read by every screen (quality.composite). Known limit, stated rather than hidden: the measure rates are evaluated over every member in the tenant, while the cost cards on this screen use the attributed members. See Part I, The quality composite.
In the demo24.1% against a 60.0% minimum to earn any savings
app/services/quality.py · composite()app/services/finance.py · contract_performance()Formula
Why this wayThe gate is binary: below it, savings generated earn nothing. That is why the demo shows about $20,570 generated and $0 settled. It is an estimate; the payer reconciles against run-out claims after the period closes.
In the demo$0.0 — Savings generated but the quality gate is not met (24.1% against a 60.0% minimum), so none of it is earned.
app/services/finance.py · contract_performance()Formula
OPEN or REOPENED (no work has moved them on)Why this wayCounted over the contract's attributed members, so it can be lower than the Command Center's tenant-wide 'Open care gaps' (28 against 29 in the demo). 'No intervention started' is read from the gap's own state: a gap an intervention has touched has moved to in progress, scheduled or awaiting authorization.
In the demo28 open; 27 of 28 have no intervention started
app/services/vbc_manager.py · contract_health()Formula
HIGH or RISINGWhy this wayThe members most likely to drive next quarter's cost. Always 'monitor': a count of risk is not by itself good or bad. Tier bands are in Part I, Clinical risk score.
In the demo2 high, 4 rising, of 12 attributed
app/services/vbc_manager.py · contract_health()Formula
Why this wayEach chip is a stated test on the card's own value, not a judgement typed by a person.
In the demoActual PMPM favorable, Gross savings positive, Quality score at_risk, Estimated settlement at_risk, Open care gaps attention, High / rising risk members monitor
app/services/vbc_manager.py · contract_health()Formula
Why this wayThe distance to the only threshold that decides whether savings are paid. See Part I, Path to the quality gate.
In the democurrent 24.1%, required 60.0%, shortfall 35.9 pts
app/services/vbc_manager.py · gate_path()Formula
Why this wayGreedy is the fewest closures here because every gap in a measure is worth the same number of points. The arithmetic uses the exact per-gap value and rounds once at the end, so closing all six eye-exam gaps is worth +20.0 here and 20.0 on the Quality screen: one quantity, one number (a guard compares the two).
In the demoDiabetes: Eye Exam Performed: close 6 of 6 → 100.0%, +20.0, Diabetes: HbA1c Control (<8.0%): close 4 of 4 → 100.0%, +13.33, Statin Adherence (PDC >= 80%): close 2 of 6 → 50.0%, +5.0
app/services/vbc_manager.py · gate_path()Formula
Why this wayWhat the arithmetic gives if exactly those gaps close and nothing else moves: a projection, not a forecast. 'Model this' on the Quality screen, run with the same plan, gives the same answer to within 0.1 point (the scenario engine re-computes each rate instead of adding points).
In the demo12 gaps → 62.4% against a 60.0% gate
app/services/vbc_manager.py · gate_path()Formula
Why this wayA trend is only as honest as its points, so today's is captured from the live engines rather than typed. The early points in the demo are a seeded synthetic backfill and the screen says so.
In the demoAttributed members 12.0 → 12.0, PMPM (allowed) 1638.32 → 1554.32, Open care gaps 36.0 → 28.0, Annual Wellness Visit 9.6 → 22.2, Controlling High Blood Pressure (<140 systolic) 27.4 → 40.0, Diabetes: HbA1c Control (<8.0%) 20.7 → 33.3
app/services/trends.py · capture()app/services/trends.py · catalogue()Formula
Why this wayDirection is judged against each metric's own sense of good: open gaps falling is improvement. Colouring every rise green would teach people to stop reading the column.
In the demoAttributed members flat, PMPM (allowed) improving, Open care gaps improving, Annual Wellness Visit improving, Controlling High Blood Pressure (<140 systolic) improving, Diabetes: HbA1c Control (<8.0%) improving, Diabetes: Eye Exam Performed flat, Statin Adherence (PDC >= 80%) improving, Quality composite improving, High or rising risk members improving
app/services/trends.py · catalogue()Formula
Why this wayShown so a reader can tell a trend from a single reading: a metric with one point has no trend, and the projection engine refuses to project it (Part I, Trends and projection).
In the demoAttributed members 1 over 0 d, PMPM (allowed) 7 over 42 d, Open care gaps 7 over 42 d, Annual Wellness Visit 7 over 42 d, Controlling High Blood Pressure (<140 systolic) 7 over 42 d, Diabetes: HbA1c Control (<8.0%) 7 over 42 d, Diabetes: Eye Exam Performed 7 over 42 d, Statin Adherence (PDC >= 80%) 7 over 42 d, Quality composite 7 over 42 d, High or rising risk members 7 over 42 d
app/services/trends.py · catalogue()Formula
Why this waySeverity is a fixed, published scale rather than a hidden score: the gate outranks everything because below it no savings are paid at all. Each row's 'why' quotes the numbers that raised it.
In the demoQuality gate is not met (100), Inpatient over benchmark (80), Pharmacy over benchmark (80), Diabetes: Eye Exam Performed below target (80.0), Annual Wellness Visit below target (75.56)
app/services/vbc_manager.py · priorities()app/services/vbc_manager.py · _stalled_campaigns()The VBC manager's and executive's money view: cost per member per month and what drives it, utilisation, the contract's settlement arithmetic, the outcomes the contract is judged on, and observed clinical change.
Formula
Why this wayCost is only meaningful over the population a contract holds you responsible for, so every cost figure on this screen divides by this population's member-months.
In the demo12 members
app/services/finance.py · cost_summary()app/services/population.py · attributed_patients()Formula
Why this wayIt counts months ELAPSED to date, so a cost-to-date is divided by the months it was incurred over, not by the year. A part month counts as its share (30.44 = the average days in a month). Known inconsistency: this period total does not stop a member at an attribution end date, while the monthly PMPM chart below does.
In the demo105.12 member-months
app/services/finance.py · member_months()app/services/finance.py · months_between()Formula
allowed, paid and member_liability over claims of attributed members with a service date between the period start and min(period end, today)Why this wayAllowed = what the plan recognises for the service (paid + member liability). Cost performance is judged on allowed, because that is what the benchmark is set on; paid alone would reward shifting cost to the member.
In the demoallowed $163390.0 = paid $129649.6 + member liability $33740.4
app/services/finance.py · cost_summary()Formula
Why this wayThe single cost figure the contract is scored on, computed in one place and read by Finance, Contract Health and the trend. See Part I, Contract performance and settlement.
In the demo$1554.32 = 163390.0 ÷ 105.12
app/services/finance.py · cost_summary()Formula
Why this wayPer 1,000 members per year is the unit payer benchmarks are published in, so the figure can be compared with a benchmark without conversion. The same two figures appear in the Utilisation panel, computed by a second function with the same rule.
In the demoED visits: 3 → 342.5 per 1,000/yr, Inpatient admissions: 4 → 456.6 per 1,000/yr
app/services/finance.py · cost_summary()Formula
Why this wayThe number actual cost is measured against. It is a negotiated term, so it is read from the contract, never derived.
In the demo1750 $ PMPM
app/services/finance.py · contract_performance()Formula
Why this waySign convention chosen so a positive variance is money saved. Known limit: every active contract card shows the tenant's current-period PMPM; the contract's own period is printed but does not narrow the cost.
In the demo1750.0 − 1554.32 = 195.68
app/services/finance.py · contract_performance()Formula
Why this wayThe variance is the displayed, cent-rounded figure, so the product can be checked on a calculator from the card itself.
In the demo195.68 × 105.12 = $20569.88
app/services/finance.py · contract_performance()Formula
Why this wayRead from the one composite function every screen uses; the minimum is the contract's term.
In the demo24.1% against 60.0% → NOT met
app/services/finance.py · contract_performance()app/services/quality.py · composite()Formula
Why this wayThe gate is binary: savings below it are generated but not earned. Labelled an estimate, because the payer reconciles against run-out claims after the period.
In the demo$0.0 — Savings generated but the quality gate is not met (24.1% against a 60.0% minimum), so none of it is earned.
app/services/finance.py · contract_performance()Formula
Why this wayEvery category divides by the same member-months, so the category PMPMs add up to the total PMPM: a driver is a slice of the one number, not a separate average.
In the demoProfessional / office: 60 claims, $556.74 PMPM, 35.8%, Inpatient: 4 claims, $540.33 PMPM, 34.8%, Pharmacy: 48 claims, $395.89 PMPM, 25.5%, Emergency department: 3 claims, $61.36 PMPM, 3.9%, Outpatient: 0 claims, $0.0 PMPM, 0.0%
Check it yourselfThe category PMPMs add up to the total PMPM on the Cost cards (to the cent, allowing for rounding).
app/services/finance.py · cost_drivers()Formula
Why this waySame sign convention as the contract: positive is under benchmark. A category with no contracted benchmark is not judged at all rather than compared with an invented one.
In the demoProfessional / office +143.26, Inpatient -0.33, Pharmacy -15.89, Emergency department +28.64, Outpatient +40.0
app/services/finance.py · cost_drivers()Formula
Why this wayA month-to-date figure read as a full month nearly always looks like an improvement, so the partial month is flagged every time.
In the demoProfessional / office 31.14 → 20.29 (-10.85), Inpatient 0.0 → 1557.02 (+1557.02), Pharmacy 0.0 → 0.0 (+0.00), Emergency department 0.0 → 235.75 (+235.75), Outpatient 0.0 → 0.0 (+0.00)
app/services/finance.py · cost_drivers()app/services/finance.py · member_months_window()Formula
Why this wayTells a reader whether a category is a few expensive members or a broad pattern, which calls for a different action.
In the demoProfessional / office 12, Inpatient 3, Pharmacy 12, Emergency department 3, Outpatient 0
app/services/finance.py · cost_drivers()Formula
Why this wayOne sentence answering 'what should I look at first'. Under 100 members a single admission moves PMPM visibly, so the screen warns before anyone reads a trend into it.
In the demoPharmacy is $15.89 PMPM over its benchmark — the largest cost opportunity in the contract.
app/services/finance.py · cost_drivers()Formula
Why this wayThe payer-standard unit. Ambulatory counts virtual visits too, because a telehealth primary-care visit is the utilisation a value-based contract wants more of.
In the demoInpatient admissions 456.6 (n=4), ED visits 342.5 (n=3), Ambulatory / PCP visits 1141.6 (n=10)
app/services/finance.py · utilization()Formula
Why this wayStays still in progress are left out, because a stay counted before it ends would make length of stay look shorter than it is.
In the demo4 days
app/services/finance.py · utilization()Formula
Why this wayA discharge whose window has not closed is excluded rather than counted as 'not readmitted', which would flatter the rate. Known inconsistency: this rate is computed over every member in the tenant, while the other utilisation rows use attributed members in the period.
In the demo33.3% = 1 of 3 index discharges; 1 still inside the window
app/services/outcomes.py · readmission_rate()Formula
Why this wayThe same windowing rule as readmissions: only discharges whose 7 days have passed are judged. Like readmissions it is computed over every member in the tenant.
In the demo0.0%
app/services/finance.py · post_discharge_followup()Formula
Why this wayEach month is divided by its own member-months, so months are comparable. The current month is flagged partial because its PMPM is month-to-date.
In the demo2026-04 $2158.25, 2026-05 $3271.46, 2026-06 $1488.25, 2026-07 $1103.45, 2026-08 $31.14, 2026-09 $1813.05 (partial)
app/services/finance.py · pmpm_by_month()app/services/finance.py · member_months_window()Formula
Why this wayEach row re-uses the engine that owns the number, so this table cannot disagree with the panels above it. A value the engine cannot compute yet (for example, no discharge whose 30-day window has closed) shows as not available with the reason, never as 0.0, and is not frozen into the trend: zero is a score somebody earned.
In the demoImprove quality (composite measure rate) 24.1 %, Close care gaps 25.6 %, Reduce avoidable utilization (ED visits) 342.5 per 1,000/yr, Lower total cost of care 1554.32 $ PMPM, Reduce avoidable utilization (30-day readmissions) 33.3 %, Patient outcomes (members whose tracked values improved) 71.4 %
app/services/finance.py · compute_outcomes()Formula
Why this wayThere is no survey (CAHPS) or grievance source in the platform, so these are declared unmeasured rather than estimated.
In the demoImprove member experience, Succeed in value-based contracts
app/services/finance.py · compute_outcomes()Formula
Why this wayAn observed change between readings, not a claim that any intervention caused it. Computed over every member with readings, with no attribution or date window, and a member with a single reading is counted as not evaluable instead of unchanged.
In the demoHbA1c: 3 of 5 improved (60.0%), mean -0.24 %, Systolic BP: 4 of 5 improved (80.0%), mean -6.4 mmHg, Total cholesterol: 2 of 3 improved (66.7%), mean +1 mg/dL, Creatinine: 1 of 1 improved (100.0%), mean -0.1 mg/dL
app/services/outcomes.py · population_change()app/services/outcomes.py · patient_trajectory()The VBC manager's (and the executive's) Actions & Outcomes screen: the operational KPI board, population-level next best actions, how providers are answering the opportunities sent to them, how each campaign's members are progressing, and what the care team has delivered.
Formula
Why this waySix KPIs (average case resolution, first contact resolution, CAHPS, grievances, member satisfaction, research time) have no source in this platform and are always shown with the system that owns them, never as 0 and never dropped. A rate over an empty denominator also shows as 'not measured here', so N can move as data arrives. The panel shows no targets by design: none has been agreed.
In the demo10 of 16
Check it yourselfCount the cards that show a number: they equal N; the rest say 'not measured here'.
app/services/opskpi.py · board()app/static/app.js · opsKpiPanel()Formula
COMPLETED or OUTCOME_CONFIRMED + vendor referrals at CONFIRMED
N = settled referrals: internal OUTCOME_CONFIRMED, DECLINED, CANCELLED, UNABLE_TO_CONTACT + vendor CONFIRMED, DECLINED, FAILED, CANCELLED
rate = round( 100 × numerator ÷ N, 1 ); 'not measured here' when N = 0Why this wayIn-flight referrals are left out of the denominator rather than counted as failures. Known inconsistency: internal COMPLETED ('team reports it done') is counted as a success here, but it is not a settled state, so it is in the numerator without being in N; the rate can therefore exceed 100%. The per-person 'Referrals (loop closed)' column further down this same screen counts only OUTCOME_CONFIRMED, so the two can differ. Tenant-wide, all time. See Part I, Referral SLA, for what settles a referral.
In the demo100% over 1
Check it yourselfIn the demo the one settled referral is a confirmed vendor referral: 1 ÷ 1 = 100%.
app/services/opskpi.py · board()Formula
Why this wayA count, so 0 is shown as 0 (a measurement), not as 'not measured'. Vendor referrals are not counted. The card also prints 'over N' where N is the same count, which adds nothing.
In the demo0 handoffs
app/services/opskpi.py · board()Formula
closed_on date; 'over N' = all mirrored cases
'not measured here' when no case has been mirrored at allWhy this waySalesforce holds the real backlog; this counts only the cases this platform has been told about, and the card says so. With nothing mirrored the card refuses rather than printing 0, because 'no view' is not 'empty'.
In the demo1 over 1
app/services/opskpi.py · board()Formula
case_type, lower-cased, is complaint; 'over N' = all mirrored cases
'not measured here' when no case has been mirroredWhy this waySame limit as the backlog: only complaints mirrored from Salesforce. CAHPS, grievances and member satisfaction beside it are never computed here and say which system owns them.
In the demo1 over 1
app/services/opskpi.py · board()Formula
PLANNED
rate = round( 100 × numerator ÷ N, 1 )Why this wayCounted per ladder, not per message. Known limit: ANY recorded outcome sets the field this counts, including 'No answer', 'Voicemail left' and 'Wrong number', so a ladder that never reached the member can count as a response; and the numerator is not restricted to attempted ladders, so the rate is not bounded by 100%. The care-team 'Response' column on this screen is a different figure (members with an inbound message, per person).
In the demo100% over 2
Check it yourselfIn the demo both attempted ladders are at REACHED (needs appointment; transportation barrier): 2 ÷ 2.
app/services/opskpi.py · board()app/services/engagement.py · record_outcome()Formula
COMPLETED ÷ every HRA raised (any status), 1 )Why this wayThe denominator is every assessment raised, so an HRA nobody chased still counts against completion; the plan cannot choose a friendlier denominator.
In the demo35.7% over 14
app/services/opskpi.py · board()Formula
OFFERED, ACCEPTED, ENROLLED or DECLINED
rate = round( 100 × those at ENROLLED ÷ N, 1 )Why this wayEnrolled over everyone offered, not over enrolments, so declines count against it. Known limit: an enrolment that later moved to DISENROLLED (or is still ELIGIBLE) is in neither count, so a member who enrolled and left drops out of the denominator.
In the demo66.7% over 12
app/services/opskpi.py · board()Formula
Why this wayThe card's basis reads 'members this platform has attempted to reach', but an inbound-only message also counts, so it is 'any two-way contact recorded'. N is the whole tenant, not the attributed population.
In the demo15.4% over 13
app/services/opskpi.py · board()Formula
Why this wayA duplicate that never happens looks like nothing happening unless it is counted. The same function feeds the Duplicate activity prevented screen. No denominator is shown: there is no meaningful 'out of'.
In the demo0 prevented
app/services/prevention.py · summary()app/services/opskpi.py · board()Formula
done in the tenant ÷ N, 1 )Why this wayA workload figure, not a score, and not ranked per person. Known limit: the numerator counts every done task in the tenant, including tasks with no owner, while N counts only owners, so unowned completed work inflates the per-person figure. All time.
In the demo3 over 1
Check it yourselfDemo: 3 done tasks, all owned by Jane Smith, 1 owner: 3 ÷ 1 = 3.0.
app/services/opskpi.py · board()Formula
Why this wayAt most 4 quality pushes plus one each for transitions, adherence, cost and enrolment can be raised, which is 8, so the limit never drops a row today. The whole panel is advisory: nothing is created until a person launches it.
In the demo8 recommendations
app/services/vbc_manager.py · population_actions()Formula
Why this wayThe score is an ordering rule, not a measurement, and it mixes units (composite points against dollars), so the exchange rate between them is a policy choice. A cost row needs more than $50 PMPM over benchmark to outrank adherence, and more than $100 plus $10 per discharge due to outrank the post-discharge queue; a quality push outranks that queue once it is worth more than 6 composite points (plus 0.1 per discharge due). In the demo all four quality pushes (13.33 to 20 points) rank first. The score is not shown.
In the demoquality_push 200.0, quality_push 155.6, quality_push 150.0, quality_push 133.3, transitions 61.0, adherence 55.0, cost 51.589, enrollment 48.0
app/services/vbc_manager.py · population_actions()Formula
Why this wayOnly the top 4 are offered, so a measure ranked fifth (in the demo, blood pressure control) is not proposed even with open gaps. Open gaps equal members because a member has at most one open gap per measure. Every figure is the Quality screen's own; see Part I, Quality opportunity and points per gap.
In the demoEED-RETINAL: 6 members, AWV: 7 members, SUPD-STATIN: 6 members, CDC-HBA1C: 4 members
Check it yourselfThe same four measures lead the Quality screen with the same open gaps and composite points; 'Open' lists exactly that many members.
app/services/vbc_manager.py · population_actions()app/services/vbc_manager.py · quality_opportunity()Formula
Why this wayThe window closes whether or not anyone acts, so it is the one event-driven row. It counts DISCHARGES, not distinct members, though the column is headed Members. Known defect: the row's Open button loads the Transitions payload, which the drill modal does not recognise, so it shows 'Nothing to show' over a non-zero count. See Part I, Transition-of-care windows.
In the demo1 discharges
Check it yourselfThe Transitions screen's 'Visit window open' card shows the same number.
app/services/vbc_manager.py · population_actions()app/services/transitions.py · recent_discharges()Formula
Why this wayCounts the whole tenant, not only attributed members. Known defects: the test is written (pdc or 1.0) < 0.80, so a PDC of exactly 0 (never filled) is read as 1.0 and that member is NOT counted, while the member's own risk and attention panels do count them; and the Open button lists the top 10 members by cost × actionability, not these members.
In the demo3 members
app/services/vbc_manager.py · population_actions()Formula
Why this wayA financial action, not a clinical one, and raised only when the contract sets a benchmark for the category; with none there is nothing to be over. The figures are the Financial screen's cost-driver row for that category.
In the demo$15.89 PMPM over benchmark across 12 member(s)
Check it yourselfFinancial → Cost drivers: the same category shows the same variance and Members; 'Open' lists that many members.
app/services/vbc_manager.py · population_actions()app/services/finance.py · cost_drivers()Formula
Why this wayThe members behind the dollar figure. The row count equals the recommendation's Members. The allowed total is summed per member and rounded as it goes, while the category row rounds once at the end, so the two can differ by a cent if a claim amount carries sub-cent precision.
In the demo12 members; top: John Doe, 4 claims, $6290.00
app/services/finance.py · category_members()Formula
Why this wayA high-risk member outside every programme is surfaced by no standing measure, so it is raised here. Known limits: the member-level list is cut to 50 ranked items first, so in a larger population this can undercount; dismissed recommendations are not counted; and the Open button lists the top 10 members by cost × actionability, not these members. See Part I, Next best action.
In the demo1 members
app/services/vbc_manager.py · population_actions()app/services/nba.py · recommend()Formula
OPEN, IN_PROGRESS, SCHEDULED, AWAITING_AUTH, SERVICE_COMPLETED, REOPENED)
sorted HIGH, RISING, MEDIUM, LOW, then name · In flight = the gap's first intervention, else 'nothing started' · Recommended action = that gap's member-level next best actionWhy this wayThe recommendation is the same one the member's care manager sees, so the two screens cannot disagree. Barrier is the measure engine's own reason the gap is open. The list is every tenant member with a live gap, not only attributed members. The modal's 'auth <ref>' branch can never show: a blocking authorisation is only looked up when an intervention exists, and then the intervention's status is shown instead.
In the demoEED-RETINAL: 6 members, first John Doe (HIGH)
Check it yourselfThe number of rows equals the row's Members (6 for the eye exam in the demo).
app/services/vbc_manager.py · measure_members()app/static/app.js · drillBody()Formula
Why this wayIt is the sum of the Sent column. The panel is hidden entirely when no opportunity has been sent.
In the demo2 opportunities
Check it yourselfAdd up the Sent column.
app/services/opportunities.py · summary()Formula
Why this wayThe denominator for evidence returned (not shown on this screen). Settled and withdrawn opportunities stay in it. See Part I, Provider response metrics.
In the demoDr. P. Osei 2
Check it yourself'view' on the row lists exactly this many opportunities.
app/services/opportunities.py · summary()Formula
NEW, VIEWED or MORE_INFO_NEEDEDWhy this wayWork waiting on the provider. A 'more information needed' answer is both awaiting AND responded, so Sent − Awaiting is not the number of responses and the columns do not add up to Sent.
In the demoDr. P. Osei 2
app/services/opportunities.py · summary()Formula
ACCEPTED / DISPUTED, whatever their status nowWhy this wayThe recorded answer, not the current status, so an accepted opportunity later withdrawn still counts as accepted. This screen shows the counts; the disputed RATE and evidence-returned rate in Part I, Provider response metrics are computed but not shown here.
In the demoDr. P. Osei 0 accepted, 0 disputed
app/services/opportunities.py · summary()Formula
Why this wayJudged only against answers: silence is not a refusal. See Part I, Provider response metrics. The responded count is not on screen, so the % cannot be rebuilt from the visible columns. Rounding is half-to-even (1 of 8 = 12.5 shows 12). Part I says the empty case 'reads as a dash'; the screen actually prints the words 'no responses yet'.
In the demoDr. P. Osei no responses yet
app/services/opportunities.py · summary()Formula
Why this wayFor an odd count this is the true median. For an even count it is the UPPER of the two middle values, not their average: response times 1 and 3 show 3, where the median is 2. Part I, Provider response metrics calls it 'the middle value'.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfOnce a provider answers, 'view' lists each opportunity; the business-day gap between creation and response gives the list to sort.
app/services/opportunities.py · summary()app/services/opportunities.py · business_date_of()Formula
provider.response_days, default 7), fixed at creation
overdue = Due < today AND status not settled (CLOSED, WITHDRAWN, DISPUTED, NOT_CLINICALLY_APPROPRIATE)
rows sorted by Overdue, then Sent, highest first; the title badge is the tenant total, hidden at 0Why this wayThe due day itself is not overdue. The due date never moves on a response, so an accepted (in progress), 'more information needed' or evidence-returned opportunity still turns overdue: the badge means 'not settled by the response deadline', not 'not answered'. The rule that raises a chase task for an unanswered opportunity (NEW or VIEWED only) fires ON the due day with its default grace of 0, one day before this badge appears.
In the demo0 overdue
Check it yourselfIn the demo both of Dr. P. Osei's opportunities were created on the reset day and fall due 7 days later, so none is overdue; 'view' shows the Due date on each.
app/services/opportunities.py · row()app/services/opportunities.py · response_days()app/services/opportunities.py · summary()app/services/task_rules.py · _r_opportunity_unanswered()Formula
Why this wayRe-running a push tops up the live campaign for that target instead of creating a second one, so this counts distinct pushes. With none the panel says 'No campaigns yet'.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfLaunch a push from a quality row (or the Quality screen); the count goes to 1, and launching the same measure again leaves it at 1.
app/services/campaigns.py · performance()Formula
Why this wayStored rather than recomputed, so the denominator cannot drift under the result. The cost: a member whose gap has since closed stays in it, and the denominator grows when a manager re-runs the push.
In the demo— nothing to show in the fresh demo tenant
app/services/campaigns.py · launch()app/services/campaigns.py · funnel()Formula
Why this wayA TASK count, not a member count. Members already holding this campaign's open work are skipped, and a member folded into another campaign's open task gets no new task, so it can be below Eligible; a re-run after a task is done can add a second task for the same member, so it can also exceed it. The funnel heads the column 'Members' regardless.
In the demo— nothing to show in the fresh demo tenant
app/services/campaigns.py · funnel()Formula
Why this wayA campaign creates tasks, never interventions, so there is no link to count by. The cost: an intervention that pre-dates the campaign, or is for another measure, or was cancelled, still counts as started.
In the demo— nothing to show in the fresh demo tenant
app/services/campaigns.py · funnel()Formula
ENGAGED or later (AWAITING_AUTH, AUTH_APPROVED, SCHEDULED, IN_PROGRESS, COMPLETED, GAP_CLOSED), or with any inbound messageWhy this wayA sent message is not a reached member; a reply or an engaged intervention is. Unreachable, declined and cancelled interventions never count. No date or purpose filter, so a reply from before the launch counts.
In the demo— nothing to show in the fresh demo tenant
app/services/campaigns.py · funnel()app/services/campaigns.py · _reached_at_least()Formula
COMPLETED or GAP_CLOSEDWhy this wayAttendance, not authorisation: the service happened. Any measure, any date.
In the demo— nothing to show in the fresh demo tenant
app/services/campaigns.py · funnel()Formula
CLOSED on the campaign's measure (any measure for a cohort campaign)Why this wayOnly the measure engine closes a gap, on clinical evidence. There is no closed-date filter, so a closure from before the launch also counts, and the screen's own caveat applies: observed progression, not attributed effect.
In the demo— nothing to show in the fresh demo tenant
app/services/campaigns.py · funnel()Formula
Why this wayBoth rates are the Quality screen's rate (see Part I, A measure across a population) over the whole population, so the change is a before-and-after, not a campaign effect; the screen says so under the table.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfC equals the measure's Performance on the Quality screen.
app/services/campaigns.py · launch()app/services/campaigns.py · performance()app/services/quality.py · evaluate_tenant()Formula
OUTREACH or later, or any outbound message
Appointment scheduled = those at SCHEDULED or later, or with an appointment BOOKED, CONFIRMED, ARRIVED or COMPLETED
(the other six stages are the table columns above)Why this wayEight stages from eligible to closed so the drop between them is visible; the drop is the finding. Like every stage, these read all of the eligible members' records in the tenant with no launch-date bound. Cancelled and no-show appointments do not count as scheduled.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfLaunch a push and click 'Funnel': eight stages, each with its count; Eligible, Work generated, Started, Reached, Completed and Gaps closed equal the table row.
app/services/campaigns.py · funnel()Formula
Why this wayEvery stage against the stored population. Work generated is a task count, so its percentage can exceed 100%.
In the demo— nothing to show in the fresh demo tenant
app/services/campaigns.py · funnel()Formula
Why this wayShows where members stop moving. Two quirks: a stage that follows an empty one reads 100.0% (0 completed, then 2 gaps closed shows '100.0%'); and the step from Work generated to Intervention created divides members by tasks.
In the demo— nothing to show in the fresh demo tenant
app/services/campaigns.py · funnel()Formula
Why this wayThe one sentence a manager acts on. The note always says 'member(s)', but the two steps touching Work generated compare members with tasks, so a leak reported there is not a member count.
In the demo— nothing to show in the fresh demo tenant
app/services/campaigns.py · _biggest_drop()Formula
UNREACHABLE, DECLINED or CANCELLEDWhy this wayCounted apart from 'not yet reached' because a channel that is not working should not hide inside a queue. It counts INTERVENTIONS, not members (a member with two stopped interventions counts twice), including ones this campaign did not prompt, although the sentence says 'member(s)'.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfAppears only when an eligible member has an intervention marked unreachable, declined or cancelled.
app/services/campaigns.py · funnel()Formula
Why this wayLaunching creates tasks (or provider opportunities) and nothing else: no message, no intervention, no gap change. A first launch's message states no counts; a top-up states new and skipped; combined, kept-separate and provider counts are added when non-zero, so a smaller task count is not read as a smaller reach.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfLaunch any quality push, then launch it again: the second message reads 0 new task(s) and N already had open work.
app/services/campaigns.py · launch()app/static/app.js · campaignCreate()Formula
Why this wayDeliberately no composite score and no ranking: the customer asked for progress toward outcomes, and a leaderboard over a handful of people is a statistic about nothing. Outcome columns come first; activity is labelled as context.
In the demoJane Smith
app/services/productivity.py · by_owner()Formula
CLOSEDWhy this wayCredited to the intervention owner, not caused by them: the measure engine closes gaps on clinical evidence that may arrive for other reasons, and the panel says so. It counts interventions, so two interventions on one closed gap count 2, and a cancelled intervention on a gap that closed still counts. All time.
In the demoJane Smith 0
app/services/productivity.py · by_owner()Formula
COMPLETED or GAP_CLOSED · Y = every intervention they own, any status
Z = round( 100 × X ÷ Y, 1 ), omitted when Y = 0Why this wayY includes interventions still in flight, so a new owner's rate starts low; the referral rate beside it uses only settled referrals. All time.
In the demoJane Smith 0 of 0
app/services/productivity.py · by_owner()Formula
OUTCOME_CONFIRMED, DECLINED, CANCELLED, UNABLE_TO_CONTACT; vendor CONFIRMED, DECLINED, FAILED, CANCELLED)
X = internal OUTCOME_CONFIRMED + vendor CONFIRMED · Z = round( 100 × X ÷ Y, 1 ); 'none settled' when Y = 0Why this wayCredited to whoever RAISED the handoff: the question is whether the referral a coordinator started produced an outcome for the member. In-flight referrals are neither success nor failure. The Operational KPIs 'Referral completion' card also counts internal COMPLETED as a success, so the two can differ. See Part I, Referral SLA.
In the demoJane Smith 100% · 1 of 1 settled · 3 raised
app/services/productivity.py · by_owner()Formula
open · M = every task they own, any status (open, done, dismissed), all timeWhy this wayM is a lifetime total, not current workload. Completed and dismissed counts are computed but not shown.
In the demoJane Smith 31 of 34
app/services/productivity.py · by_owner()Formula
open, has a due date, and that date is before today (business date)Why this wayA task due today is not overdue and a task with no due date never is. The drill applies the same rule row by row, so the badges in it add up to the column.
In the demoJane Smith: 8 (drill badges: 8)
Check it yourselfOpen 'Work' for the person and count the red OVERDUE badges.
app/services/productivity.py · by_owner()app/services/productivity.py · owner_work()Formula
intervention.create audit event to the first later intervention.* audit event, rounded to 2 decimals (dropped unless strictly later)
table value = median of those, rounded to 1 decimal; '—' when noneWhy this wayMeasured from the append-only audit trail, not a mutable column, and a median so one item left over a weekend cannot dominate. Known limits: each duration is rounded before the median, which breaks Part I's 'rounded once, at the end'; a 'touch' includes system moves (a member's reply moving the intervention to ENGAGED); and interventions created by a provider accepting an opportunity write no create event, so they are left out.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfStart an intervention and move it once; the drill shows its hours and the table the median.
app/services/productivity.py · by_owner()app/services/productivity.py · _intervention_timings()app/services/productivity.py · owner_work()Formula
task.done audit event: hours from the task's creation to its FIRST task.done, rounded to 2 decimals
value = median, rounded to 1 decimal; the line is hidden when there is noneWhy this wayFor a task the first action is also the last (open → done), so this is the task's 'time to first action' under its accurate name. Dismissed tasks, open tasks, and tasks closed without an audit row (e.g. seeded as done) are left out. Same double rounding as first touch.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfIn the demo Jane Smith's 3 done tasks were seeded done, with no task.done event, so the line is hidden until a task is closed on screen.
app/services/productivity.py · by_owner()app/services/productivity.py · _task_close_times()Formula
Why this wayContext, never the headline. Known limit: 'replied' has no timing or thread check, so an inbound message sent before the contact, or answering a colleague, counts, and two people who contacted the same member both get the reply. The Operational KPIs 'Outreach response' is a different figure (per ladder).
In the demoJane Smith no contacts made
app/services/productivity.py · by_owner()Formula
ARRIVED or COMPLETED
'no appointments booked' when Y = 0Why this wayNot 'appointments this person booked': it follows the members they own work for. Cancelled and no-show appointments are in Y, whereas the funnel's 'Appointment scheduled' on the same screen excludes them.
In the demoJane Smith no appointments booked
app/services/productivity.py · by_owner()Formula
Why this wayWork owned by nobody appears in no one's numbers, so it is surfaced. Known limit: done, dismissed, completed and cancelled work is counted too, although the note says it 'goes unworked'; My Work's unassigned count uses open tasks only, so the two can differ.
In the demo1 task(s), 1 intervention(s)
app/services/productivity.py · by_owner()The VBC manager's and executive's Analytics screen (prior-authorization volume, approval, turnaround, SLA and appeals; care gaps; the intervention funnel and risk mix), plus three panels any authorized role opens over other screens: the documentation readiness check, the eligibility (271) response and the Ask mdvin answers about authorizations.
Formula
Why this wayA volume count, not a workload count: finished and withdrawn requests stay in it. It equals the sum of the PA Pipeline table beside it and the length of the Authorizations list for the same role, because all three read the same rows at request time.
In the demo1 authorizations
Check it yourselfAdd up the Count column of the PA Pipeline table; it is the same number.
app/api/analytics.py · pa_analytics()Formula
APPROVED
D = requests whose current status is DENIED or CLOSEDWhy this wayCounted on where each request stands now, so a denial overturned on appeal counts as approved. CLOSED is treated as a denial because the only code that writes it today is an upheld appeal; the state machine also allows an approved request to be closed, and if anything ever did that, the approval would count as a denial. PARTIALLY_APPROVED, APPEALED, pending, withdrawn and expired requests are in neither A nor D. When nothing has been decided the card shows 0%, not '—' (the max(1, …) guard), unlike the three cards beside it.
In the demo100%
Check it yourselfIn the PA Pipeline table: Approved ÷ (Approved + Denied + Closed).
app/api/analytics.py · pa_analytics()Formula
submitted_at and decided_at of ( decided_at − submitted_at ), in hours, rounded to 2 decimals
'—' when there are noneWhy this wayMeasured from submission, the same start as the decision clock (see Part I, Prior-authorization decision clock). Known limit: decided_at is written by more than a determination. Pending a request writes it and resuming does not clear it; a withdrawal writes it; an overturned appeal overwrites it with the appeal's decision time. So a pended request counts at the moment it was pended, and an overturned one counts at the appeal decision. Read it as time to the first reviewer action, or to the latest appeal, not time to the final determination.
In the demo72h
Check it yourselfThe demo request PA-2026-40188 was submitted 4 days before the reset and decided 1 day before it: 3 days = 72 hours.
app/api/analytics.py · pa_analytics()app/services/workflow.py · decide_pa()app/services/appeals.py · decide_appeal()Formula
submitted_at, decided_at and a decision_due
M = those of N with decided_at ≤ decision_due
SLA % = round( 100 × M ÷ N, 1 ); '—' when N is 0Why this wayOnly requests with a recorded decision are judged, so a request that is late and still undecided is not in N yet; it shows on the Authorizations list's red SLA chip instead. The same decided_at limit as Avg TAT applies: a pend counts as meeting the clock at the moment it was pended, and an overturned appeal is compared with the ORIGINAL decision due, which can turn an on-time decision into a miss.
In the demo100% (met on 1 of 1 measured)
Check it yourselfThe note under PA Pipeline prints M and N; M ÷ N is the card.
app/api/analytics.py · pa_analytics()Formula
UPHELD, OVERTURNED or PARTIALLY_OVERTURNED
overturned = decided appeals that are not UPHELD
overturn % = round( 100 × overturned ÷ decided, 1 ); '—' when none is decidedWhy this wayA partial overturn counts as overturned, because the member got some of the service after the plan first said no. Level 1 and Level 2 appeals are counted alike. As the screen says, a high rate usually points to documentation missing at submission rather than to reviewer error; the readiness check further down this chapter exists to catch that before submission.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfNo appeal exists in the fresh demo, so the card shows '—'. File and decide one on the Authorizations screen and the card becomes overturned ÷ decided.
app/api/analytics.py · pa_analytics()Formula
Why this wayFiled minus decided is the number of appeals still waiting for a decision.
In the demo0 appeals
app/api/analytics.py · pa_analytics()Formula
CLOSED, all timeWhy this wayOnly a gap closed by evidence counts. EXCLUDED and NOT_APPLICABLE also take a gap off the open list but are not closures, so they are left out. Other screens show a same-named number computed differently: the Dashboard's 'Gaps closed this month' counts only closures dated this month, My Panel's 'Gaps closed' counts only gaps behind the signed-in care manager's own interventions, and Actions & Outcomes counts members, not gaps. The intervention state GAP_CLOSED in the funnel below is a different record and can differ from this count.
In the demo0 gaps
Check it yourselfEquals the 'closed' entry in the 'care gaps … total (…)' line at the foot of the screen (absent when 0).
app/api/analytics.py · vbc_analytics()Formula
Why this wayA snapshot of where requests stand now, not how many ever passed through a state. The rows add up to PA Volume.
In the demoAPPROVED 1
Check it yourselfFilter the Authorizations list by status; each count matches.
app/api/analytics.py · pa_analytics()app/static/app.js · rAnalytics()Formula
expedited, any statusWhy this wayExpedited requests run on the 72-hour clock rather than 7 days (see Part I, Prior-authorization decision clock). This counts all of them, open and decided.
In the demo0 requests
app/api/analytics.py · pa_analytics()Formula
Why this wayThe code is kept when a denial is overturned on appeal, so an overturned request still counts under its original reason: the panel answers 'why did we deny', not 'why are requests denied now'. A withdrawal clears the code. The API also counts denial reviews, but that figure is not shown.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfNo request is denied in the fresh demo. Deny one as the medical director (a reason code is mandatory) and it appears here under that code.
app/api/analytics.py · pa_analytics()Formula
Why this wayThe top of the funnel and the 100% width every other bar is drawn against.
In the demo1 interventions
app/api/analytics.py · vbc_analytics()Formula
OUTREACH, ENGAGED, SCHEDULED, AWAITING_AUTH, AUTH_APPROVED, IN_PROGRESS, COMPLETED or GAP_CLOSEDWhy this wayCurrent state, not 'ever reached': an intervention that went UNREACHABLE, DECLINED, REOPENED or CANCELLED drops out even if outreach happened. The name overstates it slightly: a member who phoned in can go straight from identified to engaged, or to awaiting authorization, without any outreach, and still counts here. The Dashboard's Engagement funnel uses the same state sets under different labels ('Outreach', 'Reached', 'Scheduled', 'Completed'), but a separate implementation.
In the demo1 interventions
app/api/analytics.py · vbc_analytics()Formula
ENGAGED, SCHEDULED, AWAITING_AUTH, AUTH_APPROVED, IN_PROGRESS, COMPLETED or GAP_CLOSEDWhy this wayThe Outreach set without OUTREACH itself. The same current-state limit applies: a DECLINED member leaves the count. The demo's one intervention (Derrick Boateng's retinal exam, authorization approved) counts here although it was created directly at AUTH_APPROVED.
In the demo1 interventions
app/api/analytics.py · vbc_analytics()Formula
SCHEDULED, IN_PROGRESS, COMPLETED or GAP_CLOSEDWhy this wayAWAITING_AUTH and AUTH_APPROVED are left out because they come before booking: an approved authorization unlocks scheduling. The count can go DOWN: a no-show sends a scheduled intervention back to outreach, and a completed one can be reopened.
In the demo0 interventions
app/api/analytics.py · vbc_analytics()Formula
COMPLETED or GAP_CLOSEDWhy this wayCOMPLETED means the service happened; GAP_CLOSED means the evidence also closed the care gap. This is an intervention count, so it can differ from the Gaps Closed card, which counts care-gap records.
In the demo0 interventions
app/api/analytics.py · vbc_analytics()Formula
Why this wayEach bar is that stage's share of ALL interventions created, not the conversion from the stage before it, and it is rounded to a whole percent. The Dashboard's funnel draws its bars against its first stage (Outreach) instead, so the same counts produce different bar lengths on the two screens.
In the demoInterventions created 100%, Outreach or beyond 100%, Engaged or beyond 100%, Scheduled or beyond 0%, Completed / gap closed 0%
app/static/app.js · rAnalytics()Formula
Why this wayIt counts the tier stored on each member record, the same one the Patient 360 summary and the Dashboard's 'High / rising risk' card read, not a fresh score. See Part I, Clinical risk score and tier. A tier typed in by hand is counted as typed. Tiers with no members are not listed.
In the demoHIGH 2, MEDIUM 5, RISING 4, LOW 2
Check it yourselfThe four numbers add up to the member count on the Patients list (13 in the demo).
app/api/analytics.py · vbc_analytics()app/services/risk.py · rescore()Formula
Why this wayA count of stored gap records. It is not the Quality screen's 'open gaps' (D − N per measure), which the measure engine recomputes from members; the two agree in the fresh demo (29) because every stored gap is still open, and drift apart as gaps close, are excluded, or when a member has two records for one measure.
In the demo29 gaps
app/api/analytics.py · vbc_analytics()Formula
Why this wayRaw statuses, not grouped into open and closed. Open side: OPEN, IN_PROGRESS, SCHEDULED, AWAITING_AUTH, SERVICE_COMPLETED, REOPENED. Closed side: CLOSED, EXCLUDED, NOT_APPLICABLE (and three statuses nothing writes today). Only CLOSED feeds the Gaps Closed card.
In the demoopen 28, in progress 1
app/api/analytics.py · vbc_analytics()app/static/app.js · rAnalytics()Formula
Why this wayDeterministic: it points at records and never asserts a clinical fact. Known limit, visible in the demo: the structured match is on the evidence TYPE only, never on what the criterion says. Any lab-sourced risk factor satisfies any lab criterion, so on PA-2026-40188 criterion C3 'Elevated HbA1c or insulin-dependent' shows as Evidenced by 'Total cholesterol above 240'. Read an Evidenced line as 'the record has evidence of this kind', and check the cited item. Structured evidence also outranks documents, so a criterion can be Evidenced with nothing attached to the request.
In the demoC1 SATISFIED (Type 2 diabetes (E11.9)), C2 SATISFIED (meets denominator criteria), C3 SATISFIED (Total cholesterol above 240 (was 242.0mg/dL)), C4 MISSING (nothing in the record)
Check it yourselfEach Evidenced line names the record it used and its source system; open the member's Clinical tab and find it.
app/services/readiness.py · assess()app/services/readiness.py · _match_structured()app/services/readiness.py · _match_document()app/static/app.js · readinessHtml()Formula
Why this wayAn unattached document is named before a missing one because it is the cheaper fix: one click, versus obtaining new documentation. It inherits the type-only limit of the per-criterion check above, so 'All N criteria are evidenced' can be true of the record's types and still leave a reviewer something to ask for.
In the demonot ready: 1 requirement (C4) cannot be evidenced from the record. Obtain and attach the documentation, or expect the payer to request more information.
app/services/readiness.py · assess()app/static/app.js · readinessHtml()Formula
Why this wayTicked by default: the documents are already in the chart, so attaching them at submission avoids a pend for missing information. Only documents the check found are attached; nothing is generated.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfNo seeded chart holds an unattached document of a required type, so the checkbox does not appear in the fresh demo. Upload a clinical note for a member, then launch a retinal-exam request for them: the note appears as 'In the chart, not attached' and N counts it.
app/services/readiness.py · assess()app/static/app.js · readinessHtml()app/static/app.js · loadReadiness()Formula
pa_required false → not required · otherwise requiredWhy this waySilence is never read as 'no': a 'not required' answer must come from a policy that says so (the demo loads one for routine services). 'Cannot say' costs a phone call; a wrong 'no' costs a denied claim. The authorization gate used by next best action and booking answers the same question through a separate function that ignores the pinned policy, so for a request pinned to a since-retired version the two can differ.
In the demoDerrick Boateng 92250: required · John Doe 99213: not required · Ahmed Ali 92250: cannot say
Check it yourselfAhmed Ali's plan (BCBS Texas, commercial) has no policy on file in the demo, so the panel says it cannot tell and asks you to confirm with the payer.
app/services/readiness.py · assess()app/api/pa.py · policy_answer()Formula
effective_to), whatever its status; the check is saved with a new ELG-… transaction numberWhy this wayReports what the benefit record on file says; it quotes no price. Known inconsistency: other parts of the product pick 'the' coverage differently. The readiness check and the care-gap chain take the coverage marked active, the Dashboard also requires today to fall inside its dates, and this modal takes the latest end date even when that coverage is terminated. With one coverage per member, as in the demo, all agree.
In the demoACTIVE · UnitedHealthcare MA Choice · 2026-01-01 to 2026-12-31
Check it yourselfThe modal's transaction number is saved; the Coverage tab's 'Last verified with the payer' shows it afterwards.
app/services/eligibility.py · verify()app/api/eligibility.py · check()Formula
Why this wayBoth dollar figures are read from the coverage's benefit record as filed; only the bar is computed, in the browser, and capped at 100%. A missing figure prints as '$null' rather than 'not on file'.
In the demo$875 of $1500 → 58%
Check it yourselfJohn Doe: 875 ÷ 1,500 = 58.3%, drawn as 58%.
app/static/app.js · eligibilityModal()app/services/eligibility.py · verify()Formula
Why this waySame arithmetic as the deductible bar. Known limit: coverage added through the product's own 'Add coverage' form has no out-of-pocket field. The form stores a maximum of three times the deductible, 'met' equal to the deductible met, and copays of $30 (PCP) and $60 (specialist), so for those members this bar and the copay line show values the form derived, not benefits filed by the payer. Seeded coverage carries real benefit figures.
In the demo$2200 of $5000 → 44%
Check it yourselfJohn Doe: 2,200 ÷ 5,000 = 44%.
app/static/app.js · eligibilityModal()app/static/app.js · coverageSave()Formula
active and pa_required true; one line per policy with its service codesWhy this wayThe list of services this plan says need authorization, so nobody drafts a request that eligibility would have refused. The payer match is an exact text match, and the 'Add coverage' form takes the payer as free text: coverage typed as 'United Healthcare' matches no policy filed as 'UnitedHealthcare', and the box silently disappears.
In the demoUHC-MA-EYE-014 v3: 92250
Check it yourselfSign in as the policy administrator: the Policy Packages list shows the same active, authorization-required package for UnitedHealthcare Medicare Advantage.
app/services/eligibility.py · verify()app/api/eligibility.py · check()Formula
APPROVED; 'to' = the authorization's valid_to
a new approval, or an overturned appeal, is valid from the decision's business date to that date + 180 daysWhy this wayValidity is not re-checked here. An authorization past its end date is moved to EXPIRED by the automation sweep (every 15 minutes by default), and until then it still lists. PARTIALLY_APPROVED requests receive no authorization number and never list. Known inconsistency in the demo: the seeded authorization PA-2026-40188 was written with a 90-day window, not the 180 days every real approval receives.
In the demo89 days after the reset
Check it yourselfCheck eligibility on Derrick Boateng, the member with the demo's approved authorization: the box lists PA-2026-40188 · CPT 92250 · AUTH-88213417, valid from the day before the reset to the date shown here.
app/services/eligibility.py · verify()app/services/workflow.py · grant_authorization()app/services/workflow.py · expire_authorizations()Formula
decision_due and no decided_at, soonest first
over = live with due < now · soon = the rest due within 48 hours
facts: over + soon (or all live when both are empty), at most 6; 'in 2d 3h' / '5h' / '40m' / '1d 4h overdue', whole units, never rounded upWhy this way48 hours is the assistant's own cut; the SLA chip on the Authorizations list goes red under 24 hours and amber under 72, so the two can describe the same request differently. Because pending a request writes decided_at and resuming does not clear it, a pended or resumed request drops off this answer while its clock keeps running.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfIn the fresh demo the only request is already decided, so the answer is 'No authorization has a clock running right now.' Submit a request and ask again: it is listed with its time to deadline.
app/services/assistant.py · _h_at_risk()app/services/assistant.py · _rel()Formula
Why this wayThe same readiness engine as the panel above, so the two cannot disagree about a request. Known limit: with no request or member named, 'highest reference' is not 'newest', because reference numbers are random; and it answers even for a request that is already decided, as the demo shows.
In the demoPA-2026-40188: 1 requirement(s) that nothing in the record satisfies
app/services/assistant.py · _h_pa_blocked()app/services/assistant.py · _newest_pa()app/services/readiness.py · assess()Formula
decision_due, in whole units as above
'past the deadline' when due < now and no decision is recorded
Urgency label = '72 hours' when expedited, else '7 days'Why this wayThe due time is the decision clock of Part I (see Prior-authorization decision clock). Two limits: the urgency label is fixed text, so a deployment that configures a different clock would see the old numbers here; and the 'Decision due' fact is shown even after the decision is made.
In the demoPA-2026-40188 · APPROVED · standard (7 days)
Check it yourselfThe decision-due fact moves with the clock; compare it with the SLA due date on the Authorizations list.
app/services/assistant.py · _h_pa_status()app/services/assistant.py · _rel()Formula
SUBMITTED, IN_REVIEW, PENDED or DRAFT; closed out = total − open
facts: one per status, largest firstWhy this wayTotal equals PA Volume on the Analytics screen. 'Open' here is not the same set as elsewhere: an APPEALED request is still undecided but counts as closed out, the Dashboard's 'PA blocking care' leaves out DRAFT, and the at-risk answer above leaves out pended requests. Phrasing matters: 'How many authorizations are there?' is answered with one request's status instead.
In the demo1 in total, 0 still open and 1 closed out
app/services/assistant.py · _h_counts()The attributed clinician's home screen (sidebar: My Opportunities), seen by a provider login such as the demo's Dr. P. Osei: the gap-closure opportunities the payer has routed to this provider, grouped by what they need, plus the size of the provider's attributed panel.
Formula
NEW, VIEWED or MORE_INFO_NEEDED
counted in the browser from GET /population/opportunitiesWhy this wayAn opportunity needs the provider while nobody has answered it (NEW, VIEWED). This screen also counts MORE_INFO_NEEDED, which is the provider's own question waiting on the care team: the same row's Do column says 'waiting on the care team', so the card counts a row that is not the provider's turn. It comes back as VIEWED when the care manager answers. The VBC manager's Provider responses panel counts the same three statuses as 'Awaiting'. The list is only this provider's opportunities (see 'Which opportunities are listed' below).
In the demo2 opportunities
Check it yourselfThe section below shows the same count and that many rows. As the VBC manager, Actions & Outcomes > Provider responses > Awaiting for Dr. P. Osei shows the same number.
app/static/app.js · rProvider()app/api/population.py · list_opportunities()Formula
IN_PROGRESS, COMPLETED or EVIDENCE_RETURNEDWhy this wayIN_PROGRESS means the provider accepted and the intervention was created in their name; COMPLETED means they marked the service done and the evidence is still to come. EVIDENCE_RETURNED is listed but never stays: both paths that reach it (already completed with evidence, return evidence) move the opportunity on to CLOSED in the same request, and evidence that does not match the measure is refused before it gets there. In practice this card is IN_PROGRESS + COMPLETED.
In the demo0 opportunities
Check it yourselfAccept an opportunity in 'Need your answer': it moves to this section, and both counts change by one.
app/static/app.js · rProvider()app/services/opportunities.py · return_evidence()Formula
CLOSED, WITHDRAWN, DISPUTED, NOT_CLINICALLY_APPROPRIATE)
KPI = number of listed rows flagged overdueWhy this wayComputed by the server on every read, never stored; the due day itself is not overdue. The clock is set once at creation and never stopped, so an opportunity the provider has already accepted (IN_PROGRESS), marked done (COMPLETED), or is waiting on the care team for (MORE_INFO_NEEDED) still turns overdue on its date. The caption says 'past the response deadline', but the count means 'past the deadline and not finished', not 'unanswered'. A second rule reads the same deadline differently: the 'unanswered' task raised to the VBC manager fires ON the due day and only for NEW or VIEWED. So for one day a task can say the opportunity is past its deadline while this screen shows no badge, and an accepted opportunity can be overdue here with no task raised. The Provider responses panel's Overdue column uses this screen's rule. See Part I, Provider response metrics.
In the demo0 opportunities
Check it yourselfThe KPI equals the number of red badges in the three sections. The VBC manager's Provider responses > Overdue for Dr. P. Osei shows the same. A freshly reset tenant has none, because the seeded opportunities are due 7 days after the reset.
app/services/opportunities.py · row()app/static/app.js · _oppTable()app/services/task_rules.py · _r_opportunity_unanswered()Formula
GET /vbc/patients returns for this login: members with a PatientAttribution to this provider (provider_id, not the name) in any period whose status is open, with no ended_onWhy this wayThe same list and count as the provider's My Panel screen (see the Patients chapter, 'My Panel (N), provider sign-in'). The caption says 'this period', but the rule is any open period, not the date-bounded current period that the Patient 360 attribution line uses. With one open period (the demo's MY2026) the two agree. With two open periods, a member attributed in either one is counted. If the request fails, the browser falls back to an empty list and shows 0 instead of an error, so a 0 here does not by itself prove an empty panel.
In the demo5 members
Check it yourselfClick My Panel in the sidebar: its count badge shows the same number.
app/core/scope.py · _provider_panel()app/api/vbc.py · list_patients()app/static/app.js · rProvider()Formula
CLOSED, WITHDRAWN, DISPUTED or NOT_CLINICALLY_APPROPRIATEWhy this waySettled means the provider's part is on the record, not that the gap is resolved. DISPUTED and NOT_CLINICALLY_APPROPRIATE land here, but each one raises a High-priority task for the VBC manager that is still open, and the gap itself is not changed: settled for the provider, unresolved for the payer. MORE_INFO_NEEDED is not settled. WITHDRAWN is the payer taking an opportunity back. The three sections split the list with no overlap and no gaps: every status belongs to exactly one of them.
In the demo0 opportunities
Check it yourselfDispute an opportunity with a reason: it moves from 'Need your answer' to 'Settled', and a High-priority 'Reconcile the disputed gap' task appears in the VBC manager's queue.
app/static/app.js · rProvider()app/services/opportunities.py · row()Formula
response_days calendar days
response_days = tenant setting provider.response_days, default 7; a negative value counts as 0, and a value that is not a number falls back to 7
set once at creation, never movedWhy this wayThe deadline counts calendar days, not business days, so it can fall on a weekend. It is not restarted when the care team answers a question, so a provider can get back an opportunity that is already past due. Sending a gap again while this provider already has a live opportunity on it returns the existing opportunity, with its original deadline.
In the demo7 days after the reset
Check it yourselfSend a gap to the provider as the care manager: the new row's Due date is the reset day plus 7.
app/services/opportunities.py · create()app/services/opportunities.py · response_days()Formula
provider_id is the signed-in provider's, then only those whose member is on the provider's panel (the My panel rule)
sorted: unsettled first, then by due date, earliest first (no due date last)Why this wayThe provider comes from the login's binding, never from a query parameter. A provider login bound to no provider sees nothing, not the whole tenant. The second filter has a cost: if a member leaves the panel, every opportunity for that member disappears from this screen, settled ones included. The VBC manager's Provider responses panel is not filtered by panel, so its 'Sent' count for this provider can then be higher than the rows here. Staff logins get the whole tenant from the same endpoint.
In the demoJohn Doe, CDC-HBA1C, Sarah Martinez, EED-RETINAL
Check it yourselfAs the VBC manager, Provider responses > Sent for Dr. P. Osei equals the total number of rows in the three sections here.
app/api/population.py · list_opportunities()app/services/opportunities.py · list_rows()app/core/scope.py · filter_patient_rows()Formula
NEW or VIEWED → Accept · Already completed · Need info · Not appropriate · Dispute
IN_PROGRESS → Mark service done · COMPLETED → Return evidence
MORE_INFO_NEEDED → 'waiting on the care team' · settled → 'settled' · anything else → '—'Why this wayThe screen only draws the actions the server accepts at that status, and the server still checks each one: 'Already completed' needs evidence that matches the measure, and 'Not appropriate' and 'Dispute' need a reason. Two differences from the server: it also accepts evidence while an opportunity is IN_PROGRESS, but the screen offers Return evidence only at COMPLETED. And there is no 'opened' action, so an opportunity never becomes VIEWED just because the provider looked at it. It shows as Viewed only after the care team answers a Need info question.
In the demoJohn Doe: Accept, Already completed, Need info, Not appropriate, Dispute, Sarah Martinez: Accept, Already completed, Need info, Not appropriate, Dispute
Check it yourselfClick Already completed and leave the evidence empty: nothing is sent. Enter evidence that does not match the measure: the server refuses it and the gap stays open.
app/static/app.js · _oppActions()app/services/opportunities.py · respond()The VBC manager's (and executive's) view of what went wrong: open rule-raised work that is an exception rather than routine, grouped by kind with its age, escalation and lateness, plus the two integration failures that are not per-member work. Care managers, providers and auditors cannot open it (the API answers 403).
Formula
status open) raised by the rule engine (source = 'rule') whose rule_key is one of the 15 keys in EXCEPTION_RULES
card = the sum of the Open column over every categoryWhy this wayThe Exception Center is a view over tasks the rule engine already raised, not a separate store, so an exception is resolved exactly when its task is done or dismissed. Which rules count is an explicit allow-list (pa.sla_at_risk, pa.denied_appealable, vendor.sla_breach, referral.sla_breach, referral.awaiting_acceptance, engagement.exhausted, engagement.stalled, hra.overdue, coverage.lapsing, sdoh.barrier_unaddressed, opportunity.unanswered, gap.evidence_missing, appointment.not_rebooked, opportunity.disputed, opportunity.review), so a new routine rule cannot flood this screen. The cost is the other direction: a rule left off the list never appears here, whatever it says. For example, 'Abnormal result with no follow-up' and 'Enrolled member with no care manager or no care plan' tasks sit in the team queue in the demo tenant but are not counted here, because those two rules are not on the list. The integration failures below are not included in this card.
In the demo6 = 2 HRA past its contractual window + 3 Social barrier with nothing done about it + 1 Vendor has missed its SLA
Check it yourselfthe Open column adds up to the card. Click 'open queue' on a row: the team queue opens filtered to that rule and lists the same number of tasks.
app/services/exceptions.py · summary()app/static/app.js · rExceptions()Formula
business today − the business date it was created ≥ 7 calendar days (AGED_DAYS = 7)
a task with no creation time never ages · card = the sum of the columnWhy this wayAged measures how long the TASK has been open, not how long the underlying problem has existed. After the nightly demo reset every task is re-created that day, so Aged is 0 even when a task says an assessment was due 60 days ago. It also runs on a different clock from escalation, which counts from the task's due date when it has one (see Escalated). The 7 days is a constant in the code, not a tenant setting, and the card caption repeats it as fixed text.
In the demo0 tasks
Check it yourselfin the fresh demo tenant every Oldest date is the reset day, so Aged is 0 everywhere. A task created on day D becomes aged on day D + 7.
app/services/exceptions.py · summary()Formula
task.escalated audit row exists for it
card = the sum of the columnWhy this wayEscalation is read from the audit trail, never stored on the task, so it cannot be set by hand. The rule that writes it: an open rule task whose rule sets escalate_after_days and escalate_to_role, once today − (its due date, else the business date it was created) ≥ escalate_after_days, is raised one priority band and gets '[escalated to <role>]' added to its reason, once. As shipped only gap.evidence_missing and appointment.not_rebooked set these (7 days, vbc_manager), so the other 13 categories show 0 unless a tenant adds the parameters. The caption 'raised to a second role' overstates it: the owner does not change and nothing is reassigned; the role appears only as text in the reason. See the My Work chapter, 'Escalated priority'.
In the demo0 tasks
Check it yourselfnone in a fresh tenant. After a rule sweep, an 'evidence missing' or 'missed visit not rebooked' task 7 days old is counted here, and in the queue its priority is one band higher and its reason ends '[escalated to vbc_manager]'.
app/services/exceptions.py · summary()app/services/task_rules.py · _escalate_overdue()Formula
Why this wayLateness is computed from the task on every read, never stored. Due today is not overdue. This counts exception tasks only; the Command Center's 'Tasks overdue' card uses the same test over EVERY open task, so it is normally the larger number. The due date is the one the rule copied from the triggering record (for 'HRA past its contractual window', the assessment's own due date).
In the demo2 (2 HRA past its contractual window)
Check it yourselfclick 'open queue' on a category with a red badge: that many of its rows carry the red OVERDUE badge (the queue applies the same test to the same ten characters of the due date).
app/services/exceptions.py · summary()Formula
rule_key values with at least one open exception task
each category's title and grey 'why' line come from the rule catalogue (the 'why' cut to 120 characters)Why this wayCategories are rules, not a separate taxonomy, so each one maps to exactly one filter on the team queue. A rule with no open task is not listed at all (there are no zero rows); when no category is open the table is replaced by 'No open exceptions', while the four cards still show 0.
In the demo3 categories
app/services/exceptions.py · summary()Formula
Why this wayEscalation is the strongest signal because a rule already decided the task had waited too long; lateness comes next; volume last, so a large pile of on-time work does not bury one late item. The order is the only output; no rank is shown.
In the demoHRA past its contractual window (esc 0, overdue 2, open 2), Social barrier with nothing done about it (esc 0, overdue 0, open 3), Vendor has missed its SLA (esc 0, overdue 0, open 1)
Check it yourselfthe first row has the most escalated tasks; among equal escalated counts, the most overdue.
app/services/exceptions.py · summary()Formula
Why this wayIt is the creation date of the oldest open TASK, in the tenant's business time zone, not the due date of the underlying record and not when the problem began. It is the same clock as Aged, so a category whose Oldest date is 7 or more days ago has at least one aged task.
In the demothe reset day
Check it yourselfin the fresh demo tenant every category shows the reset day, because the reset re-creates every task.
app/services/exceptions.py · summary()Formula
MAX_ATTEMPTS = 8 delivery attempts
all-time: no date windowWhy this wayAfter 8 failed attempts the relay stops retrying an event and leaves it unpublished, so it stays in this count for as long as it stays unpublished; there is no age limit and no dismissed state. The administrator's Webhooks screen shows the same events ('Dead-letter: N') with the same test, but its limit of 8 is typed separately in its own code rather than read from the relay's constant.
In the demo0 events
Check it yourselfzero in the fresh tenant (the demo relay is off). The administrator's Webhooks screen shows the same number.
app/services/exceptions.py · summary()app/services/relay.py · drain()Formula
rows_failed > 0
all-time: no date window, batch status not consideredWhy this wayA batch that had even one failed row counts here permanently: there is no resolved flag, so re-loading the failed rows successfully in a later batch does not remove the earlier one. It reads as 'batches that have ever had a failure', not 'failures waiting now'.
In the demo0 batches
Check it yourselfzero in the fresh tenant. On the Integrations screen, batches with a non-zero Failed column are these; that list shows only the latest 25 batches, so over a long history this card can be larger than what the list shows.
app/services/exceptions.py · summary()The VBC manager's (and the care manager's) check on the task rules: which rules are on, how much work each has raised, what happened to that work, and what the rules would raise if they ran now. Figures are shown as the VBC manager Alex sees them; the care manager sees the same numbers.
Formula
enabled = true
Y = number of rules in the product catalogue (CATALOGUE), on or off
the Rules table has one row per catalogue rule, so its count is also YWhy this wayThe catalogue is fixed in the product: a tenant can turn a rule off or change its priority, owner role and thresholds, but cannot add a rule with no implementation behind it. Every rule starts on. Known limit: three rules (opportunity.review, opportunity.disputed, opportunity.more_info) are raised by a provider's response, not by the sweep. They count as 'on' and 'watching for work' although the sweep never proposes anything for them.
In the demo29/29 (table: 29 rules)
Check it yourselfCount the rows in the Rules table: there are Y. As the VBC manager, each row's button says 'Turn off' when the rule is on; the care manager sees an ON badge instead.
app/services/task_rules.py · outcomes()app/services/task_rules.py · ensure_rules()Formula
rule_key, in any status (open, done or dismissed), all time
card = sum of the Raised column over the catalogue rulesWhy this wayAll time, with no date window, so the number only grows. Each rule raises at most one task per triggering record (the store enforces one task per tenant, rule and trigger), so a rule's Raised is the number of distinct records that ever triggered it. Known limit: two features write rule-keyed tasks under keys that are not in the catalogue (hra.<finding> from an HRA finding, engagement.evidence_retrieval from an Engagement outcome). They appear in no row and are not in this card, but they are in the Unassigned card. There are none in the fresh demo tenant. Coincidence in the demo: 29 tasks raised and 29 rules are unrelated numbers.
In the demo29 (transition.contact 1, transition.visit 1, transition.med_rec 1, transition.assessment 1, transition.barriers 1, gap.due_soon 1, lab.critical_result 6, sdoh.barrier_unaddressed 3, hra.overdue 2, vendor.sla_breach 1, enrollment.offer 1, enrollment.started_without_owner 8, engagement.outcome_untriggered 2) tasks
Check it yourselfAdd up the Raised column: it equals the card.
app/services/task_rules.py · outcomes()Formula
rule_key whose status is exactly open (a started task is still open)
card = sum of the Open columnWhy this wayOpen means not yet settled, whether or not someone has started it. It is narrower than My Work's 'raised by a rule' count, which counts every open task not typed by hand (campaign and transitions tasks included) and is based on the task's source, not its rule. In the demo the two agree (26) because every non-manual open task was raised by a catalogue rule. Known limit: the status is compared case-sensitively here, while the sweep lower-cases it; a task stored as 'Open' would count in Raised and in no other column. None exist in the demo tenant.
In the demo26 tasks
Check it yourselfAdd up the Open column: it equals the card. My Work, Team view, shows the same tasks with an AUTO badge.
app/services/task_rules.py · outcomes()Formula
due date (first 10 characters, read as a date) is before today's business date (America/New_York)
per rule badge: shown only when N > 0 · card subtitle = sum over rulesWhy this wayThe same boundary as My Work's OVERDUE badge: a task due today is not overdue. Two rules (gap.evidence_missing, appointment.not_rebooked) raise tasks with no due date, so their tasks can never be overdue here; those two rules escalate by age instead (see My Work, 'Escalated priority').
In the demo7 (gap.due_soon 1, lab.critical_result 4, hra.overdue 2) tasks
Check it yourselfThe red badges in the Open column add up to the card subtitle.
app/services/task_rules.py · outcomes()app/static/app.js · rAutomation()Formula
done, all timeWhy this wayA task is done when a person completes it, or when the platform completes it because the care gap it was raised for closed on evidence. Note on the same screen: the Rules table's column also headed 'Completed' is not this count but a percentage (next row), so the card and the column are different quantities under one label.
In the demo3 tasks
Check it yourselfIn the demo the three done tasks are Sam Okafor's post-discharge contact, medication reconciliation and barriers steps: those three rules show 100% in the Completed column, and the Transitions screen shows the same steps done.
app/services/task_rules.py · outcomes()Formula
Why this wayThe denominator is settled work only. Counting open tasks as failures would make a rule look worse the more recently it fired. The cost: a rule with one settled task shows 100% or 0% on that one task, so the percentage says nothing about volume; read it with Raised. Rounding is Python's, half to even, so 1 of 8 (12.5) prints 12 where a spreadsheet prints 13.
In the demotransition.contact 100%, transition.med_rec 100%, transition.barriers 100%
Check it yourselftransition.contact: 1 done, 0 dismissed, so 100% and a green badge. A rule with nothing settled shows '—' in grey.
app/services/task_rules.py · outcomes()app/static/app.js · rAutomation()Formula
Why this wayThe screen reads a high dismissal rate as a rule raising work the team does not believe in. Known limit: the platform also sets tasks to dismissed. For seven rules (gap.due_soon, sdoh.barrier_unaddressed, engagement.exhausted, engagement.escalate, coverage.lapsing, pa.sla_at_risk, pa.denied_appealable), an open task nobody has started is withdrawn as 'dismissed' when its trigger stops being true, for example because the authorization was decided, coverage was renewed or a referral for the social barrier started. So this column mixes 'the team rejected it' with 'it resolved itself', and a rule whose work mostly resolves itself can show red. The withdrawn task's reason ends '— withdrawn <date>: no longer applies', which is how to tell them apart. (A care gap closed on evidence is different: its tasks are marked done, not dismissed.)
In the demotransition.contact 0%, transition.med_rec 0%, transition.barriers 0%
Check it yourselfNo task is dismissed in the fresh tenant, so every settled rule shows 0%. Dismiss a rule-raised task in My Work and reload: that rule's Dismissed column moves and its Completed column falls by the same amount.
app/services/task_rules.py · outcomes()app/services/task_rules.py · retire_stale()Formula
rule_key (catalogue or not) whose status is open and that have no owner_idWhy this wayA rule gives a task to the member's current owner first, then to the holder of the rule's role with the fewest open tasks, and leaves it unowned only when nobody holds that role. Two known differences. (1) This card is not limited to the catalogue, unlike Raised and Open, so an unowned HRA-finding or evidence-retrieval task is counted here and in no other card. (2) My Work's 'unassigned' counts every open task with no owner, typed-in ones included. In the demo tenant this card reads 0 while My Work reads 1, because the one unowned task was typed in by hand.
In the demo0 (My Work unassigned: 1) tasks
Check it yourselfMy Work, Team view: count the UNASSIGNED badges on rows with an AUTO badge and a rule; that is this card.
app/services/task_rules.py · outcomes()app/services/task_rules.py · _assign()Formula
Why this wayIt shows the size of a change to somebody else's queue before it happens. Three known limits. (1) A trigger whose task was completed or dismissed counts as 'already raised' and is never raised again, so a recurring problem on the same record does not come back as new work. (2) 'Run now' repeats the pass up to 4 times so rules that feed each other settle, so a run can create more than this card predicted. (3) The preview is not purely a read: the same evaluation moves stalled outreach ladders to their next channel, opens ladders and refreshes enrolment eligibility, and the preview request saves those changes (see the defect list). 'Already raised' can be lower than Raised: in the demo the trigger of one 'enrolled but no active care plan' task (enrollment.started_without_owner) no longer holds, and that rule does not withdraw its tasks, so 28 of the 29 are still live.
In the demo0 would raise, 28 already raised
Check it yourselfPress Run now as a user who may run it: the toast's 'N task(s) created' is at least the card's number, and the card then reads 0.
app/api/population.py · task_rule_preview()app/services/task_rules.py · evaluate()Formula
Why this wayA sample, not the list: the panel's count is the full number, and only 10 rows are shown. Because the order is evaluation order, the most urgent candidate is not guaranteed to be among the 10.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfNothing would be raised in the fresh tenant, so the panel is hidden. It appears when a rule finds a trigger with no task yet, for example after a rule is turned back on or new data is loaded, and it lists what Run now would create.
app/api/population.py · task_rule_preview()app/services/task_rules.py · evaluate()app/static/app.js · rAutomation()Formula
Why this wayRunning repeatedly is safe: each trigger raises at most one task, so a second press says 'Nothing new'. The run result also reports how many tasks were withdrawn and escalated and whether the passes settled, but the toast shows only N. The same run happens on a timer and on every ingestion, so the button is for watching it happen.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfProduced only by pressing Run now, which writes. Known defect: the button is shown to users who can write member work (the care manager) and hidden from the VBC manager, while the endpoint accepts only the VBC manager's permission, so in the demo the person who sees the button gets 'Forbidden'.
app/api/population.py · task_rule_run()app/services/task_rules.py · run()The UM nurse's and medical director's Review Queue, and the Authorizations screen that the care manager, PA coordinator, provider (own panel only), VBC manager, auditor and administrator open from the same menu item: every prior-authorization request with its status, decision clock, policy and authorization number, the Review and Detail windows behind each row, and the Appeals panel. This chapter also covers the messages the Launch PA flow on Patient 360 prints, and the notifications bell those decisions feed. The documentation readiness panel, the eligibility window and the Ask panel have their own rows in the Analytics chapter.
Formula
Why this wayThis is the whole register, not open work. A reviewer's 'Review Queue' count includes approved, denied, withdrawn, closed and expired requests, and only rows in IN_REVIEW get a Review button; all the others get Detail. In the fresh demo the medical director's Review Queue shows 1 and has nothing to review: the one seeded request is already approved. The screen also counts the appeals still in review, and never shows that count.
In the demo1 requests
Check it yourselfCount the table rows: they match the heading, whatever their status. For work actually waiting on a reviewer, count only the rows with a Review button.
app/api/pa.py · list_pas()app/static/app.js · rPAs()Formula
IN_REVIEW (it passes through SUBMITTED inside the same save) · approve → APPROVED · deny → DENIED · pend → PENDED · provider responds to a pend → IN_REVIEW · withdraw → WITHDRAWN
appeal filed → APPEALED; appeal overturned or partially overturned → APPROVED, upheld → CLOSED
APPROVED whose valid-to date is before today (US Eastern business date) → EXPIREDWhy this wayMoves follow one transition table, and the decision paths refuse a move it does not allow. Two paths, the provider's response and the appeal decision, set the status directly, but only to moves the table allows. Only a medical director with an MD credential can deny, and only with a reason code and text. Expiry is applied by the automation sweep (every 15 minutes by default), so an authorization can read APPROVED for up to one sweep after its last valid day. PARTIALLY_APPROVED is a legal state that nothing writes: a partially overturned appeal leaves the request APPROVED, with a full authorization number.
In the demoPA-2026-40188 APPROVED
Check it yourselfApprove a request in the Review window: the toast and the badge both read APPROVED. The Audit Trail has one event for each move.
app/services/workflow.py · submit_pa()app/services/workflow.py · decide_pa()app/services/workflow.py · respond_to_pend()app/services/workflow.py · withdraw_pa()app/services/appeals.py · file_appeal()app/services/appeals.py · decide_appeal()app/services/workflow.py · expire_authorizations()Formula
IN_REVIEW; every other status shows '—'Why this wayThe clock keeps running while a request is PENDED: answering the pend does not restart it, and the column shows '—' for the whole pend (My Work's at-risk task does watch PENDED requests; see My Work, 'decision due in Hh'). Known defect: the list and the Review window receive the due time without a time zone, and a browser reads a time with no zone as its own local time. The countdown is off by the viewer's offset from UTC: a viewer on US Eastern time sees about 4 hours more than really remains, and a viewer in Pakistan about 5 hours less. The message after Submit PA receives the time with its zone, so it is correct, and for the same request it can disagree with the column by that offset. The 72 h and 7 days come from deployment settings; the labels 'Expedited — 72h SLA' and '7 calendar days' are fixed text.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfThe one seeded request is approved, so the fresh demo shows '—'. Launch a PA for John Doe's retinal exam: for a viewer on UTC the new row's chip reads 'in 6d 23h' (standard), and on US Eastern time about 'in 7d 3h' because of the defect above. Hover the chip to see the due time: it is UTC, printed without a zone.
app/services/workflow.py · submit_pa()app/api/pa.py · list_pas()app/api/pa.py · get_pa()app/static/app.js · relTime()app/static/app.js · slaChip()app/static/app.js · submitPA()Formula
Why this wayFixed thresholds in the browser, the same for request and appeal clocks. An expedited clock is 72 hours long, so it is amber from the moment it starts. These bands only colour the chip. They are separate from the points an approaching deadline adds to a task's rank on My Work (see Part I, Work-queue ranking). The same time-zone defect as the clock applies, so for a viewer far from UTC a chip can turn red hours early or late.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfNothing is on a clock in the fresh demo. Submit an expedited request: its chip is amber at once, while a standard request's chip is green.
app/static/app.js · relTime()Formula
Why this wayFrozen so that publishing a new policy version never rewrites the rules an open case is judged under; the decision trace records the same version. When nothing matched, the column prints a bare 'v' with no key: the request was still accepted, with no policy to review it against.
In the demoPA-2026-40188: UHC-MA-EYE-014 v3
Check it yourselfSign in as the policy administrator: Policy Packages lists UHC-MA-EYE-014 v3 as active for UnitedHealthcare Medicare Advantage, with 92250 among its codes.
app/api/pa.py · resolve_policy()app/api/pa.py · create_pa()Formula
Why this wayAn identifier, not a sequence. A gap between numbers is not a missing case, and the numbers carry no order or count. '2026' is fixed text, not the year of submission. Known limit: the space is 90,000 numbers shared by every tenant, and a repeated number fails the submission with a server error instead of drawing again.
In the demoPA-2026-40188
app/api/pa.py · create_pa()Formula
AUTH- + 8 random upper-case hex characters
valid from = the decision's business date (US Eastern); valid to = the business date 180 days later
'—' when the request was never approvedWhy this wayOne function mints both the number and the window, so a first approval and an overturned appeal cannot disagree on how long an authorization lasts. An overturn starts a new 180 days from the overturn date. The Detail window shows the number but not the dates, although the server returns them; they appear in the approval notification and the eligibility window. Known inconsistency in the demo: the seeded authorization was written directly, not through an approval, so its window is 90 days (valid from the day before the reset to 89 days after it) and not the 180 every real approval receives.
In the demoPA-2026-40188: AUTH-88213417
Check it yourselfApprove a request: the message ends '· AUTH-…', and the care manager's bell shows 'valid to' a date 180 days after today.
app/services/workflow.py · grant_authorization()app/services/workflow.py · decide_pa()app/services/appeals.py · decide_appeal()Formula
MET; in the chart but not attached, or not evidenced → UNKNOWN; when the check returns no criteria (no policy found), the browser's fixed C1–C3 MET are stored instead
model label = the fixed text apex-um v1.8
note stored = the text the browser sends, and the readiness narrative only when it sends noneWhy this wayNo model is involved: the advisory is the deterministic readiness check (see the Analytics chapter's readiness rows), which is why it can cite evidence and never invent it. It records a trace row and cannot change the case. Read the box with care. The label names a model version that does not exist. The browser always sends the same fixed sentence, '3/3 MET on available evidence. Approval probability high', so that sentence is what is stored, even for a four-criterion policy and even when the check found criteria it could not evidence. No approval probability is computed anywhere. On screen the note line is blank, because the window's data does not include the stored note.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfNo advisory exists in the fresh demo. As the UM nurse, open Review on a request and click Run criteria analysis: the box appears with the label apex-um v1.8, and the Detail window's trace gains an 'ai_advisory' row.
app/api/pa.py · ai_advisory()app/services/readiness.py · to_outcomes()app/static/app.js · runAI()app/static/app.js · reviewPA()Formula
APPROVED, deny → DENIED, pend → PENDED; the authorization number is added only on approval
criterion outcomes recorded = one of two fixed templates chosen in the window: 'ALL MET' (C1 C2 C3 all MET) or 'C2 UNKNOWN' (C1 C3 MET, C2 UNKNOWN)Why this wayThe status and number come back from the server, so the message cannot claim what was not saved. The outcomes do not come from the policy. The window offers two fixed three-criterion templates, whatever the policy says. The demo's retinal-exam policy has four criteria (C1 to C4), so a human decision records C4 as neither met nor unknown: it is absent. Read the trace's outcomes as the reviewer's selection, not as an evaluation of each criterion.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfAppears only after a decision. In the demo, sign in as md@demo.payer, Review the care manager's new request and Approve it. The message reads '<ref> → APPROVED · AUTH-…'.
app/services/workflow.py · decide_pa()app/api/pa.py · decision()app/static/app.js · decide()Formula
human), ai_advisory, peer_to_peer and provider_responseWhy this wayA count of recorded events, not of decisions: an advisory followed by an approval counts 2, and a peer-to-peer request counts as well. Known defect, visible in the fresh demo: the seeded approved authorization PA-2026-40188 shows a trace of 0 and the word 'none'. It was written into the database directly, not through the approval path that records the reviewer, so an APPROVED case has no recorded decision behind it.
In the demo0 rows
Check it yourselfOpen Detail on PA-2026-40188: 'Decision trace 0', then 'none'. Approve a new request and its Detail window shows 1 human row.
app/api/pa.py · get_pa()app/static/app.js · viewPA()Formula
approve deny pend withdrawn info_provided p2p_requested appeal_…; 'advisory' when none) · criteria v = the request's frozen policy version, 0 when it has noneWhy this wayThe criteria version is copied from the request, not looked up again, so the trace proves which version of the rules the case was judged under even after the policy moves on. The credential is the reviewer's own, from their login, which is how an adverse decision shows it came from a physician.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfEmpty in the fresh demo (see the count above). After an approval, the row reads 'human · MD-… | approve · criteria v3'.
app/services/workflow.py · decide_pa()app/api/pa.py · ai_advisory()app/api/pa.py · peer_to_peer()app/static/app.js · viewPA()Formula
Why this wayOpen and decided appeals are counted together, like the request count above. The screen also computes how many are still in review, and never shows that figure. Level-2 external reviews are counted when they exist, but no screen can create one: the endpoint has no button.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfNo appeal exists in the fresh demo, so the panel is hidden. Deny a request (as the medical director, with a reason), then file an appeal from its Detail window: the panel appears with 1.
app/api/appeals.py · list_appeals()app/static/app.js · rPAs()Formula
IN_REVIEW · decided: upheld → UPHELD, overturned → OVERTURNED, partially overturned → PARTIALLY_OVERTURNED
effect on the request: overturned or partially overturned → APPROVED with a new authorization number · upheld → CLOSEDWhy this wayOnly a denied request can be appealed, and only one appeal at a time. The decision is refused unless the reviewer is a medical director with an MD credential who did not issue the original denial, and an uphold needs a reasoned note of at least 10 characters. A partial overturn is treated exactly like a full one: the request becomes APPROVED, not partially approved.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfNeeds a denied, appealed request (see the appeals count). Decide it as a different medical director: the message reads 'Appeal overturned — PA APPROVED · AUTH-…'.
app/services/appeals.py · file_appeal()app/services/appeals.py · decide_appeal()app/static/app.js · decideAppeal()Formula
Why this wayThe '72h' is fixed text in the browser, and so is the '(72h)' in the medical director's notification. The clock actually applied is the tenant's appeal rule (72 hours unless the tenant changes it), so a tenant that sets 24 hours still sees '72h'. A Level-2 external review is never expedited.
In the demo— nothing to show in the fresh demo tenant
app/static/app.js · rPAs()app/services/appeals.py · appeal_rules()Formula
IN_REVIEWWhy this wayAppeal clocks are a tenant rule, while the request clock is a deployment setting: the two are configured in different places. The review window shows the chip only for expedited appeals. The same time-zone defect as the request clock applies to the panel. The message printed right after filing receives the time with its zone and is correct, so the two can differ for the same appeal by the viewer's offset from UTC.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfFile a standard appeal: the message reads 'independent review due in 29d 23h' or close to it. The panel's chip shows the same due time, shifted by the viewer's offset from UTC.
app/services/appeals.py · file_appeal()app/api/appeals.py · escalate_external()app/api/appeals.py · list_appeals()app/static/app.js · submitAppeal()app/static/app.js · appealReviewModal()Formula
Why this wayLine-of-business rules, not one universal clock, as the panel notes say. The deadline appears here only once it has passed. Two known limits. My Work's denied-authorization task names its own closing date using a flat 60 days for every line of business, so for a non-Medicare-Advantage denial it names a date 120 days earlier than this rule closes the window (see My Work, 'appeal window closes DATE'). And a tenant that sets its own per-line-of-business table replaces the default table entirely, so unless it restates Medicare Advantage's 60 days, Medicare Advantage falls back to the tenant's default window.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfThe demo has no denial, so the window never shows. A Medicare Advantage denial decided on 1 July (US Eastern) can be appealed until the same time of day on 30 August; after that, filing is refused with 'Appeal window closed 2026-08-30 (60 days for this line of business)'.
app/services/appeals.py · appeal_rules()app/services/appeals.py · file_appeal()Formula
Why this way'Not required' has to come from a policy that says so. A code that no policy on file lists is 'we do not know', never 'no': an unknown shown as unknown costs a phone call, and an unknown shown as 'no' costs a denied claim. The readiness panel answers the same question with the same resolver (see the Analytics chapter, 'Prior authorization required?').
In the demoPA REQUIRED under UHC-MA-EYE-014 v3
Check it yourselfThe screen asks through POST /pa/requirement-check, which writes an audit row, so this value is read through the readiness pre-check, which uses the same resolver. On John Doe's retinal exam (92250) the demo message reads 'PA REQUIRED under UHC-MA-EYE-014 v3' (runbook step 10).
app/api/pa.py · policy_answer()app/api/pa.py · requirement_check()app/static/app.js · startIntervention()Formula
Why this wayAttaching runs after the request is saved, one document at a time, so a failure to attach never loses the request; the message says how many made it. A document already attached counts as attached, because a repeat submission under the same idempotency key finds the request already bound to it, which is the intended end state.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfNo seeded chart holds an unattached document of a required type, so the fresh demo prints no 'N of M'. Upload a clinical note for the member first, then Submit PA: the message ends '1 of 1 found document attached'.
app/static/app.js · submitPA()Formula
Why this wayEmitted in the same save as the event, so a notification can never announce something that did not happen. Known limits. Read is one flag on the notification, not per person, so when one care manager opens a role-wide notification it disappears for every care manager. Unread items older than the newest 30 are never counted. A decision notifies the care manager role only, so the PA coordinator or provider who submitted the request is not told.
In the demo— nothing to show in the fresh demo tenant
Check it yourselfThe fresh demo has no notifications. After the medical director approves the care manager's request (runbook step 13), the care manager's bell shows 1: '<ref> approved', 'Auth AUTH-… · valid to <date>'.
app/api/appeals.py · my_notifications()app/api/appeals.py · mark_read()app/services/appeals.py · notify()app/static/app.js · refreshBell()The member's own view, signed in as the member (the demonstration member John Doe): what care is due, their visits, their prior authorizations, their messages and how they want to be contacted. It deliberately shows no risk tier, cost, contract or internal review detail.
Formula
active; payer, plan, effective from and to
no active coverage → the line is not shownWhy this wayThe member sees the plan the record says is active. Two limits, stated plainly: the query takes the FIRST active row with no ordering, so a member with two active coverages (for example a mid-year plan change not yet closed out) sees whichever the database returns first; and the line carries no verification caveat, while the care team's authorizations panel for the same member says the coverage has never been verified with the payer.
In the demoUnitedHealthcare MA Choice, 2026-01-01 to 2026-12-31
Check it yourselfThe care team's Patient 360 for the same member shows the same payer and plan.
app/api/member.py · profile()Formula
OPEN, IN_PROGRESS, SCHEDULED, AWAITING_AUTH or REOPENED
(the open-gap states GAP_OPEN_STATES minus SERVICE_COMPLETED); count = number of rows, no limit
'Why' = the reason the gap engine recorded when it opened the gapWhy this wayDeliberately narrower than every staff gap count: a gap in SERVICE_COMPLETED means the member has attended and the evidence is still on its way, so there is nothing left for the member to do and listing it would ask them to go again. The cost: this count can be LOWER than 'Open gaps' on the care team's Patient 360 summary strip for the same person, by the number of gaps awaiting evidence (in the fresh demo tenant both show 5). The list has no ordering (database order, not priority or due date), and the gap's due date is returned by the server but not shown, so an overdue item looks the same as one due at year end.
In the demo5 due: HbA1c Control — Glycemic Assessment; Diabetic Retinal Exam; Statin Adherence (PDC >= 80%); Blood Pressure Control; Annual Wellness Visit
Check it yourselfCount the table rows; open John Doe's Patient 360 as the care manager and compare with the Open gaps card (they differ only by gaps in SERVICE COMPLETED).
app/api/member.py · care()app/static/app.js · rMember()Formula
BOOKED, CONFIRMED, ARRIVED, COMPLETED, CANCELLED, NO_SHOW) and whether past or future; oldest first; no limitWhy this wayIt is the member's visit history, not a list of upcoming visits: a cancelled or missed visit still counts and still appears, with its status badge. A member reading the count as 'visits coming up' will over-read it once any visit is in the past or cancelled. The fresh demo member has no booked visit, so the panel shows 'No appointments'.
In the demo0 appointments
Check it yourselfWhen the care team books a visit for John Doe (it appears on his Patient 360 appointments list), sign in as the member: the count rises by one; cancelling the visit leaves the row, now marked CANCELLED, and the count unchanged.
app/api/member.py · appointments()Formula
Why this wayThe member sees status, dates and the specific reason they are entitled to for an adverse determination (CMS-0057-F), and nothing from the review itself: no reviewer notes, criteria evaluation or AI advisory, because exposing those would make the portal a discovery surface. The server also returns the submitted and decided dates and the authorization number, which the table does not show. Empty in the fresh demo tenant.
In the demo0 authorizations
Check it yourselfSubmit a prior authorization for John Doe as the provider or coordinator; it appears here with the same reference and status the PA queue shows.
app/api/member.py · authorizations()Formula
Engagement), newest first, every channel, both directions, any delivery status
count = rows returned, so it never exceeds 25 · '(you)' = the row's direction is inboundWhy this wayOne list across SMS, email, portal and voice, so a reply the member typed sits next to the message it answers. Limits, stated plainly: the count is capped at 25 with no sign that older messages exist; delivery status is not shown, so a message that failed to send still appears as if received; and a finished simulated call appears once, as its transcript on channel voice. The care team's contact history for the same member lists up to 40 entries and adds each call's own record (channel phone), so the two counts differ whenever a call has been made.
In the demo0 messages
Check it yourselfSend an outreach message to John Doe as the care manager, then sign in as the member: it appears at the top. Replying from the portal adds a row marked '(you)'.
app/api/member.py · messages()app/services/engagement.py · history()Formula
channel_opt_in[ch] is False)
as built: the profile the screen reads carries no consent record, so every box is tickedWhy this wayDEFECT, stated plainly: the screen reads me.preferences but the profile endpoint never returns it, so all three boxes render ticked whatever the member chose. A member who unticks SMS and saves sees SMS ticked again on reload, and the next Save writes it back as opted in. It also turns 'never asked' into 'opted in': the demo member's consent record has Voice never asked, the box shows it ticked, and one Save records a consent the member never gave. Two smaller gaps: the Portal channel has no box, and the staff screens label this channel 'Voice' where the portal says 'PHONE'. The consent rules themselves are the one consent authority described in Part I, Engagement ladder, wait times and the contact ceiling; the care team's consent table is in the Patient 360: coordination chapter.
In the demoticked: SMS, EMAIL, PHONE · consent record: sms opted in, email opted in, phone never asked
Check it yourselfUntick SMS, Save, reload the page: SMS is ticked again. The care manager's Patient 360 Engagement tab shows the member's real consent per channel.
app/static/app.js · rMember()app/api/member.py · profile()app/services/engagement.py · consent_state()The platform administrator's and auditor's screens: the tamper-evident audit trail and its verification, inbound data batches, payer policy packages, users and webhooks. Mostly records rather than calculations; the values below are the ones the product computes.
Formula
Why this wayEach event commits to the one before it, so changing, deleting or inserting any past event breaks every hash after it and the check names the first break. Nothing is trusted from storage: every hash is recomputed on each verification.
In the demointact
Check it yourselfPress Verify on the Audit screen: it recomputes the whole chain and reports the count checked.
app/core/audit.py · verify_chain()app/core/audit.py · _digest()Formula
Why this wayThe audit trail is append-only; these are plain counts of what it holds, so an auditor can see what kinds of activity exist before filtering to them.
In the demomoves with the clock — read it on screen
app/api/audit.py · list_events()app/api/audit.py · action_vocabulary()Formula
Why this wayEvery inbound row is accounted for, one outcome each, with the reason and the raw payload kept for a failed row: in the demo file one row names a member we do not hold and one carries the value 'pending' where a number is required. Known defect being fixed: the batch header's stored promoted/failed counters can lag the rows' own statuses (the header reads 1 promoted, 0 failed for this file); the row list is the authority.
In the demoquest_labs_2026-09-21.csv: 4 rows — 2 promoted, 1 rejected, 1 unmatched
app/services/ingest.py · promote()app/api/integration.py · batches()Formula
Why this wayPolicy is data, not code: the requirement check, the readiness criteria and the authorization screens all read these rows, so changing a policy changes every screen at once and the version is recorded on each decision.
In the demo3 packages, 2 require authorization
app/static/app.js · rAdmin()Formula
Why this wayA plain count of accounts; permissions come from the role (see the manual's permission matrix), never from the user row.
In the demo12 users, 0 with MFA
app/static/app.js · rAdmin()Formula
Why this wayOnly emitted events are offered, so a subscription can never be to a topic nothing publishes.
In the demo0 subscriptions, 25 topics
app/static/app.js · rAdmin()