Erledigt (2026-09-26). Alle 61 Kommando-Datensätze sind redaktionell umgebaut, in 14 Gruppen plus Abschluss, je Gruppe ein Publish und ein Version-Bump im laufenden Kandidaten (7.1.0-beta.7 bis beta.21). Nur Text, kein Verhalten – mit einer Ausnahme im Datenmodell (unten E1/E2), das die neue Form trägt. Folgebefunde: #144, #145, #146.
#121 machte einen Datensatz je wikitool-Kommando zur einzigen Quelle für wikitool <cmd> -h, den Index und die generierte tools/CONTRACT.md, und füllte ihn mechanisch: der alte Purpose-Text 1:1 in NOTES, „Exit 1 means“/„Retry policy“ 1:1 in EXIT STATUS/ON FAILURE, EXAMPLES/NEVER/SEE ALSO leer. Die Information war vollständig, aber schlecht nutzbar: NOTES mischte Verhalten, Verbote und Begründung in Absätzen bis > 4000 Zeichen, viele Texte verwiesen auf andere Kommandos („same posture as new project“), Vergangenheitsformulierungen standen neben aktuellem Verhalten, und es gab kaum kopierbare Aufrufe.
Ergebnis
Jeder Datensatz hat jetzt:
EXAMPLES – ein bis drei kopierbare Aufrufe, der häufigste zuerst; jedes Kommando mit Gate zeigt den Wiederholungsaufruf nach Exit 42 (sync, publish, upload accept, new project --resume).
NEVER – die Verbote, die vorher in Prosa standen; wo AGENTS.md eine Regel für genau dieses Kommando trägt (Invariante 1 für cite, generierte Dateien und .wikitool-kb.json, Invariante 6 für budget reset, § Routing für search/types list), steht sie zusätzlich hier.
EXIT STATUS / ON FAILURE – je Ursache eine Zeile mit eigenem Code (0/1/42) und eigener Reaktion. Ursachen, die der Code hatte und der alte Text nicht nannte, sind ergänzt (z. B. dist export fehlende Lizenz, new Capture-Feld, eval score --fail-on-error, Teilschreibfehler bei rename/rm/move/cite sync).
NOTES – Stichpunkte, Gegenwartsform, nur Verhalten.
In sich vollständig – kein „same as X“ mehr; SEE ALSO nennt verwandte Kommandos und die Instruction, die das Kommando nutzt.
Begründung raus – jede herausgelöste „why“-Aussage stand danach am Code oder in einer Doku; wo sie fehlte, ist sie jetzt ein Kommentar/Docstring an der implementierenden Stelle (dist_cmd.run_upgrade Stempel, task_cmd Moduldocstring, cite_cmd.sync_page, migrate_cmddone/verify, docs_verify.check_command_contracts). Ein veralteter Code-Kommentar (dist_cmd.build_plan zu incoming/) wurde dabei korrigiert.
Entscheidungen
E1 – NOTES als Stichpunkte.CommandRecord.notes ist ein Tupel, gerendert als - -Liste. Die Übergangsform str wurde nach der letzten Gruppe entfernt; ein str wird jetzt beim Import abgelehnt (5aae7fe).
E2 – Ein Eintrag je Ursache.Failure(cause, reaction, code=1, label="") ersetzt Failure(label, exit_1, retry). EXIT STATUS rendert <code> <cause>, ON FAILURE <cause> -> <reaction>; ohne reaction nur die EXIT-STATUS-Zeile. code ist 0, 1 oder 42; explizite 42-Einträge ersetzen die generische Gate-Zeile; 42 ohne gates wird beim Import abgelehnt (fd0f60b).
E3 – Gemeinsame Sätze stehen einmal in cli_contract.py: token_gate_reaction(flag) für die Reaktion auf Token-Gates.
E4 – Version: je Gruppe version bump --patch --impact low.
E5 – Ziele für herausgelöste Sätze: Begründung → Kommentar an der implementierenden Stelle oder bestehende docs/-/Contract-Seite; Geschichte entfällt.
E6 – Schreibregeln an einem Ort: der Docstring von CommandRecord; tools/README.md § Adding a command und README.md verweisen darauf bzw. beschreiben die Form.
E7 – Text ≠ Code wird nicht hier entschieden. Ab der Gruppe Finding and checking bleibt ein Text, der dem Code widerspricht, unverändert und steht in #146. Sechs Stellen wurden vorher (fünf entgegen dieser Regel, eine wegen eines in sich widersprüchlichen Datensatzes) direkt angeglichen; sie stehen in #146 zur Bestätigung.
Invariante
Keine Regel geht verloren. Für jede Gruppe liegt vor ihrem Publish ein Kommentar mit jedem entfernten oder umformulierten Satz und seinem Ziel (14 Gruppenkommentare, Git bis Instance health).
Stand je Gruppe
Gruppe
Commit
Version
Git (mit Modelländerung E1/E2)
fd0f60b
beta.7
Catalog and log
df8ff2f
beta.8
Distribution and versioning
9d6ca6b
beta.9
Pages
d0a740a
beta.10
Links and citations
a1f3c47
beta.11
Finding and checking
0b2d93a
beta.12
Provenance
be78ad2
beta.13
Raw material and uploads
964978a
beta.14
Workshop runs and session budget
b9c22f7
beta.15
Types, instructions and docs
9617d72
beta.16
Telemetry
71efdbe
beta.17
Content migrations
243db66
beta.18
Private instances
b83a398
beta.19
Instance health
5bfbb49
beta.20
Abschluss: str-Form entfernt, Tests über das echte Register
entfallen (Geschichte, steht im Moduldocstring von xref.py)
raw accept
„raw/ no longer addresses by type“
Gegenwartsform
publish
„a previous publish whose push failed no longer strands it“
Gegenwartsform
publish
„--yes/-y are gone …“
Regel bleibt als Exit-1-Ursache, Gegenwartsform
dist export
„a fresh export no longer creates any type subdirectories“
Gegenwartsform
work close, instructions sync, dist upgrade, version bump, version regrade, version release, doctor
„no longer needed“, „whose source is gone“ u. a.
Gegenwartsaussagen, belassen (version regrade/doctor nach dem Umbau ohne Treffer)
upstream merge
„refused to“
Falschtreffer
Akzeptanzkriterien
Jeder Datensatz hat mindestens ein Beispiel; jedes Kommando mit Exit 42 zeigt den Wiederholungsaufruf. Geprüft über alle 61 Datensätze und seitdem als Test gehalten (test_cli.py: test_every_record_shows_at_least_one_example, test_every_gated_record_shows_its_re_run_after_exit_42).
Kein Datensatz verweist für eine Verhaltensaussage auf ein anderes Kommando. grep über die generierte Region von tools/CONTRACT.md nach „same as“, „same posture“, „like “, „same reasoning“, „see its“: keine Treffer; „the same way“ nur noch als Selbstbezug (new, upstream verify`).
Die Vergangenheitsformulierungen der Fundliste sind entfernt oder als Gegenwartsaussage belassen (Tabelle oben; Nachlauf-grep ohne weitere Fundstelle).
Für jede Gruppe lag vor ihrem Publish die Satzliste im Issue (14 Kommentare).
docs verify, instructions verify und die volle pytest-Suite waren nach jeder Gruppe grün (zuletzt 1522 Tests). CI grün für jeden Commit von fd0f60b bis 5fe6003 (je Stack-Commit zwei Push-Läufe, zuletzt Läufe 400/401 für 5aae7fe und 402 für den README-Nachzug).
Außerhalb (als eigene Issues)
#144 – network: bei sync/publish/upstream * und die Zählung in version check.
#146 – Sammelbefund Text ≠ Code (offen: lint-Zitatlimit; sechs direkt angeglichene Stellen zur Bestätigung).
#143 – Abhilfe in der Fehlerausgabe selbst (unverändert offen).
Beobachtet, nicht erfasst: die Budget-Gate-Verweigerung gibt nach der ERROR-Zeile einen Python-Traceback aus.
Ablauf
Die Sitzung lief ab Gruppe 11 mit einer eigenen WIKITOOL_SESSION_ID je Gruppe (instructions/session-setup.md § Multi-unit runs); die ersten zehn Gruppen teilten sich einen Zähler und liefen beim Publish der zehnten in das Iteration Budget Gate. Weiter ging es nach Freigabe durch den Betreiber. Alle drei Phasen – Entwurf/Datenmodell, der mechanische Umbau je Gruppe und der Abschluss – liefen auf Claude Opus 5.5.
**Erledigt (2026-09-26).** Alle 61 Kommando-Datensätze sind redaktionell umgebaut, in 14 Gruppen plus Abschluss, je Gruppe ein Publish und ein Version-Bump im laufenden Kandidaten (7.1.0-beta.7 bis beta.21). Nur Text, kein Verhalten – mit einer Ausnahme im Datenmodell (unten E1/E2), das die neue Form trägt. Folgebefunde: #144, #145, #146.
## Ausgangslage (nach #121)
#121 machte einen Datensatz je `wikitool`-Kommando zur einzigen Quelle für `wikitool <cmd> -h`, den Index und die generierte `tools/CONTRACT.md`, und füllte ihn mechanisch: der alte Purpose-Text 1:1 in NOTES, „Exit 1 means“/„Retry policy“ 1:1 in EXIT STATUS/ON FAILURE, EXAMPLES/NEVER/SEE ALSO leer. Die Information war vollständig, aber schlecht nutzbar: NOTES mischte Verhalten, Verbote und Begründung in Absätzen bis > 4000 Zeichen, viele Texte verwiesen auf andere Kommandos („same posture as `new project`“), Vergangenheitsformulierungen standen neben aktuellem Verhalten, und es gab kaum kopierbare Aufrufe.
## Ergebnis
Jeder Datensatz hat jetzt:
1. **EXAMPLES** – ein bis drei kopierbare Aufrufe, der häufigste zuerst; jedes Kommando mit Gate zeigt den Wiederholungsaufruf nach Exit 42 (`sync`, `publish`, `upload accept`, `new project --resume`).
2. **NEVER** – die Verbote, die vorher in Prosa standen; wo AGENTS.md eine Regel für genau dieses Kommando trägt (Invariante 1 für `cite`, generierte Dateien und `.wikitool-kb.json`, Invariante 6 für `budget reset`, § Routing für `search`/`types list`), steht sie zusätzlich hier.
3. **EXIT STATUS / ON FAILURE** – je Ursache eine Zeile mit eigenem Code (0/1/42) und eigener Reaktion. Ursachen, die der Code hatte und der alte Text nicht nannte, sind ergänzt (z. B. `dist export` fehlende Lizenz, `new` Capture-Feld, `eval score --fail-on-error`, Teilschreibfehler bei `rename`/`rm`/`move`/`cite sync`).
4. **NOTES** – Stichpunkte, Gegenwartsform, nur Verhalten.
5. **In sich vollständig** – kein „same as `X`“ mehr; SEE ALSO nennt verwandte Kommandos und die Instruction, die das Kommando nutzt.
6. **Begründung raus** – jede herausgelöste „why“-Aussage stand danach am Code oder in einer Doku; wo sie fehlte, ist sie jetzt ein Kommentar/Docstring an der implementierenden Stelle (`dist_cmd.run_upgrade` Stempel, `task_cmd` Moduldocstring, `cite_cmd.sync_page`, `migrate_cmd` `done`/`verify`, `docs_verify.check_command_contracts`). Ein veralteter Code-Kommentar (`dist_cmd.build_plan` zu `incoming/`) wurde dabei korrigiert.
## Entscheidungen
- **E1 – NOTES als Stichpunkte.** `CommandRecord.notes` ist ein Tupel, gerendert als `- `-Liste. Die Übergangsform `str` wurde nach der letzten Gruppe entfernt; ein `str` wird jetzt beim Import abgelehnt (`5aae7fe`).
- **E2 – Ein Eintrag je Ursache.** `Failure(cause, reaction, code=1, label="")` ersetzt `Failure(label, exit_1, retry)`. EXIT STATUS rendert `<code> <cause>`, ON FAILURE `<cause> -> <reaction>`; ohne `reaction` nur die EXIT-STATUS-Zeile. `code` ist 0, 1 oder 42; explizite 42-Einträge ersetzen die generische Gate-Zeile; 42 ohne `gates` wird beim Import abgelehnt (`fd0f60b`).
- **E3 – Gemeinsame Sätze** stehen einmal in `cli_contract.py`: `token_gate_reaction(flag)` für die Reaktion auf Token-Gates.
- **E4 – Version:** je Gruppe `version bump --patch --impact low`.
- **E5 – Ziele für herausgelöste Sätze:** Begründung → Kommentar an der implementierenden Stelle oder bestehende `docs/`-/Contract-Seite; Geschichte entfällt.
- **E6 – Schreibregeln an einem Ort:** der Docstring von `CommandRecord`; `tools/README.md` § Adding a command und `README.md` verweisen darauf bzw. beschreiben die Form.
- **E7 – Text ≠ Code wird nicht hier entschieden.** Ab der Gruppe Finding and checking bleibt ein Text, der dem Code widerspricht, unverändert und steht in #146. Sechs Stellen wurden vorher (fünf entgegen dieser Regel, eine wegen eines in sich widersprüchlichen Datensatzes) direkt angeglichen; sie stehen in #146 zur Bestätigung.
## Invariante
**Keine Regel geht verloren.** Für jede Gruppe liegt vor ihrem Publish ein Kommentar mit jedem entfernten oder umformulierten Satz und seinem Ziel (14 Gruppenkommentare, Git bis Instance health).
## Stand je Gruppe
| Gruppe | Commit | Version |
|---|---|---|
| Git (mit Modelländerung E1/E2) | `fd0f60b` | beta.7 |
| Catalog and log | `df8ff2f` | beta.8 |
| Distribution and versioning | `9d6ca6b` | beta.9 |
| Pages | `d0a740a` | beta.10 |
| Links and citations | `a1f3c47` | beta.11 |
| Finding and checking | `0b2d93a` | beta.12 |
| Provenance | `be78ad2` | beta.13 |
| Raw material and uploads | `964978a` | beta.14 |
| Workshop runs and session budget | `b9c22f7` | beta.15 |
| Types, instructions and docs | `9617d72` | beta.16 |
| Telemetry | `71efdbe` | beta.17 |
| Content migrations | `243db66` | beta.18 |
| Private instances | `b83a398` | beta.19 |
| Instance health | `5bfbb49` | beta.20 |
| Abschluss: `str`-Form entfernt, Tests über das echte Register | `5aae7fe` | beta.21 |
| README-Nachzug | `5fe6003` | – (Prosa) |
## Vergangenheitsformulierungen (Fundliste, `grep` nach „is gone“, „are gone“, „used to“, „previously“, „Before“, „no longer“)
| Kommando | Fundstelle | Ergebnis |
|---|---|---|
| `xref link-source` | „the See Also bullet this used to add …“ | entfallen (Geschichte, steht im Moduldocstring von `xref.py`) |
| `raw accept` | „`raw/` no longer addresses by type“ | Gegenwartsform |
| `publish` | „a previous `publish` whose push failed no longer strands it“ | Gegenwartsform |
| `publish` | „`--yes`/`-y` are gone …“ | Regel bleibt als Exit-1-Ursache, Gegenwartsform |
| `dist export` | „a fresh export no longer creates any type subdirectories“ | Gegenwartsform |
| `work close`, `instructions sync`, `dist upgrade`, `version bump`, `version regrade`, `version release`, `doctor` | „no longer needed“, „whose source is gone“ u. a. | Gegenwartsaussagen, belassen (`version regrade`/`doctor` nach dem Umbau ohne Treffer) |
| `upstream merge` | „ref**used to**“ | Falschtreffer |
## Akzeptanzkriterien
- [x] Jeder Datensatz hat mindestens ein Beispiel; jedes Kommando mit Exit 42 zeigt den Wiederholungsaufruf. Geprüft über alle 61 Datensätze und seitdem als Test gehalten (`test_cli.py`: `test_every_record_shows_at_least_one_example`, `test_every_gated_record_shows_its_re_run_after_exit_42`).
- [x] Kein Datensatz verweist für eine Verhaltensaussage auf ein anderes Kommando. `grep` über die generierte Region von `tools/CONTRACT.md` nach „same as“, „same posture“, „like `“, „same reasoning“, „see its“: keine Treffer; „the same way“ nur noch als Selbstbezug (`new`, `upstream verify`).
- [x] Die Vergangenheitsformulierungen der Fundliste sind entfernt oder als Gegenwartsaussage belassen (Tabelle oben; Nachlauf-`grep` ohne weitere Fundstelle).
- [x] Für jede Gruppe lag vor ihrem Publish die Satzliste im Issue (14 Kommentare).
- [x] `docs verify`, `instructions verify` und die volle `pytest`-Suite waren nach jeder Gruppe grün (zuletzt 1522 Tests). CI grün für jeden Commit von `fd0f60b` bis `5fe6003` (je Stack-Commit zwei Push-Läufe, zuletzt Läufe 400/401 für `5aae7fe` und 402 für den README-Nachzug).
## Außerhalb (als eigene Issues)
- #144 – `network:` bei `sync`/`publish`/`upstream *` und die Zählung in `version check`.
- #145 – `log append --body-file` mit fehlender Datei: Traceback statt `ERROR`.
- #146 – Sammelbefund Text ≠ Code (offen: `lint`-Zitatlimit; sechs direkt angeglichene Stellen zur Bestätigung).
- #143 – Abhilfe in der Fehlerausgabe selbst (unverändert offen).
- Beobachtet, nicht erfasst: die Budget-Gate-Verweigerung gibt nach der `ERROR`-Zeile einen Python-Traceback aus.
## Ablauf
Die Sitzung lief ab Gruppe 11 mit einer eigenen `WIKITOOL_SESSION_ID` je Gruppe (`instructions/session-setup.md` § Multi-unit runs); die ersten zehn Gruppen teilten sich einen Zähler und liefen beim Publish der zehnten in das Iteration Budget Gate. Weiter ging es nach Freigabe durch den Betreiber. Alle drei Phasen – Entwurf/Datenmodell, der mechanische Umbau je Gruppe und der Abschluss – liefen auf Claude Opus 5.5.
Changelog:status/blocked entfernt – #121 ist seit 2026-09-26 geschlossen. Body um Stand, Entscheidungen E1–E5 (Datenmodell für NOTES und Exit-Ursachen, Konstanten, Version, Ziele), eine Gruppen-Fortschrittstabelle und die Fundliste der Vergangenheitsformulierungen ergänzt. Abweichung Text ↔ Code als #144 ausgelagert.
**Changelog:** `status/blocked` entfernt – #121 ist seit 2026-09-26 geschlossen. Body um Stand, Entscheidungen E1–E5 (Datenmodell für NOTES und Exit-Ursachen, Konstanten, Version, Ziele), eine Gruppen-Fortschrittstabelle und die Fundliste der Vergangenheitsformulierungen ergänzt. Abweichung Text ↔ Code als #144 ausgelagert.
Gruppe Git (sync, publish) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
Mit dabei: Modelländerung E1/E2 (notes als Tupel, Failure(cause, reaction, code, label)). Die Feldumbenennung ist mechanisch über alle Datensätze; bei noch nicht umgebauten Kommandos lautet ON FAILURE jetzt <alter Exit-1-Text> -> <alter Retry-Text>, Wortlaut unverändert.
sync
Alter Satz (gekürzt)
Ziel
„Fetch … fast-forward … rebase … exit 42 for review when they touch the same file“
NOTES Bullet 1 (Regel unverändert), Exit 42 zusätzlich als eigene EXIT-STATUS-Zeile
„(a content conflict is then impossible by construction)“
Begründung → steht bereits im Code: touched_files()- und reconcile()-Docstring
„(the rebase-review gate - see publish below)“
Querverweis entfällt; SEE ALSO wikitool publish
„Never commits, never pushes, never force-anything“
NOTES „Makes no commit, no push, and no forced operation of any kind“
„no remote configured, or one that cannot be reached, is reported and skipped, not a failure“ (NOTES und ON FAILURE)
EXIT STATUS 0-Zeile
„Meant to run once at the start of a writing session (instructions/session-setup.md)“
NOTES „Run it once at the start of a writing session“ + SEE ALSO instructions/session-setup.md
„so the rest of it works against a current tree instead of discovering the drift at the final publish“
Begründung → steht bereits im sync_command-Docstring
Exit 1: „The automatic rebase hit a real conflict (git failed)“
EXIT STATUS 1, ergänzt um „aborted cleanly“ (steht schon in atomic)
„do not retry, do not force - resolve manually and re-run“
ON FAILURE (Konflikt) + NEVER „Never retry a conflict unchanged, and never force past it“
„Exit 42, not 1, when the rebase-review gate needs clearance: show … verbatim … and stop; re-running with --confirm-rebase <token> clears it, and a wrong, invented, or superseded token exits 42 again“
EXIT STATUS 42 + ON FAILURE über token_gate_reaction("--confirm-rebase") (Wortlaut: zeigen, stoppen, nach Freigabe Wiederholungszeile, falsches/erfundenes/veraltetes Token → erneut 42) + NEVER „Never pass a --confirm-rebase token the user has not seen and approved“
„Refuses before staging anything when the push target is not the checked-out branch“
NOTES Bullet 3 + EXIT STATUS 1 (eigene Ursache)
„so a git push <branch> cannot quietly publish a ref other than the commit just made“
Begründung → steht bereits im branch_mismatch_message()-Docstring
„the unborn branch … counts as checked out, which is what lets the first publish of a new instance work (instructions/setup-instance.md step 14), while a genuine detached HEAD is still refused“
NOTES Bullet 3; Schrittnummer entfällt, SEE ALSO instructions/setup-instance.md
„… that commit is pushed anyway - a previous publish whose push failed no longer strands it, and neither does a branch the remote has never seen“
„A remote that cannot be reached at all is deliberately not read that way: … ‚Nothing to commit‘ … rather than attempting a push“
NOTES Bullet 5
„so an offline or local-only instance is unaffected“
Begründung → steht bereits im Kommentar in _local_ahead_of_remote()
„If the push is rejected despite the pre-check (a genuine race …), one more reconcile-and-retry …; never more than one“
NOTES Bullet 6; die Race-Erklärung steht bereits als Kommentar am Retry in publish_command
„Mass-Update Gate: when >= --threshold (default 10) counted files … exits 42 (EXIT_NEEDS_CLEARANCE) … – a third outcome distinct from success (0) and a validation error (1)“
EXIT STATUS 42 (eigene Ursache) + NOTES Bullet 7; Konstantenname und „third outcome“-Erklärung → stehen bereits im Moduldocstring von git_publish.py
Beschreibung des Prüfberichts (Skala, Aufmerksamkeitsnotizen, Pfade nach Bereich)
NOTES Bullet 7, unverändert
„The token digests each counted path and its contents plus the publish target, so a clearance carries neither to a different file list nor to edited contents“
NOTES Bullet 9
„a wrong, invented or superseded token exits 42 again with the current state“
ON FAILURE über token_gate_reaction("--confirm")
„Two kinds of path are committed but never counted … work/ … generated files … The refusal line accounts for both, by reason.“
NOTES Bullet 8
„each is recomputable from the tree, so approving it decides nothing, and a routine ingest rebuilds five or six of them“
Begründung → steht bereits im Kommentar über GENERATED_PATHS/GATE_EXEMPT_PREFIXES
„The gate is evaluated before anything is staged, so a refused publish leaves the working tree untouched“
NOTES Bullet 7
„Publish-Remote Gate: … exits 42 before the reconcile step even fetches – URL read from git remote get-url --push, so a repointed remote does not pass on its name“
EXIT STATUS 42 (eigene Ursache, ergänzt um „resolves to no push URL“ aus publish_remote_refusal()) + NOTES Bullet 10
„Unlike the other two gates it has no token and no flag: the way past it is the user adding the URL to that file“
ON FAILURE (Publish-Remote)
„an agent editing it to get past a refusal is opening a gate on its own initiative“
NEVER
„Absent file means unrestricted; a malformed one is an error, not permission“
NOTES Bullet 10 + EXIT STATUS 1 (eigene Ursache „unreadable or no usable allowed_push_urls“)
„See instructions/gates.md“
SEE ALSO
„--yes/-yare gone and now fail with an explicit error“
EXIT STATUS 1 „--yes/-y was passed – the flag does not exist …“, Gegenwartsform (Fundliste erledigt)
„--path (repeatable) scopes the whole operation …“
NOTES Bullet 11
Stack-machinery note (Pfade, Erinnerungszeile, „Not a gate …“)
NOTES Bullet 12
„roughly the scope a stack version bump covers, deliberately a shade broader than CI's version gate …“
Begründung → steht bereits im touches_stack_machinery()-Docstring
Exit 1 „git failed, the push target is not …, or --yes/-y was passed“
aufgeteilt in drei 1-Zeilen (git, Branch, --yes)
„Exit 42, not 1, when the Mass-Update Gate, the rebase-review gate (raised by the same reconcile sync performs), or the Publish-Remote Gate refuses“
drei 42-Zeilen; „same reconcile sync performs“ ersetzt durch die Beschreibung der Ursache selbst
„For git failures: do not retry, do not force - report and ask the user (the reconcile step already retried the push once …)“
ON FAILURE (git) unverändert im Regelgehalt + NEVER
„For exit 42: show … verbatim and stop; it names … the --confirm <token> or --confirm-rebase <token> line to re-run, and re-running without it exits 42 again“
ON FAILURE je Token-Gate über token_gate_reaction() + NEVER (kein ungesehenes Token)
„The Publish-Remote Gate is the exception with no such line: it names the push URL … and only the user resolves it“
ON FAILURE (Publish-Remote)
PROPERTIES atomic: „both gates run before staging“
„every gate runs before staging“ – publish hat drei Gates, alle laufen vor dem Staging (Textkorrektur, kein Verhalten)
– (neu, aus der Fehlermeldung)
ON FAILURE (Branch): „Check out the branch … or pass --branch <checked-out branch>, then retry once“ – deckt sich mit branch_mismatch_message()
Neu: EXAMPLES (Normalfall, Wiederholung nach Mass-Update-42, Wiederholung nach Rebase-Review-42) für publish, zwei für sync.
**Gruppe Git (`sync`, `publish`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
Mit dabei: Modelländerung E1/E2 (`notes` als Tupel, `Failure(cause, reaction, code, label)`). Die Feldumbenennung ist mechanisch über alle Datensätze; bei noch nicht umgebauten Kommandos lautet ON FAILURE jetzt `<alter Exit-1-Text> -> <alter Retry-Text>`, Wortlaut unverändert.
### `sync`
| Alter Satz (gekürzt) | Ziel |
|---|---|
| „Fetch … fast-forward … rebase … exit 42 for review when they touch the same file“ | NOTES Bullet 1 (Regel unverändert), Exit 42 zusätzlich als eigene EXIT-STATUS-Zeile |
| „(a content conflict is then impossible by construction)“ | Begründung → steht bereits im Code: `touched_files()`- und `reconcile()`-Docstring |
| „(the rebase-review gate - see `publish` below)“ | Querverweis entfällt; SEE ALSO `wikitool publish` |
| „Never commits, never pushes, never force-anything“ | NOTES „Makes no commit, no push, and no forced operation of any kind“ |
| „no remote configured, or one that cannot be reached, is reported and skipped, not a failure“ (NOTES und ON FAILURE) | EXIT STATUS `0`-Zeile |
| „Meant to run once at the start of a writing session (`instructions/session-setup.md`)“ | NOTES „Run it once at the start of a writing session“ + SEE ALSO `instructions/session-setup.md` |
| „so the rest of it works against a current tree instead of discovering the drift at the final `publish`“ | Begründung → steht bereits im `sync_command`-Docstring |
| Exit 1: „The automatic rebase hit a real conflict (git failed)“ | EXIT STATUS `1`, ergänzt um „aborted cleanly“ (steht schon in `atomic`) |
| „do not retry, do not force - resolve manually and re-run“ | ON FAILURE (Konflikt) + NEVER „Never retry a conflict unchanged, and never force past it“ |
| „Exit 42, not 1, when the rebase-review gate needs clearance: show … verbatim … and stop; re-running with `--confirm-rebase <token>` clears it, and a wrong, invented, or superseded token exits 42 again“ | EXIT STATUS `42` + ON FAILURE über `token_gate_reaction("--confirm-rebase")` (Wortlaut: zeigen, stoppen, nach Freigabe Wiederholungszeile, falsches/erfundenes/veraltetes Token → erneut 42) + NEVER „Never pass a `--confirm-rebase` token the user has not seen and approved“ |
| – (neu, aus dem Code) | NOTES: abgelehnter Aufruf macht keinen Rebase-Versuch; Token deckt Upstream-Stand und Überschneidung (aus `reconcile()`/`rebase_review_token()`) |
### `publish`
| Alter Satz (gekürzt) | Ziel |
|---|---|
| „Reconcile … exactly like `sync` (skipped for `--no-push`), then stage all changes, commit, and push“ | NOTES Bullet 1 (Reihenfolge, `--no-push`) + Bullet 2 (Reconcile ausgeschrieben statt „like `sync`“) |
| „Refuses before staging anything when the push target is not the checked-out branch“ | NOTES Bullet 3 + EXIT STATUS `1` (eigene Ursache) |
| „so a `git push <branch>` cannot quietly publish a ref other than the commit just made“ | Begründung → steht bereits im `branch_mismatch_message()`-Docstring |
| „the unborn branch … counts as checked out, which is what lets the first publish of a new instance work (`instructions/setup-instance.md` step 14), while a genuine detached HEAD is still refused“ | NOTES Bullet 3; Schrittnummer entfällt, SEE ALSO `instructions/setup-instance.md` |
| „… that commit is pushed anyway - a previous `publish` whose push failed **no longer** strands it, and neither does a branch the remote has never seen“ | NOTES Bullet 4, Gegenwartsform (Fundliste erledigt) |
| „A remote that cannot be reached at all is deliberately not read that way: … ‚Nothing to commit‘ … rather than attempting a push“ | NOTES Bullet 5 |
| „so an offline or local-only instance is unaffected“ | Begründung → steht bereits im Kommentar in `_local_ahead_of_remote()` |
| „If the push is rejected despite the pre-check (a genuine race …), one more reconcile-and-retry …; never more than one“ | NOTES Bullet 6; die Race-Erklärung steht bereits als Kommentar am Retry in `publish_command` |
| „Mass-Update Gate: when >= `--threshold` (default 10) counted files … exits 42 (`EXIT_NEEDS_CLEARANCE`) … – a third outcome distinct from success (0) and a validation error (1)“ | EXIT STATUS `42` (eigene Ursache) + NOTES Bullet 7; Konstantenname und „third outcome“-Erklärung → stehen bereits im Moduldocstring von `git_publish.py` |
| Beschreibung des Prüfberichts (Skala, Aufmerksamkeitsnotizen, Pfade nach Bereich) | NOTES Bullet 7, unverändert |
| „The token digests each counted path and its contents plus the publish target, so a clearance carries neither to a different file list nor to edited contents“ | NOTES Bullet 9 |
| „a wrong, invented or superseded token exits 42 again with the current state“ | ON FAILURE über `token_gate_reaction("--confirm")` |
| „Two kinds of path are committed but never counted … `work/` … generated files … The refusal line accounts for both, by reason.“ | NOTES Bullet 8 |
| „each is recomputable from the tree, so approving it decides nothing, and a routine ingest rebuilds five or six of them“ | Begründung → steht bereits im Kommentar über `GENERATED_PATHS`/`GATE_EXEMPT_PREFIXES` |
| „The gate is evaluated before anything is staged, so a refused publish leaves the working tree untouched“ | NOTES Bullet 7 |
| „Publish-Remote Gate: … exits 42 before the reconcile step even fetches – URL read from `git remote get-url --push`, so a repointed remote does not pass on its name“ | EXIT STATUS `42` (eigene Ursache, ergänzt um „resolves to no push URL“ aus `publish_remote_refusal()`) + NOTES Bullet 10 |
| „Unlike the other two gates it has no token and no flag: the way past it is the user adding the URL to that file“ | ON FAILURE (Publish-Remote) |
| „an agent editing it to get past a refusal is opening a gate on its own initiative“ | NEVER |
| „Absent file means unrestricted; a malformed one is an error, not permission“ | NOTES Bullet 10 + EXIT STATUS `1` (eigene Ursache „unreadable or no usable `allowed_push_urls`“) |
| „See `instructions/gates.md`“ | SEE ALSO |
| „`--yes`/`-y` **are gone** and now fail with an explicit error“ | EXIT STATUS `1` „`--yes`/`-y` was passed – the flag does not exist …“, Gegenwartsform (Fundliste erledigt) |
| „`--path` (repeatable) scopes the whole operation …“ | NOTES Bullet 11 |
| Stack-machinery note (Pfade, Erinnerungszeile, „Not a gate …“) | NOTES Bullet 12 |
| „roughly the scope a stack version bump covers, deliberately a shade broader than CI's version gate …“ | Begründung → steht bereits im `touches_stack_machinery()`-Docstring |
| Exit 1 „git failed, the push target is not …, or `--yes`/`-y` was passed“ | aufgeteilt in drei `1`-Zeilen (git, Branch, `--yes`) |
| „Exit 42, not 1, when the Mass-Update Gate, the rebase-review gate (raised by the same reconcile `sync` performs), or the Publish-Remote Gate refuses“ | drei `42`-Zeilen; „same reconcile `sync` performs“ ersetzt durch die Beschreibung der Ursache selbst |
| „For git failures: do not retry, do not force - report and ask the user (the reconcile step already retried the push once …)“ | ON FAILURE (git) unverändert im Regelgehalt + NEVER |
| „For exit 42: show … verbatim and stop; it names … the `--confirm <token>` or `--confirm-rebase <token>` line to re-run, and re-running without it exits 42 again“ | ON FAILURE je Token-Gate über `token_gate_reaction()` + NEVER (kein ungesehenes Token) |
| „The Publish-Remote Gate is the exception with no such line: it names the push URL … and only the user resolves it“ | ON FAILURE (Publish-Remote) |
| PROPERTIES `atomic`: „both gates run before staging“ | „every gate runs before staging“ – `publish` hat drei Gates, alle laufen vor dem Staging (Textkorrektur, kein Verhalten) |
| – (neu, aus der Fehlermeldung) | ON FAILURE (Branch): „Check out the branch … or pass `--branch <checked-out branch>`, then retry once“ – deckt sich mit `branch_mismatch_message()` |
Neu: EXAMPLES (Normalfall, Wiederholung nach Mass-Update-42, Wiederholung nach Rebase-Review-42) für `publish`, zwei für `sync`.
„Stale shards from removed collections/areas are deleted in the same pass“
NOTES Bullet 3
Exit 1 „Rare I/O error only“
EXIT STATUS 1 „An I/O error while writing or removing a catalog file (rare)“
„Safe to retry freely - the plan is always recomputed from the pages currently on disk, so a re-run converges“
ON FAILURE, wörtlich
– (neu, aus dem Code)
NOTES: Warnung bei verschachtelten Seiten (find_nested_pages), Verhalten von --dry-run
– (neu, aus der generierten Kopfzeile „Do not hand-edit“)
NEVER
log append
Alter Satz
Ziel
NOTES „Append a formatted entry to kb/log.md.“
NOTES Bullet 1, um das Format des Eintrags ergänzt (aus format_log_entry)
Exit 1 „Invalid --op or unreadable --body-file“
zwei 1-Zeilen
„Not idempotent.“
NOTES Bullet 2
„If the previous run's outcome is uncertain, check the tail of kb/log.md before retrying“
NEVER, Regelgehalt unverändert
– (neu)
ON FAILURE je Ursache „Nothing was written – fix … and retry once“ (beide Prüfungen laufen vor dem Schreiben)
Abweichung gefunden: eine unlesbare --body-file endet in einem Traceback, nicht in einer ERROR-Zeile → #145. Der Datensatz beschreibt weiter das zugesagte Verhalten; #145 hält Code und Text zusammen.
log status
Alter Satz
Ziel
„The deterministic trigger behind the Maintenance Schedule's ‚every 10 sources‘ full-lint cadence.“
NOTES Bullet 2 (Verhalten: ab 10 nennt die Ausgabe wiki-lint als nächsten Schritt) + SEE ALSO tools/CONTRACT.md § Maintenance schedule
„Never fails (reports 0 if kb/log.md is missing or empty).“
EXIT STATUS 0-Zeile; „reports 0“ an den Code angepasst: eine fehlende Datei meldet „nothing logged“
„Safe to retry freely.“
NOTES Bullet 3
– (neu, aus dem Code)
NOTES Bullet 1: Zählweise (seit letztem lint, sonst seit Beginn) und Gesamtzahl
**Gruppe Catalog and log (`index rebuild`, `log append`, `log status`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
### `index rebuild`
| Alter Satz | Ziel |
|---|---|
| „`kb/index.md` becomes a map (statistics, one row per collection and per area, links to the shards)“ | NOTES Bullet 1 |
| „the page tables are written to a generated `INDEX.md` in each collection. An area past 50 rows gets its own shard.“ | NOTES Bullet 2 („more than 50 rows“ – `catalog.py`: `count > SHARD_THRESHOLD`, 50) |
| „Stale shards from removed collections/areas are deleted in the same pass“ | NOTES Bullet 3 |
| Exit 1 „Rare I/O error only“ | EXIT STATUS `1` „An I/O error while writing or removing a catalog file (rare)“ |
| „Safe to retry freely - the plan is always recomputed from the pages currently on disk, so a re-run converges“ | ON FAILURE, wörtlich |
| – (neu, aus dem Code) | NOTES: Warnung bei verschachtelten Seiten (`find_nested_pages`), Verhalten von `--dry-run` |
| – (neu, aus der generierten Kopfzeile „Do not hand-edit“) | NEVER |
### `log append`
| Alter Satz | Ziel |
|---|---|
| NOTES „Append a formatted entry to `kb/log.md`.“ | NOTES Bullet 1, um das Format des Eintrags ergänzt (aus `format_log_entry`) |
| Exit 1 „Invalid `--op` or unreadable `--body-file`“ | zwei `1`-Zeilen |
| „**Not idempotent.**“ | NOTES Bullet 2 |
| „If the previous run's outcome is uncertain, check the tail of `kb/log.md` before retrying“ | NEVER, Regelgehalt unverändert |
| – (neu) | ON FAILURE je Ursache „Nothing was written – fix … and retry once“ (beide Prüfungen laufen vor dem Schreiben) |
Abweichung gefunden: eine unlesbare `--body-file` endet in einem Traceback, nicht in einer `ERROR`-Zeile → #145. Der Datensatz beschreibt weiter das zugesagte Verhalten; #145 hält Code und Text zusammen.
### `log status`
| Alter Satz | Ziel |
|---|---|
| „The deterministic trigger behind the Maintenance Schedule's ‚every 10 sources‘ full-lint cadence.“ | NOTES Bullet 2 (Verhalten: ab 10 nennt die Ausgabe `wiki-lint` als nächsten Schritt) + SEE ALSO `tools/CONTRACT.md` § Maintenance schedule |
| „Never fails (reports 0 if `kb/log.md` is missing or empty).“ | EXIT STATUS `0`-Zeile; „reports 0“ an den Code angepasst: eine fehlende Datei meldet „nothing logged“ |
| „Safe to retry freely.“ | NOTES Bullet 3 |
| – (neu, aus dem Code) | NOTES Bullet 1: Zählweise (seit letztem `lint`, sonst seit Beginn) und Gesamtzahl |
„(both roots are flat now that a file's location under raw/ is a date shard rather than a hand-picked type, so a fresh export no longer creates any type subdirectories under either root …)“
Verhalten → NOTES 3 in Gegenwart („no subdirectories“, Fundliste erledigt); Begründung (Datums-Shard) → Kommentar über plan["raw/.gitkeep"] in build_plan
„incoming/.gitkeep is trackable and survives becoming a git repository, so a plain clone gets the directory without any bootstrap step“
NOTES 3, wörtlich. Dabei gefunden: der Code-Kommentar an derselben Stelle behauptete das Gegenteil („.gitignore excludes incoming/ … bootstrap.md re-creates it“) und war seit /incoming/* + !/incoming/.gitkeep veraltet – korrigiert (nur Kommentar)
„all of them bind their instance and none are the stack's to decide“
NOTES 4 „bind their instance“; „none are the stack's to decide“ ist Begründung → steht in docs/ownership-and-templates.md
„See instructions/setup-instance.md.“
SEE ALSO
Exit 1 „Target exists and is not empty, is not a directory, or the tree has no readable VERSION“
zwei 1-Zeilen
„Point <target> at an empty (or new) directory and retry. Never merge into a non-empty one by hand“
ON FAILURE + NEVER
– (neu, aus dem Code)
1: fehlende Lizenzdatei (REQUIRED_ROOT_FILES), Leak im Plan (find_leaks, Reaktion aus der Fehlermeldung); NOTES: --dry-run
dist upgrade
Alter Satz
Ziel
Quelle, .sha256, eine Top-Level-Verzeichnis
NOTES 1
Write-Set, Klassifikation
NOTES 2, 3 (Modulnamen chemenu.ownership.is_export_stub/is_upgrade_preserved entfallen – Implementierungsdetail, steht am Code)
„its text names the three answers with the command line already filled in, so that no reader takes any of them for the default“
NOTES 4 + NEVER „Never treat any of the three answers … as the default“; Begründung steht bereits im _refusal_for_blocked()-Docstring
--keep-local/--take-release, „decided per path and compose“
NOTES 5–7
„A --take-release path that this run does not report as locally changed is refused … it is a mistake in the argument rather than a state of the tree, and a path that silently did nothing would report a successful upgrade …“
Verweigerung → EXIT STATUS 1 + ON FAILURE; Begründung steht bereits im _resolve_take_release()-Docstring und am --dry-run-Kommentar
„After a --keep-local run the new stamp is still written whole … the stamp is the baseline for the next comparison, not a literal inventory … That is what keeps a skipped file diverging …“
Verhalten → NOTES 5/6; Begründung → neuer Kommentar an shutil.copy2(stamp_path, …) in run_upgrade
--prune
NOTES 8
Migrationskette „(chemenu.kb_state.chain over the new tree's instructions/migrations/, read via a directory argument to load_migrations)“
NOTES 9; Implementierungsdetail entfällt (steht am Code)
„Refuses before touching the source at all when: …“ / „Refuses after reading the source when: …“
je Ursache eine 1-Zeile; die Reihenfolge als NOTES 12
„its version is older than or equal to the installed one (equal is a no-op success)“ + Exit-1-Text „older than, equal to, or … a pre-release“
Der alte Datensatz widersprach sich (NOTES: gleich = Erfolg; Exit 1: gleich = Fehler). Code: success("Already at …"). → EXIT STATUS 0-Zeile „equals … no-op success“, 1 nur „older / pre-release without --pre“
„Reports, but does not block on, a crossed compatibility boundary.“
NOTES 10
„Never touches git - no commit, no push (invariant 5).“
NOTES 11; Verweis „(invariant 5)“ entfällt
„The closing report carries no step list of its own … instructions/upgrade-instance.md … resumes at instructions sync.“
NOTES 15 + SEE ALSO; „carries no step list of its own“ = Begründung, steht als Kommentar vor dem Summary-Text in run_upgrade
„What a human decides before the swap … is INSTALL.md § ‚Version und Updates‘“
SEE ALSO
„For every refusal above: fix the named precondition and retry - none of them are transient.“
je ON-FAILURE-Zeile, mit der jeweiligen Abhilfe aus der Fehlermeldung (migrate baseline, migrate status, commit/stash, upstream merge)
Reaktion für lokal geänderte Dateien (drei Antworten)
ON FAILURE, Regelgehalt unverändert
„An interrupted write is not resumed automatically; compare … finish or revert by hand“
NOTES 14
PROPERTIES atomic: „Yes for the refusal cases above - nothing is written.“
„Yes for every refusal - nothing is written.“ – „above“ zeigte auf nichts mehr, seit PROPERTIES vor NOTES steht
version show
„Development tree, or a distribution with its export date and origin“ → NOTES 1, um Inhalt aus _describe_origin() ergänzt. „Bare wikitool version is an alias“, „Read-only, offline, exempt“ → NOTES. Neu: --json (aus dem Code).
version check
Alter Satz
Ziel
„One of the two commands in wikitool that make a network call …“
NOTES 2, wörtlich belassen – der Satz ist falsch, aber seine Korrektur gehört zu #144
„Never reached implicitly …, needs no key, times out“
NOTES 3, --timeout-Default ergänzt
„reports an unreachable feed as an error rather than as ‚up to date‘“ / Exit-1-Text „Never answers ‚up to date‘ …“
NEVER
Feed-Reihenfolge
NOTES 4, um --url ergänzt (Code: url or update_url(stamp))
Exit 1 + Retry
ON FAILURE unverändert; neu 1 für fehlendes/kaputtes VERSION (Code)
version notes
Alter Satz
Ziel
„The fallback exists because an instance's CHANGES.md is a stub … permanently unanswerable exactly where the release notes are most needed.“
Begründung → steht bereits im Moduldocstring von version_cmd.py und im fetch_latest_notes()-Docstring
„reached only with a release stamp present … a dev checkout keeps the plain error, which is what keeps the origin repo and CI offline“
Verhalten → NOTES 2; Begründung steht bereits im notes_command-Docstring
„(update_url is the one URL a stamp records, and composing a by-tag URL out of it would be guessing at an API shape)“
Begründung → fetch_latest_notes()-Docstring
stdout/stderr, release.yml
NOTES 4
Exit-1-Sammelsatz
vier 1-Zeilen, je mit eigener Reaktion; „Every one of those failures names the stamp's release_url“ → NOTES 6; „Safe to retry“ → NOTES 7
version bump
Alter Satz
Ziel
„Refuses more or fewer than one part, an empty title, an unknown --impact, and a VERSION/newest-changelog-entry mismatch.“
EXIT STATUS 1 (zwei Zeilen)
„The two then behave differently on a second crossing, because they answer different questions … A candidate crossing the boundary twice is the normal shape … whether content migrates stays one yes/no“
Verhalten → NOTES 8; Begründung steht bereits im bump_command-Docstring unterhalb \f
„There is deliberately no retraction path for a single accumulated --breaking reason“
NOTES 9 „Nothing retracts a recorded --breaking reason“ („deliberately“ = Begründung, Docstring)
„Which part a change earns stays a judgment call: the command enforces …“
NOTES 10
Exit-1-Sammelsatz
fünf 1-Zeilen
„Not idempotent: a second run escalates or continues the candidate again. If the outcome is uncertain, read VERSION and the top of CHANGES.md before retrying“
NOTES 11 + NEVER 1
– (neu, aus der Fehlermeldung bzw. dem Docstring)
ON FAILURE Grenzüberschreitung „…or, if nothing actually breaks, choose a smaller part“; NEVER 2 (Handbearbeitung, aus dem Docstring „invariant 1 forbids hand-editing it“)
version regrade
Der alte NOTES-Text war beim mechanischen Übertrag verstümmelt („1-based rendered position (no arguments - the correction path …)“) – aus Summary, NOTES und Docstring neu gefasst, Regelgehalt vollständig. „like version notes“ / „like version bump“ → durch die Tatsache selbst ersetzt (exempt / counted). Exit-1-Sammelsatz → zwei Zeilen. Alte Reaktion („The bare listing never writes anything. A write is not idempotent against a changed list … list again before retrying“) → NOTES 1/5 + NEVER.
version release
„Ends the pre-release phase version bump started“ → NOTES 1 ohne Querverweis. „Commits nothing and pushes nothing (invariant 5)“ → NOTES 5, Verweis entfällt. „Refuses when VERSION is already a release …, or when the changelog's newest entry does not match“ → EXIT STATUS. Alte Reaktion („Not idempotent … a release-shaped VERSION means it already ran“) → NOTES 6, ON FAILURE (Zeile 1) und NEVER.
**Gruppe Distribution and versioning – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
Alles Nicht-Aufgeführte ist unverändert in einen NOTES-Stichpunkt gewandert (nur Satzgrenzen verschoben).
### `dist export`
| Alter Satz | Ziel |
|---|---|
| Liste der ausgelieferten Dateien (ein Satz) | aufgeteilt: NOTES 2 (Maschinerie), 3 (`raw/`/`incoming/`), 4 (Templates), 5 (Stempel) |
| „(both roots are flat now that a file's location under `raw/` is a date shard rather than a hand-picked type, so a fresh export **no longer** creates any type subdirectories under either root …)“ | Verhalten → NOTES 3 in Gegenwart („no subdirectories“, Fundliste erledigt); Begründung (Datums-Shard) → Kommentar über `plan["raw/.gitkeep"]` in `build_plan` |
| „`incoming/.gitkeep` is trackable and survives becoming a git repository, so a plain clone gets the directory without any bootstrap step“ | NOTES 3, wörtlich. Dabei gefunden: der Code-Kommentar an derselben Stelle behauptete das Gegenteil („`.gitignore` excludes `incoming/` … bootstrap.md re-creates it“) und war seit `/incoming/*` + `!/incoming/.gitkeep` veraltet – korrigiert (nur Kommentar) |
| „all of them bind their instance and none are the stack's to decide“ | NOTES 4 „bind their instance“; „none are the stack's to decide“ ist Begründung → steht in `docs/ownership-and-templates.md` |
| „See `instructions/setup-instance.md`.“ | SEE ALSO |
| Exit 1 „Target exists and is not empty, is not a directory, or the tree has no readable `VERSION`“ | zwei `1`-Zeilen |
| „Point `<target>` at an empty (or new) directory and retry. Never merge into a non-empty one by hand“ | ON FAILURE + NEVER |
| – (neu, aus dem Code) | `1`: fehlende Lizenzdatei (`REQUIRED_ROOT_FILES`), Leak im Plan (`find_leaks`, Reaktion aus der Fehlermeldung); NOTES: `--dry-run` |
### `dist upgrade`
| Alter Satz | Ziel |
|---|---|
| Quelle, `.sha256`, eine Top-Level-Verzeichnis | NOTES 1 |
| Write-Set, Klassifikation | NOTES 2, 3 (Modulnamen `chemenu.ownership.is_export_stub`/`is_upgrade_preserved` entfallen – Implementierungsdetail, steht am Code) |
| „its text names the three answers with the command line already filled in, so that no reader takes any of them for the default“ | NOTES 4 + NEVER „Never treat any of the three answers … as the default“; Begründung steht bereits im `_refusal_for_blocked()`-Docstring |
| `--keep-local`/`--take-release`, „decided per path and compose“ | NOTES 5–7 |
| „A `--take-release` path that this run does not report as locally changed is refused … it is a mistake in the argument rather than a state of the tree, and a path that silently did nothing would report a successful upgrade …“ | Verweigerung → EXIT STATUS `1` + ON FAILURE; Begründung steht bereits im `_resolve_take_release()`-Docstring und am `--dry-run`-Kommentar |
| „After a `--keep-local` run the new stamp is still written whole … the stamp is the baseline for the next comparison, not a literal inventory … That is what keeps a skipped file diverging …“ | Verhalten → NOTES 5/6; Begründung → neuer Kommentar an `shutil.copy2(stamp_path, …)` in `run_upgrade` |
| `--prune` | NOTES 8 |
| Migrationskette „(`chemenu.kb_state.chain` over the *new* tree's `instructions/migrations/`, read via a `directory` argument to `load_migrations`)“ | NOTES 9; Implementierungsdetail entfällt (steht am Code) |
| „Refuses before touching the source at all when: …“ / „Refuses after reading the source when: …“ | je Ursache eine `1`-Zeile; die Reihenfolge als NOTES 12 |
| „its version is older than or equal to the installed one (equal is a no-op success)“ + Exit-1-Text „older than, equal to, or … a pre-release“ | Der alte Datensatz widersprach sich (NOTES: gleich = Erfolg; Exit 1: gleich = Fehler). Code: `success("Already at …")`. → EXIT STATUS `0`-Zeile „equals … no-op success“, `1` nur „older / pre-release without `--pre`“ |
| „Reports, but does not block on, a crossed compatibility boundary.“ | NOTES 10 |
| „Never touches git - no commit, no push (invariant 5).“ | NOTES 11; Verweis „(invariant 5)“ entfällt |
| „The closing report carries no step list of its own … `instructions/upgrade-instance.md` … resumes at `instructions sync`.“ | NOTES 15 + SEE ALSO; „carries no step list of its own“ = Begründung, steht als Kommentar vor dem Summary-Text in `run_upgrade` |
| „What a human decides *before* the swap … is `INSTALL.md` § ‚Version und Updates‘“ | SEE ALSO |
| „For every refusal above: fix the named precondition and retry - none of them are transient.“ | je ON-FAILURE-Zeile, mit der jeweiligen Abhilfe aus der Fehlermeldung (`migrate baseline`, `migrate status`, commit/stash, `upstream merge`) |
| Reaktion für lokal geänderte Dateien (drei Antworten) | ON FAILURE, Regelgehalt unverändert |
| „An interrupted write is not resumed automatically; compare … finish or revert by hand“ | NOTES 14 |
| PROPERTIES `atomic`: „**Yes for the refusal cases above - nothing is written.**“ | „Yes for every refusal - nothing is written.“ – „above“ zeigte auf nichts mehr, seit PROPERTIES vor NOTES steht |
### `version show`
„Development tree, or a distribution with its export date and origin“ → NOTES 1, um Inhalt aus `_describe_origin()` ergänzt. „Bare `wikitool version` is an alias“, „Read-only, offline, exempt“ → NOTES. Neu: `--json` (aus dem Code).
### `version check`
| Alter Satz | Ziel |
|---|---|
| „One of the **two** commands in `wikitool` that make a network call …“ | NOTES 2, **wörtlich belassen** – der Satz ist falsch, aber seine Korrektur gehört zu #144 |
| „Never reached implicitly …, needs no key, times out“ | NOTES 3, `--timeout`-Default ergänzt |
| „reports an unreachable feed as an error rather than as ‚up to date‘“ / Exit-1-Text „**Never** answers ‚up to date‘ …“ | NEVER |
| Feed-Reihenfolge | NOTES 4, um `--url` ergänzt (Code: `url or update_url(stamp)`) |
| Exit 1 + Retry | ON FAILURE unverändert; neu `1` für fehlendes/kaputtes `VERSION` (Code) |
### `version notes`
| Alter Satz | Ziel |
|---|---|
| „The fallback exists because an instance's `CHANGES.md` is a stub … permanently unanswerable exactly where the release notes are most needed.“ | Begründung → steht bereits im Moduldocstring von `version_cmd.py` und im `fetch_latest_notes()`-Docstring |
| „reached **only with a release stamp present** … a dev checkout keeps the plain error, which is what keeps the origin repo and CI offline“ | Verhalten → NOTES 2; Begründung steht bereits im `notes_command`-Docstring |
| „(`update_url` is the one URL a stamp records, and composing a by-tag URL out of it would be guessing at an API shape)“ | Begründung → `fetch_latest_notes()`-Docstring |
| stdout/stderr, `release.yml` | NOTES 4 |
| Exit-1-Sammelsatz | vier `1`-Zeilen, je mit eigener Reaktion; „Every one of those failures names the stamp's `release_url`“ → NOTES 6; „Safe to retry“ → NOTES 7 |
### `version bump`
| Alter Satz | Ziel |
|---|---|
| „Refuses more or fewer than one part, an empty title, an unknown `--impact`, and a `VERSION`/newest-changelog-entry mismatch.“ | EXIT STATUS `1` (zwei Zeilen) |
| „The two then behave differently on a *second* crossing, because they answer different questions … A candidate crossing the boundary twice is the normal shape … whether content migrates stays one yes/no“ | Verhalten → NOTES 8; Begründung steht bereits im `bump_command`-Docstring unterhalb `\f` |
| „There is deliberately no retraction path for a single accumulated `--breaking` reason“ | NOTES 9 „Nothing retracts a recorded `--breaking` reason“ („deliberately“ = Begründung, Docstring) |
| „Which part a change earns stays a judgment call: the command enforces …“ | NOTES 10 |
| Exit-1-Sammelsatz | fünf `1`-Zeilen |
| „**Not idempotent**: a second run escalates or continues the candidate again. If the outcome is uncertain, read `VERSION` and the top of `CHANGES.md` before retrying“ | NOTES 11 + NEVER 1 |
| – (neu, aus der Fehlermeldung bzw. dem Docstring) | ON FAILURE Grenzüberschreitung „…or, if nothing actually breaks, choose a smaller part“; NEVER 2 (Handbearbeitung, aus dem Docstring „invariant 1 forbids hand-editing it“) |
### `version regrade`
Der alte NOTES-Text war beim mechanischen Übertrag verstümmelt („1-based rendered position (no arguments - the correction path …)“) – aus Summary, NOTES und Docstring neu gefasst, Regelgehalt vollständig. „like `version notes`“ / „like `version bump`“ → durch die Tatsache selbst ersetzt (exempt / counted). Exit-1-Sammelsatz → zwei Zeilen. Alte Reaktion („The bare listing never writes anything. A write is **not idempotent** against a changed list … list again before retrying“) → NOTES 1/5 + NEVER.
### `version release`
„Ends the pre-release phase `version bump` started“ → NOTES 1 ohne Querverweis. „Commits nothing and pushes nothing (invariant 5)“ → NOTES 5, Verweis entfällt. „Refuses when `VERSION` is already a release …, or when the changelog's newest entry does not match“ → EXIT STATUS. Alte Reaktion („**Not idempotent** … a release-shaped `VERSION` means it already ran“) → NOTES 6, ON FAILURE (Zeile 1) und NEVER.
Gruppe Pages (new, task new|list|close, touch, rename, rm, move) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
Nicht Aufgeführtes ist wortgleich oder nur an den Satzgrenzen verschoben in NOTES gewandert.
new
Alter Satz
Ziel
Variante <type-name>: Typ-Spec, default: nur bei required:, --set/\,, „See types list/types describe“
aus der Variantennotiz in NOTES 1–3 verschoben; Variantennotiz kurz
„(an optional field's default is a reader-side assumption, not a scaffold-time value)“
Begründung → steht bereits im _build_frontmatter()-Docstring
Variante project: gesamte Mehrsatz-Notiz
NOTES 6–11, je ein Stichpunkt; Variantennotiz kurz
„exits 42 (needs_clearance(), same posture as the four named gates, without being a fifth one - see that class's docstring)“
NOTES 10 „not one of the named gates, but the same exit code and the same handling“ – Querverweis durch die Tatsache ersetzt; die Begründung steht im HumanInterventionRequired-Docstring
NOTES „new/xref/log append only produce structurally-correct frontmatter … prose … written by the LLM afterwards“
NOTES 5, nur für new (die anderen Kommandos tragen ihre eigene Aussage)
Exit 1 new <type>: „Duplicate page title, unknown type, invalid --set value, or a raw_files path that doesn't exist“
zwei 1-Zeilen
„Not transient; fix the argument and retry once. Never hand-craft the page instead“
ON FAILURE + NEVER
Exit 1 new project: „Everything new <type> covers, plus: …“
Querverweis entfällt (die new <type>-Zeilen gelten ohne Label für alle Varianten); „name taken in the tracker“, „read-only access path“ je eigene 1-Zeile mit Label new project; „--resume for another type“ eigene 1-Zeile
„A collision, a bad --set, or a read-only access path is not transient, same as new <type> - the last of those … refuses on every --resume retry too, since nothing about the config changes by asking again“
ON FAILURE der jeweiligen Zeilen, „same as new <type>“ ersetzt durch „Not transient“
„Exit 42 … is superproductivity-only …; re-run with --resume once that is done - it re-verifies … and exits 42 again unchanged …“
EXIT STATUS 42 + ON FAILURE, Regelgehalt unverändert
„caldav never produces this outcome - MKCALENDAR …“
NOTES 10
– (neu, aus dem Code)
1: Capture-Feld fehlt oder unknown (Meldung mit Beispiel); 1: Seitenschreiben nach bestätigtem Tracker-Projekt gescheitert → --resume (aus der Fehlermeldung); NOTES 4
touch
Alle Sätze in NOTES 1–8 übernommen. „same rules as new --set“ → Tatsache selbst („\, is a literal comma“). Exit-1-Sammelsatz → vier 1-Zeilen. „Fix the argument and retry once“ → ON FAILURE; „Safe to re-run as-is: --set and --add are idempotent …“ → NOTES 8. „Refused with the command that owns them instead“ → NOTES 4 + NEVER. Neu: --no-date/--dry-run (aus dem Options-Text).
task new
Alter Satz
Ziel
„The second creation command alongside new project, and the last one their split needed - see docs/knowledge-and-commitment.md.“
Geschichte/Begründung → steht im Moduldocstring von task_cmd.py und auf der docs/-Seite; SEE ALSO
„--inbox (… a deliberate exit with a cost: an item filed there never appears in review …)“
NOTES 4
„--notes … stored verbatim, never parsed - the same posture a WAITING item's own title already has …“
„No .wikitool-tasks.json fails immediately with the same ‚no tracker configured‘ message as review“
NOTES 7 ohne Querverweis
„… refuses entirely, exit 1, naming the access: "api" instance … - same posture as new project“
NOTES 8 ohne Querverweis
„Unlike new project, never exits 42: every provider offering a write path at all has a real item-creation call (…)“
Verhalten → NOTES 9; Begründung → Moduldocstring von task_cmd.py (neu)
Exit-1-Sammelsatz
fünf 1-Zeilen, Reaktionen aus der alten Retry-Zeile verteilt
„Never exit 42 - unlike new project …“ (Retry-Zeile)
NOTES 9
„an omitted --project refuses rather than silently falling into the inbox“, „never created and never searched or guessed“
NOTES 2/3 + NEVER
task list
„the id source task close and the review's own … findings need“ → NOTES 2. „Works on either access mode a provider offers, unlike the write commands below“ → NOTES 3 ohne Querverweis. „same ‚no tracker configured‘ message as review/task new“ → ON FAILURE ohne Querverweis. „--project matching no tracker project prints ‚No open items‘, since TaskReader.open_items does not distinguish …“ → EXIT STATUS 0 + NOTES 4 (Methodenname entfällt, steht am Code). Retry-Zeile „… not an error here - see its Commands row“ → 0-Zeile, Verweis auf die alte Tabelle entfällt.
task close
„never a title - the tracker-side identity is opaque, unlike the project name …“ → Verhalten NOTES 2 + NEVER; Begründung → Moduldocstring (neu). „The only closing write this stack makes: no ‚move a reminder‘, no ‚remove an item‘“ → NOTES 1. „same posture as task new“, „same reasoning as task new“ (2×) → durch die Tatsache ersetzt (NOTES 4/5). Exit-1-Sammelsatz → drei Zeilen.
rename
NOTES 1/2 wortgleich. Exit-1-Sammelsatz → drei Zeilen; neu 1 für Schreibfehler mittendrin (aus der Fehlermeldung). „Safe to retry once as-is; each page's rewrite is idempotent“ → NOTES 3 + ON FAILURE (Schreibfehler). „Use --dry-run first to see the blast radius“ → NOTES 4. „Never fix up references by hand instead“ → NEVER. Reaktion für „neither is a page“ aus der Fehlermeldung (new bzw. xref remove).
rm
„Refuses without --yes while other pages still reference it“ → NOTES 3 + EXIT STATUS. „Strips …; leaves prose and inline citations in place and reports them“ → NOTES 1/2. „For ‚still referenced‘: show the user the inbound list, get approval, then re-run with --yes“ → ON FAILURE + NEVER. „Prose references it reports afterwards are an editorial fix, not a retry“ → NOTES 2. Neu aus dem Code: 1 Schreibfehler mittendrin (Seite nicht gelöscht), --dry-run, nicht idempotent (PROPERTIES sagt es schon).
move
NOTES wortgleich aufgeteilt; „(TypeResolver.compute_target_dir)“ entfällt (Implementierungsdetail); „(lint's Misplaced Pages finding is the advisory that this fixes, and its Nested Pages finding the hard one - see lint)“ → NOTES 2 ohne „see lint“, lint in SEE ALSO. Exit-1-Sammelsatz → drei Zeilen + --reconcile-Teilfehler (aus der Fehlermeldung). „Safe to retry once as-is …“ → NOTES 5 + ON FAILURE. „Use --dry-run first“ → NOTES 6. „Never choose a directory by hand instead“ → NEVER. Neu: „Run wikitool index rebuild afterwards“ (Erfolgsmeldung des Kommandos).
**Gruppe Pages (`new`, `task new|list|close`, `touch`, `rename`, `rm`, `move`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
Nicht Aufgeführtes ist wortgleich oder nur an den Satzgrenzen verschoben in NOTES gewandert.
### `new`
| Alter Satz | Ziel |
|---|---|
| Variante `<type-name>`: Typ-Spec, `default:` nur bei `required:`, `--set`/`\,`, „See `types list`/`types describe`“ | aus der Variantennotiz in NOTES 1–3 verschoben; Variantennotiz kurz |
| „(an optional field's default is a reader-side assumption, not a scaffold-time value)“ | Begründung → steht bereits im `_build_frontmatter()`-Docstring |
| Variante `project`: gesamte Mehrsatz-Notiz | NOTES 6–11, je ein Stichpunkt; Variantennotiz kurz |
| „exits **42** (`needs_clearance()`, same posture as the four named gates, without being a fifth one - see that class's docstring)“ | NOTES 10 „not one of the named gates, but the same exit code and the same handling“ – Querverweis durch die Tatsache ersetzt; die Begründung steht im `HumanInterventionRequired`-Docstring |
| NOTES „`new`/`xref`/`log append` only produce structurally-correct frontmatter … prose … written by the LLM afterwards“ | NOTES 5, nur für `new` (die anderen Kommandos tragen ihre eigene Aussage) |
| Exit 1 `new <type>`: „Duplicate page title, unknown type, invalid `--set` value, or a `raw_files` path that doesn't exist“ | zwei `1`-Zeilen |
| „Not transient; fix the argument and retry once. Never hand-craft the page instead“ | ON FAILURE + NEVER |
| Exit 1 `new project`: „Everything `new <type>` covers, **plus**: …“ | Querverweis entfällt (die `new <type>`-Zeilen gelten ohne Label für alle Varianten); „name taken in the tracker“, „read-only access path“ je eigene `1`-Zeile mit Label `new project`; „`--resume` for another type“ eigene `1`-Zeile |
| „A collision, a bad `--set`, or a read-only access path is not transient, same as `new <type>` - the last of those … refuses on every `--resume` retry too, since nothing about the config changes by asking again“ | ON FAILURE der jeweiligen Zeilen, „same as `new <type>`“ ersetzt durch „Not transient“ |
| „**Exit 42** … is `superproductivity`-only …; re-run with `--resume` once that is done - it re-verifies … and exits 42 again unchanged …“ | EXIT STATUS `42` + ON FAILURE, Regelgehalt unverändert |
| „`caldav` never produces this outcome - `MKCALENDAR` …“ | NOTES 10 |
| – (neu, aus dem Code) | `1`: Capture-Feld fehlt oder `unknown` (Meldung mit Beispiel); `1`: Seitenschreiben nach bestätigtem Tracker-Projekt gescheitert → `--resume` (aus der Fehlermeldung); NOTES 4 |
### `touch`
Alle Sätze in NOTES 1–8 übernommen. „same rules as `new --set`“ → Tatsache selbst („`\,` is a literal comma“). Exit-1-Sammelsatz → vier `1`-Zeilen. „Fix the argument and retry once“ → ON FAILURE; „Safe to re-run as-is: `--set` and `--add` are idempotent …“ → NOTES 8. „Refused with the command that owns them instead“ → NOTES 4 + NEVER. Neu: `--no-date`/`--dry-run` (aus dem Options-Text).
### `task new`
| Alter Satz | Ziel |
|---|---|
| „The second creation command alongside `new project`, and the last one their split needed - see `docs/knowledge-and-commitment.md`.“ | Geschichte/Begründung → steht im Moduldocstring von `task_cmd.py` und auf der `docs/`-Seite; SEE ALSO |
| „`--inbox` (… a deliberate exit with a cost: an item filed there never appears in `review` …)“ | NOTES 4 |
| „`--notes` … stored verbatim, never parsed - the same posture a `WAITING` item's own title already has …“ | Verhalten → NOTES 6; Analogie → Moduldocstring (neu) |
| „No `.wikitool-tasks.json` fails immediately with the same ‚no tracker configured‘ message as `review`“ | NOTES 7 ohne Querverweis |
| „… refuses **entirely**, exit **1**, naming the `access: "api"` instance … - same posture as `new project`“ | NOTES 8 ohne Querverweis |
| „Unlike `new project`, **never exits 42**: every provider offering a write path at all has a real item-creation call (…)“ | Verhalten → NOTES 9; Begründung → Moduldocstring von `task_cmd.py` (neu) |
| Exit-1-Sammelsatz | fünf `1`-Zeilen, Reaktionen aus der alten Retry-Zeile verteilt |
| „**Never exit 42** - unlike `new project` …“ (Retry-Zeile) | NOTES 9 |
| „an omitted `--project` refuses rather than silently falling into the inbox“, „never created and never searched or guessed“ | NOTES 2/3 + NEVER |
### `task list`
„the id source `task close` and the review's own … findings need“ → NOTES 2. „Works on either access mode a provider offers, unlike the write commands below“ → NOTES 3 ohne Querverweis. „same ‚no tracker configured‘ message as `review`/`task new`“ → ON FAILURE ohne Querverweis. „`--project` matching no tracker project prints ‚No open items‘, since `TaskReader.open_items` does not distinguish …“ → EXIT STATUS `0` + NOTES 4 (Methodenname entfällt, steht am Code). Retry-Zeile „… not an error here - see its Commands row“ → `0`-Zeile, Verweis auf die alte Tabelle entfällt.
### `task close`
„never a title - the tracker-side identity is opaque, unlike the project name …“ → Verhalten NOTES 2 + NEVER; Begründung → Moduldocstring (neu). „The only closing write this stack makes: no ‚move a reminder‘, no ‚remove an item‘“ → NOTES 1. „same posture as `task new`“, „same reasoning as `task new`“ (2×) → durch die Tatsache ersetzt (NOTES 4/5). Exit-1-Sammelsatz → drei Zeilen.
### `rename`
NOTES 1/2 wortgleich. Exit-1-Sammelsatz → drei Zeilen; neu `1` für Schreibfehler mittendrin (aus der Fehlermeldung). „Safe to retry once as-is; each page's rewrite is idempotent“ → NOTES 3 + ON FAILURE (Schreibfehler). „Use `--dry-run` first to see the blast radius“ → NOTES 4. „Never fix up references by hand instead“ → NEVER. Reaktion für „neither is a page“ aus der Fehlermeldung (`new` bzw. `xref remove`).
### `rm`
„Refuses without `--yes` while other pages still reference it“ → NOTES 3 + EXIT STATUS. „Strips …; leaves prose and inline citations in place and reports them“ → NOTES 1/2. „For ‚still referenced‘: show the user the inbound list, get approval, then re-run with `--yes`“ → ON FAILURE + NEVER. „Prose references it reports afterwards are an editorial fix, not a retry“ → NOTES 2. Neu aus dem Code: `1` Schreibfehler mittendrin (Seite nicht gelöscht), `--dry-run`, nicht idempotent (PROPERTIES sagt es schon).
### `move`
NOTES wortgleich aufgeteilt; „(`TypeResolver.compute_target_dir`)“ entfällt (Implementierungsdetail); „(`lint`'s `Misplaced Pages` finding is the advisory that this fixes, and its `Nested Pages` finding the hard one - see `lint`)“ → NOTES 2 ohne „see `lint`“, `lint` in SEE ALSO. Exit-1-Sammelsatz → drei Zeilen + `--reconcile`-Teilfehler (aus der Fehlermeldung). „Safe to retry once as-is …“ → NOTES 5 + ON FAILURE. „Use `--dry-run` first“ → NOTES 6. „Never choose a directory by hand instead“ → NEVER. Neu: „Run `wikitool index rebuild` afterwards“ (Erfolgsmeldung des Kommandos).
Gruppe Links and citations (xref add|remove|link-source, links show, cite id|add|sync) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
Nicht Aufgeführtes ist wortgleich oder nur an den Satzgrenzen verschoben in NOTES gewandert.
xref add
Alter Satz
Ziel
NOTES-Absatz (ein Satz über Kante, B unberührt, Relabel, zwei Verweigerungen)
NOTES 1–5
Exit 1 „Page A or B not found, or a page's type declares no related: field“
zwei 1-Zeilen; „a page's type“ präzisiert auf „A's type“ (Code prüft nur A: _require_related_field(page_a, …))
Label-Verweigerung stand nur in NOTES
zusätzlich eigene 1-Zeile, inklusive „authorises no labels at all“ (zweiter fail() in _check_authorised)
„Safe to retry once as-is; re-running never duplicates a link“
ON FAILURE (Seite nicht gefunden)
„Never create the missing page just to force the link through, and never hand-write a reference field the type does not declare“
NEVER 1 + 2
– (neu, aus der Fehlermeldung)
NEVER 3 „Authorising a further label is a deliberate edit … not a way around this refusal“
xref remove
„it is the cleanup command … rather than the strict inverse“ → NOTES 1. „a leftover written before the check above existed has to stay repairable, or the page is a dead end“ → Begründung, steht bereits im Docstring von _require_related_field („One command created a state another could not undo“). „Idempotent“ + Reaktion „removing an absent link is a no-op“ → NOTES 5 / ON FAILURE. Neu: NEVER „Never hand-edit a page-ref array“ – aus NOTES 4 („without hand-editing frontmatter“).
xref link-source
Alter Satz
Ziel
„the See Also bullet this used to add was the reciprocal half of a model that no longer exists“
Geschichte → entfällt; steht im Moduldocstring von xref.py („It used to write four things at once …“) (Fundliste erledigt)
Exit-1-Sammelsatz
drei 1-Zeilen; der Teilerfolg (übrige Ziele verlinkt, dann Exit 1) als NOTES 4 – aus dem Code
„Use --dry-run first; safe to retry. sources trace --page … shows who was already linked“
ON FAILURE + NOTES 5
links show
„The inbound half is derived rather than stored - that is what makes it complete, and it is the answer authored directional edges would otherwise have nowhere to come from.“ → Verhalten NOTES 2; Begründung steht bereits im inbound()-Docstring. Neu: --json.
cite id
Alle drei Sätze in NOTES. Neu: NEVER „Never paste an id from here into a page by hand“ – Quelle ist AGENTS.md Invariante 1 („never compute or paste a [^cite-id] by hand - cite add mints it and prints the marker“), hier als Ausgabe wiederholt.
cite add
NOTES-Satz aufgeteilt (NOTES 1–4). Exit 1 „Page or source not found“ → zwei Zeilen (die Quellseiten-Meldung nennt den Grund „dangling reference“). „Safe to retry; upserting the same … pair twice reuses the existing id“ → NOTES 2. Neu: NEVER aus AGENTS.md Invariante 1 (wie cite id).
cite sync
„A page still carrying the pre-4.0.0 undelimited block is converted …“ → NOTES 3. „the marker carries the region's identity now, so re-rendering it under this instance's heading is a repair rather than a rename“ → Begründung → sync_page()-Docstring (neu). „Safe to retry freely. An undefined-reference report is not a failure …“ → NOTES 2/4. Neu 1: Schreibfehler mittendrin (aus der Fehlermeldung).
**Gruppe Links and citations (`xref add|remove|link-source`, `links show`, `cite id|add|sync`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
Nicht Aufgeführtes ist wortgleich oder nur an den Satzgrenzen verschoben in NOTES gewandert.
### `xref add`
| Alter Satz | Ziel |
|---|---|
| NOTES-Absatz (ein Satz über Kante, B unberührt, Relabel, zwei Verweigerungen) | NOTES 1–5 |
| Exit 1 „Page A or B not found, or a page's type declares no `related:` field“ | zwei `1`-Zeilen; „a page's type“ präzisiert auf „A's type“ (Code prüft nur A: `_require_related_field(page_a, …)`) |
| Label-Verweigerung stand nur in NOTES | zusätzlich eigene `1`-Zeile, inklusive „authorises no labels at all“ (zweiter `fail()` in `_check_authorised`) |
| „Safe to retry once as-is; re-running never duplicates a link“ | ON FAILURE (Seite nicht gefunden) |
| „Never create the missing page just to force the link through, and never hand-write a reference field the type does not declare“ | NEVER 1 + 2 |
| – (neu, aus der Fehlermeldung) | NEVER 3 „Authorising a further label is a deliberate edit … not a way around this refusal“ |
### `xref remove`
„it is the cleanup command … rather than the strict inverse“ → NOTES 1. „a leftover written before the check above existed has to stay repairable, or the page is a dead end“ → Begründung, steht bereits im Docstring von `_require_related_field` („One command created a state another could not undo“). „Idempotent“ + Reaktion „removing an absent link is a no-op“ → NOTES 5 / ON FAILURE. Neu: NEVER „Never hand-edit a page-ref array“ – aus NOTES 4 („without hand-editing frontmatter“).
### `xref link-source`
| Alter Satz | Ziel |
|---|---|
| „the See Also bullet this **used to** add was the reciprocal half of a model that **no longer** exists“ | Geschichte → entfällt; steht im Moduldocstring von `xref.py` („It used to write four things at once …“) (Fundliste erledigt) |
| Exit-1-Sammelsatz | drei `1`-Zeilen; der Teilerfolg (übrige Ziele verlinkt, dann Exit 1) als NOTES 4 – aus dem Code |
| „Use `--dry-run` first; safe to retry. `sources trace --page …` shows who was already linked“ | ON FAILURE + NOTES 5 |
### `links show`
„The inbound half is derived rather than stored - that is what makes it complete, and it is the answer authored directional edges would otherwise have nowhere to come from.“ → Verhalten NOTES 2; Begründung steht bereits im `inbound()`-Docstring. Neu: `--json`.
### `cite id`
Alle drei Sätze in NOTES. Neu: NEVER „Never paste an id from here into a page by hand“ – Quelle ist AGENTS.md Invariante 1 („never compute or paste a `[^cite-id]` by hand - `cite add` mints it and prints the marker“), hier als Ausgabe wiederholt.
### `cite add`
NOTES-Satz aufgeteilt (NOTES 1–4). Exit 1 „Page or source not found“ → zwei Zeilen (die Quellseiten-Meldung nennt den Grund „dangling reference“). „Safe to retry; upserting the same … pair twice reuses the existing id“ → NOTES 2. Neu: NEVER aus AGENTS.md Invariante 1 (wie `cite id`).
### `cite sync`
„A page still carrying the pre-4.0.0 undelimited block is converted …“ → NOTES 3. „the marker carries the region's identity now, so re-rendering it under this instance's heading is a repair rather than a rename“ → Begründung → `sync_page()`-Docstring (neu). „Safe to retry freely. An undefined-reference report is not a failure …“ → NOTES 2/4. Neu `1`: Schreibfehler mittendrin (aus der Fehlermeldung).
Gruppe Finding and checking (lint, search, review) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
Regelkorrektur für dieses Paket: In den Gruppen Git, Catalog and log, Distribution and versioning und Links and citations habe ich fünf Textstellen direkt an den Code angeglichen, statt sie – wie „Außerhalb“ verlangt – als Befund auszulagern. Sie stehen jetzt zur Bestätigung in #146. Ab dieser Gruppe bleibt ein Text, der dem Code widerspricht, unverändert stehen und wandert nach #146 (erster Fall hier: lint, Zitatlimit).
lint
Alter Satz
Ziel
Aufzählung aller Checks (ein Satz)
NOTES 1–7, eine Kategorie je Stichpunkt
„(hard - the generated catalog folds these into their area silently rather than merely reading it)“
NOTES 2, wörtlich
„(both hard once kb_version has reached … - advisory below it, so a corpus mid-migration is not refused by the check measuring it)“
Regel → NOTES 3; Begründung steht bereits im Kommentar über den migrationsabhängigen Findings in lint_core.py
„(advisory only - redundant rather than wrong, and never migration-gated, since no version turns the redundancy into an error)“
Regel → NOTES 4; Begründung steht bereits im Kommentar zu redundant_see_also bzw. über dem Gate in lint_core.py
„(advisory only - sharding is automatic but per area, so a collection nobody gave areas keeps one table however large it grows; …)“
Regel → NOTES 5; Begründung → unsharded_collections()-Docstring
„(advisory only - unclassified is the visible fallback for a genuinely unclear source, not a defect)“
Regel → NOTES 6; Begründung → unclassified_source_pages()-Docstring
NOTES 7, wörtlich belassen – der Code zählt Zitate, nicht Zeilen → #146
„Prints only the sections … --full … --json …“
NOTES 8
Exit 1 „Only with --fail-on-error: hard findings exist“
EXIT STATUS unverändert; neu NOTES 9 (ohne den Schalter immer 0)
„Safe to retry freely, but re-run it to re-measure, never to re-read: the printed path holds the full report. Exit 1 means ‚act on the findings‘, not ‚the tool is broken‘“
„the same default and the same fields are what api.search and the MCP search tool carry, from one constant“
NOTES 5, „from one constant“ entfällt (Implementierungsdetail)
„which is why a hand-run grep over kb/ can add none of them but those“
NOTES 4 + NEVER (AGENTS.md § Routing sagt es als Regel: „do not grep kb/ yourself“)
Exit-1-Sammelsatz
vier 1-Zeilen
„A timeout is a pathological pattern … rather than retrying it unchanged“
ON FAILURE (Timeout) + NEVER
„An unknown field name is reported with the list of fields that do exist - it is never answered with an empty result, because that would read as ‚no such pages‘“
EXIT STATUS/ON FAILURE + NOTES 7
review
Alter Satz
Ziel
„Joins … storing nothing - not even a reports/ file“
NOTES 1; Modulname chemenu.tasks entfällt
fünf Checks in einem Satz
NOTES 2–6, ein Check je Stichpunkt
„(… dormant/completed/abandoned never fire, since those states mean the initiative not having a next action is expected rather than a problem)“
Regel → NOTES 2; Begründung steht bereits im Kommentar in review.py (Check stalled)
Nicht lieferbare Werte, Schwellwerte, Ausgabeform
NOTES 7–9
„… a provider that cannot be reached mid-run degrades only the checks …, and the report is never rendered as if it were complete - see its error-contract row“
NOTES 10; Verweis auf die alte Tabelle entfällt
Exit-1-Sammelsatz mit zwei Ursachen
zwei 1-Zeilen
„The two exit-1 causes above need different responses: … config … editing; … unreachable provider … starting it, then a plain retry - the command re-reads everything fresh each time …“
ON FAILURE je Zeile + NOTES 11
– (neu)
NEVER „Never present a report that exited 1 as complete“ – die Aufruferseite von NOTES 10
**Gruppe Finding and checking (`lint`, `search`, `review`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
**Regelkorrektur für dieses Paket:** In den Gruppen Git, Catalog and log, Distribution and versioning und Links and citations habe ich fünf Textstellen direkt an den Code angeglichen, statt sie – wie „Außerhalb“ verlangt – als Befund auszulagern. Sie stehen jetzt zur Bestätigung in #146. Ab dieser Gruppe bleibt ein Text, der dem Code widerspricht, unverändert stehen und wandert nach #146 (erster Fall hier: `lint`, Zitatlimit).
### `lint`
| Alter Satz | Ziel |
|---|---|
| Aufzählung aller Checks (ein Satz) | NOTES 1–7, eine Kategorie je Stichpunkt |
| „(hard - the generated catalog folds these into their area silently rather than merely reading it)“ | NOTES 2, wörtlich |
| „(both hard once `kb_version` has reached … - advisory below it, so a corpus mid-migration is not refused by the check measuring it)“ | Regel → NOTES 3; Begründung steht bereits im Kommentar über den migrationsabhängigen Findings in `lint_core.py` |
| „(advisory only - redundant rather than wrong, and never migration-gated, since no version turns the redundancy into an error)“ | Regel → NOTES 4; Begründung steht bereits im Kommentar zu `redundant_see_also` bzw. über dem Gate in `lint_core.py` |
| „(advisory only - sharding is automatic but per *area*, so a collection nobody gave areas keeps one table however large it grows; …)“ | Regel → NOTES 5; Begründung → `unsharded_collections()`-Docstring |
| „(advisory only - `unclassified` is the visible fallback for a genuinely unclear source, not a defect)“ | Regel → NOTES 6; Begründung → `unclassified_source_pages()`-Docstring |
| „quote-limit overages (>2 blockquoted lines/page, advisory only)“ | NOTES 7, **wörtlich belassen** – der Code zählt Zitate, nicht Zeilen → #146 |
| „Prints only the sections … `--full` … `--json` …“ | NOTES 8 |
| Exit 1 „Only with `--fail-on-error`: hard findings exist“ | EXIT STATUS unverändert; neu NOTES 9 (ohne den Schalter immer 0) |
| „Safe to retry freely, but re-run it to re-*measure*, never to re-read: the printed path holds the full report. Exit 1 means ‚act on the findings‘, not ‚the tool is broken‘“ | ON FAILURE + NEVER |
### `search`
| Alter Satz | Ziel |
|---|---|
| NOTES-Absatz | NOTES 1–10 |
| „drops anything `kb_scan.iter_kb_pages` excludes (…)“ | NOTES 4, Funktionsname entfällt (Implementierungsdetail) |
| „the same default and the same fields are what `api.search` and the MCP `search` tool carry, from one constant“ | NOTES 5, „from one constant“ entfällt (Implementierungsdetail) |
| „which is why a hand-run grep over `kb/` can add none of them but those“ | NOTES 4 + NEVER (AGENTS.md § Routing sagt es als Regel: „do not grep `kb/` yourself“) |
| Exit-1-Sammelsatz | vier `1`-Zeilen |
| „A timeout is a pathological pattern … rather than retrying it unchanged“ | ON FAILURE (Timeout) + NEVER |
| „An unknown field name is reported with the list of fields that do exist - it is never answered with an empty result, because that would read as ‚no such pages‘“ | EXIT STATUS/ON FAILURE + NOTES 7 |
### `review`
| Alter Satz | Ziel |
|---|---|
| „Joins … storing nothing - not even a `reports/` file“ | NOTES 1; Modulname `chemenu.tasks` entfällt |
| fünf Checks in einem Satz | NOTES 2–6, ein Check je Stichpunkt |
| „(… `dormant`/`completed`/`abandoned` never fire, since those states mean the initiative not having a next action is expected rather than a problem)“ | Regel → NOTES 2; Begründung steht bereits im Kommentar in `review.py` (Check stalled) |
| Nicht lieferbare Werte, Schwellwerte, Ausgabeform | NOTES 7–9 |
| „… a provider that cannot be reached mid-run degrades only the checks …, and the report is never rendered as if it were complete - see its error-contract row“ | NOTES 10; Verweis auf die alte Tabelle entfällt |
| Exit-1-Sammelsatz mit zwei Ursachen | zwei `1`-Zeilen |
| „The two exit-1 causes above need different responses: … config … editing; … unreachable provider … starting it, then a plain retry - the command re-reads everything fresh each time …“ | ON FAILURE je Zeile + NOTES 11 |
| – (neu) | NEVER „Never present a report that exited 1 as complete“ – die Aufruferseite von NOTES 10 |
Gruppe Provenance (sources coverage|trace|rebuild-index) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
Kommando
Alter Satz
Ziel
sources coverage
NOTES (wiederholt die Summary) + „Never fails. Safe to retry freely.“
NOTES 1 + 3; neu NOTES 2 (--json)
sources trace
NOTES „Trace provenance in either direction: …“
NOTES 1/2, je Richtung ein Stichpunkt
sources trace
Exit-1-Sammelsatz inkl. „--raw names a file no source page covers (reported as a plain finding plus exit 1, not the usual ERROR-prefixed rejection)“
zwei 1-Zeilen, Klammer wörtlich in der zweiten
sources trace
„Fix the argument and retry“
ON FAILURE der ersten Zeile unverändert; für die unabgedeckte Datei: „Nothing to retry: the file is uncovered. Ingest it, or check the path“ – „check the path“ trägt das alte „fix the argument“
sources rebuild-index
NOTES „Regenerate the kb/provenance.md reverse index …“
NOTES 1; neu NOTES 2 (--dry-run, aus dem Options-Text)
sources rebuild-index
Exit 1 „Rare I/O error only“, „Safe to retry freely“
EXIT STATUS/ON FAILURE unverändert im Regelgehalt
sources rebuild-index
– (neu)
NEVER „Never hand-edit kb/provenance.md“ – AGENTS.md Invariante 1 nennt die Datei ausdrücklich als generiert
Keine Begründungssätze, keine Querverweise, keine Abweichung zum Code gefunden.
**Gruppe Provenance (`sources coverage|trace|rebuild-index`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
| Kommando | Alter Satz | Ziel |
|---|---|---|
| `sources coverage` | NOTES (wiederholt die Summary) + „Never fails. Safe to retry freely.“ | NOTES 1 + 3; neu NOTES 2 (`--json`) |
| `sources trace` | NOTES „Trace provenance in either direction: …“ | NOTES 1/2, je Richtung ein Stichpunkt |
| `sources trace` | Exit-1-Sammelsatz inkl. „`--raw` names a file no source page covers (reported as a plain finding plus exit 1, not the usual `ERROR`-prefixed rejection)“ | zwei `1`-Zeilen, Klammer wörtlich in der zweiten |
| `sources trace` | „Fix the argument and retry“ | ON FAILURE der ersten Zeile unverändert; für die unabgedeckte Datei: „Nothing to retry: the file is uncovered. Ingest it, or check the path“ – „check the path“ trägt das alte „fix the argument“ |
| `sources rebuild-index` | NOTES „Regenerate the `kb/provenance.md` reverse index …“ | NOTES 1; neu NOTES 2 (`--dry-run`, aus dem Options-Text) |
| `sources rebuild-index` | Exit 1 „Rare I/O error only“, „Safe to retry freely“ | EXIT STATUS/ON FAILURE unverändert im Regelgehalt |
| `sources rebuild-index` | – (neu) | NEVER „Never hand-edit `kb/provenance.md`“ – AGENTS.md Invariante 1 nennt die Datei ausdrücklich als generiert |
Keine Begründungssätze, keine Querverweise, keine Abweichung zum Code gefunden.
Gruppe Raw material and uploads (raw accept, upload list|show|accept|reject) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
raw accept
Alter Satz
Ziel
Variantennotiz Plain (ein Absatz)
NOTES 1–6; Variantennotiz kurz
„raw/no longer addresses by type“
NOTES 1 „raw/ does not address by type“ (Fundliste erledigt)
„(raw/CONTRACT.md ‚Getting a file in‘)“ und alte NOTES „See raw/CONTRACT.md …“
SEE ALSO
„required here (see types describe source; unknown is refused, backfill-only) - the one moment both are knowable“
NOTES 3; Begründung „the one moment both are knowable“ steht in raw/CONTRACT.md (Abschnitt ab Zeile 159)
„(refused if it already carries a different value - a capture field is fixed once)“
NOTES 4 + 1-Zeile 4
Bundle-Faltung „so a bundle never mixes an old and a new capture date“, „(provenance.duplicate_raw_file_owners)“
NOTES 5; Funktionsname entfällt; Begründung steht zusätzlich in raw/CONTRACT.md und am Code
Eindeutigkeit, „naming both --replaces and renaming-in-incoming/ without recommending either“
NOTES 6
Variantennotiz --replaces (ein Absatz)
NOTES 7–10; Variantennotiz kurz
„(same filename required; there is no type directory left to match)“
NOTES 7 „(same filename required)“; der Nebensatz ist Begründung/Geschichte → entfällt, raw/CONTRACT.md erklärt die flache Adressierung
„the one path fill-once does not block, because a corrected capture is a new edition of the source, not an edit of the page describing it“
Regel → NOTES 8; Begründung → raw/CONTRACT.md „Fixed once, correctable only as a new edition“
Exit-1-Sammelsätze (zwei, je Variante)
sieben 1-Zeilen mit Label der Variante
„Safe to retry as-is once the cause is fixed: a file already at its computed destination is what ‚already exists‘ reports, not a partial prior run to resume.“
NOTES 11
„A stem-occupied refusal is not fixed by retrying at all - it names --replaces and renaming in incoming/ as the two routes and neither is the tool's to pick.“
ON FAILURE (belegt), ergänzt um „Show the message to the user and wait“ – wörtlich die Regel aus raw/CONTRACT.md („An agent that gets this message does not pick a route on its own initiative - it shows the message to the human and waits“) + NEVER 2
„Never choose the destination by hand instead - that is the decision this command exists to take away“
NEVER 1; Begründungshalbsatz entfällt (steht im Moduldocstring von raw_cmd.py)
„Every check runs before the filesystem is touched, so a refusal leaves both files exactly as they were“
ON FAILURE der --replaces-Zeilen
upload list / upload show / upload reject
upload list: „(see the MCP read server design note)“ → SEE ALSO INSTALL-MCP.md § Schritt 7; sonst wortgleich in NOTES. upload show: NOTES aufgeteilt, wortgleich. upload reject: „No gate - rejecting needs no clearance, only accepting does“ → NOTES 3; die Ledger-Reihenfolge stand in PROPERTIES atomic und steht jetzt zusätzlich in NOTES 2; Retry-Satz „Not idempotent … a retry reports ‚unknown id‘ - that is confirmation, not a failure“ → NOTES 4 + ON FAILURE.
upload accept
Alter Satz
Ziel
„- the same shape as the Mass-Update Gate's clearance, one submission at a time“
Querverweis entfällt; NOTES 2 beschreibt die Form selbst
„Refuses (without the gate - these are ordinary validation errors) when incoming/<filename> already exists“
NOTES 4 + eigene 1-Zeile
Exit-1/42-Sammelsatz
zwei 1-Zeilen, eine 42-Zeile
„For exit 42: show the user the full manifest and the exact --confirm <token> re-run line printed, and stop - the same rule as every other exit-42 gate (AGENTS.md invariant 6).“
ON FAILURE über token_gate_reaction("--confirm") (zeigen, stoppen, nach Freigabe Wiederholungszeile) + NEVER „Never pass a --confirm token the user has not seen and approved“ (Invariante 6 selbst statt Verweis)
„an occupied incoming/<filename> is not fixed by retrying unchanged - rename or clear it first“
ON FAILURE der eigenen Zeile
Keine Abweichung zum Code gefunden.
**Gruppe Raw material and uploads (`raw accept`, `upload list|show|accept|reject`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
### `raw accept`
| Alter Satz | Ziel |
|---|---|
| Variantennotiz Plain (ein Absatz) | NOTES 1–6; Variantennotiz kurz |
| „`raw/` **no longer** addresses by type“ | NOTES 1 „`raw/` does not address by type“ (Fundliste erledigt) |
| „(`raw/CONTRACT.md` ‚Getting a file in‘)“ und alte NOTES „See `raw/CONTRACT.md` …“ | SEE ALSO |
| „required here (see `types describe source`; `unknown` is refused, backfill-only) - the one moment both are knowable“ | NOTES 3; Begründung „the one moment both are knowable“ steht in `raw/CONTRACT.md` (Abschnitt ab Zeile 159) |
| „(refused if it already carries a different value - a capture field is fixed once)“ | NOTES 4 + `1`-Zeile 4 |
| Bundle-Faltung „so a bundle never mixes an old and a new capture date“, „(`provenance.duplicate_raw_file_owners`)“ | NOTES 5; Funktionsname entfällt; Begründung steht zusätzlich in `raw/CONTRACT.md` und am Code |
| Eindeutigkeit, „naming both `--replaces` and renaming-in-`incoming/` without recommending either“ | NOTES 6 |
| Variantennotiz `--replaces` (ein Absatz) | NOTES 7–10; Variantennotiz kurz |
| „(same filename required; there is no type directory left to match)“ | NOTES 7 „(same filename required)“; der Nebensatz ist Begründung/Geschichte → entfällt, `raw/CONTRACT.md` erklärt die flache Adressierung |
| „the one path fill-once does not block, because a corrected capture is a new edition of the source, not an edit of the page describing it“ | Regel → NOTES 8; Begründung → `raw/CONTRACT.md` „Fixed once, correctable only as a new edition“ |
| Exit-1-Sammelsätze (zwei, je Variante) | sieben `1`-Zeilen mit Label der Variante |
| „Safe to retry as-is once the cause is fixed: a file already at its computed destination is what ‚already exists‘ reports, not a partial prior run to resume.“ | NOTES 11 |
| „A stem-occupied refusal is not fixed by retrying at all - it names `--replaces` and renaming in `incoming/` as the two routes and neither is the tool's to pick.“ | ON FAILURE (belegt), ergänzt um „Show the message to the user and wait“ – wörtlich die Regel aus `raw/CONTRACT.md` („An agent that gets this message does not pick a route on its own initiative - it shows the message to the human and waits“) + NEVER 2 |
| „Never choose the destination by hand instead - that is the decision this command exists to take away“ | NEVER 1; Begründungshalbsatz entfällt (steht im Moduldocstring von `raw_cmd.py`) |
| „Every check runs before the filesystem is touched, so a refusal leaves both files exactly as they were“ | ON FAILURE der `--replaces`-Zeilen |
### `upload list` / `upload show` / `upload reject`
`upload list`: „(see the MCP read server design note)“ → SEE ALSO `INSTALL-MCP.md` § Schritt 7; sonst wortgleich in NOTES. `upload show`: NOTES aufgeteilt, wortgleich. `upload reject`: „No gate - rejecting needs no clearance, only accepting does“ → NOTES 3; die Ledger-Reihenfolge stand in PROPERTIES `atomic` und steht jetzt zusätzlich in NOTES 2; Retry-Satz „Not idempotent … a retry reports ‚unknown id‘ - that is confirmation, not a failure“ → NOTES 4 + ON FAILURE.
### `upload accept`
| Alter Satz | Ziel |
|---|---|
| „- the same shape as the Mass-Update Gate's clearance, one submission at a time“ | Querverweis entfällt; NOTES 2 beschreibt die Form selbst |
| „Refuses (without the gate - these are ordinary validation errors) when `incoming/<filename>` already exists“ | NOTES 4 + eigene `1`-Zeile |
| Exit-1/42-Sammelsatz | zwei `1`-Zeilen, eine `42`-Zeile |
| „For exit 42: show the user the full manifest and the exact `--confirm <token>` re-run line printed, and stop - the same rule as every other exit-42 gate (AGENTS.md invariant 6).“ | ON FAILURE über `token_gate_reaction("--confirm")` (zeigen, stoppen, nach Freigabe Wiederholungszeile) + NEVER „Never pass a `--confirm` token the user has not seen and approved“ (Invariante 6 selbst statt Verweis) |
| „an occupied `incoming/<filename>` is not fixed by retrying unchanged - rename or clear it first“ | ON FAILURE der eigenen Zeile |
Keine Abweichung zum Code gefunden.
Gruppe Workshop runs and session budget (work new|close, budget status|reset) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
Kommando
Alter Satz
Ziel
work new
NOTES-Absatz
NOTES 1–4, wortgleich aufgeteilt; neu NOTES 5 (--dry-run)
work new
„See work/CONTRACT.md“
SEE ALSO
work new
Exit-1-Sammelsatz
drei 1-Zeilen; ergänzt um „does not exist“ und „raw/ itself (empty run key)“ aus dem Code
work new
„A collision is not transient: resume the existing run instead, or pass --again if the tree itself changed.“
ON FAILURE (Kollision), wörtlich
work new
„Never create a numbered variant by hand“
NEVER
work close
„Lists what would be lost and requires --yes, because nothing in it is recoverable from the rest of the repo - the durable conclusions must already be in kb/“
NOTES 2, wortgleich; der „because“-Teil bleibt, weil er zugleich die Pflicht trägt („conclusions must already be in kb/“)
work close
Exit 1 „Unknown run key, or --yes was not passed“
zwei 1-Zeilen; Reaktion für den unbekannten Schlüssel aus der Fehlermeldung („ls work/ shows the open ones“)
work close
„For ‚not confirmed‘: check the listed files are no longer needed, confirm the conclusions are in kb/, then re-run with --yes“
ON FAILURE, wörtlich; die Fundstelle „no longer needed“ aus der Fundliste bleibt als Gegenwartsaussage
work close
– (neu)
NEVER „Never pass --yes before the run's conclusions are in kb/“ – Aufruferseite der Pflicht
budget status
„Recent command history is never counted against the budget. Never fails. Safe to retry freely.“
NOTES 2; „command history is never counted“ präzisiert auf den Aufruf selbst („Never counted against the budget“) – budget: exempt in PROPERTIES sagt dasselbe
budget reset
„Requires --yes: clearing the counter is itself a way around the gate, so it needs the same explicit human approval“
NOTES 2, wörtlich
budget reset
– (neu)
NOTES 1 (--all, aus der Summary/Synopsis), NOTES 3 (gezählt, aus budget: counted), NEVER aus AGENTS.md Invariante 6 („Not … budget reset --yes“)
Keine Abweichung zum Code gefunden.
**Gruppe Workshop runs and session budget (`work new|close`, `budget status|reset`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
| Kommando | Alter Satz | Ziel |
|---|---|---|
| `work new` | NOTES-Absatz | NOTES 1–4, wortgleich aufgeteilt; neu NOTES 5 (`--dry-run`) |
| `work new` | „See `work/CONTRACT.md`“ | SEE ALSO |
| `work new` | Exit-1-Sammelsatz | drei `1`-Zeilen; ergänzt um „does not exist“ und „`raw/` itself (empty run key)“ aus dem Code |
| `work new` | „A collision is not transient: resume the existing run instead, or pass `--again` if the tree itself changed.“ | ON FAILURE (Kollision), wörtlich |
| `work new` | „Never create a numbered variant by hand“ | NEVER |
| `work close` | „Lists what would be lost and requires `--yes`, because nothing in it is recoverable from the rest of the repo - the durable conclusions must already be in `kb/`“ | NOTES 2, wortgleich; der „because“-Teil bleibt, weil er zugleich die Pflicht trägt („conclusions must already be in `kb/`“) |
| `work close` | Exit 1 „Unknown run key, or `--yes` was not passed“ | zwei `1`-Zeilen; Reaktion für den unbekannten Schlüssel aus der Fehlermeldung („`ls work/` shows the open ones“) |
| `work close` | „For ‚not confirmed‘: check the listed files are no longer needed, confirm the conclusions are in `kb/`, then re-run with `--yes`“ | ON FAILURE, wörtlich; die Fundstelle „no longer needed“ aus der Fundliste bleibt als Gegenwartsaussage |
| `work close` | – (neu) | NEVER „Never pass `--yes` before the run's conclusions are in `kb/`“ – Aufruferseite der Pflicht |
| `budget status` | „Recent command history is never counted against the budget. Never fails. Safe to retry freely.“ | NOTES 2; „command history is never counted“ präzisiert auf den Aufruf selbst („Never counted against the budget“) – `budget: exempt` in PROPERTIES sagt dasselbe |
| `budget reset` | „Requires `--yes`: clearing the counter is itself a way around the gate, so it needs the same explicit human approval“ | NOTES 2, wörtlich |
| `budget reset` | – (neu) | NOTES 1 (`--all`, aus der Summary/Synopsis), NOTES 3 (gezählt, aus `budget: counted`), NEVER aus AGENTS.md Invariante 6 („Not … `budget reset --yes`“) |
Keine Abweichung zum Code gefunden.
Gruppe Types, instructions and docs (types list|describe, instructions sync|verify|list, docs verify|toc|contract) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
Kommando
Alter Satz
Ziel
types list
NOTES „Name, schema path, subtype field, and description - discover what page types exist without reading types/*.md directly. Never fails. Safe to retry freely.“
NOTES 1/2; neu NEVER „Never pick a page's directory by hand“ (AGENTS.md § Routing „Never pick a directory by hand“)
types describe
„so a root: kb type's contract reads as one answer even though it may live in two files“
NOTES 2, wortgleich
types describe
„it is stripped from this output rather than echoed, since the whole body is being handed over and a navigation aid into it would be noise“
Verhalten → NOTES 3; Begründung steht bereits im Kommentar in types_cmd.py (Zeile ~136) und im toc.py-Moduldocstring
instructions sync
„Both targets are gitignored, so a fresh clone runs this once - see instructions/bootstrap.md“
NOTES 2 + SEE ALSO
instructions sync
Exit-1-Sammelsatz
zwei 1-Zeilen; Reaktion „Check whether the flagged target holds anything worth keeping, then re-run with --force if not; otherwise fix the named cause and retry“ auf die beiden Zeilen verteilt
instructions sync
– (neu)
NOTES 5 aus PROPERTIES atomic („re-run converges“); NEVER „Never hand-edit a published copy“ – aus „the source always wins“ und der Reaktion von instructions verify
instructions verify
NOTES (ein Satz, sechs Prüfungen)
NOTES 1–5
instructions verify
„(sync copies it to a different depth than the source, so a SKILL.md references a target as a repo-root-relative plain path instead - see instructions/CONTRACT.md § …)“
NOTES 2, wortgleich – das „so“ trägt hier die Regel (Pfad statt Link), nicht nur Begründung
instructions verify
Exit-1-Sammelsatz
fünf 1-Zeilen
instructions verify
„Fix the flagged file, then re-run. For a relative link … repo-root-relative plain path instead. For drift, re-run sync instead of hand-editing the published copy - the source under instructions/ always wins“
ON FAILURE je Zeile + NEVER; für „nothing references it“/„manual linked“ und dev/-Verweis neue, der Ursache entsprechende Reaktionen („Link it …“, „Remove the reference or wrap it in a dist:strip block“ – Letzteres aus der Ausnahme in NOTES 5)
instructions list
„This is how the layer is discovered; search deliberately covers kb/ only.“
NOTES 1 ohne „deliberately“ (Begründungswort)
docs verify
NOTES (ein Satz über ~20 Prüfungen)
NOTES 1–9, nach Gegenstand gruppiert, Wortlaut der Prüfungen unverändert
docs verify
„(both directions, so a command dropped from one is not hidden by the other)“
NOTES 2 „in both directions“; der Nebensatz ist Begründung → Docstring von check_command_contracts
docs verify
„what cli_contract.render_commands_region() would write“
„what docs contract would write“ – dieselbe Tatsache, als Kommando statt Funktion
docs verify
„- the tracker exists only in the origin repo, so such a number in a distributed instance is a reference its reader can neither resolve nor recognise as unresolvable“
Begründung → instructions/dev/issue-tracking.md § „Citing an issue in the repo“ (steht dort ausführlich)
docs verify
„- missing and stale are one check, because the generator is idempotent -“
NOTES 8 „missing and stale are one check“; „because …“ → toc.py
docs verify
„the same way kb/ predates the collection it now checks“
Analogie → entfällt
docs verify
Exit-1-Sammelsatz
sechs 1-Zeilen, davon neu „commands region stale → docs contract --apply“ (Prüfung stand in NOTES)
docs verify
Reaktion (vier Fälle)
je ON-FAILURE-Zeile, wörtlich; „never hand-write the region“ → NEVER
docs toc
„in the scope Anthropic's skill-authoring guidance names for a file previewed rather than read in full“
Begründung → toc.py-Moduldocstring (zitiert die Quelle wörtlich)
docs toc
„A template is in scope because it is the same document one step earlier … which is how kb/CONVENTIONS.md.template came to grow past the threshold …“
Regel → NOTES 1 („each together with the <name>.template“); Begründung und Geschichte → toc.target_files()-Docstring (Zeile ~133)
docs toc
„SKILL.md is the one exception, and the same guidance is why: …“, „Human docs … are out of scope because AGENTS.md § File naming says …“
Regel → NOTES 3; Begründung → toc.py-Moduldocstring
docs toc
Exit-„1“-Zelle „Never fails on content: …“
EXIT STATUS 0-Zeile, wörtlich; der Index zeigt dadurch exit:0 statt exit:0,1 (in #146 zur Bestätigung eingetragen)
docs toc
„Nothing to fix - re-run with --apply … If docs verify still reports a stale region afterwards … run it again“
NOTES 4/5
docs toc
„docs verify checks the result stays current the same way it checks every other generated-from-code copy“
Funktionsnamen entfallen (Implementierungsdetail), „like docs toc“ durch die Tatsache ersetzt (NOTES 2)
**Gruppe Types, instructions and docs (`types list|describe`, `instructions sync|verify|list`, `docs verify|toc|contract`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
| Kommando | Alter Satz | Ziel |
|---|---|---|
| `types list` | NOTES „Name, schema path, subtype field, and description - discover what page types exist without reading `types/*.md` directly. Never fails. Safe to retry freely.“ | NOTES 1/2; neu NEVER „Never pick a page's directory by hand“ (AGENTS.md § Routing „Never pick a directory by hand“) |
| `types describe` | „so a `root: kb` type's contract reads as one answer even though it may live in two files“ | NOTES 2, wortgleich |
| `types describe` | „it is stripped from this output rather than echoed, since the whole body is being handed over and a navigation aid into it would be noise“ | Verhalten → NOTES 3; Begründung steht bereits im Kommentar in `types_cmd.py` (Zeile ~136) und im `toc.py`-Moduldocstring |
| `instructions sync` | „Both targets are gitignored, so a fresh clone runs this once - see `instructions/bootstrap.md`“ | NOTES 2 + SEE ALSO |
| `instructions sync` | Exit-1-Sammelsatz | zwei `1`-Zeilen; Reaktion „Check whether the flagged target holds anything worth keeping, then re-run with `--force` if not; otherwise fix the named cause and retry“ auf die beiden Zeilen verteilt |
| `instructions sync` | – (neu) | NOTES 5 aus PROPERTIES `atomic` („re-run converges“); NEVER „Never hand-edit a published copy“ – aus „the source always wins“ und der Reaktion von `instructions verify` |
| `instructions verify` | NOTES (ein Satz, sechs Prüfungen) | NOTES 1–5 |
| `instructions verify` | „(`sync` copies it to a different depth than the source, so a `SKILL.md` references a target as a repo-root-relative plain path instead - see `instructions/CONTRACT.md` § …)“ | NOTES 2, wortgleich – das „so“ trägt hier die Regel (Pfad statt Link), nicht nur Begründung |
| `instructions verify` | Exit-1-Sammelsatz | fünf `1`-Zeilen |
| `instructions verify` | „Fix the flagged file, then re-run. For a relative link … repo-root-relative plain path instead. For drift, re-run `sync` instead of hand-editing the published copy - the source under `instructions/` always wins“ | ON FAILURE je Zeile + NEVER; für „nothing references it“/„manual linked“ und `dev/`-Verweis neue, der Ursache entsprechende Reaktionen („Link it …“, „Remove the reference or wrap it in a `dist:strip` block“ – Letzteres aus der Ausnahme in NOTES 5) |
| `instructions list` | „This is how the layer is discovered; `search` deliberately covers `kb/` only.“ | NOTES 1 ohne „deliberately“ (Begründungswort) |
| `docs verify` | NOTES (ein Satz über ~20 Prüfungen) | NOTES 1–9, nach Gegenstand gruppiert, Wortlaut der Prüfungen unverändert |
| `docs verify` | „(both directions, so a command dropped from one is not hidden by the other)“ | NOTES 2 „in both directions“; der Nebensatz ist Begründung → Docstring von `check_command_contracts` |
| `docs verify` | „what `cli_contract.render_commands_region()` would write“ | „what `docs contract` would write“ – dieselbe Tatsache, als Kommando statt Funktion |
| `docs verify` | „- the tracker exists only in the origin repo, so such a number in a distributed instance is a reference its reader can neither resolve nor recognise as unresolvable“ | Begründung → `instructions/dev/issue-tracking.md` § „Citing an issue in the repo“ (steht dort ausführlich) |
| `docs verify` | „- missing and stale are one check, because the generator is idempotent -“ | NOTES 8 „missing and stale are one check“; „because …“ → `toc.py` |
| `docs verify` | „the same way `kb/` predates the collection it now checks“ | Analogie → entfällt |
| `docs verify` | Exit-1-Sammelsatz | sechs `1`-Zeilen, davon neu „commands region stale → `docs contract --apply`“ (Prüfung stand in NOTES) |
| `docs verify` | Reaktion (vier Fälle) | je ON-FAILURE-Zeile, wörtlich; „never hand-write the region“ → NEVER |
| `docs toc` | „in the scope Anthropic's skill-authoring guidance names for a file previewed rather than read in full“ | Begründung → `toc.py`-Moduldocstring (zitiert die Quelle wörtlich) |
| `docs toc` | „A template is in scope because it is the same document one step earlier … which is how `kb/CONVENTIONS.md.template` came to grow past the threshold …“ | Regel → NOTES 1 („each together with the `<name>.template`“); Begründung und Geschichte → `toc.target_files()`-Docstring (Zeile ~133) |
| `docs toc` | „`SKILL.md` is the one exception, and the same guidance is why: …“, „Human docs … are out of scope because AGENTS.md § File naming says …“ | Regel → NOTES 3; Begründung → `toc.py`-Moduldocstring |
| `docs toc` | Exit-„1“-Zelle „Never fails on content: …“ | EXIT STATUS `0`-Zeile, wörtlich; der Index zeigt dadurch `exit:0` statt `exit:0,1` (in #146 zur Bestätigung eingetragen) |
| `docs toc` | „Nothing to fix - re-run with `--apply` … If `docs verify` still reports a stale region afterwards … run it again“ | NOTES 4/5 |
| `docs toc` | „`docs verify` checks the result stays current the same way it checks every other generated-from-code copy“ | SEE ALSO |
| `docs contract` | „from `cli_contract.all_records()`“, „`docs verify`'s `check_commands_region`“, „like `docs toc`“ | Funktionsnamen entfallen (Implementierungsdetail), „like `docs toc`“ durch die Tatsache ersetzt (NOTES 2) |
Changelog: Types, instructions and docs published als 9617d72 (nach Freigabe durch den Betreiber, ab jetzt je Gruppe eigene WIKITOOL_SESSION_ID, z. B. issue-142/telemetry).
Gruppe Telemetry (eval sessions, eval score) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
Kommando
Alter Satz
Ziel
eval sessions
„Most recent first. Read-only and exempt … Never fails; an empty list is a valid answer.“
NOTES 1–3, wortgleich
eval score
NOTES-Absatz (L1/L2, Default-Sitzung, --save)
NOTES 1–3; „see EVALS.md“ → SEE ALSO
eval score
Reaktion „Run eval sessions to see which ids exist. A session records nothing when telemetry is off - … so an absent trace is not necessarily a fault. Safe to retry“
ON FAILURE (erster Satz) + NOTES 4/5
eval score
– (neu, aus dem Code)
1: --fail-on-error bei harten Fehlern oder verletzter Invariante (raise typer.Exit(code=1), Options-Text) – fehlte im Datensatz; eine Lücke, kein Widerspruch
Keine Begründungssätze, keine Querverweise.
**Changelog:** Types, instructions and docs published als `9617d72` (nach Freigabe durch den Betreiber, ab jetzt je Gruppe eigene `WIKITOOL_SESSION_ID`, z. B. `issue-142/telemetry`).
**Gruppe Telemetry (`eval sessions`, `eval score`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
| Kommando | Alter Satz | Ziel |
|---|---|---|
| `eval sessions` | „Most recent first. Read-only and exempt … Never fails; an empty list is a valid answer.“ | NOTES 1–3, wortgleich |
| `eval score` | NOTES-Absatz (L1/L2, Default-Sitzung, `--save`) | NOTES 1–3; „see `EVALS.md`“ → SEE ALSO |
| `eval score` | Reaktion „Run `eval sessions` to see which ids exist. A session records nothing when telemetry is off - … so an absent trace is not necessarily a fault. Safe to retry“ | ON FAILURE (erster Satz) + NOTES 4/5 |
| `eval score` | – (neu, aus dem Code) | `1`: `--fail-on-error` bei harten Fehlern oder verletzter Invariante (`raise typer.Exit(code=1)`, Options-Text) – fehlte im Datensatz; eine Lücke, kein Widerspruch |
Keine Begründungssätze, keine Querverweise.
Gruppe Content migrations (migrate list|status|verify|done|baseline) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
Kommando
Alter Satz
Ziel
migrate list
NOTES
NOTES 1/2, wortgleich
migrate status
„offered documents … bounded by the applied ledger rather than by kb_version - taking one deliberately does not move the version, so the version cannot say whether it was taken“
Regel → NOTES 2 („taking one does not move the version“); Begründung steht bereits im done_command-Docstring („The record is the only thing that distinguishes an offer someone took … because the version stays put“)
migrate status
„Exits 1 only when .wikitool-kb.json is missing - the content's shape is a question the tool refuses to answer by guessing.“
NOTES 4 („it never guesses the content's shape“) – ergänzt um VERSION unlesbar, das stand schon in der alten Exit-1-Zelle; Begründung steht im status_command-Docstring
migrate status
Exit-1-Sammelsatz, „For a missing declaration: run migrate baseline <version> once, then retry. Safe to retry freely otherwise“
zwei 1-Zeilen mit je eigener Reaktion + NOTES 5
migrate verify
„a page that went from one links region to two has the same set of region names and a different count, and a lost marker turns a generated region into prose …“
Regel („count of marker pairs“) → NOTES 1; Begründung → verify_command-Docstring (neu)
migrate verify
„the one question lint cannot answer, since it reads a single revision …“
Begründung → verify_command-Docstring (neu); lint in SEE ALSO
migrate verify
Exit-1-Sammelsatz „Only with --fail-on-error … Also exits 1 if --from is not a revision“
zwei 1-Zeilen; neu NOTES 6 (ohne den Schalter immer 0)
migrate verify
„Exit 1 from --fail-on-error means ‚act on the findings‘ … A finding is never fixed by re-running - it names a page and what changed on it“
ON FAILURE wörtlich + NEVER
migrate done
„Refuses any version that is not the next link in the chain - skipping one leaves the corpus in a shape no version describes, and an interrupted multi-step upgrade has to be resumable rather than guessable.“
Regel → NOTES 2 (präzisiert auf „required“, wie die alte Exit-Zelle); Begründung steht bereits im done_command-Docstring
migrate done
„it is not a link in the chain, so there is nothing to skip, and requiring the chain first would make an unrelated file upgrade wait on it“
Begründung → done_command-Docstring (neu ergänzt)
migrate done
Exit-1-Sammelsatz
zwei 1-Zeilen
migrate done
„Not idempotent for a required migration: it advances the chain. For ‚not the next link‘, run migrate status and apply them in the order it prints - never force the order. Recording an offered migration is idempotent and safe to repeat“
NOTES 3/4, ON FAILURE, NEVER 1
migrate done
– (neu)
NEVER 2 „Never hand-edit .wikitool-kb.json“ – AGENTS.md Invariante 1 nennt die Datei ausdrücklich
migrate baseline
„Refuses to overwrite … without --force: advancing after a migration is done, which checks the chain, and this command must not become the quiet way around it“
NOTES 2 + NEVER „Never use --force to advance the version past a migration“
migrate baseline
Exit-1-Sammelsatz, „Safe to re-run with the same version. If a declaration exists, it is almost always migrate done that was wanted“
zwei 1-Zeilen + NOTES 3
Keine Abweichung zum Code gefunden.
**Changelog:** Telemetry published als `71efdbe`.
**Gruppe Content migrations (`migrate list|status|verify|done|baseline`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
| Kommando | Alter Satz | Ziel |
|---|---|---|
| `migrate list` | NOTES | NOTES 1/2, wortgleich |
| `migrate status` | „`offered` documents … bounded by the applied ledger rather than by `kb_version` - taking one deliberately does not move the version, so the version cannot say whether it was taken“ | Regel → NOTES 2 („taking one does not move the version“); Begründung steht bereits im `done_command`-Docstring („The record is the only thing that distinguishes an offer someone took … because the version stays put“) |
| `migrate status` | „Exits 1 only when `.wikitool-kb.json` is missing - the content's shape is a question the tool refuses to answer by guessing.“ | NOTES 4 („it never guesses the content's shape“) – ergänzt um `VERSION` unlesbar, das stand schon in der alten Exit-1-Zelle; Begründung steht im `status_command`-Docstring |
| `migrate status` | Exit-1-Sammelsatz, „For a missing declaration: run `migrate baseline <version>` once, then retry. Safe to retry freely otherwise“ | zwei `1`-Zeilen mit je eigener Reaktion + NOTES 5 |
| `migrate verify` | „a page that went from one links region to two has the same set of region names and a different count, and a lost marker turns a generated region into prose …“ | Regel („count of marker pairs“) → NOTES 1; Begründung → `verify_command`-Docstring (neu) |
| `migrate verify` | „the one question `lint` cannot answer, since it reads a single revision …“ | Begründung → `verify_command`-Docstring (neu); `lint` in SEE ALSO |
| `migrate verify` | Exit-1-Sammelsatz „Only with `--fail-on-error` … Also exits 1 if `--from` is not a revision“ | zwei `1`-Zeilen; neu NOTES 6 (ohne den Schalter immer 0) |
| `migrate verify` | „Exit 1 from `--fail-on-error` means ‚act on the findings‘ … A finding is never fixed by re-running - it names a page and what changed on it“ | ON FAILURE wörtlich + NEVER |
| `migrate done` | „**Refuses any version that is not the next link in the chain** - skipping one leaves the corpus in a shape no version describes, and an interrupted multi-step upgrade has to be resumable rather than guessable.“ | Regel → NOTES 2 (präzisiert auf „required“, wie die alte Exit-Zelle); Begründung steht bereits im `done_command`-Docstring |
| `migrate done` | „it is not a link in the chain, so there is nothing to skip, and requiring the chain first would make an unrelated file upgrade wait on it“ | Begründung → `done_command`-Docstring (neu ergänzt) |
| `migrate done` | Exit-1-Sammelsatz | zwei `1`-Zeilen |
| `migrate done` | „**Not idempotent** for a required migration: it advances the chain. For ‚not the next link‘, run `migrate status` and apply them in the order it prints - never force the order. Recording an `offered` migration *is* idempotent and safe to repeat“ | NOTES 3/4, ON FAILURE, NEVER 1 |
| `migrate done` | – (neu) | NEVER 2 „Never hand-edit `.wikitool-kb.json`“ – AGENTS.md Invariante 1 nennt die Datei ausdrücklich |
| `migrate baseline` | „Refuses to overwrite … without `--force`: advancing after a migration is `done`, which checks the chain, and this command must not become the quiet way around it“ | NOTES 2 + NEVER „Never use `--force` to advance the version past a migration“ |
| `migrate baseline` | Exit-1-Sammelsatz, „Safe to re-run with the same version. If a declaration exists, it is almost always `migrate done` that was wanted“ | zwei `1`-Zeilen + NOTES 3 |
Keine Abweichung zum Code gefunden.
Changelog: Content migrations published als 243db66.
Gruppe Private instances (upstream merge|verify) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
Kommando
Alter Satz
Ziel
upstream merge
„The code procedure behind instructions/private-instance.md § ‚Taking a stack update‘.“
SEE ALSO
upstream merge
„… stops, untouched, if git refused to open a merge at all (unrelated histories), since without a MERGE_HEAD every stack path would read as ‚the upstream deleted it‘“
Verhalten → NOTES 3; Begründung steht bereits als Kommentar im Merge-Schritt (upstream_cmd.py, „without MERGE_HEAD, _tree_paths(\"MERGE_HEAD\") is empty …“)
upstream merge
„never the stage directory wholesale, because reports/ is gitignored apart from its contract and holds local, non-recomputable data (…) that no merge has business deleting“
Verhalten → NOTES 4 („untracked and ignored local data under a stage … is never deleted“); Begründung steht bereits im Docstring zum Zurücksetzen der Stages (upstream_cmd.py ~Zeile 133)
upstream merge
„exactly the paths chemenu.ownership.is_stack_owned recognises as machinery (…)“
„re-checks the resulting range with the same logic as upstream verify; a finding there is a loud, uncommitted-nothing-rolled-back error, because the merge commit already exists and needs a human's eyes, not an automatic repair“
Verhalten → NOTES 7 + eigene 1-Zeile; Begründung steht bereits in _postcheck_failure_message („the state belongs in front of you, not behind an automatic …“)
upstream merge
„Not idempotent - see the tool error contract below“
NOTES 9, Verweis auf die alte Tabelle entfällt
upstream merge
Exit-1-Sammelsatz
sechs 1-Zeilen; neu aus dem Code: Fetch fehlgeschlagen / HEAD löst nicht auf, ein git-Schritt in der offenen Merge schlägt fehl, Postcheck-Leck (stand bisher nur in der Reaktion)
upstream merge
„Not idempotent, and not safe to retry unchanged. For a dirty tree …: fix … retry once. For a real conflict: do not retry, do not force - resolve … If the postcheck … finds a leak, the merge commit already exists and is not rolled back … this is a bug report, not a retry“
je ON-FAILURE-Zeile wörtlich + NOTES 9 + NEVER
upstream verify
„Shares its check with upstream merge's own postcheck, so a hand-resolved merge conflict, or a dist upgrade, can be verified the same way.“
NOTES 2
upstream verify
„… exempt from the Iteration Budget Gate, like migrate verify“
NOTES 4 ohne Querverweis
upstream verify
Exit-1-Sammelsatz + Reaktion
zwei 1-Zeilen, Reaktionen wörtlich; NEVER aus „A finding is not fixed by re-running“
Keine Abweichung zum Code gefunden. (#144 betrifft auch network: dieser beiden Kommandos – unverändert gelassen.)
**Changelog:** Content migrations published als `243db66`.
**Gruppe Private instances (`upstream merge|verify`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
| Kommando | Alter Satz | Ziel |
|---|---|---|
| `upstream merge` | „The code procedure behind `instructions/private-instance.md` § ‚Taking a stack update‘.“ | SEE ALSO |
| `upstream merge` | „… stops, untouched, if git refused to open a merge at all (unrelated histories), since without a `MERGE_HEAD` every stack path would read as ‚the upstream deleted it‘“ | Verhalten → NOTES 3; Begründung steht bereits als Kommentar im Merge-Schritt (`upstream_cmd.py`, „without MERGE_HEAD, `_tree_paths(\"MERGE_HEAD\")` is empty …“) |
| `upstream merge` | „never the stage directory wholesale, because `reports/` is gitignored apart from its contract and holds local, non-recomputable data (…) that no merge has business deleting“ | Verhalten → NOTES 4 („untracked and ignored local data under a stage … is never deleted“); Begründung steht bereits im Docstring zum Zurücksetzen der Stages (`upstream_cmd.py` ~Zeile 133) |
| `upstream merge` | „exactly the paths `chemenu.ownership.is_stack_owned` recognises as machinery (…)“ | NOTES 5, Funktionsname entfällt (Implementierungsdetail) |
| `upstream merge` | „re-checks the resulting range with the same logic as `upstream verify`; a finding there is a loud, uncommitted-nothing-rolled-back error, because the merge commit already exists and needs a human's eyes, not an automatic repair“ | Verhalten → NOTES 7 + eigene `1`-Zeile; Begründung steht bereits in `_postcheck_failure_message` („the state belongs in front of you, not behind an automatic …“) |
| `upstream merge` | „Not idempotent - see the tool error contract below“ | NOTES 9, Verweis auf die alte Tabelle entfällt |
| `upstream merge` | Exit-1-Sammelsatz | sechs `1`-Zeilen; neu aus dem Code: Fetch fehlgeschlagen / `HEAD` löst nicht auf, ein git-Schritt in der offenen Merge schlägt fehl, Postcheck-Leck (stand bisher nur in der Reaktion) |
| `upstream merge` | „**Not idempotent, and not safe to retry unchanged.** For a dirty tree …: fix … retry once. For a real conflict: **do not retry, do not force** - resolve … If the postcheck … finds a leak, the merge commit already exists and is **not** rolled back … this is a bug report, not a retry“ | je ON-FAILURE-Zeile wörtlich + NOTES 9 + NEVER |
| `upstream verify` | „Shares its check with `upstream merge`'s own postcheck, so a hand-resolved merge conflict, or a `dist upgrade`, can be verified the same way.“ | NOTES 2 |
| `upstream verify` | „… exempt from the Iteration Budget Gate, like `migrate verify`“ | NOTES 4 ohne Querverweis |
| `upstream verify` | Exit-1-Sammelsatz + Reaktion | zwei `1`-Zeilen, Reaktionen wörtlich; NEVER aus „A finding is not fixed by re-running“ |
Keine Abweichung zum Code gefunden. (#144 betrifft auch `network:` dieser beiden Kommandos – unverändert gelassen.)
Changelog: Private instances published als b83a398.
Gruppe Instance health (doctor) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
Alter Satz
Ziel
NOTES (ein Satz über alle Checks)
NOTES 1–10, ein Prüfbereich je Stichpunkt; Ergebnisstufen (OK/WARN/FAIL) unverändert
„(… a file still carrying the template's sentinel is a FAIL, since a renamed template is not a filled one)“
Regel → NOTES 2; Begründung steht bereits im check_personalization()-Docstring („looks present and answers nothing“)
„(… a FAIL on any of the three, because xref/cite write out of it)“
Regel → NOTES 3; der „because“-Satz entfällt: check_conventions() begründet den FAIL anders (die Datei bindet jede Seite) und nennt die Überschriften ausdrücklich „only cosmetic now“ – der alte Satz war veraltete Begründung, keine Regel
„malformed is the one FAIL here, since a broken opt-in must not silently disable the limits it exists to enforce“
Regel → NOTES 5; Begründung steht bereits im Docstring von check_upload_intake
„malformed is FAIL for the same reason the upload opt-in is“
Regel → NOTES 6 ohne Querverweis; Begründung im Docstring des Tracker-Checks („a broken one must not read as ‚nothing configured‘“)
„neither ever FAILs, an app that is simply not running is not a fault“
Regel → NOTES 7; Begründung im Docstring des Tracker-Checks („the app being closed is normal, not a fault“)
„- see chemenu.session“
entfällt (Implementierungsverweis); SEE ALSO instructions/session-setup.md
„never FAIL, see EVALS.md“
NOTES 10 + SEE ALSO
„Read-only, exit 1 only on a FAIL (a missing remote, session id, or VERSION is a WARN, not a fault). Exempt …“
NOTES 11/12
Exit 1 + Reaktion
unverändert
Keine Abweichung zum Code gefunden.
**Changelog:** Private instances published als `b83a398`.
**Gruppe Instance health (`doctor`) – entfernte/umformulierte Sätze mit Ziel** (Invariante, vor dem Publish)
| Alter Satz | Ziel |
|---|---|
| NOTES (ein Satz über alle Checks) | NOTES 1–10, ein Prüfbereich je Stichpunkt; Ergebnisstufen (`OK`/`WARN`/`FAIL`) unverändert |
| „(… a file still carrying the template's sentinel is a `FAIL`, since a renamed template is not a filled one)“ | Regel → NOTES 2; Begründung steht bereits im `check_personalization()`-Docstring („looks present and answers nothing“) |
| „(… a `FAIL` on any of the three, because `xref`/`cite` write out of it)“ | Regel → NOTES 3; der „because“-Satz entfällt: `check_conventions()` begründet den `FAIL` anders (die Datei bindet jede Seite) und nennt die Überschriften ausdrücklich „only cosmetic now“ – der alte Satz war veraltete Begründung, keine Regel |
| „malformed is the one `FAIL` here, since a broken opt-in must not silently disable the limits it exists to enforce“ | Regel → NOTES 5; Begründung steht bereits im Docstring von `check_upload_intake` |
| „malformed is `FAIL` for the same reason the upload opt-in is“ | Regel → NOTES 6 ohne Querverweis; Begründung im Docstring des Tracker-Checks („a broken one must not read as ‚nothing configured‘“) |
| „neither ever `FAIL`s, an app that is simply not running is not a fault“ | Regel → NOTES 7; Begründung im Docstring des Tracker-Checks („the app being closed is normal, not a fault“) |
| „- see `chemenu.session`“ | entfällt (Implementierungsverweis); SEE ALSO `instructions/session-setup.md` |
| „never `FAIL`, see `EVALS.md`“ | NOTES 10 + SEE ALSO |
| „Read-only, exit 1 only on a `FAIL` (a missing remote, session id, or `VERSION` is a `WARN`, not a fault). Exempt …“ | NOTES 11/12 |
| Exit 1 + Reaktion | unverändert |
Keine Abweichung zum Code gefunden.
Changelog: Instance health (5bfbb49), Abschluss (5aae7fe: str-Form von NOTES entfernt, zwei Tests über das echte Register) und README-Nachzug (5fe6003) published. Body auf den Endstand umgeschrieben, alle Akzeptanzkriterien abgehakt mit Beleg. CI grün bis 5aae7fe; geschlossen wird nach grünem Lauf 402 (5fe6003).
**Changelog:** Instance health (`5bfbb49`), Abschluss (`5aae7fe`: `str`-Form von NOTES entfernt, zwei Tests über das echte Register) und README-Nachzug (`5fe6003`) published. Body auf den Endstand umgeschrieben, alle Akzeptanzkriterien abgehakt mit Beleg. CI grün bis `5aae7fe`; geschlossen wird nach grünem Lauf 402 (`5fe6003`).
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.
Erledigt (2026-09-26). Alle 61 Kommando-Datensätze sind redaktionell umgebaut, in 14 Gruppen plus Abschluss, je Gruppe ein Publish und ein Version-Bump im laufenden Kandidaten (7.1.0-beta.7 bis beta.21). Nur Text, kein Verhalten – mit einer Ausnahme im Datenmodell (unten E1/E2), das die neue Form trägt. Folgebefunde: #144, #145, #146.
Ausgangslage (nach #121)
#121 machte einen Datensatz je
wikitool-Kommando zur einzigen Quelle fürwikitool <cmd> -h, den Index und die generiertetools/CONTRACT.md, und füllte ihn mechanisch: der alte Purpose-Text 1:1 in NOTES, „Exit 1 means“/„Retry policy“ 1:1 in EXIT STATUS/ON FAILURE, EXAMPLES/NEVER/SEE ALSO leer. Die Information war vollständig, aber schlecht nutzbar: NOTES mischte Verhalten, Verbote und Begründung in Absätzen bis > 4000 Zeichen, viele Texte verwiesen auf andere Kommandos („same posture asnew project“), Vergangenheitsformulierungen standen neben aktuellem Verhalten, und es gab kaum kopierbare Aufrufe.Ergebnis
Jeder Datensatz hat jetzt:
sync,publish,upload accept,new project --resume).cite, generierte Dateien und.wikitool-kb.json, Invariante 6 fürbudget reset, § Routing fürsearch/types list), steht sie zusätzlich hier.dist exportfehlende Lizenz,newCapture-Feld,eval score --fail-on-error, Teilschreibfehler beirename/rm/move/cite sync).X“ mehr; SEE ALSO nennt verwandte Kommandos und die Instruction, die das Kommando nutzt.dist_cmd.run_upgradeStempel,task_cmdModuldocstring,cite_cmd.sync_page,migrate_cmddone/verify,docs_verify.check_command_contracts). Ein veralteter Code-Kommentar (dist_cmd.build_planzuincoming/) wurde dabei korrigiert.Entscheidungen
CommandRecord.notesist ein Tupel, gerendert als--Liste. Die Übergangsformstrwurde nach der letzten Gruppe entfernt; einstrwird jetzt beim Import abgelehnt (5aae7fe).Failure(cause, reaction, code=1, label="")ersetztFailure(label, exit_1, retry). EXIT STATUS rendert<code> <cause>, ON FAILURE<cause> -> <reaction>; ohnereactionnur die EXIT-STATUS-Zeile.codeist 0, 1 oder 42; explizite 42-Einträge ersetzen die generische Gate-Zeile; 42 ohnegateswird beim Import abgelehnt (fd0f60b).cli_contract.py:token_gate_reaction(flag)für die Reaktion auf Token-Gates.version bump --patch --impact low.docs/-/Contract-Seite; Geschichte entfällt.CommandRecord;tools/README.md§ Adding a command undREADME.mdverweisen darauf bzw. beschreiben die Form.Invariante
Keine Regel geht verloren. Für jede Gruppe liegt vor ihrem Publish ein Kommentar mit jedem entfernten oder umformulierten Satz und seinem Ziel (14 Gruppenkommentare, Git bis Instance health).
Stand je Gruppe
fd0f60bdf8ff2f9d6ca6bd0a740aa1f3c470b2d93abe78ad2964978ab9c22f79617d7271efdbe243db66b83a3985bfbb49str-Form entfernt, Tests über das echte Register5aae7fe5fe6003Vergangenheitsformulierungen (Fundliste,
grepnach „is gone“, „are gone“, „used to“, „previously“, „Before“, „no longer“)xref link-sourcexref.py)raw acceptraw/no longer addresses by type“publishpublishwhose push failed no longer strands it“publish--yes/-yare gone …“dist exportwork close,instructions sync,dist upgrade,version bump,version regrade,version release,doctorversion regrade/doctornach dem Umbau ohne Treffer)upstream mergeAkzeptanzkriterien
test_cli.py:test_every_record_shows_at_least_one_example,test_every_gated_record_shows_its_re_run_after_exit_42).grepüber die generierte Region vontools/CONTRACT.mdnach „same as“, „same posture“, „like“, „same reasoning“, „see its“: keine Treffer; „the same way“ nur noch als Selbstbezug (new,upstream verify`).grepohne weitere Fundstelle).docs verify,instructions verifyund die vollepytest-Suite waren nach jeder Gruppe grün (zuletzt 1522 Tests). CI grün für jeden Commit vonfd0f60bbis5fe6003(je Stack-Commit zwei Push-Läufe, zuletzt Läufe 400/401 für5aae7feund 402 für den README-Nachzug).Außerhalb (als eigene Issues)
network:beisync/publish/upstream *und die Zählung inversion check.log append --body-filemit fehlender Datei: Traceback stattERROR.lint-Zitatlimit; sechs direkt angeglichene Stellen zur Bestätigung).ERROR-Zeile einen Python-Traceback aus.Ablauf
Die Sitzung lief ab Gruppe 11 mit einer eigenen
WIKITOOL_SESSION_IDje Gruppe (instructions/session-setup.md§ Multi-unit runs); die ersten zehn Gruppen teilten sich einen Zähler und liefen beim Publish der zehnten in das Iteration Budget Gate. Weiter ging es nach Freigabe durch den Betreiber. Alle drei Phasen – Entwurf/Datenmodell, der mechanische Umbau je Gruppe und der Abschluss – liefen auf Claude Opus 5.5.Changelog:
status/blockedentfernt – #121 ist seit 2026-09-26 geschlossen. Body um Stand, Entscheidungen E1–E5 (Datenmodell für NOTES und Exit-Ursachen, Konstanten, Version, Ziele), eine Gruppen-Fortschrittstabelle und die Fundliste der Vergangenheitsformulierungen ergänzt. Abweichung Text ↔ Code als #144 ausgelagert.Gruppe Git (
sync,publish) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)Mit dabei: Modelländerung E1/E2 (
notesals Tupel,Failure(cause, reaction, code, label)). Die Feldumbenennung ist mechanisch über alle Datensätze; bei noch nicht umgebauten Kommandos lautet ON FAILURE jetzt<alter Exit-1-Text> -> <alter Retry-Text>, Wortlaut unverändert.synctouched_files()- undreconcile()-Docstringpublishbelow)“wikitool publish0-Zeileinstructions/session-setup.md)“instructions/session-setup.mdpublish“sync_command-Docstring1, ergänzt um „aborted cleanly“ (steht schon inatomic)--confirm-rebase <token>clears it, and a wrong, invented, or superseded token exits 42 again“42+ ON FAILURE übertoken_gate_reaction("--confirm-rebase")(Wortlaut: zeigen, stoppen, nach Freigabe Wiederholungszeile, falsches/erfundenes/veraltetes Token → erneut 42) + NEVER „Never pass a--confirm-rebasetoken the user has not seen and approved“reconcile()/rebase_review_token())publishsync(skipped for--no-push), then stage all changes, commit, and push“--no-push) + Bullet 2 (Reconcile ausgeschrieben statt „likesync“)1(eigene Ursache)git push <branch>cannot quietly publish a ref other than the commit just made“branch_mismatch_message()-Docstringinstructions/setup-instance.mdstep 14), while a genuine detached HEAD is still refused“instructions/setup-instance.mdpublishwhose push failed no longer strands it, and neither does a branch the remote has never seen“_local_ahead_of_remote()publish_command--threshold(default 10) counted files … exits 42 (EXIT_NEEDS_CLEARANCE) … – a third outcome distinct from success (0) and a validation error (1)“42(eigene Ursache) + NOTES Bullet 7; Konstantenname und „third outcome“-Erklärung → stehen bereits im Moduldocstring vongit_publish.pytoken_gate_reaction("--confirm")work/… generated files … The refusal line accounts for both, by reason.“GENERATED_PATHS/GATE_EXEMPT_PREFIXESgit remote get-url --push, so a repointed remote does not pass on its name“42(eigene Ursache, ergänzt um „resolves to no push URL“ auspublish_remote_refusal()) + NOTES Bullet 101(eigene Ursache „unreadable or no usableallowed_push_urls“)instructions/gates.md“--yes/-yare gone and now fail with an explicit error“1„--yes/-ywas passed – the flag does not exist …“, Gegenwartsform (Fundliste erledigt)--path(repeatable) scopes the whole operation …“touches_stack_machinery()-Docstring--yes/-ywas passed“1-Zeilen (git, Branch,--yes)syncperforms), or the Publish-Remote Gate refuses“42-Zeilen; „same reconcilesyncperforms“ ersetzt durch die Beschreibung der Ursache selbst--confirm <token>or--confirm-rebase <token>line to re-run, and re-running without it exits 42 again“token_gate_reaction()+ NEVER (kein ungesehenes Token)atomic: „both gates run before staging“publishhat drei Gates, alle laufen vor dem Staging (Textkorrektur, kein Verhalten)--branch <checked-out branch>, then retry once“ – deckt sich mitbranch_mismatch_message()Neu: EXAMPLES (Normalfall, Wiederholung nach Mass-Update-42, Wiederholung nach Rebase-Review-42) für
publish, zwei fürsync.Gruppe Catalog and log (
index rebuild,log append,log status) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)index rebuildkb/index.mdbecomes a map (statistics, one row per collection and per area, links to the shards)“INDEX.mdin each collection. An area past 50 rows gets its own shard.“catalog.py:count > SHARD_THRESHOLD, 50)1„An I/O error while writing or removing a catalog file (rare)“find_nested_pages), Verhalten von--dry-runlog appendkb/log.md.“format_log_entry)--opor unreadable--body-file“1-Zeilenkb/log.mdbefore retrying“Abweichung gefunden: eine unlesbare
--body-fileendet in einem Traceback, nicht in einerERROR-Zeile → #145. Der Datensatz beschreibt weiter das zugesagte Verhalten; #145 hält Code und Text zusammen.log statuswiki-lintals nächsten Schritt) + SEE ALSOtools/CONTRACT.md§ Maintenance schedulekb/log.mdis missing or empty).“0-Zeile; „reports 0“ an den Code angepasst: eine fehlende Datei meldet „nothing logged“lint, sonst seit Beginn) und GesamtzahlGruppe Distribution and versioning – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)
Alles Nicht-Aufgeführte ist unverändert in einen NOTES-Stichpunkt gewandert (nur Satzgrenzen verschoben).
dist exportraw//incoming/), 4 (Templates), 5 (Stempel)raw/is a date shard rather than a hand-picked type, so a fresh export no longer creates any type subdirectories under either root …)“plan["raw/.gitkeep"]inbuild_planincoming/.gitkeepis trackable and survives becoming a git repository, so a plain clone gets the directory without any bootstrap step“.gitignoreexcludesincoming/… bootstrap.md re-creates it“) und war seit/incoming/*+!/incoming/.gitkeepveraltet – korrigiert (nur Kommentar)docs/ownership-and-templates.mdinstructions/setup-instance.md.“VERSION“1-Zeilen<target>at an empty (or new) directory and retry. Never merge into a non-empty one by hand“1: fehlende Lizenzdatei (REQUIRED_ROOT_FILES), Leak im Plan (find_leaks, Reaktion aus der Fehlermeldung); NOTES:--dry-rundist upgrade.sha256, eine Top-Level-Verzeichnischemenu.ownership.is_export_stub/is_upgrade_preservedentfallen – Implementierungsdetail, steht am Code)_refusal_for_blocked()-Docstring--keep-local/--take-release, „decided per path and compose“--take-releasepath that this run does not report as locally changed is refused … it is a mistake in the argument rather than a state of the tree, and a path that silently did nothing would report a successful upgrade …“1+ ON FAILURE; Begründung steht bereits im_resolve_take_release()-Docstring und am--dry-run-Kommentar--keep-localrun the new stamp is still written whole … the stamp is the baseline for the next comparison, not a literal inventory … That is what keeps a skipped file diverging …“shutil.copy2(stamp_path, …)inrun_upgrade--prunechemenu.kb_state.chainover the new tree'sinstructions/migrations/, read via adirectoryargument toload_migrations)“1-Zeile; die Reihenfolge als NOTES 12success("Already at …"). → EXIT STATUS0-Zeile „equals … no-op success“,1nur „older / pre-release without--pre“instructions/upgrade-instance.md… resumes atinstructions sync.“run_upgradeINSTALL.md§ ‚Version und Updates‘“migrate baseline,migrate status, commit/stash,upstream merge)atomic: „Yes for the refusal cases above - nothing is written.“version show„Development tree, or a distribution with its export date and origin“ → NOTES 1, um Inhalt aus
_describe_origin()ergänzt. „Barewikitool versionis an alias“, „Read-only, offline, exempt“ → NOTES. Neu:--json(aus dem Code).version checkwikitoolthat make a network call …“--timeout-Default ergänzt--urlergänzt (Code:url or update_url(stamp))1für fehlendes/kaputtesVERSION(Code)version notesCHANGES.mdis a stub … permanently unanswerable exactly where the release notes are most needed.“version_cmd.pyund imfetch_latest_notes()-Docstringnotes_command-Docstringupdate_urlis the one URL a stamp records, and composing a by-tag URL out of it would be guessing at an API shape)“fetch_latest_notes()-Docstringrelease.yml1-Zeilen, je mit eigener Reaktion; „Every one of those failures names the stamp'srelease_url“ → NOTES 6; „Safe to retry“ → NOTES 7version bump--impact, and aVERSION/newest-changelog-entry mismatch.“1(zwei Zeilen)bump_command-Docstring unterhalb\f--breakingreason“--breakingreason“ („deliberately“ = Begründung, Docstring)1-ZeilenVERSIONand the top ofCHANGES.mdbefore retrying“version regradeDer alte NOTES-Text war beim mechanischen Übertrag verstümmelt („1-based rendered position (no arguments - the correction path …)“) – aus Summary, NOTES und Docstring neu gefasst, Regelgehalt vollständig. „like
version notes“ / „likeversion bump“ → durch die Tatsache selbst ersetzt (exempt / counted). Exit-1-Sammelsatz → zwei Zeilen. Alte Reaktion („The bare listing never writes anything. A write is not idempotent against a changed list … list again before retrying“) → NOTES 1/5 + NEVER.version release„Ends the pre-release phase
version bumpstarted“ → NOTES 1 ohne Querverweis. „Commits nothing and pushes nothing (invariant 5)“ → NOTES 5, Verweis entfällt. „Refuses whenVERSIONis already a release …, or when the changelog's newest entry does not match“ → EXIT STATUS. Alte Reaktion („Not idempotent … a release-shapedVERSIONmeans it already ran“) → NOTES 6, ON FAILURE (Zeile 1) und NEVER.Gruppe Pages (
new,task new|list|close,touch,rename,rm,move) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)Nicht Aufgeführtes ist wortgleich oder nur an den Satzgrenzen verschoben in NOTES gewandert.
new<type-name>: Typ-Spec,default:nur beirequired:,--set/\,, „Seetypes list/types describe“_build_frontmatter()-Docstringproject: gesamte Mehrsatz-Notizneeds_clearance(), same posture as the four named gates, without being a fifth one - see that class's docstring)“HumanInterventionRequired-Docstringnew/xref/log appendonly produce structurally-correct frontmatter … prose … written by the LLM afterwards“new(die anderen Kommandos tragen ihre eigene Aussage)new <type>: „Duplicate page title, unknown type, invalid--setvalue, or araw_filespath that doesn't exist“1-Zeilennew project: „Everythingnew <type>covers, plus: …“new <type>-Zeilen gelten ohne Label für alle Varianten); „name taken in the tracker“, „read-only access path“ je eigene1-Zeile mit Labelnew project; „--resumefor another type“ eigene1-Zeile--set, or a read-only access path is not transient, same asnew <type>- the last of those … refuses on every--resumeretry too, since nothing about the config changes by asking again“new <type>“ ersetzt durch „Not transient“superproductivity-only …; re-run with--resumeonce that is done - it re-verifies … and exits 42 again unchanged …“42+ ON FAILURE, Regelgehalt unverändertcaldavnever produces this outcome -MKCALENDAR…“1: Capture-Feld fehlt oderunknown(Meldung mit Beispiel);1: Seitenschreiben nach bestätigtem Tracker-Projekt gescheitert →--resume(aus der Fehlermeldung); NOTES 4touchAlle Sätze in NOTES 1–8 übernommen. „same rules as
new --set“ → Tatsache selbst („\,is a literal comma“). Exit-1-Sammelsatz → vier1-Zeilen. „Fix the argument and retry once“ → ON FAILURE; „Safe to re-run as-is:--setand--addare idempotent …“ → NOTES 8. „Refused with the command that owns them instead“ → NOTES 4 + NEVER. Neu:--no-date/--dry-run(aus dem Options-Text).task newnew project, and the last one their split needed - seedocs/knowledge-and-commitment.md.“task_cmd.pyund auf derdocs/-Seite; SEE ALSO--inbox(… a deliberate exit with a cost: an item filed there never appears inreview…)“--notes… stored verbatim, never parsed - the same posture aWAITINGitem's own title already has …“.wikitool-tasks.jsonfails immediately with the same ‚no tracker configured‘ message asreview“access: "api"instance … - same posture asnew project“new project, never exits 42: every provider offering a write path at all has a real item-creation call (…)“task_cmd.py(neu)1-Zeilen, Reaktionen aus der alten Retry-Zeile verteiltnew project…“ (Retry-Zeile)--projectrefuses rather than silently falling into the inbox“, „never created and never searched or guessed“task list„the id source
task closeand the review's own … findings need“ → NOTES 2. „Works on either access mode a provider offers, unlike the write commands below“ → NOTES 3 ohne Querverweis. „same ‚no tracker configured‘ message asreview/task new“ → ON FAILURE ohne Querverweis. „--projectmatching no tracker project prints ‚No open items‘, sinceTaskReader.open_itemsdoes not distinguish …“ → EXIT STATUS0+ NOTES 4 (Methodenname entfällt, steht am Code). Retry-Zeile „… not an error here - see its Commands row“ →0-Zeile, Verweis auf die alte Tabelle entfällt.task close„never a title - the tracker-side identity is opaque, unlike the project name …“ → Verhalten NOTES 2 + NEVER; Begründung → Moduldocstring (neu). „The only closing write this stack makes: no ‚move a reminder‘, no ‚remove an item‘“ → NOTES 1. „same posture as
task new“, „same reasoning astask new“ (2×) → durch die Tatsache ersetzt (NOTES 4/5). Exit-1-Sammelsatz → drei Zeilen.renameNOTES 1/2 wortgleich. Exit-1-Sammelsatz → drei Zeilen; neu
1für Schreibfehler mittendrin (aus der Fehlermeldung). „Safe to retry once as-is; each page's rewrite is idempotent“ → NOTES 3 + ON FAILURE (Schreibfehler). „Use--dry-runfirst to see the blast radius“ → NOTES 4. „Never fix up references by hand instead“ → NEVER. Reaktion für „neither is a page“ aus der Fehlermeldung (newbzw.xref remove).rm„Refuses without
--yeswhile other pages still reference it“ → NOTES 3 + EXIT STATUS. „Strips …; leaves prose and inline citations in place and reports them“ → NOTES 1/2. „For ‚still referenced‘: show the user the inbound list, get approval, then re-run with--yes“ → ON FAILURE + NEVER. „Prose references it reports afterwards are an editorial fix, not a retry“ → NOTES 2. Neu aus dem Code:1Schreibfehler mittendrin (Seite nicht gelöscht),--dry-run, nicht idempotent (PROPERTIES sagt es schon).moveNOTES wortgleich aufgeteilt; „(
TypeResolver.compute_target_dir)“ entfällt (Implementierungsdetail); „(lint'sMisplaced Pagesfinding is the advisory that this fixes, and itsNested Pagesfinding the hard one - seelint)“ → NOTES 2 ohne „seelint“,lintin SEE ALSO. Exit-1-Sammelsatz → drei Zeilen +--reconcile-Teilfehler (aus der Fehlermeldung). „Safe to retry once as-is …“ → NOTES 5 + ON FAILURE. „Use--dry-runfirst“ → NOTES 6. „Never choose a directory by hand instead“ → NEVER. Neu: „Runwikitool index rebuildafterwards“ (Erfolgsmeldung des Kommandos).Gruppe Links and citations (
xref add|remove|link-source,links show,cite id|add|sync) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)Nicht Aufgeführtes ist wortgleich oder nur an den Satzgrenzen verschoben in NOTES gewandert.
xref addrelated:field“1-Zeilen; „a page's type“ präzisiert auf „A's type“ (Code prüft nur A:_require_related_field(page_a, …))1-Zeile, inklusive „authorises no labels at all“ (zweiterfail()in_check_authorised)xref remove„it is the cleanup command … rather than the strict inverse“ → NOTES 1. „a leftover written before the check above existed has to stay repairable, or the page is a dead end“ → Begründung, steht bereits im Docstring von
_require_related_field(„One command created a state another could not undo“). „Idempotent“ + Reaktion „removing an absent link is a no-op“ → NOTES 5 / ON FAILURE. Neu: NEVER „Never hand-edit a page-ref array“ – aus NOTES 4 („without hand-editing frontmatter“).xref link-sourcexref.py(„It used to write four things at once …“) (Fundliste erledigt)1-Zeilen; der Teilerfolg (übrige Ziele verlinkt, dann Exit 1) als NOTES 4 – aus dem Code--dry-runfirst; safe to retry.sources trace --page …shows who was already linked“links show„The inbound half is derived rather than stored - that is what makes it complete, and it is the answer authored directional edges would otherwise have nowhere to come from.“ → Verhalten NOTES 2; Begründung steht bereits im
inbound()-Docstring. Neu:--json.cite idAlle drei Sätze in NOTES. Neu: NEVER „Never paste an id from here into a page by hand“ – Quelle ist AGENTS.md Invariante 1 („never compute or paste a
[^cite-id]by hand -cite addmints it and prints the marker“), hier als Ausgabe wiederholt.cite addNOTES-Satz aufgeteilt (NOTES 1–4). Exit 1 „Page or source not found“ → zwei Zeilen (die Quellseiten-Meldung nennt den Grund „dangling reference“). „Safe to retry; upserting the same … pair twice reuses the existing id“ → NOTES 2. Neu: NEVER aus AGENTS.md Invariante 1 (wie
cite id).cite sync„A page still carrying the pre-4.0.0 undelimited block is converted …“ → NOTES 3. „the marker carries the region's identity now, so re-rendering it under this instance's heading is a repair rather than a rename“ → Begründung →
sync_page()-Docstring (neu). „Safe to retry freely. An undefined-reference report is not a failure …“ → NOTES 2/4. Neu1: Schreibfehler mittendrin (aus der Fehlermeldung).Gruppe Finding and checking (
lint,search,review) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)Regelkorrektur für dieses Paket: In den Gruppen Git, Catalog and log, Distribution and versioning und Links and citations habe ich fünf Textstellen direkt an den Code angeglichen, statt sie – wie „Außerhalb“ verlangt – als Befund auszulagern. Sie stehen jetzt zur Bestätigung in #146. Ab dieser Gruppe bleibt ein Text, der dem Code widerspricht, unverändert stehen und wandert nach #146 (erster Fall hier:
lint, Zitatlimit).lintkb_versionhas reached … - advisory below it, so a corpus mid-migration is not refused by the check measuring it)“lint_core.pyredundant_see_alsobzw. über dem Gate inlint_core.pyunsharded_collections()-Docstringunclassifiedis the visible fallback for a genuinely unclear source, not a defect)“unclassified_source_pages()-Docstring--full…--json…“--fail-on-error: hard findings exist“searchkb_scan.iter_kb_pagesexcludes (…)“api.searchand the MCPsearchtool carry, from one constant“kb/can add none of them but those“kb/yourself“)1-Zeilenreviewreports/file“chemenu.tasksentfälltdormant/completed/abandonednever fire, since those states mean the initiative not having a next action is expected rather than a problem)“review.py(Check stalled)1-ZeilenGruppe Provenance (
sources coverage|trace|rebuild-index) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)sources coverage--json)sources tracesources trace--rawnames a file no source page covers (reported as a plain finding plus exit 1, not the usualERROR-prefixed rejection)“1-Zeilen, Klammer wörtlich in der zweitensources tracesources rebuild-indexkb/provenance.mdreverse index …“--dry-run, aus dem Options-Text)sources rebuild-indexsources rebuild-indexkb/provenance.md“ – AGENTS.md Invariante 1 nennt die Datei ausdrücklich als generiertKeine Begründungssätze, keine Querverweise, keine Abweichung zum Code gefunden.
Gruppe Raw material and uploads (
raw accept,upload list|show|accept|reject) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)raw acceptraw/no longer addresses by type“raw/does not address by type“ (Fundliste erledigt)raw/CONTRACT.md‚Getting a file in‘)“ und alte NOTES „Seeraw/CONTRACT.md…“types describe source;unknownis refused, backfill-only) - the one moment both are knowable“raw/CONTRACT.md(Abschnitt ab Zeile 159)1-Zeile 4provenance.duplicate_raw_file_owners)“raw/CONTRACT.mdund am Code--replacesand renaming-in-incoming/without recommending either“--replaces(ein Absatz)raw/CONTRACT.mderklärt die flache Adressierungraw/CONTRACT.md„Fixed once, correctable only as a new edition“1-Zeilen mit Label der Variante--replacesand renaming inincoming/as the two routes and neither is the tool's to pick.“raw/CONTRACT.md(„An agent that gets this message does not pick a route on its own initiative - it shows the message to the human and waits“) + NEVER 2raw_cmd.py)--replaces-Zeilenupload list/upload show/upload rejectupload list: „(see the MCP read server design note)“ → SEE ALSOINSTALL-MCP.md§ Schritt 7; sonst wortgleich in NOTES.upload show: NOTES aufgeteilt, wortgleich.upload reject: „No gate - rejecting needs no clearance, only accepting does“ → NOTES 3; die Ledger-Reihenfolge stand in PROPERTIESatomicund steht jetzt zusätzlich in NOTES 2; Retry-Satz „Not idempotent … a retry reports ‚unknown id‘ - that is confirmation, not a failure“ → NOTES 4 + ON FAILURE.upload acceptincoming/<filename>already exists“1-Zeile1-Zeilen, eine42-Zeile--confirm <token>re-run line printed, and stop - the same rule as every other exit-42 gate (AGENTS.md invariant 6).“token_gate_reaction("--confirm")(zeigen, stoppen, nach Freigabe Wiederholungszeile) + NEVER „Never pass a--confirmtoken the user has not seen and approved“ (Invariante 6 selbst statt Verweis)incoming/<filename>is not fixed by retrying unchanged - rename or clear it first“Keine Abweichung zum Code gefunden.
Gruppe Workshop runs and session budget (
work new|close,budget status|reset) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)work new--dry-run)work newwork/CONTRACT.md“work new1-Zeilen; ergänzt um „does not exist“ und „raw/itself (empty run key)“ aus dem Codework new--againif the tree itself changed.“work newwork close--yes, because nothing in it is recoverable from the rest of the repo - the durable conclusions must already be inkb/“kb/“)work close--yeswas not passed“1-Zeilen; Reaktion für den unbekannten Schlüssel aus der Fehlermeldung („ls work/shows the open ones“)work closekb/, then re-run with--yes“work close--yesbefore the run's conclusions are inkb/“ – Aufruferseite der Pflichtbudget statusbudget: exemptin PROPERTIES sagt dasselbebudget reset--yes: clearing the counter is itself a way around the gate, so it needs the same explicit human approval“budget reset--all, aus der Summary/Synopsis), NOTES 3 (gezählt, ausbudget: counted), NEVER aus AGENTS.md Invariante 6 („Not …budget reset --yes“)Keine Abweichung zum Code gefunden.
Gruppe Types, instructions and docs (
types list|describe,instructions sync|verify|list,docs verify|toc|contract) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)types listtypes/*.mddirectly. Never fails. Safe to retry freely.“types describeroot: kbtype's contract reads as one answer even though it may live in two files“types describetypes_cmd.py(Zeile ~136) und imtoc.py-Moduldocstringinstructions syncinstructions/bootstrap.md“instructions sync1-Zeilen; Reaktion „Check whether the flagged target holds anything worth keeping, then re-run with--forceif not; otherwise fix the named cause and retry“ auf die beiden Zeilen verteiltinstructions syncatomic(„re-run converges“); NEVER „Never hand-edit a published copy“ – aus „the source always wins“ und der Reaktion voninstructions verifyinstructions verifyinstructions verifysynccopies it to a different depth than the source, so aSKILL.mdreferences a target as a repo-root-relative plain path instead - seeinstructions/CONTRACT.md§ …)“instructions verify1-Zeileninstructions verifysyncinstead of hand-editing the published copy - the source underinstructions/always wins“dev/-Verweis neue, der Ursache entsprechende Reaktionen („Link it …“, „Remove the reference or wrap it in adist:stripblock“ – Letzteres aus der Ausnahme in NOTES 5)instructions listsearchdeliberately coverskb/only.“docs verifydocs verifycheck_command_contractsdocs verifycli_contract.render_commands_region()would write“docs contractwould write“ – dieselbe Tatsache, als Kommando statt Funktiondocs verifyinstructions/dev/issue-tracking.md§ „Citing an issue in the repo“ (steht dort ausführlich)docs verifytoc.pydocs verifykb/predates the collection it now checks“docs verify1-Zeilen, davon neu „commands region stale →docs contract --apply“ (Prüfung stand in NOTES)docs verifydocs toctoc.py-Moduldocstring (zitiert die Quelle wörtlich)docs tockb/CONVENTIONS.md.templatecame to grow past the threshold …“<name>.template“); Begründung und Geschichte →toc.target_files()-Docstring (Zeile ~133)docs tocSKILL.mdis the one exception, and the same guidance is why: …“, „Human docs … are out of scope because AGENTS.md § File naming says …“toc.py-Moduldocstringdocs toc0-Zeile, wörtlich; der Index zeigt dadurchexit:0stattexit:0,1(in #146 zur Bestätigung eingetragen)docs toc--apply… Ifdocs verifystill reports a stale region afterwards … run it again“docs tocdocs verifychecks the result stays current the same way it checks every other generated-from-code copy“docs contractcli_contract.all_records()“, „docs verify'scheck_commands_region“, „likedocs toc“docs toc“ durch die Tatsache ersetzt (NOTES 2)Changelog: Types, instructions and docs published als
9617d72(nach Freigabe durch den Betreiber, ab jetzt je Gruppe eigeneWIKITOOL_SESSION_ID, z. B.issue-142/telemetry).Gruppe Telemetry (
eval sessions,eval score) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)eval sessionseval score--save)EVALS.md“ → SEE ALSOeval scoreeval sessionsto see which ids exist. A session records nothing when telemetry is off - … so an absent trace is not necessarily a fault. Safe to retry“eval score1:--fail-on-errorbei harten Fehlern oder verletzter Invariante (raise typer.Exit(code=1), Options-Text) – fehlte im Datensatz; eine Lücke, kein WiderspruchKeine Begründungssätze, keine Querverweise.
Changelog: Telemetry published als
71efdbe.Gruppe Content migrations (
migrate list|status|verify|done|baseline) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)migrate listmigrate statusoffereddocuments … bounded by the applied ledger rather than bykb_version- taking one deliberately does not move the version, so the version cannot say whether it was taken“done_command-Docstring („The record is the only thing that distinguishes an offer someone took … because the version stays put“)migrate status.wikitool-kb.jsonis missing - the content's shape is a question the tool refuses to answer by guessing.“VERSIONunlesbar, das stand schon in der alten Exit-1-Zelle; Begründung steht imstatus_command-Docstringmigrate statusmigrate baseline <version>once, then retry. Safe to retry freely otherwise“1-Zeilen mit je eigener Reaktion + NOTES 5migrate verifyverify_command-Docstring (neu)migrate verifylintcannot answer, since it reads a single revision …“verify_command-Docstring (neu);lintin SEE ALSOmigrate verify--fail-on-error… Also exits 1 if--fromis not a revision“1-Zeilen; neu NOTES 6 (ohne den Schalter immer 0)migrate verify--fail-on-errormeans ‚act on the findings‘ … A finding is never fixed by re-running - it names a page and what changed on it“migrate donedone_command-Docstringmigrate donedone_command-Docstring (neu ergänzt)migrate done1-Zeilenmigrate donemigrate statusand apply them in the order it prints - never force the order. Recording anofferedmigration is idempotent and safe to repeat“migrate done.wikitool-kb.json“ – AGENTS.md Invariante 1 nennt die Datei ausdrücklichmigrate baseline--force: advancing after a migration isdone, which checks the chain, and this command must not become the quiet way around it“--forceto advance the version past a migration“migrate baselinemigrate donethat was wanted“1-Zeilen + NOTES 3Keine Abweichung zum Code gefunden.
Changelog: Content migrations published als
243db66.Gruppe Private instances (
upstream merge|verify) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)upstream mergeinstructions/private-instance.md§ ‚Taking a stack update‘.“upstream mergeMERGE_HEADevery stack path would read as ‚the upstream deleted it‘“upstream_cmd.py, „without MERGE_HEAD,_tree_paths(\"MERGE_HEAD\")is empty …“)upstream mergereports/is gitignored apart from its contract and holds local, non-recomputable data (…) that no merge has business deleting“upstream_cmd.py~Zeile 133)upstream mergechemenu.ownership.is_stack_ownedrecognises as machinery (…)“upstream mergeupstream verify; a finding there is a loud, uncommitted-nothing-rolled-back error, because the merge commit already exists and needs a human's eyes, not an automatic repair“1-Zeile; Begründung steht bereits in_postcheck_failure_message(„the state belongs in front of you, not behind an automatic …“)upstream mergeupstream merge1-Zeilen; neu aus dem Code: Fetch fehlgeschlagen /HEADlöst nicht auf, ein git-Schritt in der offenen Merge schlägt fehl, Postcheck-Leck (stand bisher nur in der Reaktion)upstream mergeupstream verifyupstream merge's own postcheck, so a hand-resolved merge conflict, or adist upgrade, can be verified the same way.“upstream verifymigrate verify“upstream verify1-Zeilen, Reaktionen wörtlich; NEVER aus „A finding is not fixed by re-running“Keine Abweichung zum Code gefunden. (#144 betrifft auch
network:dieser beiden Kommandos – unverändert gelassen.)Changelog: Private instances published als
b83a398.Gruppe Instance health (
doctor) – entfernte/umformulierte Sätze mit Ziel (Invariante, vor dem Publish)OK/WARN/FAIL) unverändertFAIL, since a renamed template is not a filled one)“check_personalization()-Docstring („looks present and answers nothing“)FAILon any of the three, becausexref/citewrite out of it)“check_conventions()begründet denFAILanders (die Datei bindet jede Seite) und nennt die Überschriften ausdrücklich „only cosmetic now“ – der alte Satz war veraltete Begründung, keine RegelFAILhere, since a broken opt-in must not silently disable the limits it exists to enforce“check_upload_intakeFAILfor the same reason the upload opt-in is“FAILs, an app that is simply not running is not a fault“chemenu.session“instructions/session-setup.mdFAIL, seeEVALS.md“FAIL(a missing remote, session id, orVERSIONis aWARN, not a fault). Exempt …“Keine Abweichung zum Code gefunden.
Changelog: Instance health (
5bfbb49), Abschluss (5aae7fe:str-Form von NOTES entfernt, zwei Tests über das echte Register) und README-Nachzug (5fe6003) published. Body auf den Endstand umgeschrieben, alle Akzeptanzkriterien abgehakt mit Beleg. CI grün bis5aae7fe; geschlossen wird nach grünem Lauf 402 (5fe6003).Changelog: CI-Lauf 402 (
5fe6003) grün; Kopfzeile und CI-Kriterium auf den Endstand gesetzt, Issue geschlossen.