Commit graph

76 commits

Author SHA1 Message Date
Matt Johnson
1fefc0f491 fix(gui): revert port to 8000, use 302 for setup gate redirect
- Revert uvicorn port from 8088 to 8000 (1b-1 pinned value)
- Change SetupGateMiddleware redirect from 307 to 302 for consistency
  with all other redirects in the codebase

Port 8000 confirmed free on CT104. Earlier change to 8088 was
incorrect — 8080 is held by NATS WebSocket, not 8000.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 06:13:13 +00:00
Matt Johnson
f059f982bc feat(gui): add auth core, setup gate, and first-run operator creation
- Add migrations 007-010 for system config, operators, sessions, audit_log
- Implement argon2id password hashing via argon2-cffi
- Implement session-based authentication with database-stored tokens
- Add SetupGateMiddleware to redirect to /setup until first operator created
- Add SessionMiddleware to load session from cookie and attach operator
- Create /setup, /login, /logout, /change-password routes with CSRF protection
- Add periodic session cleanup task (hourly)
- Add audit logging for auth events
- Update systemd unit with EnvironmentFile for /etc/central/central.env
- Add comprehensive tests for auth, middleware, and audit modules

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 05:30:49 +00:00
afde118d35
Merge pull request #11 from zvx-echo6/feature/1b-1-gui-scaffold
feat(gui): Phase 1b-1 GUI scaffold
2026-05-16 22:39:12 -06:00
Matt Johnson
614312db36 feat(gui): add FastAPI + Jinja2 + HTMX scaffold
- FastAPI app with Jinja2 templates and Pico CSS + HTMX from CDN
- Routes: GET / (placeholder page), GET /health (JSON healthcheck)
- systemd unit (no Install section - manual start only)
- TestClient tests for both endpoints

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 04:32:39 +00:00
69ef8b3e93
Merge pull request #10 from zvx-echo6/docs/migration-policy
docs: migration idempotency and runner policy
2026-05-16 22:08:48 -06:00
Matt Johnson
315f5cdab6 docs: migration idempotency and runner policy 2026-05-17 04:08:20 +00:00
158504f335
Merge pull request #9 from zvx-echo6/chore/close-out-1a v0.2.0
chore: Phase 1a close-out
2026-05-16 16:26:34 -06:00
Matt Johnson
9bdd4bc73e docs: changelog for v0.2.0 2026-05-16 22:26:12 +00:00
Matt Johnson
374a8c067f chore: normalize line endings to LF 2026-05-16 22:26:12 +00:00
43088d7fbb
Merge pull request #8 from zvx-echo6/feature/1a-7-usgs-quake
feat: Phase 1a-7 USGS earthquake adapter
2026-05-16 16:24:16 -06:00
Matt Johnson
e0df0bb4aa docs: add USGS quake GUI planning notes
- Feed selection (all_hour vs all_day)
- Magnitude tier color coding for GUI display

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 20:51:51 +00:00
Matt Johnson
39d5226661 feat(supervisor): wire USGS quake adapter
- Add USGSQuakeAdapter to _ADAPTER_REGISTRY
- Add CENTRAL_QUAKE stream to STREAM_SUBJECTS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 20:51:46 +00:00
Matt Johnson
668027b442 feat(models): add quake event subject routing
Update subject_for_event to handle quake.* category events.
Subject format: central.quake.event.<magnitude_tier>

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 20:51:41 +00:00
Matt Johnson
aacf06499b feat(adapters): add USGS earthquake adapter
USGS Earthquake Hazards Program adapter:
- Polls GeoJSON feed (all_hour default, configurable)
- Magnitude tier classification (minor/light/moderate/strong/major/great)
- Deduplication via USGS stable event ID
- Region filter via shapely point-in-bbox
- Skips events with null magnitude (quarry blasts, etc.)

