Kommando-Datensätze redaktionell ausbauen: NOTES aufteilen, Beispiele und Verbote ergänzen, Begründungen herauslösen #142

Closed
opened 2026-09-25 20:35:43 +00:00 by torben · 17 comments
Owner

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 „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.
  • #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.

**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.
torben added the prio/plannedsize/Larea/processkind/buildstatus/blocked labels 2026-09-25 20:35:43 +00:00
torben removed the status/blocked label 2026-09-26 06:17:59 +00:00
Author
Owner

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.
Author
Owner

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.

**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`.
Author
Owner

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
**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 |
Author
Owner

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 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.
Author
Owner

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 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).
Author
Owner

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).
Author
Owner

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 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 |
Author
Owner

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.
Author
Owner

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.
Author
Owner

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.
Author
Owner

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)
**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) |
Author
Owner

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.
Author
Owner

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:** 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.
Author
Owner

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:** 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.)
Author
Owner

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.
Author
Owner

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`).
Author
Owner

Changelog: CI-Lauf 402 (5fe6003) grün; Kopfzeile und CI-Kriterium auf den Endstand gesetzt, Issue geschlossen.

**Changelog:** CI-Lauf 402 (`5fe6003`) grün; Kopfzeile und CI-Kriterium auf den Endstand gesetzt, Issue geschlossen.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#142