follow_up_at liest das falsche SP-Feld: remindAt statt dueWithTime/dueDay #135

Closed
opened 2026-09-20 15:34:07 +00:00 by torben · 1 comment
Owner

Umgesetzt und veröffentlicht (2026-09-20, Commit e07d1ca, Stack 7.0.0-beta.11, im selben
Publish wie #133): docs verify, instructions verify und die volle pytest-Suite (1410 Tests)
grün. Alle Akzeptanzkriterien unten sind erfüllt und abgehakt.

Der SP-Adapter bildet follow_up_at auf remindAt ab und schließt dueDay/dueWithTime
ausdrücklich aus. Die Begründung beruft sich auf #119 D9 („ein eigenes Datum, ausdrücklich
nicht das Fälligkeitsdatum"). Die Berufung ist falsch: dueDay/dueWithTime sind bei Super
Productivity nicht das Fälligkeitsdatum.

Der Beleg

src/app/features/tasks/task.model.ts (geprüft gegen master, 2026-09-20) benennt seine Felder
selbst:

Feld Docstring im Modell
dueDay „Scheduled date as ISO date string (YYYY-MM-DD). For tasks scheduled for all-day (no specific time)"
dueWithTime „Scheduled time as Unix timestamp (ms). For tasks scheduled with a specific time"
deadlineDay „Deadline date as ISO string (YYYY-MM-DD). For deadlines without a specific time"
deadlineWithTime „Deadline as Unix timestamp (ms). For deadlines with a specific time"
deadlineRemindAt „Reminder timestamp for the deadline"

Dieselbe Datei führt den Typalias TaskPlannedWithDayOrTime = TaskWithDueTime | TaskWithDueDay.
Das due im Namen liest sich für Außenstehende wie Fälligkeit, meint aber Terminierung; SPs
Fälligkeitsdatum heißt deadline*.

D9 bleibt unverändert gültig — es schließt deadlineDay/deadlineWithTime/deadlineRemindAt
aus, und die bleiben ausgeschlossen. Korrigiert wird allein die Abbildung aus #124.

Warum das mehr ist als eine Begriffsfrage: Prüfung 2 ist heute blind

remindAt existiert nur, wenn eine Aufgabe auf eine Uhrzeit terminiert ist und jemand eine
Benachrichtigung wollte:

  • src/app/features/reminder/migrate-legacy-task-reminders.util.ts setzt beim Übernehmen eines
    Reminders dueWithTime = reminder.remindAt — der Reminder hängt an einer Terminierung mit
    Uhrzeit.
  • task.model.ts führt eigens den Typ TaskWithoutReminder { remindAt: undefined } für
    terminierte Aufgaben ohne Erinnerung.

Der Normalfall eines Ticklers — ein waiting-Posten, ganztägig auf den 15. gelegt, ohne
Benachrichtigung — trägt damit dueDay: "2026-10-15" und kein remindAt. Prüfung 2
(tools/chemenu/review.py:175) überspringt ihn wegen follow_up_at is None. Ein korrekt
angelegter Posten fällt still durch. Das ist genau die leise Falschheit, gegen die der Stack sonst
überall anläuft.

Zweite Folge: erst damit wird der Schreibweg möglich

SPs lokale REST-API lässt remindAt nicht schreiben — ALLOWED_TASK_FIELDS
(src/app/core/electron/local-rest-api-handler.service.ts:37) führt es nicht, dueDay und
dueWithTime dagegen schon. Mit der korrigierten Abbildung kann #132 einen WAITING-Posten
samt follow_up_at anlegen; mit der heutigen könnte er es nicht, und alle übrigen schreibbaren
Datumsfelder sind Deadline-Felder und damit durch D9 ausgeschlossen.

Was sich am Verhalten ändert

Prüfung 2 schlägt künftig häufiger an, aus zwei Richtungen: das geschlossene Loch (ganztägige
Tickler) und die breitere Abbildung — ein waiting-Posten, der aus einem anderen Grund terminiert
ist, liest sich jetzt als Nachfasstermin.

Das Zweite ist bewusst hingenommen: ein WAITING-Posten ist nichts, was man selbst bearbeitet, sein
Termin ist der Nachfasstermin. Für Prüfung 2 bleibt die Aussage dieselbe — der Termin ist
überschritten.

Bestehende Instanzen sehen dadurch in einem Rückblick mehr Befunde als vorher. Kein Datenverlust,
keine Handarbeit beim Upgrade, also nach instructions/dev/version-parts.md kein Grenzübertritt —
aber ein Changelog-Eintrag, der die Verhaltensänderung ausdrücklich benennt. (Umgesetzt: der
Changelog-Eintrag zu 7.0.0-beta.11 benennt sie, gemeinsam mit #133s eigener Verhaltensänderung
an Prüfung 3.)

Akzeptanzkriterien

  • SuperProductivityReader.open_items liest follow_up_at als dueWithTime, sonst dueDay —
    in dieser Reihenfolge, weil SPs eigene Leseregel sie vorgibt („When reading, check
    dueWithTime FIRST (it takes priority over dueDay)").
  • Ein waiting-Posten mit dueDay und ohne remindAt erzeugt einen waiting_overdue-Befund,
    sobald die Schwelle überschritten ist. Ein Fixture-Test hält genau diesen Fall fest — er ist
    der Grund für dieses Issue.
  • deadlineDay, deadlineWithTime und deadlineRemindAt werden nie als follow_up_at
    gelesen; ein Posten, der nur diese trägt, hat follow_up_at: None. Getestet.
  • remindAt wird nicht mehr gelesen, und kein Test stützt sich noch darauf.
  • Der Modul-Docstring von tools/chemenu/tasks/superproductivity.py sagt, welches SP-Feld
    das Fälligkeitsdatum ist und warum due* nicht dazugehört — belegt mit dem Wortlaut aus
    task.model.ts, nicht als Behauptung.
  • Der D9-Absatz in tools/chemenu/tasks/protocol.py („deliberately not the item's due
    date") formuliert die Regel so, dass sie auch einen Provider bindet, dessen Feldnamen anders
    liegen als seine Begriffe. Genau dieser Fall ist hier eingetreten.
  • #128 ist um den korrigierten Wortlaut nachgezogen — es trägt die Regel für den zweiten
    Adapter ausgeschrieben.
  • docs verify, instructions verify, pytest grün. Version gebumpt, mit einem
    Changelog-Eintrag, der die Verhaltensänderung an Prüfung 2 benennt.

Abhängigkeiten

Keine blockierenden. Berührungspunkte: #132 (der Schreibweg für follow_up_at hängt daran), #133
(dieselbe Quellcode-Verifikation, inhaltlich unabhängig — beide im selben Publish umgesetzt), #128
(erbt die Regel — Body dort nachgezogen), #119 (Entscheidungsgeschichte, geschlossen — D9 selbst
bleibt gültig, nur #124s Abbildung war falsch).

Umsetzung

chemenu.tasks.superproductivity._follow_up_at: liest dueWithTime, sonst dueDay, nie
remindAt/deadline* - geteilt zwischen SuperProductivityReader (Schnappschuss) und dem neuen
SuperProductivityApiReader (#133) über eine gemeinsame Modulfunktion. chemenu.tasks.protocol:
WaitingItems Docstring trägt jetzt die Korrektur selbst - die Regel bindet den Begriff
Fälligkeitsdatum, nicht einen Feldnamen. tasks/protocol.pys Moduldocstring (die verify()-
Begründung aus #134) korrigiert im selben Zug. Tests: test_superproductivity.py (vier neue
follow_up_at-Tests: dueWithTime, dueDay-Fallback, Priorität, nie remindAt/deadline*),
test_review.py (test_check2_fires_for_an_all_day_waiting_item_with_no_due_with_time - der
Fixture-Test, der der eigentliche Grund für dieses Issue war). Gitea #128s Body um die Korrektur
nachgezogen. Version: gemeinsam mit #133 auf 7.0.0-beta.11 (MAJOR, dort begründet - #133s
Feldpflicht trägt den Grenzübertritt, nicht diese Änderung für sich allein, die selbst kein
Grenzübertritt wäre). Commit e07d1ca.

**Umgesetzt und veröffentlicht** (2026-09-20, Commit `e07d1ca`, Stack `7.0.0-beta.11`, im selben Publish wie #133): `docs verify`, `instructions verify` und die volle `pytest`-Suite (1410 Tests) grün. Alle Akzeptanzkriterien unten sind erfüllt und abgehakt. Der SP-Adapter bildet `follow_up_at` auf `remindAt` ab und schließt `dueDay`/`dueWithTime` ausdrücklich aus. Die Begründung beruft sich auf #119 D9 („ein eigenes Datum, ausdrücklich **nicht** das Fälligkeitsdatum"). Die Berufung ist falsch: `dueDay`/`dueWithTime` sind bei Super Productivity nicht das Fälligkeitsdatum. ## Der Beleg `src/app/features/tasks/task.model.ts` (geprüft gegen `master`, 2026-09-20) benennt seine Felder selbst: | Feld | Docstring im Modell | |---|---| | `dueDay` | „**Scheduled** date as ISO date string (YYYY-MM-DD). For tasks scheduled for all-day (no specific time)" | | `dueWithTime` | „**Scheduled** time as Unix timestamp (ms). For tasks scheduled with a specific time" | | `deadlineDay` | „**Deadline** date as ISO string (YYYY-MM-DD). For deadlines without a specific time" | | `deadlineWithTime` | „**Deadline** as Unix timestamp (ms). For deadlines with a specific time" | | `deadlineRemindAt` | „Reminder timestamp for the deadline" | Dieselbe Datei führt den Typalias `TaskPlannedWithDayOrTime = TaskWithDueTime | TaskWithDueDay`. Das `due` im Namen liest sich für Außenstehende wie Fälligkeit, meint aber Terminierung; SPs Fälligkeitsdatum heißt `deadline*`. **D9 bleibt unverändert gültig** — es schließt `deadlineDay`/`deadlineWithTime`/`deadlineRemindAt` aus, und die bleiben ausgeschlossen. Korrigiert wird allein die Abbildung aus #124. ## Warum das mehr ist als eine Begriffsfrage: Prüfung 2 ist heute blind `remindAt` existiert nur, wenn eine Aufgabe auf eine **Uhrzeit** terminiert ist **und** jemand eine Benachrichtigung wollte: - `src/app/features/reminder/migrate-legacy-task-reminders.util.ts` setzt beim Übernehmen eines Reminders `dueWithTime = reminder.remindAt` — der Reminder hängt an einer Terminierung mit Uhrzeit. - `task.model.ts` führt eigens den Typ `TaskWithoutReminder { remindAt: undefined }` für terminierte Aufgaben ohne Erinnerung. Der Normalfall eines Ticklers — ein `waiting`-Posten, ganztägig auf den 15. gelegt, ohne Benachrichtigung — trägt damit `dueDay: "2026-10-15"` und **kein** `remindAt`. Prüfung 2 (`tools/chemenu/review.py:175`) überspringt ihn wegen `follow_up_at is None`. Ein korrekt angelegter Posten fällt still durch. Das ist genau die leise Falschheit, gegen die der Stack sonst überall anläuft. ## Zweite Folge: erst damit wird der Schreibweg möglich SPs lokale REST-API lässt `remindAt` nicht schreiben — `ALLOWED_TASK_FIELDS` (`src/app/core/electron/local-rest-api-handler.service.ts:37`) führt es nicht, `dueDay` und `dueWithTime` dagegen schon. Mit der korrigierten Abbildung kann #132 einen `WAITING`-Posten **samt** `follow_up_at` anlegen; mit der heutigen könnte er es nicht, und alle übrigen schreibbaren Datumsfelder sind Deadline-Felder und damit durch D9 ausgeschlossen. ## Was sich am Verhalten ändert Prüfung 2 schlägt künftig häufiger an, aus zwei Richtungen: das geschlossene Loch (ganztägige Tickler) und die breitere Abbildung — ein `waiting`-Posten, der aus einem anderen Grund terminiert ist, liest sich jetzt als Nachfasstermin. Das Zweite ist bewusst hingenommen: ein WAITING-Posten ist nichts, was man selbst bearbeitet, sein Termin *ist* der Nachfasstermin. Für Prüfung 2 bleibt die Aussage dieselbe — der Termin ist überschritten. Bestehende Instanzen sehen dadurch in einem Rückblick mehr Befunde als vorher. Kein Datenverlust, keine Handarbeit beim Upgrade, also nach `instructions/dev/version-parts.md` kein Grenzübertritt — aber ein Changelog-Eintrag, der die Verhaltensänderung ausdrücklich benennt. (Umgesetzt: der Changelog-Eintrag zu `7.0.0-beta.11` benennt sie, gemeinsam mit #133s eigener Verhaltensänderung an Prüfung 3.) ## Akzeptanzkriterien - [x] `SuperProductivityReader.open_items` liest `follow_up_at` als `dueWithTime`, sonst `dueDay` — in dieser Reihenfolge, weil SPs eigene Leseregel sie vorgibt („When reading, check `dueWithTime` FIRST (it takes priority over `dueDay`)"). - [x] Ein `waiting`-Posten mit `dueDay` und ohne `remindAt` erzeugt einen `waiting_overdue`-Befund, sobald die Schwelle überschritten ist. Ein Fixture-Test hält genau diesen Fall fest — er ist der Grund für dieses Issue. - [x] `deadlineDay`, `deadlineWithTime` und `deadlineRemindAt` werden nie als `follow_up_at` gelesen; ein Posten, der nur diese trägt, hat `follow_up_at: None`. Getestet. - [x] `remindAt` wird nicht mehr gelesen, und kein Test stützt sich noch darauf. - [x] Der Modul-Docstring von `tools/chemenu/tasks/superproductivity.py` sagt, **welches** SP-Feld das Fälligkeitsdatum ist und warum `due*` nicht dazugehört — belegt mit dem Wortlaut aus `task.model.ts`, nicht als Behauptung. - [x] Der D9-Absatz in `tools/chemenu/tasks/protocol.py` („deliberately **not** the item's due date") formuliert die Regel so, dass sie auch einen Provider bindet, dessen Feldnamen anders liegen als seine Begriffe. Genau dieser Fall ist hier eingetreten. - [x] #128 ist um den korrigierten Wortlaut nachgezogen — es trägt die Regel für den zweiten Adapter ausgeschrieben. - [x] `docs verify`, `instructions verify`, `pytest` grün. Version gebumpt, mit einem Changelog-Eintrag, der die Verhaltensänderung an Prüfung 2 benennt. ## Abhängigkeiten Keine blockierenden. Berührungspunkte: #132 (der Schreibweg für `follow_up_at` hängt daran), #133 (dieselbe Quellcode-Verifikation, inhaltlich unabhängig — beide im selben Publish umgesetzt), #128 (erbt die Regel — Body dort nachgezogen), #119 (Entscheidungsgeschichte, geschlossen — D9 selbst bleibt gültig, nur #124s Abbildung war falsch). ## Umsetzung `chemenu.tasks.superproductivity._follow_up_at`: liest `dueWithTime`, sonst `dueDay`, nie `remindAt`/`deadline*` - geteilt zwischen `SuperProductivityReader` (Schnappschuss) und dem neuen `SuperProductivityApiReader` (#133) über eine gemeinsame Modulfunktion. `chemenu.tasks.protocol`: `WaitingItem`s Docstring trägt jetzt die Korrektur selbst - die Regel bindet den *Begriff* Fälligkeitsdatum, nicht einen Feldnamen. `tasks/protocol.py`s Moduldocstring (die `verify()`- Begründung aus #134) korrigiert im selben Zug. Tests: `test_superproductivity.py` (vier neue `follow_up_at`-Tests: `dueWithTime`, `dueDay`-Fallback, Priorität, nie `remindAt`/`deadline*`), `test_review.py` (`test_check2_fires_for_an_all_day_waiting_item_with_no_due_with_time` - der Fixture-Test, der der eigentliche Grund für dieses Issue war). Gitea #128s Body um die Korrektur nachgezogen. Version: gemeinsam mit #133 auf `7.0.0-beta.11` (MAJOR, dort begründet - #133s Feldpflicht trägt den Grenzübertritt, nicht diese Änderung für sich allein, die selbst kein Grenzübertritt wäre). Commit `e07d1ca`.
torben added the prio/plannedsize/Sarea/kbkind/defect labels 2026-09-20 15:34:07 +00:00
Author
Owner

Umgesetzt und veröffentlicht: Commit e07d1ca, Stack 7.0.0-beta.11 (im selben Publish wie #133). docs verify, instructions verify, pytest (1410 Tests) grün. Body oben auf den Endzustand nachgezogen, alle Akzeptanzkriterien abgehakt, inklusive #128s nachgezogener Regel-1-Korrektur.

Umgesetzt und veröffentlicht: Commit `e07d1ca`, Stack `7.0.0-beta.11` (im selben Publish wie #133). `docs verify`, `instructions verify`, `pytest` (1410 Tests) grün. Body oben auf den Endzustand nachgezogen, alle Akzeptanzkriterien abgehakt, inklusive #128s nachgezogener Regel-1-Korrektur.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#135