diff --git a/src/journal_bot/context.py b/src/journal_bot/context.py index 62cfb66..b032bc0 100644 --- a/src/journal_bot/context.py +++ b/src/journal_bot/context.py @@ -21,6 +21,11 @@ def _read_frontmatter(text: str) -> dict[str, str]: return out +def day_context(d: date) -> dict: + """today/weekday for a given date (the message's send day).""" + return {"today": d.isoformat(), "weekday": WEEKDAYS_DE[d.weekday()]} + + def collect_vault_context(vault_path: Path, today: date) -> dict: persons: list[dict] = [] persons_dir = vault_path / "00 Kontext" / "Personen" diff --git a/src/journal_bot/process.py b/src/journal_bot/process.py index 2b29ce5..e1fa403 100644 --- a/src/journal_bot/process.py +++ b/src/journal_bot/process.py @@ -1,6 +1,6 @@ from datetime import date, datetime from pathlib import Path -from .context import collect_vault_context +from .context import collect_vault_context, day_context from .queue import Queue from .vault_writer import VaultWriter from .processor_protocol import ProcessorInput @@ -18,9 +18,14 @@ def process_once(processor, queue: Queue, writer: VaultWriter, vault_path: Path, try: received_dt = datetime.fromisoformat(item.received_at) received_time = received_dt.strftime("%H:%M") + # Default day is the message's SEND day, not the processing day, + # so a message sent yesterday but processed today lands in + # yesterday's note. "gestern"/"heute" in the text are relative + # to the send day. Fall back to `today` if received_at is unusable. + send_day = day_context(received_dt.date()) payload = ProcessorInput( - today=ctx["today"], - weekday=ctx["weekday"], + today=send_day["today"], + weekday=send_day["weekday"], received_time=received_time, persons=ctx["persons"], projects=ctx["projects"], diff --git a/src/journal_bot/prompts/journal_system.md b/src/journal_bot/prompts/journal_system.md index 8953981..f5f9fb6 100644 --- a/src/journal_bot/prompts/journal_system.md +++ b/src/journal_bot/prompts/journal_system.md @@ -15,7 +15,7 @@ Antworte ausschließlich mit einem JSON-Objekt nach folgendem Schema. Kein Flie # Regeln -1. **target_date:** Standard = `today` aus dem Context. Bei „gestern" → today − 1, „vorgestern" → today − 2. Bei explizitem Datum (z.B. „am 12. Juni") dieses verwenden. +1. **target_date:** Standard = `today` aus dem Context. `today` ist der **Sendetag der Nachricht** (nicht der Verarbeitungstag), also der Tag, an dem Christian die Nachricht geschrieben hat. Bei „gestern" → today − 1, „vorgestern" → today − 2 (relativ zum Sendetag). Bei explizitem Datum (z.B. „am 12. Juni") dieses verwenden. 2. **target_path:** Immer `05 Daily Notes/{target_date}.md`. 3. **entry_markdown:** Beginnt IMMER mit `## HH:MM`. Nutze `received_time` aus dem Context. 4. **Meta-Anweisungen entfernen:** Phrasen wie „Schreib ins Journal, dass …", „Notier dir, dass …", „Merk dir …" gehören NICHT in den Eintragstext. Liste sie in `raw_excluded`. diff --git a/tests/test_process.py b/tests/test_process.py index 7c231bd..4ad509e 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -22,6 +22,23 @@ class FakeProcessor: return self._output +class CapturingProcessor: + """Records the payload it was asked to process and echoes today as target.""" + def __init__(self): + self.payload = None + + def health_check(self): + return True + + def process(self, payload): + self.payload = payload + return ProcessorOutput( + target_date=payload.today, + target_path=f"05 Daily Notes/{payload.today}.md", + entry_markdown=f"## {payload.received_time}\n{payload.text}", + ) + + def make_item(update_id=1, text="Hallo"): return QueueItem( update_id=update_id, @@ -74,6 +91,35 @@ def test_process_fails_item_on_error(tmp_path): assert data["attempts"] == 1 +def test_target_date_follows_send_day_not_processing_day(tmp_path): + # Message sent yesterday (2026-06-25), processed today (2026-06-26). + # The daily note must be the send day, not the processing day. + vault = tmp_path / "vault" + (vault / "05 Daily Notes").mkdir(parents=True) + queue = Queue(tmp_path / "q") + item = QueueItem( + update_id=1, + received_at="2026-06-25T08:13:42+02:00", + type="text", + text="Neue Charge Kefir angesetzt", + ) + queue.enqueue(item) + processor = CapturingProcessor() + writer = VaultWriter(vault) + process_once( + processor, queue, writer, + vault_path=vault, + today=date(2026, 6, 26), # processing day differs from send day + processed_at="2026-06-26T06:55:22+02:00", + ) + # The processor must have been told today = the send day, with matching weekday. + assert processor.payload.today == "2026-06-25" + assert processor.payload.weekday == "Donnerstag" # 2026-06-25 is a Thursday + # And the entry landed in the send-day note. + data = json.loads((tmp_path / "q" / "done" / "1.json").read_text(encoding="utf-8")) + assert data["target_path"] == "05 Daily Notes/2026-06-25.md" + + def test_process_records_result_fields(tmp_path): vault = tmp_path / "vault" (vault / "05 Daily Notes").mkdir(parents=True)