fix(bib,llm): rule kind from the rule's own text — proposed rules were labelled 'final' because CMS titles since CY2018 carry no kind word (refs #691 #692)
Some checks failed
CI / lint (push) Successful in 29s
CI / notebooks-smoke (push) Successful in 1m27s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / llm (push) Has been skipped
Deploy / mc (push) Has been skipped
CI / test (push) Has been cancelled
Deploy / report (push) Has been cancelled
Infra CI / zotero (push) Has been cancelled
Infra CI / docs (push) Has been cancelled
Infra CI / api (push) Has been cancelled
Infra CI / llm (push) Has been cancelled
Infra CI / mc (push) Has been cancelled
Infra CI / notebooks (push) Has been cancelled
Some checks failed
CI / lint (push) Successful in 29s
CI / notebooks-smoke (push) Successful in 1m27s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / llm (push) Has been skipped
Deploy / mc (push) Has been skipped
CI / test (push) Has been cancelled
Deploy / report (push) Has been cancelled
Infra CI / zotero (push) Has been cancelled
Infra CI / docs (push) Has been cancelled
Infra CI / api (push) Has been cancelled
Infra CI / llm (push) Has been cancelled
Infra CI / mc (push) Has been cancelled
Infra CI / notebooks (push) Has been cancelled
bib.frlink.rule_kind decides proposed/final/correction from the FR paragraphs
("this proposed rule"/"we propose" vs "this final rule"/"we are finalizing";
a Correction title wins outright); the title is only the fallback and an
undecidable rule is labelled 'rule', never 'final'. All 80 grabbed PFS rules
classify correctly (30 proposed, 28 final, 22 corrections) — ten post-2017
proposed rules (incl. the CY2027 NPRM 5ITGVDJV and XFGGRBDH) were 'final' before.
Lineage labels, the collapse tie-break and the golden audio-only label use it.
This commit is contained in:
@@ -434,6 +434,83 @@ def resolve(
|
|||||||
# ── Transmutations + rendering ──────────────────────────────────────
|
# ── Transmutations + rendering ──────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
RULE_KINDS = ("proposed", "final", "correction", "rule")
|
||||||
|
|
||||||
|
# A rule's own body text says what it is: a proposed rule refers to itself
|
||||||
|
# as "this proposed rule" and says "we propose"/"we are proposing"; a final
|
||||||
|
# rule says "this final rule" and "we are finalizing"/"we finalized" (and
|
||||||
|
# "we proposed", past tense, which these patterns deliberately exclude).
|
||||||
|
_PROPOSED_SIGNALS = (
|
||||||
|
"%this proposed rule%",
|
||||||
|
"%we propose %",
|
||||||
|
"%we are proposing%",
|
||||||
|
)
|
||||||
|
_FINAL_SIGNALS = (
|
||||||
|
"%this final rule%",
|
||||||
|
"%we are finalizing%",
|
||||||
|
"%we finalized%",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _signal_count(con: Any, item_key: str, patterns: tuple[str, ...]) -> int:
|
||||||
|
where = " OR ".join("text LIKE ?" for _ in patterns)
|
||||||
|
row = con.execute(
|
||||||
|
f"SELECT count(*) FROM fr_anchors WHERE item_key = ? AND ({where})", # noqa: S608
|
||||||
|
(item_key, *patterns),
|
||||||
|
).fetchone()
|
||||||
|
return int(row[0]) if row else 0
|
||||||
|
|
||||||
|
|
||||||
|
def kind_from_title(title: str) -> str:
|
||||||
|
"""``proposed`` / ``final`` / ``correction`` from a rule's title, else
|
||||||
|
``rule``. Titles are the FALLBACK only — since CY2018 the CMS titles
|
||||||
|
("Medicare and Medicaid Programs; CY 2027 Payment Policies Under the
|
||||||
|
Physician Fee Schedule …") carry no proposed/final word at all."""
|
||||||
|
t = (title or "").lower()
|
||||||
|
if "correction" in t or "correcting amendment" in t:
|
||||||
|
return "correction"
|
||||||
|
if "proposed" in t:
|
||||||
|
return "proposed"
|
||||||
|
if "final" in t:
|
||||||
|
return "final"
|
||||||
|
return "rule"
|
||||||
|
|
||||||
|
|
||||||
|
def rule_kind(store: Store, item_key: str, *, title: str | None = None) -> str:
|
||||||
|
"""What kind of FR document *item_key* is: ``proposed``, ``final``,
|
||||||
|
``correction`` or ``rule`` (undecidable — never claim ``final``
|
||||||
|
without evidence).
|
||||||
|
|
||||||
|
A title that says "Correction" wins outright — a correction notice
|
||||||
|
quotes the rule it corrects, so its text is not evidence of its
|
||||||
|
own kind. Otherwise the rule's OWN paragraphs decide
|
||||||
|
(``fr_anchors``): the proposed/final self-reference counts are
|
||||||
|
decisive when one is at least three times the other. Measured on
|
||||||
|
the 80 grabbed PFS rules (2001–2026) every proposed and final rule
|
||||||
|
is decisive this way, including the ten post-2017 proposed rules
|
||||||
|
whose titles never say "Proposed". Short notices with no
|
||||||
|
self-references fall back to the title (``kind_from_title``).
|
||||||
|
|
||||||
|
*title* may be passed by a caller that already holds the item
|
||||||
|
(saves the ``store.get`` round trip); ``None`` fetches it, and an
|
||||||
|
unknown item is ``rule``."""
|
||||||
|
if title is None:
|
||||||
|
try:
|
||||||
|
title = store.get(item_key).title
|
||||||
|
except Exception: # noqa: BLE001 — unknown item: undecidable, not "final"
|
||||||
|
title = ""
|
||||||
|
if kind_from_title(title) == "correction":
|
||||||
|
return "correction"
|
||||||
|
con = store._con() # noqa: SLF001
|
||||||
|
proposed = _signal_count(con, item_key, _PROPOSED_SIGNALS)
|
||||||
|
final = _signal_count(con, item_key, _FINAL_SIGNALS)
|
||||||
|
if proposed and proposed >= 3 * final:
|
||||||
|
return "proposed"
|
||||||
|
if final and final >= 3 * proposed:
|
||||||
|
return "final"
|
||||||
|
return kind_from_title(title)
|
||||||
|
|
||||||
|
|
||||||
def page_of(store: Store, item_key: str, p_id: int) -> int:
|
def page_of(store: Store, item_key: str, p_id: int) -> int:
|
||||||
"""The printed FR page a paragraph anchor sits on."""
|
"""The printed FR page a paragraph anchor sits on."""
|
||||||
row = _anchor_row(store._con(), item_key, p_id) # noqa: SLF001
|
row = _anchor_row(store._con(), item_key, p_id) # noqa: SLF001
|
||||||
|
|||||||
@@ -299,15 +299,30 @@ class LineageEvidence:
|
|||||||
|
|
||||||
|
|
||||||
def rule_label(
|
def rule_label(
|
||||||
title: str, date_published: str, p_id: int, *, vol: str = "", page: int = 0
|
title: str,
|
||||||
|
date_published: str,
|
||||||
|
p_id: int,
|
||||||
|
*,
|
||||||
|
vol: str = "",
|
||||||
|
page: int = 0,
|
||||||
|
kind: str = "",
|
||||||
) -> str:
|
) -> str:
|
||||||
"""``"CY2021 PFS final 85 FR 84639 ¶1578"`` when *vol*/*page* are
|
"""``"CY2021 PFS final 85 FR 84639 ¶1578"`` when *vol*/*page* are
|
||||||
known (Ruling B13 — ``I2``), else the shorter
|
known (Ruling B13 — ``I2``), else the shorter
|
||||||
``"CY2021 PFS final ¶1578"`` / ``"CY2027 PFS proposed ¶394"``.
|
``"CY2021 PFS final ¶1578"`` / ``"CY2027 PFS proposed ¶394"``.
|
||||||
``proposed`` when *title* contains "Proposed" (case-insensitive),
|
|
||||||
else ``final``; the year from ``rule_year_of``."""
|
*kind* is ``proposed`` / ``final`` / ``correction`` / ``rule`` as
|
||||||
|
decided by ``bib.frlink.rule_kind`` from the rule's own text (the
|
||||||
|
chat passes it via ``_rule_kind``). Without it the title decides
|
||||||
|
(``bib.frlink.kind_from_title``) — and a title that says neither
|
||||||
|
labels the row ``rule``, never ``final``: since CY2018 the CMS
|
||||||
|
titles carry no proposed/final word, and a proposed rule presented
|
||||||
|
as final is a false statement of policy. The year comes from
|
||||||
|
``rule_year_of``."""
|
||||||
|
from bib.frlink import kind_from_title # bib is an optional extra
|
||||||
|
|
||||||
year = rule_year_of(title, date_published)
|
year = rule_year_of(title, date_published)
|
||||||
kind = "proposed" if "proposed" in (title or "").lower() else "final"
|
kind = kind or kind_from_title(title)
|
||||||
if vol and page:
|
if vol and page:
|
||||||
return f"CY{year} PFS {kind} {vol} FR {page} ¶{p_id}"
|
return f"CY{year} PFS {kind} {vol} FR {page} ¶{p_id}"
|
||||||
return f"CY{year} PFS {kind} ¶{p_id}"
|
return f"CY{year} PFS {kind} ¶{p_id}"
|
||||||
@@ -377,6 +392,10 @@ class _ReplicaCache:
|
|||||||
_ITEM_CACHE = _ReplicaCache()
|
_ITEM_CACHE = _ReplicaCache()
|
||||||
_URL_CACHE = _ReplicaCache()
|
_URL_CACHE = _ReplicaCache()
|
||||||
_PARAGRAPH_CACHE = _ReplicaCache()
|
_PARAGRAPH_CACHE = _ReplicaCache()
|
||||||
|
#: item_key -> "proposed"/"final"/"correction"/"rule" (bib.frlink.rule_kind),
|
||||||
|
#: keyed on the bib mtime like the item cache: the answer reads the rule's
|
||||||
|
#: paragraphs, so a re-grab can change it.
|
||||||
|
_KIND_CACHE = _ReplicaCache()
|
||||||
#: code -> on-demand EventRow list — keyed on the DuckDB REPLICA's mtime
|
#: code -> on-demand EventRow list — keyed on the DuckDB REPLICA's mtime
|
||||||
#: (passed explicitly by callers): on-demand lineage is derived from
|
#: (passed explicitly by callers): on-demand lineage is derived from
|
||||||
#: ``pfs.rvu``/``pfs.code_event``, which live on the replica, not the
|
#: ``pfs.rvu``/``pfs.code_event``, which live on the replica, not the
|
||||||
@@ -431,7 +450,36 @@ def _source_label(store: Any, item_key: str, p_id: int, mtime: int) -> str:
|
|||||||
if para is not None:
|
if para is not None:
|
||||||
vol = str(para.get("fr_volume") or "")
|
vol = str(para.get("fr_volume") or "")
|
||||||
page = para.get("page") or 0
|
page = para.get("page") or 0
|
||||||
return rule_label(item.title, item.date_published, p_id, vol=vol, page=page)
|
return rule_label(
|
||||||
|
item.title,
|
||||||
|
item.date_published,
|
||||||
|
p_id,
|
||||||
|
vol=vol,
|
||||||
|
page=page,
|
||||||
|
kind=_rule_kind(store, item_key, mtime),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _rule_kind(store: Any, item_key: str, mtime: int) -> str:
|
||||||
|
"""``bib.frlink.rule_kind`` for *item_key*, cached per item on the
|
||||||
|
bib mtime; ``rule`` (undecided) when the store can't answer — a
|
||||||
|
label must never say ``final`` on a failure path."""
|
||||||
|
if store is None or not item_key:
|
||||||
|
return "rule"
|
||||||
|
cached = _KIND_CACHE.get(item_key, mtime)
|
||||||
|
if cached is not _MISSING:
|
||||||
|
return cached
|
||||||
|
try:
|
||||||
|
from bib.frlink import rule_kind
|
||||||
|
|
||||||
|
item = _cached_item(store, item_key, mtime) # one Store.get per item
|
||||||
|
title = (item.title or "") if item is not None else ""
|
||||||
|
kind = rule_kind(store, item_key, title=title)
|
||||||
|
except Exception as e: # noqa: BLE001
|
||||||
|
log.warning("lineage rule kind unresolved (%s): %s", item_key, e)
|
||||||
|
kind = "rule"
|
||||||
|
_KIND_CACHE.put(item_key, mtime, kind)
|
||||||
|
return kind
|
||||||
|
|
||||||
|
|
||||||
def _fr_url(store: Any, item_key: str, p_id: int, mtime: int) -> str:
|
def _fr_url(store: Any, item_key: str, p_id: int, mtime: int) -> str:
|
||||||
@@ -499,16 +547,12 @@ def _resolve_prompt_urls(
|
|||||||
|
|
||||||
|
|
||||||
def _is_proposed(store: Any, item_key: str, mtime: int) -> bool:
|
def _is_proposed(store: Any, item_key: str, mtime: int) -> bool:
|
||||||
"""True when *item_key*'s title contains "proposed" — ``False`` (not
|
"""True when ``bib.frlink.rule_kind`` decides *item_key* is a
|
||||||
"unknown") for an empty *item_key* or a *store*-less caller, which
|
proposed rule (from the rule's own text, title as fallback) —
|
||||||
|
``False`` for an empty *item_key* or a *store*-less caller, which
|
||||||
keeps every ``_pref_key`` caller that doesn't have a store (existing
|
keeps every ``_pref_key`` caller that doesn't have a store (existing
|
||||||
tests, mostly) exactly as deterministic as before Ruling B12."""
|
tests, mostly) exactly as deterministic as before Ruling B12."""
|
||||||
if store is None or not item_key:
|
return _rule_kind(store, item_key, mtime) == "proposed"
|
||||||
return False
|
|
||||||
item = _cached_item(store, item_key, mtime)
|
|
||||||
if item is None:
|
|
||||||
return False
|
|
||||||
return "proposed" in (item.title or "").lower()
|
|
||||||
|
|
||||||
|
|
||||||
def _pref_key(
|
def _pref_key(
|
||||||
|
|||||||
@@ -360,3 +360,90 @@ class TestQuoteTieBreak:
|
|||||||
with pytest.raises(ValueError, match="matches 2 paragraphs"):
|
with pytest.raises(ValueError, match="matches 2 paragraphs"):
|
||||||
frlink.resolve("shared quote text appears here", store=s)
|
frlink.resolve("shared quote text appears here", store=s)
|
||||||
s.close()
|
s.close()
|
||||||
|
|
||||||
|
|
||||||
|
# ── rule_kind ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
def _store_with_text(title: str, paragraphs: list[str]) -> tuple[Store, str]:
|
||||||
|
s, key = _store_with_rule()
|
||||||
|
s._con().execute("UPDATE items SET title = ? WHERE key = ?", (title, key)) # noqa: SLF001
|
||||||
|
s._con().executemany( # noqa: SLF001
|
||||||
|
"INSERT INTO fr_anchors (item_key, p_id, page, ordinal, text) VALUES (?,?,?,?,?)",
|
||||||
|
[(key, i + 1, 100, i + 1, text) for i, text in enumerate(paragraphs)],
|
||||||
|
)
|
||||||
|
s._con().commit() # noqa: SLF001
|
||||||
|
return s, key
|
||||||
|
|
||||||
|
|
||||||
|
class TestRuleKind:
|
||||||
|
def test_proposed_from_text_when_the_title_says_nothing(self) -> None:
|
||||||
|
s, key = _store_with_text(
|
||||||
|
"Medicare and Medicaid Programs; CY 2027 Payment Policies Under the PFS",
|
||||||
|
[
|
||||||
|
"In this proposed rule we propose to update the conversion factor.",
|
||||||
|
"We are proposing to revise the telehealth list.",
|
||||||
|
"Commenters on the CY 2026 final rule asked for more time.",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert frlink.rule_kind(s, key) == "proposed"
|
||||||
|
|
||||||
|
def test_final_from_text_when_the_title_says_nothing(self) -> None:
|
||||||
|
s, key = _store_with_text(
|
||||||
|
"Medicare and Medicaid Programs; CY 2025 Payment Policies Under the PFS",
|
||||||
|
[
|
||||||
|
"After considering comments, we are finalizing the policy as proposed.",
|
||||||
|
"In this final rule we finalized the APCM codes.",
|
||||||
|
"We proposed the change in the CY 2025 PFS proposed rule.",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert frlink.rule_kind(s, key) == "final"
|
||||||
|
|
||||||
|
def test_past_tense_we_proposed_is_not_a_proposed_signal(self) -> None:
|
||||||
|
s, key = _store_with_text(
|
||||||
|
"Medicare Program; CY 2021 Payment Policies Under the PFS",
|
||||||
|
["We proposed this in July. We are finalizing it now in this final rule."],
|
||||||
|
)
|
||||||
|
assert frlink.rule_kind(s, key) == "final"
|
||||||
|
|
||||||
|
def test_silent_text_falls_back_to_the_title(self) -> None:
|
||||||
|
s, key = _store_with_text(
|
||||||
|
"Medicare Program; CY 2016 PFS Correction", ["Corrections to page 1."]
|
||||||
|
)
|
||||||
|
assert frlink.rule_kind(s, key) == "correction"
|
||||||
|
s2, key2 = _store_with_text("Medicare Program; CY 2005 PFS Proposed Rule", [])
|
||||||
|
assert frlink.rule_kind(s2, key2) == "proposed"
|
||||||
|
|
||||||
|
def test_undecidable_is_rule_never_final(self) -> None:
|
||||||
|
s, key = _store_with_text("Medicare Program; Revisions to Payment Policies", [])
|
||||||
|
assert frlink.rule_kind(s, key) == "rule"
|
||||||
|
|
||||||
|
def test_unknown_item_is_rule(self) -> None:
|
||||||
|
s, _ = _store_with_rule()
|
||||||
|
assert frlink.rule_kind(s, "NOPE0000") == "rule"
|
||||||
|
|
||||||
|
def test_kind_from_title(self) -> None:
|
||||||
|
assert frlink.kind_from_title("CY 2025 PFS Proposed Rule") == "proposed"
|
||||||
|
assert frlink.kind_from_title("CY 2025 PFS Final Rule") == "final"
|
||||||
|
assert (
|
||||||
|
frlink.kind_from_title("CY 2025 PFS Final Rule; Correction") == "correction"
|
||||||
|
)
|
||||||
|
assert frlink.kind_from_title("CY 2025 Payment Policies") == "rule"
|
||||||
|
|
||||||
|
def test_correction_title_wins_over_the_quoted_text(self) -> None:
|
||||||
|
"""A correction notice quotes the rule it corrects ("this final
|
||||||
|
rule …"), so its text is not evidence of its own kind."""
|
||||||
|
s, key = _store_with_text(
|
||||||
|
"Medicare Program; CY 2025 PFS Final Rule; Correction",
|
||||||
|
[
|
||||||
|
"On page 97864 of this final rule, we are finalizing … is corrected to read"
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert frlink.rule_kind(s, key) == "correction"
|
||||||
|
|
||||||
|
def test_title_kwarg_skips_the_item_lookup(self) -> None:
|
||||||
|
s, key = _store_with_text("x", ["In this proposed rule we propose a change."])
|
||||||
|
assert (
|
||||||
|
frlink.rule_kind(s, "NOPE0000", title="CY 2005 PFS Final Rule") == "final"
|
||||||
|
)
|
||||||
|
assert frlink.rule_kind(s, key, title="") == "proposed"
|
||||||
|
|||||||
@@ -66,7 +66,9 @@
|
|||||||
- item_key: XFGGRBDH
|
- item_key: XFGGRBDH
|
||||||
p_id: 489
|
p_id: 489
|
||||||
expect_labels:
|
expect_labels:
|
||||||
- 'CY2025 PFS final .*¶489'
|
# XFGGRBDH is the CY2025 *proposed* rule (91 FR, 2024-07-31); its title
|
||||||
|
# carries no "Proposed", so the kind must come from the rule's text.
|
||||||
|
- 'CY2025 PFS proposed .*¶489'
|
||||||
expect_events:
|
expect_events:
|
||||||
- code: "99441"
|
- code: "99441"
|
||||||
kind: deleted|disappeared|cpt_deleted
|
kind: deleted|disappeared|cpt_deleted
|
||||||
|
|||||||
@@ -148,6 +148,17 @@ class _FakeStore:
|
|||||||
"A temporary crosswalk between G2058 and new CPT code "
|
"A temporary crosswalk between G2058 and new CPT code "
|
||||||
"99439 (with a descriptor identical to G2058).",
|
"99439 (with a descriptor identical to G2058).",
|
||||||
),
|
),
|
||||||
|
# The proposed rule decides its kind from its own text —
|
||||||
|
# bib.frlink.rule_kind counts "this proposed rule"/"we
|
||||||
|
# propose" against "this final rule"/"we are finalizing".
|
||||||
|
(
|
||||||
|
"ZPROP2027",
|
||||||
|
394,
|
||||||
|
32388,
|
||||||
|
1,
|
||||||
|
"In this proposed rule we propose to keep the three-step "
|
||||||
|
"telehealth review.",
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -214,14 +225,44 @@ def _gd(
|
|||||||
|
|
||||||
|
|
||||||
class TestRuleLabel:
|
class TestRuleLabel:
|
||||||
def test_final(self):
|
def test_title_without_a_kind_word_is_rule_not_final(self):
|
||||||
|
"""Since CY2018 the CMS titles say neither "Proposed" nor
|
||||||
|
"Final"; without a decided kind the label must not claim
|
||||||
|
``final`` (a proposed rule presented as final is a false
|
||||||
|
statement of policy)."""
|
||||||
assert (
|
assert (
|
||||||
rule_label(
|
rule_label(
|
||||||
"Medicare Program; CY 2021 Payment Policies Under the PFS",
|
"Medicare Program; CY 2021 Payment Policies Under the PFS",
|
||||||
"2020-12-28",
|
"2020-12-28",
|
||||||
1578,
|
1578,
|
||||||
)
|
)
|
||||||
== "CY2021 PFS final ¶1578"
|
== "CY2021 PFS rule ¶1578"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_final_from_title(self):
|
||||||
|
assert (
|
||||||
|
rule_label("Medicare Program; CY 2015 PFS Final Rule", "2014-11-13", 1251)
|
||||||
|
== "CY2015 PFS final ¶1251"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_kind_from_the_rule_text_overrides_the_title(self):
|
||||||
|
"""The chat passes ``kind`` decided by ``bib.frlink.rule_kind``
|
||||||
|
from the rule's own paragraphs — a title that says nothing
|
||||||
|
still labels a proposed rule ``proposed``."""
|
||||||
|
assert (
|
||||||
|
rule_label(
|
||||||
|
"Medicare and Medicaid Programs; CY 2027 Payment Policies",
|
||||||
|
"2026-07-16",
|
||||||
|
394,
|
||||||
|
kind="proposed",
|
||||||
|
)
|
||||||
|
== "CY2027 PFS proposed ¶394"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_correction_from_title(self):
|
||||||
|
assert (
|
||||||
|
rule_label("Medicare Program; CY 2016 PFS Correction", "2016-03-08", 12)
|
||||||
|
== "CY2016 PFS correction ¶12"
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_proposed(self):
|
def test_proposed(self):
|
||||||
@@ -242,6 +283,7 @@ class TestRuleLabel:
|
|||||||
1578,
|
1578,
|
||||||
vol="85",
|
vol="85",
|
||||||
page=84639,
|
page=84639,
|
||||||
|
kind="final",
|
||||||
)
|
)
|
||||||
== "CY2021 PFS final 85 FR 84639 ¶1578"
|
== "CY2021 PFS final 85 FR 84639 ¶1578"
|
||||||
)
|
)
|
||||||
@@ -253,6 +295,7 @@ class TestRuleLabel:
|
|||||||
"2020-12-28",
|
"2020-12-28",
|
||||||
1578,
|
1578,
|
||||||
vol="85",
|
vol="85",
|
||||||
|
kind="final",
|
||||||
)
|
)
|
||||||
== "CY2021 PFS final ¶1578"
|
== "CY2021 PFS final ¶1578"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user