Includes comprehensive unit tests.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 20:51:36 +00:00
Matt Johnson
be307b000c feat(schema): add USGS quake adapter and CENTRAL_QUAKE stream
Migration 006 seeds:
- config.adapters row for usgs_quake (60s cadence, PNW bbox)
- config.streams row for CENTRAL_QUAKE (7d retention)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 20:51:28 +00:00
2fd5bc01c0
Merge pull request #7 from zvx-echo6/feature/1a-6-firms-adapter
feat: FIRMS fire hotspot adapter (Phase 1a-6)
2026-05-16 14:25:55 -06:00
Matt Johnson
cbe9e50383 refactor(supervisor): use adapter registry pattern
- Add _ADAPTER_REGISTRY dict for adapter class lookup
- Unify adapter __init__ signatures (all take config, config_store, cursor_db_path)
- NWSAdapter now accepts config_store param (unused, for signature uniformity)
- Adding new adapters requires only one dict entry, no supervisor changes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 20:21:34 +00:00
Matt Johnson
95853200b2 fix(firms): use public sweep_old_ids method
Match NWS adapter pattern for supervisor compatibility.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 20:11:12 +00:00
Matt Johnson
22c50d3176 fix(firms): use public is_published/mark_published methods
Match NWS adapter pattern for supervisor compatibility.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 20:03:34 +00:00
Matt Johnson
47359a8144 docs: add FIRMS GUI planning notes
- MAP_KEY management (alias display, rotation)
- Satellite selection (toggle SNPP/NOAA20/NOAA21)
- SNPP end-of-life notice (~Oct 2026)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 19:58:46 +00:00
Matt Johnson
5dbaf1dd5c feat(supervisor): wire FIRMS adapter
- Add FIRMSAdapter import and factory case
- Add CENTRAL_FIRE stream to STREAM_SUBJECTS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 19:58:41 +00:00
Matt Johnson
a007418e0a feat(models): add fire event subject routing
Update subject_for_event to handle fire.* category events:
- Fire events: central.<category> (e.g., central.fire.hotspot.viirs_snpp.high)
- Weather events: existing geo-based subject logic

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 19:58:37 +00:00
Matt Johnson
0097163edf feat(adapters): add FIRMS fire hotspot adapter
NASA FIRMS adapter for VIIRS satellite fire detections:
- Polls VIIRS_SNPP_NRT and VIIRS_NOAA20_NRT satellites
- Deduplication via stable ID (satellite📅time:lat:lon)
- Hot-reload support for region, satellites, and API key
- Confidence mapping: l/n/h -> low/nominal/high
- Severity: high=3, nominal=2, low=1

Includes comprehensive unit tests for:
- CSV parsing and event generation
- Deduplication logic
- URL building and config application

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 19:58:31 +00:00
Matt Johnson
b42589c69c feat(schema): add FIRMS adapter and CENTRAL_FIRE stream
Migration 005 seeds:
- config.adapters row for firms (300s cadence, PNW bbox)
- config.streams row for CENTRAL_FIRE (7d retention)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 19:58:20 +00:00
025ccc6e62
Merge pull request #6 from zvx-echo6/feature/1a-5-stream-retention
Phase 1a-5: Stream retention + adapter config refactor + unified region
2026-05-16 13:10:11 -06:00
Matt Johnson
f7a55c3cc4 docs: add Phase 1a-5 verification report
Documents test results for:
- Gate 5: max_bytes self-loop prevention (PASS)
- Gate 6: bbox hot-reload (PASS)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 19:08:00 +00:00
Matt Johnson
a157f39fe0 fix(nws): replace centroid filter with polygon intersection
- Add shapely dependency for geometry intersection
- Replace _point_in_region with _geometry_intersects_region
- Uses Shapely shape() and box() for proper GeoJSON handling
- Avoids false negatives on large alert polygons

Also adds antimeridian-crossing bbox rejection to RegionConfig validator.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 19:05:05 +00:00
Matt Johnson
f9426caa27 feat: add stream management infrastructure
- config_store: add stream CRUD methods
- stream_manager: ensure_stream, apply_retention, recompute_max_bytes
- Auto-clamp max_bytes to [1GB floor, 30% ceiling]
- Parse server max_file_store from nats-server.conf

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 18:50:12 +00:00
Matt Johnson
da8942a457 schema: migrate NWS settings from states to region bbox
- Remove states array from NWS settings
- Add region bbox covering ID/OR/WA/MT/WY/UT/NV
- Bbox: north=49.5, south=31.0, east=-102.0, west=-124.5

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 18:50:05 +00:00
Matt Johnson
71a43d3c98 schema: add config.streams table with column-filtered notify
- config.streams table for JetStream retention config
- Column-filtered NOTIFY: only fires on max_age_s changes
- Prevents self-loop when supervisor updates max_bytes
- Seeds CENTRAL_WX (7d/10GB) and CENTRAL_META (1d/100MB)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 18:49:59 +00:00
Matt Johnson
ab7126ec8d refactor(supervisor): remove adapter-specific branches, add stream wiring
- Replace if name == nws with generic apply_config call
- Add _create_adapter factory method
- Add stream management: ensure_stream, retention recompute loop
- Handle streams config changes via NOTIFY

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 18:49:53 +00:00
Matt Johnson
dfcc0c3a5c refactor(nws): migrate from states to bbox region filtering
- Add RegionConfig pydantic model with validators
- NWSAdapter now uses bbox for client-side alert filtering
- Implement apply_config for hot-reload of region changes
- Remove states-based filtering logic

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 18:49:46 +00:00
Matt Johnson
1ea56b67fd refactor(adapter): add abstract apply_config method
SourceAdapter now requires apply_config() for hot-reload support.
Each adapter implements its own config extraction from settings.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 18:49:40 +00:00
Matt Johnson
12a66d45ba docs: add Phase 1B planning notes
- Stream retention GUI design
- Region picker for bbox selection
- API key management requirements

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 18:49:29 +00:00
93d86a9276
Merge pull request #5 from zvx-echo6/feature/remove-adapter-limiter
fix: remove NWSAdapter internal AsyncLimiter (cadence-decrease root cause)
2026-05-16 11:31:38 -06:00
Matt Johnson
2597153a9c docs: add final cadence-decrease fix verification
Documents production verification of the AsyncLimiter removal fix:
- Decrease 60-30s: poll at Tlast+30s (not 60s)
- Increase 30-60s: poll at Tlast+60s
- Decrease 60-15s: immediate poll (deadline passed)
- All subsequent intervals use new cadence

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 17:26:26 +00:00
Matt Johnson
5b028b38e8 test: remove ineffective hot-reload tests
These tests pass on both fixed and unfixed code, meaning they do
not actually exercise the cadence-decrease bug. The tests were
added as part of PR #4 but direct verification showed they
do not catch the issue they claim to test.

