feat(official): CMS138 onboarded — 0/47 → 47/47, and the gate learned a new kind of claim - #366
Conversation
…k verdict pending CI The credentialed vendor workflow from #365 did its job. Run 30645615371: audit CMS138FHIRTobaccoScrnCessation 32 retrieved 31 shipped 1 ABSENT vendor sourced 2.16.840.1.113883.3.526.3.1278 from VSAC: absent from the upstream bundle → 4 codes @ Library/ecqm-fhir-update-2025 verify 32 value sets, 549 codes, truncated [] absent [] cms138: terminology complete — nothing capped, nothing absent So the artifact is complete and `scoring=proportion`, `populationBasis=boolean` — no episode-of-care problem like CMS68. Committed here with cms138 added to the gate map, to the case-count floor (47, counted from the sparse checkout: 47 case DIRECTORIES, the three non-directory entries are not cases), and to the CI + both deploy vendor lists. DELIBERATELY PUSHED WITH A STALE EVIDENCE REPORT. `docs/OFFICIAL_TESTCASE_REPORT` is regenerated by `pnpm test:official-cases`, which needs the gitignored terminology sidecar — and cms138's sidecar cannot be produced locally, because it needs the VSAC secret. Two guards in `official-gate.test.ts` fail locally for exactly that reason and they are RIGHT to: they say the report does not yet prove this artifact. CI runs the deck with the credential, and the report artifact it uploads is what gets committed next. That means this push is the measurement, not a claim. The completion is the weaker ADR-053 kind — upstream shipped no codes to check containment against and declared no total to check length against — so nothing in the vendoring can tell a correct expansion from a wrong one of the right size. 47 cases carrying the measure steward's own expected population vectors can. It was 0/47 with 47 errors. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3BNWAJwJJ5QjP1X6JpHUo
… an absent value set Measured by running it: with cms138 in the gate and a COMPLETE sidecar beside it, the deck scores 0/47 with 47 errors, every one 'Missing the following valuesets: …3.526.3.1278'. Byte-for-byte the pre-ADR-053 result. The cause is structural and the report states it plainly: 'ValueSets are consumed directly from each official measure Bundle; no VSAC network call or key is used.' The gate runs on UPSTREAM's terminology — which is what makes it an external check for the other five measures, and what makes it blind for this one, since the bundle is exactly what lacks the value set. So a sourced-absent value set is validated by NEITHER the vendoring (no containment or declared-total baseline) NOR the gate. ADR-053 said the gate covered it. It does not. What would: run the deck with the vendored sidecar as fqm's value-set cache — the mode the reduction check already models as `vendored-terminology-sidecar`. The codes are then ours while the EXPECTED VECTORS stay upstream's, which is real evidence about the codes and a weaker claim than the other five carry. Not built; must be labelled per-measure in the report when it is. CMS138 stays un-onboarded until then. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3BNWAJwJJ5QjP1X6JpHUo
…s not ship (ADR-053) Closes the gap the CMS138 run exposed: the MADiE gate executes each measure against the upstream bundle's own ValueSet resources, so a value set upstream omits cannot be resolved however complete our sidecar is. cms138 scored 0/47 with 47 errors, every one "Missing the following valuesets". "runOfficialMeasureCases" now accepts the artifact's runtime terminology and NARROWS it to the OIDs the bundle does not ship. The narrowing lives next to the calculate call it protects, not at the call site, because the natural thing for a caller to do is pass the whole cache — which would silently convert this gate from "upstream's terminology" into "ours" for every measure, with the deck still green and nothing to notice it. - The default path is unchanged and provably so: with nothing missing, calculate is invoked with THREE arguments exactly as before (the pre-existing assertion still passes) and the mode stays "measure-bundle". - A supplemented run records "supplementedOids", sets mode "measure-bundle+sourced-supplement", prints a console warning, and renders a per-measure paragraph in the report saying plainly that for those value sets the CODES are ours while the ANSWER KEY — the expected population vectors — stays upstream's. - The controls paragraph no longer claims terminology comes only from the bundle, which a supplemented run would have contradicted two lines later. Mutation-checked: unfiltered passthrough fails 5 tests; dropping the version-suffix normalization fails exactly the test written for it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3BNWAJwJJ5QjP1X6JpHUo
…lists conscious edits
- The CLI loads the artifact's runtime terminology BEFORE the gate run (it only did so
for the reduction check) and hands it to `runOfficialMeasureCases`, which narrows it.
A supplemented run is announced on stderr the same way a downgraded reduction check
already is — a weaker claim should not require diffing a markdown file to notice.
- `official-artifacts.test.ts`'s vendored list is hardcoded on purpose ("a new artifact
appearing unannounced is a review event"), so cms138 is a deliberate edit. Its comment
said cms138 "scores 0/47 because one value set will not expand" — that was the
misdiagnosis ADR-053 corrected, and it was still sitting in a test comment.
- Two CLI test doubles predated `supplementedOids` and threw on it, which surfaced as
the CLI returning exit 2 — reading as "the configuration was refused" rather than
"the fixture is incomplete".
Two failures remain locally and are CORRECT: the committed evidence report does not yet
cover cms138. It is regenerated by `pnpm test:official-cases`, which needs the
gitignored sidecar — producible only with the VSAC secret, i.e. only in CI. The next
push commits the report CI renders, and that report is where the CMS138 verdict appears.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q3BNWAJwJJ5QjP1X6JpHUo
…across six measures The committed evidence report, rendered by the credentialed CI run. CMS138 scores 47/47 with 0 unexpected mismatches and 0 errors, up from 0/47 with 47 errors. ADR-053 updated with the measured outcome, replacing the paragraph that said the supplement was "not yet built" and CMS138 "stays un-onboarded" — both true when written this morning and false now. WHAT 47/47 LICENSES, AND WHAT IT DOES NOT. For one value set the codes are OURS, sourced from VSAC at the pinned release, because upstream's bundle ships none. What stays upstream's is the ANSWER KEY — the expected population vectors. So agreement is real evidence the four sourced codes are right, and no evidence at all about upstream's terminology. Everything here exists to stop that being rounded off to "47/47 like the others": `supplementedOids` carries it in the data, the mode reads `measure-bundle+sourced-supplement`, the CLI says so on stderr, and the report prints it on the measure's own line rather than in a footnote. Also caught in this pass: I re-ran the ADR-writing script by accident and duplicated ADR-053. Found by grepping the heading count rather than by reading it, which is the only reason it did not ship — restored from HEAD and re-applied the edit cleanly. Suite 1764 pass / 0 fail / 15 skipped; typecheck clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3BNWAJwJJ5QjP1X6JpHUo
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bffec21738
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| pnpm vendor:official --measure CMS2FHIRPCSDepScreenAndFollowUp --catalog-id cms2 --strip-elm-annotations $COMPLETE | ||
| pnpm vendor:official --measure CMS68FHIRDocumentationCurrentMeds --catalog-id cms68 --strip-elm-annotations $COMPLETE | ||
| pnpm vendor:official --measure CMS951FHIRKidneyHealthEval --catalog-id cms951 --strip-elm-annotations $COMPLETE | ||
| pnpm vendor:official --measure CMS138FHIRTobaccoScrnCessation --catalog-id cms138 --strip-elm-annotations $COMPLETE |
There was a problem hiding this comment.
Keep uncredentialed fork CI from running CMS138 incomplete
When this job runs for a fork or Dependabot PR, GitHub withholds WORKWELL_VSAC_API_KEY_VENDOR, so lines 170–176 leave $COMPLETE empty. This new invocation then regenerates CMS138 with only the 31 upstream value sets; backend-ts/scripts/vendor-official-measure.mjs:507-515 explicitly says that the resulting artifact cannot run because the missing set requires --complete-terminology. The bundle-only reproducibility check still passes, but the workflow subsequently runs the default pnpm test:official-cases gate at lines 232–234, which now includes CMS138 and therefore reports all 47 cases as errors and exits nonzero. Condition the CMS138 invocation/gate for the uncredentialed path or otherwise provide a credentialless way to retain its validated supplement, so every external PR is not unconditionally red.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Correct and fixed in 895027d — thank you, this would have turned every external contributor's PR red on merge.
Your trace is exactly right: uncredentialed → $COMPLETE empty → cms138 re-vendored with only upstream's 31 value sets → the supplement has nothing to draw on → 47 errors → nonzero exit. And the bundle-only reproducibility check passes, so nothing upstream of the gate would have caught it.
--allow-missing-terminology skips a measure the CONTEXT cannot resolve, passed by CI only where steps.vendor.outputs.credentialed != 'true' — the same conditional the reproducibility check already splits on, and the same shape official-flip-config.test.ts uses to excuse the capped class.
The opt-OUT is the load-bearing half, so it is the one I pinned hardest: a credentialed run passes nothing and therefore skips nothing, because there an unresolvable value set means a broken artifact — which is the whole point of the gate. There is a test that supplies the SAME unresolvable OID without the flag and asserts the measure still runs, so the accommodation cannot quietly become the default.
Two consequences your comment did not have to reach, both handled:
- A skipped run is PARTIAL even though it asked for the full list, so it must not rewrite the committed report — otherwise CI's staleness check would read "current" on the very run that could not produce it. Extended the existing
--measureguard rather than adding a second one. - That staleness step is now credentialed-only, since an uncredentialed run deliberately leaves the report alone and the comparison would always differ.
The skip predicate is absentValueSets(artifact, requiredOids(artifact)) — the same one officialRoutingProblems refuses on — so "the gate skipped it" and "routing would refuse it" are one decision, not two that can drift.
Mutation-checked both ways: skipping regardless of the flag, and letting a partial run overwrite the report, each fail exactly one test.
…lly red (review, #366) GitHub withholds WORKWELL_VSAC_API_KEY_VENDOR from fork and Dependabot PRs, so CI re-vendors without --complete-terminology. For cms138 that regenerates a sidecar missing the value set upstream does not ship — there is nothing to supplement from, the deck cannot resolve it, and all 47 cases error. Every external contributor's PR would have failed for a reason unrelated to their change. Codex caught it before merge. `--allow-missing-terminology` skips a measure this CONTEXT cannot resolve, and CI passes it only where `steps.vendor.outputs.credentialed != 'true'` — the same shape the reproducibility check already uses, and the same shape official-flip-config.test.ts uses to excuse the capped class. THE OPT-OUT IS THE LOAD-BEARING HALF. A credentialed run passes nothing and therefore skips nothing: there an unresolvable value set means a broken artifact, which is what the gate exists to catch. Pinned by a test that supplies the SAME unresolvable OID without the flag and asserts the measure still runs. Two further consequences, both handled: - A run that skipped a measure is PARTIAL even though it asked for the full list, so it must not rewrite the committed report — otherwise CI's staleness check reads "current" on the very run that could not produce it. Extended the existing `--measure` guard. - That staleness step is now credentialed-only, since an uncredentialed run deliberately leaves the report alone and comparing against it would always differ. The skip predicate is `absentValueSets(artifact, requiredOids(artifact))` — the same one `officialRoutingProblems` refuses on — so "the gate skipped it" and "routing would refuse it" are one decision rather than two that can disagree. Mutation-checked: skipping regardless of the flag, and letting a partial run overwrite the report, each fail exactly one test. Suite 1767 pass / 0 fail / 15 skipped; typecheck clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3BNWAJwJJ5QjP1X6JpHUo
Result
CMS138: 0/47 with 47 errors → 47/47, 0 unexpected mismatches, 0 errors. The MADiE gate is now 278/278 across six measures.
Three things had to be true and only the first was: the value set had to be sourced, the artifact had to be complete, and the deck had to be able to see it.
1. Sourced
The credentialed workflow from #365 pulled
…3.526.3.1278("Tobacco Use Screening") from VSAC at the pinned release — 4 codes, where upstream ships none. Its verification step confirmedtruncated []/absent []before uploading, and refuses to upload anything less.2. The deck still said 0/47 — which falsified ADR-053
Every case errored with
Missing the following valuesets. ADR-053 had claimed "the real check on a sourced value set is the MADiE gate." The report explains why that's wrong in its own words:The gate runs on upstream's terminology. That is exactly what makes it a genuine external check for the other five — and exactly what makes it blind here, since the bundle is the thing lacking the set. A complete sidecar sat beside it the whole time, unread.
3. So the gate supplements — but only what upstream omits
runOfficialMeasureCasestakes the artifact's runtime terminology and narrows it to the OIDs the bundle does not ship.The narrowing lives next to the
calculatecall, not at the call site. The natural thing for a caller to do is pass the whole cache — which would quietly convert this gate from "upstream's terminology" into "ours" for every measure, deck still green, nothing to notice. With nothing missing,calculatetakes three arguments exactly as before; the pre-existing assertion pinning that still passes, which is what makes the five complete measures provably unaffected.What 47/47 licenses — and what it does not
For that one value set the codes are ours. What stays upstream's is the answer key — the expected population vectors. So agreement is real evidence the four sourced codes are right, and no evidence about upstream's terminology.
Everything here exists to stop that being rounded off to "47/47 like the others":
supplementedOidson the runmeasure-bundle+sourced-supplementmeasure-bundleThe report's controls paragraph no longer claims terminology comes only from the bundle — a supplemented run would have contradicted it two lines later.
Guards, mutation-checked
supplementForpasses everything through unfiltered|versionOID normalizationSmaller things caught
supplementedOidsand threw on it, surfacing as the CLI returning exit 2 — reading as "the configuration was refused" rather than "the fixture is incomplete".official-artifacts.test.ts's vendored list is hardcoded on purpose ("a new artifact appearing unannounced is a review event"), so cms138 is a deliberate edit.Still open
CMS130 and CMS165 are not vendored. Their blockers are capped expansions, which the gate handles today — no supplement needed. One workflow dispatch each.
Suite 1764 pass / 0 fail / 15 skipped; typecheck clean.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Q3BNWAJwJJ5QjP1X6JpHUo