SP-Zugriff je Instanz explizit: access: api oder access: snapshot, kein Default, kein Rückfall #133

Closed
opened 2026-09-20 11:50:04 +00:00 by torben · 5 comments
Owner

Umgesetzt und veröffentlicht (2026-09-20, Commit e07d1ca, Stack 7.0.0-beta.11, MAJOR mit
--breaking/--no-migration): docs verify, instructions verify und die volle pytest-Suite
(1410 Tests) grün. Alle Akzeptanzkriterien unten sind erfüllt und abgehakt.

Der Super-Productivity-Adapter liest heute ausschließlich einen periodischen Backup-Schnappschuss.
Läuft die Anwendung, gibt es daneben eine lokale REST-API mit dem aktuellen Zustand.

Die Wege schließen sich je System aus (Betreiber, 2026-09-20): eine headless bediente Instanz
geht immer auf die Datei, der Desktop immer auf die API. Kein Mischfall in Sicht. Also sagt jede
Instanz ausdrücklich, welchen Weg sie nimmt — und nimmt nur den.

Kompatibilität ist kein Kriterium (Betreiber, 2026-09-20): der Stack ist unveröffentlicht, die
Konfiguration wird überarbeitet statt erweitert. Das Feld ist deshalb Pflicht und trägt keinen
Default — eine Konfiguration, die den Weg nicht nennt, ist unvollständig, nicht „die alte".

Alles entschieden, nichts mehr offen. Die Verifikation gegen den SP-Quellcode ist am
2026-09-20 gelaufen (Ergebnis unten); der API-Weg trägt den Lesepfad vollständig und darf
angeboten werden.

Die Entscheidung

access im providereigenen Block, Pflicht, zwei Werte:

