* chore: remove central.budget re-export shim
The shim's implementation lived at notifications.formatters._budget from
the start; central.budget was only a 9-line re-export kept around for
import-path compatibility. Point every importer directly at the real
module and delete the shim:
- notifications/renderers/composer.py: lazy import inside a function
- central/wfigs_handler.py, central/satpass_handler.py: import line only
- tests/test_fire_refactor.py, test_nws_refactor.py, test_firms_refactor.py:
import line only, no behavior change
test_budget_shim.py existed solely to assert identity-equality between
the shim and the real module; with the shim gone there is nothing left
for it to test, so it is deleted too.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: delete dead renderers/work_zone.py
format_work_zone_mesh() had exactly one production caller, the
central/consumer.py NATS bridge deleted in the prior Central-excision
pass. Its live replacement, formatters.incident._render_work_zone()
(registered for category "work_zone" in formatters/__init__.py), is an
already-shipped byte-identical replica per that module's own docstring.
All remaining references to renderers.work_zone were prose/comments
describing the replica relationship, not imports.
Test fallout:
- tests/test_work_zone_renderer.py tested only the dead renderer in
isolation (17 cases). Deleted — the live path has its own coverage
(test_adapter_wzdx.py's formatter-integration tests, plus
TestCrossSourceIdentity::test_work_zone_category_uses_wz_renderer and
TestWorkZoneGolden in test_incident_refactor.py).
- tests/test_itd_511_work_zone.py::test_itd_511_work_zone_renderer_produces_wire
only smoke-tested the dead renderer's wire output for itd_511 data;
redundant with TestWorkZoneGolden's byte-identical fixture coverage
for the same adapter. Deleted.
- tests/test_incident_refactor.py::TestWorkZoneGolden compared the live
formatters.incident.format() output against a golden computed by
calling the dead renderer live on two real fixtures. Mirroring the
precedent already in test_nws_refactor.py for this exact situation
(golden generator deleted out from under a parity test), the two
golden strings were captured by running format_work_zone_mesh()
against these fixtures immediately before deletion and are now
pinned as literals — same coverage, no live dependency on the dead
module.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Matt Johnson <mj@k7zvx.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migrate the three FIRMS fire-tracker BROADCAST paths (wildfire_growth,
wildfire_spotting, wildfire_halted) behind the registry, NO cutover.
Attribution/pass/centroid/perimeter plumbing stays inline; legacy live
path is byte-identical.
- gating/firms.py decide() discriminates on handler-stamped _kind
(firms_growth/firms_spotting/firms_halt)
- wildfire_growth reuses formatters/fire.py (verified byte-identical:
growth SELECT uses current_* columns _render doesn't read, so the wire
is the movement+anchor line with "size/containment unknown" — a latent
legacy quirk, reproduced exactly, NOT fixed)
- formatters/firms.py renders spotting + halt wires
- tier-b (flagged): the eager latch writes (fires.last_spotting_broadcast_at,
fires.halt_broadcast_at) move into deferred commit closures — a dropped
broadcast no longer burns the latch. Validated by gate-sequence, not
golden bytes. Not-cutover live path keeps eager latches verbatim.
- FIRMS broadcasts never touch event_log (eager handled=1 at pixel
storage) → no event_log flip to wrap
- _maybe_emit_cluster stays dead (unconditional return None) + test
Deferred follow-ups (unchanged): env/firms.py native hotspot broadcast
neutralization; native canonical emission.
27 new tests; fire-tracker + firms handler suites preserved; full suite
at 34-failure baseline (1597 passed).
Co-authored-by: Matt Johnson <mj@k7zvx.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move wfigs wire rendering into notifications/formatters/fire.py and the
full fire state machine into notifications/gating/fire.py, behind the
registry, NO cutover. handle_wfigs builds a canonical dict, calls
decide(), keeps the inline fires INSERT/UPDATE of current_* and the
tombstoned_at stamp unconditional, then branches on is_cutover(...) —
legacy _attach_commit_handles/all-clear path stays byte-identical while
the new path bakes in shadow.
Reproduces every legacy stamp through GateResult.data_patch:
- forward-only acres/containment growth + 8h cooldown gating
- tombstone wildfire_closed all-clear (row exists AND last_broadcast_at
IS NOT NULL) with _severity_override="priority", _dedup_suffix="closed"
- growth _dedup_suffix=f"{acres}|{contained_pct}", _cooldown_suffix=irwin_id
- idempotent commit UPSERT of fires(last_broadcast_*) + event_log flip
- full _location_anchor fallback chain (geocoder_city -> resolve_anchor
-> landclass -> county -> state) preserved in the formatter
Registered under the three explicit categories (wildfire_declared,
wildfire_incident, wildfire_closed) rather than the `fire` toggle, so the
family-fallback does NOT capture the still-deferred FIRMS categories
(wildfire_hotspot/new_ignition/wildfire_growth); a registration test
asserts those resolve elsewhere.
Native env/fires.py deferred (missing IRWIN/cause/landclass, no tombstone
concept); non-cutover so store._emit_event won't run it.
tier-a: 19 new golden+gate-sequence tests; wfigs handler 23/23 preserved;
suite at 34-failure baseline (1571 passed).
Co-authored-by: Matt Johnson <mj@k7zvx.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>