Commit graph

8 commits

Author SHA1 Message Date
81a2c30fdb
v0.10.8: discriminate Nats-Msg-Id by event.category to prevent incident+perimeter dedup collision (#96)
JetStream's 2-min per-stream duplicate window keys on Nats-Msg-Id alone --
the subject is NOT part of the dedup key. So when wfigs_incidents and
wfigs_perimeters published envelopes for the same Summit Creek IRWIN
{6B1C6EB1-30F7-4613-9C58-4801DC8FD822} within seconds of each other on
2026-06-07, the second publish was silently dropped: supervisor logged
'Published event' for both, but CENTRAL_FIRE's last_seq advanced by 25
instead of 26.

Root cause: cloudevents_wire.wrap_event returned event.id verbatim as
msg_id, and both wfigs adapters use the bare IRWIN GUID as event.id.

Fix: synthesize msg_id as f'{event.id}:{event.category}' in wrap_event.
Categories already differ ('fire.incident.X' vs 'fire.perimeter.X') so
this is a natural and load-bearing discriminator. envelope['id'] stays
the bare event.id per CloudEvents spec, so subscribers that key off the
payload id field are unaffected. Adapter-side event.id construction
unchanged.

Backward compatibility: this is a one-time msg_id-shape change. The
JetStream 2-min dedup window is per-(event-id, category) starting now
instead of per-event-id. For events still in the dedup window at the
moment of the deploy under the OLD shape, their first post-deploy
publish under the NEW shape is a fresh msg_id and lands normally -- no
collision risk. Quake and other single-class adapters get a no-op shape
change (their category is constant per adapter, so dedup still catches
genuine same-id duplicates).

Tests:
- test_required_fields_present updated for the new assertion.
- New test_msgid_disambiguates_incident_vs_perimeter_same_guid regression
  guard with the real Summit Creek IRWIN -- assert the two msg_ids differ
  and match the expected shape exactly.
- New parametrize test_msgid_shape_is_id_colon_category over 5
  categories covering multi-class (fire.incident, fire.perimeter) and
  single-class (quake, wx.alert, hydro) adapters.

Full sweep: 1028 passed, 0 failures (+6 from this PR), ruff clean.

Deploy: NOT an output-shape change to envelope payload, no published_ids
flush needed. Squash-merge -> tag v0.10.8 -> pull on central -> restart
central-supervisor. Verify by forcing a Summit Creek republish and
confirming both .incident.id.cassia AND .perimeter.id.cassia land
post-deploy with the same IRWIN.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-08 01:12:22 -06:00
Matt Johnson
4573bf6ee2 refactor(adapters): self-describing adapter pattern with auto-discovery
- Add stream_name, subject_for(), and settings_schema() to SourceAdapter ABC
- Implement all three methods in NWSAdapter, FIRMSAdapter, USGSQuakeAdapter
- Replace manual _ADAPTER_REGISTRY with pkgutil.iter_modules auto-discovery
- Remove subject_for_event from models.py (each adapter owns its subject logic)
- Update supervisor to use adapter.subject_for(event) instead of helper
- Fix quake events going to wrong stream (was publishing to CENTRAL_WX)
- Update test files to use adapter methods

This fixes the quake stream bug where events were published to
central.wx.alert.us.unknown instead of central.quake.event.<tier>.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-18 22:14:12 +00:00
8c2e4a358d
chore: housekeeping - orphan branch + three stale tests (#22)
* test(bootstrap): isolate env vars in test_reads_from_env_file

The test was failing on CT104 because live CENTRAL_DB_DSN
environment variable overrode the test .env file content.

Fix: use monkeypatch.delenv to clear all CENTRAL_* env vars
before creating the Settings object, ensuring the test env
file is the only source of configuration values.

Also add CENTRAL_CSRF_SECRET to test env file since it's
now a required field.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(models): remove stale test_custom_prefix test

The test called subject_for_event(event, prefix="myapp.events")
but the prefix parameter was removed from the API.

The prefix functionality was intentionally removed - subjects
now always use the "central." prefix hardcoded in the function.
Delete the test rather than re-add the parameter.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(nws): update fixtures for new adapter signature and region filtering

NWSAdapter.__init__ signature changed from (config, cursor_db_path)
to (config, config_store, cursor_db_path) with config now being
AdapterConfig with a settings dict instead of NWSAdapterConfig.

Also adapts tests to region-based bbox filtering:
- TestStateFilter now uses region bbox to accept PNW, reject CA
- Add geometry to SAMPLE_FEATURE_OR so it passes region filter
- Other test fixtures use region=None to skip filtering

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Matt Johnson <mj@k7zvx.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 18:14:58 -06:00
Ubuntu
8601a19f60 feat(schema): add adapter column to events, drop source
Replaces module-path-based source column (e.g. "central/adapters/nws")
with stable adapter identifier (e.g. "nws") that foreign-keys to
config.adapters.name.

Migration 011:
- ADD COLUMN adapter TEXT
- Backfill via REPLACE(source, 'central/adapters/', '')
- SET NOT NULL + FK RESTRICT
- CREATE INDEX (adapter, received DESC) for dashboard queries
- DROP COLUMN source

Code changes:
- Event model: source field renamed to adapter
- All adapters: use adapter="name" instead of source="central/adapters/name"
- Archive: write adapter column instead of source

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-17 16:09:59 +00:00
Matt Johnson
374a8c067f chore: normalize line endings to LF 2026-05-16 22:26:12 +00:00
Ubuntu
25909b0f4d fix(tests): replace echo6 reference with central.local
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-16 01:36:44 +00:00
Matt Johnson
4a7f1a76c7 refactor: rename CloudEvents extension attributes hub* → central*
Rename extension attributes for consistency with project naming:
- hubschemaversion → centralschemaversion
- hubcategory → centralcategory
- hubseverity → centralseverity

Non-breaking change - no consumers depend on these names yet.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-15 21:47:50 +00:00
Matt Johnson
714971fe99 foundation: models, adapter ABC, config, CE wire, schema
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-15 21:08:56 +00:00