7.0 KiB
eCFR Jump Links — Bidirectional CFR Cite ↔ URL (P41)
Date: 2026-08-17. Milestone: P41. Requested as: "the same [as P40's FR jump links] for eCFR — so a CFR cite goes back and forth."
Verified ground truth (2026-08-17)
https://www.ecfr.gov/current/title-42/section-425.400(short form) 302-redirects server-side to the canonical hierarchy URL (/current/title-42/chapter-IV/subchapter-B/part-425/subpart-E/section-425.400) — cite → URL needs no structure lookup; fragments survive redirects client-side.- Paragraph anchors on section pages are semantic:
id="p-425.400(c)(1)(iv)"— the fragment IS the cite's paragraph path (316 such anchors on § 425.400). Both directions are therefore deterministic string transforms. - The eCFR versioner API is open (
/api/versioner/v1/titles.jsonresponds), but the plain/cite/permalink endpoint 406s for non-browser clients — irrelevant, the short form covers it. - bib holds 699
item_type='regulation'items with eCFR URLs — both part-level (…/title-42/part-414) and section-level (…/part-405/section-405.534) — the Title 42/45 Regulations collections. These are the placement targets and the validation index.
Decisions (inherited from P40's user-selected pattern)
Consumers: all (notebooks, :pincite:, Zotero child links, CLI).
Addressing: cite (with/without paragraph path), URL (inverse), both
directions. Persistence: no anchor grab needed — the transform is
deterministic; the bib regulation index provides context/validation.
Placement discipline: only place()d links reach Zotero.
Architecture
src/bib/cfrlink.py — parse, transmute, context, place. Hooks:
bib/pincite.py (jump_url covers the existing cfr locator type),
notebook helper cfr_md(), CLI stack bib cfr-jump. Zotero placement
reuses the P40 fr_links table + _sync_fr_links path unchanged
(rows carry page=0 and p_id=NULL for non-FR links — the sync only
reads label/url; documented here rather than forking a parallel
table).
Data model
CfrCite frozen dataclass: title: int, part: str, section: str ("425.400", empty for part-level cites), paras: tuple[str, ...] (("c","1","iv")), date: str ("" = current).
Parse (parse_cite(ref) -> CfrCite)
Accepted spellings (case-insensitive, C.F.R. dots optional, §
optional, whitespace collapsed):
42 CFR 425.400(c)(1)(iv)/42 C.F.R. § 425.400(c)(1)(iv)42 CFR § 414.1425/42 CFR 414.1450(b)(1)42 CFR Part 425/42 CFR part 425 subpart E(subpart ignored for URL purposes — the short form resolves placement) Title is required (bare§ 425.400raises naming the reason — the title selects the eCFR tree). Paragraph path parsed from consecutive parenthesized tokens.
Transmute
url(cite) -> str: section:https://www.ecfr.gov/current/title-{t}/section-{s}+ (#p-{s}({a})({b})…when paras present); part:https://www.ecfr.gov/current/title-{t}/part-{p}; date-pinned:/on/{date}/replaces/current/whencite.date.cite_of(url) -> str: inverse over every eCFR URL form — short, canonical full-hierarchy,/on/{date}/, with or without#p-…fragment. Emits the canonical spelling42 CFR 425.400(c)(1)(iv)(part-level:42 CFR Part 425).- Round-trip law:
cite_of(url(parse_cite(x)))== canonical spelling ofx, andurl(parse_cite(cite_of(u)))reproducesu's short form — tested explicitly.
Bib context + placement
item_for(cite, store) -> str | "": match against regulation items' eCFR URLs — exact section item first, then the part item. Powers placement targets and lightweight validation ("is this cited reg in the library?"); a cite with no library item still transmutes (URL construction never requires the store).place(store, ref, *, label="") -> JumpLink: resolve +item_for(raises when no regulation item matches — placed links need a parent), upsert intofr_links(page=0), synced by the existing_sync_fr_linksas linkMode=3 children.md_link(ref, *, text="")— store-free (deterministic URL).- CLI:
stack bib cfr-jump REF [--md] [--place [--label L]]andstack bib cfr-jump --url URLfor the reverse direction (prints the cite).
:pincite:
Pincite.jump_url gains the cfr branch: locators like
42 CFR 425.400(c) resolve through cfrlink (no store data needed);
non-title locators (§ 3.2-style, classified section) stay
URL-less. Degradation contract unchanged ("", never raise).
Notebook
cfr_md() helper beside fr_md() (same graceful fallback shape, but
store-free); the CY2027 notebook's 42 CFR 414.1450(b)(1) (APM
revival), § 414.1425(c)(5)(ii) (QP alignment — spelled with title),
and the PQM section's 42 CFR § 425.400(c) cites become live eCFR
links. Gate: nb_integration.py single-notebook run.
Testing
- Parse: every accepted spelling + reject-without-title + part form.
- Transmute: URL forms incl. date pin and fragments;
cite_ofover short/canonical/dated/fragmented URLs; both round-trip laws. - Context:
item_forsection-over-part preference against a fixture store;placeon a regulation item; sync reuses the P40 linkMode=3 tests' path (one new test: CFR-placed row syncs identically). - Live smoke:
url(parse_cite("42 CFR 425.400(c)(1)(iv)"))fetches 200 with the fragment's anchor present in the body.
Out of scope
- eCFR structure/versioner grabs (no data needed for the transform; revisit only if full-hierarchy canonical URLs or historical snapshots become requirements).
- Quote → paragraph addressing for CFR text (would need section text ingestion; FR quotes already cover the rulemaking corpus).
- Auto-creating regulation items for cites not in the library.
P41 build outcomes (2026-08-17)
Issues #639–#641, milestone P41 (5 commits, b872d7d..HEAD, direct on main; TDD throughout).
- #639 (
b872d7d):bib/cfrlink.pypure transmuter — 23 tests incl. both round-trip laws; live smoke: the generated…/section-425.400#p-425.400(c)(1)(iv)URL returns 200 with the fragment's anchor present in the body. - #640:
item_for(exact-section beats part over the 699 regulation items),place()reusingfr_links(page=0) and the untouched_sync_fr_linkspath,cfr-jumpCLI with--urlreverse mode. Live: all three rollout cites matched exact section-level regulation items (74YXT4TC / HFY6IREA / 95PQGJRP). - #641:
Pincite.jump_urlcfr branch (store-free); notebookcfr_md()helper + live eCFR links for42 CFR 414.1450(b)(1),42 CFR 414.1425(c)(5)(ii),42 CFR 425.400(c)(gatepass=1, in-container resolution proven); placed links synced via--tag source:ecfr(699 items, all URL-dedupe skips,fr_links: 3) onto the pre-existing Zotero regulation items (GEZXDVQ9 / AEHYQWRZ / 47GK4BZE — Zotero held the regs under pre-bib keys; the sync's URL dedupe attached children to them exactly as designed). - Note:
cite_ofon a date-pinned URL returns the undated canonical cite (the date is a view parameter, not part of the citation) — by design, documented here.