Files
stack/docs/superpowers/specs/2026-08-17-ecfr-jump-links-design.md
kert 77751de9fc
All checks were successful
CI / lint (push) Successful in 32s
CI / notebooks-smoke (push) Successful in 1m29s
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 56s
Infra CI / zotero (push) Successful in 13s
Infra CI / docs (push) Successful in 1m26s
Infra CI / api (push) Successful in 1m1s
Infra CI / llm (push) Successful in 52s
Infra CI / mc (push) Successful in 22s
Deploy / report (push) Successful in 13s
CI / test (push) Successful in 13m16s
Notebooks Integration / notebooks-integration (push) Successful in 7m55s
Zotero Sync / zotero-sync (push) Successful in 1m21s
Package Supply Chain / pkg-supply-chain (push) Successful in 58s
docs(spec): P41 build outcomes; plan checked off (refs #639-#641)
2026-08-17 15:08:32 -04:00

7.0 KiB
Raw Blame History

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.json responds), 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.400 raises 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/ when cite.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 spelling 42 CFR 425.400(c)(1)(iv) (part-level: 42 CFR Part 425).
  • Round-trip law: cite_of(url(parse_cite(x))) == canonical spelling of x, and url(parse_cite(cite_of(u))) reproduces u'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 into fr_links (page=0), synced by the existing _sync_fr_links as linkMode=3 children.
  • md_link(ref, *, text="") — store-free (deterministic URL).
  • CLI: stack bib cfr-jump REF [--md] [--place [--label L]] and stack bib cfr-jump --url URL for 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_of over short/canonical/dated/fragmented URLs; both round-trip laws.
  • Context: item_for section-over-part preference against a fixture store; place on 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.py pure 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() reusing fr_links (page=0) and the untouched _sync_fr_links path, cfr-jump CLI with --url reverse mode. Live: all three rollout cites matched exact section-level regulation items (74YXT4TC / HFY6IREA / 95PQGJRP).
  • #641: Pincite.jump_url cfr branch (store-free); notebook cfr_md() helper + live eCFR links for 42 CFR 414.1450(b)(1), 42 CFR 414.1425(c)(5)(ii), 42 CFR 425.400(c) (gate pass=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_of on a date-pinned URL returns the undated canonical cite (the date is a view parameter, not part of the citation) — by design, documented here.