Files
thor-watcher/CHANGELOG.md
T
serversdown 3bef58b8dd chore(release): bump to v0.4.0 — mirror (dual-send) docs
Version bump across series4_ingest.py / tray / settings dialog / installer.iss.
CHANGELOG + README document the optional best-effort mirror server
(mirror_api_url / mirror_sfm_url / mirror_sfm_state_file, default off).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 05:54:14 +00:00

7.1 KiB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[0.4.0] - 2026-06-25

Added — Mirror (dual-send)

  • Optional best-effort mirror server. Each heartbeat and each forwarded event can now be sent to a second ("mirror") server in addition to the primary, so a standby box (e.g. the office NAS) stays a continuous replica during a migration — making the eventual cutover a non-event. Default off — blank mirror_api_url/mirror_sfm_url means existing installs are unchanged after auto-update.
  • Heartbeat mirror (best-effort). After the primary heartbeat POST, the same payload is fired at mirror_api_url when set. Bounded by the existing API timeout and fully wrapped — it can never delay or fail the primary heartbeat; its result is ignored except for a debug log line.
  • Event mirror (reliable, isolated). Events are re-forwarded to mirror_sfm_url using a separate sha256 state file (mirror_sfm_state_file, blank → <log_dir>/thor_forwarded_mirror.json), so the mirror tracks its own delivery independently of the primary. A quick reachability probe (~3 s) skips the mirror pass when the mirror server is down, so a dead mirror never stalls the loop on per-event timeouts; skipped events stay pending in the mirror state and deliver when the mirror returns — no data loss.
  • Isolation invariant (the one rule). Nothing on the mirror path can delay or fail the primary: its own state file, its own try/except, the reachability guard + bounded timeouts, all exceptions swallowed-and-logged. The primary path stays exactly as reliable as before.
  • Mirror tab in the Settings dialog with Mirror API URL + Mirror SFM URL fields (blank = off). The mirror rides along with the primary — there is no separate enable flag (heartbeat-mirror active iff the primary heartbeat is on and mirror_api_url is set; event-mirror active iff primary forwarding is on and mirror_sfm_url is set).
  • New unit tests in test_event_forwarder.py covering mirror reachability, the down-mirror skip, separate-state idempotency, and the isolation invariant (a mirror failure leaves the primary's result + state untouched).

Configuration

New config.json keys (all default-empty = off; existing 0.3.x deployments don't change behaviour on auto-update):

Key Default Notes
mirror_api_url "" Second heartbeat destination — same URL form as api_url (blank = off)
mirror_sfm_url "" Second SFM base URL, e.g. http://10.0.0.x:8200 (blank = off)
mirror_sfm_state_file "" Override the mirror's forwarded-sha256 state file. Blank → <log_dir>\thor_forwarded_mirror.json

Changed

  • Bumped VERSION to 0.4.0

Operational note (migration seeding). To make the mirror re-deliver only the gap since a one-time replica snapshot, copy the primary state file to the mirror state file and drop entries whose forwarded_at is after the snapshot. SFM-side dedup covers any overlap. See docs/mirror-dual-send-design.md.

[0.3.1] - 2026-05-20

Hot fix

  • Improved update logging
  • Improved update settings

[0.3.0] - 2026-05-19

Added

  • event_forwarder.py — forwards .IDFH (histogram) and .IDFW (waveform) event files plus their TXT/<basename>.txt sidecars to a seismo-relay SFM server's new /db/import/idf_file endpoint
  • Sha256-keyed thor_forwarded.json state file for idempotency across restarts and re-scans (default path: <log_dir>/thor_forwarded.json)
  • "SFM Forward" tab in Settings dialog: enable/URL/Test, forward interval, quiescence, missing-report grace, HTTP timeout, max forwards per pass, max event age, state file picker
  • Forwarder status line in tray menu: SFM OK | N fwd, M err | last 30s ago
  • Tray icon goes amber when the SFM forwarder is failing but the API heartbeat is still healthy
  • Re-pair logic: events forwarded without their TXT are re-forwarded once the sidecar appears so the relay can refresh DB rows with device-authoritative PPV/ZCFreq/peak values
  • event_forwarder.py --seed-state CLI for skipping historical backfill on a first deploy
  • Version badge: Thor Watcher vX.Y.Z shown at the top of the tray menu and in the Settings dialog title bar — operators no longer have to crack open the .exe properties to tell which version is running

Changed

  • Bumped VERSION to 0.3.0
  • Settings dialog tab order: Connection / Paths / Scanning / Logging / SFM Forward / Updates

[0.2.0] - 2026-03-20

Added

  • thor_tray.py — system tray launcher with status icon (green/amber/red/grey), Settings and Open Log Folder menu items
  • thor_settings_dialog.py — Tkinter settings dialog with first-run wizard; tabs for Connection, Paths, Scanning, Logging, Updates
  • Hardened auto-updater: three-layer download validation (100 KB floor, 50% relative size floor, MZ magic bytes), safer swap bat with 5-retry cap and :fail exit, .exe.old backup
  • Configurable update source: update_source (gitea / url / disabled), update_url for custom server
  • Remote push support: update_available flag in API heartbeat response triggers update regardless of update_source setting
  • build.bat — PyInstaller build script; outputs versioned exe for Gitea and plain copy for Inno Setup
  • installer.iss — Inno Setup installer script with startup shortcut
  • _update_log() helper writes timestamped [updater] lines to the watcher log
  • log_tail included in heartbeat payload (last 25 lines) for terra-view display
  • run_watcher(state, stop_event) pattern in series4_ingest.py for background thread use from tray

Changed

  • series4_ingest.py refactored into tray-friendly background thread module; main() retained for standalone use
  • Config key sfm_endpoint renamed to api_url for consistency with series3-watcher
  • Heartbeat payload now uses source_id, source_type, version fields matching terra-view WatcherAgent model
  • AppData folder: ThorWatcher (was not previously defined)

[0.1.1] - 2025-12-08

Changed

  • Moved configuration from hard-coded values to external config.json file
  • Configuration now loads from JSON file with graceful fallback to defaults
  • Config file is loaded relative to script location for portability

Added

  • config.json - External configuration file for all application settings
  • load_config() function with error handling and default value fallback
  • Warning messages when config file is missing or malformed

[0.1.0] - 2025-12-04

Added

  • Initial release of Series 4 Ingest Agent
  • Micromate (Series 4) heartbeat monitoring for Seismo Fleet Manager
  • THORDATA folder scanner for MLG files
  • Automatic detection of newest MLG file per unit by timestamp
  • Age calculation and status classification (OK / LATE / STALE)
  • Console heartbeat display with formatted output
  • Optional HTTP POST to SFM backend endpoint
  • Configurable age thresholds and scan intervals
  • Debug logging capability
  • Graceful error handling for filesystem and network operations