feat(dashboard): add forward "what's next" signal + fix upcoming floor
The daily-file bill queue is a backward snapshot, so "upcoming" could only resurface the latest past day (the 08-31 snapshot read as today's queue) and there was no "what is scheduled next." leginfo bill status/history are backward-only, so the genuine future-dated signal is the chambers' "upcoming events" calendars. - api.py: floor the "upcoming" view at *today* (not the DB max date) when no as_of is pinned; surface next_legislative_day + scheduled_events (next 7 days) on /bills. Add _today_iso / _next_legislative_day / _scheduled_events, all degrading to a recess marker / [] (never 5xx). - relational.py: schema v2 adds the scheduled_events table + store_scheduled_events (idempotent per-day refresh), load_scheduled_events, next_legislative_day. - parsers.py: parse_events_page + classify_event_kind for the chamber events calendar; skip empty-title rows (decompose the <time> before the fallback). - ingest.py + cli.py: --store-events lane (cache-first, recess-safe) that parses the calendar HTML into scheduled_events. - sources.py + config.yaml: register assembly_events / senate_events (kind: events, empty_is_ok: true). - run_ingest.sh: run the events lane after the daily-file lane as non-fatal (skippable via CALI_SCRAPER_SKIP_EVENTS=1); daily-file exit still gates cron. - frontend: "Next legislative day" line + "What's next · next 7 days" band with honest recess empty states. - DASHBOARD.md: document the forward signal + known limitations (leginfo backward-only gap, recess empty state, 08-31 snapshot is analysis-only). - tests: 5 new API tests + 18 parse-events tests; 170 pass, 92% coverage.
This commit is contained in:
1 parent
1919d43bf0
commit
03eeb6bb62
16 files changed
+941
-70
No files matched your search
@@ -33,10 +33,11 @@
|
||||
<main id="app">
|
||||
<!-- §9 status / context band -->
|
||||
<section class="freshness" id="freshness" aria-live="polite">
|
||||
<span id="freshness-updated">Loading…</span>
|
||||
<span id="freshness-session" class="badge"></span>
|
||||
<span id="freshness-chamber" class="note"></span>
|
||||
<button type="button" id="btn-refresh" class="ghost">Refresh</button>
|
||||
<span id="freshness-updated">Loading…</span>
|
||||
<span id="freshness-session" class="badge"></span>
|
||||
<span id="freshness-chamber" class="note"></span>
|
||||
<span id="freshness-next-day" class="note"></span>
|
||||
<button type="button" id="btn-refresh" class="ghost">Refresh</button>
|
||||
</section>
|
||||
|
||||
<!-- Controls bar -->
|
||||
@@ -64,9 +65,17 @@
|
||||
<input type="checkbox" id="f-reason" title="Show why each
|
||||
floated bill is in your view">
|
||||
</label>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!-- Logged-in personal controls (ZIP + watch/opt-in) -->
|
||||
<!-- What's next: forward-looking chamber events calendar (scheduled_events) -->
|
||||
<section class="band next-band" id="next-band" aria-label="Next 7 days">
|
||||
<h2 class="band-title">What's next · next 7 days
|
||||
<span id="next-count" class="count"></span></h2>
|
||||
<div id="next-list" class="list next-list"></div>
|
||||
<div id="next-empty" class="empty-state" hidden></div>
|
||||
</section>
|
||||
|
||||
<!-- Logged-in personal controls (ZIP + watch/opt-in) -->
|
||||
<section class="personal-controls" id="personal-controls" hidden>
|
||||
<div class="zip-lookup">
|
||||
<label for="zip-input">Where do you live?</label>
|
||||
|
||||
Reference in new issue
Block a user