update to 0.26.0. Big chonking update including 0.23, 0.24, and 0.25 as well. #33

Merged
serversdown merged 30 commits from dev into main 2026-08-27 13:43:01 -04:00
4 changed files with 74 additions and 10 deletions
Showing only changes of commit 37043a47e9 - Show all commits
+7 -4
View File
@@ -24,13 +24,16 @@ window).
`SeismoDb()` construction, no manual migration). `query_events` /
`get_event` (and thus `/db/events`) return it automatically (`SELECT *`).
- **Mutual exclusivity with `false_trigger`** — setting `reviewed_real=1`
clears `false_trigger`, and vice versa, both via `set_false_trigger` /
the sidecar review PATCH path.
clears `false_trigger`, and vice versa, enforced on both review paths:
the sidecar review PATCH (`update_event_review`) and the quick
`PATCH /db/events/{id}/false_trigger` endpoint (`set_false_trigger`).
- **`find_twins`** — matches an event's histogram/waveform twins by serial +
identical peak-vector-sum + a timestamp window.
- **`propagate_review_to_twins`** — copies an event's `false_trigger`/
`reviewed_real` state onto its twins, wired into the
`PATCH /db/events/{id}/sidecar` review path so flagging one flags both.
`reviewed_real` state onto its twins, wired into both the
`PATCH /db/events/{id}/sidecar` review path and the quick
`PATCH /db/events/{id}/false_trigger` path, so flagging one flags both
regardless of which endpoint made the change.
---
+28 -5
View File
@@ -610,6 +610,16 @@ class SeismoDb:
within ``window_seconds`` of this event's timestamp. Excludes the
event itself. Returns [] if the event or any required field
(serial / peak_vector_sum / timestamp) is missing.
Caveat: identical-PVS matching is a proxy for "same physical event
recorded twice," not a guarantee. In the rare case where the device
clamps/saturates PVS (clamped to sqrt(3) * geo_range), two distinct
saturated events on the same serial within the window can share the
same clamped PVS value and be matched as twins even though they are
different events. This is harmless in practice — false_trigger/
reviewed_real are derived/index columns re-derivable from the
sidecar source of truth — but worth knowing if twin counts look
surprising on a saturated/clamped run.
"""
row = self.get_event(event_id)
if not row:
@@ -652,12 +662,25 @@ class SeismoDb:
return moved
def set_false_trigger(self, event_id: str, value: bool) -> bool:
"""Set or clear the false_trigger flag on an event. Returns True if found."""
"""
Set or clear the false_trigger flag on an event. Returns True if found.
Mirrors the 3-state exclusivity enforced by `update_event_review`:
setting false_trigger true also clears `reviewed_real` (a false
trigger can't also be a confirmed-real event). Clearing false_trigger
leaves `reviewed_real` untouched.
"""
with self._connect() as conn:
cur = conn.execute(
"UPDATE events SET false_trigger=? WHERE id=?",
(1 if value else 0, event_id),
)
if value:
cur = conn.execute(
"UPDATE events SET false_trigger=1, reviewed_real=0 WHERE id=?",
(event_id,),
)
else:
cur = conn.execute(
"UPDATE events SET false_trigger=0 WHERE id=?",
(event_id,),
)
return cur.rowcount > 0
def delete_event(self, event_id: str) -> Optional[dict]:
+10 -1
View File
@@ -1957,7 +1957,10 @@ def db_set_false_trigger(
value: bool = Query(..., description="True to flag as false trigger, False to clear"),
) -> dict:
"""
Set or clear the false_trigger flag on a single event.
Set or clear the false_trigger flag on a single event. Enforces the
same 3-state exclusivity as the sidecar review PATCH (flagging false_trigger
clears reviewed_real) and propagates the resulting flags to the event's
histogram/waveform twin(s), same as the sidecar path.
Used by the terra-view event review UI.
Returns 404 if the event_id is not found.
@@ -1965,6 +1968,12 @@ def db_set_false_trigger(
found = _get_db().set_false_trigger(event_id, value)
if not found:
raise HTTPException(status_code=404, detail=f"Event {event_id} not found")
try:
_get_db().propagate_review_to_twins(event_id)
except Exception as exc:
log.warning("twin review-propagation failed for %s: %s", event_id, exc)
return {"status": "ok", "event_id": event_id, "false_trigger": value}
@@ -0,0 +1,29 @@
from sfm.database import SeismoDb
from minimateplus.models import Event
def _ins(db, eid_key="01110000", serial="BE1"):
ev = Event(index=0); ev._waveform_key = bytes.fromhex(eid_key)
db.insert_events([ev], serial=serial)
return db.query_events(serial=serial)[0]["id"]
def test_set_false_trigger_clears_reviewed_real(tmp_path):
db = SeismoDb(tmp_path / "s.db"); eid = _ins(db)
db.update_event_review(eid, {"reviewed_real": True})
assert db.get_event(eid)["reviewed_real"] == 1
db.set_false_trigger(eid, True)
row = db.get_event(eid)
assert row["false_trigger"] == 1 and row["reviewed_real"] == 0
def test_clearing_false_trigger_leaves_reviewed_real_untouched(tmp_path):
db = SeismoDb(tmp_path / "s.db"); eid = _ins(db)
db.update_event_review(eid, {"false_trigger": True})
db.set_false_trigger(eid, False)
row = db.get_event(eid)
assert row["false_trigger"] == 0
# reviewed_real was never set true, so it stays 0 either way; the point
# is set_false_trigger(False) does not touch the column at all.
assert row["reviewed_real"] == 0