A follow-up issue should be filed for proper regression tests
that reproduce the actual bug (AsyncLimiter blocking).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 17:19:27 +00:00
Matt Johnson
c368f175a1 build: remove aiolimiter dependency
No longer needed after removing internal rate limiting from NWSAdapter.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 17:19:15 +00:00
Matt Johnson
0eba319071 refactor(supervisor): remove adapter.cadence_s update
The NWSAdapter no longer has a cadence_s attribute since the
internal limiter was removed. The supervisor's rate limiting
via state.config.cadence_s and last_completed_poll is sufficient.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 17:18:55 +00:00
Matt Johnson
9d4ba97537 refactor(nws): remove internal AsyncLimiter rate limiting
The NWSAdapter had an internal AsyncLimiter that duplicated the
supervisor's rate-limit guarantee. When cadence changed, only
state.adapter.cadence_s was updated, not the internal limiter,
causing the cadence-decrease bug.

Since the supervisor already enforces rate limiting via
last_completed_poll + cadence_s scheduling, the adapter-level
limiter was redundant and caused the 30-second blocking observed
in diagnostic logs.

Removes:
- aiolimiter import
- self.cadence_s attribute (unused elsewhere)
- self._limiter creation
- async with self._limiter context in _fetch_alerts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 17:17:11 +00:00
6deccf1cf8
Merge pull request #4 from zvx-echo6/feature/1a-4-cadence-decrease-fix
fix: cadence-decrease hot-reload + integration tests + env docs
2026-05-16 00:58:24 -06:00
Matt Johnson
d210c980fd docs: add environment reference and bug investigation report
environment.md:
- Documents CT104 as the active development location
- Lists SSH access, repository paths, and service commands
- Notes that cortex clone is parked, matt-desktop has no clones

BUG-CADENCE-DECREASE.md:
- Full investigation of the cadence-decrease hot-reload bug
- Root cause analysis: cancel_event.set() inside lock context
- Proposed fix (Option A - structural)
- Test gap identification
- Production verification steps

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 05:59:53 +00:00
Matt Johnson
4215744a30 fix: move cancel_event signal outside lock for immediate delivery
The cancel_event.set() call was inside the async lock context in
_on_config_change, causing delayed signal delivery to the sleeping
loop. This manifested as cadence decreases not applying without a
restart - the loop would sleep its full original timeout before
seeing the new cadence.

Fix: _reschedule_adapter now returns the AdapterState to signal,
and _on_config_change signals AFTER releasing the lock. This ensures
immediate event delivery per asyncio semantics.

The lock protects state consistency during config fetches and updates.
The cancel_event is a one-way notification that does not need lock
protection - it simply wakes the sleeping coroutine.

See docs/BUG-CADENCE-DECREASE.md for full investigation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 05:59:45 +00:00
Matt Johnson
35de09ea93 test: add hot-reload integration tests for cadence changes
Add tests that exercise the ACTUAL running loop with cancel_event
signaling, not just AdapterState math in isolation.

Test cases:
- Test 1: Cadence decrease (60->30) wakes loop immediately
- Test 2: Cadence increase (10->20) extends wait correctly
- Test 3: Enable/disable/enable with gap > cadence polls immediately
- Test 4: Enable/disable/enable with gap < cadence waits

These tests verify the cancel_event mechanism properly interrupts
the sleeping loop when config changes occur via _on_config_change.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 05:59:35 +00:00
Matt Johnson
c4a65a2ad7 docs: Phase 1a-3 final close-out verification
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 04:04:02 +00:00
0b23cc4572
Merge pull request #3 from zvx-echo6/feature/1a-3-phase-c-toml-retirement
Phase 1a-3 Part C: Retire TOML config source
2026-05-15 22:00:02 -06:00
Matt Johnson
24d99f18e2 docs: append cadence revert to Phase 1a-3 verification
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 03:57:32 +00:00
Ubuntu
a362b7b93e test: remove TomlConfigSource and config_source flag tests
TOML-related tests no longer needed after Phase C retirement.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 03:42:43 +00:00
Ubuntu
c6f4f3b081 refactor: supervisor always uses DbConfigSource
Remove conditional config source loading, simplify async_main.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 03:42:38 +00:00
Ubuntu
a1e81bae8a refactor: remove config_source flag from bootstrap settings
Database config is now the only option, no need for feature flag.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 03:42:33 +00:00