From f73c8eec9105e2d9ccc56a0172def29e08b09618 Mon Sep 17 00:00:00 2001 From: serversdown Date: Tue, 25 Aug 2026 00:34:25 +0000 Subject: [PATCH] feat(db): update_event_review mirrors reviewed_real + enforces 3-state exclusivity --- sfm/database.py | 36 +++++++++++++------ .../test_update_event_review_reviewed_real.py | 25 +++++++++++++ 2 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 tests/test_update_event_review_reviewed_real.py diff --git a/sfm/database.py b/sfm/database.py index 846ebcf..90f54ea 100644 --- a/sfm/database.py +++ b/sfm/database.py @@ -685,17 +685,23 @@ class SeismoDb: """ Sync derived index columns from a sidecar's `review` block. - Currently the only derived index is `events.false_trigger` — kept - in sync so `/db/events?false_trigger=true` queries don't have to - scan every sidecar JSON on disk. The sidecar JSON itself remains - the source of truth for the full review state. + The derived indexes are `events.false_trigger` and + `events.reviewed_real` — kept in sync so `/db/events` queries don't + have to scan every sidecar JSON on disk. The sidecar JSON itself + remains the source of truth for the full review state. + + The two columns are mutually exclusive: setting either one true + forces the other's column to 0. Returns True when the row exists, False otherwise. No-op fields - (review without `false_trigger`) leave the column untouched. + (review without `false_trigger` or `reviewed_real`) leave both + columns untouched. """ if not isinstance(review, dict): return False - if "false_trigger" not in review: + has_ft = "false_trigger" in review + has_real = "reviewed_real" in review + if not has_ft and not has_real: # Nothing derived to update; just confirm the row exists. with self._connect() as conn: row = conn.execute( @@ -703,12 +709,20 @@ class SeismoDb: ).fetchone() return row is not None - flag = 1 if review.get("false_trigger") else 0 + sets = {} + if has_ft: + sets["false_trigger"] = 1 if review.get("false_trigger") else 0 + if has_real: + sets["reviewed_real"] = 1 if review.get("reviewed_real") else 0 + # mutual exclusivity: a true in one forces the other column to 0 + if sets.get("false_trigger") == 1: + sets["reviewed_real"] = 0 + if sets.get("reviewed_real") == 1: + sets["false_trigger"] = 0 + assign = ", ".join(f"{k}=?" for k in sets) + params = list(sets.values()) + [event_id] with self._connect() as conn: - cur = conn.execute( - "UPDATE events SET false_trigger=? WHERE id=?", - (flag, event_id), - ) + cur = conn.execute(f"UPDATE events SET {assign} WHERE id=?", params) return cur.rowcount > 0 # ── Monitor log ─────────────────────────────────────────────────────────── diff --git a/tests/test_update_event_review_reviewed_real.py b/tests/test_update_event_review_reviewed_real.py new file mode 100644 index 0000000..ea09162 --- /dev/null +++ b/tests/test_update_event_review_reviewed_real.py @@ -0,0 +1,25 @@ +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_confirm_real_sets_and_clears_ft(tmp_path): + db = SeismoDb(tmp_path/"s.db"); eid = _ins(db) + db.update_event_review(eid, {"false_trigger": True}) + assert db.get_event(eid)["false_trigger"] == 1 + db.update_event_review(eid, {"reviewed_real": True}) # confirming real clears FT + row = db.get_event(eid) + assert row["reviewed_real"] == 1 and row["false_trigger"] == 0 + + +def test_flag_ft_clears_reviewed_real(tmp_path): + db = SeismoDb(tmp_path/"s.db"); eid = _ins(db) + db.update_event_review(eid, {"reviewed_real": True}) + db.update_event_review(eid, {"false_trigger": True}) + row = db.get_event(eid) + assert row["false_trigger"] == 1 and row["reviewed_real"] == 0