Eine Quelle kann beides tragen — Wissen und eine Verpflichtung. Bis zu diesem Paket konnte der
Ingest nur die erste Hälfte: der Schreibpfad in den Tracker kannte genau ein Kommando, und das legte
ein Projekt an, keinen Posten.
Umgesetzt und ausgeliefert mit Stack 7.0.0-beta.12, Commit cfbe3ea (2026-09-20).
Was es jetzt gibt
wikitool task new legt einen Posten im Tracker an, ohne jede kb/-Seite:
Darunter liegt TaskWriter.create_item(title, *, project_name, waiting, follow_up_at, notes) -
die zweite Methode des Schreibprotokolls neben create_project, umgesetzt im
Super-Productivity-Adapter über POST /tasks. Der Ingest-Skill fragt in Schritt 5 jetzt auch nach
einer Verpflichtung und legt sie, falls bestätigt, vor der Quellenseite an.
Damit gibt es einen zweiten Schreibweg in den Tracker in derselben Haltung wie der erste: nichts
wird gelesen und nichts abgeglichen, es wird einmal etwas hineingeschrieben. Die
Zwei-Schichten-Trennung bleibt unberührt - der Posten lebt ausschließlich im Tracker, keine kb/-Seite trägt einen Aufgabenzustand, und ein Agent hat weiterhin keinen Anlass, die
Aufgabenliste außerhalb des Wochenrückblicks zu lesen.
Fallbeispiel, an dem das Paket entworfen wurde
Ein Kunde reklamiert per Mail. Die Mail geht nach incoming/. Chemenu legt daraus
die Reklamation inhaltlich ab, verknüpft mit dem zugehörigen Projekt, und
die Verpflichtung, das Ganze nachzufassen, als Posten im Tracker.
Das ist kein Sonderfall, sondern der Normalfall für alles, was von außen hereinkommt und nicht bloß
Lesestoff ist: eine Mail, ein Protokoll, ein Angebot, ein Prüfbericht. Jedes davon hinterlässt etwas
zu wissen und etwas zu tun. Die ursprüngliche Frage „was geht wohin — kb/, kb/gtd/ oder
Tracker" war richtig gestellt und falsch beantwortet: die Ziele schließen sich nicht aus.
Die Entscheidungen
D1 — Ein zweites Schreibkommando, bewusst schmal
Ein Posten trägt: Projekt (oder Eingang), Titel, optional WAITING mit follow_up_at, optional
einen Freitext-Rückverweis. Kein Fälligkeitsdatum, kein Aufwand, keine Zuständigkeit - die Regel
aus #128 gilt unverändert: ein gemeinsames Modell, das je Provider verschieden viel weiß, ist kein
gemeinsames Modell. Die Methode bindet jeden künftigen Adapter, also auch #128, bevor er existiert.
D2 — Der Mensch klärt, der Agent schlägt vor: eine Frage im Skill, kein Gate
Eine Verpflichtung, die niemand eingegangen ist, ist schlimmer als eine vergessene: sie sieht aus
wie ein Commitment, steht in der Liste und wird beim nächsten Rückblick als echter offener Posten
behandelt. GTDs Clarify ist eine menschliche Entscheidung und wird nicht aus einer Mail erraten.
Kein eigenes Gate im Code, sondern eine Frage im Skill. Ein Gate ist für Unumkehrbares und
Massenhaftes da (docs/why-gates-are-code.md); ein einzelner Posten ist beides nicht - new hat
aus demselben Grund keines, und ein Gate, das bei jedem Ingest feuerte, wäre genau das reflexhaft
Geräumte. Die Verbindlichkeit liegt darin, dass der Agent das Kommando mit einem vom Nutzer
bestätigten Titel aufruft.
Ausdrücklich ohne Auflage an #112 (Betreiber, 2026-09-20): die Gegenposition — läuft der
Ingest-Weg irgendwann unbeaufsichtigt, fehlt genau die Skill-Ebene — besteht fort und ist hier
nicht adressiert. Wer einen unbeaufsichtigten Stapellauf spezifiziert, stellt die Frage dort neu.
D3 — Reihenfolge: Tracker vor Seite
Entscheidend ist, welcher Zwischenzustand entdeckt wird:
Posten angelegt, Seite scheitert → die Rohdatei bleibt ohne Quellenseite, und das meldet lint
als uncovered_raw_files.
Seite angelegt, Posten scheitert → nichts meldet das. Die Verpflichtung ist still verloren,
und sie ist die dringlichere Hälfte.
Umgesetzt als Schrittfolge im Ingest-Skill: task new in Schritt 5, Quellenseite in Schritt 6. Die
Beförderung nach raw/ (Schritt 1) blieb, wo sie war - dazu #136, siehe § Was bewusst offen
blieb.
D4 — Fehlt das Projekt, hält der Ingest an und fragt: drei Wege, kein Default
Existiert weder eine Projektseite noch ein Tracker-Projekt, rät der Agent nicht: er hält an und legt
drei Wege vor - ein vorhandenes Projekt benennen, new project (hält den Ingest auf jeder Instanz
an, weil kein Provider ein Tracker-Projekt selbst anlegen kann), oder in den Eingang des
Trackers als ausdrücklich gewählte Notausfahrt.
Der Eingang ist nie ein Default, nur eine Wahl, und der Skill nennt beim Anbieten ihre Kosten:
ein Posten ohne Projekt ist für den Rückblick unerreichbar (siehe § Der Rückblick erreicht Posten
nur über ihr Projekt). Der Unterschied zwischen dieser Route und einem Default ist der ganze Punkt:
ein Mensch, der sie wählt, weiß, dass der Posten außer Sicht liegt; ein Default hätte es ihm
verschwiegen. Deshalb hat sie eine eigene Form am Kommando (--inbox) - ein weggelassenes --project ist ein Fehler, keine stille Eingangs-Ablage.
D5 — Der Rückverweis auf die Seite ist Freitext und wird nie geparst
Genau die Haltung, die WaitingItem.title schon hat. Ein maschinenlesbarer Verweis wäre eine zweite
Kopplung neben dem Projektnamen und damit etwas, das auseinanderlaufen kann - docs/knowledge-and-commitment.md § „One name, carrying the duties of an identifier" ist die
Begründung, warum es bei einer bleibt. Umgesetzt über notes.
D6 — Die Projekterkennung schlägt vor, sie ordnet nicht zu
Vorschlag per search im Skill, Bestätigung durch den Nutzer, keine automatische Zuordnung, auch
nicht bei einem eindeutigen Treffer. Der Join bleibt exakte, case-normalisierte Gleichheit
(normalize_project_name); eine unscharfe Zuordnung wäre eine zweite, schwächere Matching-Regel
daneben, und rät sie falsch, landet die Verpflichtung in einem fremden Projekt, wo sie gültig
aussieht und von keiner Prüfung je auffällt. Ein falscher Treffer ist teurer als ein ausgebliebener.
Das Suchen blieb deshalb beim Skill: das Kommando sucht nicht selbst.
Ein Dialogschritt, nicht drei
D2, D4 und D6 verlangen dieselbe menschliche Auskunft an derselben Stelle des Laufs und sind in der
Umsetzung auf einen Bestätigungsschritt zusammengefallen: der Skill legt Titel und
vorgeschlagenes Projekt gemeinsam als Frage vor, die Antwort ist eine Bestätigung, eine Korrektur
oder einer der drei Wege aus D4, danach ein Kommandoaufruf.
Gegen den Quellcode verifiziert (super-productivity/super-productivity@master, 2026-09-20)
POST /tasks existiert (src/app/core/electron/local-rest-api-handler.service.ts).
Schreibbar sind ausschließlich die Felder in ALLOWED_TASK_FIELDS: title, notes, isDone, timeEstimate, timeSpent, projectId, tagIds, dueDay, dueWithTime, plannedAt, deadlineDay, deadlineWithTime, deadlineRemindAt. Alles andere wirft pickAllowedFields
still weg. Der Fall, der create_project zu Exit 42 zwingt, tritt hier also nicht ein.
Der waiting-Tag muss schon existieren.tagIds ist schreibbar, Tags sind über die API nicht
anlegbar (GET /tags ist die einzige Tag-Route). Umgesetzt: die Tag-Auflösung läuft vor dem
einen POST, sodass nie ein Posten ohne seinen Status entsteht.
follow_up_at wird als dueDay geschrieben - die Spiegelung der mit #135 korrigierten
Leseregel (dueWithTime, sonst dueDay; nie deadline*).
Ein Posten landet nie im Backlog (isAddToBacklog fest false). Für dieses Paket ohne
Folgen - Someday/Maybe wird hier nicht geschrieben -, aber es ist die Grenze des Schreibwegs.
Der Eingang erscheint nicht in GET /projects.INBOX_PROJECT ist zwar immer ein echtes
Projekt-Entity im Store (_addInboxProjectIfNecessary legt es an, falls es fehlt), aber selectUnarchivedProjects - der Selektor hinter GET /projects - filtert es unbedingt über seine
feste id heraus (p.id !== INBOX_PROJECT.id, project.selectors.ts/project.const.ts). Folge: Prüfung 3 (unpaged_project_weeks) braucht keine Ausnahme für den Eingang - er
taucht in tracker_projects nie auf, es gibt nichts auszunehmen. Der Adapter schreibt die feste
id deshalb explizit (INBOX_PROJECT_ID), statt projectId wegzulassen: ohne Angabe fällt Super
Productivity auf den gerade aktiven Work Context zurück, also auf das zufällig geöffnete Projekt.
Der Rückblick erreicht Posten nur über ihr Projekt
run_review erreicht Posten ausschließlich über projects() → open_items(project.name)
(tools/chemenu/review.py). Ein Posten ohne Projekt ist für den Rückblick unsichtbar - es
bleibt kein Befund aus, es entsteht schlicht nie einer. Kein Argument gegen den Eingang als
Ablageort, sondern eines dafür, dass diese Route ihre Kosten beim Anbieten nennt statt beim
Vermissen (D4); der Ingest-Skill tut das.
Akzeptanzkriterien
Ein Posten lässt sich über wikitool in einem benannten Tracker-Projekt anlegen, optional als WAITING mit follow_up_at und mit einem Freitext-Rückverweis in notes; gegen Fixtures
getestet, kein Test braucht eine laufende Super-Productivity-Instanz.
Der Posten taucht anschließend in wikitool review auf: als offener Posten des Projekts, und
bei gesetztem follow_up_at nach Ablauf der Schwelle in Prüfung 2 - über den Lesepfad
getestet, angelegt und wiedergelesen
(test_created_item_appears_in_review_as_an_open_and_overdue_waiting_item).
Fehlt der waiting-Tag im Tracker, scheitert die Anlage eines WAITING-Postens laut; es
entsteht kein Posten ohne seinen Status. Getestet auf beiden Ebenen (Adapter und Kommando),
jeweils mit der Zusicherung, dass keinPOST abgesetzt wurde.
Die Eingangs-Route hat eine eigene Form am Kommando (--inbox); ein weggelassenes --project
ist ein Fehler, keine stille Eingangs-Ablage. Getestet, in beiden Richtungen (keines von
beiden angegeben, und beide zugleich).
Verifiziert beim Bauen: der Eingang erscheint nicht in GET /projects - siehe
§ Gegen den Quellcode verifiziert. Prüfung 3 braucht folglich keine Ausnahme, und der Skill
sagt beim Anbieten der Route ausdrücklich, dass review den Posten nicht sieht.
Der Schreibweg steht nur einer Instanz mit access: api zur Verfügung; auf einer snapshot-Instanz gibt es ihn nicht (test_snapshot_access_has_no_write_path, exit 1 mit
Verweis auf die api-Instanz).
Ein Adapter kann den Schreibweg nicht anbieten, ohne dass der Lesepfad berührt wird - create_item ist eine zweite TaskWriter-Methode, unverändert getrennt von TaskReader.
Keine Seite trägt nach dem Lauf einen Aufgabenzustand. Durch Bauart erfüllt: task new
schreibt nirgends eine Seite.
Kein Skill und keine Instruction nennt den Provider. test_gtd_weekly_review_skill_names_no_provider
ist zu test_task_tracker_skills_name_no_provider geworden und läuft parametrisiert über gtd-weekly-reviewundwiki-ingest.
Das Kommando ordnet kein Projekt selbst zu: es nimmt den Namen als Angabe, sucht nicht und
vergleicht nicht unscharf. Der Ingest-Skill legt Titel und vorgeschlagenes Projekt in einem
Schritt als Frage vor, und die drei Wege aus D4 stehen dort benannt.
Nachgezogen: docs/knowledge-and-commitment.md, tools/CONTRACT.md (Kommandotabelle und
Fehlervertrag), der Ingest-Skill, README.md und INSTALL.md (beide nannten bislang nur new project als Schreibweg), sowie #128 um das Kriterium, dass ein Azure-DevOps-Adapter create_item mitliefert. types/project.md und kb/gtd/COLLECTION.md blieben unverändert
- beide beschreiben nur die Seite und ihr Frontmatter, nie einen Schreibweg, also gab es dort
nichts nachzuziehen.
docs verify, instructions verify, pytest grün; Version gebumpt (--minor, neues Kommando
plus Protokollerweiterung, beidseitig drop-in).
Scheitert die Anlage des Postens, ist keine Seite geschrieben und keine Rohdatei
befördert — zur einen Hälfte erfüllt, zur anderen bewusst abgetrennt. „Keine Seite"
ist durch Bauart erfüllt (task new rührt raw//kb/ nie an) und durch die Schrittfolge im
Skill gesichert (Posten in Schritt 5, Seite in Schritt 6); „keine Rohdatei befördert" ist es
nicht, weil raw accept weiterhin Schritt 1 des Ingest ist und damit vor der
Verpflichtungserkennung läuft. Das ist der von lint/sources coverage ohnehin gemeldete
Zustand „Rohdatei ohne Quellenseite", also genau der entdeckte Zwischenzustand, den D3 als
den akzeptablen benennt. Ob die Beförderung trotzdem hinter die Verpflichtungsentscheidung
rücken soll, ist eine Änderung am Anfang jedes Ingest-Laufs und damit eine eigene
Entscheidung: #136.
Was bewusst offen blieb
#136 — soll raw accept hinter die Verpflichtungsentscheidung rücken? Siehe das gestrichene
Kriterium oben.
#112 — die Gegenposition zu D2 (unbeaufsichtigter Ingest) ist notiert und nicht gebaut; dieses
Paket setzt sie nicht voraus.
Verifiziert
pytest: 1429 Tests grün (davon neu: 6 Adapter-Tests in test_superproductivity.py, 12
Kommando-Tests in test_task_cmd.py, der parametrisierte Skill-Regressionstest).
tools/wikitool docs verify: grün, 58 dokumentierte Kommandos, keine Issue-Referenzen in 78
ausgelieferten Dokumenten.
Ausgeliefert als Commit cfbe3ea auf origin/main, Stack 7.0.0-beta.12; der Nachzug an README.md/INSTALL.md folgte im Abschluss-Commit derselben Arbeit.
Berührungspunkte
#128 (der zweite Adapter muss create_item mitliefern — dort eingetragen), #133 (der Schreibweg
setzt access: api voraus), #135 (Voraussetzung für den follow_up_at-Teil, eingearbeitet), #136 (die abgetrennte Reihenfolgefrage), #112 (unbeaufsichtigter Ingest), #131 (die Leserichtung).
Eine Quelle kann beides tragen — Wissen **und** eine Verpflichtung. Bis zu diesem Paket konnte der
Ingest nur die erste Hälfte: der Schreibpfad in den Tracker kannte genau ein Kommando, und das legte
ein Projekt an, keinen Posten.
**Umgesetzt und ausgeliefert** mit Stack `7.0.0-beta.12`, Commit `cfbe3ea` (2026-09-20).
## Was es jetzt gibt
`wikitool task new` legt **einen Posten im Tracker an, ohne jede `kb/`-Seite**:
```
wikitool task new --title "<Titel>" (--project "<Name>" | --inbox) \
[--waiting [--follow-up-at YYYY-MM-DD]] [--notes "<Freitext>"]
```
Darunter liegt `TaskWriter.create_item(title, *, project_name, waiting, follow_up_at, notes)` -
die zweite Methode des Schreibprotokolls neben `create_project`, umgesetzt im
Super-Productivity-Adapter über `POST /tasks`. Der Ingest-Skill fragt in Schritt 5 jetzt auch nach
einer Verpflichtung und legt sie, falls bestätigt, **vor** der Quellenseite an.
Damit gibt es einen zweiten Schreibweg in den Tracker in derselben Haltung wie der erste: nichts
wird gelesen und nichts abgeglichen, es wird einmal etwas hineingeschrieben. Die
Zwei-Schichten-Trennung bleibt unberührt - der Posten lebt ausschließlich im Tracker, keine
`kb/`-Seite trägt einen Aufgabenzustand, und ein Agent hat weiterhin keinen Anlass, die
Aufgabenliste außerhalb des Wochenrückblicks zu lesen.
## Fallbeispiel, an dem das Paket entworfen wurde
Ein Kunde reklamiert per Mail. Die Mail geht nach `incoming/`. Chemenu legt daraus
1. die Reklamation **inhaltlich** ab, verknüpft mit dem zugehörigen Projekt, und
2. die **Verpflichtung**, das Ganze nachzufassen, als Posten im Tracker.
Das ist kein Sonderfall, sondern der Normalfall für alles, was von außen hereinkommt und nicht bloß
Lesestoff ist: eine Mail, ein Protokoll, ein Angebot, ein Prüfbericht. Jedes davon hinterlässt etwas
zu wissen und etwas zu tun. Die ursprüngliche Frage „was geht wohin — `kb/`, `kb/gtd/` oder
Tracker" war richtig gestellt und falsch beantwortet: die Ziele schließen sich nicht aus.
## Die Entscheidungen
### D1 — Ein zweites Schreibkommando, bewusst schmal
Ein Posten trägt: Projekt (oder Eingang), Titel, optional `WAITING` mit `follow_up_at`, optional
einen Freitext-Rückverweis. **Kein Fälligkeitsdatum, kein Aufwand, keine Zuständigkeit** - die Regel
aus #128 gilt unverändert: ein gemeinsames Modell, das je Provider verschieden viel weiß, ist kein
gemeinsames Modell. Die Methode bindet jeden künftigen Adapter, also auch #128, bevor er existiert.
### D2 — Der Mensch klärt, der Agent schlägt vor: eine Frage im Skill, kein Gate
Eine Verpflichtung, die niemand eingegangen ist, ist schlimmer als eine vergessene: sie sieht aus
wie ein Commitment, steht in der Liste und wird beim nächsten Rückblick als echter offener Posten
behandelt. GTDs *Clarify* ist eine menschliche Entscheidung und wird nicht aus einer Mail erraten.
**Kein eigenes Gate im Code, sondern eine Frage im Skill.** Ein Gate ist für Unumkehrbares und
Massenhaftes da (`docs/why-gates-are-code.md`); ein einzelner Posten ist beides nicht - `new` hat
aus demselben Grund keines, und ein Gate, das bei jedem Ingest feuerte, wäre genau das reflexhaft
Geräumte. Die Verbindlichkeit liegt darin, dass der Agent das Kommando mit einem vom Nutzer
bestätigten Titel aufruft.
**Ausdrücklich ohne Auflage an #112** (Betreiber, 2026-09-20): die Gegenposition — läuft der
Ingest-Weg irgendwann unbeaufsichtigt, fehlt genau die Skill-Ebene — besteht fort und ist hier
nicht adressiert. Wer einen unbeaufsichtigten Stapellauf spezifiziert, stellt die Frage dort neu.
### D3 — Reihenfolge: Tracker vor Seite
Entscheidend ist, welcher Zwischenzustand *entdeckt* wird:
- Posten angelegt, Seite scheitert → die Rohdatei bleibt ohne Quellenseite, und das meldet `lint`
als `uncovered_raw_files`.
- Seite angelegt, Posten scheitert → **nichts meldet das.** Die Verpflichtung ist still verloren,
und sie ist die dringlichere Hälfte.
Umgesetzt als Schrittfolge im Ingest-Skill: `task new` in Schritt 5, Quellenseite in Schritt 6. Die
Beförderung nach `raw/` (Schritt 1) blieb, wo sie war - dazu **#136**, siehe § Was bewusst offen
blieb.
### D4 — Fehlt das Projekt, hält der Ingest an und fragt: drei Wege, kein Default
Existiert weder eine Projektseite noch ein Tracker-Projekt, rät der Agent nicht: er hält an und legt
drei Wege vor - ein vorhandenes Projekt benennen, `new project` (hält den Ingest auf jeder Instanz
an, weil kein Provider ein Tracker-Projekt selbst anlegen kann), oder **in den Eingang des
Trackers** als ausdrücklich gewählte Notausfahrt.
Der Eingang ist **nie ein Default, nur eine Wahl**, und der Skill nennt beim Anbieten ihre Kosten:
ein Posten ohne Projekt ist für den Rückblick unerreichbar (siehe § Der Rückblick erreicht Posten
nur über ihr Projekt). Der Unterschied zwischen dieser Route und einem Default ist der ganze Punkt:
ein Mensch, der sie wählt, weiß, dass der Posten außer Sicht liegt; ein Default hätte es ihm
verschwiegen. Deshalb hat sie eine eigene Form am Kommando (`--inbox`) - ein weggelassenes
`--project` ist ein Fehler, keine stille Eingangs-Ablage.
### D5 — Der Rückverweis auf die Seite ist Freitext und wird nie geparst
Genau die Haltung, die `WaitingItem.title` schon hat. Ein maschinenlesbarer Verweis wäre eine zweite
Kopplung neben dem Projektnamen und damit etwas, das auseinanderlaufen kann -
`docs/knowledge-and-commitment.md` § „One name, carrying the duties of an identifier" ist die
Begründung, warum es bei einer bleibt. Umgesetzt über `notes`.
### D6 — Die Projekterkennung schlägt vor, sie ordnet nicht zu
Vorschlag per `search` im Skill, Bestätigung durch den Nutzer, **keine automatische Zuordnung, auch
nicht bei einem eindeutigen Treffer**. Der Join bleibt exakte, case-normalisierte Gleichheit
(`normalize_project_name`); eine unscharfe Zuordnung wäre eine zweite, schwächere Matching-Regel
daneben, und rät sie falsch, landet die Verpflichtung in einem fremden Projekt, wo sie gültig
aussieht und von keiner Prüfung je auffällt. Ein falscher Treffer ist teurer als ein ausgebliebener.
Das Suchen blieb deshalb beim Skill: **das Kommando sucht nicht selbst.**
### Ein Dialogschritt, nicht drei
D2, D4 und D6 verlangen dieselbe menschliche Auskunft an derselben Stelle des Laufs und sind in der
Umsetzung auf **einen** Bestätigungsschritt zusammengefallen: der Skill legt Titel und
vorgeschlagenes Projekt gemeinsam als Frage vor, die Antwort ist eine Bestätigung, eine Korrektur
oder einer der drei Wege aus D4, danach ein Kommandoaufruf.
## Gegen den Quellcode verifiziert (`super-productivity/super-productivity@master`, 2026-09-20)
- **`POST /tasks` existiert** (`src/app/core/electron/local-rest-api-handler.service.ts`).
Schreibbar sind ausschließlich die Felder in `ALLOWED_TASK_FIELDS`: `title`, `notes`, `isDone`,
`timeEstimate`, `timeSpent`, `projectId`, `tagIds`, `dueDay`, `dueWithTime`, `plannedAt`,
`deadlineDay`, `deadlineWithTime`, `deadlineRemindAt`. Alles andere wirft `pickAllowedFields`
still weg. Der Fall, der `create_project` zu Exit 42 zwingt, tritt hier also nicht ein.
- **Der `waiting`-Tag muss schon existieren.** `tagIds` ist schreibbar, Tags sind über die API nicht
anlegbar (`GET /tags` ist die einzige Tag-Route). Umgesetzt: die Tag-Auflösung läuft **vor** dem
einen `POST`, sodass nie ein Posten ohne seinen Status entsteht.
- **`follow_up_at` wird als `dueDay` geschrieben** - die Spiegelung der mit #135 korrigierten
Leseregel (`dueWithTime`, sonst `dueDay`; nie `deadline*`).
- **Ein Posten landet nie im Backlog** (`isAddToBacklog` fest `false`). Für dieses Paket ohne
Folgen - Someday/Maybe wird hier nicht geschrieben -, aber es ist die Grenze des Schreibwegs.
- **Der Eingang erscheint nicht in `GET /projects`.** `INBOX_PROJECT` ist zwar immer ein echtes
Projekt-Entity im Store (`_addInboxProjectIfNecessary` legt es an, falls es fehlt), aber
`selectUnarchivedProjects` - der Selektor hinter `GET /projects` - filtert es unbedingt über seine
feste id heraus (`p.id !== INBOX_PROJECT.id`, `project.selectors.ts`/`project.const.ts`).
**Folge:** Prüfung 3 (`unpaged_project_weeks`) braucht **keine** Ausnahme für den Eingang - er
taucht in `tracker_projects` nie auf, es gibt nichts auszunehmen. Der Adapter schreibt die feste
id deshalb explizit (`INBOX_PROJECT_ID`), statt `projectId` wegzulassen: ohne Angabe fällt Super
Productivity auf den gerade aktiven Work Context zurück, also auf das zufällig geöffnete Projekt.
## Der Rückblick erreicht Posten nur über ihr Projekt
`run_review` erreicht Posten ausschließlich über `projects()` → `open_items(project.name)`
(`tools/chemenu/review.py`). Ein Posten **ohne Projekt ist für den Rückblick unsichtbar** - es
bleibt kein Befund aus, es entsteht schlicht nie einer. Kein Argument gegen den Eingang als
Ablageort, sondern eines dafür, dass diese Route ihre Kosten beim Anbieten nennt statt beim
Vermissen (D4); der Ingest-Skill tut das.
## Akzeptanzkriterien
- [x] Ein Posten lässt sich über `wikitool` in einem benannten Tracker-Projekt anlegen, optional als
`WAITING` mit `follow_up_at` und mit einem Freitext-Rückverweis in `notes`; gegen Fixtures
getestet, kein Test braucht eine laufende Super-Productivity-Instanz.
- [x] Der Posten taucht anschließend in `wikitool review` auf: als offener Posten des Projekts, und
bei gesetztem `follow_up_at` nach Ablauf der Schwelle in Prüfung 2 - über den Lesepfad
getestet, angelegt und wiedergelesen
(`test_created_item_appears_in_review_as_an_open_and_overdue_waiting_item`).
- [x] Fehlt der `waiting`-Tag im Tracker, scheitert die Anlage eines `WAITING`-Postens laut; es
entsteht kein Posten ohne seinen Status. Getestet auf beiden Ebenen (Adapter und Kommando),
jeweils mit der Zusicherung, dass **kein** `POST` abgesetzt wurde.
- [x] Die Eingangs-Route hat eine eigene Form am Kommando (`--inbox`); ein weggelassenes `--project`
ist ein Fehler, keine stille Eingangs-Ablage. Getestet, in beiden Richtungen (keines von
beiden angegeben, und beide zugleich).
- [x] **Verifiziert beim Bauen:** der Eingang erscheint **nicht** in `GET /projects` - siehe
§ Gegen den Quellcode verifiziert. Prüfung 3 braucht folglich keine Ausnahme, und der Skill
sagt beim Anbieten der Route ausdrücklich, dass `review` den Posten nicht sieht.
- [x] Der Schreibweg steht nur einer Instanz mit `access: api` zur Verfügung; auf einer
`snapshot`-Instanz gibt es ihn nicht (`test_snapshot_access_has_no_write_path`, exit 1 mit
Verweis auf die `api`-Instanz).
- [x] Ein Adapter kann den Schreibweg nicht anbieten, ohne dass der Lesepfad berührt wird -
`create_item` ist eine zweite `TaskWriter`-Methode, unverändert getrennt von `TaskReader`.
- [x] Keine Seite trägt nach dem Lauf einen Aufgabenzustand. Durch Bauart erfüllt: `task new`
schreibt nirgends eine Seite.
- [x] Kein Skill und keine Instruction nennt den Provider. `test_gtd_weekly_review_skill_names_no_provider`
ist zu `test_task_tracker_skills_name_no_provider` geworden und läuft parametrisiert über
`gtd-weekly-review` **und** `wiki-ingest`.
- [x] Das Kommando ordnet kein Projekt selbst zu: es nimmt den Namen als Angabe, sucht nicht und
vergleicht nicht unscharf. Der Ingest-Skill legt Titel und vorgeschlagenes Projekt in **einem**
Schritt als Frage vor, und die drei Wege aus D4 stehen dort benannt.
- [x] Nachgezogen: `docs/knowledge-and-commitment.md`, `tools/CONTRACT.md` (Kommandotabelle und
Fehlervertrag), der Ingest-Skill, `README.md` und `INSTALL.md` (beide nannten bislang nur
`new project` als Schreibweg), sowie #128 um das Kriterium, dass ein Azure-DevOps-Adapter
`create_item` mitliefert. **`types/project.md` und `kb/gtd/COLLECTION.md` blieben unverändert**
- beide beschreiben nur die Seite und ihr Frontmatter, nie einen Schreibweg, also gab es dort
nichts nachzuziehen.
- [x] `docs verify`, `instructions verify`, `pytest` grün; Version gebumpt (`--minor`, neues Kommando
plus Protokollerweiterung, beidseitig drop-in).
- [x] ~~Scheitert die Anlage des Postens, ist keine Seite geschrieben **und keine Rohdatei
befördert**~~ — **zur einen Hälfte erfüllt, zur anderen bewusst abgetrennt.** „Keine Seite"
ist durch Bauart erfüllt (`task new` rührt `raw/`/`kb/` nie an) und durch die Schrittfolge im
Skill gesichert (Posten in Schritt 5, Seite in Schritt 6); „keine Rohdatei befördert" ist es
nicht, weil `raw accept` weiterhin Schritt 1 des Ingest ist und damit vor der
Verpflichtungserkennung läuft. Das ist der von `lint`/`sources coverage` ohnehin gemeldete
Zustand „Rohdatei ohne Quellenseite", also genau der *entdeckte* Zwischenzustand, den D3 als
den akzeptablen benennt. Ob die Beförderung trotzdem hinter die Verpflichtungsentscheidung
rücken soll, ist eine Änderung am Anfang **jedes** Ingest-Laufs und damit eine eigene
Entscheidung: **#136.**
## Was bewusst offen blieb
- **#136** — soll `raw accept` hinter die Verpflichtungsentscheidung rücken? Siehe das gestrichene
Kriterium oben.
- **#112** — die Gegenposition zu D2 (unbeaufsichtigter Ingest) ist notiert und nicht gebaut; dieses
Paket setzt sie nicht voraus.
## Verifiziert
- `pytest`: 1429 Tests grün (davon neu: 6 Adapter-Tests in `test_superproductivity.py`, 12
Kommando-Tests in `test_task_cmd.py`, der parametrisierte Skill-Regressionstest).
- `tools/wikitool docs verify`: grün, 58 dokumentierte Kommandos, keine Issue-Referenzen in 78
ausgelieferten Dokumenten.
- `tools/wikitool instructions verify`: grün, 23 Instructions und 8 Skills, 16 publizierte Kopien
deckungsgleich.
- Ausgeliefert als Commit `cfbe3ea` auf `origin/main`, Stack `7.0.0-beta.12`; der Nachzug an
`README.md`/`INSTALL.md` folgte im Abschluss-Commit derselben Arbeit.
## Berührungspunkte
#128 (der zweite Adapter muss `create_item` mitliefern — dort eingetragen), #133 (der Schreibweg
setzt `access: api` voraus), #135 (Voraussetzung für den `follow_up_at`-Teil, eingearbeitet),
#136 (die abgetrennte Reihenfolgefrage), #112 (unbeaufsichtigter Ingest), #131 (die Leserichtung).
torben
changed title from Capture und Zielwahl: was geht nach raw/kb, was nach kb/gtd, was in den Tracker? to Ein Ingest, zwei Schichten: die Seite ablegen und die Verpflichtung im Tracker anlegen2026-09-20 10:27:11 +00:00
Changelog: Body und Titel vollständig neu geschrieben am Fallbeispiel des Betreibers
(Kundenreklamation per Mail → Inhalt mit Projektbezug ablegen und das Nachfassen als Verpflichtung
anlegen).
Gestrichen: der MCP-Capture-Rahmen und der mobile Fall — beides Spielerei (siehe #131). Der
Weg über incoming/ bleibt, den es ohnehin gibt.
Korrigiert: die alte Fassung fragte „was geht wohin — kb/, kb/gtd/ oder Tracker" und nahm
die drei Ziele als exklusiv an. Sie sind es nicht: eine Quelle erzeugt in der Regel beides.
Neu belegt:TaskWriter kennt genau create_project — für einen Posten gibt es weder
Protokoll noch Kommando, das ist die eigentliche Lücke. Die SP-REST-API hat Task-CRUD (nur
Projekt-CRUD fehlt), der HumanInterventionRequired-Fall tritt hier also nicht ein.
„Nachfassen" fällt exakt auf das vorhandene WAITING/follow_up_at-Paar, womit Prüfung 2 des
Rückblicks die Verpflichtung ohne neuen Mechanismus wieder anfasst. Reihenfolge Tracker-vor-Seite
jetzt mit eigenem Beleg: „Posten ohne Seite" meldet lint als uncovered_raw_files, „Seite ohne
Posten" meldet nichts.
Neue Entscheidungen: D1 zweites Schreibkommando, D2 Klärung durch den Menschen, D3
Reihenfolge, D4 Projektzuordnung, D5 Rückverweis im Posten.
**Changelog:** Body und Titel vollständig neu geschrieben am Fallbeispiel des Betreibers
(Kundenreklamation per Mail → Inhalt mit Projektbezug ablegen *und* das Nachfassen als Verpflichtung
anlegen).
- **Gestrichen:** der MCP-Capture-Rahmen und der mobile Fall — beides Spielerei (siehe #131). Der
Weg über `incoming/` bleibt, den es ohnehin gibt.
- **Korrigiert:** die alte Fassung fragte „was geht wohin — `kb/`, `kb/gtd/` oder Tracker" und nahm
die drei Ziele als exklusiv an. Sie sind es nicht: eine Quelle erzeugt in der Regel beides.
- **Neu belegt:** `TaskWriter` kennt genau `create_project` — für einen Posten gibt es weder
Protokoll noch Kommando, das ist die eigentliche Lücke. Die SP-REST-API hat Task-CRUD (nur
Projekt-CRUD fehlt), der `HumanInterventionRequired`-Fall tritt hier also nicht ein.
„Nachfassen" fällt exakt auf das vorhandene `WAITING`/`follow_up_at`-Paar, womit Prüfung 2 des
Rückblicks die Verpflichtung ohne neuen Mechanismus wieder anfasst. Reihenfolge Tracker-vor-Seite
jetzt mit eigenem Beleg: „Posten ohne Seite" meldet `lint` als `uncovered_raw_files`, „Seite ohne
Posten" meldet nichts.
- **Neue Entscheidungen:** D1 zweites Schreibkommando, D2 Klärung durch den Menschen, D3
Reihenfolge, D4 Projektzuordnung, D5 Rückverweis im Posten.
Changelog: Die Endpunkt-Verifikation gegen den SP-Quellcode ist gelaufen (2026-09-20) und
erledigt den letzten der vier Punkte unter „Vorher zu klären". Die drei Entscheidungsfragen D2, D4
und die Projekterkennung bleiben offen — kind/decision steht unverändert.
Neu: § Der Schreibweg, gegen den Quellcode verifiziert. POST /tasks existiert, die
schreibbare Feldliste steht vollständig im Body.
Neu, vier Auflagen: der waiting-Tag muss vorher existieren (Tags sind über die API nicht
anlegbar); follow_up_at ist erst nach #135 schreibbar; ein Posten landet nie im Backlog
(isAddToBacklog fest false); notes ist schreibbar, D5 also umsetzbar.
Geschärft: die erste der „drei Dinge, die den Weg kurz machen" stand als Notiz unter
Verifikationsvorbehalt und ist jetzt belegt — samt der Abgrenzung, warum create_project Exit 42
braucht und dieser Weg nicht.
Neu bei D4: dass new project das Tracker-Projekt auf keiner Instanz selbst anlegen kann,
ist eine Randbedingung der Entscheidung — die Variante „erst new project" hält den Ingest
immer an.
Neues Kriterium: fehlender waiting-Tag muss laut scheitern statt stumm einen Posten ohne
Status anzulegen.
Abhängigkeit: der follow_up_at-Teil der Umsetzung setzt #135 voraus.
**Changelog:** Die Endpunkt-Verifikation gegen den SP-Quellcode ist gelaufen (2026-09-20) und
erledigt den letzten der vier Punkte unter „Vorher zu klären". Die drei Entscheidungsfragen D2, D4
und die Projekterkennung bleiben offen — `kind/decision` steht unverändert.
- **Neu:** § Der Schreibweg, gegen den Quellcode verifiziert. `POST /tasks` existiert, die
schreibbare Feldliste steht vollständig im Body.
- **Neu, vier Auflagen:** der `waiting`-Tag muss vorher existieren (Tags sind über die API nicht
anlegbar); `follow_up_at` ist erst nach #135 schreibbar; ein Posten landet nie im Backlog
(`isAddToBacklog` fest `false`); `notes` ist schreibbar, D5 also umsetzbar.
- **Geschärft:** die erste der „drei Dinge, die den Weg kurz machen" stand als Notiz unter
Verifikationsvorbehalt und ist jetzt belegt — samt der Abgrenzung, warum `create_project` Exit 42
braucht und dieser Weg nicht.
- **Neu bei D4:** dass `new project` das Tracker-Projekt auf **keiner** Instanz selbst anlegen kann,
ist eine Randbedingung der Entscheidung — die Variante „erst `new project`" hält den Ingest
immer an.
- **Neues Kriterium:** fehlender `waiting`-Tag muss laut scheitern statt stumm einen Posten ohne
Status anzulegen.
- **Abhängigkeit:** der `follow_up_at`-Teil der Umsetzung setzt #135 voraus.
Changelog: Die drei offenen Punkte sind am 2026-09-20 entschieden; „Vorher zu klären" ist leer. kind/decision → kind/build, size/L → size/M (die offenen Designfragen vor dem ersten Commit
waren das L-Kriterium, und sie sind weg — mehrere Dateien plus Contract-/Instruction-Änderung mit
eigenem Testaufwand bleiben).
D2 entschieden: Skill-Frage, kein Gate — und ausdrücklich ohne Auflage an #112. Die
Gegenposition (unbeaufsichtigter Stapellauf) ist im Body als bestehend und unadressiert notiert;
wer sie baut, stellt die Frage dort neu.
D4 entschieden: kein Default. Der Ingest hält an und legt drei Wege vor — vorhandenes Projekt
benennen, new project, oder in den Eingang des Trackers. Der Eingang ist die ausdrücklich
gewählte Notausfahrt, nie ein Default, und der Skill nennt beim Anbieten ihre Kosten. Dazu neu:
das Kommando braucht für sie eine eigene Form (--inbox), ein weggelassenes --project ist ein
Fehler.
D6 neu, entschieden: die Projekterkennung schlägt per search vor und ordnet nie automatisch
zu, auch nicht bei einem eindeutigen Treffer. Das Suchen bleibt beim Skill; das Kommando nimmt den
Namen als Angabe.
Neuer Befund aus dem Lesepfad: § Der Rückblick erreicht Posten nur über ihr Projekt. run_review erreicht Posten ausschließlich über projects() → open_items(project.name)
(tools/chemenu/review.py:145-184) — ein Posten ohne Projekt ist für Prüfung 2 unsichtbar. Das
beschneidet D4 Weg 3 und ist der Grund, warum diese Route ihre Kosten beim Anbieten nennen muss.
Neues Kriterium, eine Verifikation beim Bauen: erscheint der SP-Eingang in GET /projects?
Wenn ja, nimmt Prüfung 3 ihn aus (getestet); wenn nein, sagt der Skill beim Anbieten der Route,
dass review den Posten nicht sieht. Das Ergebnis wird im Body nachgezogen statt als Annahme in
den Code geschrieben.
Neuer Abschnitt § Ein Dialogschritt, nicht drei: D2, D4 und D6 verlangen dieselbe menschliche
Auskunft an derselben Stelle und fallen in der Umsetzung auf eine Frage zusammen (Titel +
vorgeschlagenes Projekt), danach ein Kommandoaufruf.
Geschärft: D1 nennt den Freitext-Rückverweis aus D5 als Feld mit; das Kriterium zum
Schreibweg nennt notes jetzt ausdrücklich.
**Changelog:** Die drei offenen Punkte sind am 2026-09-20 entschieden; „Vorher zu klären" ist leer.
`kind/decision` → `kind/build`, `size/L` → `size/M` (die offenen Designfragen vor dem ersten Commit
waren das L-Kriterium, und sie sind weg — mehrere Dateien plus Contract-/Instruction-Änderung mit
eigenem Testaufwand bleiben).
- **D2 entschieden:** Skill-Frage, kein Gate — **und ausdrücklich ohne Auflage an #112.** Die
Gegenposition (unbeaufsichtigter Stapellauf) ist im Body als bestehend und unadressiert notiert;
wer sie baut, stellt die Frage dort neu.
- **D4 entschieden:** kein Default. Der Ingest hält an und legt drei Wege vor — vorhandenes Projekt
benennen, `new project`, oder in den Eingang des Trackers. Der Eingang ist die ausdrücklich
gewählte Notausfahrt, nie ein Default, und der Skill nennt beim Anbieten ihre Kosten. Dazu neu:
das Kommando braucht für sie eine eigene Form (`--inbox`), ein weggelassenes `--project` ist ein
Fehler.
- **D6 neu, entschieden:** die Projekterkennung schlägt per `search` vor und ordnet nie automatisch
zu, auch nicht bei einem eindeutigen Treffer. Das Suchen bleibt beim Skill; das Kommando nimmt den
Namen als Angabe.
- **Neuer Befund aus dem Lesepfad:** § Der Rückblick erreicht Posten nur über ihr Projekt.
`run_review` erreicht Posten ausschließlich über `projects()` → `open_items(project.name)`
(`tools/chemenu/review.py:145-184`) — ein Posten ohne Projekt ist für Prüfung 2 unsichtbar. Das
beschneidet D4 Weg 3 und ist der Grund, warum diese Route ihre Kosten beim Anbieten nennen muss.
- **Neues Kriterium, eine Verifikation beim Bauen:** erscheint der SP-Eingang in `GET /projects`?
Wenn ja, nimmt Prüfung 3 ihn aus (getestet); wenn nein, sagt der Skill beim Anbieten der Route,
dass `review` den Posten nicht sieht. Das Ergebnis wird im Body nachgezogen statt als Annahme in
den Code geschrieben.
- **Neuer Abschnitt § Ein Dialogschritt, nicht drei:** D2, D4 und D6 verlangen dieselbe menschliche
Auskunft an derselben Stelle und fallen in der Umsetzung auf eine Frage zusammen (Titel +
vorgeschlagenes Projekt), danach ein Kommandoaufruf.
- **Geschärft:** D1 nennt den Freitext-Rückverweis aus D5 als Feld mit; das Kriterium zum
Schreibweg nennt `notes` jetzt ausdrücklich.
Changelog: Umgesetzt (2026-09-20). Alle Akzeptanzkriterien bis auf eines abgehakt - siehe die
Anmerkung an der einen offenen Zeile für eine Lesart, die zur Bestätigung vorgelegt wird statt
selbst entschieden zu sein.
Neu: wikitool task new, TaskWriter.create_item im Protokoll, SuperProductivityWriters
Umsetzung (INBOX_PROJECT-Konstante, Projekt-Id- und waiting-Tag-Auflösung vor dem einen POST /tasks).
Der Ingest-Skill (instructions/wiki-ingest/SKILL.md) hat Schritt 5 um die
Verpflichtungs-Erkennung erweitert: ein Dialogschritt (D2/D4/D6), task new vor Schritt 6
(Quellenseite).
Eine Lesart zur Bestätigung: Die Kriteriumszeile zu „keine Rohdatei befördert, wenn die
Postenanlage scheitert" ist nur teilweise erfüllt - task new selbst rührt raw//kb/ nie an,
aber Schritt 1 (raw accept) läuft weiterhin vor der Verpflichtungserkennung, nicht danach. Details
und Begründung stehen an der Zeile selbst im Body. Wenn die Beförderung ebenfalls hinter die
Verpflichtungsentscheidung soll, ist das ein Nachzug an Schritt 1 des Ingest-Skills - noch nicht
gebaut.
**Changelog:** Umgesetzt (2026-09-20). Alle Akzeptanzkriterien bis auf eines abgehakt - siehe die
Anmerkung an der einen offenen Zeile für eine Lesart, die zur Bestätigung vorgelegt wird statt
selbst entschieden zu sein.
- Neu: `wikitool task new`, `TaskWriter.create_item` im Protokoll, `SuperProductivityWriter`s
Umsetzung (`INBOX_PROJECT`-Konstante, Projekt-Id- und `waiting`-Tag-Auflösung vor dem einen
`POST /tasks`).
- Der Ingest-Skill (`instructions/wiki-ingest/SKILL.md`) hat Schritt 5 um die
Verpflichtungs-Erkennung erweitert: ein Dialogschritt (D2/D4/D6), `task new` vor Schritt 6
(Quellenseite).
- `docs/knowledge-and-commitment.md`, `tools/CONTRACT.md` nachgezogen; #128 aktualisiert.
- Tests: `test_superproductivity.py` (Schreibpfad), `test_task_cmd.py` (CLI, inkl. Rundlauf durch
`review`), `test_instructions_cmd.py` (Provider-Regressionstest parametrisiert).
- `docs verify`/`instructions verify`/`pytest` grün.
**Eine Lesart zur Bestätigung:** Die Kriteriumszeile zu „keine Rohdatei befördert, wenn die
Postenanlage scheitert" ist nur teilweise erfüllt - `task new` selbst rührt `raw/`/`kb/` nie an,
aber Schritt 1 (`raw accept`) läuft weiterhin vor der Verpflichtungserkennung, nicht danach. Details
und Begründung stehen an der Zeile selbst im Body. Wenn die Beförderung ebenfalls hinter die
Verpflichtungsentscheidung soll, ist das ein Nachzug an Schritt 1 des Ingest-Skills - noch nicht
gebaut.
Changelog: Abschluss-Rewrite. Der Body ist jetzt der Endzustand statt einer Spezifikation:
„Wo es heute abbricht" ist durch „Was es jetzt gibt" ersetzt, die Entscheidungen D1-D6 lesen sich
als entschieden, und die Verifikationsergebnisse (inkl. des Befunds zum SP-Eingang) stehen im Body
statt verteilt in den Kommentaren.
Alle Akzeptanzkriterien abgehakt bis auf eines: „keine Rohdatei befördert" ist gestrichen und
als #136 abgetrennt (kind/decision, size/S) — task new rührt raw//kb/ nie an, aber raw accept bleibt Schritt 1 des Ingest und läuft damit vor der Verpflichtungserkennung; ob das
so bleibt, ist eine Änderung am Anfang jedes Ingest-Laufs und damit eine eigene Entscheidung.
Neu im Nachzug:README.md und INSTALL.md nannten bislang nur new project als Schreibweg
in den Tracker - beide nennen jetzt auch task new (Commit 88e7cc1).
Festgehalten:types/project.md und kb/gtd/COLLECTION.md blieben bewusst unverändert.
**Changelog:** Abschluss-Rewrite. Der Body ist jetzt der Endzustand statt einer Spezifikation:
„Wo es heute abbricht" ist durch „Was es jetzt gibt" ersetzt, die Entscheidungen D1-D6 lesen sich
als entschieden, und die Verifikationsergebnisse (inkl. des Befunds zum SP-Eingang) stehen im Body
statt verteilt in den Kommentaren.
- **Alle Akzeptanzkriterien abgehakt** bis auf eines: „keine Rohdatei befördert" ist gestrichen und
als **#136** abgetrennt (`kind/decision`, `size/S`) — `task new` rührt `raw/`/`kb/` nie an, aber
`raw accept` bleibt Schritt 1 des Ingest und läuft damit vor der Verpflichtungserkennung; ob das
so bleibt, ist eine Änderung am Anfang jedes Ingest-Laufs und damit eine eigene Entscheidung.
- **Neu im Nachzug:** `README.md` und `INSTALL.md` nannten bislang nur `new project` als Schreibweg
in den Tracker - beide nennen jetzt auch `task new` (Commit `88e7cc1`).
- **Festgehalten:** `types/project.md` und `kb/gtd/COLLECTION.md` blieben bewusst unverändert.
- **Verifikation benannt:** `pytest` (1429 grün), `docs verify`, `instructions verify`, Commits
`cfbe3ea` und `88e7cc1`, Stack `7.0.0-beta.12`.
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.
Eine Quelle kann beides tragen — Wissen und eine Verpflichtung. Bis zu diesem Paket konnte der
Ingest nur die erste Hälfte: der Schreibpfad in den Tracker kannte genau ein Kommando, und das legte
ein Projekt an, keinen Posten.
Umgesetzt und ausgeliefert mit Stack
7.0.0-beta.12, Commitcfbe3ea(2026-09-20).Was es jetzt gibt
wikitool task newlegt einen Posten im Tracker an, ohne jedekb/-Seite:Darunter liegt
TaskWriter.create_item(title, *, project_name, waiting, follow_up_at, notes)-die zweite Methode des Schreibprotokolls neben
create_project, umgesetzt imSuper-Productivity-Adapter über
POST /tasks. Der Ingest-Skill fragt in Schritt 5 jetzt auch nacheiner Verpflichtung und legt sie, falls bestätigt, vor der Quellenseite an.
Damit gibt es einen zweiten Schreibweg in den Tracker in derselben Haltung wie der erste: nichts
wird gelesen und nichts abgeglichen, es wird einmal etwas hineingeschrieben. Die
Zwei-Schichten-Trennung bleibt unberührt - der Posten lebt ausschließlich im Tracker, keine
kb/-Seite trägt einen Aufgabenzustand, und ein Agent hat weiterhin keinen Anlass, dieAufgabenliste außerhalb des Wochenrückblicks zu lesen.
Fallbeispiel, an dem das Paket entworfen wurde
Ein Kunde reklamiert per Mail. Die Mail geht nach
incoming/. Chemenu legt darausDas ist kein Sonderfall, sondern der Normalfall für alles, was von außen hereinkommt und nicht bloß
Lesestoff ist: eine Mail, ein Protokoll, ein Angebot, ein Prüfbericht. Jedes davon hinterlässt etwas
zu wissen und etwas zu tun. Die ursprüngliche Frage „was geht wohin —
kb/,kb/gtd/oderTracker" war richtig gestellt und falsch beantwortet: die Ziele schließen sich nicht aus.
Die Entscheidungen
D1 — Ein zweites Schreibkommando, bewusst schmal
Ein Posten trägt: Projekt (oder Eingang), Titel, optional
WAITINGmitfollow_up_at, optionaleinen Freitext-Rückverweis. Kein Fälligkeitsdatum, kein Aufwand, keine Zuständigkeit - die Regel
aus #128 gilt unverändert: ein gemeinsames Modell, das je Provider verschieden viel weiß, ist kein
gemeinsames Modell. Die Methode bindet jeden künftigen Adapter, also auch #128, bevor er existiert.
D2 — Der Mensch klärt, der Agent schlägt vor: eine Frage im Skill, kein Gate
Eine Verpflichtung, die niemand eingegangen ist, ist schlimmer als eine vergessene: sie sieht aus
wie ein Commitment, steht in der Liste und wird beim nächsten Rückblick als echter offener Posten
behandelt. GTDs Clarify ist eine menschliche Entscheidung und wird nicht aus einer Mail erraten.
Kein eigenes Gate im Code, sondern eine Frage im Skill. Ein Gate ist für Unumkehrbares und
Massenhaftes da (
docs/why-gates-are-code.md); ein einzelner Posten ist beides nicht -newhataus demselben Grund keines, und ein Gate, das bei jedem Ingest feuerte, wäre genau das reflexhaft
Geräumte. Die Verbindlichkeit liegt darin, dass der Agent das Kommando mit einem vom Nutzer
bestätigten Titel aufruft.
Ausdrücklich ohne Auflage an #112 (Betreiber, 2026-09-20): die Gegenposition — läuft der
Ingest-Weg irgendwann unbeaufsichtigt, fehlt genau die Skill-Ebene — besteht fort und ist hier
nicht adressiert. Wer einen unbeaufsichtigten Stapellauf spezifiziert, stellt die Frage dort neu.
D3 — Reihenfolge: Tracker vor Seite
Entscheidend ist, welcher Zwischenzustand entdeckt wird:
lintals
uncovered_raw_files.und sie ist die dringlichere Hälfte.
Umgesetzt als Schrittfolge im Ingest-Skill:
task newin Schritt 5, Quellenseite in Schritt 6. DieBeförderung nach
raw/(Schritt 1) blieb, wo sie war - dazu #136, siehe § Was bewusst offenblieb.
D4 — Fehlt das Projekt, hält der Ingest an und fragt: drei Wege, kein Default
Existiert weder eine Projektseite noch ein Tracker-Projekt, rät der Agent nicht: er hält an und legt
drei Wege vor - ein vorhandenes Projekt benennen,
new project(hält den Ingest auf jeder Instanzan, weil kein Provider ein Tracker-Projekt selbst anlegen kann), oder in den Eingang des
Trackers als ausdrücklich gewählte Notausfahrt.
Der Eingang ist nie ein Default, nur eine Wahl, und der Skill nennt beim Anbieten ihre Kosten:
ein Posten ohne Projekt ist für den Rückblick unerreichbar (siehe § Der Rückblick erreicht Posten
nur über ihr Projekt). Der Unterschied zwischen dieser Route und einem Default ist der ganze Punkt:
ein Mensch, der sie wählt, weiß, dass der Posten außer Sicht liegt; ein Default hätte es ihm
verschwiegen. Deshalb hat sie eine eigene Form am Kommando (
--inbox) - ein weggelassenes--projectist ein Fehler, keine stille Eingangs-Ablage.D5 — Der Rückverweis auf die Seite ist Freitext und wird nie geparst
Genau die Haltung, die
WaitingItem.titleschon hat. Ein maschinenlesbarer Verweis wäre eine zweiteKopplung neben dem Projektnamen und damit etwas, das auseinanderlaufen kann -
docs/knowledge-and-commitment.md§ „One name, carrying the duties of an identifier" ist dieBegründung, warum es bei einer bleibt. Umgesetzt über
notes.D6 — Die Projekterkennung schlägt vor, sie ordnet nicht zu
Vorschlag per
searchim Skill, Bestätigung durch den Nutzer, keine automatische Zuordnung, auchnicht bei einem eindeutigen Treffer. Der Join bleibt exakte, case-normalisierte Gleichheit
(
normalize_project_name); eine unscharfe Zuordnung wäre eine zweite, schwächere Matching-Regeldaneben, und rät sie falsch, landet die Verpflichtung in einem fremden Projekt, wo sie gültig
aussieht und von keiner Prüfung je auffällt. Ein falscher Treffer ist teurer als ein ausgebliebener.
Das Suchen blieb deshalb beim Skill: das Kommando sucht nicht selbst.
Ein Dialogschritt, nicht drei
D2, D4 und D6 verlangen dieselbe menschliche Auskunft an derselben Stelle des Laufs und sind in der
Umsetzung auf einen Bestätigungsschritt zusammengefallen: der Skill legt Titel und
vorgeschlagenes Projekt gemeinsam als Frage vor, die Antwort ist eine Bestätigung, eine Korrektur
oder einer der drei Wege aus D4, danach ein Kommandoaufruf.
Gegen den Quellcode verifiziert (
super-productivity/super-productivity@master, 2026-09-20)POST /tasksexistiert (src/app/core/electron/local-rest-api-handler.service.ts).Schreibbar sind ausschließlich die Felder in
ALLOWED_TASK_FIELDS:title,notes,isDone,timeEstimate,timeSpent,projectId,tagIds,dueDay,dueWithTime,plannedAt,deadlineDay,deadlineWithTime,deadlineRemindAt. Alles andere wirftpickAllowedFieldsstill weg. Der Fall, der
create_projectzu Exit 42 zwingt, tritt hier also nicht ein.waiting-Tag muss schon existieren.tagIdsist schreibbar, Tags sind über die API nichtanlegbar (
GET /tagsist die einzige Tag-Route). Umgesetzt: die Tag-Auflösung läuft vor demeinen
POST, sodass nie ein Posten ohne seinen Status entsteht.follow_up_atwird alsdueDaygeschrieben - die Spiegelung der mit #135 korrigiertenLeseregel (
dueWithTime, sonstdueDay; niedeadline*).isAddToBacklogfestfalse). Für dieses Paket ohneFolgen - Someday/Maybe wird hier nicht geschrieben -, aber es ist die Grenze des Schreibwegs.
GET /projects.INBOX_PROJECTist zwar immer ein echtesProjekt-Entity im Store (
_addInboxProjectIfNecessarylegt es an, falls es fehlt), aberselectUnarchivedProjects- der Selektor hinterGET /projects- filtert es unbedingt über seinefeste id heraus (
p.id !== INBOX_PROJECT.id,project.selectors.ts/project.const.ts).Folge: Prüfung 3 (
unpaged_project_weeks) braucht keine Ausnahme für den Eingang - ertaucht in
tracker_projectsnie auf, es gibt nichts auszunehmen. Der Adapter schreibt die festeid deshalb explizit (
INBOX_PROJECT_ID), stattprojectIdwegzulassen: ohne Angabe fällt SuperProductivity auf den gerade aktiven Work Context zurück, also auf das zufällig geöffnete Projekt.
Der Rückblick erreicht Posten nur über ihr Projekt
run_reviewerreicht Posten ausschließlich überprojects()→open_items(project.name)(
tools/chemenu/review.py). Ein Posten ohne Projekt ist für den Rückblick unsichtbar - esbleibt kein Befund aus, es entsteht schlicht nie einer. Kein Argument gegen den Eingang als
Ablageort, sondern eines dafür, dass diese Route ihre Kosten beim Anbieten nennt statt beim
Vermissen (D4); der Ingest-Skill tut das.
Akzeptanzkriterien
wikitoolin einem benannten Tracker-Projekt anlegen, optional alsWAITINGmitfollow_up_atund mit einem Freitext-Rückverweis innotes; gegen Fixturesgetestet, kein Test braucht eine laufende Super-Productivity-Instanz.
wikitool reviewauf: als offener Posten des Projekts, undbei gesetztem
follow_up_atnach Ablauf der Schwelle in Prüfung 2 - über den Lesepfadgetestet, angelegt und wiedergelesen
(
test_created_item_appears_in_review_as_an_open_and_overdue_waiting_item).waiting-Tag im Tracker, scheitert die Anlage einesWAITING-Postens laut; esentsteht kein Posten ohne seinen Status. Getestet auf beiden Ebenen (Adapter und Kommando),
jeweils mit der Zusicherung, dass kein
POSTabgesetzt wurde.--inbox); ein weggelassenes--projectist ein Fehler, keine stille Eingangs-Ablage. Getestet, in beiden Richtungen (keines von
beiden angegeben, und beide zugleich).
GET /projects- siehe§ Gegen den Quellcode verifiziert. Prüfung 3 braucht folglich keine Ausnahme, und der Skill
sagt beim Anbieten der Route ausdrücklich, dass
reviewden Posten nicht sieht.access: apizur Verfügung; auf einersnapshot-Instanz gibt es ihn nicht (test_snapshot_access_has_no_write_path, exit 1 mitVerweis auf die
api-Instanz).create_itemist eine zweiteTaskWriter-Methode, unverändert getrennt vonTaskReader.task newschreibt nirgends eine Seite.
test_gtd_weekly_review_skill_names_no_providerist zu
test_task_tracker_skills_name_no_providergeworden und läuft parametrisiert übergtd-weekly-reviewundwiki-ingest.vergleicht nicht unscharf. Der Ingest-Skill legt Titel und vorgeschlagenes Projekt in einem
Schritt als Frage vor, und die drei Wege aus D4 stehen dort benannt.
docs/knowledge-and-commitment.md,tools/CONTRACT.md(Kommandotabelle undFehlervertrag), der Ingest-Skill,
README.mdundINSTALL.md(beide nannten bislang nurnew projectals Schreibweg), sowie #128 um das Kriterium, dass ein Azure-DevOps-Adaptercreate_itemmitliefert.types/project.mdundkb/gtd/COLLECTION.mdblieben unverändert- beide beschreiben nur die Seite und ihr Frontmatter, nie einen Schreibweg, also gab es dort
nichts nachzuziehen.
docs verify,instructions verify,pytestgrün; Version gebumpt (--minor, neues Kommandoplus Protokollerweiterung, beidseitig drop-in).
Scheitert die Anlage des Postens, ist keine Seite geschrieben und keine Rohdatei— zur einen Hälfte erfüllt, zur anderen bewusst abgetrennt. „Keine Seite"befördert
ist durch Bauart erfüllt (
task newrührtraw//kb/nie an) und durch die Schrittfolge imSkill gesichert (Posten in Schritt 5, Seite in Schritt 6); „keine Rohdatei befördert" ist es
nicht, weil
raw acceptweiterhin Schritt 1 des Ingest ist und damit vor derVerpflichtungserkennung läuft. Das ist der von
lint/sources coverageohnehin gemeldeteZustand „Rohdatei ohne Quellenseite", also genau der entdeckte Zwischenzustand, den D3 als
den akzeptablen benennt. Ob die Beförderung trotzdem hinter die Verpflichtungsentscheidung
rücken soll, ist eine Änderung am Anfang jedes Ingest-Laufs und damit eine eigene
Entscheidung: #136.
Was bewusst offen blieb
raw accepthinter die Verpflichtungsentscheidung rücken? Siehe das gestricheneKriterium oben.
Paket setzt sie nicht voraus.
Verifiziert
pytest: 1429 Tests grün (davon neu: 6 Adapter-Tests intest_superproductivity.py, 12Kommando-Tests in
test_task_cmd.py, der parametrisierte Skill-Regressionstest).tools/wikitool docs verify: grün, 58 dokumentierte Kommandos, keine Issue-Referenzen in 78ausgelieferten Dokumenten.
tools/wikitool instructions verify: grün, 23 Instructions und 8 Skills, 16 publizierte Kopiendeckungsgleich.
cfbe3eaauforigin/main, Stack7.0.0-beta.12; der Nachzug anREADME.md/INSTALL.mdfolgte im Abschluss-Commit derselben Arbeit.Berührungspunkte
#128 (der zweite Adapter muss
create_itemmitliefern — dort eingetragen), #133 (der Schreibwegsetzt
access: apivoraus), #135 (Voraussetzung für denfollow_up_at-Teil, eingearbeitet),#136 (die abgetrennte Reihenfolgefrage), #112 (unbeaufsichtigter Ingest), #131 (die Leserichtung).
Capture und Zielwahl: was geht nach raw/kb, was nach kb/gtd, was in den Tracker?to Ein Ingest, zwei Schichten: die Seite ablegen und die Verpflichtung im Tracker anlegenChangelog: Body und Titel vollständig neu geschrieben am Fallbeispiel des Betreibers
(Kundenreklamation per Mail → Inhalt mit Projektbezug ablegen und das Nachfassen als Verpflichtung
anlegen).
Weg über
incoming/bleibt, den es ohnehin gibt.kb/,kb/gtd/oder Tracker" und nahmdie drei Ziele als exklusiv an. Sie sind es nicht: eine Quelle erzeugt in der Regel beides.
TaskWriterkennt genaucreate_project— für einen Posten gibt es wederProtokoll noch Kommando, das ist die eigentliche Lücke. Die SP-REST-API hat Task-CRUD (nur
Projekt-CRUD fehlt), der
HumanInterventionRequired-Fall tritt hier also nicht ein.„Nachfassen" fällt exakt auf das vorhandene
WAITING/follow_up_at-Paar, womit Prüfung 2 desRückblicks die Verpflichtung ohne neuen Mechanismus wieder anfasst. Reihenfolge Tracker-vor-Seite
jetzt mit eigenem Beleg: „Posten ohne Seite" meldet
lintalsuncovered_raw_files, „Seite ohnePosten" meldet nichts.
Reihenfolge, D4 Projektzuordnung, D5 Rückverweis im Posten.
torben referenced this issue2026-09-20 14:32:30 +00:00
Changelog: Die Endpunkt-Verifikation gegen den SP-Quellcode ist gelaufen (2026-09-20) und
erledigt den letzten der vier Punkte unter „Vorher zu klären". Die drei Entscheidungsfragen D2, D4
und die Projekterkennung bleiben offen —
kind/decisionsteht unverändert.POST /tasksexistiert, dieschreibbare Feldliste steht vollständig im Body.
waiting-Tag muss vorher existieren (Tags sind über die API nichtanlegbar);
follow_up_atist erst nach #135 schreibbar; ein Posten landet nie im Backlog(
isAddToBacklogfestfalse);notesist schreibbar, D5 also umsetzbar.Verifikationsvorbehalt und ist jetzt belegt — samt der Abgrenzung, warum
create_projectExit 42braucht und dieser Weg nicht.
new projectdas Tracker-Projekt auf keiner Instanz selbst anlegen kann,ist eine Randbedingung der Entscheidung — die Variante „erst
new project" hält den Ingestimmer an.
waiting-Tag muss laut scheitern statt stumm einen Posten ohneStatus anzulegen.
follow_up_at-Teil der Umsetzung setzt #135 voraus.Changelog: Die drei offenen Punkte sind am 2026-09-20 entschieden; „Vorher zu klären" ist leer.
kind/decision→kind/build,size/L→size/M(die offenen Designfragen vor dem ersten Commitwaren das L-Kriterium, und sie sind weg — mehrere Dateien plus Contract-/Instruction-Änderung mit
eigenem Testaufwand bleiben).
Gegenposition (unbeaufsichtigter Stapellauf) ist im Body als bestehend und unadressiert notiert;
wer sie baut, stellt die Frage dort neu.
benennen,
new project, oder in den Eingang des Trackers. Der Eingang ist die ausdrücklichgewählte Notausfahrt, nie ein Default, und der Skill nennt beim Anbieten ihre Kosten. Dazu neu:
das Kommando braucht für sie eine eigene Form (
--inbox), ein weggelassenes--projectist einFehler.
searchvor und ordnet nie automatischzu, auch nicht bei einem eindeutigen Treffer. Das Suchen bleibt beim Skill; das Kommando nimmt den
Namen als Angabe.
run_reviewerreicht Posten ausschließlich überprojects()→open_items(project.name)(
tools/chemenu/review.py:145-184) — ein Posten ohne Projekt ist für Prüfung 2 unsichtbar. Dasbeschneidet D4 Weg 3 und ist der Grund, warum diese Route ihre Kosten beim Anbieten nennen muss.
GET /projects?Wenn ja, nimmt Prüfung 3 ihn aus (getestet); wenn nein, sagt der Skill beim Anbieten der Route,
dass
reviewden Posten nicht sieht. Das Ergebnis wird im Body nachgezogen statt als Annahme inden Code geschrieben.
Auskunft an derselben Stelle und fallen in der Umsetzung auf eine Frage zusammen (Titel +
vorgeschlagenes Projekt), danach ein Kommandoaufruf.
Schreibweg nennt
notesjetzt ausdrücklich.Changelog: Umgesetzt (2026-09-20). Alle Akzeptanzkriterien bis auf eines abgehakt - siehe die
Anmerkung an der einen offenen Zeile für eine Lesart, die zur Bestätigung vorgelegt wird statt
selbst entschieden zu sein.
wikitool task new,TaskWriter.create_itemim Protokoll,SuperProductivityWritersUmsetzung (
INBOX_PROJECT-Konstante, Projekt-Id- undwaiting-Tag-Auflösung vor dem einenPOST /tasks).instructions/wiki-ingest/SKILL.md) hat Schritt 5 um dieVerpflichtungs-Erkennung erweitert: ein Dialogschritt (D2/D4/D6),
task newvor Schritt 6(Quellenseite).
docs/knowledge-and-commitment.md,tools/CONTRACT.mdnachgezogen; #128 aktualisiert.test_superproductivity.py(Schreibpfad),test_task_cmd.py(CLI, inkl. Rundlauf durchreview),test_instructions_cmd.py(Provider-Regressionstest parametrisiert).docs verify/instructions verify/pytestgrün.Eine Lesart zur Bestätigung: Die Kriteriumszeile zu „keine Rohdatei befördert, wenn die
Postenanlage scheitert" ist nur teilweise erfüllt -
task newselbst rührtraw//kb/nie an,aber Schritt 1 (
raw accept) läuft weiterhin vor der Verpflichtungserkennung, nicht danach. Detailsund Begründung stehen an der Zeile selbst im Body. Wenn die Beförderung ebenfalls hinter die
Verpflichtungsentscheidung soll, ist das ein Nachzug an Schritt 1 des Ingest-Skills - noch nicht
gebaut.
Changelog: Abschluss-Rewrite. Der Body ist jetzt der Endzustand statt einer Spezifikation:
„Wo es heute abbricht" ist durch „Was es jetzt gibt" ersetzt, die Entscheidungen D1-D6 lesen sich
als entschieden, und die Verifikationsergebnisse (inkl. des Befunds zum SP-Eingang) stehen im Body
statt verteilt in den Kommentaren.
als #136 abgetrennt (
kind/decision,size/S) —task newrührtraw//kb/nie an, aberraw acceptbleibt Schritt 1 des Ingest und läuft damit vor der Verpflichtungserkennung; ob dasso bleibt, ist eine Änderung am Anfang jedes Ingest-Laufs und damit eine eigene Entscheidung.
README.mdundINSTALL.mdnannten bislang nurnew projectals Schreibwegin den Tracker - beide nennen jetzt auch
task new(Commit88e7cc1).types/project.mdundkb/gtd/COLLECTION.mdblieben bewusst unverändert.pytest(1429 grün),docs verify,instructions verify, Commitscfbe3eaund88e7cc1, Stack7.0.0-beta.12.torben referenced this issue2026-09-25 15:52:16 +00:00
torben referenced this issue2026-09-25 19:14:36 +00:00