comments: extract author/org metadata from attachment text #416
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Background
After the regulations.gov backfill + extraction pipeline (commits
8a09925→dfa2590→ sync to Zotero), every comment item in the Zotero library has acombined.mdattachment containing the inline body and full extracted text of every uploaded attachment.Item titles default to
Comment on <rule_id>(e.g.Comment on CMS-2025-0304-0009) because the regulations.gov APIfirstName/lastName/organizationfields are unpopulated for the bulk of submissions.upsert_commentalready prepends a byline when those fields are present (src/bib/regulations_gov.py), so the API path works — the data just isn't there.Problem
For most comments the real author and organization live inside the attachment itself: letterhead, signature line, "Submitted by:" preamble, the
From:field on PDFs, etc. Pulling these out turns ~23k anonymous-lookingComment on ...records into properly attributed items, which makes the corpus actually browsable in Zotero and citable downstream.Scope
combined.md(~23,610 items underdata/zotero/data/storage/<key>/combined.md).firstName,lastName,organizationon eachitemsrow indata/bib.sqlite.stack bib sync-zoteroalready carries those fields throughupsert_comment's byline logic, so once bib is updated the Zotero titles refresh on next sync.Approach options
Sincerely,\n<name>,On behalf of <org>, common letterhead structures). Misses scanned-image letterheads, image-only signatures, free-form prose.combined.mdonce, ask for{first_name, last_name, organization, role}. ~95% accuracy. Ballpark cost: 23k items × ~3k input tokens × $0.80/Mtok + ~50 output tokens × $4/Mtok ≈ $60. One-shot batch (messages.batches) → 50% off ≈ $30.Acceptance
stack comments extract-metadatawalks every Zotero combined.md, extracts{first_name, last_name, organization}, writes them to bib'sitemstable.first_nameororganizationis already set (or use a tag likemeta:extractedto mark processed items).stack bib sync-zoteroafterwards repopulates the byline-prefixed titles.combined.mdfrontmatter on next extract pass so the data lives next to the corpus.Notes / open questions
extra_jsonor as tags.Status update: all prerequisites are now in place — every comment item in Zotero carries its
combined.mdnote (#253 closed), the corpus is complete (#251 closed), andskin_subs.rulemaking_commentshascommenter_name/organizationcolumns waiting for backfilled values. The extraction heuristics (letterhead / signature / 'Submitted by:' parsing over ~23k attachments) are still to be built.Status audit (2026-08-13, repo-verified): NOT DONE. Only author/org signal is the LLM classifier's side fields (
rex/comments/classify.py:126-137) scoped to one docket's analytics table; nothing writes first/last/organization back to bib.sqlite, no frontmatter enrichment, no extract-metadata CLI.Premise check (2026-09-11), before anyone builds this: the data model has moved since this was filed.
Re-scoped plan when this is picked up: (1) regex/heuristic pass over the abstract and the first ~2k chars of extracted attachment text (letterhead, 'Sincerely,' signature blocks, 'on behalf of', 'From:'), writing first_name/last_name/organization to items and a meta:extracted tag; (2) local-LLM pass (qwen on the fleet, structured output, null allowed) only for items the regex left empty; (3) sync-zotero already carries the byline. Golden set of ~200 hand-checked items to measure both passes before the corpus-wide run — same gate shape as #577.