Skip to content

feat(sync): priority decode gate + hourly RSS newsdesk — spend drops to ~$0–2/day#90

Merged
cm2489 merged 3 commits into
mainfrom
feat/priority-decode-newsdesk
Jul 16, 2026
Merged

feat(sync): priority decode gate + hourly RSS newsdesk — spend drops to ~$0–2/day#90
cm2489 merged 3 commits into
mainfrom
feat/priority-decode-newsdesk

Conversation

@cm2489

@cm2489 cm2489 commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Implements the owner's 2026-07-16 spend directive: decode only legislation with real motion or real press, everything else tracked free.

Deadline note (the one merge that shouldn't wait)

Tonight's 07:30 UTC (3:30am ET) nightly cron runs UNGATED at cap 120 (~$8–18) unless this merges first. Merged before then, the backlog instead drains gated: ~$3–12 one-time, then the costs below.

Part 1 — priority decode gate

Data-driven line (corpus measured 2026-07-16): 79.5% of the 2,147 bills sit at 'committee', and 92.2% of those are literal referral-with-zero-action. The gate decodes only markup / floor_vote / passed_chamber / conference / signed / vetoed (~20.5% of today's corpus). Gate-skipped bills cost nothing, are never published, and re-enter automatically the moment Congress.gov shows new motion — the cursor advances past them, which drains the 29-day backlog nearly free. FORCE_DECODE_SLUGS (env + dispatch input) bypasses the gate; MAX_NEW_DECODES drops 120→60 as a pure safety ceiling.

Part 2 — newsdesk (hourly, free RSS, no new secrets)

Hourly Actions job over a politically balanced, live-verified feed basket (The Hill, Roll Call, NPR, Fox, CBS + a Google News congressional query; AP/Politico/WaPo feeds are dead — verified 2026-07-16). Matching, cheapest first: explicit-citation regex → free token overlap vs titles/press_names → one batched Haiku call only for leftovers (skipped when empty). Nonpartisan guardrail: t2/t3 matches fire only on ≥2 distinct outlets (citation matches are unambiguous and fire on one). On fire: free status refresh, or decode-before-publish capped 3/run and 10/day (code-enforced). No-change runs don't commit (no deploy churn); seen-set lives in actions/cache, not the repo.

Costs

typical day busy day hard ceiling
newsdesk ~$0 $0.12–0.57 ~$1.80 (enforced)
nightly gated decodes ~$0–1 $1–4 $4.20–9 (cap 60)

Also fixed here

mapStatus missed hyphenated "Mark-up" action text — 133 live bills with genuine committee activity read as mere 'committee' and would have been wrongly gated out. Two-token fix + pinning tests (orchestrator commit 3bac1ee). Congress-fetch's key check moved from import time to first call so its pure exports stay unit-testable.

Verification

76 new unit tests (gate table, citation regex hard cases, ≥2-outlet rule, no-commit guard) + full suite 1368 passed / 14 skipped / 0 failed; all repo gates green; re-run after the orchestrator's fix (78/78 on affected specs). Live mock proof: gated bill → no Anthropic call; markup bill → decodes; forced slug → bypasses. Built by a Sonnet 5 subagent; orchestrator independently verified the branch, caught the mapStatus gap from the agent's own report, and fixed it before this PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XexCqeBQ2csGYiBMC62p2G

cm2489 and others added 3 commits July 16, 2026 13:38
…s a decode

Owner directive: reduce spend right now by focusing the AI decode pass on
bills with real legislative motion, not the "majority… junk with high odds
of never going anywhere." A brand-new bill now only spends a decode if
mapStatus's output clears scripts/decode-gate.mjs's passesGate() (markup or
later); mere "referred to committee" — sampled at 1,573/1,706 (92.2%) of
today's 'committee'-status bills — does not.

Extracted the shared decode-before-publish path (fetchBillText/decode/
syncOneBill) out of sync-bills.mjs into scripts/bill-decode.mjs, taking
bills/es/bySlug/anthropic as explicit parameters instead of module-scope
closures, so the newsdesk (next commit) can decode a press-triggered bill
via the exact same path instead of a second copy of the prompts.

Gate-skipped bills are NOT stored and count as fully handled: the ascending
backlog pass's cursor advances past them exactly as if decoded, which drains
the multi-week decode backlog nearly for free. If a gated bill later gets
real motion, Congress.gov's own updateDate resurfaces it on a later run and
the gate re-evaluates. FORCE_DECODE_SLUGS (env + workflow_dispatch input)
bypasses the gate for specific slugs. MAX_NEW_DECODES reverts to a pure
safety ceiling (120 -> 60) now that the gate does the real limiting, and
per-run logging now reports new-bills-seen/gated/decoded so the digest-era
numbers stay honest.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New scripts/newsdesk.mjs + .github/workflows/newsdesk.yml (hourly, cron
'7 * * * *'), the news-headline trigger half of the owner's spend-reduction
ask, ALL-IN cost under $5/day. Free RSS only — NO paid news API (TheNewsAPI
stays sync-coverage.mjs's own quota) — a politically-balanced 6-feed basket
(The Hill/Roll Call/NPR/Fox/CBS + a Google News congressional-keyword query
carrying per-article outlet attribution), each verified live 2026-07-16 to
return real, parseable RSS/Atom.

Matching, cheapest first (scripts/newsdesk-match.mjs, a pure/I-O-free module
so it's unit-testable with zero mocking): t1 explicit bill-number citation
regex (hr/s/hjres/sjres only — "H. Res. 12" and "US 567" correctly excluded)
-> t2 free normalized-token overlap against corpus titles+press_names -> t3
ONE batched claude-haiku-4-5-20251001 call for headlines t2 leaves
ambiguous, skipped entirely when that batch is empty.

Nonpartisan guardrail (non-negotiable): a bill fires only on (a) an explicit
citation from any outlet, or (b) a t2/t3 match corroborated by >=2 distinct
outlets, accumulated across runs — single-outlet soft-match triggering would
be a prioritization channel data/media-bias.json's display-only lean
normalization doesn't cover. On fire, the bill refreshes (free) or, if not
yet in the corpus, decodes via the exact same decode-before-publish path as
sync-bills.mjs (force-bypassing the priority gate — the press trigger's own
corroboration is the worthiness signal here), bounded by both
NEWSDESK_DECODE_CAP=3/run and a NEWSDESK_DAILY_DECODE_CAP=10/day so the
documented <$2/day ceiling is code-enforced, not just expected. A
seen-headlines cache (actions/cache, GitHub's own 7-day-unused eviction)
dedupes across hourly runs and degrades gracefully on a cache miss. Never
writes data/coverage.json (stays sync-coverage.mjs's) or sync-state.json's
nightly cursor. Commits data/ only when scripts/newsdesk.mjs actually
changed something, so a no-op hour never triggers a deploy.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
133 live corpus bills carry the hyphenated spelling and would have been
wrongly gated out as mere 'committee'. Key check moves from import time to
first cg() call so the module's pure exports stay unit-testable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XexCqeBQ2csGYiBMC62p2G
@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
oravan Ready Ready Preview, Comment Jul 16, 2026 5:53pm

Request Review

@cm2489
cm2489 merged commit 2b873b3 into main Jul 16, 2026
3 checks passed
@cm2489
cm2489 deleted the feat/priority-decode-newsdesk branch July 16, 2026 17:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant