test(pfs): no CPT descriptor text in tests or golden sets — fixture scrubbed, parenthetical and eight-word-run guards (C1)

This commit is contained in:
kert
2026-11-13 02:32:16 -05:00
parent 550f53112b
commit 3a18f63841
5 changed files with 188 additions and 7 deletions

View File

@@ -2,7 +2,7 @@
"PETM225D:1673": "The following is a summary of the comments we received and our responses.",
"PETM225D:1674": "Comment: The commenters supported our proposal to accept the CPT coding changes for Home or Residence Services codes.",
"PETM225D:1675": "Response: We appreciate the feedback from the commenters regarding our proposal, and are finalizing as proposed to adopt the CPT merger of the home and domiciliary visits into one family, and adopt the CPT codes as revised for reporting these services.",
"PETM225D:1676": "The RUC survey time includes pre-service time 3 days before the date of encounter, intraservice time on the date of encounter, and post-service time that includes 7 days after the date of encounter. These eight CPT codes were reviewed at the October 2021 RUC meeting with recommendations submitted to CMS for the CY 2023 rule cycle. The RUC recommended the survey 25th percentile value for all CPT codes in the Home or Residence Services code family, except for CPT code 99350, for which the RUC recommended the median value. We proposed the RUC-recommended work RVU for all eight CPT codes in the Home or Residence Services CPT code family. We proposed a work RVU of 1.00 for CPT code 99341 ( Home or residence visit for the evaluation and management of a new patient, which requires a medically appropriate history and/or examination and straightforward medical decision making), a work RVU of 1.65 for CPT code 99342 ( Home or residence visit for the evaluation and management of a new patient, which requires a medically appropriate history and/or examination and low level of medical decision making), a work RVU of 2.87 for CPT code 99344 ( Home or residence visit for the evaluation and management of a new patient, which requires a medically appropriate history and/or examination and moderate level of medical decision making), a work RVU of 3.88 for CPT code 99345 ( Home or residence visit for the evaluation and management of a new patient, which requires a medically appropriate history and/or examination and high level of medical decision making), a work RVU of 0.90 for CPT code 99347 ( Home or residence visit for the evaluation and management of an established patient, which requires a medically appropriate history and/or examination straightforward medical decision making), a work RVU of 1.50 for CPT code 99348 ( Home or residence visit for the evaluation and management of an established patient, which requires a medically appropriate history and/or examination and low level of medical decision making), a work RVU of 2.44 for CPT code 99349 ( Home or residence visit for the evaluation and management of an established patient, which requires a medically appropriate history and/or examination and moderate level of medical decision making), and a work RVU of 3.60 for CPT code 99350 ( Home or residence visit for the evaluation and management of an established patient, which requires a medically appropriate history and/or examination and high level of medical decision making).",
"PETM225D:1676": "The RUC survey time includes pre-service time 3 days before the date of encounter, intraservice time on the date of encounter, and post-service time that includes 7 days after the date of encounter. These eight CPT codes were reviewed at the October 2021 RUC meeting with recommendations submitted to CMS for the CY 2023 rule cycle. The RUC recommended the survey 25th percentile value for all CPT codes in the Home or Residence Services code family, except for CPT code 99350, for which the RUC recommended the median value. We proposed the RUC-recommended work RVU for all eight CPT codes in the Home or Residence Services CPT code family. We proposed a work RVU of 1.00 for CPT code 99341 ( [descriptor] ), a work RVU of 1.65 for CPT code 99342 ( [descriptor] ), a work RVU of 2.87 for CPT code 99344 ( [descriptor] ), a work RVU of 3.88 for CPT code 99345 ( [descriptor] ), a work RVU of 0.90 for CPT code 99347 ( [descriptor] ), a work RVU of 1.50 for CPT code 99348 ( [descriptor] ), a work RVU of 2.44 for CPT code 99349 ( [descriptor] ), and a work RVU of 3.60 for CPT code 99350 ( [descriptor] ).",
"PETM225D:1677": "We proposed the RUC-recommended direct PE inputs for CPT codes 99345 and 99347-99350 without refinement. For CPT codes 99341 and 99342, we are refining the direct PE inputs by removing supply item SK062 (patient education booklet). For CPT code 99344, we are refining the direct PE inputs by removing supply items SK062 (patient education booklet), SJ053 (swab-pad, alcohol), and SJ061 (tongue depressor). Per the PE Summary of Recommendations provided by the RUC, CPT codes 99341, 99342, 99344, and 99347 would typically have procedures performed on the same date of service. For those CPT codes, the RUC stated that they removed supplies that would be duplicative, such as gloves, alcohol wipes, booklet, and tongue depressor. However, we found that not all of these duplicative supplies had been removed from CPT codes ( printed page 69609) 99341, 99342, and 99344 by the RUC. Therefore, we proposed to remove these duplicative supplies from CPT codes 99341, 99342, and 99344, and accept the remaining RUC-recommended direct PE inputs without refinement.",
"PETM225D:1678": "The following is a summary of the comments we received and our responses.",
"PETM225D:1679": "Comment: The majority of commenters supported our proposal to accept the RUC-recommended RVUs for all of the Home or Residence Services codes.",
@@ -32,4 +32,4 @@
"9V89NVZG:1624": "Response: We are finalizing this policy change to remove the requirement that the medical record must document the medical necessity of furnishing the visit in the home rather than in the office, as proposed, effective January 1, 2019.",
"DE2VH9PD:864": "Response: We recognize the commenters' concerns with the use of G-codes. We agree that it is preferable to use CPT codes whenever possible. Under our finalized process, the use of G-codes for the purpose of holding over current coding and payment policies should not be necessary, generally, as long as we receive RUC recommendations for all new, revised and potentially misvalued codes before February 10th of the prior year. However, we need to preserve our ability to establish a proxy for current coding and values in situations where we receive the RUC recommendations too late or, for some other reason, encounter serious difficulty developing proposed values for revised code sets. In the proposed rule, we sought input as to ways to achieve this without using G-codes. The only suggestion offered by commenters was to value such codes on an interim final basis. As we discuss above, we believe the program and its stakeholders are better served by delaying revaluations for one year while we used the notice and comment process to obtain public comments in advance. The comments on this proposal were overall overwhelming supportive of this point of view. Accordingly, we are not foreclosing the possibility of using G-codes for this purpose when warranted by the circumstances. However, we are cognizant of the difficulties created by the use of G-codes and will seek to minimize their use. We also note that the RUC and stakeholders can assist us in minimizing the use of G-codes by taking steps to insure that we receive RUC recommendations as early as possible.",
"WHNGCYHB:3377": "Response: We recognize that reporting use of CEHRT under the QPP's Advancing Care Information performance category according to MIPS requirements will be new for many ECs and that it will take some time for ACOs and their ECs to gain some familiarity with the new reporting requirements for ACO-11. For this reason, we proposed and are finalizing a policy to treat ACO-11 as a newly introduced measure and to hold the ACO accountable for pay for reporting only for the first 2 years after the revised measure is introduced. However, to stress the importance of care coordination and support the use of CEHRT, we intend to phase in the measure to pay for performance according to the schedule outlined in Table 36 of the proposed rule (81 FR 46421-46422) and as indicated in Table 42 of this final rule. Consistent with our established policies for setting quality performance benchmarks for new measures, a new benchmark for this measure will be set based on the data gathered during the two pay for reporting years after the measure is introduced."
}
}

