Commit graph

4 commits

Author SHA1 Message Date
Matt Johnson
1ffde64c3c chore(central-ripout 2d-i): relocate the fire engine + renderer out of central/
Moves the last two live files out of the retired-Central folder. central/ is
now EMPTY and deleted entirely (incl. __init__.py).

- fire-fusion engine (ingest_hotspot_pixel + the growth/cluster/spotting
  engine) → env/fire_fusion.py, next to its sole consumer env/firms.py.
- wildfire text renderer (_render + its live helpers) → env/fire_render.py.

THE COUPLING RESOLVED: firms_handler._handle_pass_boundary had a LAZY import
inside a function body — `from meshai.central.wfigs_handler import _render` —
sitting on the live FIRMS fire-growth path. It is now a normal top-of-file
import (`from meshai.env.fire_render import _render`), visible and greppable.

PURE MOVE — no behavior change:
- The parity oracle (test_fire_refactor.py) PASSES UNCHANGED (only its import
  paths updated) — proving the fire wire output is byte-for-byte identical
  before and after. Fire alerts say exactly what they said.
- handle_firms / handle_wfigs (dead entrypoints, only caller was the deleted
  consumer.py) were KEPT and moved rather than dropped — the wording-cleanup
  PR removes them deliberately. "When unsure, keep."
- fire_render.py's geo-helper imports still point at central_normalizer — that
  file's split is a SEPARATE PR; carried the imports along, did not touch it.

Consumers + test import paths rewired. Full suite: 2059 passed, 0 failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 22:27:08 +00:00
ff127bee18
chore(central-ripout 2a): remove the budget shim + dead work_zone renderer (#161)
* 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>
2026-07-17 15:12:55 -06:00
531bd20378
refactor(phase3c): migrate FIRMS fusion broadcasts to formatter+decider (#34)
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>
2026-07-04 23:18:51 -06:00
8bc9b14dba
refactor(phase3b): migrate WFIGS fire to formatter+decider (tier-a) (#33)
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>
2026-07-04 22:51:26 -06:00