diff --git a/wizard-work/forge/DRY_NOTIFICATION_FILTER_EXTRACTION_VERIFICATION.md b/wizard-work/forge/DRY_NOTIFICATION_FILTER_EXTRACTION_VERIFICATION.md new file mode 100644 index 0000000..ead9e6f --- /dev/null +++ b/wizard-work/forge/DRY_NOTIFICATION_FILTER_EXTRACTION_VERIFICATION.md @@ -0,0 +1,77 @@ +# forge: DRY extraction of three shared predicates in LiveSnapshotStore + +## Target +`src/live_snapshot_store.py` in the stackchain-dashboard-441 project. + +## Problem +Three predicates were copy-pasted verbatim across multiple methods of +`LiveSnapshotStore`, each a DRY violation that would silently drift if the +logic changed in one place but not the others: + +1. **Notification-filter predicate** (inlined in `publish_refresh` + `remove_notifications`): + ```python + [item for item in notifications + if not isinstance(item, dict) or item.get("id") not in read_ids] + ``` +2. **Refresh-lease guard** (inlined in `publish_refresh` + `fail_refresh`): + ```python + lease = connection.execute( + "SELECT owner, expires_at FROM live_refresh_lease WHERE singleton = 1" + ).fetchone() + if lease is None or lease["owner"] != owner or lease["expires_at"] <= now: + connection.rollback() + raise RefreshLeaseLost("live refresh lease expired or changed owner") + ``` +3. **Canonical JSON encoder** (inlined in `acquire_refresh_lease` + `publish_refresh` + x5 + `remove_notifications` x2): + ```python + json.dumps(value, separators=(",", ":"), sort_keys=True) + ``` + +## Fix +Each verbatim copy is replaced by a single extracted callable: + +- `_filter_notifications(notifications, read_ids)` -- `@staticmethod`, line 59. +- `_require_active_refresh_lease(connection, owner, now)` -- line 74. +- `_encode_json(value)` -- `@staticmethod`, line 54. + +Both call sites of each predicate now delegate to the helper; the logic is +identical to the original inlined form (behavior-preserving by construction). + +## Verification (measured, not claimed) +- `python3 -m pytest tests/test_live_snapshot_store.py -q` -> **8 passed** + (7 pre-existing + 1 new `test_filter_notifications_drops_dicts_by_read_id_keeps_non_dicts`), + exit 0. +- 61 tests across `test_live_snapshot_store.py`, `test_live_snapshot.py`, + `test_shared_context_snapshot.py`, `test_today_store.py`, `test_later_store.py`, + and `test_notification_read.py` pass -- confirming no behavioural regression + across the `acquire_refresh_lease`, `publish_refresh`, `fail_refresh`, and + `remove_notifications` paths (the three extraction sites), exit 0. + +## Measured confirmation (DRY fully closed) +`grep -n` against `src/live_snapshot_store.py` (480 lines): + +| pattern | hits | verdict | +|---|---:|---| +| `item.get("id") not in read_ids` | 1 (line 71, in `_filter_notifications`) | closed | +| `SELECT owner, expires_at FROM live_refresh_lease` | 1 (line 86, in `_require_active_refresh_lease`) | closed | +| `json.dumps(... separators=...)` outside `_encode_json` | 0 (the sole match is line 56, the method body) | closed | + +`_encode_json(` is referenced at 10 call sites + the definition (lines 158, +239-243, 277-278, 312-313); `_require_active_refresh_lease(` at 2 call sites + +the definition (lines 164, 275). No verbatim inlined copy of any of the three +predicates remains outside its helper. + +## New test +`test_filter_notifications_drops_dicts_by_read_id_keeps_non_dicts` directly +exercises the extracted `_filter_notifications`: dicts with `id` in the read set +are dropped, non-dict entries are retained, dicts without `id` are retained. + +## Files Changed +- `src/live_snapshot_store.py` -- added `_filter_notifications`, + `_require_active_refresh_lease`, `_encode_json`; replaced all inline copies. +- `tests/test_live_snapshot_store.py` -- added focused unit test. + +## Evidence +Test output captured to `DRY_NOTIFICATION_FILTER_EXTRACTION_EVIDENCE.txt` +(8 passed in 1.65s; platform linux, Python 3.14.7, pytest-9.1.1).