personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

audit: dedupe reflection_ready chat events

+49 -2
+36
tests/test_push_triggers.py
··· 392 392 assert sleeps == [1] * 10 393 393 assert send_calls == [] 394 394 assert chat_events == [] 395 + 396 + 397 + def test_handle_weekly_reflection_finish_dedupes_chat_event_without_devices( 398 + monkeypatch, tmp_path 399 + ): 400 + monkeypatch.setenv("_SOLSTONE_JOURNAL_OVERRIDE", str(tmp_path)) 401 + reflection_path = tmp_path / "reflections" / "weekly" / "20260308.md" 402 + reflection_path.parent.mkdir(parents=True, exist_ok=True) 403 + reflection_path.write_text("# reflection\n", encoding="utf-8") 404 + monkeypatch.setattr(triggers.time, "sleep", lambda seconds: None) 405 + monkeypatch.setattr(triggers, "_eligible_devices", lambda: []) 406 + chat_events: list[dict[str, object]] = [] 407 + monkeypatch.setattr(triggers, "read_chat_events", lambda day: list(chat_events)) 408 + monkeypatch.setattr( 409 + triggers, 410 + "append_chat_event", 411 + lambda kind, **fields: chat_events.append({"kind": kind, **fields}), 412 + ) 413 + 414 + message = { 415 + "tract": "cortex", 416 + "event": "finish", 417 + "name": "weekly_reflection", 418 + "day": "20260308", 419 + } 420 + triggers.handle_weekly_reflection_finish(message) 421 + triggers.handle_weekly_reflection_finish(message) 422 + 423 + assert chat_events == [ 424 + { 425 + "kind": "reflection_ready", 426 + "day": "20260308", 427 + "url": "/app/reflections/20260308", 428 + } 429 + ] 430 + assert not _log_path(tmp_path).exists()
+13 -2
think/push/triggers.py
··· 13 13 from typing import Any 14 14 15 15 from apps.home.routes import _load_briefing_md 16 - from convey.chat_stream import append_chat_event 16 + from convey.chat_stream import append_chat_event, read_chat_events 17 17 from think.activities import load_activity_records 18 18 from think.facets import get_enabled_facets 19 19 from think.push.config import get_bundle_id, get_environment, is_configured ··· 113 113 "failed": failed, 114 114 **payload, 115 115 } 116 + ) 117 + 118 + 119 + def _has_reflection_ready_event(day: str, route: str) -> bool: 120 + today = datetime.now().strftime("%Y%m%d") 121 + return any( 122 + event.get("kind") == "reflection_ready" 123 + and event.get("day") == day 124 + and event.get("url") == route 125 + for event in read_chat_events(today) 116 126 ) 117 127 118 128 ··· 278 288 context_id=context_id, 279 289 route=route, 280 290 ) 281 - append_chat_event("reflection_ready", day=day, url=route) 291 + if not _has_reflection_ready_event(day, route): 292 + append_chat_event("reflection_ready", day=day, url=route) 282 293 283 294 284 295 __all__ = [