Formatted, versioned legislative data for District of Columbia. Part of the govbot civic data project.
This Chi Hack Night project transforms Open States scraper output into a git-native, filesystem-friendly structure.
This enables a few things:
- Free Unlimited Git Powered Legislative Data Analysis: The raw data is as simple as a
git pull. - Event Source Data Analysis: Replay a session from our immutable event logs, making for a paper-trail.
- Easier AI Analysis: Plain text legislation with files/folders works with a number of different tools.
- Decentralize Government Data: Because We the People
Just git clone this repo β everything under country:us/ is the dataset.
This is the formatted data repo for District of Columbia β one of two repos per jurisdiction:
- Scraper repo (
govbot-openstates-scrapers/dc-legislation) β runs OpenStates scrapers, produces raw scraped JSON - This repo (
dc-legislation) β reads the scraper repo's output and:- π§Ό Sanitizes the data by removing ephemeral fields (
_id,scraped_at) for deterministic output - π§ Formats it into a blockchain-style, versioned structure with incremental processing
- π Links events to bills and sessions automatically
- π©Ί Monitors data quality by tracking orphaned bills
- π Extracts full text from bills, amendments, and supporting documents (PDFs, XMLs, HTMLs)
- π Commits the formatted output and extracted text nightly (or manually), with auto-save
- π§Ό Sanitizes the data by removing ephemeral fields (
This split keeps scraping (which can be blocked/rate-limited per state) independent from formatting/extraction, and keeps every jurisdiction's repo consistent, auditable, and easy to maintain.
- π Incremental Processing - Only processes new or updated bills (no duplicate work!)
- πΎ Auto-Save Failsafe - Commits progress during long text-extraction runs, and auto-restarts if a run times out
- π©Ί Data Quality Monitoring - Tracks orphaned bills (votes/events without bill data)
- π Bill-Event Linking - Automatically connects committee hearings and events to bills
- β±οΈ Timestamp Tracking - Two-level timestamps for logs and text extraction
- π― Multi-Format Text Extraction - XML β HTML β PDF with fallbacks
- π Detailed Error Logging - Categorized errors for easy debugging
This repo is generated and kept up to date by actions/pipeline-manager in the main chihacknight/govbot repo β it is not set up by hand.
To change District of Columbia's configuration (branch pinning, runner, enabled jobs, labels), edit its entry in chn-openstates-files.yml and re-run apply.py β don't hand-edit the workflow files in this repo directly, since the next apply.py run will overwrite them.
Current settings for District of Columbia:
- State code:
dc - Toolkit branch:
main - Scraper repo:
govbot-openstates-scrapers/dc-legislation
Two independent workflows:
Pulls the latest scraped data from the scraper repo, sanitizes it, formats it into country:us/state:dc/sessions/..., links events, and updates orphan tracking.
Downloads and extracts full bill text into each bill's files/ folder. Runs independently of formatting since it can take hours on large states. If a run times out or fails, a follow-up job automatically re-triggers it β incremental processing means it resumes rather than starting over.
Both can also be run manually via Actions β [workflow] β Run workflow.
dc-legislation/
βββ .github/workflows/
β βββ format.yml # Format scraped data + link events/orphans
β βββ extract-text.yml # Text extraction (independent, longer-running)
βββ country:us/
β βββ state:dc/ # state:usa for federal, state:il for Illinois, etc.
β βββ sessions/
β βββ {session_id}/
β βββ bills/
β β βββ {bill_id}/
β β βββ metadata.json # Bill data + _processing timestamps
β β βββ files/ # Extracted text & documents
β β β βββ *.pdf # Original PDFs
β β β βββ *.xml # Original XMLs
β β β βββ *.html # Original HTML
β β β βββ *_extracted.txt # Extracted text
β β βββ logs/ # Action/event/vote logs
β βββ events/ # Committee hearings
β βββ {timestamp}_hearing.json
βββ .windycivi/ # Pipeline metadata (committed)
β βββ errors/ # Processing errors
β β βββ text_extraction_errors/ # Text extraction failures
β β β βββ download_failures/ # Failed downloads
β β β βββ parsing_errors/ # Failed text parsing
β β β βββ missing_files/ # Missing source files
β β βββ missing_session/ # Bills without session info
β β βββ event_archive/ # Archived event data
β β βββ orphaned_placeholders_tracking.json # Data quality monitoring
β βββ bill_session_mapping.json # Bill-to-session mappings
β βββ sessions.json # Session metadata
β βββ latest_timestamp_seen.txt # Last processed timestamp
β βββ last-processed-sha # Last scraper-repo commit this repo formatted
βββ data.json # DCAT dataset descriptor
Formatted metadata is saved to country:us/state:dc/sessions/, organized by session and bill.
Each bill directory contains:
metadata.jsonβ structured information about the bill with_processingtimestampslogs/β action, event, and vote logsfiles/β original documents and extracted text
Example metadata.json structure:
{
"identifier": "HB 1234",
"title": "Example Bill",
"_processing": {
"logs_latest_update": "2025-01-15T14:30:00Z",
"text_extraction_latest_update": "2025-01-16T08:00:00Z"
},
"actions": [
{
"description": "Introduced in House",
"date": "2025-01-01",
"_processing": {
"log_file_created": "2025-01-01T12:00:00Z"
}
}
]
}When text extraction runs, each bill directory also includes:
files/β original documents and extracted text*.pdfβ Original PDF documents*.xmlβ Original XML bill text*.htmlβ Original HTML documents*_extracted.txtβ Plain text extracted from documents
Failed items are logged separately:
.windycivi/errors/text_extraction_errors/download_failures/β Documents that couldn't be downloaded.windycivi/errors/text_extraction_errors/parsing_errors/β Documents that couldn't be parsed.windycivi/errors/text_extraction_errors/missing_files/β Bills missing source files.windycivi/errors/missing_session/β Bills without session information
Tracks orphaned bills - bills that have vote events or hearings but no actual bill data. Check this file periodically to identify data quality issues:
{
"HB999": {
"first_seen": "2025-01-21T12:00:00Z",
"last_seen": "2025-01-23T14:30:00Z",
"occurrence_count": 3,
"session": "103",
"vote_count": 2,
"event_count": 0,
"path": "country:us/state:dc/sessions/103/bills/HB999"
}
}What to look for:
- Bills with high
occurrence_count(3+) are chronic orphans - likely data quality issues - Check for typos in bill identifiers or scraper configuration
- Orphans automatically resolve when the bill data arrives! π
π See orphan tracking documentation for more details.
- Logs are saved per bill under
logs/ - Processing summary shows total bills, events, and votes processed
- Session mapping tracks bill-to-session relationships
- Orphan tracking shows new, existing, and resolved orphans
- Download attempts with success/failure status
- Extraction method used (XML, HTML, PDF)
- Error details saved to
.windycivi/errors/text_extraction_errors/ - Summary reports include total documents processed, successful extractions by type, skipped (already extracted) documents, and failed downloads/extractions with reasons
Both workflows are fault-tolerant β if a single bill fails, the run continues for all others.
| Type | Format | Extraction Method | Notes |
|---|---|---|---|
| Bills | XML | Direct XML parsing | Primary bill text |
| Bills | pdfplumber + PyPDF2 | With strikethrough detection | |
| Bills | HTML | BeautifulSoup | Fallback for HTML-only sources |
| Amendments | pdfplumber + PyPDF2 | State amendments only | |
| Documents | PDF/HTML | Auto-detect | CBO reports, committee reports |
Note: Federal congress.gov HTML amendments are currently skipped due to blocking issues. XML bill versions from govinfo.gov work perfectly.
- GitHub Actions tab shows all runs
- Green checkmark = success
- Red X = failure (click for logs)
- Review
.windycivi/errors/orphaned_placeholders_tracking.jsonfor data issues - Look for chronic orphans (occurrence_count >= 3)
- Check
.windycivi/errors/for formatting/extraction errors
No new data showing up:
- Check the scraper repo (
govbot-openstates-scrapers/dc-legislation) actually got fresh data first β this repo only formats what that repo has already scraped - Check
.windycivi/last-processed-shaagainst the scraper repo's latest commit
Text extraction fails or times out:
- Check
.windycivi/errors/text_extraction_errors/for details - A timed-out/failed run auto-restarts and resumes (incremental) β no manual re-run needed
- Review error logs for specific bills
Orphaned bills appear:
- Check
orphaned_placeholders_tracking.jsonfor details - Verify bill identifiers match between scraper and vote/event data
- Bills may auto-resolve on the next format run if it's a timing issue
This repo is generated from a template in the chihacknight/govbot monorepo (actions/pipeline-manager/templates/openstates-to-ocd-files/). If you're fixing a bug in the pipeline itself (not this jurisdiction's data), open an issue or PR there β changes to this repo's workflow files will be overwritten on the next apply.py run.
For discussions, join the Chi Hack Night community on Slack or GitHub Discussions.
- Data Structures Reference - Full schema for bills, logs, events, errors
- Orphan Tracking Guide - Understanding data quality monitoring
- Main Repository - Full technical documentation
Part of the Windy Civi ecosystem β building a transparent, verifiable civic data archive for all 56 US jurisdictions.