# California Legislature Daily File - source specification
# Produced by research task t_a171f4d1 (software_engineer_programmer_analyst)
# Verified live: 2026-09-04 (PDT). Samples archived under ./samples/.
# Consumed by: t_f595542f (ingestion), t_fb8081e7 (parsing), t_8e5a3821 (RDB schema).
#
# IMPORTANT DESIGN NOTE (read first):
# The Assembly Daily File is a fully server-rendered HTML page with clean,
# data-attributed tables -> parse with BeautifulSoup/CSS selectors offline.
# The Senate "Daily File" is NOT HTML. senate.ca.gov/dailyfile is a Vue
# pdf-viewer wrapper with no parseable table; the publication itself is a
# PDF, served behind an antibot challenge. Senate parsing must go through
# a PDF text-extraction path (pdfplumber/PyMuPDF), with antibot mitigation.
meta:
generated: "2026-09-04"
verified_live: true
session_current: "2025-2026" # current regular session; used inside bill_id
notes: >
Per chamber we expose two independent concerns:
(a) the human-facing DAILY FILE (hearing schedule + floor items + committee items)
(b) the per-BILL canonical record (author, title, committee history) on leginfo.
The parent project (t_21cd58a9 section 2.5) requires correlating bills <-> committees
<-> committee members <-> legislators. For that we ALSO ingest leginfo bill
pages and committee rosters (see correlation_sources).
sources:
assembly_daily_file:
description: >
California State Assembly Daily File. Server-rendered HTML, no JS required
to read the data tables (data lives in static
markup with
data-* attributes). Always renders the CURRENT live daily file; there is
NO date query parameter that selects a historical daily file.
url:
canonical: "https://www.assembly.ca.gov/schedules-publications/daily-file"
aliases:
- "https://assembly.ca.gov/schedules-publications/daily-file"
- "https://assembly.ca.gov/dailyfile/pdfpublications"
legacy_help: "https://leginfo.ca.gov/help/dayfileh.html"
fetch:
method: GET
auth: none
requires_js: false
antibot: false
suggested_ua: "Mozilla/5.0 (research-scanner/1.0; +https://github.com/)"
content_type: "text/html; charset=UTF-8"
sample: "samples/assembly_dailyfile_latest.html"
parameters:
# Confirmed by probe: ?date=... and ?dailyfile=... are NOT honored; the
# page always returns the live file. "Date" is captured FROM the data
# (hearing dates in the hearing table), not from the URL.
by_url: []
historical_retrieval: >
No date-addressable URL. To obtain a historical daily file, fetch the
live page and record the as-of date; or pull from the Senate/Assembly
PDF publication archive (see senate_daily_file + assembly pdfmirror).
session: "derived from bill_id (leading 8 digits, 'YYYYYYYY')"
tables:
- id: committee_hearings
selector: "table.committee-hearing-table"
row: "tr[class*='committee-hearing-details']"
fields:
date:
selector: "td.committee_hearing-date"
best: "attr:data-sort"
note: "raw 'MM/DD/YY-###'; display text 'MM/DD/YY'"
time:
selector: "td.committee_hearing-time"
best: "text"
committee:
selector: "td.committee_hearing-name"
best: "attr:data-sort"
location:
selector: "td.committee_hearing-location"
best: "attr:data-sort"
agenda_id:
selector: "td.committee_hearing-menu a[href^='/api/dailyfile/agenda/']"
best: "href"
note: "Drupal AJAX id for detail view"
ics_url:
selector: "td.committee_hearing-menu a[href^='/api/ics/generate']"
best: "href"
xpath:
date: "//tr[contains(@class,'committee-hearing-details')]//td[contains(@class,'committee_hearing-date')]/@data-sort"
committee: "//tr[contains(@class,'committee-hearing-details')]//td[contains(@class,'committee_hearing-name')]/@data-sort"
agenda_id: "//tr[contains(@class,'committee-hearing-details')]//td[contains(@class,'committee_hearing-menu')]//a[starts-with(@href,'/api/dailyfile/agenda/')]/@href"
sample_row: |
| 08/31/26 |
Upon Call of the Chair |
Budget |
1021 O Street, Room 1100 |
- id: floor_bills
selector: "table.floor-bills-table"
row: "tr.class='floor-bill-details'"
fields:
bill_number:
selector: "td.floor_bill-measure a"
best: "attr:href"
parse: "extract bill_id, see bill_id_encoding"
bill_display:
selector: "td.floor_bill-measure a"
best: "text" # e.g. "AB 28"
supplement:
selector: "td.floor_bill-measure"
best: "text-after-br" # e.g. "Supplemental 2"
author:
selector: "td.floor_bill-author"
best: "attr:data-sort"
title:
selector: "td.floor_bill-subject"
best: "text" # short title / description
location:
selector: "td.floor_bill-location"
best: "attr:data-sort"
item_number:
selector: "td.floor_bill-item"
best: "text" # zero-padded; strip leading zeros
chamber:
derived: true
from: "bill_id"
note: "AB/ACR/HR -> Assembly-origin; SB/SCR/SJR -> Senate-origin"
date:
derived: true
note: "inherit hearing/date context or record as-of; not on this row"
xpath:
bill_number: "//tr[contains(@class,'floor-bill-details')]//td[contains(@class,'floor_bill-measure')]/a/@href"
author: "//tr[contains(@class,'floor-bill-details')]//td[contains(@class,'floor_bill-author')]/@data-sort"
title: "//tr[contains(@class,'floor-bill-details')]//td[contains(@class,'floor_bill-subject')]/text()"
item_number: "//tr[contains(@class,'floor-bill-details')]//td[contains(@class,'floor_bill-item')]/text()"
sample_row: |
AB 28 Supplemental 2 |
Schiavo et al. |
An act relating to solid waste, and making an appropriation therefor. |
Unfinished Business - Concurrence In Senate Amendments |
32 |
|
- id: committee_bills
selector: "table.committee-bills-table"
row: "tr[class*='committee-bills-details']"
fields:
bill_number:
selector: "td.committee_bill-number a"
best: "attr:href"
parse: "extract bill_id, see bill_id_encoding"
author:
selector: "td.committee_bill-author"
best: "attr:data-sort"
title:
selector: "td.committee_bill-subject"
best: "text"
committee:
selector: "td.committee_bill-committee"
best: "attr:data-sort"
xpath:
bill_number: "//tr[contains(@class,'committee-bills-details')]//td[contains(@class,'committee_bill-number')]/a/@href"
author: "//tr[contains(@class,'committee-bills-details')]//td[contains(@class,'committee_bill-author')]/@data-sort"
title: "//tr[contains(@class,'committee-bills-details')]//td[contains(@class,'committee_bill-subject')]/text()"
committee: "//tr[contains(@class,'committee-bills-details')]//td[contains(@class,'committee_bill-committee')]/@data-sort"
sample_row: |
|
SB 795 |
Archuleta |
Air pollution: gasoline vapor control systems: ethanol blends. |
Emergency Management |
bill_id_encoding:
template: "https://leginfo.legislature.ca.gov/faces/billNavClient.xhtml?bill_id={bill_id}"
bill_id_pattern: "^(?P\\d{8})\\d(?PAB|SB|ACR|SCR|HR|SJR|ABR)(?P\\d+)$"
fields:
session: "leading 8 digits 'YYYYYYYY' = 'YYYY-YYYY' (e.g. 20252026 == 2025-2026)"
chamber: "AB|SB|ACR|SCR|HR|SJR; ASSEMBLY origin = AB/ACR/HR/ABR, SENATE origin = SB/SCR/SJR"
number: "digits; zero-pad to 4 when writing back (AB 28 -> '0028')"
example: "bill_id '202520260AB28' -> session=2025-2026, chamber=AB, number=28 -> 'AB 28'"
extraction_notes: >
PREFER the 'data-sort' attribute over textContent: it holds the already-cleaned
canonical value (dates without the '-###' suffix, names/committees trimmed).
Fall back to textContent() when data-sort is absent or null.
Ignore td.floor_bill-view-details (contains a