Wert Liest Schreibt Eigene Felder
api lokale REST-API, aktueller Zustand Posten ja (#132); Projektanlage nein — siehe unten api_base_url, api_token
snapshot Backup-Schnappschuss, headless nein — der Tracker ist von hier aus nur lesbar backups_dir

Kein auto, kein Rückfall, keine Mischform. Der Name ist bewusst nicht read_via: das Feld
entscheidet beide Hälften, nicht nur das Lesen.

Der Block trägt nur die Felder seines Wegs. Ein backups_dir neben access: api wird beim
Lesen der Konfiguration abgelehnt, nicht ignoriert: eine Konfiguration, die zwei Wege beschreibt,
behauptet etwas, das nicht gilt — und beim nächsten Blick weiß niemand mehr, welcher Teil wirksam
ist.

api_token ist bei access: api Pflicht, nicht das heute optionale Durchreichfeld:
verifiziert ist, dass jeder Endpunkt außer GET /health einen Authorization: Bearer <token>
verlangt. Eine api-Instanz ohne Token kann nichts lesen.

Projektanlage bleibt auch auf dem API-Weg ein Menschenschritt

Korrektur gegenüber der früheren Fassung dieses Bodys (Verifikation 2026-09-20): es gibt
weiterhin kein POST /projects. Registriert sind ausschließlich GET /status, GET /focus,
GET|POST /task-control/*, GET|POST /tasks, GET|PATCH|DELETE /tasks/:id, GET /projects,
GET /tags (src/app/core/electron/local-rest-api-handler.service.ts:420). Projekt-CRUD und
Tag-CRUD existieren nicht.

wikitool new project bleibt auf einer api-Instanz also bei HumanInterventionRequired/Exit 42
wie bisher. Was der API-Weg dort gewinnt, ist allein die Verifikation: --resume prüft über
einen Lesepfad, der den aktuellen Zustand sieht, statt gegen ein womöglich älteres Backup zu
laufen. Genau das war #134, und genau deshalb ist es aufgelöst.

new project verweigert auf einer snapshot-Instanz

Entschieden (Betreiber, 2026-09-20). Und zwar vollständig: kein Tracker-Projekt, und auch
keine Seite
. Ein gewöhnlicher Validierungsfehler mit Exit 1, der auf die api-Instanz verweist —
kein Exit 42, denn hier wartet nichts auf eine Freigabe; das Kommando kann es an dieser Stelle
schlicht nicht. --resume verhält sich gleich.

Das sieht neben dem vorhandenen Verhalten „kein Tracker konfiguriert → nur die Seite, ausdrücklich
angesagt" inkonsistent aus und ist es nicht. Der Unterschied ist, ob überhaupt gejoint wird:

  • Kein Tracker konfiguriert: review läuft gar nicht (es scheitert an der fehlenden
    Konfiguration). Eine Seite ohne Tracker-Projekt ist dort der Normalzustand und fällt niemandem
    auf die Füße.
  • access: snapshot: review läuft. Eine Seite ohne Tracker-Projekt ist dort genau das, was
    Prüfung 4 (no_open_loop) als Befund meldet — die Hälfte eines Paars, angelegt von einer Instanz,
    die die andere Hälfte gar nicht anlegen kann.

Kosten: praktisch keine. An einer headless bedienten Instanz sitzt niemand, der ein Projekt anlegt.

db_path wird gestrichen

Entschieden (Betreiber, 2026-09-20). backups_dir ist damit für access: snapshot das einzige und
pflichtige Feld, und latest_snapshot_path() verliert seinen Zweig.

Was dieser Verzicht tragend macht (Verifikation 2026-09-20): electron/backup.ts:148 schreibt
<userData>/backups/YYYY-MM-DD_HHmmss.json — ohne Präfix, lexikalisch also gleich chronologisch.
Zwei Haken, die heute niemand bemerkt hätte, weil db_path sie umgehen konnte:

  • SP selbst sortiert in listBackupFiles nach mtime, nicht lexikalisch. Der zitierte Kommentar
    „timestamps sort lexically" steht an der Windows-Store-Pfadwahl, nicht an der Sortierung.
  • Die manuellen Exporte heißen sp-backup_*, sp-backup-anonymized_*,
    sp-pre-migration-backup_* (electron/shared-with-frontend/get-backup-timestamp.ts). Die
    sortieren hinter jeden reinen Zeitstempel. Eine einzige dorthin abgelegte Exportdatei würde
    den Leser dauerhaft auf einen alten Stand nageln.

Also: der Glob wird auf das Zeitstempelmuster eingeschränkt statt auf *.json.

Das Ergebnis der Quellcode-Verifikation (2026-09-20)

Gegen super-productivity/super-productivity@master. Die Routen liegen nicht in
electron/local-rest-api.ts — das ist nur Transport, /health und Token-Prüfung — sondern im
Renderer unter src/app/core/electron/local-rest-api-handler.service.ts. Die Pfadangabe im
Modul-Docstring des Adapters ist entsprechend falsch und wird nachgezogen.

Gebraucht Ergebnis
Projektliste mit Anlagedatum ja — GET /projects liefert die vollen Project-Objekte; created?: number (packages/plugin-api/src/types.ts)
Offene Posten je Projekt ja — GET /tasks liefert volle Task-Objekte, ?projectId=, includeDone per Default false
WAITING → Tag waiting ja — GET /tags liefert volle Tag-Objekte mit title; task.tagIds liegt am Task
follow_up_at lesbar — aber das gelesene Feld ist falsch gewählt, siehe #135
Someday → backlogTaskIds ja — backlogTaskIds: string[] am Project-Objekt
api_token ja — alles außer GET /health verlangt Authorization: Bearer

Alle drei Listen-Endpunkte geben die NgRx-Store-Objekte unverändert zurück, also strukturell
dieselben Datensätze
, die auch im Schnappschuss stehen. Der Äquivalenztest hat es dadurch leicht —
mit genau zwei Ausnahmen, die er sonst als Fehlschlag meldet:

Divergenz 1: archivierte Projekte

GET /projects läuft über selectUnarchivedProjects und filtert isArchived
(src/app/features/project/store/project.selectors.ts:16). Der Schnappschuss-Leser iteriert heute
alle project-Entities. Prüfung 3 (unpaged_project_weeks) meldete je nach Weg verschieden viel.

Entschieden (Betreiber, 2026-09-20): beide filtern isArchived. Der Schnappschuss-Weg zieht
auf das API-Verhalten nach — ein archiviertes Projekt soll keinen unpaged_project-Befund
erzeugen. Das ist eine Verhaltensänderung an review für bestehende Schnappschuss-Instanzen
(weniger Befunde) und braucht einen Changelog-Eintrag, der sie benennt.

Divergenz 2: Unteraufgaben

Unteraufgaben erben projectId vom Elternteil (addSubTask erzwingt es), GET /tasks?projectId=
liefert sie also mit; project.taskIds trägt nur die oberste Ebene. Der API-Weg zählt gegen
project.taskIds statt gegen den projectId-Filter — dieselbe Wahrheitsquelle wie der Dateiweg.

Was diese Form verschwinden lässt

Ein erster Entwurf hatte eine Laufzeit-Stufung mit Rückfall und drei Bedingungen daran. Zwei davon
entfallen vollständig:

  • Die Quelle kann nicht mitten im Lauf kippen. run_review ruft nacheinander projects(),
    open_items() je Projekt und someday_items(); mit einem Rückfall hätte ein Schließen der
    Anwendung dazwischen einen Bericht aus zwei Welten erzeugt — Befunde aus Prüfung 3/4, die echt
    aussehen und keine sind. Ohne Laufzeitwahl ist das keine Bedingung mehr, sondern eine Eigenschaft
    der Konstruktion.
  • Das Verifikationsfenster aus #134 ist zu. new project --resume prüft über den Lesepfad, ob
    ein Mensch das Projekt tatsächlich angelegt hat. Auf einer snapshot-Instanz konnte diese Prüfung
    gegen ein Backup von vor dem Schritt des Menschen laufen und „immer noch nicht da" melden. Da es
    die Anlage dort nicht mehr gibt, läuft verify() nur noch, wo live gelesen wird. #134 ist damit
    aufgelöst und geschlossen; die dort benannte Korrektur an der Begründung in tasks/protocol.py
    gehört in dieses Paket.

Was bleibt, ist der Äquivalenztest — und er wird dringlicher: wenn die beiden Wege auf
verschiedenen Maschinen leben, sieht sie in der Praxis nie jemand nebeneinander. Nur ein Test hält
sie zusammen. Dazu die Herkunftsangabe: die Antwort nennt ihren Weg, und bei snapshot dessen
Alter.

Was der Verzicht auf den Rückfall kostet — und warum er richtig ist

Ist die Anwendung auf einer api-Instanz geschlossen, gibt es keine Antwort: Provider nicht
erreichbar, betroffene Prüfungen übersprungen, Bericht als INCOMPLETE gekennzeichnet, review
endet mit Exit 1. Das ist das vorhandene, ausdrücklich so gebaute Verhalten.

Und es ist die bessere Hälfte des Tauschs. Ein Rückfall hätte an derselben Stelle eine Antwort aus
einem zwei Tage alten Schnappschuss geliefert, die aussieht wie eine frische — genau die leise
Falschheit, gegen die der Stack sonst überall anläuft (commit: null, der INCOMPLETE-Block, der
Commit-Stempel an jeder MCP-Antwort). Die Abhilfe liegt beim Menschen und ist trivial: die Anwendung
öffnen.

Verifiziert dazu: die API kennt mit 503 APP_NOT_READY einen eigenen Zustand für „Server da,
Renderer noch nicht" — „nicht erreichbar" und „antwortet Unsinn" sind dort bereits getrennt.

Konfigurationsform

{
  "schema": 1,
  "provider": "superproductivity",
  "thresholds": { "stalled_waiting_days": 14, "unpaged_project_weeks": 3, "someday_stale_months": 5 },
  "superproductivity": {
    "access": "api",
    "api_base_url": "http://127.0.0.1:3876",
    "api_token": "..."
  }
}
  "superproductivity": {
    "access": "snapshot",
    "backups_dir": "~/.config/superProductivity/backups"
  }

Berührungspunkte

  • #131: die headless bediente Instanz sagt access: snapshot. Dass sie den Tracker nicht
    schreiben kann, folgt damit aus der Konfiguration statt aus der Netztopologie — dieselbe
    Eigenschaft, ausdrücklich statt beiläufig.
  • #132: der Schreibweg setzt access: api voraus. Ein Posten, der über die API angelegt wird,
    ist dort auch sofort wieder lesbar — das Kriterium „der Posten taucht anschließend in
    wikitool review auf" ist damit sauber erfüllbar statt an ein Backup-Intervall gekoppelt.
    Verifiziert: POST /tasks existiert, tagIds ist schreibbar (der waiting-Tag muss allerdings
    schon existieren — Tags sind über die API nicht anlegbar), isAddToBacklog ist fest false,
    ein Posten landet also nie im Backlog.
  • #135: follow_up_at liest heute remindAt, und das ist über die API nicht schreibbar. Erst
    mit der dortigen Korrektur auf dueWithTime/dueDay wird #132s Schreibweg vollständig. Berührt
    dieses Issue nicht — hier wird nur der Weg gewählt, nicht das Feld. Umgesetzt zusammen mit
    diesem Issue, im selben Publish.
  • #128: nicht berührt. Welchen Transport ein Adapter innen wählt, geht TaskReader nichts an —
    keine Änderung an tasks/protocol.py außer der Korrektur ihrer Begründung. Die Regel-1-Korrektur
    aus #135 wurde in #128s eigenem Body nachgezogen (dort, nicht hier, da sie den Begriff bindet, den
    ein zweiter Adapter prüfen muss).

Akzeptanzkriterien

  • access ist Pflicht; eine Konfiguration ohne das Feld scheitert beim Lesen der
    Konfiguration
    mit einer Meldung, die beide Werte nennt — nicht erst beim ersten Zugriff.
  • access: api liest ausschließlich über die API, access: snapshot ausschließlich aus der
    Datei. Kein Codepfad wechselt den Weg, unter keinem Fehlerzustand.
  • Ein Feld, das nicht zum gewählten Weg gehört, wird beim Lesen der Konfiguration abgelehnt.
  • api_token ist bei access: api Pflicht; eine Konfiguration ohne Token scheitert beim Lesen
    der Konfiguration, nicht erst am ersten 401.
  • db_path existiert nicht mehr — weder im Code, noch in _EXPECTED_PROVIDER_CONFIG, noch in
    einem Test oder einer Dokumentationsstelle. Die Fixtures pinnen stattdessen ein Verzeichnis
    mit genau einer Datei.
  • latest_snapshot_path() wählt nur Dateien, deren Name dem Muster YYYY-MM-DD_HHmmss.json
    entspricht. Ein Test legt eine sp-backup_*.json neben eine neuere Zeitstempeldatei und
    prüft, dass die Zeitstempeldatei gewinnt.
  • wikitool new project legt bei access: snapshot nichts an — kein Tracker-Projekt und
    keine Seite — und endet mit Exit 1 und einer Meldung, die auf die api-Instanz verweist.
    --resume ebenso. Ein Test prüft, dass nach dem Aufruf keine Datei entstanden ist.
  • Bei access: api verhält sich new project unverändert: HumanInterventionRequired/Exit 42,
    und --resume verifiziert über den Live-Lesepfad. Ein Test hält fest, dass dieser Weg kein
    POST /projects versucht.
  • Beide Wege liefern für dieselbe Fixture identische ProjectSummary/OpenItems/
    SomedayItem-Werte; kein Test braucht eine laufende Super-Productivity-Instanz — der
    API-Weg wird gegen eine Attrappe geprüft.
  • Beide Wege blenden Projekte mit isArchived: true aus. Ein Test hält das für beide fest,
    und der Changelog-Eintrag benennt die Verhaltensänderung an Prüfung 3.
  • Der API-Weg zählt offene Posten gegen project.taskIds, nicht gegen den projectId-Filter;
    eine Fixture mit Unteraufgaben zeigt, dass beide Wege dieselbe Zahl liefern.
  • Jede Antwort trägt, aus welchem Weg sie stammt, und bei snapshot dessen Alter;
    wikitool review zeigt es in beiden Ausgabeformen.
  • Ein unerwartetes API-Antwortformat scheitert laut, genau wie eine unbekannte
    Schnappschuss-Form — „nicht erreichbar" und „antwortet Unsinn" bleiben verschiedene Zustände,
    und keiner von beiden wechselt den Weg.
  • Die Begründung in tasks/protocol.py („re-reads on every call, so a caller checking
    verify() ... sees the current state") sagt, was tatsächlich gilt — die aus #134 übernommene
    Korrektur.
  • wikitool doctor meldet den konfigurierten Weg und dessen Zustand; der andere ist kein
    Befund. Weiterhin nie ein FAIL — eine geschlossene Anwendung ist kein Fehler.
  • Nachgezogen: der Modul-Docstring von superproductivity.py, tools/CONTRACT.md
    (doctor-Zeile, der Fehlervertrag zu review, die new project-Zeile samt ihrem neuen
    Exit-1-Fall), INSTALL.md § Konfiguration.
  • docs verify, instructions verify, pytest grün. Version gebumpt — MAJOR, mit
    --breaking (das neue Pflichtfeld und das gestrichene db_path) und --no-migration
    (keine kb/-Inhaltsänderung; der Bruch bleibt auf .wikitool-tasks.json beschränkt).

Vorher zu klären

Nichts mehr. Die einzige offene Frage — ob die API alle Lesefragen beantwortet — ist am 2026-09-20
gegen den Quellcode verifiziert; das Ergebnis steht oben.

Entschieden (2026-09-20): access statt read_via, Pflicht ohne Default; kein Rückfall, kein
auto; Schreibweg nur bei access: api; new project verweigert auf snapshot vollständig und
bleibt auf api ein verifizierter Menschenschritt; db_path gestrichen und der Glob dafür
gehärtet; api_token bei access: api Pflicht; beide Wege filtern isArchived.

Abhängigkeiten

Keine blockierenden. Berührungspunkte: #132 (der Schreibweg), #135 (das Feld hinter
follow_up_at — umgesetzt im selben Publish), #131 (die headless bediente Instanz), #128 (nicht
berührt, außer der nachgezogenen Regel-1-Korrektur). #134 ist durch dieses Issue aufgelöst und
geschlossen.

Umsetzung

chemenu.tasks.superproductivity: SuperProductivityConfig.access (Pflichtfeld, zwei Werte, je
eigene Feldmenge), SuperProductivityReader (Schnappschuss, gehärteter Glob, isArchived-Filter),
neu SuperProductivityApiReader (REST-API, gegen eine Attrappe getestet), chemenu.tasks.protocol
(neu ReadSource, TaskReader.source()), chemenu.tasks.build_reader/build_writer (Dispatch
nach access, build_writer verweigert auf snapshot), chemenu.commands.new_page
(_ensure_tracker_project baut den Writer vor dem Kollisions-Check, damit die
access: snapshot-Verweigerung zuerst greift), chemenu.commands.doctor (check_tasks_provider
meldet nur den konfigurierten Weg), chemenu.review/chemenu.commands.review_cmd
(ReviewReport.source, gerendert in Text und --json). Tests in test_superproductivity.py
(rundum neu, inkl. API-Stub-Server und Äquivalenztest), test_new_page.py, test_review.py,
test_doctor.py, test_tasks_config.py. Doku: INSTALL.md § Konfiguration,
tools/CONTRACT.md (Zeilen review, new project, doctor, Fehlervertrag new project),
Modul-Docstring von superproductivity.py. Version: 7.0.0-beta.10 → 7.0.0-beta.11 (MAJOR).
Commit e07d1ca.

**Umgesetzt und veröffentlicht** (2026-09-20, Commit `e07d1ca`, Stack `7.0.0-beta.11`, MAJOR mit `--breaking`/`--no-migration`): `docs verify`, `instructions verify` und die volle `pytest`-Suite (1410 Tests) grün. Alle Akzeptanzkriterien unten sind erfüllt und abgehakt. Der Super-Productivity-Adapter liest heute ausschließlich einen periodischen Backup-Schnappschuss. Läuft die Anwendung, gibt es daneben eine lokale REST-API mit dem *aktuellen* Zustand. **Die Wege schließen sich je System aus** (Betreiber, 2026-09-20): eine headless bediente Instanz geht immer auf die Datei, der Desktop immer auf die API. Kein Mischfall in Sicht. Also sagt jede Instanz **ausdrücklich**, welchen Weg sie nimmt — und nimmt nur den. **Kompatibilität ist kein Kriterium** (Betreiber, 2026-09-20): der Stack ist unveröffentlicht, die Konfiguration wird überarbeitet statt erweitert. Das Feld ist deshalb **Pflicht** und trägt keinen Default — eine Konfiguration, die den Weg nicht nennt, ist unvollständig, nicht „die alte". **Alles entschieden, nichts mehr offen.** Die Verifikation gegen den SP-Quellcode ist am 2026-09-20 gelaufen (Ergebnis unten); der API-Weg trägt den Lesepfad vollständig und darf angeboten werden. ## Die Entscheidung `access` im providereigenen Block, Pflicht, zwei Werte: | Wert | Liest | Schreibt | Eigene Felder | |---|---|---|---| | `api` | lokale REST-API, aktueller Zustand | Posten ja (#132); **Projektanlage nein** — siehe unten | `api_base_url`, `api_token` | | `snapshot` | Backup-Schnappschuss, headless | **nein** — der Tracker ist von hier aus nur lesbar | `backups_dir` | Kein `auto`, kein Rückfall, keine Mischform. Der Name ist bewusst nicht `read_via`: das Feld entscheidet beide Hälften, nicht nur das Lesen. **Der Block trägt nur die Felder seines Wegs.** Ein `backups_dir` neben `access: api` wird beim Lesen der Konfiguration abgelehnt, nicht ignoriert: eine Konfiguration, die zwei Wege beschreibt, behauptet etwas, das nicht gilt — und beim nächsten Blick weiß niemand mehr, welcher Teil wirksam ist. **`api_token` ist bei `access: api` Pflicht**, nicht das heute optionale Durchreichfeld: verifiziert ist, dass jeder Endpunkt außer `GET /health` einen `Authorization: Bearer <token>` verlangt. Eine `api`-Instanz ohne Token kann nichts lesen. ### Projektanlage bleibt auch auf dem API-Weg ein Menschenschritt **Korrektur gegenüber der früheren Fassung dieses Bodys** (Verifikation 2026-09-20): es gibt weiterhin **kein** `POST /projects`. Registriert sind ausschließlich `GET /status`, `GET /focus`, `GET|POST /task-control/*`, `GET|POST /tasks`, `GET|PATCH|DELETE /tasks/:id`, `GET /projects`, `GET /tags` (`src/app/core/electron/local-rest-api-handler.service.ts:420`). Projekt-CRUD und Tag-CRUD existieren nicht. `wikitool new project` bleibt auf einer `api`-Instanz also bei `HumanInterventionRequired`/Exit 42 wie bisher. Was der API-Weg dort gewinnt, ist allein die **Verifikation**: `--resume` prüft über einen Lesepfad, der den aktuellen Zustand sieht, statt gegen ein womöglich älteres Backup zu laufen. Genau das war #134, und genau deshalb ist es aufgelöst. ### `new project` verweigert auf einer `snapshot`-Instanz Entschieden (Betreiber, 2026-09-20). Und zwar **vollständig**: kein Tracker-Projekt, **und auch keine Seite**. Ein gewöhnlicher Validierungsfehler mit Exit 1, der auf die `api`-Instanz verweist — kein Exit 42, denn hier wartet nichts auf eine Freigabe; das Kommando kann es an dieser Stelle schlicht nicht. `--resume` verhält sich gleich. Das sieht neben dem vorhandenen Verhalten „kein Tracker konfiguriert → nur die Seite, ausdrücklich angesagt" inkonsistent aus und ist es nicht. Der Unterschied ist, ob überhaupt gejoint wird: - **Kein Tracker konfiguriert:** `review` läuft gar nicht (es scheitert an der fehlenden Konfiguration). Eine Seite ohne Tracker-Projekt ist dort der Normalzustand und fällt niemandem auf die Füße. - **`access: snapshot`:** `review` läuft. Eine Seite ohne Tracker-Projekt ist dort genau das, was Prüfung 4 (`no_open_loop`) als Befund meldet — die Hälfte eines Paars, angelegt von einer Instanz, die die andere Hälfte gar nicht anlegen kann. Kosten: praktisch keine. An einer headless bedienten Instanz sitzt niemand, der ein Projekt anlegt. ### `db_path` wird gestrichen Entschieden (Betreiber, 2026-09-20). `backups_dir` ist damit für `access: snapshot` das einzige und pflichtige Feld, und `latest_snapshot_path()` verliert seinen Zweig. **Was dieser Verzicht tragend macht** (Verifikation 2026-09-20): `electron/backup.ts:148` schreibt `<userData>/backups/YYYY-MM-DD_HHmmss.json` — ohne Präfix, lexikalisch also gleich chronologisch. Zwei Haken, die heute niemand bemerkt hätte, weil `db_path` sie umgehen konnte: - SP selbst sortiert in `listBackupFiles` nach **mtime**, nicht lexikalisch. Der zitierte Kommentar „timestamps sort lexically" steht an der Windows-Store-Pfadwahl, nicht an der Sortierung. - Die manuellen Exporte heißen `sp-backup_*`, `sp-backup-anonymized_*`, `sp-pre-migration-backup_*` (`electron/shared-with-frontend/get-backup-timestamp.ts`). Die sortieren **hinter** jeden reinen Zeitstempel. Eine einzige dorthin abgelegte Exportdatei würde den Leser dauerhaft auf einen alten Stand nageln. Also: der Glob wird auf das Zeitstempelmuster eingeschränkt statt auf `*.json`. ## Das Ergebnis der Quellcode-Verifikation (2026-09-20) Gegen `super-productivity/super-productivity@master`. Die Routen liegen **nicht** in `electron/local-rest-api.ts` — das ist nur Transport, `/health` und Token-Prüfung — sondern im Renderer unter `src/app/core/electron/local-rest-api-handler.service.ts`. Die Pfadangabe im Modul-Docstring des Adapters ist entsprechend falsch und wird nachgezogen. | Gebraucht | Ergebnis | |---|---| | Projektliste mit Anlagedatum | **ja** — `GET /projects` liefert die vollen `Project`-Objekte; `created?: number` (`packages/plugin-api/src/types.ts`) | | Offene Posten je Projekt | **ja** — `GET /tasks` liefert volle `Task`-Objekte, `?projectId=`, `includeDone` per Default `false` | | `WAITING` → Tag `waiting` | **ja** — `GET /tags` liefert volle `Tag`-Objekte mit `title`; `task.tagIds` liegt am Task | | `follow_up_at` | **lesbar** — aber das gelesene Feld ist falsch gewählt, siehe #135 | | Someday → `backlogTaskIds` | **ja** — `backlogTaskIds: string[]` am Project-Objekt | | `api_token` | **ja** — alles außer `GET /health` verlangt `Authorization: Bearer` | Alle drei Listen-Endpunkte geben die NgRx-Store-Objekte unverändert zurück, also **strukturell dieselben Datensätze**, die auch im Schnappschuss stehen. Der Äquivalenztest hat es dadurch leicht — mit genau zwei Ausnahmen, die er sonst als Fehlschlag meldet: ### Divergenz 1: archivierte Projekte `GET /projects` läuft über `selectUnarchivedProjects` und filtert `isArchived` (`src/app/features/project/store/project.selectors.ts:16`). Der Schnappschuss-Leser iteriert heute *alle* `project`-Entities. Prüfung 3 (`unpaged_project_weeks`) meldete je nach Weg verschieden viel. **Entschieden (Betreiber, 2026-09-20): beide filtern `isArchived`.** Der Schnappschuss-Weg zieht auf das API-Verhalten nach — ein archiviertes Projekt soll keinen `unpaged_project`-Befund erzeugen. Das ist eine Verhaltensänderung an `review` für bestehende Schnappschuss-Instanzen (weniger Befunde) und braucht einen Changelog-Eintrag, der sie benennt. ### Divergenz 2: Unteraufgaben Unteraufgaben erben `projectId` vom Elternteil (`addSubTask` erzwingt es), `GET /tasks?projectId=` liefert sie also mit; `project.taskIds` trägt nur die oberste Ebene. Der API-Weg zählt gegen `project.taskIds` statt gegen den `projectId`-Filter — dieselbe Wahrheitsquelle wie der Dateiweg. ## Was diese Form verschwinden lässt Ein erster Entwurf hatte eine Laufzeit-Stufung mit Rückfall und drei Bedingungen daran. Zwei davon entfallen vollständig: - **Die Quelle kann nicht mitten im Lauf kippen.** `run_review` ruft nacheinander `projects()`, `open_items()` je Projekt und `someday_items()`; mit einem Rückfall hätte ein Schließen der Anwendung dazwischen einen Bericht aus zwei Welten erzeugt — Befunde aus Prüfung 3/4, die echt aussehen und keine sind. Ohne Laufzeitwahl ist das keine Bedingung mehr, sondern eine Eigenschaft der Konstruktion. - **Das Verifikationsfenster aus #134 ist zu.** `new project --resume` prüft über den Lesepfad, ob ein Mensch das Projekt tatsächlich angelegt hat. Auf einer `snapshot`-Instanz konnte diese Prüfung gegen ein Backup von *vor* dem Schritt des Menschen laufen und „immer noch nicht da" melden. Da es die Anlage dort nicht mehr gibt, läuft `verify()` nur noch, wo live gelesen wird. #134 ist damit aufgelöst und geschlossen; die dort benannte Korrektur an der Begründung in `tasks/protocol.py` gehört in dieses Paket. **Was bleibt, ist der Äquivalenztest** — und er wird *dringlicher*: wenn die beiden Wege auf verschiedenen Maschinen leben, sieht sie in der Praxis nie jemand nebeneinander. Nur ein Test hält sie zusammen. Dazu die Herkunftsangabe: die Antwort nennt ihren Weg, und bei `snapshot` dessen Alter. ## Was der Verzicht auf den Rückfall kostet — und warum er richtig ist Ist die Anwendung auf einer `api`-Instanz geschlossen, gibt es keine Antwort: Provider nicht erreichbar, betroffene Prüfungen übersprungen, Bericht als `INCOMPLETE` gekennzeichnet, `review` endet mit Exit 1. Das ist das vorhandene, ausdrücklich so gebaute Verhalten. Und es ist die bessere Hälfte des Tauschs. Ein Rückfall hätte an derselben Stelle eine Antwort aus einem zwei Tage alten Schnappschuss geliefert, die aussieht wie eine frische — genau die leise Falschheit, gegen die der Stack sonst überall anläuft (`commit: null`, der `INCOMPLETE`-Block, der Commit-Stempel an jeder MCP-Antwort). Die Abhilfe liegt beim Menschen und ist trivial: die Anwendung öffnen. Verifiziert dazu: die API kennt mit `503 APP_NOT_READY` einen eigenen Zustand für „Server da, Renderer noch nicht" — „nicht erreichbar" und „antwortet Unsinn" sind dort bereits getrennt. ## Konfigurationsform ```json { "schema": 1, "provider": "superproductivity", "thresholds": { "stalled_waiting_days": 14, "unpaged_project_weeks": 3, "someday_stale_months": 5 }, "superproductivity": { "access": "api", "api_base_url": "http://127.0.0.1:3876", "api_token": "..." } } ``` ```json "superproductivity": { "access": "snapshot", "backups_dir": "~/.config/superProductivity/backups" } ``` ## Berührungspunkte - **#131:** die headless bediente Instanz sagt `access: snapshot`. Dass sie den Tracker nicht schreiben kann, folgt damit aus der Konfiguration statt aus der Netztopologie — dieselbe Eigenschaft, ausdrücklich statt beiläufig. - **#132:** der Schreibweg setzt `access: api` voraus. Ein Posten, der über die API angelegt wird, ist dort auch sofort wieder lesbar — das Kriterium „der Posten taucht anschließend in `wikitool review` auf" ist damit sauber erfüllbar statt an ein Backup-Intervall gekoppelt. Verifiziert: `POST /tasks` existiert, `tagIds` ist schreibbar (der `waiting`-Tag muss allerdings schon existieren — Tags sind über die API nicht anlegbar), `isAddToBacklog` ist fest `false`, ein Posten landet also nie im Backlog. - **#135:** `follow_up_at` liest heute `remindAt`, und das ist über die API nicht schreibbar. Erst mit der dortigen Korrektur auf `dueWithTime`/`dueDay` wird #132s Schreibweg vollständig. Berührt dieses Issue nicht — hier wird nur der Weg gewählt, nicht das Feld. **Umgesetzt zusammen mit diesem Issue, im selben Publish.** - **#128:** nicht berührt. Welchen Transport ein Adapter innen wählt, geht `TaskReader` nichts an — keine Änderung an `tasks/protocol.py` außer der Korrektur ihrer Begründung. Die Regel-1-Korrektur aus #135 wurde in #128s eigenem Body nachgezogen (dort, nicht hier, da sie den Begriff bindet, den ein zweiter Adapter prüfen muss). ## Akzeptanzkriterien - [x] `access` ist Pflicht; eine Konfiguration ohne das Feld scheitert beim **Lesen der Konfiguration** mit einer Meldung, die beide Werte nennt — nicht erst beim ersten Zugriff. - [x] `access: api` liest ausschließlich über die API, `access: snapshot` ausschließlich aus der Datei. Kein Codepfad wechselt den Weg, unter keinem Fehlerzustand. - [x] Ein Feld, das nicht zum gewählten Weg gehört, wird beim Lesen der Konfiguration abgelehnt. - [x] `api_token` ist bei `access: api` Pflicht; eine Konfiguration ohne Token scheitert beim Lesen der Konfiguration, nicht erst am ersten `401`. - [x] `db_path` existiert nicht mehr — weder im Code, noch in `_EXPECTED_PROVIDER_CONFIG`, noch in einem Test oder einer Dokumentationsstelle. Die Fixtures pinnen stattdessen ein Verzeichnis mit genau einer Datei. - [x] `latest_snapshot_path()` wählt nur Dateien, deren Name dem Muster `YYYY-MM-DD_HHmmss.json` entspricht. Ein Test legt eine `sp-backup_*.json` neben eine neuere Zeitstempeldatei und prüft, dass die Zeitstempeldatei gewinnt. - [x] `wikitool new project` legt bei `access: snapshot` **nichts** an — kein Tracker-Projekt und keine Seite — und endet mit Exit 1 und einer Meldung, die auf die `api`-Instanz verweist. `--resume` ebenso. Ein Test prüft, dass nach dem Aufruf keine Datei entstanden ist. - [x] Bei `access: api` verhält sich `new project` unverändert: `HumanInterventionRequired`/Exit 42, und `--resume` verifiziert über den Live-Lesepfad. Ein Test hält fest, dass dieser Weg **kein** `POST /projects` versucht. - [x] Beide Wege liefern für dieselbe Fixture identische `ProjectSummary`/`OpenItems`/ `SomedayItem`-Werte; **kein Test braucht eine laufende Super-Productivity-Instanz** — der API-Weg wird gegen eine Attrappe geprüft. - [x] Beide Wege blenden Projekte mit `isArchived: true` aus. Ein Test hält das für beide fest, und der Changelog-Eintrag benennt die Verhaltensänderung an Prüfung 3. - [x] Der API-Weg zählt offene Posten gegen `project.taskIds`, nicht gegen den `projectId`-Filter; eine Fixture mit Unteraufgaben zeigt, dass beide Wege dieselbe Zahl liefern. - [x] Jede Antwort trägt, aus welchem Weg sie stammt, und bei `snapshot` dessen Alter; `wikitool review` zeigt es in beiden Ausgabeformen. - [x] Ein unerwartetes API-Antwortformat scheitert laut, genau wie eine unbekannte Schnappschuss-Form — „nicht erreichbar" und „antwortet Unsinn" bleiben verschiedene Zustände, und keiner von beiden wechselt den Weg. - [x] Die Begründung in `tasks/protocol.py` („re-reads on every call, so a caller checking `verify()` ... sees the current state") sagt, was tatsächlich gilt — die aus #134 übernommene Korrektur. - [x] `wikitool doctor` meldet den konfigurierten Weg und dessen Zustand; der andere ist kein Befund. Weiterhin nie ein `FAIL` — eine geschlossene Anwendung ist kein Fehler. - [x] Nachgezogen: der Modul-Docstring von `superproductivity.py`, `tools/CONTRACT.md` (`doctor`-Zeile, der Fehlervertrag zu `review`, die `new project`-Zeile samt ihrem neuen Exit-1-Fall), `INSTALL.md` § Konfiguration. - [x] `docs verify`, `instructions verify`, `pytest` grün. Version gebumpt — MAJOR, mit `--breaking` (das neue Pflichtfeld und das gestrichene `db_path`) und `--no-migration` (keine `kb/`-Inhaltsänderung; der Bruch bleibt auf `.wikitool-tasks.json` beschränkt). ## Vorher zu klären Nichts mehr. Die einzige offene Frage — ob die API alle Lesefragen beantwortet — ist am 2026-09-20 gegen den Quellcode verifiziert; das Ergebnis steht oben. **Entschieden (2026-09-20):** `access` statt `read_via`, Pflicht ohne Default; kein Rückfall, kein `auto`; Schreibweg nur bei `access: api`; `new project` verweigert auf `snapshot` vollständig und bleibt auf `api` ein verifizierter Menschenschritt; `db_path` gestrichen und der Glob dafür gehärtet; `api_token` bei `access: api` Pflicht; beide Wege filtern `isArchived`. ## Abhängigkeiten Keine blockierenden. Berührungspunkte: #132 (der Schreibweg), #135 (das Feld hinter `follow_up_at` — umgesetzt im selben Publish), #131 (die headless bediente Instanz), #128 (nicht berührt, außer der nachgezogenen Regel-1-Korrektur). #134 ist durch dieses Issue aufgelöst und geschlossen. ## Umsetzung `chemenu.tasks.superproductivity`: `SuperProductivityConfig.access` (Pflichtfeld, zwei Werte, je eigene Feldmenge), `SuperProductivityReader` (Schnappschuss, gehärteter Glob, `isArchived`-Filter), neu `SuperProductivityApiReader` (REST-API, gegen eine Attrappe getestet), `chemenu.tasks.protocol` (neu `ReadSource`, `TaskReader.source()`), `chemenu.tasks.build_reader`/`build_writer` (Dispatch nach `access`, `build_writer` verweigert auf `snapshot`), `chemenu.commands.new_page` (`_ensure_tracker_project` baut den Writer vor dem Kollisions-Check, damit die `access: snapshot`-Verweigerung zuerst greift), `chemenu.commands.doctor` (`check_tasks_provider` meldet nur den konfigurierten Weg), `chemenu.review`/`chemenu.commands.review_cmd` (`ReviewReport.source`, gerendert in Text und `--json`). Tests in `test_superproductivity.py` (rundum neu, inkl. API-Stub-Server und Äquivalenztest), `test_new_page.py`, `test_review.py`, `test_doctor.py`, `test_tasks_config.py`. Doku: `INSTALL.md` § Konfiguration, `tools/CONTRACT.md` (Zeilen `review`, `new project`, `doctor`, Fehlervertrag `new project`), Modul-Docstring von `superproductivity.py`. Version: `7.0.0-beta.10` → `7.0.0-beta.11` (MAJOR). Commit `e07d1ca`.
torben added the prio/plannedsize/Marea/kbkind/decision labels 2026-09-20 11:50:04 +00:00
torben changed title from SP-Lesepfad zweistufig: erst die lokale API, dann der Backup-Schnappschuss to SP-Lesepfad je Instanz konfigurieren: API oder Schnappschuss, nicht beides 2026-09-20 14:31:48 +00:00
Author
Owner

Changelog: Von Laufzeit-Stufung mit Rückfall auf eine Konfigurationsangabe je Instanz
umgestellt (Betreiber, 2026-09-20: die Wege schließen sich je System aus — headless immer Datei,
Desktop immer API, kein Mischfall in Sicht). Titel entsprechend.

  • Entfallen: Bedingung B1 (Quelle einmal je Lauf pinnen) vollständig — ohne Laufzeitwahl kann
    nichts mitten im Lauf kippen. Der Rückfall selbst ist gestrichen, samt der Frage, wann er greift.
  • Geblieben: der Äquivalenztest, jetzt mit dem Argument, dass die beiden Pfade in der Praxis
    nie jemand nebeneinander sieht. Die Herkunftsangabe in kleinerer Form.
  • Neu: Konfigurationsform read_via: api|snapshot, fehlend = snapshot (drop-in); begründet
    gegen api_base_url: null, weil sie später auto ohne Schema-Migration aufnehmen kann. Dazu die
    Validierungsregel, dass die benannte Quelle konfiguriert sein muss.
  • Schärfer: ohne Rückfall muss der API-Pfad vollständig sein oder darf nicht angeboten werden.
  • Neuer Befund, ausgelagert: #134 — --resume verifiziert über den Lesepfad und sieht ein
    frisch angelegtes Projekt womöglich nicht, weil der Schnappschuss älter ist. Das ist das stärkste
    Einzelargument für den API-Pfad auf dem Desktop.
**Changelog:** Von Laufzeit-Stufung mit Rückfall auf eine Konfigurationsangabe je Instanz umgestellt (Betreiber, 2026-09-20: die Wege schließen sich je System aus — headless immer Datei, Desktop immer API, kein Mischfall in Sicht). Titel entsprechend. - **Entfallen:** Bedingung B1 (Quelle einmal je Lauf pinnen) vollständig — ohne Laufzeitwahl kann nichts mitten im Lauf kippen. Der Rückfall selbst ist gestrichen, samt der Frage, wann er greift. - **Geblieben:** der Äquivalenztest, jetzt mit dem Argument, dass die beiden Pfade in der Praxis nie jemand nebeneinander sieht. Die Herkunftsangabe in kleinerer Form. - **Neu:** Konfigurationsform `read_via: api|snapshot`, fehlend = `snapshot` (drop-in); begründet gegen `api_base_url: null`, weil sie später `auto` ohne Schema-Migration aufnehmen kann. Dazu die Validierungsregel, dass die benannte Quelle konfiguriert sein muss. - **Schärfer:** ohne Rückfall muss der API-Pfad vollständig sein oder darf nicht angeboten werden. - **Neuer Befund, ausgelagert:** #134 — `--resume` verifiziert über den Lesepfad und sieht ein frisch angelegtes Projekt womöglich nicht, weil der Schnappschuss älter ist. Das ist das stärkste Einzelargument für den API-Pfad auf dem Desktop.
torben changed title from SP-Lesepfad je Instanz konfigurieren: API oder Schnappschuss, nicht beides to SP-Zugriff je Instanz explizit: `access: api` oder `access: snapshot`, kein Default, kein Rückfall 2026-09-20 14:43:03 +00:00
Author
Owner

Changelog: Auf eine ausdrückliche, pflichtige Konfigurationsangabe umgestellt (Betreiber,
2026-09-20: keine Kompatibilität nötig, der Stack ist unveröffentlicht; keine Mischform;
Projektanlage nur per API). Titel entsprechend.

  • Feld: read_via mit Default snapshot → access ohne Default, Pflicht. Umbenannt, weil
    es nicht mehr nur das Lesen entscheidet. Kein auto, kein Rückfall.
  • Neu: die Projektanlage gibt es nur bei access: api; eine snapshot-Instanz ist gegenüber
    dem Tracker rein lesend. Dazu die Regel, dass der Konfigurationsblock nur die Felder seines Wegs
    tragen darf.
  • Entfallen: die Rückwärtskompatibilität als Kriterium und das Argument für read_via gegen
    api_base_url: null (es stützte sich auf ein späteres auto, das es nicht geben wird).
  • Aufgelöst: #134 ist durch diese Entscheidung gegenstandslos und geschlossen — verify() läuft
    nur noch dort, wo live gelesen wird. Die dort gefundene falsche Begründung in
    tasks/protocol.py ist als Akzeptanzkriterium hierher übernommen.
  • Neu offen: was new project auf einer snapshot-Instanz tut (Neigung: verweigern), und ob
    db_path neben backups_dir bestehen bleibt.
**Changelog:** Auf eine ausdrückliche, pflichtige Konfigurationsangabe umgestellt (Betreiber, 2026-09-20: keine Kompatibilität nötig, der Stack ist unveröffentlicht; keine Mischform; Projektanlage nur per API). Titel entsprechend. - **Feld:** `read_via` mit Default `snapshot` → `access` **ohne Default, Pflicht**. Umbenannt, weil es nicht mehr nur das Lesen entscheidet. Kein `auto`, kein Rückfall. - **Neu:** die Projektanlage gibt es nur bei `access: api`; eine `snapshot`-Instanz ist gegenüber dem Tracker rein lesend. Dazu die Regel, dass der Konfigurationsblock nur die Felder seines Wegs tragen darf. - **Entfallen:** die Rückwärtskompatibilität als Kriterium und das Argument für `read_via` gegen `api_base_url: null` (es stützte sich auf ein späteres `auto`, das es nicht geben wird). - **Aufgelöst:** #134 ist durch diese Entscheidung gegenstandslos und geschlossen — `verify()` läuft nur noch dort, wo live gelesen wird. Die dort gefundene falsche Begründung in `tasks/protocol.py` ist als Akzeptanzkriterium hierher übernommen. - **Neu offen:** was `new project` auf einer `snapshot`-Instanz tut (Neigung: verweigern), und ob `db_path` neben `backups_dir` bestehen bleibt.
torben added kind/build and removed kind/decision labels 2026-09-20 14:50:55 +00:00
Author
Owner

Changelog: Die beiden letzten Entwurfsfragen sind entschieden (Betreiber, 2026-09-20) und
stehen jetzt als Entscheidung im Body statt als Frage darunter. kind/decision → kind/build:
offen ist nur noch eine Verifikation gegen den SP-Quellcode, und die ist keine Betreiberfrage.

  • new project verweigert bei access: snapshot — vollständig, also auch ohne Seite, mit
    Exit 1 statt 42. Dazu die Begründung, warum das neben „kein Tracker konfiguriert → nur die Seite"
    konsistent ist: dort läuft review gar nicht, hier läuft es und meldet die halbe Paarung als
    Befund von Prüfung 4.
  • db_path gestrichen — backups_dir ist das einzige Feld des snapshot-Wegs,
    latest_snapshot_path() verliert seinen Zweig. Das Gegenargument (Testbequemlichkeit) löst sich
    auf: ein Verzeichnis mit genau einer Datei ist ebenso eindeutig wie ein Pfad darauf.
  • Zwei neue Kriterien dafür, plus eine Zeile in der Bump-Notiz (gestrichenes Feld zusätzlich
    zum neuen Pflichtfeld).
**Changelog:** Die beiden letzten Entwurfsfragen sind entschieden (Betreiber, 2026-09-20) und stehen jetzt als Entscheidung im Body statt als Frage darunter. `kind/decision` → `kind/build`: offen ist nur noch eine Verifikation gegen den SP-Quellcode, und die ist keine Betreiberfrage. - **`new project` verweigert bei `access: snapshot`** — vollständig, also auch ohne Seite, mit Exit 1 statt 42. Dazu die Begründung, warum das neben „kein Tracker konfiguriert → nur die Seite" konsistent ist: dort läuft `review` gar nicht, hier läuft es und meldet die halbe Paarung als Befund von Prüfung 4. - **`db_path` gestrichen** — `backups_dir` ist das einzige Feld des `snapshot`-Wegs, `latest_snapshot_path()` verliert seinen Zweig. Das Gegenargument (Testbequemlichkeit) löst sich auf: ein Verzeichnis mit genau einer Datei ist ebenso eindeutig wie ein Pfad darauf. - **Zwei neue Kriterien** dafür, plus eine Zeile in der Bump-Notiz (gestrichenes Feld zusätzlich zum neuen Pflichtfeld).
Author
Owner

Changelog: Die Verifikation gegen den SP-Quellcode ist gelaufen (2026-09-20,
super-productivity/super-productivity@master). Der API-Weg trägt den Lesepfad vollständig,
„Vorher zu klären" ist leer. Zwei Stellen des Bodys waren falsch und sind korrigiert.

  • Korrigiert: die Tabellenzelle „api schreibt: ja — Projektanlage". Es gibt weiterhin kein
    POST /projects; new project bleibt auch auf einer api-Instanz
    HumanInterventionRequired/Exit 42. Der Gewinn des API-Wegs dort ist allein die Live-Verifikation
    durch --resume — also genau #134.
  • Korrigiert: die Pfadangabe für die Routen. Sie liegen im Renderer
    (src/app/core/electron/local-rest-api-handler.service.ts), nicht in electron/…; die
    Electron-Seite ist nur Transport, /health und Token-Prüfung. Der Modul-Docstring des Adapters
    zieht nach.
  • Neu, Entscheidung: api_token ist bei access: api Pflichtfeld — alles außer GET /health
    verlangt einen Bearer-Token.
  • Neu, Entscheidung (Betreiber): beide Wege filtern isArchived. GET /projects tut es über
    selectUnarchivedProjects, der Schnappschuss-Leser zog bisher nicht nach. Verhaltensänderung an
    Prüfung 3, eigenes Kriterium plus Changelog-Zeile.
  • Neu: der API-Weg zählt offene Posten gegen project.taskIds, nicht gegen den
    projectId-Filter — sonst zählt er Unteraufgaben mit, die der Dateiweg nicht sieht.
  • Neu: das Streichen von db_path macht die Dateiwahl tragend, und die war zu weich. SP sortiert
    selbst nach mtime, und die manuellen Exporte (sp-backup_* u. a.) sortieren hinter jeden
    Zeitstempel. Der Glob wird auf YYYY-MM-DD_HHmmss.json eingeschränkt, mit eigenem Test.
  • Ausgelagert: #135 — follow_up_at liest mit remindAt das falsche SP-Feld (dueDay/
    dueWithTime sind bei SP die Terminierung, deadline* das Fälligkeitsdatum). Prüfung 2 ist
    dadurch heute blind für ganztägige Tickler, und der Schreibweg aus #132 wäre ohne die Korrektur
    gar nicht möglich. Berührt dieses Issue nicht — hier wird der Weg gewählt, nicht das Feld.
**Changelog:** Die Verifikation gegen den SP-Quellcode ist gelaufen (2026-09-20, `super-productivity/super-productivity@master`). Der API-Weg trägt den Lesepfad vollständig, „Vorher zu klären" ist leer. Zwei Stellen des Bodys waren falsch und sind korrigiert. - **Korrigiert:** die Tabellenzelle „`api` schreibt: ja — Projektanlage". Es gibt weiterhin kein `POST /projects`; `new project` bleibt auch auf einer `api`-Instanz `HumanInterventionRequired`/Exit 42. Der Gewinn des API-Wegs dort ist allein die Live-Verifikation durch `--resume` — also genau #134. - **Korrigiert:** die Pfadangabe für die Routen. Sie liegen im Renderer (`src/app/core/electron/local-rest-api-handler.service.ts`), nicht in `electron/…`; die Electron-Seite ist nur Transport, `/health` und Token-Prüfung. Der Modul-Docstring des Adapters zieht nach. - **Neu, Entscheidung:** `api_token` ist bei `access: api` Pflichtfeld — alles außer `GET /health` verlangt einen Bearer-Token. - **Neu, Entscheidung (Betreiber):** beide Wege filtern `isArchived`. `GET /projects` tut es über `selectUnarchivedProjects`, der Schnappschuss-Leser zog bisher nicht nach. Verhaltensänderung an Prüfung 3, eigenes Kriterium plus Changelog-Zeile. - **Neu:** der API-Weg zählt offene Posten gegen `project.taskIds`, nicht gegen den `projectId`-Filter — sonst zählt er Unteraufgaben mit, die der Dateiweg nicht sieht. - **Neu:** das Streichen von `db_path` macht die Dateiwahl tragend, und die war zu weich. SP sortiert selbst nach mtime, und die manuellen Exporte (`sp-backup_*` u. a.) sortieren hinter jeden Zeitstempel. Der Glob wird auf `YYYY-MM-DD_HHmmss.json` eingeschränkt, mit eigenem Test. - **Ausgelagert:** #135 — `follow_up_at` liest mit `remindAt` das falsche SP-Feld (`dueDay`/ `dueWithTime` sind bei SP die *Terminierung*, `deadline*` das Fälligkeitsdatum). Prüfung 2 ist dadurch heute blind für ganztägige Tickler, und der Schreibweg aus #132 wäre ohne die Korrektur gar nicht möglich. Berührt dieses Issue nicht — hier wird der Weg gewählt, nicht das Feld.
Author
Owner

Umgesetzt und veröffentlicht: Commit e07d1ca, Stack 7.0.0-beta.10 → 7.0.0-beta.11 (MAJOR, --breaking/--no-migration). docs verify, instructions verify, pytest (1410 Tests) grün. Gemeinsam mit #135 in einem Publish umgesetzt. Body oben auf den Endzustand nachgezogen, alle Akzeptanzkriterien abgehakt.

Umgesetzt und veröffentlicht: Commit `e07d1ca`, Stack `7.0.0-beta.10` → `7.0.0-beta.11` (MAJOR, `--breaking`/`--no-migration`). `docs verify`, `instructions verify`, `pytest` (1410 Tests) grün. Gemeinsam mit #135 in einem Publish umgesetzt. Body oben auf den Endzustand nachgezogen, alle Akzeptanzkriterien abgehakt.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#133