View File

@@ -119,8 +119,8 @@ def test_cms_summary_template():
def test_comment_first_sentence_is_cms_words_without_cpt_text():
para = (
"Comment: One commenter requested clarification on CPT codes 99347 and "
"99348 ( Home visit for the evaluation and management of an established "
"patient (two of three)) and ( printed page 84506) more. Second sentence."
"99348 ( Descriptor (two of three)) and ( printed page 84506) more. "
"Second sentence."
)
assert dos.comment_first_sentence(para) == (
"One commenter requested clarification on CPT codes 99347 and 99348 "

View File

@@ -492,8 +492,7 @@ class TestNewKinds:
781,
"From our re-review of the AMA RUC recommendations, we do note that in "
"the text material accompanying the RUC recommendation for CPT code "
"76000 ( Fluoroscopy (separate procedure), up to 1 hour physician or "
"other qualified health care professional time) codes or language was "
"76000 ( [descriptor] (two parts)) codes or language was "
"struck from the text material. It is unclear if the reference to CPT "
"code 76000 was intentionally deleted, but we note that CPT code 76000 "
"has a work RVU value of 0.30 and an intra-service time of 10.0 minutes.",

View File

@@ -0,0 +1,182 @@
"""No CPT descriptor text in the repository's tests and golden sets (the
user's rule: no AMA/CPT descriptor text in the repo; final review C1).
Two guards over every tracked test module, test fixture and golden set:
* a CPT code followed by a parenthesized descriptor of the kind CMS prints
in a rule ("99341 ( Home or residence visit for ...)"): runs everywhere,
CI included;
* any run of eight words shared with a ``pfs.cpt_code`` descriptor (the
licensed books' text): runs only where the replica holds that table.
A HCPCS Level II code's descriptor is CMS's own text (public domain), so a
parenthetical or colon clause after one (G0318, the placeholder GXXX3) is
not scanned for the eight-word runs.
"""
from __future__ import annotations
import re
import subprocess
import unicodedata
from functools import cache
from pathlib import Path
import pytest
from conf import connect
ROOT = Path(__file__).resolve().parents[2]
#: a five-digit code, then "(" and a capitalized word, a lower-case word and
#: at least 60 more characters on the line before a ")": a descriptor CMS
#: printed. "(codes ...)", "(a range ...)", "(see ...)" and a placeholder
#: such as "( [descriptor] )" are not descriptors.
DESCRIPTOR_PAREN = re.compile(
r"\b\d{5}\s*\(\s*(?!codes?\b|a range\b|see\b)[A-Z][a-z]+ [a-z]+ [^\n]{60,}?\)"
)
RUN = 8
#: files outside this plan that hold descriptor text on purpose, reported
#: in final-fix-report.md for the user's decision (R103 scope); the list is
#: never added to
KNOWN_EXEMPT = frozenset(
{
# descriptor-parser tests that predate Plan A (P49, 2026-09-09)
"tests/pfs/test_cpt_load.py",
"tests/pfs/test_descriptors.py",
"tests/pfs/test_elements.py",
"tests/pfs/test_extract.py",
"tests/pfs/fixtures/cpt_sample.xhtml",
# the market tier's own AMA-guard test input (6a45806), another
# builder's file; reported in final-fix-report.md, never added to
"tests/market/test_fts.py",
}
)
#: a HCPCS Level II code (or a proposed-rule placeholder) and the start of
#: its descriptor
_HCPCS_LEAD = re.compile(r"\b(?:[A-V]\d{4}|[A-Z]XXX\d)\s*([(:])")
def _scanned(rel: str) -> bool:
parts = Path(rel).parts
if rel.startswith("src/pfs/golden/"):
return True
if parts[:1] != ("tests",):
return False
return "fixtures" in parts or rel.endswith(".py")
@cache
def _files() -> tuple[str, ...]:
"""The tracked files the guards read (every file on disk under the same
paths when git is unavailable)."""
try:
out = subprocess.run(
["git", "ls-files", "-z", "--", "tests", "src/pfs/golden"],
cwd=ROOT,
capture_output=True,
check=True,
).stdout.decode()
rels = [r for r in out.split("\0") if r]
except (OSError, subprocess.CalledProcessError): # pragma: no cover
rels = [
str(p.relative_to(ROOT))
for base in ("tests", "src/pfs/golden")
for p in (ROOT / base).rglob("*")
if p.is_file()
]
return tuple(r for r in sorted(rels) if _scanned(r) and (ROOT / r).is_file())
def _text(rel: str) -> str:
try:
return (ROOT / rel).read_text(encoding="utf-8")
except UnicodeDecodeError: # pragma: no cover - binary fixture
return ""
def _words(text: str) -> list[str]:
return re.findall(r"[a-z0-9]+", unicodedata.normalize("NFKC", text).lower())
def _runs(words: list[str]) -> set[tuple[str, ...]]:
"""Eight-word runs with at least six words of letters (a list of codes
is not a run)."""
runs = (tuple(words[i : i + RUN]) for i in range(len(words) - RUN + 1))
return {run for run in runs if sum(w.isalpha() for w in run) >= 6}
def without_hcpcs_text(text: str) -> str:
"""*text* without the descriptor after each HCPCS Level II code: a
balanced parenthetical, or a colon clause to the end of its line or
quoted string."""
out, i = [], 0
for m in _HCPCS_LEAD.finditer(text):
if m.start() < i:
continue
j = m.end()
if m.group(1) == "(":
depth = 1
while j < len(text) and depth:
depth += {"(": 1, ")": -1}.get(text[j], 0)
j += 1
else:
stop = re.search(r'["\n]', text[j:])
j = j + stop.start() if stop else len(text)
out.append(text[i : m.end()])
i = j
out.append(text[i:])
return "".join(out)
def test_descriptor_parenthetical_pattern_catches_the_shape():
shape = "99999 ( Lorem ipsum " + "dolor sit amet " * 6 + "end)"
assert DESCRIPTOR_PAREN.search(shape)
for fine in (
"99341 ( [descriptor] ) and more",
"CPT codes 99341 (codes 99341 through 99350 are listed here in full) x",
"99343 ( Short text)",
"G0318 is not a five-digit code (Lorem ipsum dolor sit amet " * 3 + ")",
):
assert not DESCRIPTOR_PAREN.search(fine), fine
def test_hcpcs_level_two_text_is_set_aside():
text = 'code G0318 ( Lorem (ipsum) dolor) stays, "GXXX3: lorem ipsum" ok'
assert without_hcpcs_text(text) == 'code G0318 ( stays, "GXXX3:" ok'
def test_no_cpt_descriptor_parentheticals_in_tests_or_golden_sets():
hits = [
f"{rel}: {m.group(0)[:80]}"
for rel in _files()
for m in DESCRIPTOR_PAREN.finditer(_text(rel))
]
assert hits == []
_REPLICA = connect._replica_path("aco")
@pytest.mark.skipif(not _REPLICA.exists(), reason="live replica")
def test_no_eight_word_run_shared_with_a_cpt_descriptor():
con = connect.duckdb("aco", replica=True)
try:
rows = con.execute(
"SELECT DISTINCT descriptor FROM pfs.cpt_code WHERE descriptor IS NOT NULL"
).fetchall()
except Exception as exc: # noqa: BLE001 - only a missing table skips
pytest.skip(f"no pfs.cpt_code on the replica ({exc})")
finally:
con.close()
book: set[tuple[str, ...]] = set()
for (d,) in rows:
book |= _runs(_words(d))
hits = []
for rel in _files():
if rel in KNOWN_EXEMPT:
continue
shared = _runs(_words(without_hcpcs_text(_text(rel)))) & book
if shared:
hits.append(f"{rel}: {' '.join(sorted(shared)[0])}")
assert hits == []

View File

@@ -335,7 +335,7 @@ def test_cy2008_nprm_table_10_parses_with_the_data_row_columns():
# ── paragraph source ─────────────────────────────────────────────────
DESC = "( Home or residence visit for the evaluation and management of a patient)"
DESC = "( Descriptor text omitted)"
P1676 = (
"The RUC survey time includes pre-service time 3 days before the date of "
"encounter. These eight CPT codes were reviewed at the October 2021 RUC "