This is the persistent context file for Claude Code. Keep it concise and useful.
template/vendor/, no CDN.env)votes.jsonl) — analyze.py is chamber-agnosticbuild_members.py workersbuild_members.py uses multiprocessing.Pool with initializer-shared records (no per-task serialization)manifest.json is the picker index AND carries per-member KPI dict (k) so ranking.html needs only one fetchbuild_app.py inlines the full manifest as <script type="application/json" id="polisci-manifest"> so file:// works for the picker.chart-canvas-wrap (position:relative, flex:1 1 auto, min-height:0) inside fixed-height .chart-frame (340px / 280px mobile) — fixes Chart.js infinite-growth feedback loop#polisci-root — required by inline-embed contract (CSS audit gates this at 0 violations)data-base="./data/" on #polisci-root lets host pages relocate the data dirS270); Congress.gov uses bioguide — lis_to_bioguide.json crosswalk built by name+state+party match (Congress.gov v3 does not expose LIS reliably)/v3/member/{bg} endpoint — bulk listing is too sparse, so enrich_roster runs detail lookups for every replacement-chain memberfull_name, district, served_from/to, photo_url, served_partial, is_delegate, congress_term, death_year, current_member, replaces, replaced_by from members_directory.json^[A-Z]\d{6}$|^S\d{3,4}$ validated on every URL read AND against manifestByIdtextContent / createElement — zero innerHTML (security-audited)polisci:v119:*; only lastMember persisted in MVPfetch.py → parse.py → enrich_roster.py → parse.py → pytest → build_members.py → build_app.py
fetch.py — idempotent network fetch into data/<C>/{house,senate}/cache/parse.py — XML → votes.jsonl + roster.json; rejects upstream strings with <, >, control chars; merges directory fields (delegate flag, congress_term, death_year, current_member, replaces/replaced_by) and overrides "XX" state for delegatesenrich_roster.py — three passes: (1) bulk Congress.gov → members_directory.json + LIS crosswalk; (2) rescue individual /v3/member/{bg} for vote-derived House bioguides missing from bulk (e.g. Gaetz); (3) replacement-linking by (state, district) within Congress window → replaces/replaced_by, then detail-enrich every chain member for term/death/current fields. 350ms throttle; User-Agent: polisci-pipeline/1.0build_members.py — parallel pool; passes full chamber records to analyze.aggregate (NOT pre-filtered by member) so absences count as N/A rowsbuild_app.py — wipes + recreates results/<C>/; injects manifest into HTML heads; writes README with CSP + iframe snippetbuild_all.py — one-command wrapper; runs parse.py twice (before and after enrich) so directory data merges indata/<C>/{house,senate}/{cache/, votes.jsonl, roster.json} — raw + parsed per-chamberdata/<C>/members/<id>.json — per-member metrics (~80 KB each)data/<C>/manifest.json — picker index; per-member carries k (KPI dict for Rankings), dl (delegate), un (unseated), rs/rb (replacement refs), sy/ey (term years), dy (death year)data/<C>/members_directory.json — Congress.gov roster (~551 members)data/<C>/lis_to_bioguide.json — Senate ID crosswalkdata/<C>/api_cache/ — cached Congress.gov responsesdata/<C>/build_report.json — per-build success/failure logresults/<C>/ — embeddable artifact (the shipping output)app.html — single-member dashboard: sidebar filters (chamber/party/state), typeahead, 8 KPI tiles (incl. Voted With GOP / Voted With Dem), 5 charts, sortable vote tablecompare.html — overlay up to 6 members across 5 comparison charts; per-member color-coded pillsranking.html — rank House or Senate members by any of 14 metrics; House/Senate radio + party checkboxes + metric dropdown + order radio; URL state; row click opens member dashboardrenderNote() priority: delegate > unseated > died > replaced_by > replaces > served_partial; successor/predecessor rendered as in-app links via state.membersByIdMember · Compare · Rankings in <header>?id=, ?ids=, ?c=&m=&o=&p=) — deep-linkable, validated against manifestapp.html directly (over HTTP)sandbox="allow-scripts allow-same-origin" referrerpolicy="no-referrer"<link> + <script> + <div id="polisci-root" data-base="..."> into host pageresults/<C>/README.mdlegacy/: 8/8 PASS (script: tests/parity_check.py; report: research/PHASE3_PARITY.md)research/PHASE6_CSS_AUDIT.md)build_members.py for 552 members: ~5 s on local CPU.env (gitignored); rotated via Congress.gov sign-up flow; redacted from DOCUMENTATION.md §2.gitignore: .env, __pycache__/, *.pyc, data/*/cache/, data/*/api_cache/parse.py rejects <, >, control chars at XML parse timetextContent / createElement / replaceChildren — grep innerHTML returns empty across template/ and results/eval, no Function(), no inline event handlersapp.js, compare.js, ranking.js); IIFE wrappersapp.js and compare.js — accepted for v1 to avoid coupling--congress N (default 119), shebang + executabletests/ (not the test-engineer sandbox) per project requirementmonthly['Helped Neither'] as proxy — analyze.py doesn't emit a true monthly own-party-defection serieslastMember; filter state lives in URL only_iframe_test.html + _embed_test.html available in results/119/DOCUMENTATION.md §8/§9/§11 for new file layout + regeneration commands + change-loglegacy/ after user confirmation