Commit Graph
7 Commits
Author SHA1 Message Date
Logan Cusano 70d63abeaa Re-evaluate incident severity on link, stamp resolved_at at every resolution site
#17: severity was written once at _create_incident and never touched again,
so an incident that opened routine and escalated to a working fire stayed
routine forever. _update_incident now merges call_severity into the incident
via _max_severity() on every link.

Severity is monotonic: it only ever rises, never falls. An incident briefly
assessed "major" genuinely was major at that moment; a later, calmer-sounding
call is evidence the situation is winding down, not that the earlier read was
wrong. status/resolved_at exist to retire an incident — severity should stay
as the high-water mark so the worst-first rail, "Major only" filter, and map
colouring never bury a call that was genuinely major. See _max_severity's
docstring in incident_correlator.py for the full argument.

#18: none of the resolution sites wrote resolved_at, so an incident's
lifespan couldn't be reconstructed for the history-scrub feature. Added
resolved_at alongside status="resolved" at all six sites that flip it:
  - incident_correlator.py _update_incident (signal-based: units all cleared)
  - incident_correlator.py maybe_resolve_parent (master auto-resolve)
  - summarizer.py _stale_sweep (90-minute auto-resolve)
  - upload.py, both scene-resolution loops (single- and multi-scene)
  - calls.py reprocess/correction path
(_update_incident's signal-resolve and maybe_resolve_parent's master-resolve
weren't named in the issue's four call sites, but they set status the same
way and were missing resolved_at too.)

No backfill: existing resolved incidents keep resolved_at = null, which
means "resolved before this field existed," not "never resolved." Backfilling
from updated_at would be a guess dressed up as data.

Tests: added to tests/test_correlator_gate.py, which needs no Firestore for
the pure _max_severity cases and patches fstore for the _update_incident/
maybe_resolve_parent writes. Covers the escalation case (routine -> major),
the no-downgrade case, and resolved_at on both the signal-resolve and
master-resolve paths. 52/52 passing in that file; 83 passed / 10
pre-existing failures for drb-c2-core overall (baseline was 69/10 — the
+14 is exactly the new tests, no regressions).

Fixes #17, #18.
2026-08-19 22:57:20 -04:00
Logan 8b660d8e10 feat: incident correlation overhaul, signal-based auto-resolve, token fixes
Correlator
- Raise fast-path idle gate 30 → 90 min (tg_fast_path_idle_minutes)
- Fix disambiguate always-commits bug: run _call_fits_incident on winner
  before committing; fall through to new-incident creation if it fails
- Add unit-continuity path (path 1.5): matches all_active by shared unit
  IDs with a reassignment guard, bridges calls past the idle gate
- Add tag-based incident_type inference (_TAG_TYPE_HINTS) as GPT fallback,
  rescuing tagged calls that would have been dropped (616 observed orphans)
- Add master/child incident model: _create_master_incident, _demote_to_child,
  _add_child_to_master; new incidents stamped incident_type="master"
- Add cross-system parent detection (_find_cross_system_parent): two-signal
  scoring (road overlap=0.4, embedding≥0.78=0.3, proximity=0.3, threshold=0.5)
  wired into create-if-new path; creates master shell on first cross-system match
- Add maybe_resolve_parent: auto-resolves master when all children close;
  called from upload pipeline (LLM closure) and summarizer stale sweep
- Add signal-based auto-resolve via units_active/units_cleared tracking:
  GPT now extracts cleared_units per scene; _update_incident moves units
  between active/cleared lists and resolves the incident when active empties;
  stored on call doc for re-correlation sweep reuse
- Add _create_incident initialization of units_active/units_cleared fields

Re-correlation sweep
- Add corr_sweep_count + MAX_SWEEP_ATTEMPTS=3: orphans get 3 attempts
  then are tombstoned as corr_path="unlinked", ending the re-sweep loop
  (previously hammering each orphan 29-31 times per shift)

Intelligence extraction
- Add cleared_units to GPT prompt schema and rules
- Extract and propagate cleared_units per scene; merge across scenes;
  store on call doc for re-correlation sweep

Token management
- Fix token release bug: remove release_token call on discord_connected=False
  in MQTT checkin (transient Discord drops were orphaning bots mid-shift)
- Add PUT /tokens/{id}/prefer/{system_id} endpoint: lock a bot token to a
  system; pass _none as system_id to clear; stored bidirectionally on both
  token and system documents
- discord_join handler resolves preferred_token_id from system doc and passes
  system_name in MQTT payload
2026-05-10 19:49:05 -04:00
Logan c959437059 Implement Admin UI to disable AI components 2026-04-27 00:37:51 -04:00
Logan ba43796c51 Updates, big updates
incident_correlator.py — full rewrite: always runs on every call, fetches all active incidents cross-type, fast path collects all talkgroup matches and disambiguates by unit/vehicle overlap → location proximity → embedding, new location proximity path, slow path requires location corroboration, "Auto:" stripped from titles, "auto-generated" tag added, units/vehicles now accumulated on update
intelligence.py — resolved field in GPT schema, returned as 5th value
upload.py — both pipelines unpack 5-tuple, always call correlate, auto-resolve on resolved=True
summarizer.py — stale sweep runs each tick, resolves incidents idle for 90+ minutes
config.py — correlation_window_hours=2, embedding_similarity_threshold=0.93, location_proximity_km=0.5, incident_auto_resolve_minutes=90
2026-04-19 22:53:53 -04:00
Logan 03212fca51 Move to GPT for API consistency 2026-04-19 08:18:55 -04:00
Logan 10aabf4fb2 Change models 2026-04-13 01:43:10 -04:00
Logan 7b6fd640d9 Update intelligence 2026-04-12 23:33:44 -04:00