feat(bib): --docket scope for backfill-comments; drop ocr stub from refarm
All checks were successful
CI / lint (push) Successful in 34s
CI / notebooks-smoke (push) Successful in 1m28s
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
Infra CI / notebooks (push) Successful in 3m33s
Infra CI / zotero (push) Successful in 23s
Infra CI / docs (push) Successful in 1m34s
Infra CI / api (push) Successful in 1m5s
Infra CI / llm (push) Successful in 49s
Infra CI / mc (push) Successful in 13s
Deploy / report (push) Successful in 15s
CI / test (push) Successful in 17m10s
Harden / build-scan-report (push) Successful in 18m38s
Notebooks Integration / notebooks-integration (push) Successful in 7m29s
Renovate / renovate (push) Successful in 18s
Zotero Sync / zotero-sync (push) Successful in 1m13s
Package Supply Chain / pkg-supply-chain (push) Successful in 1m0s

An unscoped 'bib backfill-comments' walks every un-enriched reg.gov
stub in the store (~167k) at the 970/hr rate cap — a week-long crawl
that buried the freshly farmed CMS-2026-2377 comments (highest item
ids, ORDER BY i.id) at the back of the queue and blocked the P37
extract/index chain behind it. backfill_details now takes docket=,
filtering on the store's reg-docket:<id> tag, and the CLI forwards
--docket. The September refarm script uses it, and no longer calls
comments extract-ocr, a phase-2 stub that always exits 2 (#253) and
would have logged a spurious failed step every run.

refs #615
This commit is contained in:
kert
2026-08-14 15:23:11 -04:00
parent f34600749a
commit a03801fb63
5 changed files with 82 additions and 4 deletions

View File

@@ -17,9 +17,10 @@ echo "=== re-farm run $(date -Is) ==="
FAILURES=0 FAILURES=0
uv run stack bib fetch-pfs-comments || { echo "WARN: fetch-pfs-comments rc=$?"; FAILURES=$((FAILURES+1)); } uv run stack bib fetch-pfs-comments || { echo "WARN: fetch-pfs-comments rc=$?"; FAILURES=$((FAILURES+1)); }
uv run stack bib backfill-comments || { echo "WARN: backfill rc=$?"; FAILURES=$((FAILURES+1)); } uv run stack bib backfill-comments --docket CMS-2026-2377 || { echo "WARN: backfill rc=$?"; FAILURES=$((FAILURES+1)); }
uv run stack comments extract --docket CMS-2026-2377 || { echo "WARN: extract rc=$?"; FAILURES=$((FAILURES+1)); } uv run stack comments extract --docket CMS-2026-2377 || { echo "WARN: extract rc=$?"; FAILURES=$((FAILURES+1)); }
uv run stack comments extract-ocr --docket CMS-2026-2377 || { echo "WARN: ocr rc=$?"; FAILURES=$((FAILURES+1)); } # extract-ocr is a phase-2 stub (always exits 2, no --docket) — see #253.
# ocr_needed attachments stay flagged in combined.md frontmatter for now.
uv run stack llm index --collection comments --docket CMS-2026-2377 \ uv run stack llm index --collection comments --docket CMS-2026-2377 \
|| { echo "WARN: index rc=$?"; FAILURES=$((FAILURES+1)); } || { echo "WARN: index rc=$?"; FAILURES=$((FAILURES+1)); }

View File

@@ -377,6 +377,7 @@ def backfill_details(
store: Store, store: Store,
client: Client, client: Client,
*, *,
docket: str = "",
limit: int | None = None, limit: int | None = None,
log_path: Path | None = None, log_path: Path | None = None,
commit_every: int = 25, commit_every: int = 25,
@@ -403,6 +404,19 @@ def backfill_details(
# Using a tag (not just the abstract) lets us handle "see attached" # Using a tag (not just the abstract) lets us handle "see attached"
# comments with near-empty body AND still drives distinct retry # comments with near-empty body AND still drives distinct retry
# states (``enriched:gone`` for 404s, untagged for transient fails). # states (``enriched:gone`` for 404s, untagged for transient fails).
docket_clause = ""
params: list[str] = []
if docket:
# Scope to one docket so a fresh farm enriches in hours, not the
# multi-day full-store crawl (reg.gov's 1000/hr cap is binding).
# ``reg-docket:`` is the store's docket tag (``docket:`` is the
# empty-valued wart — see llm/source.py).
docket_clause = """
AND i.id IN (
SELECT item_id FROM item_tags
WHERE tag_id IN (SELECT id FROM tags WHERE name = ?)
)"""
params.append(f"reg-docket:{docket}")
rows = con.execute( rows = con.execute(
""" """
SELECT i.id, i.key, i.url SELECT i.id, i.key, i.url
@@ -415,9 +429,11 @@ def backfill_details(
SELECT item_id FROM item_tags SELECT item_id FROM item_tags
WHERE tag_id IN (SELECT id FROM tags WHERE name IN ('enriched:ok','enriched:gone')) WHERE tag_id IN (SELECT id FROM tags WHERE name IN ('enriched:ok','enriched:gone'))
) )
ORDER BY i.id
""" """
+ (f" LIMIT {int(limit)}" if limit else "") + docket_clause
+ " ORDER BY i.id"
+ (f" LIMIT {int(limit)}" if limit else ""),
params,
).fetchall() ).fetchall()
stats = { stats = {

View File

@@ -338,6 +338,13 @@ def ingest_mail(
@app.command(name="backfill-comments") @app.command(name="backfill-comments")
def backfill_comments( def backfill_comments(
docket: str = typer.Option(
"",
"--docket",
help="Limit to one docket (e.g. CMS-2026-2377). Without it the "
"walk covers every un-enriched stub in the store — a multi-day "
"crawl at the reg.gov rate cap.",
),
limit: int = typer.Option( limit: int = typer.Option(
0, 0,
"--limit", "--limit",
@@ -374,6 +381,7 @@ def backfill_comments(
stats = backfill_details( stats = backfill_details(
store, store,
api, api,
docket=docket,
limit=limit or None, limit=limit or None,
log_path=log_path, log_path=log_path,
) )

View File

@@ -144,6 +144,43 @@ class TestUpsertComment:
class TestBackfillDetails: class TestBackfillDetails:
def test_docket_scope_limits_candidates(self, tmp_path):
"""docket= restricts the walk to that docket's stubs, so a
freshly farmed docket enriches without a full-store crawl."""
from bib.item import Item
from bib.store import Store
store = Store(str(tmp_path / "bib.sqlite"), storage_dir=tmp_path / "storage")
for docket, cid in [
("CMS-2026-2377", "CMS-2026-2377-0001"),
("CMS-2025-0304", "CMS-2025-0304-0001"),
]:
store.create(
Item(
item_type="source",
title=f"comment {cid}",
url=f"https://www.regulations.gov/comment/{cid}",
tags=["source:regulations-gov", f"reg-docket:{docket}"],
)
)
api = MagicMock()
api.get_comment_detail.return_value = {
"data": {"attributes": {"comment": "Body", "organization": "Org"}},
"included": [],
}
stats = backfill_details(
store,
api,
docket="CMS-2026-2377",
log_path=tmp_path / "log.txt",
scratch_root=tmp_path / "scratch",
)
store.close()
assert stats["enriched"] == 1
api.get_comment_detail.assert_called_once_with("CMS-2026-2377-0001")
def test_basic_enrichment(self, tmp_path): def test_basic_enrichment(self, tmp_path):
store = MagicMock() store = MagicMock()
con = MagicMock() con = MagicMock()

View File

@@ -343,6 +343,22 @@ class TestBackfillComments:
assert result.exit_code == 0 assert result.exit_code == 0
assert "enriched" in result.output assert "enriched" in result.output
@patch("bib.connect")
@patch("bib.regulations_gov.Client")
@patch("bib.regulations_gov.backfill_details", return_value={"enriched": 1})
def test_docket_forwarded(self, mc_backfill, mc_client_cls, mc_connect):
store = MagicMock()
mc_connect.return_value = store
api = MagicMock()
api.__enter__ = MagicMock(return_value=api)
api.__exit__ = MagicMock(return_value=False)
mc_client_cls.return_value = api
result = runner.invoke(app, ["backfill-comments", "--docket", "CMS-2026-2377"])
assert result.exit_code == 0
assert mc_backfill.call_args.kwargs["docket"] == "CMS-2026-2377"
class TestIngestIom: class TestIngestIom:
@patch("bib.connect") @patch("bib.connect")