Ein zweiter Provider fuer die Aufgaben-Schicht — und der erste Beweis, dass sie wirklich eine
Schicht ist.
Dieses Issue steht auf eigenen Beinen. Es stammt urspruenglich aus dem Entwurf in #119, der
inzwischen abgeschlossen und geschlossen ist; alles hier Noetige steht hier. Zwei Orte lohnen
trotzdem den Blick, keiner davon ein Tracker-Eintrag: docs/knowledge-and-commitment.md traegt
die Begruendung der ganzen Konstruktion (warum Wissen und Verpflichtung zwei Schichten sind, warum
nicht synchronisiert wird, warum keine Instruction je den Provider nennt), und tools/CONTRACT.md
die verbindlichen Zeilen zu review, new project, task new und doctor. #119 ist nur noch die
Entscheidungsgeschichte, nicht die Spezifikation.
Ausloeser
prio/waiting, und der Ausloeser ist benannt: es gibt noch keine berufliche Instanz. Eine
Instanz ist dauerhaft an genau einen Provider gekoppelt — drei Kontexte heissen drei Instanzen,
nicht eine mit drei Faechern, und es gibt bewusst keinen Migrationspfad zwischen Providern.
Beruflich heisst also: ein eigener Clone. Solange der nicht existiert, waere dieser Adapter auf
Vorrat gebaut.
Was gebaut wird
Ein zweiter Adapter gegen dasselbe Protokoll: Projekte mit Alter, offene Posten je Projekt, WAITING mit follow_up_at, Someday-Posten, ein Projekt anlegen — und, seit #132, einen
einzelnen Posten anlegen.
Die Flaeche, gegen die gebaut wird, steht in chemenu/tasks/:
Ort
Was dort steht
tasks/protocol.py
TaskReader (projects(), open_items(project_name), someday_items(), source()) und TaskWriter (create_project(name), seit #132 auch create_item(title, *, project_name, waiting, follow_up_at, notes)) als getrennte Protocols, dazu die Datenklassen ProjectSummary/OpenItems/WaitingItem/SomedayItem/ReadSource, normalize_project_name() und find_project()
tasks/config.py
.wikitool-tasks.json: KNOWN_PROVIDERS (hier zu ergaenzen), der providereigene Konfigurationsblock, und die drei Schwellwerte stalled_waiting_days/unpaged_project_weeks/someday_stale_months
tasks/__init__.py
build_reader()/build_writer() — die Dispatch-Tabelle, die heute nur superproductivity kennt; hier kommt der zweite Zweig hin. build_writer() darf einen Provider ablehnen, dessen konfigurierter Zugriffsweg keinen Schreibpfad hat (das Muster, das #133 fuer superproductivitys access: "snapshot" eingefuehrt hat) — falls Azure DevOps je einen analogen Modus bekommt
tasks/superproductivity.py
Der Praezedenzfall, gegen den sich dieser Adapter lesen lassen sollte — inzwischen inklusive #133 (expliziter, exklusiver Zugriffsweg statt Laufzeit-Rueckfall), #135 (Korrektur: follow_up_at nach dem, was ein Feld bedeutet, nicht nach seinem Namen) und #132 (create_item: eine feste INBOX_PROJECT_ID fuer den Eingang, eine waiting-Tag-Aufloesung, die laut scheitert statt einen Posten ohne Status anzulegen)
review.py
Die fuenf Pruefungen, die den Reader konsumieren — nicht zu aendern
wikitool doctor berichtet den konfigurierten Provider; ein neuer Adapter meldet sich dort
sinnvollerweise mit demselben Muster (Lesepfad bereit? Dienst erreichbar? — beides nie ein FAIL,
ein nicht laufender Tracker ist kein Fehler; FAIL nur auf eine kaputte Konfiguration).
Die Regeln, die hier gelten
Sie stehen hier ausgeschrieben, damit dieses Issue ohne #119 lesbar ist.
Nur WAITING-Status und follow_up_at sind maschinenlesbar. Die Person, auf die gewartet
wird, steht im Klartext im Aufgabentitel. follow_up_at ist ein eigenes Datum, ausdruecklich nicht das Faelligkeitsdatum. Das gilt auch hier, obwohl Azure DevOps mehr koennte — ein
Assignee waere idiomatisch, aber ein gemeinsames Modell, das je Provider verschieden viel weiss,
ist kein gemeinsames Modell. Wenn sich das als falsch erweist, ist es eine Aenderung am Protokoll
und damit an allen Adaptern, nicht eine Sonderlocke hier.
Korrektur aus #135, verbindlich auch hier: die Regel bindet den Begriff „Faelligkeitsdatum",
nicht den Namen eines Felds. Der SP-Adapter las ursprünglich remindAt unter Berufung auf genau
diese Regel — die Berufung war falsch, remindAt war nie das Faelligkeitsdatum, es war schlicht
das falsche Feld. Bevor dieser Adapter ein Azure-DevOps-Feld unter D9 einordnet, muss dessen
eigene Dokumentation gelesen werden (welches Feld heisst dort Due Date, welches ist etwas
anderes, das nur so aussieht) — nicht der Feldname allein. due* bei Super Productivity war genau
dieser Fall: der Name legt „Faelligkeit" nahe, das Modell selbst sagt „Scheduled".
Keine Instruction und kein Skill erfaehrt je, welcher Provider laeuft. Das ist die Eigenschaft,
die dieses Paket ueberhaupt testet. Ein Regressionstest haelt sie am echten Skill-Text fest —
seit #132 parametrisiert ueber gtd-weekly-reviewundwiki-ingest
(test_task_tracker_skills_name_no_provider).
Der Projektname ist die einzige Kopplung zwischen Tracker und kb/gtd/-Seite, case-normalisiert
verglichen. Vor der Anlage laeuft ein Eindeutigkeits-Preflight; es gibt keine automatische
Ruecksynchronisierung, und der Rueckblick meldet beidseitig unmatched, damit ein Rename ein
sichtbares Ereignis wird statt eines stillen Datenverlusts. task new (#132) haelt sich an
dieselbe Regel: es sucht und rät kein Projekt, es nimmt den Namen als Angabe und scheitert laut,
wenn keins passt.
Fehlende Faehigkeiten stehen nie in der Instruction. Ein Provider, der etwas nicht kann,
scheitert nach dem Tool-Error-Contract mit Exit 1 — oder, wenn ein Mensch die Luecke schliessen
kann, mit chemenu.errors.HumanInterventionRequired und Exit 42: Anweisungen ausgeben, anhalten,
nichts erfinden. Der SP-Adapter ist dafuer der Praezedenzfall (siehe unten). create_item
(#132) ist der Gegenbeweis, dass nicht jede Luecke ein Exit 42 braucht: wo der Schreibpfad
grundsaetzlich existiert (Super Productivity: POST /tasks), scheitert eine einzelne fehlende
Voraussetzung (kein passendes Projekt, keine waiting-Markierung verfuegbar) mit gewoehnlichem
Exit 1, nicht mit Exit 42 — Exit 42 bleibt reserviert fuer „ein Mensch muss ausserhalb dieses
Prozesses handeln", nicht fuer jede Praezedenzbedingung.
Schema- bzw. API-Drift muss laut scheitern. Ein Adapter, der still falsch parst, liefert einen
Bericht, der plausibel aussieht und falsch ist — das ist schlimmer als kein Bericht.
Lese- und Schreibpfad duerfen verschiedene Transporte sein. Bei Super Productivity sind sie es:
gelesen wird ein Backup-Schnappschuss auf der Platte (laeuft ohne Anwendung), geschrieben ueber
eine lokale REST-API (nur bei laufender Anwendung) — und seit #133 sind beide Wege zusaetzlich
je Instanz exklusiv konfiguriert (access: api/access: snapshot), nicht gleichzeitig verfuegbar.
Was der SP-Adapter gelernt hat
Vier Befunde aus #124/#126/#133/#135/#132, die fuer jeden zweiten Adapter zaehlen:
Der naheliegende Lesepfad war der falsche. Erwartet war eine Datenbankdatei; tatsaechlich liegt
der Live-Zustand in IndexedDB, und gelesen wird der jueingste periodische Backup-Schnappschuss.
Was die Doku eines Werkzeugs nahelegt, ist nicht, was der Quellcode tut — beides pruefen, bevor der
Adapter darauf baut.
Die API konnte das Projekt nicht anlegen, aber einen Posten schon.GET /projects existiert, POST /projects nicht — create_project wirft seitdem HumanInterventionRequired; wikitool new project zeigt die Anweisungen und beendet sich mit 42, und ein spaeterer Lauf mit --resume
verifiziert ueber den Lesepfad, statt der Behauptung zu glauben. POST /tasks existiert dagegen
(#132) — der Fall, der create_project zu Exit 42 zwingt, tritt fuer create_item also nicht ein.
Falls Azure DevOps bei Projekten mehr kann als Super Productivity, ist der automatische Weg
richtig — die Struktur haelt beides aus.
Reihenfolge bei der Anlage: Tracker vor Seite. Ein Fehlschlag dazwischen landet dann immer im
bekannten Zustand „Tracker-Projekt ohne Seite", den Pruefung 3 des Rueckblicks ohnehin meldet — nie
im unbekannten „Seite ohne Tracker-Projekt". Dieselbe Reihenfolge gilt fuer task new gegenueber
der Wissens-Seite, die eine Quelle parallel erzeugen kann (#132) — nur dass dort zwei unabhaengige
Kommandos in dieser Reihenfolge aufgerufen werden, nicht ein einzelnes wie bei new project.
Ein Feldname ist keine Feldbedeutung (#135).remindAt klang nach dem Nachfasstermin und war
es fuer den Regelfall nicht; due* klang nach Faelligkeit und war es nie. Ein zweiter Adapter muss
jedes Kandidatenfeld gegen die Dokumentation seines Anbieters pruefen, nie gegen den Klang seines
Namens — siehe Regel 1 oben.
Akzeptanzkriterien
Der Adapter erfuellt TaskReader/TaskWritervollstaendig, inklusive create_item, ohne
dass tasks/protocol.py geaendert werden muss. Ist eine Protokollaenderung noetig, ist das ein
Befund ueber die Schicht selbst und gehoert dort korrigiert — nicht hier umgangen.
wikitool review, wikitool new projectund wikitool task new funktionieren gegen diesen
Provider, ohne dass ein Wort in Skill oder Instruction geaendert wird. Das ist der
eigentliche Test dieses Pakets.
KNOWN_PROVIDERS und die Dispatch-Zweige in build_reader/build_writer kennen den neuen
Provider; eine unbekannte Angabe scheitert weiterhin beim Lesen der Konfiguration, nicht spaeter.
Lese- und Schreibpfad (inklusive create_item) sind gegen Fixtures getestet; kein Test
braucht eine erreichbare Azure-DevOps-Organisation.
Authentifizierung ueber ein Token aus .wikitool-tasks.json; kein Credential im Repo, die
Datei ist gitignored.
Schema- bzw. API-Drift scheitert laut — niemals ein stilles Teilergebnis.
wikitool doctor berichtet den Provider mit Lese- und Erreichbarkeitsstatus, nach demselben
Muster wie fuer SP.
INSTALL.md § Konfiguration nennt den neuen Provider und die Form seines Konfigurationsblocks —
das ist der Ort, an dem ein Mensch die Form nachschlaegt.
docs verify, instructions verify, pytest gruen.
Vorher zu klaeren
Bleibt der Projektname bei einem Rename in Azure DevOps stabil, oder wandert er? Das entscheidet,
ob die Namenskopplung (Regel 3) dort ueberhaupt greift.
Welches Feld traegt die Aufwandsschaetzung (Original Estimate, Remaining Work, Story Points)? Die
Schaetzung war das Topkriterium der Werkzeugwahl, aber der Rueckblick liest sie derzeit gar nicht
— zu pruefen ist, ob das so bleiben soll.
Gibt es ein Someday/Maybe-Aequivalent, oder faellt Pruefung 5 in dieser Instanz aus? Ein Provider,
der eine Pruefung nicht bedienen kann, scheitert mit Exit 1 und klarer Meldung — zu entscheiden
ist, ob das hier das gewuenschte Verhalten ist oder ob die Pruefung abschaltbar sein muss.
Hat Azure DevOps ein Aequivalent zu access, oder ist dort nur ein Zugriffsweg ueberhaupt
denkbar? Falls es einen Live- und einen Offline-Weg gibt, gilt #133s Regel unveraendert: explizit,
exklusiv, kein Rueckfall.
Kann Azure DevOps ein Work Item ohne Bereich/Team-Zuordnung anlegen (ein Aequivalent zu Super
Productivitys INBOX_PROJECT)? #132s --inbox-Weg setzt das fuer den zweiten Provider nicht
voraus, aber wenn es dort kein Aequivalent gibt, muss task new --inbox gegen diesen Provider
klar mit Exit 1 scheitern statt etwas zu erfinden.
Abhaengigkeiten
Keine offenen. Die Schicht, gegen die dieser Adapter gebaut wird, steht seit Stack 7.0.0-beta.2; der
Rueckblick und die Projektanlage stehen seit 7.0.0-beta.3 bzw. 7.0.0-beta.5; #133/#135 (Zugriffsweg, follow_up_at-Korrektur) und #132 (create_item, der zweite Schreibweg) sind eingearbeitet.
Ein zweiter Provider fuer die Aufgaben-Schicht — und der erste Beweis, dass sie wirklich eine
Schicht ist.
**Dieses Issue steht auf eigenen Beinen.** Es stammt urspruenglich aus dem Entwurf in #119, der
inzwischen abgeschlossen und geschlossen ist; alles hier Noetige steht hier. Zwei Orte lohnen
trotzdem den Blick, keiner davon ein Tracker-Eintrag: **`docs/knowledge-and-commitment.md`** traegt
die Begruendung der ganzen Konstruktion (warum Wissen und Verpflichtung zwei Schichten sind, warum
nicht synchronisiert wird, warum keine Instruction je den Provider nennt), und **`tools/CONTRACT.md`**
die verbindlichen Zeilen zu `review`, `new project`, `task new` und `doctor`. #119 ist nur noch die
Entscheidungsgeschichte, nicht die Spezifikation.
## Ausloeser
`prio/waiting`, und der Ausloeser ist benannt: **es gibt noch keine berufliche Instanz.** Eine
Instanz ist dauerhaft an genau einen Provider gekoppelt — drei Kontexte heissen drei Instanzen,
nicht eine mit drei Faechern, und es gibt bewusst keinen Migrationspfad zwischen Providern.
Beruflich heisst also: ein eigener Clone. Solange der nicht existiert, waere dieser Adapter auf
Vorrat gebaut.
## Was gebaut wird
Ein zweiter Adapter gegen dasselbe Protokoll: Projekte mit Alter, offene Posten je Projekt,
`WAITING` mit `follow_up_at`, Someday-Posten, ein Projekt anlegen — **und, seit #132, einen
einzelnen Posten anlegen.**
Die Flaeche, gegen die gebaut wird, steht in `chemenu/tasks/`:
| Ort | Was dort steht |
|---|---|
| `tasks/protocol.py` | `TaskReader` (`projects()`, `open_items(project_name)`, `someday_items()`, `source()`) und `TaskWriter` (`create_project(name)`, seit #132 auch `create_item(title, *, project_name, waiting, follow_up_at, notes)`) als getrennte `Protocol`s, dazu die Datenklassen `ProjectSummary`/`OpenItems`/`WaitingItem`/`SomedayItem`/`ReadSource`, `normalize_project_name()` und `find_project()` |
| `tasks/config.py` | `.wikitool-tasks.json`: `KNOWN_PROVIDERS` (hier zu ergaenzen), der providereigene Konfigurationsblock, und die drei Schwellwerte `stalled_waiting_days`/`unpaged_project_weeks`/`someday_stale_months` |
| `tasks/__init__.py` | `build_reader()`/`build_writer()` — die Dispatch-Tabelle, die heute nur `superproductivity` kennt; **hier kommt der zweite Zweig hin**. `build_writer()` darf einen Provider ablehnen, dessen *konfigurierter* Zugriffsweg keinen Schreibpfad hat (das Muster, das #133 fuer `superproductivity`s `access: "snapshot"` eingefuehrt hat) — falls Azure DevOps je einen analogen Modus bekommt |
| `tasks/superproductivity.py` | Der Praezedenzfall, gegen den sich dieser Adapter lesen lassen sollte — inzwischen inklusive #133 (expliziter, exklusiver Zugriffsweg statt Laufzeit-Rueckfall), #135 (Korrektur: `follow_up_at` nach dem, was ein Feld *bedeutet*, nicht nach seinem Namen) und #132 (`create_item`: eine feste `INBOX_PROJECT_ID` fuer den Eingang, eine `waiting`-Tag-Aufloesung, die laut scheitert statt einen Posten ohne Status anzulegen) |
| `review.py` | Die fuenf Pruefungen, die den Reader konsumieren — nicht zu aendern |
`wikitool doctor` berichtet den konfigurierten Provider; ein neuer Adapter meldet sich dort
sinnvollerweise mit demselben Muster (Lesepfad bereit? Dienst erreichbar? — beides nie ein `FAIL`,
ein nicht laufender Tracker ist kein Fehler; `FAIL` nur auf eine kaputte Konfiguration).
## Die Regeln, die hier gelten
Sie stehen hier ausgeschrieben, damit dieses Issue ohne #119 lesbar ist.
1. **Nur `WAITING`-Status und `follow_up_at` sind maschinenlesbar.** Die Person, auf die gewartet
wird, steht im Klartext im Aufgabentitel. `follow_up_at` ist ein eigenes Datum, ausdruecklich
**nicht** das Faelligkeitsdatum. **Das gilt auch hier, obwohl Azure DevOps mehr koennte** — ein
Assignee waere idiomatisch, aber ein gemeinsames Modell, das je Provider verschieden viel weiss,
ist kein gemeinsames Modell. Wenn sich das als falsch erweist, ist es eine Aenderung am Protokoll
und damit an *allen* Adaptern, nicht eine Sonderlocke hier.
**Korrektur aus #135, verbindlich auch hier:** die Regel bindet den *Begriff* „Faelligkeitsdatum",
nicht den Namen eines Felds. Der SP-Adapter las ursprünglich `remindAt` unter Berufung auf genau
diese Regel — die Berufung war falsch, `remindAt` war nie das Faelligkeitsdatum, es war schlicht
das falsche Feld. Bevor dieser Adapter ein Azure-DevOps-Feld unter D9 einordnet, muss dessen
eigene Dokumentation gelesen werden (welches Feld heisst dort *Due Date*, welches ist etwas
anderes, das nur so aussieht) — nicht der Feldname allein. `due*` bei Super Productivity war genau
dieser Fall: der Name legt „Faelligkeit" nahe, das Modell selbst sagt „Scheduled".
2. **Keine Instruction und kein Skill erfaehrt je, welcher Provider laeuft.** Das ist die Eigenschaft,
die dieses Paket ueberhaupt testet. Ein Regressionstest haelt sie am echten Skill-Text fest —
seit #132 parametrisiert ueber `gtd-weekly-review` **und** `wiki-ingest`
(`test_task_tracker_skills_name_no_provider`).
3. **Der Projektname ist die einzige Kopplung** zwischen Tracker und `kb/gtd/`-Seite, case-normalisiert
verglichen. Vor der Anlage laeuft ein Eindeutigkeits-Preflight; es gibt keine automatische
Ruecksynchronisierung, und der Rueckblick meldet beidseitig unmatched, damit ein Rename ein
sichtbares Ereignis wird statt eines stillen Datenverlusts. **`task new` (#132) haelt sich an
dieselbe Regel:** es sucht und rät kein Projekt, es nimmt den Namen als Angabe und scheitert laut,
wenn keins passt.
4. **Fehlende Faehigkeiten stehen nie in der Instruction.** Ein Provider, der etwas nicht kann,
scheitert nach dem Tool-Error-Contract mit Exit 1 — oder, wenn ein Mensch die Luecke schliessen
kann, mit `chemenu.errors.HumanInterventionRequired` und Exit 42: Anweisungen ausgeben, anhalten,
nichts erfinden. Der SP-Adapter ist dafuer der Praezedenzfall (siehe unten). **`create_item`
(#132) ist der Gegenbeweis, dass nicht jede Luecke ein Exit 42 braucht:** wo der Schreibpfad
grundsaetzlich existiert (Super Productivity: `POST /tasks`), scheitert eine einzelne fehlende
Voraussetzung (kein passendes Projekt, keine `waiting`-Markierung verfuegbar) mit gewoehnlichem
Exit 1, nicht mit Exit 42 — Exit 42 bleibt reserviert fuer „ein Mensch muss ausserhalb dieses
Prozesses handeln", nicht fuer jede Praezedenzbedingung.
5. **Schema- bzw. API-Drift muss laut scheitern.** Ein Adapter, der still falsch parst, liefert einen
Bericht, der plausibel aussieht und falsch ist — das ist schlimmer als kein Bericht.
6. **Lese- und Schreibpfad duerfen verschiedene Transporte sein.** Bei Super Productivity sind sie es:
gelesen wird ein Backup-Schnappschuss auf der Platte (laeuft ohne Anwendung), geschrieben ueber
eine lokale REST-API (nur bei laufender Anwendung) — und seit #133 sind beide Wege zusaetzlich
je Instanz exklusiv konfiguriert (`access: api`/`access: snapshot`), nicht gleichzeitig verfuegbar.
## Was der SP-Adapter gelernt hat
Vier Befunde aus #124/#126/#133/#135/#132, die fuer jeden zweiten Adapter zaehlen:
- **Der naheliegende Lesepfad war der falsche.** Erwartet war eine Datenbankdatei; tatsaechlich liegt
der Live-Zustand in IndexedDB, und gelesen wird der jueingste periodische Backup-Schnappschuss.
Was die Doku eines Werkzeugs nahelegt, ist nicht, was der Quellcode tut — beides pruefen, bevor der
Adapter darauf baut.
- **Die API konnte das Projekt nicht anlegen, aber einen Posten schon.** `GET /projects` existiert,
`POST /projects` nicht — `create_project` wirft seitdem `HumanInterventionRequired`; `wikitool new
project` zeigt die Anweisungen und beendet sich mit 42, und ein spaeterer Lauf mit `--resume`
verifiziert ueber den Lesepfad, statt der Behauptung zu glauben. `POST /tasks` existiert dagegen
(#132) — der Fall, der `create_project` zu Exit 42 zwingt, tritt fuer `create_item` also nicht ein.
Falls Azure DevOps bei Projekten mehr kann als Super Productivity, ist der automatische Weg
richtig — die Struktur haelt beides aus.
- **Reihenfolge bei der Anlage: Tracker vor Seite.** Ein Fehlschlag dazwischen landet dann immer im
bekannten Zustand „Tracker-Projekt ohne Seite", den Pruefung 3 des Rueckblicks ohnehin meldet — nie
im unbekannten „Seite ohne Tracker-Projekt". Dieselbe Reihenfolge gilt fuer `task new` gegenueber
der Wissens-Seite, die eine Quelle parallel erzeugen kann (#132) — nur dass dort zwei unabhaengige
Kommandos in dieser Reihenfolge aufgerufen werden, nicht ein einzelnes wie bei `new project`.
- **Ein Feldname ist keine Feldbedeutung (#135).** `remindAt` klang nach dem Nachfasstermin und war
es fuer den Regelfall nicht; `due*` klang nach Faelligkeit und war es nie. Ein zweiter Adapter muss
jedes Kandidatenfeld gegen die Dokumentation seines Anbieters pruefen, nie gegen den Klang seines
Namens — siehe Regel 1 oben.
## Akzeptanzkriterien
- [ ] Der Adapter erfuellt `TaskReader`/`TaskWriter` **vollstaendig, inklusive `create_item`**, ohne
dass `tasks/protocol.py` geaendert werden muss. Ist eine Protokollaenderung noetig, ist das ein
Befund ueber die Schicht selbst und gehoert dort korrigiert — nicht hier umgangen.
- [ ] `wikitool review`, `wikitool new project` **und `wikitool task new`** funktionieren gegen diesen
Provider, **ohne dass ein Wort in Skill oder Instruction geaendert wird.** Das ist der
eigentliche Test dieses Pakets.
- [ ] `KNOWN_PROVIDERS` und die Dispatch-Zweige in `build_reader`/`build_writer` kennen den neuen
Provider; eine unbekannte Angabe scheitert weiterhin beim Lesen der Konfiguration, nicht spaeter.
- [ ] Lese- und Schreibpfad (inklusive `create_item`) sind gegen Fixtures getestet; **kein Test
braucht eine erreichbare Azure-DevOps-Organisation.**
- [ ] Authentifizierung ueber ein Token aus `.wikitool-tasks.json`; **kein Credential im Repo**, die
Datei ist gitignored.
- [ ] Schema- bzw. API-Drift scheitert laut — niemals ein stilles Teilergebnis.
- [ ] `wikitool doctor` berichtet den Provider mit Lese- und Erreichbarkeitsstatus, nach demselben
Muster wie fuer SP.
- [ ] `INSTALL.md` § Konfiguration nennt den neuen Provider und die Form seines Konfigurationsblocks —
das ist der Ort, an dem ein Mensch die Form nachschlaegt.
- [ ] `docs verify`, `instructions verify`, `pytest` gruen.
## Vorher zu klaeren
- [ ] Bleibt der Projektname bei einem Rename in Azure DevOps stabil, oder wandert er? Das entscheidet,
ob die Namenskopplung (Regel 3) dort ueberhaupt greift.
- [ ] Welches Feld traegt die Aufwandsschaetzung (Original Estimate, Remaining Work, Story Points)? Die
Schaetzung war das Topkriterium der Werkzeugwahl, aber der Rueckblick liest sie derzeit gar nicht
— zu pruefen ist, ob das so bleiben soll.
- [ ] Gibt es ein Someday/Maybe-Aequivalent, oder faellt Pruefung 5 in dieser Instanz aus? Ein Provider,
der eine Pruefung nicht bedienen kann, scheitert mit Exit 1 und klarer Meldung — zu entscheiden
ist, ob das hier das gewuenschte Verhalten ist oder ob die Pruefung abschaltbar sein muss.
- [ ] Hat Azure DevOps ein Aequivalent zu `access`, oder ist dort nur ein Zugriffsweg ueberhaupt
denkbar? Falls es einen Live- und einen Offline-Weg gibt, gilt #133s Regel unveraendert: explizit,
exklusiv, kein Rueckfall.
- [ ] Kann Azure DevOps ein Work Item ohne Bereich/Team-Zuordnung anlegen (ein Aequivalent zu Super
Productivitys `INBOX_PROJECT`)? #132s `--inbox`-Weg setzt das fuer den zweiten Provider nicht
voraus, aber wenn es dort kein Aequivalent gibt, muss `task new --inbox` gegen diesen Provider
klar mit Exit 1 scheitern statt etwas zu erfinden.
## Abhaengigkeiten
Keine offenen. Die Schicht, gegen die dieser Adapter gebaut wird, steht seit Stack 7.0.0-beta.2; der
Rueckblick und die Projektanlage stehen seit 7.0.0-beta.3 bzw. 7.0.0-beta.5; #133/#135 (Zugriffsweg,
`follow_up_at`-Korrektur) und #132 (`create_item`, der zweite Schreibweg) sind eingearbeitet.
Changelog: Body auf Eigenstaendigkeit umgeschrieben, status/blocked entfernt.
#119 ist geschlossen, also darf dieses Issue nicht mehr auf dessen D-Nummern zeigen: die sechs Regeln, die fuer einen zweiten Adapter gelten (maschinenlesbar nur WAITING/follow_up_at, Provider-Neutralitaet, der Name als einzige Kopplung, fehlende Faehigkeiten als Exit 1 bzw. 42, lautes Scheitern bei Drift, getrennte Lese-/Schreibtransporte) stehen jetzt ausgeschrieben im Body. Dazu neu: die konkrete Flaeche in chemenu/tasks/ als Tabelle (wo KNOWN_PROVIDERS und der build_reader/build_writer-Zweig zu ergaenzen sind), die drei Lehren aus dem SP-Adapter (falscher naheliegender Lesepfad, fehlender Schreib-Endpunkt, Tracker-vor-Seite), und zwei Akzeptanzkriterien, die vorher fehlten (doctor-Bericht, INSTALL.md § Konfiguration).
status/blocked war ueberholt - der Blocker (#124, Provider-Schicht) ist seit Stack 7.0.0-beta.2 erledigt. prio/waiting bleibt: der Ausloeser ist unveraendert die Existenz der beruflichen Instanz, nicht ein anderes Issue.
Begruendung der Gesamtkonstruktion jetzt im Repo statt im Tracker: docs/knowledge-and-commitment.md.
**Changelog:** Body auf Eigenstaendigkeit umgeschrieben, `status/blocked` entfernt.
#119 ist geschlossen, also darf dieses Issue nicht mehr auf dessen D-Nummern zeigen: die sechs Regeln, die fuer einen zweiten Adapter gelten (maschinenlesbar nur `WAITING`/`follow_up_at`, Provider-Neutralitaet, der Name als einzige Kopplung, fehlende Faehigkeiten als Exit 1 bzw. 42, lautes Scheitern bei Drift, getrennte Lese-/Schreibtransporte) stehen jetzt ausgeschrieben im Body. Dazu neu: die konkrete Flaeche in `chemenu/tasks/` als Tabelle (wo `KNOWN_PROVIDERS` und der `build_reader`/`build_writer`-Zweig zu ergaenzen sind), die drei Lehren aus dem SP-Adapter (falscher naheliegender Lesepfad, fehlender Schreib-Endpunkt, Tracker-vor-Seite), und zwei Akzeptanzkriterien, die vorher fehlten (`doctor`-Bericht, `INSTALL.md` § Konfiguration).
`status/blocked` war ueberholt - der Blocker (#124, Provider-Schicht) ist seit Stack 7.0.0-beta.2 erledigt. `prio/waiting` bleibt: der Ausloeser ist unveraendert die Existenz der beruflichen Instanz, nicht ein anderes Issue.
Begruendung der Gesamtkonstruktion jetzt im Repo statt im Tracker: `docs/knowledge-and-commitment.md`.
Changelog: Nachgezogen aus #132, wie dort in dessen Akzeptanzkriterien vorgesehen (create_item / task new sind jetzt Teil der Flaeche, gegen die dieser Adapter gebaut wird).
tasks/protocol.pys TaskWriter traegt seit #132 eine zweite Methode, create_item; die
Akzeptanzkriterien hier verlangen jetzt explizit, dass der neue Adapter sie mit erfuellt, nicht nur create_project.
Regel 3 (Projektname als einzige Kopplung) und Regel 4 (fehlende Faehigkeiten nie in der
Instruction) um create_items eigene Auspraegung ergaenzt: kein Suchen/Raten des Projekts, und ein
fehlender Schreibweg-Baustein (z.B. keine WAITING-Markierung verfuegbar) ist Exit 1, nicht Exit 42 -
Exit 42 bleibt create_projects eigener Fall (kein Endpunkt vorhanden), der bei create_item nicht
eintritt, weil der Endpunkt existiert.
„Was der SP-Adapter gelernt hat" um den vierten Befund ergaenzt (Exit 42 ist nicht das Standardmuster
fuer jede Luecke) und die bestehenden drei um den create_item-Bezug erweitert.
Neue Klaerungsfrage: ob Azure DevOps ein Aequivalent zu Super Productivitys INBOX_PROJECT hat -
falls nicht, muss task new --inbox dort klar mit Exit 1 scheitern statt etwas zu erfinden.
Der Regressionstest, den Regel 2 zitiert, ist seit #132 parametrisiert (gtd-weekly-review und wiki-ingest) - der Name in der Klammer ist entsprechend aktualisiert.
**Changelog:** Nachgezogen aus #132, wie dort in dessen Akzeptanzkriterien vorgesehen (`create_item` /
`task new` sind jetzt Teil der Flaeche, gegen die dieser Adapter gebaut wird).
- `tasks/protocol.py`s `TaskWriter` traegt seit #132 eine zweite Methode, `create_item`; die
Akzeptanzkriterien hier verlangen jetzt explizit, dass der neue Adapter sie mit erfuellt, nicht nur
`create_project`.
- Regel 3 (Projektname als einzige Kopplung) und Regel 4 (fehlende Faehigkeiten nie in der
Instruction) um `create_item`s eigene Auspraegung ergaenzt: kein Suchen/Raten des Projekts, und ein
fehlender Schreibweg-Baustein (z.B. keine WAITING-Markierung verfuegbar) ist Exit 1, nicht Exit 42 -
Exit 42 bleibt `create_project`s eigener Fall (kein Endpunkt vorhanden), der bei `create_item` nicht
eintritt, weil der Endpunkt existiert.
- „Was der SP-Adapter gelernt hat" um den vierten Befund ergaenzt (Exit 42 ist nicht das Standardmuster
fuer jede Luecke) und die bestehenden drei um den `create_item`-Bezug erweitert.
- Neue Klaerungsfrage: ob Azure DevOps ein Aequivalent zu Super Productivitys `INBOX_PROJECT` hat -
falls nicht, muss `task new --inbox` dort klar mit Exit 1 scheitern statt etwas zu erfinden.
- Der Regressionstest, den Regel 2 zitiert, ist seit #132 parametrisiert (`gtd-weekly-review` und
`wiki-ingest`) - der Name in der Klammer ist entsprechend aktualisiert.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Ein zweiter Provider fuer die Aufgaben-Schicht — und der erste Beweis, dass sie wirklich eine
Schicht ist.
Dieses Issue steht auf eigenen Beinen. Es stammt urspruenglich aus dem Entwurf in #119, der
inzwischen abgeschlossen und geschlossen ist; alles hier Noetige steht hier. Zwei Orte lohnen
trotzdem den Blick, keiner davon ein Tracker-Eintrag:
docs/knowledge-and-commitment.mdtraegtdie Begruendung der ganzen Konstruktion (warum Wissen und Verpflichtung zwei Schichten sind, warum
nicht synchronisiert wird, warum keine Instruction je den Provider nennt), und
tools/CONTRACT.mddie verbindlichen Zeilen zu
review,new project,task newunddoctor. #119 ist nur noch dieEntscheidungsgeschichte, nicht die Spezifikation.
Ausloeser
prio/waiting, und der Ausloeser ist benannt: es gibt noch keine berufliche Instanz. EineInstanz ist dauerhaft an genau einen Provider gekoppelt — drei Kontexte heissen drei Instanzen,
nicht eine mit drei Faechern, und es gibt bewusst keinen Migrationspfad zwischen Providern.
Beruflich heisst also: ein eigener Clone. Solange der nicht existiert, waere dieser Adapter auf
Vorrat gebaut.
Was gebaut wird
Ein zweiter Adapter gegen dasselbe Protokoll: Projekte mit Alter, offene Posten je Projekt,
WAITINGmitfollow_up_at, Someday-Posten, ein Projekt anlegen — und, seit #132, eineneinzelnen Posten anlegen.
Die Flaeche, gegen die gebaut wird, steht in
chemenu/tasks/:tasks/protocol.pyTaskReader(projects(),open_items(project_name),someday_items(),source()) undTaskWriter(create_project(name), seit #132 auchcreate_item(title, *, project_name, waiting, follow_up_at, notes)) als getrennteProtocols, dazu die DatenklassenProjectSummary/OpenItems/WaitingItem/SomedayItem/ReadSource,normalize_project_name()undfind_project()tasks/config.py.wikitool-tasks.json:KNOWN_PROVIDERS(hier zu ergaenzen), der providereigene Konfigurationsblock, und die drei Schwellwertestalled_waiting_days/unpaged_project_weeks/someday_stale_monthstasks/__init__.pybuild_reader()/build_writer()— die Dispatch-Tabelle, die heute nursuperproductivitykennt; hier kommt der zweite Zweig hin.build_writer()darf einen Provider ablehnen, dessen konfigurierter Zugriffsweg keinen Schreibpfad hat (das Muster, das #133 fuersuperproductivitysaccess: "snapshot"eingefuehrt hat) — falls Azure DevOps je einen analogen Modus bekommttasks/superproductivity.pyfollow_up_atnach dem, was ein Feld bedeutet, nicht nach seinem Namen) und #132 (create_item: eine festeINBOX_PROJECT_IDfuer den Eingang, einewaiting-Tag-Aufloesung, die laut scheitert statt einen Posten ohne Status anzulegen)review.pywikitool doctorberichtet den konfigurierten Provider; ein neuer Adapter meldet sich dortsinnvollerweise mit demselben Muster (Lesepfad bereit? Dienst erreichbar? — beides nie ein
FAIL,ein nicht laufender Tracker ist kein Fehler;
FAILnur auf eine kaputte Konfiguration).Die Regeln, die hier gelten
Sie stehen hier ausgeschrieben, damit dieses Issue ohne #119 lesbar ist.
Nur
WAITING-Status undfollow_up_atsind maschinenlesbar. Die Person, auf die gewartetwird, steht im Klartext im Aufgabentitel.
follow_up_atist ein eigenes Datum, ausdruecklichnicht das Faelligkeitsdatum. Das gilt auch hier, obwohl Azure DevOps mehr koennte — ein
Assignee waere idiomatisch, aber ein gemeinsames Modell, das je Provider verschieden viel weiss,
ist kein gemeinsames Modell. Wenn sich das als falsch erweist, ist es eine Aenderung am Protokoll
und damit an allen Adaptern, nicht eine Sonderlocke hier.
Korrektur aus #135, verbindlich auch hier: die Regel bindet den Begriff „Faelligkeitsdatum",
nicht den Namen eines Felds. Der SP-Adapter las ursprünglich
remindAtunter Berufung auf genaudiese Regel — die Berufung war falsch,
remindAtwar nie das Faelligkeitsdatum, es war schlichtdas falsche Feld. Bevor dieser Adapter ein Azure-DevOps-Feld unter D9 einordnet, muss dessen
eigene Dokumentation gelesen werden (welches Feld heisst dort Due Date, welches ist etwas
anderes, das nur so aussieht) — nicht der Feldname allein.
due*bei Super Productivity war genaudieser Fall: der Name legt „Faelligkeit" nahe, das Modell selbst sagt „Scheduled".
Keine Instruction und kein Skill erfaehrt je, welcher Provider laeuft. Das ist die Eigenschaft,
die dieses Paket ueberhaupt testet. Ein Regressionstest haelt sie am echten Skill-Text fest —
seit #132 parametrisiert ueber
gtd-weekly-reviewundwiki-ingest(
test_task_tracker_skills_name_no_provider).Der Projektname ist die einzige Kopplung zwischen Tracker und
kb/gtd/-Seite, case-normalisiertverglichen. Vor der Anlage laeuft ein Eindeutigkeits-Preflight; es gibt keine automatische
Ruecksynchronisierung, und der Rueckblick meldet beidseitig unmatched, damit ein Rename ein
sichtbares Ereignis wird statt eines stillen Datenverlusts.
task new(#132) haelt sich andieselbe Regel: es sucht und rät kein Projekt, es nimmt den Namen als Angabe und scheitert laut,
wenn keins passt.
Fehlende Faehigkeiten stehen nie in der Instruction. Ein Provider, der etwas nicht kann,
scheitert nach dem Tool-Error-Contract mit Exit 1 — oder, wenn ein Mensch die Luecke schliessen
kann, mit
chemenu.errors.HumanInterventionRequiredund Exit 42: Anweisungen ausgeben, anhalten,nichts erfinden. Der SP-Adapter ist dafuer der Praezedenzfall (siehe unten).
create_item(#132) ist der Gegenbeweis, dass nicht jede Luecke ein Exit 42 braucht: wo der Schreibpfad
grundsaetzlich existiert (Super Productivity:
POST /tasks), scheitert eine einzelne fehlendeVoraussetzung (kein passendes Projekt, keine
waiting-Markierung verfuegbar) mit gewoehnlichemExit 1, nicht mit Exit 42 — Exit 42 bleibt reserviert fuer „ein Mensch muss ausserhalb dieses
Prozesses handeln", nicht fuer jede Praezedenzbedingung.
Schema- bzw. API-Drift muss laut scheitern. Ein Adapter, der still falsch parst, liefert einen
Bericht, der plausibel aussieht und falsch ist — das ist schlimmer als kein Bericht.
Lese- und Schreibpfad duerfen verschiedene Transporte sein. Bei Super Productivity sind sie es:
gelesen wird ein Backup-Schnappschuss auf der Platte (laeuft ohne Anwendung), geschrieben ueber
eine lokale REST-API (nur bei laufender Anwendung) — und seit #133 sind beide Wege zusaetzlich
je Instanz exklusiv konfiguriert (
access: api/access: snapshot), nicht gleichzeitig verfuegbar.Was der SP-Adapter gelernt hat
Vier Befunde aus #124/#126/#133/#135/#132, die fuer jeden zweiten Adapter zaehlen:
der Live-Zustand in IndexedDB, und gelesen wird der jueingste periodische Backup-Schnappschuss.
Was die Doku eines Werkzeugs nahelegt, ist nicht, was der Quellcode tut — beides pruefen, bevor der
Adapter darauf baut.
GET /projectsexistiert,POST /projectsnicht —create_projectwirft seitdemHumanInterventionRequired;wikitool new projectzeigt die Anweisungen und beendet sich mit 42, und ein spaeterer Lauf mit--resumeverifiziert ueber den Lesepfad, statt der Behauptung zu glauben.
POST /tasksexistiert dagegen(#132) — der Fall, der
create_projectzu Exit 42 zwingt, tritt fuercreate_itemalso nicht ein.Falls Azure DevOps bei Projekten mehr kann als Super Productivity, ist der automatische Weg
richtig — die Struktur haelt beides aus.
bekannten Zustand „Tracker-Projekt ohne Seite", den Pruefung 3 des Rueckblicks ohnehin meldet — nie
im unbekannten „Seite ohne Tracker-Projekt". Dieselbe Reihenfolge gilt fuer
task newgegenueberder Wissens-Seite, die eine Quelle parallel erzeugen kann (#132) — nur dass dort zwei unabhaengige
Kommandos in dieser Reihenfolge aufgerufen werden, nicht ein einzelnes wie bei
new project.remindAtklang nach dem Nachfasstermin und wares fuer den Regelfall nicht;
due*klang nach Faelligkeit und war es nie. Ein zweiter Adapter mussjedes Kandidatenfeld gegen die Dokumentation seines Anbieters pruefen, nie gegen den Klang seines
Namens — siehe Regel 1 oben.
Akzeptanzkriterien
TaskReader/TaskWritervollstaendig, inklusivecreate_item, ohnedass
tasks/protocol.pygeaendert werden muss. Ist eine Protokollaenderung noetig, ist das einBefund ueber die Schicht selbst und gehoert dort korrigiert — nicht hier umgangen.
wikitool review,wikitool new projectundwikitool task newfunktionieren gegen diesenProvider, ohne dass ein Wort in Skill oder Instruction geaendert wird. Das ist der
eigentliche Test dieses Pakets.
KNOWN_PROVIDERSund die Dispatch-Zweige inbuild_reader/build_writerkennen den neuenProvider; eine unbekannte Angabe scheitert weiterhin beim Lesen der Konfiguration, nicht spaeter.
create_item) sind gegen Fixtures getestet; kein Testbraucht eine erreichbare Azure-DevOps-Organisation.
.wikitool-tasks.json; kein Credential im Repo, dieDatei ist gitignored.
wikitool doctorberichtet den Provider mit Lese- und Erreichbarkeitsstatus, nach demselbenMuster wie fuer SP.
INSTALL.md§ Konfiguration nennt den neuen Provider und die Form seines Konfigurationsblocks —das ist der Ort, an dem ein Mensch die Form nachschlaegt.
docs verify,instructions verify,pytestgruen.Vorher zu klaeren
ob die Namenskopplung (Regel 3) dort ueberhaupt greift.
Schaetzung war das Topkriterium der Werkzeugwahl, aber der Rueckblick liest sie derzeit gar nicht
— zu pruefen ist, ob das so bleiben soll.
der eine Pruefung nicht bedienen kann, scheitert mit Exit 1 und klarer Meldung — zu entscheiden
ist, ob das hier das gewuenschte Verhalten ist oder ob die Pruefung abschaltbar sein muss.
access, oder ist dort nur ein Zugriffsweg ueberhauptdenkbar? Falls es einen Live- und einen Offline-Weg gibt, gilt #133s Regel unveraendert: explizit,
exklusiv, kein Rueckfall.
Productivitys
INBOX_PROJECT)? #132s--inbox-Weg setzt das fuer den zweiten Provider nichtvoraus, aber wenn es dort kein Aequivalent gibt, muss
task new --inboxgegen diesen Providerklar mit Exit 1 scheitern statt etwas zu erfinden.
Abhaengigkeiten
Keine offenen. Die Schicht, gegen die dieser Adapter gebaut wird, steht seit Stack 7.0.0-beta.2; der
Rueckblick und die Projektanlage stehen seit 7.0.0-beta.3 bzw. 7.0.0-beta.5; #133/#135 (Zugriffsweg,
follow_up_at-Korrektur) und #132 (create_item, der zweite Schreibweg) sind eingearbeitet.Changelog: Body auf Eigenstaendigkeit umgeschrieben,
status/blockedentfernt.#119 ist geschlossen, also darf dieses Issue nicht mehr auf dessen D-Nummern zeigen: die sechs Regeln, die fuer einen zweiten Adapter gelten (maschinenlesbar nur
WAITING/follow_up_at, Provider-Neutralitaet, der Name als einzige Kopplung, fehlende Faehigkeiten als Exit 1 bzw. 42, lautes Scheitern bei Drift, getrennte Lese-/Schreibtransporte) stehen jetzt ausgeschrieben im Body. Dazu neu: die konkrete Flaeche inchemenu/tasks/als Tabelle (woKNOWN_PROVIDERSund derbuild_reader/build_writer-Zweig zu ergaenzen sind), die drei Lehren aus dem SP-Adapter (falscher naheliegender Lesepfad, fehlender Schreib-Endpunkt, Tracker-vor-Seite), und zwei Akzeptanzkriterien, die vorher fehlten (doctor-Bericht,INSTALL.md§ Konfiguration).status/blockedwar ueberholt - der Blocker (#124, Provider-Schicht) ist seit Stack 7.0.0-beta.2 erledigt.prio/waitingbleibt: der Ausloeser ist unveraendert die Existenz der beruflichen Instanz, nicht ein anderes Issue.Begruendung der Gesamtkonstruktion jetzt im Repo statt im Tracker:
docs/knowledge-and-commitment.md.Changelog: Nachgezogen aus #132, wie dort in dessen Akzeptanzkriterien vorgesehen (
create_item/task newsind jetzt Teil der Flaeche, gegen die dieser Adapter gebaut wird).tasks/protocol.pysTaskWritertraegt seit #132 eine zweite Methode,create_item; dieAkzeptanzkriterien hier verlangen jetzt explizit, dass der neue Adapter sie mit erfuellt, nicht nur
create_project.Instruction) um
create_items eigene Auspraegung ergaenzt: kein Suchen/Raten des Projekts, und einfehlender Schreibweg-Baustein (z.B. keine WAITING-Markierung verfuegbar) ist Exit 1, nicht Exit 42 -
Exit 42 bleibt
create_projects eigener Fall (kein Endpunkt vorhanden), der beicreate_itemnichteintritt, weil der Endpunkt existiert.
fuer jede Luecke) und die bestehenden drei um den
create_item-Bezug erweitert.INBOX_PROJECThat -falls nicht, muss
task new --inboxdort klar mit Exit 1 scheitern statt etwas zu erfinden.gtd-weekly-reviewundwiki-ingest) - der Name in der Klammer ist entsprechend aktualisiert.torben referenced this issue2026-10-03 20:19:48 +00:00