An old rate and a missing rate are not the same note
A rate lookup used to have two states: an amount, or a 404. That's honest when the requested quarter is on file. It stops being honest the moment a quarter isn't — because "not found" and "CMS never published a file for that quarter, so the prior figures carried forward" are different facts, and only one of them means the data is missing.
We had the same problem one layer up. A code page showing the current CLFS lab rate doesn't say which release that rate is from unless you go looking. Most of the time the newest release on file is also the current quarter's. When it isn't, the page was silently serving a number without saying it might be behind.
Both are the same shape of bug: an answer presented with the same confidence whether or not it actually matches the period asked about. So we stopped letting either surface stay quiet about it.
What the API says now
A request for a quarter we don't have on file no longer just 404s. If a
nearby release can answer it, the response comes back with that release's
figures, a data_quality field set to approximate instead of exact, and a
notes array explaining why:
"data_quality": "approximate",
"notes": [
{
"code": "substituted_release",
"severity": "caution",
"message": "The 2024 Q1 MPFS file is not on file here; figures are from the 2023 Q4 release and may not reflect 2024 Q1 revisions."
}
]
Each note carries a stable code so you can branch on it in code instead of
parsing the sentence, and the same message is mirrored into the existing
warnings array for callers who only read that field. The code values are
part of the API contract — we won't rename or reuse one once it ships.
There are three codes, and the wording changes depending on which one fires:
no_quarterly_update_published(severityinfo) — CMS didn't publish anything for the requested quarter, so the prior release's figures stayed in effect the whole time. Nothing was missed; this is just how the rate behaved. "CMS did not list a 2024 Q2 MPFS file; figures from the 2024 Q1 file remained in effect."substituted_release(severitycaution) — we don't have a file for the requested quarter and can't say CMS skipped it, so we're answering from the nearest earlier release instead. "The 2024 Q1 MPFS file is not on file here; figures are from the 2023 Q4 release and may not reflect 2024 Q1 revisions."stale_release(severitycaution) — this is the CLFS-page version of the same idea, phrased for a live view rather than a specific lookup: "The 2024 Q1 CLFS file has not been ingested yet; figures shown are from the 2023 Q4 file."
The distinction between the first code and the other two is deliberate. "CMS didn't publish anything, so nothing changed" is a calmer fact than "we're missing a file and the real number might differ" — and handing a customer the wrong one either overstates our own lag as CMS's decision, or understates a real gap as if it were routine. Rate lookups used for appeals or reimbursement audits need to know which one they're looking at.
What the calculator shows
On the public CLFS code pages, an info-severity note doesn't interrupt the
page — the rate is correct and current, it's just annotated. A
caution-severity note — the file we'd need hasn't been ingested yet — gets
an amber "Data note:" banner under the rate so the staleness is impossible to
miss:
Data note: The 2024 Q1 CLFS file has not been ingested yet; figures shown are from the 2023 Q4 file.
That's the same asymmetry as the API: routine continuity stays quiet, an actual gap gets flagged.
The pattern
Neither change added a new data source or a new formula — both added a sentence, the right one, to an answer we were already computing. What made it worth doing carefully:
- a substituted release is not the same note as a stale one, because a point-in-time lookup and a live page fail differently when the newest file isn't the requested one;
- "CMS published nothing for this quarter" is not the same note as "we haven't ingested it yet," and asserting the wrong one misattributes the gap;
- and a free-form warning string is not a substitute for a stable code a customer can branch on, or a severity that decides whether a page banner fires at all.
An amount without provenance reads as more certain than it is. The fix wasn't a bigger disclaimer — it was naming, precisely, which kind of approximate the answer is, and saying so in the response itself.