-
v7.0.0 Stable
released this
2026-09-22 20:56:08 +00:00 | 88 commits to main since this release7.0.0 - 2026-09-22 - Task-Tracker-Anbindung: Vorhaben als Seitenart, Verpflichtungsschicht, Weekly Review als Read-Time-Join
Author: Torben Nehmer
Breaking Change:
- docs verify now requires an adopted
projecttype-spec (schema requiringstate:) and itskb/gtd/collection - an instance must adopt types/project.md(.schema.yaml) and kb/gtd/COLLECTION.md from their .template before docs verify passes again - superproductivity's provider section in .wikitool-tasks.json now requires 'access' ('api' or 'snapshot'), no default and no fallback between the two; 'db_path' no longer exists at all. An existing config must add 'access' and, if it used 'db_path', switch to 'backups_dir' (see INSTALL.md's example).
Migration: none required - No kb/ page content changes - the break is confined to .wikitool-tasks.json, an instance-owned, gitignored file every operator already edits by hand per INSTALL.md's example.
High impact
- SP-Zugriffsweg explizit (access: api/snapshot, #133) und follow_up_at-Korrektur (dueWithTime/dueDay, #135)
Medium impact
- Typ
projectund Collectionkb/gtd/: das Vorhaben als eigene Seitenart - Task-tracker provider layer, with a Super Productivity adapter
- wikitool review: the weekly GTD review as a read-time join
- wikitool new project: Seite und Tracker-Projekt unter einem Namen
- Skill weekly-review: turning wikitool review's findings into decisions
- Doku-Nachzug zu #119: die Verpflichtungsschicht erreicht Installation, Setup und docs/
- task new: einen zweiten Schreibweg in den Tracker (ein Posten, keine Seite)
- wiki-ingest: raw accept rückt hinter die Verpflichtungsentscheidung
- Weekly review proposes task new/task close; tracker gains a closing write path
Low impact
- new project: Testabdeckung fuer die required-responsibility-Ablehnung
- docs/-Nachzug: Exit 42 als Haltung, und die Adoption eines neu ausgelieferten Templates
- Skill-Namensfamilien: weekly-review -> gtd-weekly-review, dritte Person in allen Descriptions
- Veraltete Skill-Aufzaehlungen in der Instruction-Schicht nachgezogen
- gtd-weekly-review: task new nachgezogen, veralteter Begründungszeiger korrigiert
- instructions/CONTRACT.md drops other files' step counts from the copy-in-checklist rationale
Dieser Kandidat bringt die Verpflichtungsschicht in den Stack: ein neuer Seitentyp
projectund
die Collectionkb/gtd/geben dem Vorhaben (Ziel, Beteiligte, dauerhafter Status) eine eigene
Seitenart neben dem Artefakt; eine Task-Tracker-Provider-Schicht (chemenu.tasks) verbindet das
mit einem echten Tracker, mit Super Productivity als erstem Adapter;wikitool reviewliest beide
Seiten zur Laufzeit zusammen statt sie zu synchronisieren, und das neue Skill
gtd-weekly-reviewmacht dessen Funde zu Entscheidungen. Der Tracker bekommt zwei neue
Schreibwege dazu (task new,task close) neben den bestehenden Lesekommandos, undwiki-ingest
stellt seither bei jeder Quelle die Verpflichtungsfrage in beide Richtungen. Zwei
Grenzübertritte kommen mit:docs verifyverlangt jetzt den adoptierten Typprojectund die
Collectionkb/gtd/, und.wikitool-tasks.jsons Provider-Abschnitt verlangt ein explizites
access(api/snapshot) ohne Fallback aufdb_path. Der Rest der Bumps sind Nacharbeiten und
kleinere Korrekturen an genau dieser Naht - Doku-Nachzug, Namensfamilien, eine korrigierte
Zurückweisungs-Meldung, und die hier laufende Bereinigung veralteter Schrittzahlen in der
Instruction-Schicht.Typ
projectund Collectionkb/gtd/: das Vorhaben als eigene SeitenartGitea #119 (Paket #123): ein neuer Seitentyp
projectfuer das Vorhaben - Ziel, Beteiligte,
dauerhafter Status, offene Schleifen - abgegrenzt gegen das Artefakt (entity/codebase, seit
6.2.0).types/project.md/.schema.yamlund die neue Collectionkb/gtd/(Bereichehaus/,
finanzen/,technik/ueberresponsibility:) folgen exakt dem Muster, dasentity/concept/
source/comparisonschon vorgeben - kein Code noetig fuerwikitool new project,types list
oder den Template-Versand, alles daran ist bereits generisch.Neu ist nur eine Zeile Code:
projecttritt nebensourcein
kb_collections.STACK_REQUIRED_TYPES, nach demselben "fordern statt besitzen"-Idiom (D16) - ein
Type-Specname: project, dessen Schemastate:fuehrt, muss existieren, weil der
Wochenrueckblick (#125) sonst nichts hat, wogegen er ein Tracker-Projekt abgleichen kann. Das
machtdocs verifyzum Grenzuebertritt (siehe Breaking Change oben): eine Instanz, die die
neuetools/-Fassung uebernimmt, ohnetypes/project.md.templateund
kb/gtd/COLLECTION.md.templatezu adoptieren, faellt fortan durch, wo sie vorher bestand. Dabei
aufgefallen und mitkorrigiert:kb_collections.declaration_issues()s Meldung fuer eine fehlende
Pflicht-Collection nannte immersource, unabhaengig davon, welcher Typ tatsaechlich fehlte -
jetzt benennt sie den Typ, denstack_required_collection_owners()tatsaechlich dafuer
verantwortlich macht.kb/entities/COLLECTION.mdtraegt jetzt einengtd:-Block (vorerst nur
see-also), ohne den keine Kante von einer Entity auf ein Vorhaben autorisierbar waere - das ist
der Block, auf den #118 wartet.Task-tracker provider layer, with a Super Productivity adapter
Gitea #119 (Paket #124): die Schicht, ueber die
wikitoolan einen Aufgaben-Tracker kommt -
ohne dass eine Instruction je erfaehrt, welcher es ist (D25).chemenu.tasks.protocoldeklariert
TaskReader/TaskWriterals getrennte Protocols,chemenu.tasks.superproductivityimplementiert
beide gegen Super Productivity,.wikitool-tasks.json(chemenu.tasks.config) traegt Provider,
Verbindungsangaben und die drei Schwellwerte des Wochenrueckblicks (#125).wikitool doctor
berichtet den konfigurierten Provider, seinen Lesepfad-Status und ob seine lokale REST-API
antwortet - read-only, FAILt nur auf eine kaputte Konfiguration, nie auf einen nicht laufenden
Tracker. Kein Kommando entsteht hier (#124s eigene Abgrenzung) - das ist #125/#126.Zwei Zwischenbefunde aus der Umsetzung, gegen den tatsaechlichen Quellcode von
super-productivity/super-productivity(master, 2026-09-19) verifiziert:- Der Lesepfad liest keine
db.json- die gibt es auf dem Desktop nicht, der Live-Zustand
liegt in IndexedDB. Gelesen wird die neueste Datei unter dessen periodischen
Dateisystem-Backups (electron/backup.ts,<userData>/backups/<timestamp>.json), deren
Inhalt exakt die verifizierte Form hat. - Die lokale REST-API kann keine Projekte anlegen -
GET /projectsexistiert,
POST /projectsnicht (electron/local-rest-api-handler.service.ts). Damit entfaellt fuer
diesen Provider der in #119 D31 vorgesehene automatische Schreibpfad;create_projectprueft
weiterhin die Namenskollision (D8), verlangt dann aber menschliches Eingreifen statt es zu
simulieren:SuperProductivityWriter.create_projectwirft ein neues
chemenu.errors.HumanInterventionRequiredmit Anweisungen fuer den Menschen und einem
verify(), das den Lesepfad danach erneut befragt statt der Bestaetigung einfach zu glauben.
Dieselbe Klasse haengt sich an den bestehendenEXIT_NEEDS_CLEARANCE-Code (42) - keine neue
benannte Gate, aber dieselbe Haltung: dem Menschen die Ausgabe zeigen und anhalten, statt eine
Umgehung zu erfinden. Die CLI-seitige Uebersetzung (needs_clearance) folgt mit dem Kommando
in #126; #124 liefert nur die Bibliotheksseite. #119s Umsetzungstabelle und #124s eigener
Akzeptanzkriterien-Absatz sind entsprechend nachgezogen.
Ausserdem verifiziert, ohne Designfolgen: Super Productivitys Someday/Maybe-Aequivalent ist der
bestehendebacklogTaskIds-Puffer je Projekt, keine eigene Tag-Konvention.wikitool review: the weekly GTD review as a read-time join
Gitea #119 (Paket #125): das tragende Bauteil -
wikitool reviewjoint die Tracker-Seite
(chemenu.tasks, #124) und diekb/gtd/-Projektseiten ueber den case-normalisierten Namen und
gibt einen Bericht aus. Es speichert nichts, nicht einmal einereports/-Datei (D3) -search
ist das naechste Vorbild dafuer, undreviewist deshalb genauso vom Iterationsbudget
ausgenommen.Fuenf Pruefungen (#119 D10/D26), alle in
chemenu.review.run_review: stalled (Tracker-
Projekt ohne offene Posten,kb/-Seitestate: active-dormant/completed/abandoned
melden nie, D27), waiting_overdue (follow_up_ataelter alsstalled_waiting_days),
unpaged_project (Tracker-Projekt ohnekb/-Seite, aelter alsunpaged_project_weeks),
no_open_loop (kb/-Seiteactive, aber kein Tracker-Projekt dieses Namens oder keine
offenen Posten - die Gegenrichtung des vorigen Abgleichs, D8s beidseitiger unmatched-Bericht),
someday_stale (Someday-Posten seitsomeday_stale_monthsunveraendert, ueber Kalendermonate
gerechnet statt ueberTage / 30). Ein Tracker-Projekt ohne offene Posten mit aktiverkb/-Seite
erfuellt zugleich stalled und no_open_loop - beide melden, das ist keine Dopplung, sondern zwei
verschiedene Aussagen ueber denselben Zustand.Jeder Providerzugriff ist einzeln abgesichert: scheitert
projects(), entfallen die vier darauf
aufbauenden Pruefungen; scheitertsomeday_items(), entfaellt nur die fuenfte; scheitert
open_items()fuer ein einzelnes Tracker-Projekt, faellt nur dieses eine aus den betroffenen
Pruefungen heraus, der Rest laeuft weiter. Ein so unvollstaendiger Bericht setztcompleteauf
false, druckt trotzdem alles, was noch entschieden werden konnte, und die CLI beendet sich mit
Exit 1 - nie mit einem leisen Teilbericht, der wie eine ruhige Woche aussieht. Fehlt
.wikitool-tasks.jsonganz, oder ist es kaputt, scheitert der Aufruf sofort und sagt das - das
ist ein Konfigurationsfehler, kein Erreichbarkeitsproblem, und braucht deshalb keinen Teilbericht.--jsontraegt dieselben Befunde maschinenlesbar (findings/checks_run/checks_skipped/
kb_project_count/complete); ein Test haelt beide Formen gegeneinander, wie es
test_mcp_server.pyfuer den MCP-Lesepfad gegen die CLI tut.wikitool new project: Seite und Tracker-Projekt unter einem Namen
Gitea #119 (Paket #126):
wikitool new project --name X --set responsibility=Ylegt jetzt, wenn
.wikitool-tasks.jsoneinen Tracker konfiguriert, zusaetzlich ein gleichnamiges Tracker-Projekt
an - ein Geburtsort, ein Name (D8/D31). Tracker vor Seite: erst steht die Tracker-Seite fest,
erst danach wird diekb/-Seite geschrieben, damit ein Fehlschlag zwischen beiden immer im
selben, bereits bekannten Zustand landet - "Tracker-Projekt ohne Seite", dasreviews Pruefung 3
ohnehin meldet - nie im unbekannten "Seite ohne Tracker-Projekt". Ist kein Tracker konfiguriert,
bleibt es bei der reinen Seitenanlage, jetzt aber ausdruecklich als solche vermerkt statt
stillschweigend.chemenu.tasks.build_reader/build_writer(neu inchemenu/tasks/__init__.py) sind die eine
Dispatch-Tabelle vonTasksConfig.providerauf einen konkreten Adapter, jetzt vonreview.py
undnew_page.pygeteilt statt zweimal derselbenif cfg.provider == "superproductivity".Fuer einen Provider ohne Schreibpfad (Super Productivity, #124: keine
POST /projects) wirft
create_projectchemenu.errors.HumanInterventionRequired- das Kommando zeigt die Anweisung
und beendet sich mit Exit 42, ohne irgendetwas anzulegen. Die offene Frage aus #126s eigenem
Issue-Text war, wie ein zustandsloser CLI-Prozess bei einem erneuten Aufruf eine echte
Namenskollision von "der Mensch hat gerade getan, worum genau dieses Kommando gebeten hat"
unterscheidet - beides sieht am Lesepfad identisch aus (Tracker hat den Namen,kb/noch keine
Seite). Entschieden (mit dem Betreiber, nicht allein): ein explizites--resume, das ein Treffer
im Tracker als bestaetigte Fortsetzung liest statt als Kollision - ohne--resumebleibt jeder
Treffer eine Ablehnung samt Fundort, auch bei einem Wiederholungsaufruf.--resumeohne einen
tatsaechlich fehlenden Tracker-Eintrag wirft dieselbeHumanInterventionRequired-Meldung erneut,
keine stille Weiterarbeit auf Zuruf.--resumebei jedem anderen Typ wird abgelehnt.Ein erzwungener Fehlschlag der eigentlichen Seiten-Schreibaktion (Schritt 3) nach bereits
bestaetigtem Tracker-Projekt ist eigens getestet: die Meldung nennt, dass die Tracker-Seite schon
steht und nur diekb/-Seite fehlt, nie umgekehrt.new project: Testabdeckung fuer die required-responsibility-Ablehnung
Gitea #119 (Paket #126s eigenes AC):
--responsibilityist Pflicht und ein Wert ausserhalb des
Enums wird abgelehnt - beides galt schon vorher generisch uebertypes/project.schema.yamls
required:/enum:(#123), ohne dass #126 dafuer neuen Code brauchte. Nachgetragen: ein Test,
der das fuer den fehlenden Fall (--set responsibility=...ganz weggelassen) tatsaechlich belegt,
statt es nur zu behaupten.Skill weekly-review: turning wikitool review's findings into decisions
Gitea #119 (Paket #127):
instructions/weekly-review/SKILL.md, publiziert nach.agents/skills/
und.claude/skills/.wikitool reviewliefert fuenf Befunde (#125); dieser Skill fuehrt das
Gespraech, das aus jedem eine Entscheidung macht - je Befund mindestens zwei Handlungsoptionen und
ein Unterscheidungsmerkmal, wie in #127s Akzeptanzkriterien gefordert.Der Skill nennt bewusst keinen Provider, keine Datei- und keine API-Form (D25) - eine neue
Regressionstest (test_weekly_review_skill_names_no_provider) haelt das am echten Repo-Inhalt
fest, nicht nur als Review-Behauptung. Erinnert im Text an D28 (Personen in## Beteiligte
bleiben Erwaehnung, bekommen keine Seite) und D7 (die Seite fasst die Aufgabenliste nie
zusammen). Die Kommandoflaeche bleibt beireview/new project; alles Aufgabenbezogene - eine
naechste Aktion anlegen,follow_up_atverschieben, einen Someday-Eintrag streichen - bleibt eine
Handlung im Tracker selbst, weil dafuer keinwikitool-Kommando existiert (D31).Doku-Nachzug zu #119: die Verpflichtungsschicht erreicht Installation, Setup und docs/
Gitea #119, nach Abschluss von #122-#127: die sechs Umsetzungspakete haben ihre Vertragszeilen
jeweils mitgebracht (tools/CONTRACT.md,kb/CONTRACT.md), aber drei Flaechen blieben zurueck,
die kein Paket fuer sich allein besass - und keine davon faellt beidocs verifyauf, weil dort
keine Zeile fehlt, sondern Prosa.INSTALL.md§ Konfiguration kannte.wikitool-tasks.jsonnicht. Die Datei stand in
tools/CONTRACT.mdsdoctor-Zeile und inreviews Fehlerkontrakt, also dort, wo ein Agent
nachschlaegt - nur nicht dort, wo ein Mensch die Form nachschlaegt. Sie steht jetzt neben
.wikitool-telemetry.jsonund.wikitool-remotes.json, mit vollstaendigem Beispiel, den drei
Schwellwerten als Konfiguration statt Schema, und dem fuer Super Productivity getrennten
Lese-/Schreibpfad. Diedoctor-Beschreibung unter § Verifikation nennt den Tracker jetzt mit.setup-instance.mdbot den Tracker nie an. Eine neue Instanz bekam Typ und Collection ueber
die generische Template-Adoption (Schritt 5), aber nichts fragte nach der anderen Haelfte des
Rueckblicks. Neuer Entscheidungspunkt (Schritt 11, parallel zur Telemetrie): einmal fragen,
.wikitool-tasks.jsonanlegen oder nichts tun - kein Tracker ist ein gueltiger Endzustand. Die
Form steht nicht hier, sondern inINSTALL.md(Invariante 8). Folgenummern 12-16 nachgezogen,
Skill-Liste umweekly-reviewergaenzt.upgrade-instance.mdhatte keinen Pfad fuer ein neu ausgeliefertes.template. Genau der
Fall, den 7.0.0 erzwingt: Schritt 5 sagte „newbraucht keine Entscheidung", und die
Schritt-6-Tabelle sagt, instanzeigene Dateien koennten dort gar nicht auftauchen - beides
richtig und zusammen irrefuehrend, weil ein neuestypes/<name>.md.templatefuer einen
geforderten Typ sehr wohl eine Handlung braucht. Schritt 5 benennt diese eine Ausnahme jetzt,
Schritt 9 traegt die Reparatur neben der TOC-Reparatur: die gewoehnliche Adoption, mit den zwei
cp-Zeilen, ausdruecklich keine Datenmigration.
Dazu die Begruendung selbst:
docs/knowledge-and-commitment.mdist neu und haelt fest, warum
Wissen und Verpflichtung zwei Schichten sind (verschiedene Halbwertszeiten), warum nicht
synchronisiert wird (Muster 4, mit den drei verworfenen Anordnungen), warum der Join zur Lesezeit
passiert und nichts speichert, warum ein Name die Pflichten eines Identifiers erbt, warum eine
Seite ihre Aufgabenliste nie zusammenfasst, warum Archivierung einstate:-Wert ist, und warum
keine Instruction je den Provider nennt. Das stand bisher ausschliesslich in Gitea #119 - und ein
Issue ist genau das, wasdist exportnicht mitliefert: eine ausgelieferte Instanz bekam den
Mechanismus ohne das Warum.AGENTS.md§ File naming zaehlt jetzt sechs statt fuenf von dort
verlinktedocs/-Seiten.tools/README.md§ Layout fuehrtreview.pyund das Pakettasks/; und
instructions/dev/doc-pull-through.mdbekommt die zwei Zeilen, deren Fehlen dieser Nachzug ist:
eine fuer eine instanzeigene Konfigurationsdatei (INSTALL.md § Konfiguration + der
setup-instance-Entscheidungspunkt +doctors Vertragszeile), eine fuer einen neuen geforderten
Seitentyp oder eine neue Collection (Type-Spec/COLLECTION.md+kb/CONTRACT.md+ beide
Adoptionspfade). Die Zeile zurdocs/-Begruendung sagt jetzt zusaetzlich, dass eine Entscheidung
ohne Seite die eigentliche Luecke ist, weil Begruendungen aus einem Issue nie ausgeliefert werden.docs/-Nachzug: Exit 42 als Haltung, und die Adoption eines neu ausgelieferten Templates
Die Abschlusspruefung dieses Kandidaten (
stack-closeSchritt 3) hat zweidocs/-Seiten gefunden,
deren Begruendung die Pakete #124/#126 bzw. #123 verschoben hatten, ohne dass jemand sie nachzog -
beide unpruefbar, weil einedocs/-Seite per Konstruktion keinen normativen Satz traegt.docs/why-gates-are-code.mdkannte Exit 42 nur als Gate. Die Seite oeffnet mit „vier harte
Grenzen", und seit #124/#126 verlaesstHumanInterventionRequireddenselben Code, ohne eine
fuenfte Gate zu sein. Neuer Abschnitt „Exit 42 is a posture, and it outgrew the gates": die vier
Gates teilen eine Weigerung (die Operation waere moeglich, das Werkzeug fuehrt sie
unbesehen nicht aus), der neue Fall ist das Gegenteil (die Operation ist gar nicht moeglich, kein
Token koennte das aendern) - gemeinsam ist beiden nur, was der Exit-Code tatsaechlich sagt:
anhalten, einem Menschen zeigen, nichts umgehen. Dazu die verworfene Alternative, die Luecke in
der Instruction-Schicht zu beschreiben - genau die Prosa-Regel, gegen die diese Seite argumentiert.docs/ownership-and-templates.mdbeschrieb die.template-Kategorie nur von innen. „Wird
von einem Upgrade nie geschrieben" stimmt weiterhin fuer eine bereits adoptierte Datei; der Fall,
dass ein Release ein Template fuer einen Typ liefert, den die Instanz noch gar nicht hat, stand
nirgends - und genau der ist seit #123 der Grenzuebertritt. Die Kategorie nennt ihn jetzt als die
eine Gestalt, in der „das Upgrade schreibt diese Datei nie" zu Arbeit wird, mit Verweis auf den
Schritt inupgrade-instance.md, den Stack 7.0.0-beta.7 dort angelegt hat.
Skill-Namensfamilien: weekly-review -> gtd-weekly-review, dritte Person in allen Descriptions
Gitea #129: the published skill collection had drifted into three naming shapes where it should
have three families.weekly-review(added earlier in this same candidate, never released)
named neither its domain nor its distribution boundary, unlikewiki-*andstack-*either
side of it - renamed togtd-weekly-review, joining a newgtd-prefix for the commitment layer
(kb/gtd/,types/project.md,docs/knowledge-and-commitment.md) that sits besidewiki-(the
knowledge pipeline) andstack-(the stack's own development, underinstructions/dev/).
instructions/CONTRACT.md§ "Writing an instruction" now states both the family-prefix
convention and, separately, that a skill'sdescriptionspeaks in third person per Anthropic's
skill-authoring guidance - all eight published skills' descriptions were rewritten to match
("Processes...", not "Process..."); the flatinstructions/<name>.mdform keeps its existing
imperative-title convention, since itsdescriptionis read on demand rather than injected into
the system prompt. No--breakingline: the renamed skill was introduced by this same
unreleased candidate, so no existing instance carries the old name to migrate away from.Veraltete Skill-Aufzaehlungen in der Instruction-Schicht nachgezogen
Gitea #129s Abschlusspruefung: die Skill-Umbenennung hat sichtbar gemacht, dass mehrere Dokumente
die Skill-Liste hart aufzaehlen und beim Wachsen der Liste still veralten. Vier Stellen waren
falsch, eine davon schon vor diesem Paket:instructions/CONTRACT.md§ "When a skill carries a copy-in checklist" zaehlte „die zwei
Skills mit Block und die drei ohne" - also fuenf von inzwischen acht. Die Zahlen im Einstiegssatz
sind jetzt ganz raus (sie unterscheiden sich ohnehin zwischen diesem Repo und einer
ausgelieferten Instanz, dieinstructions/dev/nicht hat), die Aufzaehlung nennt alle
ausgelieferten Skills, und die beiden Dev-Skills stehen in einemdist:strip-Block.- Dieselbe Passage nannte
wiki-querymit sechs Schritten - es sind sieben, und zwar schon
laenger. Die Regel selbst (ein Flow ab acht Schritten und still scheiternde Schritte) bleibt
unveraendert; kein Skill wechselt dadurch die Seite. instructions/CONTRACT.md§ "outbound reference" sprach im Praesens von „this repo's seven
skills", wo die Zahl zu einer datierten Messung (52 von 58 Links) gehoert - jetzt als „at the
time" markiert, statt die Messung nachzurechnen.instructions/bootstrap.mdund die Scope-Abschnitte vonstack-dev/stack-closelisteten
die Content-Skills ohnegtd-weekly-reviewauf.
Dazu
test_the_real_repo_publishes_the_six_wiki_skills->..._every_skill: der Test pruefte
sechs der acht Skills und trug die veraltete Zahl im Namen; er nennt jetzt alle acht, nach
Familien erklaert. Dass die Passage weiterhin Schrittzahlen fremder Dateien zitiert, die genauso
still veralten koennen, ist als eigene Frage festgehalten und hier bewusst nicht geloest.SP-Zugriffsweg explizit (access: api/snapshot, #133) und follow_up_at-Korrektur (dueWithTime/dueDay, #135)
Gitea #133: der Super-Productivity-Adapter unterscheidet jetzt zwei sich ausschliessende
Zugriffswege, per Pflichtfeldaccessohne Default und ohne Laufzeit-Ruckfall -"api"liest
und (fuer #132 vorbereitet) schreibt ausschliesslich ueber die lokale REST-API und den aktuellen
Zustand,"snapshot"liest ausschliesslich den juengsten Backup-Schnappschuss und ist von dort
aus nie schreibbar.db_pathentfaellt vollstaendig,backups_dirs Glob ist auf das echte
Zeitstempelmuster (YYYY-MM-DD_HHmmss.json) gehaertet, und beide Wege blenden archivierte
Tracker-Projekte aus - verifiziert gegen den tatsaechlichen Quellcode von
super-productivity/super-productivity(master, 2026-09-20).SuperProductivityApiReaderist
der neue Leser fueraccess: "api", gegen eine Attrappe getestet, nie gegen eine laufende App.
tools/wikitool new projectverweigert auf eineraccess: "snapshot"-Instanz jetzt vollstaendig
(Exit 1, weder Tracker-Projekt noch Seite) statt den nicht mehr moeglichen 42er-Menschenschritt zu
versuchen;wikitool doctorundwikitool reviewberichten nur noch den tatsaechlich
konfigurierten Weg, und jede Antwort vonreviewnennt jetzt explizit, aus welchem Weg sie
stammt (beisnapshotsamt Alter des gelesenen Schnappschusses). Aufgeloest damit: #134, dessen
Verdacht (--resumekoennte gegen einen veralteten Schnappschuss verifizieren) durch den Wegfall
der Projektanlage aufsnapshot-Instanzen gegenstandslos wurde.Gitea #135, im selben Zug korrigiert:
follow_up_atlas bislangremindAt, das sich nur bei
einer mit Uhrzeit terminierten und benachrichtigten Aufgabe fuellt - ein ganztaegiger, stiller
Tickler (dueDayohnedueWithTime, das haeufigste WAITING-Muster) hatte dadurch nie einen
follow_up_atund fiel bei Pruefung 2 des Wochenrueckblicks still durch. Gelesen wird jetzt
dueWithTime, sonstdueDay- Super Productivitys eigene Leseregel - niedeadline*(D9 bleibt
in der Sache unveraendert, nur die falsche Berufung auf sie ist korrigiert). Bestehende Instanzen
sehen dadurch rueckblickend mehr Befunde, nicht weniger.task new: einen zweiten Schreibweg in den Tracker (ein Posten, keine Seite)
Gitea #132: eine Quelle kann Wissen und eine Verpflichtung zugleich tragen (eine Kundenreklamation
etwa), und bislang hatte nur die Wissenshaelfte einen Schreibweg.chemenu.tasks.protocol.TaskWriter
traegt jetzt eine zweite Methode,create_item- Projekt, Titel, optionalWAITINGmit
follow_up_at, optional ein Freitext-Rueckverweis innotes-, darueber das neue Kommando
wikitool task new. Anders alscreate_projectschreibt sie tatsaechlich: bei Super Productivity
existiertPOST /tasks, woPOST /projectsfehlt, also gibt es hier keinen
HumanInterventionRequired-Fall. Das Kommando ordnet kein Projekt selbst zu - ein--project, das
zu keinem Tracker-Projekt passt, oder--waitingohne vorhandenenwaiting-Tag scheitert laut,
exit 1, statt zu raten oder einen Posten ohne seinen Status anzulegen. Die Eingangs-Ablage
(--inbox) ist eine eigene, ausdrueckliche Form am Kommando, nie ein Ersatz fuer ein vergessenes
--project.Verifiziert gegen
super-productivity/super-productivity@master(2026-09-20): Super Productivitys
INBOX_PROJECTist zwar immer ein echtes Projekt-Entity im Store, aber
selectUnarchivedProjects- der Selektor hinterGET /projects- filtert es ueber seine feste id
unbedingt heraus. Ein per--inboxabgelegter Posten erscheint deshalb in keiner
wikitool review-Pruefung, nicht weil eine Ausnahme dafuer noetig waere, sondern weil der Eingang
in der Projektliste schlicht nie auftaucht - der Ingest-Skill nennt diese Kosten jetzt ausdruecklich,
wenn er die Route anbietet.Der Ingest-Skill (
instructions/wiki-ingest/SKILL.md) fragt in Schritt 5 jetzt auch nach einer
Verpflichtung, nicht nur nach dem Wissen, und legt Titel und vorgeschlagenes Projekt in einem
Bestaetigungsschritt vor (nie eine automatische Zuordnung, auch nicht bei einem eindeutigen
search-Treffer). Der Posten wird vor der Quellenseite angelegt - dieselbe Tracker-vor-Seite-
Reihenfolge, dienew projectschon haelt, hier mit eigenem Beleg: eine Rohdatei ohne Quellenseite
meldetlintalsuncovered_raw_files, eine stillschweigend verlorene Verpflichtung meldet
nichts. Der bestehende Regressionstest, der sicherstellt, dass kein Skill den Tracker-Provider
nennt, ist entsprechend aufwiki-ingesterweitert.docs/knowledge-and-commitment.mdund
tools/CONTRACT.mdsind nachgezogen; Gitea #128 (der zweite Adapter) traegt jetztcreate_item
in seiner eigenen Flaeche.wiki-ingest: raw accept rückt hinter die Verpflichtungsentscheidung
Gitea #136, eine offen gebliebene Teilfrage aus #132:
raw acceptlief dort weiterhin ganz am
Anfang des Laufs, vor Lesen, Diskussion und Verpflichtungserkennung - scheitertetask new, fand
sich eine bereits nachraw/befoerderte Rohdatei vor, obwohl #132s eigenes Kriterium "keine
Seite geschrieben und keine Rohdatei befoerdert" verlangte.docs/knowledge-and-commitment.md
behauptete diese Eigenschaft seit demselben Commit bereits als Tatsache; der Baum beschrieb ein
Design, das es nicht gab.wiki-ingests Schritte 1-5 sind neu geordnet: lesen, Metadaten,search, Diskussion inklusive
Verpflichtung undtask new, dann erstraw accept. Die Schritte 6-12 behalten ihre Nummern
unveraendert, ebenso jeder Fremdverweis, der eine dieser Nummern nennt. Zwei Stellen sind dabei
verschaerft, nicht nur verschoben: diefidelity/authority-Frage in Schritt 5 benennt jetzt
ausdruecklich, dass die Datei zu diesem Zeitpunkt schon vollstaendig gelesen ist - der Moment, in
dem die Versuchung, den Wert aus dem Inhalt zu erschliessen statt ihn zu erfragen, am groessten
ist -, und derselbe Schritt benennt, dass seine Kollisionsverweigerung jetzt spaeter faellt, nach
Lesen, Diskussion und moeglicherweise bereits angelegtem Tracker-Posten.Eine Ausnahme bleibt bewusst bestehen: ein Lauf, der wegen Volumen oder Breite an
instructions/ingest-large-tree.mduebergibt, befoerdert weiterhin vor der Verpflichtungsfrage -
dessenwork new --input <pfad>verweigert jeden Pfad ausserhalbraw/, und der Lauf ist ohnehin
nicht atomar, da er unit-weise ueber Tage publiziert und seine eigene Verpflichtungsfrage erst in
Schritt 5d je Unit stellt.docs/knowledge-and-commitment.mdnennt diese Ausnahme jetzt explizit,
statt die Eigenschaft unbedingt zu behaupten.README.mdundinstructions/CONTRACT.mdsind
nachgezogen.Zwei Fragen, die sich beim Durchsehen der Naht zwischen Wissen und Verpflichtungen zusaetzlich
zeigten -gtd-weekly-reviews veraltete Zaehlung der GTD-Kommandos, und ob der Weekly Review
task newkuenftig anbieten soll -, sind bewusst nicht Teil dieser Aenderung: Gitea #137 und #138.gtd-weekly-review: task new nachgezogen, veralteter Begründungszeiger korrigiert
Gitea #137, der liegengebliebene Pull-Through von #132 am GTD-Rand:
instructions/gtd-weekly- review/SKILL.mdbehauptete zweimal,reviewundnew projectseien die einzigen zwei
GTD-Kommandos, und begruendete die Haltung "der Nutzer handelt selbst in seinem Tracker" mit
"becausewikitoolhas no command for it" - seit #132stask newschlicht falsch. Der
Begruendungszeiger fuer die schmale Kommandoflaeche zeigte zudem auftypes/project.mdund
kb/gtd/COLLECTION.md; die Begruendung steht tatsaechlich in
docs/knowledge-and-commitment.md§ "Status has exactly one home", die #132 korrekt nachzog,
waehrend dieses Skill unberuehrt blieb.Beide Stellen benennen
task newjetzt als drittes, tatsaechlich vorhandenes Kommando, das dieses
Skill bewusst nicht aufruft - die Haltung selbst ist unveraendert, nur ihre Begruendung ist jetzt
eine Wahl statt eine Behauptung ueber eine fehlende Faehigkeit. Ob der Weekly Reviewtask new
kuenftig anbieten soll, bleibt unentschieden in Gitea #138; dieses Issue korrigiert nur, was
nachweislich falsch dastand.Weekly review proposes task new/task close; tracker gains a closing write path
Gitea #138 entschied die dort offene Frage: der Weekly Review bietet
task newjetzt bei
stalled/no_open_loopOption (a) an, nach ausdruecklicher Bestaetigung von Titel und Projekt in
einer Frage - dieselbe Haltung wie im Ingest. Die zweite Haelfte derselben Naht war unentschieden
liegen geblieben: eine Quelle kann eine Verpflichtung anlegen, aber nie schliessen. Der Tracker
bekommt dafuer einen dritten, letzten Schreibweg,task close --id, der einen Posten erledigt
markiert - niemals loescht, verifiziert gegen Super Productivitysmaster-Branch, dass
PATCH /tasks/:idmitisDone: truebit-identisch zur eigenen "erledigt"-Checkbox der App ist.
task list --projectliefert dazu die Item-Ids, dietask closeund die Review-Funde fuer
waiting_overdue/someday_stalejetzt mitfuehren.wiki-ingeststellt die Verpflichtungsfrage
seither in beide Richtungen (oeffnen und schliessen), undingest-large-treeSchritt 5d begruendet
jetzt in einem Satz, warum diese Frage pro Unit gestellt wird statt einmal pro Baum.Die zwei Instruktionsstellen, an denen die Haltung zum Tracker-Schreibzugriff bislang doppelt
stand, sind auf eine zusammengezogen; die zweite verweist nur noch.
docs/knowledge-and-commitment.md§ "Status has exactly one home" zaehlt die Kommandoflaeche
korrekt (zwei Lese-, drei Schreibkommandos) und haelt fest, warum sie bei "anlegen" und "erledigt
markieren" endet, nie bei "loeschen" oder "aendern".instructions/CONTRACT.md drops other files' step counts from the copy-in-checklist rationale
instructions/CONTRACT.md§ "When a skill carries a copy-in checklist" used to justify the
threshold by citing each other skill's step count by number - evidence that the two-halves test
(length and a silently-omittable step) is what actually decideswiki-ingest/wiki-lint, not a
count fitted after the fact. Nothing kept those numbers in sync with theSKILL.mdfiles they
described: one of them had already drifted silently (wiki-querycited at six steps where it had
been seven for a while), and the passage itself named only five of the eight skills that exist -
neither wrong number failed any check, becausedocs verifyreads presence, not another file's
prose (instructions/dev/doc-pull-through.md).Of the three fixes considered - a
docs verifycheck against a codified step-counting convention,
a qualitative rewrite that drops the numbers, or tracking the sync as a manualdoc-pull-through.md
duty - the qualitative rewrite won: it is the only one of the three that removes the possibility of
drift rather than catching or documenting it, and the per-skill counts were decoration for the
two-halves test, never load-bearing for it. The passage now names which skills qualify and why,
without citing a number that belongs to a file it does not own. Today's counts were checked against
the actual files before this bump (wiki-ingesttwelve,wiki-lintnine,wiki-managetwo flows
of seven,wiki-queryseven,wiki-statusfive,gtd-weekly-reviewfive,stack-devsix,
stack-closefour) - all correct, confirming the passage was not itself wrong, only unguarded.
This note is a snapshot of the
CHANGES.mdentry as it stood when the tag was cut, and
is never edited afterwards. The maintained version of this text - including any later
correction - is the entry for this version inCHANGES.mdin the repository.Downloads
- docs verify now requires an adopted
-
v6.2.0 Stable
released this
2026-09-19 15:45:07 +00:00 | 106 commits to main since this release6.2.0 - 2026-09-19 - Entity-Subtyp project nach codebase umbenannt
Author: Torben Nehmer
- Entity-Subtyp project nach codebase umbenannt
Entity-Subtyp project nach codebase umbenannt
entity_type: projectbezeichnete in diesem Korpus ausnahmslos Codebasen; Gitea #119 zieht
daraus einen eigenen Typ fuer das Vorhaben (gtd/project, Paket #123), wodurch der bisherige
Wert homonym geworden waere.types/entity.schema.yamlundtypes/entity.mdfuehren jetzt
codebasestattproject,kb/entities/projects/heisstkb/entities/codebases/, und die elf
betroffenen Seiten wurden ausschliesslich ueberwikitool touch/moveumgezogen. Kein
Grenzuebertritt:types/entity.mdist.template-basiert,dist upgradeschreibt nie die
adoptierte Kopie einer Instanz, nur den mitgelieferten Standard daneben - eine bestehende
Instanz behaelt ihren eigenenproject-Wert unangetastet und uebernimmt die Umbenennung erst,
wenn sie es sich vornimmt.
This note is a snapshot of the
CHANGES.mdentry as it stood when the tag was cut, and
is never edited afterwards. The maintained version of this text - including any later
correction - is the entry for this version inCHANGES.mdin the repository.Downloads
-
v6.1.0 Stable
released this
2026-09-17 07:18:09 +00:00 | 107 commits to main since this release6.1.0 - 2026-09-17 - Upgrade-Pfad und Iteration-Budget-Gate gehaertet, wiki/-Pfadliterale bereinigt
Author: Torben Nehmer
High impact
- Session-Id-Fallback: Harness-Variable schliesst die Luecke zwischen Telemetrie-Join und Iteration-Budget-Gate
Medium impact
- Upgrade-Prozedur als eigene Instruktion statt als Prosa in INSTALL.md
- Migrationsdokument prueft gegen eine festgehaltene Vorher-Ausgabe, Beispielverweis auf die .template-Form
- dist upgrade: --take-release nimmt fuer einen lokal geaenderten Pfad die Release-Fassung
- version notes antwortet auf einer ausgelieferten Instanz aus dem Release-Feed
- new: scaffold materializes a schema default only for a required field
Low impact
- Stale
wiki/path literals swept out of tools/ and types/, with a test guarding against the next rename - CHANGES.md/Guard-Docstring: die Zahl der nachgezogenen Pfadliterale korrigiert (33, nicht 27)
Dieser Kandidat sammelt, was ein getraceter 5.0.0-auf-6.0.0-Upgrade-Lauf auf einer echten Instanz
offengelegt hat: ein fehlender Upgrade-Leitfaden, zwei falsche Verweise im Migrationsdokument,
eine fehlende dritte Antwort indist upgradefuer eine lokal geaenderte Datei, und
version notes, das auf einer ausgelieferten Instanz nie antworten konnte. Im selben Lauf zerfiel
die Sitzung durch einen PID-basierten Session-Id-Fallback in 21 Telemetrie-Buckets, wodurch das
Iteration-Budget-Gate strukturell unerreichbar blieb - behoben durch eine Registry bekannter
Harness-Session-Variablen, mit einem SIGPIPE-Nebenbefund im CLI-Emitter gleich mit. Dazu,
unabhaengig vom getraceten Lauf: ein Scaffold-Fix, derobligation: requirednicht mehr in jede
neue Instruktion schreibt, und eine Bereinigung von 33 stehengebliebenenwiki/-Pfadliteralen aus
derwiki/-nach-kb/-Umbenennung, mit einem Test-Guard gegen die naechste Umbenennung.Kein Grenzuebertritt: jede Aenderung ist in beide Richtungen ein Drop-in, additiv gegenueber
6.0.1.Upgrade-Prozedur als eigene Instruktion statt als Prosa in INSTALL.md
Der Upgrade-Pfad einer ausgelieferten Instanz stand nur in INSTALL.md § "Eine Instanz
aktualisieren" - einem Dokument fuer Menschen, dasAGENTS.md§ File naming ausdruecklich als
"never by an agent as instruction" fuehrt. Ausgefuehrt wird er aber von einer Agent-Sitzung,
jedes Mal. Der getracete 5.0.0-auf-6.0.0-Lauf auf einer echten Instanz zeigt, was daraus folgt:
der erste Tool-Call listeteinstructions/mit, fand keine passende Instruktion, oeffnete die
naechstliegende (private-instance.md, der falsche der beiden Wege) und fiel dann auf INSTALL.md
zurueck.migrate verify --from <commit vor dem Tausch>- INSTALL.md Schritt 6, erster
Pruefschritt - lief in 33 Werkzeugaufrufen kein einziges Mal, und die Agent-Sitzung wurde nie neu
gestartet, obwohlAGENTS.mdim selben Commit +44/-3 bekommen hatte. Die anschliessende Migration
lief damit unter dem alten Kontrollplan.Dahinter lagen drei Reihenfolgen nebeneinander: die in INSTALL.md, die im Abschlussbericht von
dist upgrade, und die tatsaechlich gelaufene. Genau der Zustand, den Invariante 8 verbietet.instructions/upgrade-instance.mdist jetzt die eine Fassung: dreizehn Schritte von der
Sitzungs-Id bis zum zweiten Publish, mit dem Sitzungsneustart an der Stelle, an der der neue
Kontrollplan zu gelten anfaengt - nach dem Publish der Maschinerie, vor der Migrationskette, und
mitmigrate statusals Wiedereinstiegspunkt fuer die neue Sitzung.manual: true, weil die
Prozedur einmal pro Release laeuft und nie implizit aufgegriffen werden darf; ein Skill wuerde
seinedescriptiondafuer in jede Sitzung legen. Auffindbar ist sie ueber den Abschlussbericht
vondist upgrade, der statt einer eigenen Schrittliste jetzt die Datei nennt und das Kommando,
bei dem der Lauf weitergeht (instructions sync). INSTALL.md behaelt, was ein Mensch vorher
entscheidet, und den einen Sonderfall, den die Instruktion nicht abdecken kann, weil es sie dort
noch nicht gibt: den ersten Sprung auf4.5.0.Zwei Schritte der Instruktion sagen ausdruecklich, dass sie eine Luecke umgehen, und was sie
ueberfluessig macht. Schritt 2 liest die Release-Notes von der Release-Seite statt mit
version notes, weil eine Instanz ihreCHANGES.mdals Stub bekommt unddist upgradesie nie
ueberschreibt - der Befehl kann dort nicht heute und nicht spaeter antworten. Schritt 6 nimmt fuer
eine lokal veraenderte stackeigene Datei die Release-Fassung von Hand, weil es zu--keep-local
kein Gegenstueck gibt; dabei geht der noetige Commit ueberpublish --no-push, nicht ueber
git commit- Invariante 5 kennt keine Ausnahme fuer "ist ja nur eine Vorbedingung", und genau
diese Ausnahme hat sich der beobachtete Lauf genommen.instructions/session-setup.mdsagt jetzt, dass einexportnur traegt, solange die Shell
traegt. Mehrere Harnesses starten pro Tool-Call eine frische Shell - das Arbeitsverzeichnis
ueberlebt, Shell-State nicht - und dann faellt jeder Aufruf auf seine eigene Parent-PID zurueck.
Im gemessenen Lauf wurde eine Sitzung so zu 21 Telemetrie-Buckets mit hoechstens drei Aufrufen
pro Bucket: das Iteration-Budget-Gate (60) und der Loop-Breaker (3 identische in Folge) konnten
strukturell nicht ausloesen. Die Anleitung nennt deshalb die Inline-Form pro Aufruf und den
Einzeiler, mit dem sich beantworten laesst, welcher Fall vorliegt.Verifiziert:
docs verify(73 ausgelieferte Dokumente, 58 Referenzdateien),
instructions verify(23 Instruktionen, 7 Skills) und 1276 Tests gruen - einer davon neu und auf
genau die Stelle gerichtet, an der die Doppelung wieder entstehen wuerde: der Abschlussbericht
vondist upgrademuss die Instruktion und ihr Wiedereinstiegskommando nennen, nicht eine zweite
Kopie der Liste.Kein Grenzuebertritt: eine neue Instruktionsdatei und ein geaenderter Meldungstext sind in beide
Richtungen ein Drop-in. Eine Instanz, die zurueckgeht, behaelt die Datei als ueberzaehlige Datei,
und nichts liest sie automatisch -manual: trueheisst genau das.Migrationsdokument prueft gegen eine festgehaltene Vorher-Ausgabe, Beispielverweis auf die .template-Form
instructions/migrations/6.0.0-type-guidance-split.mdverlangte in seinem Verifikationsschritt,
die Ausgabe vontypes describe <name>muesse "read the same as it did before this migration" -
ohne dass ein Schritt davor dieses Vorher festhielt. Eine Pruefung gegen einen Zustand, den
niemand aufgeschrieben hat, faellt auf das Gedaechtnis des Ausfuehrenden zurueck, und bei ueber
150 Zeilen Ausgabe je Typ ist das keins. Der getracete 6.0.0-Lauf hat entsprechend durch
| head -250und| tail -80geprueft und "structurally identical to before" geurteilt; was
das uebersah, lag in der Mitte dersource-Ausgabe. Das Dokument schreibt die Ausgabe jetzt in
einem eigenen Schritt vor der Aenderung in eine Datei und diffed hinterher, mit
grep -c '^## Authoring guidance'als Ein-Zahl-Probe: zwei Koepfe sind richtig - einen setzt
types describeselbst, einen bringt die Guidance-Datei mit.Als generisches Muster steht dasselbe jetzt in
instructions/migrate-corpus.md§ "Writing the
migration document", weil es nicht an diesem einen Dokument haengt:migrate verifytraegt seine
Baseline im letzten Commit, ob jemand daran denkt oder nicht - eine Migration an der Maschinerie
statt ankb/hat gar keine, und genau dort entsteht die Behauptung, die sich nicht widerlegen
laesst.Zweiter Fehler im selben Dokument: der Beispielverweis auf
types/entity.mdzeigt in einer
ausgelieferten Instanz auf die beim Setup adoptierte Kopie - also auf genau den Vorher-Zustand,
den der Schritt entfernen laesst. Der Nachher-Zustand liegt dort unter
types/entity.md.template, und im Ursprungs-Repo existiert diese Datei ueberhaupt nicht:
dist exportre-keyttypes/<name>.mderst beim Export. Der Satz konnte in einer Instanz also
nicht bloss unguenstig sein, er konnte dort nie stimmen. Dazu sagt der Schritt jetzt die Sprache
des Pointer-Absatzes - englisch, weil Anleitungsprosa an einen Agenten Control Plane ist,
unabhaengig davon, wem die Datei gehoert - und dass das auch fuer behaltene lokale Prosa gilt:
die wird uebersetzt, nicht umbenannt. Die Tabelle dazu wird verlinkt statt kopiert
(types/type-spec.md§ "Who owns a type-spec"), und ein behaltener Abschnitt bekommt einen
eigenen Namen statt der Ueberschrift, dietypes describeschon selbst setzt.Derselbe Defekt eine Ebene hoeher, gefunden beim Nachmessen:
types/source.mdtrug hier im
Ursprungs-Repo noch einen Rest-Abschnitt## Authoring guidancemit einem einzigen Bullet, der
dietitle_prefix-Frontmatter wiederholte -types describe sourcegab drei Koepfe aus, die
anderen drei Typen zwei. Die Sprachzentralisierung hat den Abschnitt uebersetzt, der
Guidance-Split den Rest der Prosa ausgelagert und diesen Bullet stehenlassen. Die Datei wird beim
Export zutypes/source.md.template, also haette ihn jede neu aufgesetzte Instanz mit adoptiert.
Entfernt, geprueft mit genau dem Muster, das der Schritt oben jetzt vorschreibt: Vorher-Datei,
Diff, vier entfernte Zeilen und sonst nichts, alle vier Typen komponieren jetzt mit zwei Koepfen.Verifiziert:
docs verify(73 ausgelieferte Dokumente, 58 Referenzdateien),
instructions verify(23 Instruktionen, 7 Skills) und 1276 Tests gruen. Kein neuer Test: die
Aenderung ist Prosa in zwei Instruktionen und ein entfernter Abschnitt aus einem Type-Spec -
was hier mechanisch pruefbar waere, prueftdocs verifybereits als Type-Spec gegen sein Schema.Kein Grenzuebertritt: in beide Richtungen ein Drop-in. Die Korrektur gilt denen, die noch
upgraden - eine Instanz, die das Angebot bereits genommen hat, liest das Dokument nicht noch
einmal. Fuer sie lohnt der eine Befehl, mit dem der Schaden hier gefunden wurde:
grep -c '^## Authoring guidance'uebertypes describe <name>fuer alle vier Typen, drei
bedeutet einen Rest-Abschnitt im eigenen Type-Spec.dist upgrade: --take-release nimmt fuer einen lokal geaenderten Pfad die Release-Fassung
dist upgradekannte zwei Antworten auf eine lokal geaenderte Datei und die dritte, die man
eigentlich will, war keine davon.--keep-localbehaelt die Aenderung - und weil der neue Stamp
die Release-Digest trotzdem schreibt, wird dieselbe Datei bei jedem kuenftigen Upgrade erneut
gemeldet. Fuer eine Datei, die der Instanz gar nicht gehoert, ist das der dauerhaft falsche
Zustand. Der andere angebotene Weg, "reconcile them by hand first", hatte kein Werkzeug: im
getraceten 5.0.0-auf-6.0.0-Lauf war einekb/CONTRACT.mddurch ein Format-on-Save um
Tabellen-Whitespace verschoben, und das kostete eine Handkopie aus dem entpackten Tarball, einen
Commit nur zur Herstellung der Clean-Tree-Vorbedingung des naechsten Kommandos - und damit einen
rohengit commit, anAGENTS.mdInvariante 5 vorbei, die fuer "ist ja nur eine Vorbedingung"
keine Ausnahme kennt.--take-release <pfad>ist die fehlende Antwort: schreibe fuer diesen Pfad die Release-Fassung,
statt abzubrechen. Wiederholbar, weil der Pfad die Entscheidung benennt ---keep-localverliert
nichts,--take-releaseverwirft eine lokale Aenderung, und die zwei sind darum nicht symmetrisch
genug fuer ein pauschales Flag. Beide gelten pro Pfad und komponieren auf einem Aufruf, was der
gemischte Fall braucht: eine Datei zuruecksetzen, eine andere behalten. Ohne--keep-localbricht
ein blockierter Pfad, zu dem nichts gesagt wurde, weiter ab; ein--take-release-Pfad, der gar
nicht blockiert ist, wird abgelehnt - auch im--dry-run, denn das ist ein Fehler im Argument
und nicht ein Zustand des Baums, und ein still ignorierter Tippfehler haette ein erfolgreiches
Upgrade gemeldet und die Aenderung behalten, die verworfen werden sollte.Anders als bei
--keep-localist die Drift danach weg und nicht bloss uebergangen: die Datei
stimmt wieder mit der Digest ueberein, die der Stamp fuehrt, und verschwindet aus der Meldung.Dazu die Abbruchmeldung selbst, die den Fehlgriff mitverursacht hat. Sie nannte
--keep-localund
"reconcile by hand", sagte aber nicht, dass es zu--keep-localkein Gegenstueck gibt - der Lauf
kuendigte woertlich an, "I'll let the upgrade take the release's version", und rief das Kommando
ohne Flag auf. Jetzt nennt sie alle drei Antworten mit fertig eingesetzter Kommandozeile, im Muster
des Mass-Update-Gates, und sagt ausdruecklich, dass keine davon der Default ist.instructions/upgrade-instance.mdSchritt 6 traegt entsprechend nicht mehr die Drei-Schritt-Handreparatur, sondern die Entscheidung und den Dry-Run, mit dem man sie vorher sieht.version notes antwortet auf einer ausgelieferten Instanz aus dem Release-Feed
version notesliest die lokaleCHANGES.md. Eine ausgelieferte Instanz bekommt die aber als
neunzeiligen Stub ohne einen einzigen Versionseintrag, undCHANGES.mdsteht in
chemenu.ownership.is_upgrade_preserved-dist upgradeueberschreibt sie also nie. Der Stub
bleibt der Stub, dauerhaft. Der Befehl konnte dort nicht nur heute nicht antworten, sondern nie,
und das an genau der Stelle, an der die Antwort am meisten zaehlt: dem Grenzuebertritt, vor dem
Breaking Change: und Migration: gelesen werden muessen. Der getracete
5.0.0-auf-6.0.0-Lauf kam nur weiter, weil er die Release-Notes ueber einen MCP-Server holte - ein
Weg, den die Anleitung nicht nannte und den eine Instanz ohne erreichbaren Server gar nicht hat.Fehlt der Eintrag lokal, fragt der Befehl jetzt den Feed aus
update_url- denselben, den
version checkbenutzt - und druckt denbodydes Release, denrelease.ymlim Ursprungs-Repo
ohnehin ausversion notesbaut. Drei Praezisierungen halten das von einem stillen Netzaufruf
auseinander:- Nur mit Release-Stamp. Ein Baum ohne
.wikitool-release.jsonist ein Dev-Checkout und
behaelt die alte Fehlermeldung. Damit kann der neue Pfad im Ursprungs-Repo und in CI nicht
betreten werden - auch nicht vonrelease.ymls eigenemversion notes. - stdout traegt nur die Notes. Die Zeile, welcher Feed gefragt wird, und die, welche Version
geantwortet hat, gehen nach stderr.release.ymlleitet stdout in die Datei um, die es als
Release-Body postet; alles andere dort waere Inhalt im Release. --offlineverweigert den Aufruf und scheitert mit derrelease_urlaus dem Stamp. Dieselbe
Seite nennt auch jeder Fehlerfall des Feeds, damit ein Lauf, der die Notes nicht lesen kann,
wenigstens weiss, wo sie stehen. Ein leererbodyist ebenfalls ein Fehler: eine leere Antwort
darf nicht als "dieses Release hat nichts zu melden" durchgehen.
Gefragt werden kann nur das neueste Release:
update_urlist die einzige URL, die der Stamp
fuehrt, und eine/releases/tags/<tag>-URL daraus zusammenzusetzen waere eine geratene
API-Form statt einer gelesenen (Invariante 7). Antwortet der Feed eine andere Version als die
gefragte, wird das auf stderr benannt und die Notes werden trotzdem gedruckt - das ist nicht der
Randfall, sondern der Hauptfall, weil die Notes vor dem Tausch gelesen werden, wennVERSION
noch das Release nennt, das verlassen wird.instructions/upgrade-instance.mdSchritt 2 und INSTALL.md § "Version und Updates" tragen
entsprechend nicht mehr den Hinweis, dass der Befehl auf einer Instanz nicht antwortet; damit ist
auch die letzte der beiden Werkzeugluecken aus dieser Instruktion heraus, und ihr Vorwort nennt
keine mehr.Bei der Gelegenheit zwei Eintraege aus
tools/CONTRACT.md§ "Future considerations (not
implemented)" entfernt, die dort seit ihrer Umsetzung falsch standen: der MCP-Server-Wrapper und
dist upgradeselbst. Beide sind im selben Dokument weiter oben als existierend beschrieben.Session-Id-Fallback: Harness-Variable schliesst die Luecke zwischen Telemetrie-Join und Iteration-Budget-Gate
Gemessen an einem getracten Lauf (33
wikitool-Aufrufe, eine Sitzung): unter Claude Code, dessen
Bash-Tool jeden Aufruf in einer frisch initialisierten Shell ausfuehrt, fielchemenu.session
ohne gesetztesWIKITOOL_SESSION_IDaufos.getppid()zurueck - eine neue "Sitzung" pro Aufruf.
Der Lauf zerfiel so in 21 Telemetrie-Buckets (hoechster Bucket: 3 von 33 Aufrufen), und das
Iteration-Budget-Gate (60 Aufrufe, Loop-Breaker bei 3 identischen in Folge) sah nie mehr als 3 von
60 - strukturell unerreichbar, obwohlAGENTS.mdes als eine der vier code-durchgesetzten
Sicherungen fuehrt. Derselbe Bruch traf den Telemetrie-Join: Hook-Events (prompt.submitted)
trugen die Harness-UUID,wikitool.call-Events die wechselnde PID - kein gemeinsamer Schluessel,
undeval scorebewertete 1-3 Aufrufe statt 33.chemenu.sessionbekommt eine dritte Stufe zwischen der expliziten Variable und dem
PID-Fallback: eine kleine Registry bekannter Harness-Session-Variablen (HARNESS_ENV_VARS),
heute mit einem verifizierten Eintrag,CLAUDE_CODE_SESSION_ID. Verifiziert heisst: gegen eine
echte Sitzung gemessen, dass die Variable ueber Tool-Aufrufe hinweg stabil bleibt (anders als die
Shell-PID) und exakt der Wert ist, den derUserPromptSubmit-Hook in die Trace schreibt - der
Wert wird unveraendert als Schluessel uebernommen, kein Praefix, keine Umschreibung, sonst waere
der Join wieder zerstoert. Ein Eintrag wird nur nach genau dieser Verifikation aufgenommen: ein
Variablenname, der zufaellig existiert und etwas anderes bedeutet, waere ein stillerer Fehler als
der PID-Fallback, den er ersetzt.run_budgets Zustandsdatei (budget.json) traegt je Eintrag jetzt die Herkunft seiner Id; faellt
dieselbe Id-Zeichenkette unter eine andere Herkunft als die gespeicherte, beginnt ein neuer
Zaehler statt einen fremden zu erben - ein Eintrag ohne das Feld (vor dieser Aenderung
geschrieben) behaelt seinen Count unveraendert.doctorist jetzt dreiwertig (OKfuer eine
explizite Variable oder eine erkannte Harness-Variable,WARNnur noch fuer den reinen
PID-Fallback), und sowohlbudget statusals auch dersession.start-Event derwikitool-
Telemetriequelle nennen die Herkunft der Id.Im selben Lauf gemessener Nebenbefund auf der Emitter-Seite: ein durch eine geschlossene Pipe
abgebrochener, ansonsten erfolgreicher Aufruf (... | head) stand mitexit_code: 1in der
Trace - Click faengtBrokenPipeErrorselbst ab und erzwingtsys.exit(1), ununterscheidbar von
einem echten Fehler.cli.pyinstalliert jetzt vor jedem Dispatch einen Wrapper um
stdout/stderr, der einen EPIPE-Schreibfehler schluckt, bevor Click ihn sieht, und markiert den
Trace-Eintrag stattdessen mitstdout_truncated: truebei unveraendertem, dem tatsaechlichen
Kommandoerfolg entsprechendemexit_code.Reproduziert mit Tests, die echte Subprozesse statt In-Process-Aufrufe verwenden -
os.getppid()
ist sonst ueber die Testlaufzeit hinweg konstant: 61 Aufrufe aus je eigenem Prozess mit nur der
Harness-Variablen loesen das Gate jetzt aus, drei identische ebenso den Loop-Breaker; vor dieser
Aenderung waeren beide Tests gruen und blind gewesen.--minor: additiv (ein neues optionalessource-Feld inbudget.json, die Id faellt weiterhin
aufgetppid()zurueck, wo keine Variable greift), keine der beiden Drop-in-Richtungen verletzt.new: scaffold materializes a schema default only for a required field
tools/wikitool new instruction --name "x"schrieb bislangobligation: requiredin jede neue
Instruktion.obligation:ist ein Migrationsfeld (instructions/CONTRACT.md
§instructions/migrations/) - eine gewoehnliche Instruktion ist keine Migration und hat nichts,
was laufen muesste. Ursache:new_page._build_frontmatter()materialisierte jedes
Schema-default:unbesehen; ueber alle achttypes/*.schema.yamlgibt es genau zwei
(entity/conceptsprovenance, inrequired:;instructionsobligation:, nicht).Die Regel jetzt: ein Schema-
default:wird nur fuer ein Feld materialisiert, das das Schema auch
inrequired:fuehrt. Auf einem optionalen Feld ist eindefault:eine Lese-Annahme (was ein
fehlendes Feld bedeutet), keine Schreib-Vorgabe - sie hinzuschreiben macht aus der stillen
Annahme eine ausgesprochene Behauptung.instruction.obligations eigene Lese-Annahme steht
unveraendert und unabhaengig inkb_state.py(frontmatter.get("obligation") or REQUIRED).
Derarray-Zweig direkt daneben (leere Liste fuer ein unbesetztes Array-Feld wietags:) ist
davon ausdruecklich nicht betroffen - er bleibt fuer optionale wie Pflichtfelder gleich, weil ein
fehlender Schluessel sonst den Template-Filter-Suffix woertlich in den Body schreiben wuerde
({related|bullets}-> das Wort "bullets").--patch: kein Bestandsdokument aendert sich (obligation:stand bislang nur explizit oder auf
den beiden Migrationsdokumenten), keine Migration noetig, und ein zurueckgerolltes Werkzeug
schriebe das Feld nur wieder mit.Stale
wiki/path literals swept out of tools/ and types/, with a test guarding against the next renameDie Wissensschicht wurde am 2026-08-21 von
wiki/nachkb/umbenannt. Das Verzeichnis zog um,
die Zeichenkette nicht: 33 Stellen nannten weiter einen Pfad, den es nicht mehr gibt. Gemeldet
war davon eine - die Kopfzeile des Lint-Reports (Scanned N pages under `wiki/`) - als
kosmetischer Einzelfall. Der Scan selbst war immer korrekt:run_lint(kb_dir)laeuft ueber
kb/, gezaehlt wird, was dort liegt. Falsch waren ausschliesslich die Beschriftungen.Dreizehn davon sind nutzersichtbar. Die Fehlermeldungen von
xref,cite,touch,
move,rm,rename,raw acceptundlog statusnanntenwiki/, ebenso die--help-Texte
voncite sync --all,provenance rebuild-index --dry-runundmove --reconcile. Dazu die
description:-Felder intypes/type-spec.schema.yaml, die uebertypes describeund ueber jede
Schema-Validierungsmeldung bei einem Agenten landen. Zwei Stellen waren doppelt falsch:
git_publish.pyundrun_budget.pyverwiesen aufwiki/concepts/Mass-Update Gate.md, waehrend
die Seite unterkb/concepts/workflows/Mass-Update Gate.mdliegt - dort war auch die
Collection-Ebene veraltet.Nicht angefasst:
raw/(unveraenderlich, was immer dort steht) und die Alteintraege dieser
Datei. Beide sind Aufzeichnungen dessen, was zu ihrer Zeit galt, keine Wegweiser - dieselbe
Unterscheidung, dieinstructions/dev/issue-tracking.mdfuer den Tracker trifft.Dass es vier Wochen unbemerkt blieb, ist der eigentliche Befund: kein Check liest ein Pfadliteral
in Quelltext.docs verifykam dafuer nicht in Frage, weil esshipped_prose()liest, also
Markdown - der Grossteil des Defekts sass in.py-Zeichenketten. Der Guard ist deshalb ein Test:
tools/chemenu/tests/test_source_hygiene.pyscannt jede.py-Datei untertools/chemenu/sowie
tools/wikitoolgegen eine Tabelle stillgelegter Stufenpfade. Die naechste Umbenennung traegt
dort eine Zeile nach und bekommt jede vergessene Stelle als Testfehler, statt als Zeichenkette,
die ein Jahr lang niemand liest. Die zwei Ausnahmen stehen bewusst als Liste mit Begruendung und
nicht als geschickteres Muster: eine Fixture-URL, in derwikiein Repository-Name ist, und die
Guard-Datei selbst, die die stillgelegten Pfade ja gerade deklariert.kb/entities/projects/Chemenu.mdtrug denselben Fehler in einer Kerndaten-Zeile und wurde ueber
touchnachgezogen. "Dreilagig" blieb dort stehen: das deckt sich mit der Concept-Seite
Three-Layer Architecture, diereports/ausdruecklich als vierte Phase neben den drei
Schichten fuehrt.--patch: keine Schnittstelle aendert sich, kein Verhalten, keine Migration. Ein
zurueckgerolltes Werkzeug gibt nur wieder die alten Beschriftungen aus.CHANGES.md/Guard-Docstring: die Zahl der nachgezogenen Pfadliterale korrigiert (33, nicht 27)
Der Eintrag darueber nannte 27 nachgezogene Stellen und "rund die Haelfte davon nutzersichtbar".
Beides war falsch. Die 27 stammten aus einemwc -l, das nurtools/**/*.pygezaehlt hatte -
tools/wikitool,types/type-spec.mdund die vierdescription:-Felder in
types/type-spec.schema.yamlfehlten darin. Nachgezaehlt am Commit selbst
(git show <sha> | grep -c '^-.*wiki/'): 33, davon 32 im Stack und eine auf der Seite
Chemenu. Nutzersichtbar sind davon dreizehn, also gut ein Drittel und nicht die Haelfte.Derselbe Zahlendreher stand im Docstring von
tools/chemenu/tests/test_source_hygiene.py, wo er
kuenftigen Lesern erklaert, wogegen der Guard schuetzt - dort ebenfalls korrigiert. Dass diese
Korrektur einen eigenen Bump braucht, ist kein Formalismus: der Docstring liegt untertools/,
und das Version-Gate in.gitea/workflows/ci.ymlist nach Pfad geschnitten, nicht nach Absicht.--patch: reine Prosakorrektur, kein Verhalten, keine Schnittstelle.
This note is a snapshot of the
CHANGES.mdentry as it stood when the tag was cut, and
is never edited afterwards. The maintained version of this text - including any later
correction - is the entry for this version inCHANGES.mdin the repository.Downloads
-
v6.0.1 Stable
released this
2026-09-16 04:47:50 +00:00 | 118 commits to main since this release6.0.1 - 2026-09-16 - docs toc/verify erreichen die .template-Form einer Referenzdatei
Author: Torben Nehmer
High impact
- docs toc/verify erreichen die .template-Form einer Referenzdatei
docs toc/verify erreichen die .template-Form einer Referenzdatei
kb/CONVENTIONS.md.templatewar 105 Zeilen lang und trug keine TOC-Region.toc.target_files()
berechnete den Dateisatz ueber die adoptierten Namen, und eine Datei auf.md.templatefaellt
aus jedem dieser Walks heraus - also hatdocs toc --applydas Template nie angefasst und
docs verifyes nie gelesen. Eine Instanz, die es nachinstructions/setup-instance.md
adoptiert, bekam damit einekb/CONVENTIONS.mdohne Region und fiel amdocs verifyin
Schritt 13 derselben Anleitung um - dem Befehl, mit dem das Setup endet. Ausgeliefert war das in
6.0.0.Eine in Scope stehende Datei nimmt ihr
<name>.templatejetzt mit hinein: das Template ist
dasselbe Dokument einen Schritt frueher in seinem Leben, und wer es auslaesst, laesst die
adoptierte Kopie den Fehler erben.docs verifyprueft im Ursprungs-Repo damit 57 statt 56
Referenzdateien, in einer frisch exportierten Instanz 59.Ausgeloest hat es ein Wachstum um sechs Zeilen:
f350999hat das Template von 99 auf 105 Zeilen
gebracht und damit ueber die Schwelle von 100. Seither warci.ymlauf jedem Push rot (Laeufe
279 bis 289) - was als Flackern gelesen wurde, weil jeder Push zusaetzlich einen gruenen
release.yml-Lauf erzeugt und die Paare wie Lauf und Wiederholung aussehen. Sie sind zwei
verschiedene Workflows.Grenzuebertritt-Frage geprueft und verneint, gegen den dokumentierten Update-Weg: das Template ist
stack-eigen (ownership.is_stack_owned- jede.templateunter einer Content-Stage), steht nicht
inUPGRADE_PRESERVED_PATHS, unddist upgradeschreibt es damit mit. Eine Instanz bekommt das
reparierte Template also durch den Upgrade selbst, ohne Handarbeit; der Rueckweg funktioniert
ebenso, weil die alte Maschinerie das Template gar nicht erst prueft. Handarbeit faellt nur an, wo
eine Instanz ihr stack-eigenes Template lokal veraendert hat -dist upgrademeldet genau das als
blockedund verlangt--keep-local.Verifiziert:
docs verify/instructions verifygruen, 1275 Tests gruen (3 neu: das Template einer
in Scope stehenden Datei steht im Dateisatz, ein.templateohne solche Datei daneben nicht
(USER.md.template), und ein Template ueber der Schwelle ohne Region ist ein Befund - der letzte
waere am heutigen Stand rot gewesen). Dazu der vollstaendigesetup-instance.md-Replay gegen einen
frischendist export:doctor,docs verify,instructions verifyundlintlaufen in der
frischen Instanz durch.
This note is a snapshot of the
CHANGES.mdentry as it stood when the tag was cut, and
is never edited afterwards. The maintained version of this text - including any later
correction - is the entry for this version inCHANGES.mdin the repository.Downloads
-
v6.0.0 Stable
released this
2026-09-15 19:38:53 +00:00 | 119 commits to main since this release6.0.0 - 2026-09-15 - search: Pfad und Titel vollstaendig, Trunkierung sichtbar
Author: Torben Nehmer
Breaking Change:
- docs verify loest ab dieser Version jeden relativen Markdown-Link in den Referenzdateien auf und meldet ein totes Ziel als Fehler - auch in kb/CONVENTIONS.md und kb//COLLECTION.md, die eine Instanz selbst besitzt und die ein Drop-in-Copy der Maschinerie nicht ersetzt. Eine Instanz, deren eigene Konventions- oder Collection-Datei einen relativen Link mit falscher ../-Tiefe oder auf eine inzwischen geloeschte Datei traegt, sieht docs verify nach dem Update fehlschlagen, wo es vorher durchlief. Reparatur: den in der Meldung genannten Datei:Zeile-Link korrigieren - kein Werkzeuglauf, keine Inhaltsmigration.
- docs verify prueft die TOC-Region ab dieser Version auch auf types/.md und docs/.md. Eine Instanz, die die Page-Type-Spec-Templates adoptiert hat, traegt types/source.md und types/concept.md ohne Region und sieht docs verify nach dem Update fehlschlagen, wo es vorher durchlief; dasselbe gilt fuer eine selbst angelegte oder lokal geaenderte docs/-Seite ueber 100 Zeilen. Reparatur: tools/wikitool docs toc --apply - ein Werkzeuglauf, keine Inhaltsmigration.
Migration: none required - Keine kb/-Seite aendert ihre Form. Der Grenzuebertritt ist ein strengerer Check auf instanz-eigener Prosa, keine Schema- oder Frontmatteraenderung.
High impact
- SKILL.md: relative Links durch repo-root-relative Pfade ersetzt, docs verify/instructions verify pruefen Linkziele
- docs verify: der Linkziel-Check erreicht auch die instanz-eigenen kb/CONVENTIONS.md und COLLECTION.md - daher Grenzuebertritt
- TOC-Scope auf types/ und docs/ erweitert, Sprachregeln zentralisiert, --breaking akkumuliert
- types/: Seiten-Type-Spec-Anleitungsprosa in stackeigene guidance-Datei ausgelagert
Medium impact
- docs verify: ein nur als .template ausgeliefertes Linkziel gilt als aufgeloest
- Control-Plane-Sprache universell: Achse ist das Publikum, kein Instanz-Schalter
- types/type-spec.schema.yaml enforced against real type-spec frontmatter
- search: Pfad und Titel vollstaendig, Trunkierung sichtbar
Low impact
- gates.md/session-setup.md: die Budget-Ausnahme von version regrade haengt an der Aufrufform
- types/type-spec.md: Ownership und Sprache getrennt benannt (Nachzug zu #99)
Ausgangspunkt war ein realer Bruch:
instructions synckopiert jedeSKILL.mdin eine andere
Verzeichnistiefe, und 52 von 58 relativen Links darin zeigten in der publizierten Kopie ins Leere,
unbemerkt, weil kein Check je ein Linkziel gelesen hat. Die Reparatur - repo-root-relative Pfade
statt../-Links - zieht zwei neue mechanische Checks nach sich (instructions verifyverbietet
relative Links inSKILL.md,docs verifyloest Linkziele in allen Referenzdateien auf), und der
zweite Check erreicht auch instanz-eigene Prosa (kb/CONVENTIONS.md,COLLECTION.md), die ein
Drop-in-Copy nicht ersetzt - der Grenzuebertritt, der diesen Kandidaten auf6.0.0eskaliert hat.
Denselben Linkziel-Check bekommt die TOC-Pflicht gleich mit auftypes/unddocs/erweitert, und
die Sprachregeln fuer die Control-Plane sind zu einer einzigen, publikumsbasierten Regel in
AGENTS.mdzentralisiert statt eines Instanz-Schalters. Daneben, unabhaengig vom Linkproblem: die
Seiten-Type-Spec-Anleitungsprosa ist in eine stackeigene Guidance-Datei ausgelagert,
type-spec.schema.yamlwird jetzt gegen echte Type-Spec-Frontmatter durchgesetzt, undsearch
zeigt Pfad und Titel eines Treffers vollstaendig statt trunkiert.gates.md/session-setup.md: die Budget-Ausnahme von version regrade haengt an der Aufrufform
Doku-Nachzug zu
5.1.0. Beide Dateien beschrieben die Budget-Ausnahme als feste Liste pro
Kommandoname ("fixed allowlist");version regradeist die erste Ausnahme, die nur in einer
Aufrufform liest - bar listet sie, mit Positionen schreibt sieCHANGES.md. Die Liste selbst
bleibt an ihrem einen Ort (tools/CONTRACT.md), beide Stellen benennen jetzt aber, dass dort ein
Eintrag pro Aufruf statt pro Namen gilt. Aufgefallen in der Schlussphase derselben Arbeit, deshalb
ein eigener Patch-Bump: der Pfadinstructions/liegt im Version-Gate der CI.SKILL.md: relative Links durch repo-root-relative Pfade ersetzt, docs verify/instructions verify pruefen Linkziele
instructions synckopiert jedeSKILL.mdbyteidentisch in.agents/skills/und
.claude/skills/- eine andere Verzeichnistiefe als die Quelle, ohne deren Nachbardateien. 52 von
58 relativen Markdown-Links in den sieben Skills zeigten deshalb in der publizierten Kopie ins
Leere, unbemerkt, weil kein Check je ein Linkziel gelesen hat (Gitea-Meldung: einsession-setup.md-Read
schlug in einer ausgelieferten Instanz fehl). Alle 58 Links sind jetzt repo-root-relative
Klartextpfade (instructions/session-setup.mdstatt[session-setup.md](../session-setup.md)) -
sie ueberleben die Kopie unveraendert, weil sie nicht von der Position der lesenden Datei abhaengen.
instructions/CONTRACT.md§ "A skill's outbound reference is a plain path, not a link" traegt die
Regel.Zwei neue mechanische Checks verhindern das Wiederauftreten:
instructions verifyverbietet jeden
relativen Markdown-Link in einerSKILL.md(check_skill_reference_paths),docs verifyloest
jeden relativen Link in den flachen Instructions und Contracts gegen den Arbeitsbaum auf
(check_reference_targets, ueber denselben Dateisatz wiedocs toc). Nebenbei behoben:
instructions/dev/doc-pull-through.mdhatte zwei Links mit falscher../-Tiefe, unabhaengig vom
Skill-Copy-Problem.docs verify: der Linkziel-Check erreicht auch die instanz-eigenen kb/CONVENTIONS.md und COLLECTION.md - daher Grenzuebertritt
Nachtraegliche Neueinstufung des Bumps darueber, kein zusaetzlicher Code.
check_reference_targets
laeuft ueber den Dateisatz vondocs toc, und fuenf Dateien darin gehoeren der Instanz statt dem
Stack:kb/CONVENTIONS.mdund die vierkb/<collection>/COLLECTION.md. Ein Drop-in-Copy von
tools/,types/,instructions/undAGENTS.mdersetzt sie nicht - ein toter relativer Link
darin laesstdocs verifynach dem Update fehlschlagen, wo es vorher durchlief. Genau die Form,
dietools/README.md§ Adding a command Schritt 5 als MAJOR-Zeile benennt ("a stricter check that
newly fails on shipped content an instance already had"), undinstructions/dev/version-parts.md
entscheidet den Zweifelsfall zugunsten des Grenzuebertritts.Gemessen bricht heute nichts: die zweite bekannte Instanz traegt 25 relative Links in diesen fuenf
Dateien, davon null tote; dieses Repo ebenso. Die Einstufung folgt der Reichweite des Checks, nicht
einem beobachteten Schaden - der Preis einer unnoetigen MAJOR ist eine Release-Notiz, der Preis
einer MINOR, die doch bricht, ist eine Instanz mit fehlschlagendem Update-Pfad unter einer
Versionsnummer, die Drop-in versprochen hat. Aufgefallen ist es in der Schlussphase beim Lesen der
eigenen Regel intools/README.md, nicht durch einen Check - wasdocs/version-model.mdueber
genau diese Stelle sagt ("a person looking at the diff ... not a validator"), hat sich hier
wiederholt.docs verify: ein nur als .template ausgeliefertes Linkziel gilt als aufgeloest
Defektbehebung am Check aus den beiden Bumps darueber, gefunden unmittelbar nach deren Publish.
check_reference_targetsmeldete auf einem frisch exportierten Baum 13 tote Links -kb/CONTRACT.md
neunmal, dazugerman-terminology.md,kb-profiles.mdundlink-taxonomy.md- und zwar dafuer,
dass der Export tut, was er soll.kb/CONVENTIONS.mdund die vierkb/<name>/COLLECTION.mdsind
instanz-eigen: die Distribution traegt<name>.template, und die Instanz uebernimmt sie erst im
Personalisierungsschritt voninstructions/setup-instance.mddurch Umbenennen. Zwischen
dist exportund diesem Schritt existiert die fertige Datei berechtigterweise nicht, waehrend die
stack-eigenen Dateien sie unter ihrem kuenftigen Namen verlinken - korrekt, denn so wird sie heissen.Ein Linkziel gilt jetzt auch dann als aufgeloest, wenn daneben
<ziel>.templateliegt. Die
Ausnahme ist eng: fehlt beides, bleibt es ein Befund. Damit beschreibt der Check nicht laenger
"noch nicht personalisiert" als "kaputter Link" - diesen Zustand meldetdoctorunter
conventionspraezise und zustaendig.CI war davon nie rot: der Replay in
.gitea/workflows/ci.ymluebernimmt die Templates, bevor er
docs verifyaufruft, und der dokumentierte Weg insetup-instance.mdstellt die Personalisierung
(Schritt 5/6) ebenfalls vor die Verifikation (Schritt 13). Getroffen haette es jeden, der nach dem
Export einmal zur Kontrolledocs verifyaufruft. Aufgefallen ist es, weil die Verifikation des
vorherigen Publishes den Arbeitsbaum geprueft hatte und nicht den exportierten - ausgerechnet bei
einer Aenderung, deren ganzer Gegenstand Kopien in anderer Verzeichnistiefe sind.TOC-Scope auf types/ und docs/ erweitert, Sprachregeln zentralisiert, --breaking akkumuliert
Drei Straenge, ausgeloest von einer Beobachtung: manche agentengeladene Referenzdatei trug keine
TOC, und manche Instruction war teilweise deutsch.TOC-Scope. Die Pflicht aus
5.0.0galt fuerAGENTS.md, die Stage-Contracts,
kb/CONVENTIONS.md, jedeCOLLECTION.mdund die flacheinstructions/**.md-Form.docs/und die
Seiten-Type-Specs fielen ohne genannten Grund heraus - waehrendSKILL.mdund die Menschendoku
ihren Ausschlussgrund im Docstring stehen hatten, was die beiden anderen Luecken wie Absicht
aussehen liess.docs/ist dabei genau der Fall, fuer den die Schwelle existiert:
AGENTS.md§ File naming fuehrt es als agentengeladen per Link, also am zweiten Hop. Beide sind
jetzt drin; vier Dateien haben eine Region bekommen.SKILL.mdbleibt die eine Ausnahme, und
zwar belegt statt behauptet: die vendorte Guidance setzt den SKILL.md-Body auf die Ladeebene, die
beim Triggern ganz gelesen wird, und richtet ihren eigenen TOC-Rat an die gebuendelten
Referenzdateien daneben. Ein Type-Spec wird zwar auch ganz geladen, aber eben auch als Datei
gelesen - deshalb traegt es eine Region, undtypes describestrippt sie aus seiner Ausgabe, weil
dort der ganze Body ohnehin mitkommt.Sprache. Die Regel gab es schon ("the control plane stays English"), sie stand nur in
kb/CONVENTIONS.md- einer Datei, die der Instanz gehoert und die sie umschreiben darf, waehrend
die Regel stackeigene Dateien bindet. Sie ist nachAGENTS.md§ File naming gezogen, zusammen mit
einer zweiten, die vorher gar nicht geschrieben stand: ein Agent spricht die KB-Sprache der
Instanz. Der Wert dafuer lebt weiter inkb/CONVENTIONS.mdslanguage:;SOUL.mds eigene
Sprache:-Zeile war damit eine Dublette und ist weg.instructions/setup-instance.md- 297 Zeilen,
die einzige vollstaendig deutsche Instruction, verbatim an jede Instanz ausgeliefert - ist
uebersetzt, samtdescription:. Die zwei deutschen Blockquotes in den Dev-Skills sind es auch; sie
lesen sich jetzt als englisches Modell der Nachricht, die der Agent in der KB-Sprache ausspricht.Dieselbe Regel gilt fuer alles, was als Template ausgeliefert wird - eine Instanz adoptiert es,
bevor sie ihre Sprache ueberhaupt gewaehlt hat.USER.md.template,SOUL.md.templateund
ENVIRONMENT.md.templatewaren vollstaendig deutsch und sind uebersetzt;kb/sources/und
kb/concepts/COLLECTION.mdwaren es in Teilen und ziehen jetzt mitkb/entities/und
kb/comparisons/gleich, die es laengst waren. Bei den vier Seiten-Type-Specs laeuft der Schnitt
mitten durch die Datei, und zwar entlang derselben Prosa/Identifier-Grenze, diekb/CONTRACT.md
schon innerhalb einer Seite zieht: die Anleitungsprosa ist Anweisung an einen Agenten und damit
Control Plane, der## Template-Block und dielayout:-Titel sind Seitentext und bleiben in der
KB-Sprache -wikitool new entityscaffoldet also weiter deutsche Ueberschriften.
kb/CONVENTIONS.mdbehauptete bis hierher, die Type-Specs folgten als Ganzes der KB-Sprache; der
Satz ist auf den tatsaechlichen Schnitt nachgezogen.
Mechanisch geprueft wird nichts davon: ein Stoppwort-Scan schluege auf dem zitierten Vokabular in
kb-profiles.mdundlink-taxonomy.mdfalsch an. Stattdessen nennen
instructions/CONTRACT.md§ "Writing an instruction" undstack-devdie Regel an der Stelle, an
der sie befolgt oder verloren wird.--breakingakkumuliert. Bis hierher ersetzte ein zweites--breakingdie Zeile des
Kandidaten - der Eintrag versprach dann einen Bruch und lieferte zwei. Genau dieser Kandidat ist der
Fall: sein Linkziel-Uebertritt ausbeta.1und der TOC-Uebertritt von hier sind zwei Dinge, auf die
ein Betreiber getrennt reagieren muss. Eine Begruendung bleibt flach auf der Markerzeile, ab der
zweiten werden es Bullets; eine vor dieser Aenderung geschriebene Einzelzeile liest sich unveraendert
als Ein-Element-Liste zurueck, also musste kein bestehender Eintrag angefasst werden.--migration:
bleibt bewusst eine Einzelzeile - sie beantwortet eine Ja/Nein-Frage ueber den Kandidaten als Ganzes,
und--migration-requiredist ihr Ruecknahmepfad. Fuer eine falsche Breaking-Begruendung gibt es
keinen; der Kandidat ist bis zum Release dev-lokal.Nebenbefund, den die Scope-Erweiterung sofort aufgedeckt hat:
docs/version-model.mdverlinkte nach
instructions/dev/version-parts.md, dasdist exportwegschneidet - im Ursprungs-Repo gruen, in
jeder ausgelieferten Instanz ein toter Link. Jetzt ein Klartextpfad mit dem Satz, warum er keiner
ist.types/type-spec.md: Ownership und Sprache getrennt benannt (Nachzug zu #99)
types/type-spec.mdsagte weiterhin, Prosa,## Template-Body und Sprache eines
Seiten-Type-Specs gehoerten der Instanz, die bei anderer KB-Sprache "einfach die Datei
uebersetzt" - genau das Gegenteil des Schnitts, den der Bump davor ausgeliefert hat. Aufgefallen
in der Schlussphase, beim Nachdenken darueber, welche Sprachregel fuer einen instanz-eigenen
neuen Seitentyp gilt.Der Abschnitt trennt die zwei Fragen jetzt: Ownership sagt, wer eine Zeile aendern darf, die
Sprache folgt davon unabhaengig dem Publikum der Zeile - Anleitungsprosa an einen Agenten ist
Control Plane und englisch,## Template-Body undlayout:-Titel sind Seitentext in der
KB-Sprache, Feldnamen und Enum-Werte sind Identifier und werden nie uebersetzt. Als Tabelle, weil
der Schnitt mitten durch eine Datei laeuft und eine Aufzaehlung im Fliesstext ihn genau deshalb
nicht haelt. Der Satz bindet ausdruecklich auch einen Type-Spec, den eine Instanz sich selbst
schreibt: der ist zwar durchgaengig instanzeigen, aber seine Anleitungshaelfte hat trotzdem einen
Agenten als Leser.Control-Plane-Sprache universell: Achse ist das Publikum, kein Instanz-Schalter
Die Sprachregel in
AGENTS.mdruhte auf einer Begruendung, die schmaler war als sie selbst:
"Every file in the table above belongs to the stack and ships to instances that share none of
this instance's language choices, so:". Das traegt nur fuer ausgeliefertes Material und laesst
offen, was fuer ein Control-Plane-Dokument gilt, das eine Instanz nur fuer sich selbst schreibt -
eine eigene Instruction, ein selbst angelegter Seitentyp (types/nimmt einen ohne Code-Aenderung
auf), ein weiterer Stage-Contract. Genau dort fallen Ownership und Publikum auseinander: die Datei
ist durchgaengig instanzeigen, ihre Anleitungshaelfte hat trotzdem einen Agenten als Leser.Der Vorsatz nennt jetzt die tatsaechliche Achse - die For-Spalte der Tabelle darueber, also wer
die Zeile liest, und weder wem die Datei gehoert noch ob sie den Checkout je verlaesst. Regel 1
sagt ausdruecklich, dass sie auch fuer ein nie ausgeliefertes Control-Plane-Dokument gilt und dass
es nebenkb/CONVENTIONS.mdslanguage:bewusst keinen zweiten Sprachwert gibt.
kb/CONVENTIONS.mdund ihr.templatesagen dasselbe von ihrer Seite aus: die
Control-Plane-Sprache ist keine Einstellung, die diese Datei zurueckhaelt - es ist gar keine.Die Begruendung dazu steht als neue
docs/-Seite
(docs/language-boundaries.md), weil sie sonst in einem Jahr neu
verhandelt wird: warum Englisch (der Stack redet fast nur ueber Identifier, und die sind
englisch), warum kein Parameter (die Kosten traegt jede Datei, den Nutzen haette ein Dokument, das
ohnehin nur ein Agent liest), und was die Entscheidung wieder aufmachen wuerde. Die Seite haelt
zugleich fest, welches Argument falsch war: "Sprache folgt der Ownership" hat funktioniert,
solange nur ausgeliefertes Material betrachtet wurde, und faellt am instanz-eigenen Typ.Nebenbei zwei Befunde derselben Ecke behoben. Der Docstring von
dist_cmd.instance_owned_type_stems()behauptete weiter, "its prose, its template and its
language are the instance's business" - Stand vor dem TOC-/Sprach-Bump oben. Und die
Aufzaehlung derdocs/-Seiten inAGENTS.mdsagte "Four pages exist today", waehrend das
Verzeichnis fuenf trug:docs/model-and-effort-selection.mdfehlte, und zwar absichtlich, weil
ein Link dorthin die Claude-Code-eigene Entscheidung in die anderen drei Harnesses laden wuerde.
Der Satz zaehlt jetzt, was von hier aus verlinkt ist, und benennt die sechste Seite samt Grund.types/: Seiten-Type-Spec-Anleitungsprosa in stackeigene guidance-Datei ausgelagert
Ein
root: kbType-Spec (entity,concept,source,comparison) hatte zwei Publika in
einer Datei: Anleitungsprosa fuer den Agenten (When to use/When NOT to use/Authoring guidance),
und Seitenmaterial (## Template-Block,layout:-Titel). Ownership gilt pro Datei, also wurde
die ganze Datei beim Setup als.templateadoptiert und danach nie wieder angefasst - eine
Instanz, die ihre Type-Specs frueh adoptiert hat, las bis in alle Zukunft die Anleitung vom Tag
ihrer Erzeugung, weildist upgradedas.templateneben die adoptierte Datei schrieb, nie die
Datei selbst (docs/ownership-and-templates.md§ "Where the file boundary strains").Der urspruengliche Vorschlag drehte den Schnitt um (Type-Spec stackeigen, Seitenmaterial heraus)
und wurde beim Pruefen gegensetup-instance.mdundevolve-subtypes.mdverworfen: die
Frontmatter-Konfiguration (layout:, Enum-Werte,base_dir) ist instanzeigener Inhalt, keine
Stack-Maschinerie - beide Instructions weisen die Instanz an, Enum undlayout:-Eintrag in
derselben Aenderung zu setzen. Stattdessen bleibt der Type-Spec instanzeigen, und nur die
maschinenabgeleitete Anleitungsprosa zieht in eine neue, stackeigenetypes/<name>.guidance.md,
verknuepft ueber ein optionalesguidance:-Frontmatterfeld (neuer, nicht instanziierbarer Typ
type-guidance, wielint-reportohnebase_dir:).tools/wikitool types describe <name>
komponiert beide Haelften weiterhin zu einer Antwort - ein Agent muss nie wissen, dass ein Typ aus
zwei Dateien besteht.type_resolver.extract_template()liest das Template unveraendert allein
austypes/<name>.md; kein zweiter Ladepfad fuerwikitool new.dist_cmd._plan_types()/find_leaks()teilten sich vorhername.split(".", 1)[0]als
Stamm-Berechnung - beides haetteentity.guidance.mdfaelschlich als instanzeigenen Stamm
"entity" erkannt (die eine haette sie zum.templategemacht, die andere sie als Leak gemeldet).
Neuer gemeinsamer Prädikat_owned_type_stem()prueft die exakte Endung (<stem>.mdoder
<stem>.schema.yaml), nicht den ersten Punkt.Grenzuebertritt-Frage bewusst geprueft und verneint: Drop-in in beide Richtungen (ein Type-Spec
ohneguidance:verhaelt sich unveraendert, eine alte Maschinerie liesttypes/<name>.mdwie
zuvor und die Guidance-Datei ist fuer sie inert), also--minorstatt--major. Die einmalige
Adoption in einer bestehenden Instanz ist alsinstructions/migrations/6.0.0-type-guidance-split.md
dokumentiert -obligation: offered, der erste Gebrauch dieses seit 4.0.0 existierenden, bis jetzt
unbenutzten Mechanismus fuer ein instanzeigenes, upgradebares Machinery-File.Verifiziert:
tools/wikitool docs verify/instructions verifygruen, 1261 Tests gruen (8 neu:
get_guidance, das Template bleibt auftypes/<name>.mdallein geladen, die Guidance-Datei
schifft verbatim neben einem.template-adoptierten Type-Spec statt als weiteres.template,
eindist upgradeschreibt verbesserte Guidance-Prosa in eine adoptierte Instanz obwohl deren
Type-Spec selbst nie im Stamp stand,types describekomponiert beide Haelften in JSON und
Textausgabe getrennt nachweisbar).types/type-spec.schema.yaml enforced against real type-spec frontmatter
Bei der Vorbereitung der Aenderung oben fiel auf:
types/type-spec.schema.yamltraegt
additionalProperties: false, kannte aberroot:undcapture_fields:nicht, obwohl
types/instruction.mdbzw.types/source.mdbeide Felder tragen undtype_resolver.get_root()/
get_capture_fields()sie lesen. Gegen das Schema validiert waeren beide Type-Specs ungueltig
gewesen. Dass es niemandem auffiel, war der eigentliche Befund: Type-Spec-Frontmatter wurde
nirgends gegen sein eigenes Schema validiert -resolver.validate_frontmatter()lief nur ueber
kb/-Seiten, neu erzeugte Seiten und Instruktionsdateien, nie ueber die Type-Specs selbst.
TypeResolver._validate_type_spec(), der einzige Weg, den der Selbstbezugtype: types/type-spec.md
nimmt, prueft ausschliesslich, obtype/name/descriptionvorhanden sind.Beide fehlenden Felder ergaenzt (
root:als Enumkb/repo,capture_fields:als Liste wie
page_ref_fields:), dazuguidance:(seit der Aenderung oben real benutzt, aber noch nie im
Schema).docs verifybekommt eine neue Pruefung: jede Datei untertypes/mit
type: types/type-spec.mdvalidiert jetzt gegentypes/type-spec.schema.yaml
(check_type_spec_frontmatter(), wiederverwendetresolver.list_type_specs()statt eines zweiten
Parse-Durchlaufs).types/type-spec.md§ Validation Contract und die beidendocs verify-Zeilen
intools/CONTRACT.mdnennen das jetzt.Daneben ein zweiter, unabhaengiger Befund derselben Aufraeumrunde behoben:
instructions/dev/doc-pull-through.mdverwies fuerdocs/-Seiten weiter auf "AGENTS.md § File
naming lists all four" - der Zaehler in AGENTS.md selbst war beim vorigen Bump schon auf fuenf
(plus eine sechste, nur vonCLAUDE.mdaus verlinkte) korrigiert worden, diese eine verbliebene
Stelle nicht.Grenzuebertritt-Frage geprueft und verneint: additiv in beide Richtungen - eine bestehende Instanz
validiert bereits (0 Befunde gegen den realen Baum), und ein Type-Spec ohne die drei neuen Felder
bleibt unveraendert gueltig.--patch, kein--breaking, keine neue Migration noetig.Verifiziert:
tools/wikitool docs verify/instructions verifygruen, 1263 Tests gruen (2 neu:
alle Type-Specs dieses Repos validieren gegen ihr eigenes Schema; ein Type-Spec mit einem dem
Schema unbekannten Feld wird gemeldet, mit Dateiname und Feldname in der Meldung).search: Pfad und Titel vollstaendig, Trunkierung sichtbar
Gemeldet wurde eine Sitzung, die nach
wikitool searchzusaetzlichgrep -rlueberkb/
laufen liess. Der Grep war redundant -searchist einrg-Lauf ueberkb/und kann keine
Seite verfehlen, die ein Grep findet -, aber die Ausgabe gab ihr drei Gruende dafuer, und die
sind der eigentliche Befund.Die Tabelle nannte keinen Pfad, obwohl
wiki-queryverlangt, nur die Seiten zu lesen, auf
die die Suche zeigt. Sie kappte ausserdem den Titel auf 34 Zeichen - im gemeldeten
Transkript vier von fuenf Treffern -, und der Titel ist nach Invariante 2 der einzige
Identifier einer Seite und das Argument, dastouch,xref addundcite addnehmen. Die
Sitzung hatte also weder etwas zum Oeffnen noch etwas zum Weiterreichen;grep -rllieferte
genau beides.Drittens war
N result(s).die gekappte Zahl:run_searchgab nur die beschnittene Liste
zurueck, also konnte kein Adapter die Gesamtzahl melden, und20 result(s).auf einer Anfrage
mit 182 Treffern war von einem vollstaendigen Ergebnis nicht zu unterscheiden. Eine
Vollstaendigkeitsaussage, zu der die Ausgabe nicht berechtigt war - der staerkste denkbare
Anlass, ihr zu misstrauen.Die Zeile hat jetzt die Form
score | kind/subtype | titel | pfad | summary, ohne
Spaltenauffuellung. Titel und Pfad werden nie gekappt; die Summary ist das einzige verlustige
Feld und steht deshalb am Ende, wo ein|in Prosa beim Trennen mitmaxsplit=4folgenlos
bleibt (ein|im Titel schliesst die Wikilink-Syntax ohnehin aus). JSON als Default-Ausgabe
wurde erwogen und verworfen: ein Treffer ist flach, JSON kostet dafuer ein Vielfaches an Tokens,
undsearchexistiert dafuer, Retrieval billig zu machen - der Fehler war ein fehlendes Feld,
kein Parse-Problem. Wer Struktur braucht, hat--json,api.searchund MCP.run_searchgibt jetzt einSearchResultmit Treffern, Gesamtzahl und Limit zurueck. Die
Tabelle schreibt50 of 182 result(s) - raise --limit (0 for all) or narrow the query., das
JSON traegttotal/truncated/limitnebencount, dessen Bedeutung unveraendert bleibt
(len(results)), undapi.searchsowie der MCP-search-Tool tragen dieselben Felder. Das
Default-Limit steigt von 20 auf 50 und liegt als eine KonstanteDEFAULT_LIMITstatt als drei
Literale in drei Adaptern: gekappt wurden bisher vor allem die strukturellen Sweeps
(--field '!sources'), die alphabetisch und nicht nach Relevanz sortiert sind, wo die Kappung
also eine beliebige Scheibe der Antwort wegwirft statt ihres schwaechsten Endes. Sichtbar zu
sein ist es, was ein endliches Default ueberhaupt erst unbedenklich macht.AGENTS.md§ Routing traegt die Regel an genau einer Stelle -searchist erschoepfend, ein
eigener Grep ueberkb/fuegt nur die generierten Dateien hinzu, die Invariante 1 ohnehin
verbietet;tools/CONTRACT.mdtraegt daneben nur den Mechanismus.Grenzuebertritt-Frage geprueft und verneint: kein Flag entfernt oder umbenannt, keine
Umgebungsvariable, keine maschinengelesene Datei in ihrer Form veraendert, JSON rein additiv.
Die Tabelle liest ein Agent, kein Skript, und ihre Aenderung verlangt keiner Instanz Handarbeit
ab.Verifiziert:
docs verify/instructions verifygruen, 1272 Tests gruen (9 neu: Pfad vorhanden;
Titel und Pfad ungekappt bei langem Titel; eine Trefferzeile zerfaellt trotz|in der Prosa in
ihre fuenf Felder; ein gekapptes Ergebnis nennt die Gesamtzahl, ein ungekapptes behauptet
nichts;--limit 0gilt nie als gekappt; die Gesamtzahl ueberlebt das Limit inrun_search;
api.searchmeldet dasselbe; alle drei Adapter teilen ein Default-Limit - der MCP-Golden-Test
haelt die neuen Felder zwischen CLI und Server zusammen).
This note is a snapshot of the
CHANGES.mdentry as it stood when the tag was cut, and
is never edited afterwards. The maintained version of this text - including any later
correction - is the entry for this version inCHANGES.mdin the repository.Downloads
-
v5.1.0 Stable
released this
2026-09-12 16:27:52 +00:00 | 133 commits to main since this release5.1.0 - 2026-09-12 - changelog: Kandidaten-Eintrag nach Impact gruppiert, version regrade zur Nachkorrektur, version release verlangt eine Zusammenfassung
Author: Torben Nehmer
High impact
- changelog: Kandidaten-Eintrag nach Impact gruppiert, version regrade zur Nachkorrektur, version release verlangt eine Zusammenfassung
Seit
4.4.0sammelt ein laufender Kandidat alle Bumps in einem Eintrag; bei5.0.0wurde das
mit 20 Bumps und ~1440 Zeilen unlesbar, weil die Liste chronologisch und ungewichtet war und die
Release-Seite genau diesen Eintrag 1:1 uebernimmt (version notes,release.yml). Der Eintrag
ist jetzt geschichtet statt einer einzigen Wand Text:version bump --impact high|medium|low
(Defaultmedium) graduiert jeden Bump, die Liste rendert nach High/Medium/Low gruppiert - ausser
wenn allesmediumist, dann bleibt sie flach wie bisher, damit jeder alte Eintrag und jeder
einfache Patch unveraendert bleibt.version regradekorrigiert eine Note im Nachhinein, gegen
einen einzelnen Lesevorgang der ganzen Liste, bevor der Kandidat geschlossen wird. Direkt unter
der Liste steht jetzt eine kurze Zusammenfassung, darunter je Bump ein eigener
### <Bump-Titel>-Changeset-Absatz;version releaseverweigert das Schliessen eines Kandidaten
mit zwei oder mehr Bumps, solange diese Zusammenfassung fehlt (ein Kandidat mit genau einem Bump
ist ausgenommen - sein Changeset ist bereits die Zusammenfassung, wie hier). Geschlossene
Eintraege wie der zu5.0.0bleiben in der alten Form stehen: die Release-Seiten sind laut
eigenem Footer unveraenderliche Snapshots, undinstructions/dev/version-parts.mdsowie
docs/version-model.mdzitieren den2.0.0-Eintrag mit Abschnittsnamen.--breaking/**Migration:**sitzen jetzt oberhalb der Bump-Liste statt darunter, damit die fuer
einen Operator wichtigste Zeile nicht unter einer moeglicherweise langen Liste verschwindet.
This note is a snapshot of the
CHANGES.mdentry as it stood when the tag was cut, and
is never edited afterwards. The maintained version of this text - including any later
correction - is the entry for this version inCHANGES.mdin the repository.Downloads
-
v5.0.1 Stable
released this
2026-09-12 15:37:52 +00:00 | 134 commits to main since this release5.0.1 - 2026-09-12 - publish: ungeborene main ist kein detached HEAD, erster Push zu leerem Remote (schliesst #96, #97)
Author: Torben Nehmer
Zwei Defekte, die zusammen dazu führten, dass eine frisch aufgesetzte Instanz
sich über keinen dokumentierten Weg initial veröffentlichen ließ. Beide sitzen
inpublishund wurden erst beim Einrichten einer 5.0.0-Instanz aus dem
Release-Tarball sichtbar - der Pfad, deninstructions/setup-instance.md
Schritt 14 als den ersten schreibenden Aufruf einer neuen Instanz nennt.Ein ungeborener Branch ist kein detached HEAD.
current_branch()fragte
git rev-parse --abbrev-ref HEAD. Nachgit init -b main, vor dem ersten
Commit, zeigtHEADauf einen Ref, der sich nicht auflöst:rev-parseendet
mit Exit 128 und war damit von einem echten detached HEAD nicht zu
unterscheiden. Der erstepublisheiner neuen Instanz brach deshalb mit
"Refusing to pushmainfrom a detached HEAD" ab, und Invariante 5 schneidet
den naheliegenden Ausweg (git commitvon Hand) ab. Die Funktion liest jetzt
git symbolic-ref --short -q HEAD- wasHEADbenennt statt worauf es
zeigt. Damit beantwortet die Branch-Prüfung den ungeborenen Fall korrekt,
statt für ihn ausgesetzt werden zu müssen: sie vergleichtmainmitmain
und lässt durch. Ein echter detached HEAD wird unverändert abgelehnt, und ein
--branch, das nicht dem ausgecheckten entspricht, ebenfalls.Ein nie gepushter Branch ist nicht "nicht ahead".
_local_ahead_of_remote()
entscheidet, ob ein sauberer Working-Tree trotzdem etwas zu pushen hat, und
gabFalsezurück, sobald kein Tracking-Ref existierte. Genau das ist der Fall
bei einem frisch angelegten, leeren Remote-Repository: der lokale Commit stand,
publishmeldete "Nothing to commit" und pushte nie - beliebig oft
wiederholbar. Unterschieden wird jetzt übergit ls-remote --exit-code, dessen
Exit-Code die drei Lagen ohne Textvergleich trennt (0 = Ref vorhanden,
2 = Remote erreichbar und ohne diesen Ref, 128 = unerreichbar oder gar nicht
konfiguriert); auf die Meldung zu matchen schiede aus, weil git sie übersetzt.
Nur der mittlere Fall gilt als "ahead", und auch dort nur, wenn lokal
überhaupt ein Commit existiert. Ein unerreichbares Remote behält bewusst das
bisherige Verhalten, damit Offline- und Nur-lokal-Instanzen keine
Verhaltensänderung sehen.remote_ref_exists()bleibt unangetastet - sein
zweiter Aufruferreconcile()meint damit weiterhin richtig "nichts zum
Abgleichen da".tools/CONTRACT.mdzieht beides nach: diepublish-Zeile beschrieb den
Strandungsfall bisher als gelöst, was für einen nie gepushten Branch nicht
stimmte, und der Fehlerkontrakt benennt die Branch-Prüfung jetzt als
eigenständigen Exit-1-Grund.instructions/setup-instance.mdundINSTALL.md
blieben inhaltlich richtig - sie hatten den Umweg nie beschrieben, sondern den
Weg, der jetzt tatsächlich funktioniert.
This note is a snapshot of the
CHANGES.mdentry as it stood when the tag was cut, and
is never edited afterwards. The maintained version of this text - including any later
correction - is the entry for this version inCHANGES.mdin the repository.Downloads
-
v5.0.0 Stable
released this
2026-09-11 17:25:49 +00:00 | 136 commits to main since this release5.0.0 - 2026-09-11 - TOC-Pflicht in docs verify, Konfidenz-Mechanismus ersatzlos entfernt
Author: Torben Nehmer
- status/incoming: menschliche Stubs werden ausgearbeitet, nie so umgesetzt
- page move: eine kb-Seite folgt ihrem Subtype ins Verzeichnis, das ihr Type-Spec berechnet
- kb/CONTRACT.md: Tiefe 1 als Grenze - Katalog liest nur eine Area-Ebene
- raw accept: incoming/ als abgeleiteter Rohablage-Eingang (schliesst #58)
- raw accept: Stem-Eindeutigkeit im Typverzeichnis erzwingen, --replaces als einziger Weg daran vorbei (schliesst #64)
- update entity naming conventions to use singular form for consistency
- kb/concepts/ bekommt Areas: layout: fuer concept, Area-Titel aus jedem Type-Spec, Schwellen-Empfehlung im lint (schliesst #59)
- source_type: Default streichen, unclassified als sichtbares Fach, layout: fuer source (schliesst #66)
- raw accept: Datums-Shard statt Typverzeichnis, fidelity/authority am Drop-Punkt (schliesst #67)
- source_type ist Instanzsache: Profilkatalog, Setup-Frage, evolve-subtypes-Instruction (#68)
- instructions/CONTRACT.md: Skill-H1, Referenztiefe und Begruendungsprosa praezisiert (#71, #72, #79)
- SKILL.md-Sanierung: Checklisten, Kommandolisten, wiki-status-Hard-Rule, wiki-query-Filingpruefung (#70, #74, #75, #78)
- Ausgelieferte Doku zitiert keine Issue-Nummern mehr, docs verify prueft es (schliesst #77)
- TOC-Pflicht fuer Referenzdateien ueber 100 Zeilen; session-setup.md/gates.md nennen die tatsaechliche Budget-Ausnahmeliste (schliesst #73, #76)
- tools/CONTRACT.md: docs toc im Fehlerkontrakt, docs-verify-Zeile nennt die TOC-Pruefung; tools/README.md korrigiert das --major-Kriterium
- dist export erzeugt die TOC-Region nach dem Marker-Strip neu (CI-Fund im Export-Replay)
- Konfidenz-Mechanismus ersatzlos entfernt
- Konfidenz-Mechanismus ersatzlos entfernt
- version-parts.md dokumentiert den --migration-required-Ruecknahmepfad
- wiki-status verweist auf session-setup.md (schliesst #84)
- CLAUDE.md-Importkette entdrifted, Modellwahl nach docs/ verschoben (schliesst #81)
- Telemetrie-Default nach Installationsform, Byte-Deckel und Session-Retention
- tools/CONTRACT.md: raw accept Doku auf Datums-Shard und Capture-Felder nachgezogen (schliesst #89)
- MCP submit-Tool: Quarantäne-Schreibpfad mit Upload Review Gate (schliesst #32)
- AGENTS.md-Changelog-Absatz korrigiert: Contract-Prosa ist Sitzungsarbeit, doc-pull-through-Instruction ergaenzt
- docs verify prueft die Kommando- und Fehlerkontrakttabelle in tools/CONTRACT.md getrennt, 10 fehlende Fehlerkontrakt-Zeilen nachgetragen (schliesst #91)
- tools/CONTRACT.md als Nachschlage-Dokument strukturiert: ###-Gruppen in beiden Tabellen, spiegelnde Reihenfolge, Lead-in-Regel
- incoming/.gitkeep als Datei- statt Verzeichnismuster trackbar (schliesst #88)
- dist export-Doku: Typverzeichnis-Behauptung nach #67 korrigiert (schliesst #93)
- raw/*/.gitkeep-Glob in dist-upgrade-Doku auf den flachen raw/.gitkeep-Anker korrigiert
- Breiten-Auslöser für Ingests: eine einzelne, thematisch breite Quelle bekommt einen Extract-Pass statt einer Seite pro Namen
- Breiten-Auslöser für Ingests: Extract-Pass statt einer Seite pro Namen, types/source.md nachgezogen
- stack-close Schritt 3: ein Doku-Nachzug in einen versionierten Pfad braucht seinen eigenen Bump
Breaking Change: docs verify verlangt eine aktuelle Inhaltsverzeichnis-Region () auf AGENTS.md, jedem Stage-/Collection-Contract und jeder flachen instructions/**.md-Datei ueber 100 Zeilen - eine bestehende Instanz mit einer eigenen instructions/*.md-Datei ueber 100 Zeilen ohne TOC sieht docs verify nach dem Tool-Update neu fehlschlagen, bis einmalig 'wikitool docs toc --apply' laeuft und der Diff committet wird. Ausserdem verschwinden wikitool confidence decay und confidence init-base ersatzlos, touch --confidence-base ebenso, und die Schemas fuer entity/concept verlieren confidence/confidence_base vollstaendig (additionalProperties: false) - jede bestehende Instanz muss den Korpus migrieren, sonst werden alle Entity-/Concept-Seiten beim Schema-Update sofort schemainvalide. Ablauf: instructions/migrations/5.0.0-confidence-removal.md
Das Label
status/incominggibt es seit heute in Gitea: der Mensch legt einen
Stub an — zwei Sätze, ein Verdacht, ein „wäre interessant" — und der Stack
komplettiert ihn.instructions/dev/issue-tracking.mdbeschrieb es nicht, und
das ist die gefährlichere Hälfte: ein Stub sieht aus wie ein Body, und der
Body ist genau das, was eine Sitzung nach Schritt 2 als Spec glaubt. Zwei
solche Issues lagen bereits offen auf dem Board (#60, #61).Neu in der Instruction ist deshalb ein eigener Abschnitt „Incoming stubs" mit
dem Verbot als erstem Satz — einstatus/incoming-Issue wird nie so umgesetzt,
wie es dasteht — und der Ausarbeitung als sechsschrittigem Ablauf: den Wortlaut
als Absichtserklärung lesen, gegen den Baum prüfen, den Originaltext wörtlich in
den Kommentar retten, bevor der Rewrite ihn überschreibt, offene Fragen benennen
statt beantworten (kind/decision), erst dann die vier Pflichtlabel, dann das
Flag entfernen. Zwei Ausgänge wie beistatus/unconfirmed: ausgearbeitet oder
mit Begründung geschlossen.Der interessante Punkt ist Schritt 4:
status/incomingist das einzige Flag,
das Schritt 4 nicht qualifiziert, sondern aussetzt. Die vier Pflichtachsen
fehlen einem Stub nicht, sie sind noch nicht fällig —kind/,prio/und
size/sind Antworten auf Fragen, die niemand gegen den Baum geprüft hat. Ein
Stub auf Sicht durchzulabeln ist der Fehler, nicht das Weglassen: es lässt
Ungeprüftes triagiert aussehen.Der Schaden, den das verhindert, ist derselbe wie bei #30, nur eine Stufe
früher: dort schrieb ein Body einen Mechanismus vor und bekam dessen Bugs
gebaut, hier schreibt ein Body gar nichts vor und bekommt die Lücke von
demjenigen gefüllt, der ihn am schnellsten gelesen hat — inklusive Close, womit
die Frage, für die der Stub stand, nie wieder gestellt wird.Keine neue Schrittnummer, bewusst:
stack-close/SKILL.mdund ältere
CHANGES.md-Einträge verweisen namentlich auf „Schritte 2-3 und 7". Eine
Umnummerierung hätte diese Verweise still falsch gemacht — genau der Zerfall,
den dieselbe Datei in § Renames beschreibt.Geändert: instructions/dev/issue-tracking.md
(Frontmatter, § When to run, Schritt 5, neuer § Incoming stubs, § What no tool
checks, § Decision points) und die Routing-Zeile in
instructions/dev/stack-dev/SKILL.md. Dev-only —dist exportschließt
instructions/dev/aus, eine ausgelieferte Instanz sieht davon nichts, deshalb
PATCH.Nachgezogen in derselben Sitzung, aber als eigenes Paket (#63, Commit
a0aecfc):kb/concepts/Issue Label Scheme.mdbeschrieb weiter nur die beiden
altenstatus/-Flags und zählte sechzehn statt siebzehn Labels. Das ist
kb/-Inhalt und brauchte nach Invariante 3 erst eine Quelle — die Threadkopie
von #62/#63 inraw/notes/— also einewiki-manage-Sitzung statt dieser
hier. Die Seite trägt jetzt die drittestatus/-Zeile samt Verbot und einen
Kernpunkt dazu, dass dieses Flag die Vier-Achsen-Pflicht aussetzt.Offen bleibt die erste tatsächliche Anwendung der Regel: #60 und #61 sind
weiterhin unausgearbeitete Stubs.wikitool move(#56): Nichts im Stack bewegte bisher eine Seite über eine
Verzeichnisgrenze —renameschreibt laut eigenem Docstring nie über
target.path.parenthinaus, undnew_page._target_dirrechnete die
Platzierung nur beim Anlegen. Ändert sichentity_typespäter, blieb die
Datei still am alten Ort liegen, und nichts prüfte das nach: weder
lint_core.pynochdoctor.pyverglichen den Ist-Ort einer Seite mit dem,
was ihr Type-Spec berechnen würde.Die Platzierungslogik selbst gibt es jetzt genau einmal:
TypeResolver.compute_target_dir(plusTypeResolver.subtype_dirfür den
layout:-Teil),new_page._target_dirdelegiert nur noch dorthin. Darauf
aufbauend zwei neue Stücke:wikitool move --page "<Titel>"bewegt eine Seite an den berechneten Ort;
--reconcilewendet dieselbe Regel auf den ganzen Bestand an und ist
idempotent (ein zweiter Lauf meldet nichts mehr zu tun). Beide Modi fassen
weder Body noch Frontmatter an, und der Titel — die einzige Identität einer
Seite — ändert sich nie, also folgt kein Referenz-Update. Ein bereits
belegtes Ziel (ein alter Stem-Kollisionsrest) wird verweigert statt still
überschrieben. Top-level registriert, wierename/rm, nicht unter einem
page-Unterbefehl.lintbekommt einen neuen Befund, Misplaced Pages, mit Ist- und
Soll-Pfad. Bewusst nicht inHARD_ERROR_KEYS: ein von Hand platzierter
Bestand ist keine kaputte Seite, nur eine, diemoveaufräumen könnte — auf
dieser Instanz sind das aktuell die dreikb/entities/projects/*/-Seiten,
die #57 separat behandelt.
Ein Fund unterwegs, der ohne #56 unsichtbar geblieben wäre:
migrate verify
schlüsselte Seiten über den repo-relativen Pfad. Ein reiner Move ergab
„N removed, N added, 0 compared" und lief grün durch — der eine mechanische
Check, für deninstructions/migrate-corpus.mdexistiert, hätte bei genau der
Operation nichts geprüft, die dieses Issue einführt. Behoben:PageShape
trägt jetzt zusätzlich den Pfad,_shapes_at_revision/_shapes_now
schlüsseln über den Titel (die einzige Identität einer Seite), und
CorpusDiff.movedmeldet einen reinen Ortswechsel separat — informativ,
niemals als Finding. Regressionstest deckt drei verschobene Seiten mit
compared == 3, added == 0, removed == 0ab.Bewusst nicht Teil dieses Pakets: die drei realen Seiten aus #57 bleiben
liegen (kein Korpus-Publish hier, nur Stack), undraw rename(#16) — das
git mv-mit-mv-Fallback aus #56s Entwurf war für Rohdateien gedacht;
rename/rm/movebewegen kb-Seiten über ein einfachesPath.rename, weil
publishohnehin übergit add -Astaged.Geändert:
tools/chemenu/type_resolver.py(compute_target_dir,
subtype_dir),tools/chemenu/commands/new_page.py(delegiert),
tools/chemenu/commands/page_ops.py(move_command),
tools/chemenu/lint_core.py(find_misplaced,misplaced_pages),
tools/chemenu/corpus_diff.pyundtools/chemenu/commands/migrate_cmd.py
(Titel-Schlüsselung,moved),tools/chemenu/commands/log_append.py(--op move),tools/CONTRACT.md,instructions/page-lifecycle.md,
instructions/publish-cycle.md. MINOR: rückwärts liest ein älterer Stack eine
verschobene Seite unverändert (Identität ist der Titel, nicht der Ort),
vorwärts reines Überkopieren.Katalogtiefe (#57):
index_build.group_pageslas bislang genau zwei
Pfadsegmente unterkb/(parts[0]als Collection,parts[1]als Area) und
faltete alles darunter still in die Level-1-Area. Real betroffen waren die
drei Seiten aus #56s Befund,kb/entities/projects/{kfchou,vanillaflava, yugasun}/*.md— im generierten Katalog nicht als eigener Ort sichtbar,
sondern als läge jede direkt inentities/projects/.kb/CONTRACT.md§
Collections beschrieb bis heute nur eine Ebene, ohne eine zweite
auszuschließen; der Baum hatte trotzdem eine, handplatziert, ohne
unterstützten Weg dorthin.Entscheidung war (b) aus dem Issue: die drei Verzeichnisse auflösen statt den
Katalog rekursiv zu machen. Die Gruppierungsachse dahinter — Owner
(kfchou/vanillaflava/yugasun) — kommt aus keinem Frontmatter-Feld und
aus keinem Type-Spec, sondern aus einer Ad-hoc-Entscheidung beim Anlegen; sie
verdient keine zweite Verzeichnisebene. Tiefe 1 ist jetzt geschriebene Regel
inkb/CONTRACT.md§ Collections, mit dieser Begründung.Vier Stücke setzen das um:
kb_scan.find_nested_pagesliefert(title, page, depth)für jede
Seite mehr als ein Verzeichnis unterhalb ihrer Collection — reine
Pfadtiefe, unabhängig davon, ob der Typ auflöst, damit auch eine Seite mit
kaputtemtype:nicht durchrutscht.lintbekommt den Befund Nested Pages, und anders als
misplaced_pageshart: eine fehlplatzierte Seite katalogisiert noch
korrekt von der falschen Stelle aus, eine verschachtelte macht den
generierten Katalog selbst falsch, und es gibt keine Version, ab der das
toleriert würde.index rebuildlehnt eine verschachtelte Seite nicht ab, sondern warnt
(Entscheidung aus der Session: melden statt verweigern, damit ein
Fremdinstanz-Upgrade mit handverschachtelten Seiten nicht hart bricht) —
group_pagesfaltet weiterhin wie zuvor, die Warnung ist die neue
Sichtbarkeit, nicht eine Verhaltensänderung der Faltung selbst.TypeResolver.get_layoutvalidiertlayout: {dir: ...}jetzt auf
einen einzelnen Pfadabschnitt (kein/, kein\, kein./.., nicht
leer) und schlägt fehl statt eine zweite Ebene über den einzigen
unterstützten Weg — ein Type-Spec — entstehen zu lassen.
Ein fünftes Stück, das das Issue selbst nicht explizit forderte, aber die
move-Mechanik aus #56 sonst mit toten Verzeichnissen zurückgelassen hätte:
move(--pagewie--reconcile) entfernt jetzt ein Verzeichnis, das es
durch den Wegzug seiner letzten Seite geleert hat — symmetrisch zum
mkdir(parents=True)auf der Zielseite. Ohne das hättenkfchou/,
vanillaflava/,yugasun/den eigenen Fix überlebt, leer und für git
unsichtbar, aber für einen verzeichnisbasierten Test sichtbar.Auf dieser Instanz angewendet:
wikitool move --reconcilehat die drei
Seiten nachkb/entities/projects/gezogen und die drei leeren
Owner-Verzeichnisse mitentfernt.migrate verify --from HEADbestätigt
compared == 182, added == 0, removed == 0, alle drei alsmovedmarkiert.
Titelkollision trat wie im Issue erwartet keine auf.Geändert:
tools/chemenu/kb_scan.py(find_nested_pages),
tools/chemenu/lint_core.py(nested_pages,HARD_ERROR_KEYS),
tools/chemenu/commands/index_build.py(Rebuild-Warnung),
tools/chemenu/type_resolver.py(get_layout-Validierung),
tools/chemenu/commands/page_ops.py(_rmdir_if_emptied),tools/CONTRACT.md,
kb/CONTRACT.md§ Collections, plus die drei realen Seiten unter
kb/entities/projects/. PATCH: reine Codeänderung ohne Schnittstellenwechsel,
gefaltet in den offenen4.8.0-Kandidaten (max-wins gegen die MINOR-Bewegung
aus #56); die drei bewegten Seiten sind Korpus dieser Instanz, kein
ausgelieferter Inhalt.Schließt #57.
raw accept(#58):raw/CONTRACT.mds Routing-Tabelle war bislang eine Regel für Menschen —
wer eine Datei ablegt, wähltarticles//documents//notes//assets/selbst, und mehrere
Dateien einer logischen Quelle waren im Dateisystem nicht als zusammengehörig erkennbar. Neu ist
ein gitignorierter Eingangincoming/, der dieselben vier Typverzeichnisse spiegelt: der Mensch
klassifiziert nur, indem er dort ablegt,tools/wikitool raw accept <datei> [<datei> ...] [--page "<Titel>"]berechnet die Beförderung nachraw/.Zwei Entscheidungen, gegen die ursprüngliche Skizze im Issue: ein Bundle-Verzeichnis
(raw/<typ>/<stamm>/, benannt nach der ersten Datei) entsteht erst ab der zweiten Datei, nie
einheitlich — damit sind die 29 heute flach liegenden Bestandsdateien keine Ausnahme, sondern
bereits die Regelform, und die Frage „was passiert mit dem Bestand" beantwortet sich von selbst.
Und der Typ wird über das Eingangs-Unterverzeichnis deklariert, nicht über ein--type-Flag: die
Erklärung wird abgegeben, wenn der Mensch die Datei in der Hand hat, statt im Moment des
accept-Aufrufs neu geraten werden zu müssen.--pagedeckt den Wachstumsfall ab: erweitertraw_files:einer bestehenden Source-Seite und
faltet deren schon abgelegte Einzeldatei ins neue Bundle, sobald das die Seite über eine Datei
hinaus wachsen lässt — ohne ein Fenster, in demraw_files:ins Leere zeigt. Die dafür nötige
Rückwärtssuche und der Mehrfach-Owner-Schutz sind keine neue Mechanik, sondern
provenance.source_pages_by_raw_file, daslintschon fürduplicate_raw_file_ownersbenutzt —
ein Owner-Konflikt lehnt die Beförderung ab, statt eine andere Seite unbemerkt zu brechen.incoming/ist fürsources coverageundlintunsichtbar (beide laufen ausschließlich über
config.iter_raw_files(config.RAW_DIR)), und dass keine Datei dort je committet werden kann, ist
überdocs_verify.REQUIRED_IGNORE_CANARIESbewiesen, nicht nur zugesichert.RAW_SUBDIRS
(dist_cmd.py) bleibt die einzige Quelle der Vier-Verzeichnis-Liste:docs verify
(check_raw_subdirs) hältraw/CONTRACT.mds Tabelle jetzt in beiden Richtungen dagegen, und
dist exportsätincoming/<typ>/.gitkeepnebenraw/<typ>/.gitkeep;instructions/bootstrap.md
legt den Eingang für einen bestehenden Klon nach, da er dort nie aus git kommt.Geändert:
tools/chemenu/commands/raw_cmd.py(neu,raw accept),tools/chemenu/cli.py,
tools/chemenu/commands/dist_cmd.py(RAW_SUBDIRS-Kommentar,incoming/*/.gitkeep),
tools/chemenu/commands/docs_verify.py(check_raw_subdirs,incoming/-Ignore-Kanarie),
.gitignore,raw/CONTRACT.md,tools/CONTRACT.md,instructions/bootstrap.md,
instructions/wiki-ingest/SKILL.md. MINOR: eine Umsortierung des Bestands wäre die Grenze
gewesen, findet aber unter der Bundle-erst-ab-zwei-Regel nicht statt — der Bestand bleibt
unangetastet, keine fremde Instanz muss migrieren, vorwärts wie rückwärts reines Überkopieren.Schließt #58.
raw acceptprüfte Kollisionen bisher nur auf einzelnen Dateipfaden
(dst.exists()), nie auf dem Bundle-Verzeichnis selbst. Weil der Bundle-Name
aus dem Stem der Primärdatei entsteht, konnte eine zweite, unabhängige Quelle
wortlos in das Bundle einer ersten wandern, sobald die Dateinamen zufällig
nicht kollidierten — verifiziert mit einem Wegwerf-Test:handbuch.txt+
anhang.mdohne--pagelandeten unbemerkt in einem bestehenden
raw/documents/handbuch/.lintmeldete nichts, weil beide Quellen ihre
Dateien korrekt abdeckten.Die Menge der Namen auf
raw/<typ>/-Ebene — Dateistämme plus
Bundle-Verzeichnisnamen — ist jetzt eindeutig erzwungen (_occupied_stemsin
raw_cmd.py), unter Ausnahme dessen, was der Aufruf selbst schon besitzt: ein
Bundle, das über--pagewächst, oder ein bereits registriertes, sich
fortsetzendes Bundle. Ein belegter Stem wird mit Exit 1 abgelehnt und nennt
beide Auswege, ohne einen zu empfehlen —--replacesoder Umbenennen in
incoming/.--replaces <raw-pfad>ist der einzige sanktionierte Weg, eine Rohdatei
wortwörtlich zu ersetzen: genau eine eingehende Datei, identischer Dateiname,
gleiches Typverzeichnis, Ablehnung bei mehr als einem Owner.raw_files:
bleibt unverändert, es wird keinekb/-Seite geschrieben, und die Altfassung
lebt ausschließlich ingit log --followweiter — kein Archivverzeichnis,
kein Hash im Dateinamen, kein neues Frontmatter-Feld. Nach einem Ersatz nennt
das Kommando die Source-Seite und ihre zitierenden Seiten, damit deren
Nachzug im selben Commit passiert wie die Ersetzung.raw/CONTRACT.md§ Rules trägt beide Regeln aus dieser Entscheidung
(unveränderlich, aber ersetzbar als Ganzes);instructions/wiki-ingest/SKILL.md
benennt den Kollisionsfall als Haltepunkt, an dem eine Sitzung die Meldung dem
Menschen vorlegt statt selbst zu entscheiden — dieselbe Klasse wie AGENTS.md
Invariante 6, auch ohne dass hier ein Exit-42-Gate greift.Geändert:
tools/chemenu/commands/raw_cmd.py(_occupied_stems,
_stem_collision_message,--replaces/_replace),
tools/chemenu/tests/test_raw_cmd.py(16 neue Tests),raw/CONTRACT.md,
tools/CONTRACT.md,instructions/wiki-ingest/SKILL.md. MINOR:raw accept
wurde nie released (letztes Releasev4.7.4), die Verschärfung kostet also
keine Kompatibilitätsfrage, solange sie vor4.8.0landet.Schließt #64.
kb/concepts/bekommt Areas (#59): Sharden ist längst automatisch —
index_build.SHARD_THRESHOLD = 50, hergeleitet aus der wikieigenen Seite
Index Scaling— aber es passiert pro Area, und eine Area legt niemand an.
kb/concepts/hatte keine, also war die Schwelle dort ein toter Wert: 80 Seiten
in einer einzigen Tabelle, weit über der eigenen Grenze, ohne dass je etwas
gefeuert hätte. Die Ursache war eine Asymmetrie in den Type-Specs —entity
deklarierte einlayout:,conceptnicht, obwohl das Subtype-Feld fertig dalag.types/concept.mddeklariert es jetzt für alle sechsconcept_type-Werte
(architectures/,patterns/,protocols/,workflows/,decisions/,
problems/). Fürsourcebewusst nicht: 25 von 29 Seiten sindnotes, die
Aufteilung ergäbe eine Area und vier Splitter, undkb/sources/liegt mit 29
Seiten ohnehin unter der Schwelle. Ein Subtype-Feld zu haben ist kein Grund, es
als Achse zu benutzen.Zwei Dinge im Code, beide Folgen desselben Befunds.
_area_titles()in
index_build.pylösteentityfest überfind_type_by_name("entity")auf und
las nur dessenlayout:— jeder zweite Typ mit einemlayout:hätte
.title()-Namen auf dem Verzeichnisnamen bekommen statt der deklarierten Titel.
Es liest jetzt jedes Type-Spec, und zwar pro Collection geschlüsselt, damit
zwei Typen denselben Area-Namen für Verschiedenes benutzen dürfen. Und der neue
lint-Befund meldet eine Collection über der Schwelle ohne Areas, mit der
Verteilung ihres Subtype-Felds — als Empfehlung, nicht als Failure, und nur
dann, wenn die Aufteilung jede entstehende Area unter die Schwelle drückt. Das
begrenzt sich selbst in beide Richtungen:kb/comparisons/mit einer Seite
feuert nie, und die schlechte Aufteilung nachsource_typeunterbleibt von
allein, ohne dass der Check etwas über Sources wüsste.Zwei Dinge fielen unterwegs an, die das Issue nicht vorhergesehen hatte.
lint_core.pydurfteSHARD_THRESHOLD/group_pagesnicht aus
commands/index_build.pyimportieren —test_api.pyprüft strukturell, dass
chemenu.apikein Modul unterchemenu.commandslädt, und der Import hätte den
ganzen CLI-Kopf mitgezogen. Die Gruppierung liegt deshalb neu in
tools/chemenu/catalog.py, entlang derselben Linie wielint_core.py:
Korpusform hier, Darstellung dort. Und_anchor()strich mit[^a-z0-9\s-]
jeden Nicht-ASCII-Buchstaben ersatzlos — die Karte verlinkte auf#ablufe,
während die Überschrift im Shard#abläufeheißt. Vorher fiel das keinem auf,
weil alle Entity-Area-Titel zufällig ASCII sind;Abläufeist der erste, der es
nicht ist.Auf dieser Instanz angewendet:
wikitool move --reconcilehat alle 80
Concept-Seiten in ihre Area gezogen,migrate verify --from HEADbestätigt
182 compared, 0 added, 0 removed, 80 moved, 0 findings— kein Titel, kein
Body, kein Frontmatter-Feld angefasst.index rebuilderzeugt sechs Areas
(Abläufe 28, Architekturen 20, Muster 17, Entscheidungen 7, Problemstellungen 5,
Protokolle 3); keine über der Schwelle, also kein eigener Shard, und die
Schwelle wirkt wieder als Schwelle.Geändert:
types/concept.md(layout:),types/type-spec.md(wann ein
layout:sich lohnt),tools/chemenu/catalog.py(neu),
tools/chemenu/commands/index_build.py(area_titles,_anchor),
tools/chemenu/lint_core.py(unsharded_collections),
tools/chemenu/tests/(Fixture-Concept liegt jetzt in seiner Area, plus neun
neue Tests),tools/CONTRACT.md,tools/README.md,README.md,
kb/concepts/COLLECTION.md, sowie die 80 bewegten Seiten unterkb/concepts/.MINOR, nicht MAJOR: der Umzug ist ein Angebot, kein Zwang. Eine
bestehende Instanz, diemove --reconcilenicht laufen lässt, bleibt
funktionsfähig —group_pagesliest das Dateisystem, nicht daslayout:, also
landen flache Bestandsseiten in der Area „All" und neu angelegte in ihrer
eigenen; beides rendert. Der gemischte Zustand meldet sich alslint-Befund
Misplaced Pages, der seit jeher advisory ist. Und ein Downgrade auf einen
Stack ohne dieseslayout:funktioniert weiter: die Verzeichnisse bleiben
Verzeichnisse, nur die Anzeigetitel fallen auf.title()zurück. Kosmetik, kein
Bruch der Austauschbarkeit in beiden Richtungen.Schließt #59.
Nachzug an
63b4bb8: die Umstellung der Namenskonvention aufHA Integration
hatte inREADME.mddas Gegenbeispiel verloren — die Zeile las
Use singular for entities: `HA Integration.md` (not `HA Integration.md`), beide
Seiten des „not" identisch, also eine Regel ohne Fall, an dem sie greift.
kb/CONVENTIONS.mdundkb/entities/COLLECTION.mdhatten im selben Commit das
korrekte Paar bekommen;README.mdzieht jetzt mitHA Integrations.mdnach.source_typehatte intypes/source.schema.yamleindefault: notes— der Compiler wählte
das Sammelbecken, sobald niemand widersprach, nicht ein Mensch. #59 hatte den Bestand deshalb
für lopsided gehalten (25 von 29 Seitennotes) undsourcebewusst flach gelassen; nachgezählt
nach dem, was die Seiten tatsächlich sind (Dateiname,author:, Rohdatei), waren es 16
Session-Transkripte, 4 LLM-Analysen, 2 Tracker-Exporte und nur 3 echte Notizen. Der Default war
der Fehler, nicht das Enum.Umgesetzt:
default:gestrichen,wikitool new sourceverweigert jetzt ohne expliziten Wert.
Enum neu:transcript,analysis,article,document,notes,tracker,unclassified—
specundimageentfallen (null Seiten, nie am echten Material bewährt).unclassifiedist
das neue, sichtbare Fach für eine Quelle, deren Kategorie noch nicht feststeht — eigene Area,
beratenderlint-Befund (unclassified_source_pages), keine harte Fehlerklasse.types/source.md
deklariert jetzt einlayout:für alle sieben Werte.Auf dieser Instanz angewendet, in einem eigenen
work/reclassify-source-types/-Lauf: 22 der 29
Source-Seiten perwikitool touch --set source_type=<wert>auf ihren tatsächlichen Wert
korrigiert (16 transcript, 4 analysis, 2 tracker), 7 unverändert.wikitool move --reconcilehat
alle 29 danach in ihre Area gezogen (transcripts 16, analyses 4, articles 3, notes 3, trackers 2,
documents 1, unclassified 0).migrate verify --from HEADbestätigt182 compared, 0 added, 0 removed, 29 moved, 22 findings— die 22 sind exakt die beabsichtigtensource_type-Änderungen,
kein Titel, kein Body, keine Wikilink- oder Zitatzahl angefasst.lint --fail-on-errorgrün,
insbesondere ohne Misplaced Pages, Nested Pages oder den neuen Unclassified Source Pages.Geändert:
types/source.schema.yaml(Enum, kein Default),types/source.md(layout:),
types/type-spec.md(sourceals Beispiel für ein bewusst fehlendeslayout:ersetzt —
ein lopsided Feld wird repariert, nicht dauerhaft flach gelassen),tools/chemenu/lint_core.py
(unclassified_source_pages, neu),tools/CONTRACT.md,instructions/wiki-ingest/SKILL.md
(--set source_type=,unclassifiedals Ausweg),instructions/dev/corpus-policy.md
(Floor-Ausnahme fürunclassified),kb/sources/COLLECTION.md(Areas, Autorschaft trennt
analysisvondocument), fünf Tests umgehängt (davon einer auf einen neuen
Fixture-Type-Spec, weilsourceals „hat Subtype-Feld, keinlayout:"-Beispiel wegfällt),
sowie die 29 bewegten und 22 reklassifizierten Seiten unterkb/sources/.MINOR, geprüft am Drop-in-Test: eine bestehende Instanz besitzt ihr eigenes
types/source.md(Auslieferung nur als.template), kopierttools//types//instructions/
über sich und bleibt unverändert funktionsfähig — kein Downgrade-Bruch, kein umgeschriebenes
maschinengelesenes Format. Kein--breaking, kein Migrationsdokument.Schließt #66.
raw accept: Datums-Shard statt Typverzeichnis,fidelity/authorityam Drop-Punkt (#67,
Paket B von vier — A ist #66 oben, C ist #68, D ist #69): zwei unabhängige Befunde, ein
Codepfad.Befund 1:
raw/CONTRACT.mds vier Typverzeichnisse (articles/,documents/,notes/,
assets/) lösten keinen der drei Gründe ein, die einen Verzeichnis-Split rechtfertigen —
raw/wird nie durchgeblättert, keine Klausel dieser Datei galt je pro Verzeichnis, alle vier
verrotten gleich (unveränderlich, nie gelöscht). Der Split kostete real: der Mensch trifft beim
Ablegen inincoming/<typ>/eine Routing-Entscheidung, die später blind nachsource_type:
abgeschrieben wird — genau darüber entstand der in #66 korrigierte Bias (raw/notes/hielt laut
altem Contract-Text „Gesprächsprotokolle", 16 der 25 Dateien dort waren tatsächlich Transkripte).Befund 2: was am Drop-Punkt bekannt ist und danach nirgends mehr — wie treu eine Erfassung ist
und was das Material über seinen Gegenstand behaupten darf. Zwei neue, unabhängige Achsen auf
types/source.md:fidelity(verbatim/published/secondhand/nontextual) undauthority
(normative/reporting/opinion), beide mitunknownals backfill-only-Wert.Umgesetzt:
raw acceptadressiert eine Datei jetzt überraw/<YYYY>/<MM>/, berechnet aus dem
Annahmedatum — eine reine Funktion von etwas Unveränderlichem, kann also nie rebalancieren und
keinen[^cite-id]-Anker brechen.incoming/wird flach; ein Unterverzeichnis wird toleriert
und ignoriert statt inspiziert (alteincoming/<typ>/-Skripte laufen unverändert weiter).
Bestandsdateien inraw/articles|documents|notes|assets/bleiben unbewegt und weiter gültige
--replaces-Ziele — das Layout war nirgends versioniert, es gibt also keine „zwei Korpusformen".
Wächst eine bereits promotete Einzeldatei zum Bündel, entsteht das Bündel an ihrem eigenen
Speicherort, nie im heutigen Shard — ein Bündel aus altem und neuem Datum hätte keine
eindeutig richtige Adresse.- Stem-Eindeutigkeit (#64) gilt jetzt global über
raw/, nicht mehr pro Typverzeichnis —
ohne Typverzeichnisse als Grenze wäre die Prüfung sonst wirkungslos gegen ein Bündel in einem
anderen Shard oder einem Alt-Verzeichnis. fidelity/authority: neu intypes/source.schema.yaml, ohnedefault:und bewusst
nicht inrequired:(sonst bricht jede bestehende Instanz an der Validierung — die
MINOR-Einstufung unten hängt daran). Erzwungen stattdessen im Werkzeug:raw acceptverlangt
beide Flags immer; trägt der Aufruf--page, schreibt es sie direkt auf die Zielseite, sonst
druckt es die fertigenew source --set fidelity=... --set authority=...-Folgezeile, und
new sourceverweigert seinerseits ohne beide Werte.unknownist backfill-only — weder
raw acceptnochnew sourcedürfen es schreiben.- Capture-Felder sind fill-once, nicht auf
touch.pysUNSETTABLE-Denylist: eine Denylist
hätte auch den ersten (Backfill-)Schreibzugriff verboten, den der Migrationslauf braucht.
touch --set <feld>=<wert>schreibt nur, solange das Feld fehlt, und verweist danach auf
raw accept --replacesals einzigen Korrekturweg — der einzige Aufruf, der einen bereits
gesetzten Capture-Wert überschreiben darf, weil eine korrigierte Erfassung eine neue Edition
der Quelle ist, keine Bearbeitung der Seite.types/source.mddeklariert die Feldliste selbst
(capture_fields:), gelesen überTypeResolver.get_capture_fieldsstatt an drei Stellen
hartkodiert. lintbekommt einen neuen beratenden Befund, Confidence Above Source Standing: die
Autoritätsbewertung, diekb/CONVENTIONS.mds Confidence-Rubrik seit je verlangt („+0.1 für
offizielle Doku"), aber nirgends festhielt. Eine stackseitige Obergrenzentabelle in
kb/CONTRACT.md(reporting0.8,opinion0.6,secondhand/nontextual0.7,normative/
verbatim/published/unknownohne Obergrenze) begrenztconfidence_base, ersetzt es aber
nicht — eine Formel hätte zwei widersprechende Ableitungen derselben Zahl, und Autorität ist
eine Obergrenze, kein Determinant. Nicht inHARD_ERROR_KEYS. Auf dieser Instanz meldet der
Befund aktuell nichts: kein Bestand trägt die neuen Felder, das ist erwartet, nicht geprüft.- Aufgeräumt:
dist_cmd.RAW_SUBDIRSund der darauf laufendedocs verify-Check
(check_raw_subdirs) entfallen ersatzlos,raw/CONTRACT.mds Routing-Tabelle beschreibt
stattdessen den Shard, die Ignore-Kanarie wandert vonincoming/documents/probe.pdfauf
incoming/probe.pdf.
MINOR,
4.8.0-beta.8desselben Kandidaten — drei geprüfte Bedingungen:raw acceptnimmt
weiterhin Dateien ausincoming/<irgendwas>/an, statt sie zu verweigern;fidelity/authority
stehen nicht inrequired:; die zwei neuen Pflichtflags anraw acceptsind eine
Verhaltensänderung, aber dieselbe Einstufung, die #66snew source-Verweigerung im selben
Kandidaten schon bekam. Kein--breaking, kein Migrationsdokument nötig — kein Bestand wird
durch diesen Bump ungültig.Geändert:
raw/CONTRACT.md,types/source.md,types/source.schema.yaml,
tools/chemenu/commands/raw_cmd.py(Neufassung),tools/chemenu/commands/new_page.py
(Capture-Feld-Pflicht),tools/chemenu/commands/touch.py(_capture_field_or_fail,
Fill-once),tools/chemenu/type_resolver.py(get_capture_fields),
tools/chemenu/commands/dist_cmd.py/docs_verify.py(Aufräumen),tools/chemenu/lint_core.py
(neuer Befund),kb/CONTRACT.md(Obergrenzentabelle),tools/CONTRACT.md,.gitignore,
instructions/bootstrap.md,instructions/wiki-ingest/SKILL.md(Schritt 1 und 6), zugehörige
Tests.Der Backfill über den Bestand lief als eigener
work/-Lauf (backfill-capture-fields,
Commit00220f8) hinterher, nachinstructions/migrate-corpus.mdund durch das
Mass-Update-Gate: 29 Source-Seiten, nicht 31 wie zwischenzeitlich im Issue notiert — die
höhere Zahl zählteINDEX.mdundCOLLECTION.mdmit.Die Regel dieses Laufs war enger als die des laufenden Betriebs, weil ein nachgetragener
Capture-Wert erschlossen ist und nicht erhoben: ein echter Wert nur dort, wo die Art des
Artefakts ihn aus dem Material selbst festlegt, sonstunknown. Ergebnis:verbatim+reporting
18 (16 Gesprächstranskripte, 2 Tracker-Exporte — beide wörtliche Mitschnitte, beide Protokoll
statt Festlegung),secondhand+opinion3 (LLM-Analysen),published+reporting2,
published+normative1 (Karpathys Idea-File, das definierende Dokument seines eigenen
Gegenstands),verbatim+normative1 (das qmd-README, dessen Rohdatei ihre Treue selbst
deklariert),unknown+normative1,unknown+reporting3.fidelity: unknownsteht auf 4 der 29 Seiten,authority: unknownauf keiner. Die
Asymmetrie ist der interessante Teil: wer für einen Gegenstand zuständig war, ließ sich überall
aus dem Material beantworten — wie treu ein selbstverfasstes Cheat Sheet oder ein Anweisungsdokument
„erfasst", nicht, weil der Enum für ein originär geschriebenes Artefakt keinen Wert hat. Das ist
kein Backfill-Fehler, sondern genau die Grenze, dieunknownmarkieren soll.Und der
lint-Befund hat einen Fall — 67 sogar: nach dem Backfill melden 67 von 152 Seiten
mitconfidence_basemehr Konfidenz, als die Quellenlage trägt (47 gegen die 0.8-Grenze für
reporting, 20 gegen die 0.6-Grenze füropinion). Das ist kein Fehlalarm und auch keine
Nacharbeit dieses Eintrags: der Korpus ist zu gut der Hälfte aus Gesprächstranskripten kompiliert,
und die Rubrik inkb/CONVENTIONS.mdlässt Quellenzahl und Aktualität allein bis 0.95 laufen,
während der Autoritätsterm der kleinste Summand ist. Ob daraus folgt, dass 67 Seiten überbewertet
sind oder dass die 0.8-Grenze für einen selbstdokumentierenden Korpus zu eng ist, ist eine
Entscheidung und keine Korrektur — sie hängt als Messung am Stub #60, der genau diesen Verdacht
ohne Zahlen aufgeschrieben hatte. Die Transkripte wurden ausdrücklich nicht aufnormative
hochgestuft, nur damit der Report leiser wird.Schließt #67.
source_typeist Instanzsache: Profilkatalog, Setup-Frage,evolve-subtypes-Instruction
(#68, Paket C von vier — A ist #66, B ist #67, D ist #69): reine Doku- und Instruction-Arbeit,
kein Korpus-Sweep.Befund:
source_types sieben Werte (transcript,analysis,article,document,notes,
tracker,unclassified) beschreiben diese Instanz, nicht den Stack — gegen drei
hypothetische Zielinstanzen (Handball-Verein, Produktentwicklung, Pen-&-Paper) hat die Liste
fast nichts gemeinsam, währendfidelity/authority(#67) in allen vieren dieselben Werte
bleiben. Architektonisch war das längst wahr (types/source.mdträgtroot: kb,dist export
liefert es nur als.template), nur stellte nichts die Frage:instructions/kb-profiles.md
riet imentities-Abschnitt „Adapt the area list first", sagte imsources-Abschnitt aber kein
Wort zusource_type. Zweiter Befund, aus #66 mitgenommen: dasunclassified-Fach bekam einen
beratendenlint-Befund, aber nie eine Prozedur, es wieder zu leeren.Umgesetzt:
kb-profiles.mdssources-Abschnitt behandeltsource_typejetzt wieentitiesseine Area-
Liste: als das, was zuerst anzupassen ist, mit zwei ausformulierten Domänenprofilen
(Handball-Verein, Pen-&-Paper) als Anschauung, und dem ausdrücklichen Gegenbeispiel
fidelity/authority— die sind Stack-Vokabular und stehen nicht zur Wahl.instructions/setup-instance.mdSchritt 5 bekommt einen neuen Unterschritt: nach dem
Anwendungsgebiet fragen,source_type-Vorschlag ableiten, Enum undlayout:in derselben
Bearbeitung setzen. Mit der Ansage, dass der Betreiber zum Setup-Zeitpunkt null Quellen hat und
seine Taxonomie vor jedem Material rät — das Ergebnis ist ein Startpunkt, keine Festlegung, und
unclassifiedbleibt in jedem Vorschlag erhalten.- Neue Instruction
instructions/evolve-subtypes.md,manual: true: benennt die
Weiterentwicklungsschleife, die werkzeugseitig schon vollständig existierte (Fach sehen →
Wert samtlayout:ergänzen →touch/move --reconcile→index rebuild/migrate verify),
über alle drei Subtype-Achsen (entity_type,concept_type,source_type— alle drei tragen
subtype_field:undlayout:;comparisonkeins von beidem). Zwei Regeln im Body: Wert
und Sweep sind untrennbar (ein deklarierter Wert ohne Seite lädt zum Raten ein — genau der
notes-Fall aus #66), und eine Aufnahmeschwelle von ≥3 Seiten, mitspec/imageaus #66 als
Gegenbeispiel und einer benannten-Ausnahme-Klausel für Fälle wietrackerbei zwei Seiten.
manual: trueverhindert, dass eine Taxonomie-Änderung in einen laufenden Ingest hineinstolpert
— erwähnt auskb-profiles.md,setup-instance.mdundkb/sources/COLLECTION.md, aus keinem
Skill, keiner AGENTS.md, keiner CLAUDE.md verlinkt. kb/sources/COLLECTION.mdbenenntevolve-subtypes.mdan derunclassified/-Zeile.
Die vom Vorbereitungs-Body übernommene, ursprünglich vierte Maßnahme entfiel: die
corpus-policy.md-Floor-Ausnahme fürunclassifiedsteht dort bereits seit #66.MINOR, geprüft gegen den Drop-in-Test: eine Instanz kopiert
instructions/undtypes/
über sich, nichts wird umbenannt oder entfernt, kein Kommando, kein Flag, kein
maschinengelesenes Format. Kein--breaking, kein Migrationsdokument.4.8.0-beta.9desselben
Kandidaten.Geändert:
instructions/kb-profiles.md,instructions/setup-instance.md,
instructions/evolve-subtypes.md(neu),kb/sources/COLLECTION.md.Schließt #68.
instructions/CONTRACT.md§ Writing an instruction: drei offene Fragen entschiedenDrei Issues aus der #65-Analyse zeigten auf denselben Abschnitt. Alle drei
enden dort, wo die Regel steht, nicht in einem Issue-Kommentar.Der Imperativ-Titel bindet eine Instruction, nicht ein
SKILL.md(#71).
Die Regel griff dem Wortlaut nach auf alle fünf Skills durch, deren H1
Nomenphrasen sind. Geprüft gegen die Primärquelle: Anthropic normiertname
unddescriptionund sagt zur Body-Überschrift nichts; die eigenen
Beispiel-Skills heißen# PDF Processing,# BigQuery Data Analysis. Dazu
das Sachargument — der H1 liegt auf keinem Retrieval-Pfad, weil über die
Aufnahme eines Skills diedescriptionentscheidet, die ab Sessionstart im
Kontext steht, während der Body erst beim Zugriff gelesen wird. In der Sitzung
kam ein Beleg dazu, den keines der Issues kannte: der vendorierte
commonplace-Korpus trägt dieselbe Imperativ-Titel-Regel, unabhängig
entstanden, und macht im selben Absatz dieselbe Ausnahme („for promoted skills,
the skill name is the title"). Die fünf Titel bleiben unverändert.Referenztiefe: Anthropics „one level deep" gilt gebündeltem Material (#72).
Weg 2 der drei zur Wahl stehenden. Der Beleg für die Reichweite steht im
vendoriertencodex-skill-creator/SKILL.md: die Beispiele der Regel sind
DOCX-JS.md,REDLINING.md,OOXML.md— alles Dateien im Skill-Bündel. Kein
Skill dieses Repos hat heute eine solche Datei, die Regel bindet hier also
wörtlich nichts. Für den Link von einem Skill auf einen repo-weiten Contract
fallen die beiden Hälften der Frage auseinander: die Mechanik (Zweit-Hop wird
womöglich nur angelesen) ist real und verzeichnisunabhängig, die Vorschrift ist
für diesen Fall von Anthropic nicht belegt. Die geteilten Contracts bleiben
geteilt — Invariante 8 hat sie dorthin gestellt, und § Frontload verlangt, dass
ein Schritt ohne Vorkontext entscheidbar ist, nicht dass jede Regel an ihm
wiederholt wird. Als Auflage bleibt das Billigere: ein Link sagt, was der
Schritt aus der Datei braucht.Ob die Mechanik hier überhaupt beißt, wurde vor der Entscheidung im Eval-Aufbau
nachgesehen, und die Antwort ist: nicht messbar. Die L2-Trajectory-Regeln lesen
ausschließlichwikitool.call,gate.*,publish.commitund
prompt.submitted— keine Dateizugriffe eines Agenten; auf Claude Code ist
überhaupt kein Tool-Hook verdrahtet, einhead -100hinterlässt also keine
Spur. Die zweite Hälfte der Behauptung, was am Ende im Kontextfenster stand,
erzeugt konstruktionsbedingt nirgends ein Event. Ein kausaler A/B-Vergleich
bräuchte den L3-Runner, der entworfen und nicht gebaut ist. Das steht jetzt im
Contract: eine Festlegung über Reichweite, keine Messung. Der Nebenfund — L2
sieht auf dem primären Harness gar keine Tool-Calls — ist ein eigenes Issue
wert und nicht Teil dieser Änderung.Wieviel Begründung ein Schritt tragen darf, ist jetzt messbar (#79). Der
alte Satz („Keep reasoning out of the body […] keep only enough reasoning to
decide edge cases") zog in zwei Richtungen, und die größte Instruction des
Repos lebte in der Lücke. Neu sind eine Keep/Cut-Tabelle und zwei Tests:
Substitution — die Passage streichen und den Schritt noch einmal lesen; rät
ein Agent ohne Vorkontext jetzt, war es eine Entscheidungshilfe und sie bleibt,
egal wie lang. Once — eine Entscheidungshilfe steht an dem Schritt, an dem die
Entscheidung fällt, und an genau einem solchen (Invariante 8). Danach gemessen
stand diesource_type/Capture-Asymmetrie inwiki-ingestzweimal; sie steht
jetzt einmal, in Schritt 1, und Schritt 6 trägt die Anweisung plus Verweis.
Die beiden anderen in #79 genannten Stellen — Namenskollision in Schritt 1,
## Not Extractedin Schritt 6 — bestehen den Substitutionstest und bleiben.
214 → 211 Zeilen; die Kürzung ist nicht der Zweck, die Eindeutigkeit ist es.PATCH, geprüft gegen den Drop-in-Test: eine Instanz kopiert
instructions/über sich, nichts wird umbenannt oder entfernt, kein Kommando,
kein Flag, kein maschinengelesenes Format, und der Rückweg funktioniert
genauso. Kein--breaking, kein Migrationsdokument.Geändert:
instructions/CONTRACT.md(§ Writing an instruction, drei neue
Unterabschnitte),instructions/wiki-ingest/SKILL.md(Schritte 1 und 6).Vier Befunde in der Skill-Prosa, ein Publish
Der Rest der #65-Analyse, soweit er die fünf
SKILL.mdselbst betrifft. Vier
Issues, fünf Dateien, kein Codeanteil.Die Hard Rule von
wiki-statuswar falsch (#70). Sie sagte „read-only.
Never writes, scaffolds, or modifies any file" — und Schritt 2 ruftlint,
schreibt also einen Report, was Schritt 2 sogar selbst beschreibt. Ein Agent,
der die Regel wörtlich nimmt, kann den Skill nicht ausführen; einer, der ihn
ausführt, hat die stärkste Aussage des Dokuments gebrochen, bevor er Schritt 5
erreicht. Das ist die teurere Sorte Widerspruch, weil die Hard Rule genau die
Stelle ist, an der ein Konflikt entschieden wird. Sie lautet jetzt wie die von
wiki-query— read-only gegenüber Wiki-Inhalt — und benennt den einen Write
mitsamt Grund:reports/ist gitignored und trägt keine Wiki-Seite. Schritt 5
behauptet nicht mehr, es sei keine Datei geschrieben worden, sondern sagt, was
mit der geschriebenen nicht passiert (Semantic Review bleibt leer, nichts
wird ausgetragen — das istwiki-lintSchritt 9). Der Decision Point „Never
publishes — nothing was written" trägt jetzt den wahren Grund: unterkb/hat
sich nichts geändert, und der Report kann gar nicht in einen Commit geraten.wiki-ingestundwiki-lintbekommen einen Abhak-Block (#74). Anthropics
Skill-Doku empfiehlt für „particularly complex workflows" eine Checkliste, die
der Agent in die Antwort kopiert und mitführt. Zwölf Schritte fallen
unzweifelhaft darunter. Der Ausschlag gibt aber nicht die Länge, sondern was
still ausfällt:## Not Extractedin Schritt 6, die Coverage-Prüfung in
Schritt 10, die Lint-Kadenz in Schritt 12 — keiner davon erzeugt eine
Fehlermeldung, wenn er ausbleibt.Die offene Frage des Issues — ob
wiki-lintdenselben Block bekommt — ist mit
ja beantwortet: neun Schritte, davon 3-6 reines Judgment, und ein Lauf, der
leise nur seine mechanische Hälfte gemacht hat, sieht aus wie ein
vollständiger. Damit haben zwei von fünf Skills einen Block und drei nicht, und
genau das wäre ohne festgeschriebenes Kriterium die nächste strukturelle
Ungleichheit im Sinne von #78.instructions/CONTRACT.md§ Writing an
instruction trägt sie deshalb jetzt: ein Block, wenn ein Ablauf acht
Schritte oder mehr hat und darin still ausfallende Schritte stehen. Beide
Hälften nötig — ein langer Ablauf aus reinen Tool-Calls meldet seine Lücken
selbst, weil der nächste Call ohne den vorigen scheitert. Der Abschnitt nennt
die drei anderen Skills mit ihren Schrittzahlen, damit niemand aus Symmetrie
einen vierten Block nachrüstet.wiki-queryprüfte nicht, bevor es filete (#75). Die drei Kriterien
(Synthese über mehrere Seiten, etwas noch nicht Dokumentiertes, wird wieder
gefragt) standen im Filing-Schritt selbst, und der Skill darf mehrere Seiten
je Sitzung anlegen — es gab also keine Stelle, an der jede geplante Seite
einzeln gemessen wurde. Neuer Schritt 5 vor dem erstennew: Kandidaten
benennen, jeden für sich gegen alle drei halten, ein Stapel wird nie als Stapel
beurteilt. Wer durchfällt, wird nicht angelegt, sondern in der Antwort mit
einem Satz genannt — der Nutzer kann ihn trotzdem verlangen. Der bisherige
Filing-Schritt ist Schritt 6,log appendSchritt 7, die Hard Rule zieht mit.
Der Mass-Update-Gate-Hinweis bleibt, sagt aber jetzt dazu, dass er keine
Ersatzprüfung ist: das Gate zählt Dateien und weiß nichts über Berechtigung,
und ein Stapel unter der Schwelle ist von ihm nicht freigegeben, nur nicht
angehalten worden. Dazu diesession-setup.md-Zeile in derselben Form wie in
den drei anderen — Schritt 7 läuft immer und der Filing-Pfad ziehtnew,
xref addund die Rebuilds nach sich.Die Kommandolisten gingen mit den Schritten auseinander (#78).
cite addfehlte inwiki-ingestundwiki-manage, obwohl beide es
ausdrücklich vorschreiben;types describefehlte inwiki-ingest, wo
Schritt 6 diesource_type-Werte daraus zieht;xref addfehlte in
wiki-lint, wo Schritt 1 das Umlabeln einer schwachen Kante darauf stützt;
publishfehlte inwiki-lintundwiki-query, wo je ein Decision Point es
beim Namen nennt. In die andere Richtung:rmstand inwiki-lints Liste,
ohne dass ein Schritt es begründet — die gefährlichere Richtung der Drift, weil
rmSeiten löscht. Dazulog status(entscheidet den Trigger, gelaufen wird
es vonwiki-ingest) und die nie benutzten Flagslint --markdownund
lint --json. Beide Streichungen stehen jetzt als Deliberately absent unter
der Liste, mit Grund — sonst trägt sie jemand aus Vollständigkeit wieder ein.Nicht als Drift gezählt und bewusst gelistet geblieben:
publish,
log append,index rebuildundsources rebuild-index, wo ein Skill sie
überpublish-cycle.mddelegiert. Ebensoxref removeinwiki-manage, das
zum Unlinking-Fall gehört, den der Skill als Ganzes anpage-lifecycle.md
abgibt; auch das steht jetzt als Satz dort, nicht als stille Annahme.Der zweite Teil von #78 ist die Symmetrie:
wiki-manageundwiki-status
tragen jetzt einen Beispielblock wie die drei anderen. Fünf Skills mit
demselben Aufbau sollten denselben Aufbau haben — ein fehlender Abschnitt liest
sich sonst als Aussage („hier gibt es keine typischen Fälle"), die niemand
gemeint hat.Die offene Frage aus #78 — ob
instructions verifydiesen Abgleich künftig
selbst macht — ist mit ja beantwortet und als #83 ausgelagert. Trivial ist er
nicht: die drei Ausnahmen oben (Delegation überpublish-cycle.md, benannte
Delegation an eine andere Instruction, „Deliberately absent") müsste ein Prüfer
alle kennen, sonst meldet er bei jedem Lauf dieselben Stellen. Nur die dritte
hat heute einen maschinenlesbaren Anker — den Absatz, den dieser Eintrag oben
eingeführt hat.PATCH, geprüft gegen den Drop-in-Test: eine Instanz kopiert
instructions/
über sich, nichts wird umbenannt oder entfernt, kein Kommando, kein Flag, kein
maschinengelesenes Format, und der Rückweg funktioniert genauso. Kein
--breaking, kein Migrationsdokument.Geändert:
instructions/wiki-status/SKILL.md,instructions/wiki-query/SKILL.md,
instructions/wiki-ingest/SKILL.md,instructions/wiki-lint/SKILL.md,
instructions/wiki-manage/SKILL.md,instructions/CONTRACT.md(§ Writing an
instruction, neuer Unterabschnitt „When a skill carries a copy-in checklist").
wiki-ingestbleibt mit 233 Zeilen unter Anthropics 500er-Schwelle.Schließt #70, #74, #75 und #78.
Issue-Nummern in ausgelieferter Doku (#77):
dist exportlieferte
Dateien aus, die im Fließtext auf Issue-Nummern dieses Trackers verwiesen —
„flat since Gitea #67", „new sourcerefuses without it (Gitea #66)". In einer
verteilten Instanz zeigt das auf nichts. Der Leser kann den Verweis weder
auflösen noch als unauflösbar erkennen, und eine Regel sieht damit so aus, als
stütze sie sich auf einen Beleg, den niemand beibringen kann. Das Board liegt
im Ursprungs-Repo, undinstructions/dev/issue-tracking.md— die einzige Datei,
die das überhaupt sagt — wird vondist exportmit dem Rest von
instructions/dev/weggeschnitten. Gegenprobe zum eigenen Anspruch aus
instructions/CONTRACT.md§ „Writing an instruction": „self-contained enough
for an agent with no prior context".Gemessen statt geschätzt: ein Export in ein leeres Verzeichnis,
grep -rn '#[0-9]', ergab 43 Treffer in 16 Dateien außerhalb vontools/**/*.py—
raw/CONTRACT.mdallein acht. Das Issue hatte zehn gelistet.Aufgelöst wurde nicht durch eine Markierung, sondern durch Umformulierung:
die Nummer fällt weg, die Datierung geht in Worte. Aus „flat since Gitea
#67" wird „flat since the addressing scheme dropped type directories", aus
„Pre-#67 files are not moved" wird „Files promoted under the old type
directories are not moved". Der Satz trägt sich damit selbst — es gibt keine
repoweite Notation zu definieren und an genau einer Stelle zu halten
(Invariante 8), und kein Leser vonREADME.mdmussAGENTS.mdgeladen haben,
um sie aufzulösen. Rückverfolgbar bleibt es hier übergit blame→ Commit-
Message; die tragen die Nummern ohnehin.Zwei Stellen, an denen der Zeiger der ganze Wert des Satzes war und in Worten
nichts übrig geblieben wäre, stehen jetzt in einem
<!-- dist:strip-start/end -->-Block: ininstructions/CONTRACT.md(was ein
Test der Kontextfenster-Behauptung kosten würde) und inEVALS.md(wo die
Coverage-Lücken geschlossen werden). Im Dev-Repo sichtbar, im Export weg — die
bestehende Konvention ausinstructions/CONTRACT.md§instructions/dev/, hier
zum zweiten Mal angewandt statt neu erfunden.docs verifyprüft es jetzt — die offene Frage des Issues, mit Ja
beantwortet.check_no_issue_referencesliest nicht den Arbeitsbaum, sondern
den Text, dendist_cmd.build_plan()schreiben würde: dort lebenROOT_FILES,
derinstructions/dev/-Ausschluss und das.template-Rekeying schon, und der
Text hat seine Marker-Blöcke bereits verloren. Deshalb ist ein Strip-Block
automatisch exemptiert, ohne dass der Check ihn kennen müsste.Der Einwand aus
instructions/dev/issue-tracking.md§ „What no tool checks" —
wikitoolsoll den Tracker nicht kennen — trägt hier nicht, und das ist die
Grenze, die der Abschnitt jetzt selbst zieht:re.compile(r"#\d+")hat keinen
Client, keine URL und keinen Begriff vom Zustand eines Issues. Der Check sieht
eine Eigenschaft des Dokuments, nicht des Boards. Gemessen: null False
Positives über den gesamten Export, weil Markdown-Anker aus Wortzeichen
bestehen (](#gates)matcht nicht). Der erste Fund war prompt der Satz, den
diese Sitzung selbst intools/CONTRACT.mdgeschrieben hatte, um die Regel zu
erklären.tools/**/*.pybleibt bewusst außen vor, mit ~90 Treffern in Docstrings und
Kommentaren. Ein Code-Kommentar adressiert, wer die Zeile editiert, und das
passiert ausschließlich im Ursprungs-Repo:dist exportschneidet den
stack-dev-Skill mitinstructions/dev/weg. Ein ausgeliefertestools/ist
Laufzeit-Maschinerie, keine Lektüre..gitignoreundtools/.coveragercsind
aus demselben Grund nicht im Check — von Hand mitgezogen wurden sie trotzdem,
sodass der Export heute in keiner Datei außerhalb.pyeine Nummer trägt.MINOR, geprüft gegen den Drop-in-Test: kein Kommando, kein Flag, kein
Dateiformat, keine Umbenennung; der Rückweg funktioniert unverändert, die alte
Version führt den Check schlicht nicht aus. Kein--breaking, kein
Migrationsdokument. Eine Konsequenz ist zu kennen: der Check liest auch die
instanzeigenenkb/CONVENTIONS.mdundkb/<collection>/COLLECTION.md, weil ein
Export sie als.templatemitnimmt. Eine Instanz, die dort ihre eigene
Ticket-Nummer zitiert, bekommt beim nächstendocs verifyein Finding. Das ist
kein Fehlalarm — ein Export dieser Instanz würde den Verweis weitergeben —
aber es ist neu.Geändert:
tools/chemenu/commands/docs_verify.py(neuer Check plus
shipped_prose()),tools/chemenu/tests/test_docs_verify.py(sechs Tests:
sauberer Baum, präparierte Datei, Anker-Nicht-Treffer,.pyaußerhalb des
Scans, Strip-Block unsichtbar,verifybricht ab),tools/CONTRACT.md
(Kommandotabelle und Fehlerkontrakt-Zeile),tools/README.md,
instructions/dev/issue-tracking.md(neuer § Citing an issue in the repo, und
§ What no tool checks zieht die Grenze zwischen „was dieses Repo über den
Tracker schreibt" und „dem Tracker selbst"), sowie die 16 Doku-Dateien:
raw/CONTRACT.md,kb/CONTRACT.md,tools/CONTRACT.md,types/type-spec.md,
types/source.schema.yaml,kb/sources/COLLECTION.md,
kb/concepts/COLLECTION.md,instructions/wiki-ingest/SKILL.md,
instructions/evolve-subtypes.md,instructions/bootstrap.md,
instructions/kb-profiles.md,instructions/mcp-read-server.md,
instructions/CONTRACT.md,README.md,EVALS.md,INSTALL.md,
docs/pipeline-rationale.md,.gitignore,tools/.coveragerc.Schließt #77.
Warum das eine MAJOR ist, obwohl
kb/unberührt bleibt (#73, #76): Anthropics
Skill-Authoring-Doku verlangt für Referenzdateien über 100 Zeilen ein
Inhaltsverzeichnis, damit ein Agent, der eine solche Datei nur mithead -100
anliest, trotzdem die volle Abschnittsübersicht sieht — dieselbe Vorschau-Mechanik,
die #72 schon für die Referenztiefe als real anerkannt hat. Ein von Hand
gepflegtes Inhaltsverzeichnis wäre die nächste Drift-Quelle; also ist es jetzt eine
dritte generierte Region nebenxrefs undcites (<!-- wikitool:toc -->...
<!-- /wikitool:toc -->,tools/chemenu/toc.py), erzeugt und geprüft wie jede
andere abgeleitete Kopie.wikitool docs toc [--apply]schreibt sie;docs verify
prüft jetzt, dass sie auf jeder Datei aktuell ist, dieAGENTS.md, ein
Stage-/Collection-Contract oder die flacheinstructions/**.md-Form abdeckt (25
Dateien in diesem Repo,instructions/dev/eingeschlossen — strukturell dieselbe
Dateiform, nur vondist exportausgenommen). Der Umfang ist berechnet, nie eine
Handliste: er folgt AGENTS.md § File naming, nicht einer Link-Traversierung ab den
fünf Content-Skills, und schließttypes/<name>.md-Einzelspecs bewusst aus — die
laufen überwikitool types describe, das den Inhalt neu rendert statt die Datei
roh auszugeben, sodass die Vorschau-Mechanik dort gar nicht greift.Das ist grenzüberschreitend, weil
docs verifydamit eine neue Pflichtprüfung
über bestehenden Inhalt bekommt: eine Instanz mit einer eigenen
instructions/*.md-Datei über 100 Zeilen, an der nichts geändert wurde, sieht
docs verifynach reinem Tool-Update neu fehlschlagen, bis einmalig
wikitool docs toc --applyläuft und der Diff committet wird — derselbe
Bruchtyp wie ein verschärftes Type-Spec-Pflichtfeld. Keine Migration nötig, weil
keinkb/-Inhalt betroffen ist; der einmaligedocs toc --apply-Lauf ist der
volle Reparaturweg.Zwei Nebenfunde beim Bauen der TOC-Regel, beide vor dem Bump behoben, weil sie
sonst denselben Bump falsch aussehen ließen:docs verifys
ISSUE_REFERENCE_RE(#\d+) hielt numerierte-Schritt-Anker wie
#2-fix-the-fidelity-before-writing-a-wordfür Issue-Zitate — die Regel nahm
bisher an, dass ein Anker immer mit einem Buchstaben beginnt, was für
nummerierte Überschriften (instructions/capture-session.md) nicht mehr gilt;
behoben durch einen Lookbehind, der genau die](#...-Linkfragment-Form
ausschließt, ohne ein echtes(#66)-Zitat zu übersehen. Und
instructions_cmd.dev_only_forbidden_referencesprüfte mit blankem
name in text: ein TOC-Anker wie#where-stack-development-happens
(instructions/private-instance.md) enthält „stack-dev" als reine Teilzeichenkette,
ohne den Skill zu meinen — behoben durch eine wortgrenzengebundene
Regex-Suche.Geändert:
tools/chemenu/toc.py(neu),tools/chemenu/commands/docs_verify.py
(check_toc_regions,docs toc-Kommando,ISSUE_REFERENCE_RE-Lookbehind),
tools/chemenu/commands/instructions_cmd.py
(dev_only_forbidden_referenceswortgrenzengebunden),tools/CONTRACT.md
(docs toc-Zeile),tools/chemenu/tests/test_toc.py(neu, 15 Tests),
tools/chemenu/tests/test_docs_verify.py(drei neue Tests: nummerierter Anker,
geklammertes echtes Zitat, TOC-Region auf dem realen Baum),
tools/chemenu/tests/test_instructions_cmd.py(ein neuer Test für die
Teilzeichenketten-Kollision), sowie die 25 Referenzdateien, die jetzt eine
TOC-Region tragen:AGENTS.md,kb/CONTRACT.md,kb/CONVENTIONS.md,
kb/concepts/COLLECTION.md,raw/CONTRACT.md,tools/CONTRACT.md,
types/type-spec.md,instructions/CONTRACT.md,instructions/gates.md,
instructions/setup-instance.md,instructions/private-instance.md,
instructions/link-taxonomy.md,instructions/kb-profiles.md,
instructions/ingest-large-tree.md,instructions/capture-session.md,
instructions/claude-code-model-selection.md,instructions/german-terminology.md,
instructions/evolve-subtypes.md,instructions/mcp-read-server.md,
instructions/migrate-corpus.md,instructions/migrations/3.0.0-authoring-conventions.md,
instructions/migrations/4.0.0-link-taxonomy.md,instructions/dev/issue-tracking.md,
instructions/dev/testing-conventions.md,instructions/dev/version-parts.md.Zusätzlich, unabhängig davon (#76):
instructions/session-setup.md§ Scope und
instructions/gates.mdbehaupteten, die Budget-Ausnahme richte sich danach, ob
ein Kommando das Wiki verändert. Tatsächlich zähltrun_budget.pyeine feste
Allowlist (SKIP_COMMANDS/SKIP_COMMAND_PATHS) —lintschreibt nur ins
gitignortereports/, sieht also lesend aus, steht aber nicht auf der Liste und
zählt wie jedes mutierende Kommando. Beide Dateien verweisen jetzt auf die Liste
intools/CONTRACT.md, statt sie mit einer falschen Faustregel zu umschreiben.
Kein Versionsbezug — reine Prosa-Korrektur, im selben Bump mitgeführt.Nachgezogen in
-beta.3:dist exporterzeugt die TOC-Region jetzt nach
dem Marker-Strip neu. Ein<!-- dist:strip-start/end -->-Block kann eine ganze
Sektion umschließen — der inAGENTS.mdumschließt## Developing this stack—,
sodass die ausgelieferte Datei eine Überschrift weniger hat, als das im
Arbeitsbaum erzeugte Inhaltsverzeichnis auflistet. Die frische Instanz wäre
damit beim allererstendocs verifyüber eine Datei gefallen, die niemand
angefasst hat. Gefunden hat das die CI im Export-Replay („The distribution works
as a fresh instance"), nichtpytestund nichtdocs verifyim Arbeitsbaum —
beide sehen den gestrippten Text nie. Der Regressionstest sitzt jetzt in
test_dist_cmd.py.Nachgezogen in
-beta.2, weildocs verifydie eigene Dokumentationstreue nur
für die Existenz einer Kommandozeile prüft, nicht für deren Inhalt: die
docs verify-Zeile intools/CONTRACT.mdnennt jetzt die TOC-Prüfung, die
Fehlerkontrakt-Tabelle bekommt die fehlendedocs toc-Zeile (Schritt 3 in
tools/README.md§ Adding a command verlangt beide Tabellen, geprüft wird nur
eine), undtools/README.md§ Adding a command Schritt 5 nannte als
--major-Kriterium „wenn bestehender Inhalt migriert werden muss" — was
instructions/dev/version-parts.mdausdrücklich verneint und was dieser Bump
selbst widerlegt: grenzüberschreitend mit--no-migration.Konfidenz-Mechanismus ersatzlos entfernt (schließt #60).
confidence,
confidence_base, der Zeit-Decay und die Konfidenz-Rubrik sind aus Schema,
Kommandos (confidence decay/init-base,touch --confidence-base), Lint
(confidence_exceeds_source_standing), Suche (--sort -confidence,
Konfidenzspalte) und jeder Doku-Stelle entfernt, die sie erwähnte.Der Mechanismus wurde gemessen, nicht nur für unschön befunden: 43 der 152
betroffenen Seiten trugen nie mehr als den Schema-Vorgabewert 0.5, der Decay
hat seit seiner Einführung keinen einzigen Wert bewegt (confidence_decay.py
übersprangconcept_type: decision,touch --confidence-basezog das
abgeleitete Feld nie mit), und kein Konsument im Stack hing außer über
corpus_diff.STRUCTURAL_FIELDS— eine Abhängigkeit von der Existenz des
Feldes, nicht von seinem Wert — überhaupt an ihm. Vier Entwürfe für eine
Reparatur (Rubrik nachjustieren, Quellenautorität anheben, aus
authority × fidelityberechnen, zwei Schubladen für Reifegrad und
Volatilität) scheiterten an denselben Messwerten. Die vollständige Studienlage
steht in #85, wo das Thema als zurückgestellt geführt wird, nicht als
verworfen.An die Stelle tritt nichts Neues:
kb/CONVENTIONS.mdbekommt eine
Prosa-Hedging-Regel — nach Quellenlage hedgen statt nach Schwellenwert, siehe
kb/CONVENTIONS.md § Hedging— und die Arbeitsliste ersetzt
--field 'confidence<0.6'durch Prädikate auf tatsächlich aufgezeichneten
Feldern (--field '!sources',--field provenance=general). Mit dem Feld
stirbt auchconfidence_exceeds_source_standing, der einzige automatische
Abgleich zwischen einer Seite und der Standing ihrer Quellen; ein Ersatz ohne
Zahl ist als Kandidat in #85 vorgemerkt, aber bewusst nicht Teil dieses Pakets.version bumpbekommt dabei ein neues Flag,--migration-required: der
laufende Kandidat hatte in einem früheren Bump--no-migrationerklärt, und
dieses Paket macht die Erklärung falsch. Die**Migration:** none required-Zeile ist maschinengeschrieben (Invariante 1 verbietet den
Handgriff), und bislang gab es keinen Weg, sie zurückzunehmen, sobald ein
späterer Bump doch eine Migration braucht. Das Flag entfernt die Zeile
stattdessen und verlangt ein Migrationsdokument, das die neue Basisversion
referenziert, bevor es das tut.Was das für eine bestehende Instanz bricht, steht in der
**Breaking Change:**-Zeile oben.instructions/migrations/5.0.0-confidence-removal.md
ist der mechanische Strip der zwei Felder über den betroffenen Korpus,
mitsamt der Invariante, die ein automatisierter Lauf einhalten muss (kein
modified:-Bump, byte-identischer Body, unveränderte Referenzarrays).Nachgezogen in
-beta.6:instructions/dev/version-parts.mdSchritt 6
beschreibt den Rücknahmepfad jetzt selbst.tools/CONTRACT.mdführte das neue
Flag bereits, aber die Instruction, die eine Sitzung vor einem Bump liest,
kannte den Fall nicht — dieselbe Sitzung ist genau darüber gestolpert. Der
Abschnitt nennt auch, warum ihn nichts meldet: die Zeile ist
maschinengeschrieben,docs verifygenügt ihr bloßes Vorhandensein, und die
Eskalationsprüfungen laufen nur auf dem Bump, der die Grenze zuerst
überschreitet.Nachgezogen in
-beta.7:instructions/wiki-status/SKILL.mdträgt jetzt den
session-setup.md-Verweis, den die anderen vier Content-Skills längst haben.
Der Skill ruft in Schritt 2lintauf, undlintsteht nicht auf der
Ausnahme-Allowlist inrun_budget.py— er zählt wie jedes mutierende
Kommando. Ohne exportierteWIKITOOL_SESSION_IDfällt die Zählung auf
getppid()zurück, die Sitzung erbt also den Stand irgendeiner fremden Shell.
Bis-beta.6war das Fehlen des Verweises durch die falsche Regel gedeckt, die
session-setup.md§ Scope selbst aufstellte („verändert das Wiki"); seit sie
die tatsächliche Allowlist nennt, ist es schlicht ein Loch.Die Alternative —
lintdurch etwas Befreites ersetzen undwiki-status
wirklich budgetfrei machen — scheidet an der Sache aus: der Skill liest aus dem
Report die Graph-Auswertung (Broken Links, Orphans, Most-Linked Pages,
uncovered raw files), und kein befreites Kommando liefert die.doctorprüft
die Installation, nicht den Korpus;searchist Retrieval. Einwiki-status
ohnelintwäre kein leichterer Skill, sondern ein leerer.Damit gilt über alle fünf Content-Skills dieselbe Aussage: ein Skill verlinkt
session-setup.mdgenau dann, wenn er mindestens ein nicht-befreites
wikitool-Kommando aufruft. Geprüft wird sie nicht —instructions verify
kennt weder die Kommandolisten der Skills noch die Allowlist. Das wäre ein
eigener Schnitt.Nachgezogen in
-beta.8:CLAUDE.mdimportierte bislangUSER.md,SOUL.md,
ENVIRONMENT.mdundinstructions/claude-code-model-selection.mdzusätzlich
zuAGENTS.md— eine Harness-Drift, denn dieselben drei
Personalisierungsdateien werden auf den anderen drei Harnesses (Codex CLI,
Copilot, Vibe) allein durchAGENTS.mds eigene Anweisung gelesen, nie
injiziert.CLAUDE.mdimportiert jetzt nur nochAGENTS.md; die Bedingung
„if the runtime has not already injected them" inAGENTS.md§
Personalization entfällt, weil kein Runtime mehr injiziert.instructions/claude-code-model-selection.mdist entfernt und als
docs/model-and-effort-selection.mdneu geschrieben, in Empfehlungsstimme
statt als Instruktion: die Datei beschrieb überwiegend Handlungen, die eine
Sitzung nicht selbst ausführen kann (das eigene Modell,/code-review-Stufen),
und wurde im ganzen Baum nur von den beiden dev-only Skillsstack-devund
stack-closereferenziert, deren Links jetzt dorthin zeigen. Eine
bestehende Instanz behält die entfernte Datei als Überbleibsel, bis sie
wikitool dist upgrade --prunelaufen lässt oder die Datei von Hand löscht —
instructions verifymeldet sie sonst neu als verwaist.AGENTS.md§§ Personalization, Environment und File naming sind an den
Stellen gekürzt, die eine zweite Kopie einer Regel waren, die
docs/ownership-and-templates.mdoder eine Invariante schon trägt; § File
naming verlinkt jetzt alle vierdocs/-Seiten namentlich, was vorher
nirgends geschah.USER.mdundSOUL.mdverlieren an derselben Stelle
Rahmen- bzw. Herkunftsprosa, dieUSER.md.templatebzw. ein Kommentar in
SOUL.mdselbst schon trägt.Telemetrie-Default nach Installationsform (#55):
chemenu.telemetry.writer.enabled()war
eine Zeile - immer an,WIKI_TRACE=0das einzige Opt-out. Richtig für dieses Repo, dessen
Traces das Messinstrument sind, mit dem der Stack sich selbst bewertet, aber die falsche
Voreinstellung für eine ausgelieferte Instanz: dort hat niemand Telemetrie bestellt, und
niemand liestEVALS.md, bevor die erste Datei geschrieben ist. Dazu kam eine zweite Lücke:
keine Mengenbegrenzung irgendeiner Art -reports/telemetry/<session>/trace.jsonlwächst,
solange die Instanz läuft, und nichts räumt je etwas weg.tools/chemenu/telemetry/policy.py(neu) löst jetzt beides an einer Stelle, gekeyt auf den
aufgelösten Root, damitwikitool doctor, der Writer und der MCP-Server-Start-Guard dieselbe
Antwort für denselben Checkout geben. Ein Git-Clone dieses Repos bleibt beim alten Verhalten
(an,WIKI_TRACE=0schaltet ab); eine perdist exportausgelieferte Instanz startet ab jetzt
mit Telemetrie aus - erkannt an der ohnehin vorhandenen, maschinengeschriebenen
.wikitool-release.json(Invariante 1). Wer sie dort anschalten will, legt eine
.wikitool-telemetry.jsonan (pro Checkout, gitignored, kein.template- wie
.wikitool-remotes.json);WIKI_TRACEüberschreibt weiterhin beide Richtungen und schlägt die
Datei.Zwei unabhängige, fail-silent durchgesetzte Mengendeckel greifen in beiden Installationsformen:
ein Byte-Deckel pro Session-Trace (Default 5 MiB, einstatvor jedem Append) und eine
Retention über die Anzahl der Session-Verzeichnisse (Default 250). Die Retention reserviert den
Platz der gerade entstehenden Session, statt sie mitzuzählen - sonst pendelt der Bestand
dauerhaft beikeep+1statt beikeep, weil jeder Lauf immer nur das räumt, was der vorige
Lauf über dem Limit gelassen hat. Am Byte-Limit schreibt ein weiterer Aufruf nichts mehr außer
einem einmaligentelemetry.limit-Event, per Exclusive-Create auf eine.limit-Sentinel-Datei
ausgelost - derselbe Ein-Schreiber-Trick wie beimsession.start-Header, für den Fall, dass
mehrere Prozesse gleichzeitig auf denselben Trace schreiben. Eine Retention-Runde löscht
ausschließlichtrace.jsonl/.limitder überzähligen Verzeichnisse undrmdirt nur, wenn
danach leer - niermtree, aus demselben Grund wie beiupstream merge(#30):
reports/telemetry/hält lokale, nicht rekonstruierbare Daten, dieeval scoreliest.wikitool doctorbekommt einen neuentelemetry-Check (an/aus, warum, Menge gegen beide
Deckel, nieFAIL, wiepublish-remotesundenvironment). Der MCP-Server-Start-Guard
(check_trace_destination) lasWIKI_TRACEbisher selbst statt den Writer zu fragen - eine
zweite Kopie derselben Regel, die Invariante 8 verletzte, bevor diese Änderung sie schließt; er
fragt jetzt dieselbe Policy.instructions/setup-instance.mdbekommt einen neuen
Entscheidungspunkt (Schritt 10).MINOR, kein neuer Boundary-Crossing: additiv in beide Richtungen - eine bestehende Instanz
kopiert die neue Maschinerie über sich und hört still auf zu schreiben, ohne Hand-Arbeit oder
Migration; die alte Version zurücklegen stellt den alten Default wieder her, weil sie die neue
Datei und die neuen Variablen schlicht ignoriert. Der Kandidat trägt seine--breaking-Zeile
bereits aus einem früheren Bump (Confidence-Entfernung); diese Änderung fügt keine neue hinzu.Geändert:
tools/chemenu/telemetry/policy.py(neu),tools/chemenu/telemetry/writer.py,
tools/chemenu/telemetry/schema.py,tools/chemenu/commands/doctor.py,
tools/chemenu/mcp/server.py,tools/chemenu/config.py,tools/chemenu/version.py,
.gitignore,tools/chemenu/tests/conftest.pyund die Telemetrie-/Doctor-/MCP-Server-Tests,
.gitea/workflows/ci.yml,EVALS.md,INSTALL.md,INSTALL-MCP.md,reports/CONTRACT.md,
tools/CONTRACT.md,instructions/setup-instance.md. Schließt #55.tools/CONTRACT.mdbeschriebraw acceptnoch vor #67: Typverzeichnisse statt Datums-Shard,
kein--fidelity/--authority, Stem-Eindeutigkeit "atraw/<type>/level" statt global. Vier
Zellen (beideraw accept-Zeilen der Kommandotabelle, beide im Fehlerkontrakt) waren an #67
vorbeigeschrieben worden -raw/CONTRACT.mdselbst war korrekt,docs verifyscheck_commands
prüft nur Kommandonamen gegen die Tabelle, nicht deren Prosa gegen den Code. Reine
Doku-Korrektur, kein Verhalten geändert. Schließt #89.Der MCP-Server bekommt ein sechstes, optionales Tool:
submit, ein Schreibpfad für Dokumente
von einem Aufrufer, der nicht dieses Terminal ist. #19s Eigenschaft "kein Tool schreibt" galt
strukturell - nichts unterchemenu.commandswar importierbar - und diese Formulierung wird mit
einem echten Schreibpfad falsch. Die tragfähige Ersatzformulierung ist eine Positiv-Liste
statt einer Abwesenheit: der Serverprozess darf in genau ein Verzeichnis schreiben,
mcp-upload/, erzwungen durch eine einzige Funktion (chemenu.upload._write_atomic_within),
die jeden aufgelösten Zielpfad gegen dieses eine Verzeichnis prüft - Tests decken..,
absolute Pfade und einen Symlink, der aus dem Verzeichnis hinausführt. Die alte
Abwesenheitseigenschaft bleibt daneben unverändert bestehen: die Reviewer-Kommandos
(upload accept/upload reject) liegen unterchemenu.commandsund sind vom Server aus nicht
erreichbar.Zwei Stufen vor
raw/, zwei verschiedene Grenzen.mcp-upload/<id>/hält Material, das
niemand geprüft hat;wikitool upload accept <id> --confirm <token>befördert es nach
incoming/, wo es sich nicht mehr von einer lokal abgelegten Datei unterscheidet und
wiki-ingestSchritt 1 unverändert greift. Ohne Token verweigertupload acceptmit Exit
42 - der vierte Gate des Stacks, Upload Review Gate, gleiche Form wie der
Mass-Update-Gate: ein Token, der Id, Dateiname, Größe, Sha256 und Einreicher digestet, wird
also ungültig, sobald sich das Manifest ändert.wikitool upload reject <id> --reason "<warum>"
braucht keinen Gate - Ablehnen braucht keine Freigabe, nur Annehmen tut das - und löscht das
Material, behält aber Grund und Sha256 im append-onlymcp-upload/ledger.jsonl.Die Einreicher-Identität kommt ausschließlich aus einem HTTP-Header, nie aus einem
Tool-Argument.identity_header(DefaultX-Forwarded-User) in.wikitool-upload.json
nennt den Header; fehlt er auf der Anfrage, wird ohne jeden Schreibvorgang verweigert - eine
unzurechenbare Einreichung ist damit unmöglich, nicht nur unerwünscht. Das Manifest hält neben
submitterauchsubmitter_source(den Headernamen), damit der Datensatz sagt, worauf die
Behauptung ruht, statt sie als Tatsache zu führen. Die Middleware muss den Header selbst setzen
und eine vom Client mitgeschickte Kopie verwerfen - eine Deployment-Pflicht, dokumentiert in
INSTALL-MCP.mdSchritt 5 undinstructions/ingest-queue.md, die der Prozess selbst nicht
erzwingen kann..wikitool-upload.jsonist ein struktureller Opt-in, nicht bloß eine Konfiguration. Fehlt
die Datei, wird dassubmit-Tool gar nicht erst registriert - anders als bei
.wikitool-remotes.json, wo Abwesenheit "unbeschränkt" heißt, heißt sie hier "der Schreibpfad
existiert nicht". Eine defekte Datei ist ein Startfehler des Servers (ValidationErrorbeim
Aufbau) und einFAILinwikitool doctors neuemupload-intake-Check - nie "keine
Beschränkung". Weitere Schutzschichten inchemenu/upload.py: eine Größenprüfung auf der
base64-Länge vor dem Dekodieren (mit einem Toleranzband von 2 Bytes für Padding, damit sie
keine an der Grenze liegende, legitime Einreichung fälschlich ablehnt - der Nachdekodier-Check
bleibt die exakte Durchsetzung), eine Endungs-Positivliste, ein rollierendes
24-Stunden-Kontingent pro Einreicher (Anzahl und Bytes, aus dem Ledger berechnet, nie aus
Verweigerungen), und eine Ablehnung doppelter Inhalte, solange die erste Einreichung noch
wartet - unter Nennung der wartenden Id.incoming/bleibt komplett unberührt als zweite, unabhängige Grenze. Ein Unterverzeichnis
dort wird seit #67 toleriert und ignoriert, sodass eine Fremdeinreichung darunter still
promotierbar gewesen wäre - deshalb ein eigenes Top-Level-Verzeichnismcp-upload/, gitignored,
ohne.gitkeep(die Schreibprimitive legt es selbst an).docs_verifys Ignore-Kanarien prüfen
jetzt auchmcp-upload/probe.pdfund.wikitool-upload.json.MINOR, kein neuer Boundary-Crossing: additiv in beide Richtungen geprüft - eine bestehende
Instanz kopiert die neue Maschinerie über sich und bekommt ein neues, standardmäßig
unregistriertes Tool, ohne Hand-Arbeit oder Migration; kein.wikitool-kb.json-Feld, kein
Type-Spec, kein umbenanntes Kommando oder Flag, kein geändertes Dateiformat. Die alte Version
zurücklegen verliert nichts - der Schreibpfad existiert dort schlicht nicht. Der Kandidat trägt
seine--breaking-Zeile bereits aus einem früheren Bump (Confidence-Entfernung); diese Änderung
fügt keine neue hinzu.Geändert:
tools/chemenu/upload.py(neu),tools/chemenu/commands/upload_cmd.py(neu),
tools/chemenu/tests/test_upload.py(neu),tools/chemenu/tests/test_upload_cmd.py(neu),
tools/chemenu/mcp/server.py,tools/chemenu/tests/test_mcp_server.py,
tools/chemenu/commands/doctor.py,tools/chemenu/tests/test_doctor.py,
tools/chemenu/commands/docs_verify.py,tools/chemenu/cli.py,tools/chemenu/config.py,
.gitignore,tools/CONTRACT.md,AGENTS.md,instructions/gates.md,
instructions/mcp-read-server.md,instructions/wiki-ingest/SKILL.md,
instructions/ingest-queue.md(neu),raw/CONTRACT.md,docs/why-gates-are-code.md,
INSTALL-MCP.md,README.md. Schließt #32.AGENTS.md behauptete,
docs verifyprüfe die Contract-Prosa selbst - das stimmt nicht (#90).
check_cli_readme()prüft nur, ob der gebacktickte Pfad einer Tabellenzeile registriert ist, nie
den Rest der Zelle: eine ausgetauschte Kommandobeschreibung oder ein neues--flagbleiben
unsichtbar, undTABLE_CELL_REläuft über das ganze Dokument statt über eine abgegrenzte
"Kommandotabelle".AGENTS.md§ Changelog zählte trotzdem "command tables, contracts, ignore
canaries" als maschinell geprüft auf und grenzte die Sitzungspflicht aufREADME.md/EVALS.md/
tools/README.mdein -tools/CONTRACT.mdund jedes<stage>/CONTRACT.mdstanden damit auf
keiner Liste, die je jemand nachzieht.Der Absatz nennt jetzt nur noch, was
docs verifys eigene Zeile intools/CONTRACT.md
tatsächlich auflistet (Verweis statt Kopie), und macht jede Zellenprosa - Kommandotabelle,
Fehlerkontrakt, Stage-Contract - ausdrücklich zur Sitzungsarbeit, neben den drei README-artigen
Dateien. Die Docstring voncheck_cli_readme()behauptet nicht mehr, sie prüfe
"tools/CONTRACT.md's command table" - sie beschreibt jetzt, dassTABLE_CELL_REdas ganze
Dokument scannt und nur den gebacktickten Pfad liest, nie die restliche Zelle.Neue Instruction instructions/dev/doc-pull-through.md
(dev-only) listet je berührter Fläche, welches Dokument eine Behauptung darüber trägt: beide
Tabellen intools/CONTRACT.md, der berührte<stage>/CONTRACT.md,AGENTS.mdbei
verschobener Regel/Gate/Invariante, die README-artigen Dateien,docs/bei verschobener
Begründung.stack-dev/SKILL.mdbekommt dafür einen neuen Schritt 5 zwischen Versionsbump und
Verify/Publish (jetzt Schritt 6) - ein Satz plus Link, die Liste bleibt in der Instruction; die
Katalog-Liste in Schritt 2 undstack-close/SKILL.mdSchritt 3 nennen die neue Instruction bzw.
die Contracts jetzt ebenfalls.version-parts.mdundtesting-conventions.mdkorrigieren dabei
zwei schon vorher falsche Schrittverweise aufstack-dev(Schritt 3 -> 4, Schritt 4 -> 6),
gefunden beim Nachziehen der Umnummerierung.MINOR, kein neuer Boundary-Crossing: additiv und drop-in in beide Richtungen - eine
bestehende Instanz kopiert die neue Instruction und die korrigierte Prosa über sich, ohne
Migration oder Hand-Arbeit; kein Feld, kein Kommando, kein Flag ändert sich. Der Kandidat trägt
seine--breaking-Zeile bereits aus einem früheren Bump; diese Änderung fügt keine neue hinzu.Geändert:
AGENTS.md,tools/chemenu/commands/docs_verify.py,
instructions/dev/doc-pull-through.md(neu),instructions/dev/stack-dev/SKILL.md,
instructions/dev/stack-close/SKILL.md,instructions/dev/version-parts.md,
instructions/dev/testing-conventions.md. Verifiziert:tools/wikitool docs verify,
tools/wikitool instructions verify(nachinstructions sync), vollepytest-Suite (1185
passed). Schließt #90.docs verifyprüfte § Commands und § Error contracts intools/CONTRACT.mdals einen Topf
(#91).TABLE_CELL_REsammelte das erste gebacktickte Wort jeder Tabellenzeile über das ganze
Dokument, ohne Abschnittsgrenze - eine aus § Commands gelöschte Zeile fiel nicht auf, solange
derselbe Name noch in § Error contracts stand, und § Error contracts wurde gegen nichts
erzwungen. Gemessen am Baum vor diesem Fix (55 registrierte Kommandos): § Commands war
vollständig, § Error contracts fehlten zehn Zeilen -budget reset,instructions list,
instructions verify,log append,migrate status,sources rebuild-index,sources trace,
types describe,upload show,version notes- unddocs verifyblieb grün.check_cli_readme()liest die beiden Tabellen jetzt über ihre##-Überschrift ab (neue
section_text()), unabhängig voneinander und je Tabelle in beide Richtungen; fehlt eine der
beiden Überschriften, meldet die Funktion das explizit statt stillschweigend auf "ganzes
Dokument" zurückzufallen. Ursache der zehn Lücken war überwiegend eine zweite, bisher unsichtbare
Untugend: mehrere Kommandos teilten sich in § Error contracts eine Zeile der Form "a/b" -
nur das erste Backtick-Wort einer Zeile zählte je als "dokumentiert", der Rest der Gruppe war für
den (ungeprüften) Check unsichtbar. Behoben, indem jede betroffene Gruppe in eigene Zeilen mit
eigenem, gegen den Code nachgesehenem Inhalt aufgeteilt wurde - dabei fielen nebenbei drei
sachlich falsche Zeilen auf:sources coverage,types list,instructions listundbudget statusschlagen nie fehl, die alte gemeinsame Zeile behauptete das Gegenteil, weil sie das
Verhalten des jeweils benachbarten Kommandos mit übernahm. Eine echte Formatierungslücke kam
dazu:log appends Zeile stand im Quelltext ohne Zeilenumbruch hinter der vonindex rebuild/
sources rebuild-indexverschmolzen - für Menschen als Tabelle kaum lesbar und für die
zeilenanfang-verankerte Regex unsichtbar.MINOR, kein neues Boundary-Crossing: additiv und in beide Richtungen drop-in - eine
bestehende Instanz kopiertdocs_verify.pyundtools/CONTRACT.mdüber sich, ohne Hand-Arbeit
oder Migration. Eine Ausnahme ist es wert, genannt zu werden: eine private Instanz mit einem
lokal abweichendentools/CONTRACT.md(instructions/private-instance.md) kann nach diesem
Update zum ersten Mal an der strengeren Prüfung scheitern, wenn ihr eigener Baum dieselbe
Fehlerkontrakt-Lücke trägt oder ihre Kommandotabelle anders benannte##-Überschriften
verwendet. Das ist kein Boundary-Crossing - kein Dateiformat ändert sich, keine bestehende
Funktion verschwindet -, sondern derselbe bereits akzeptierte Fall, den jede Verschärfung von
docs verifyseit jeher mit sich bringt: der Fix legt eine bereits vorhandene
Dokumentationslücke bloß, statt eine neue Anforderung einzuführen. Der Kandidat trägt seine
--breaking-Zeile bereits aus einem früheren Bump; diese Änderung fügt keine neue hinzu.Geändert:
tools/chemenu/commands/docs_verify.py(section_text,check_cli_readme),
tools/CONTRACT.md(diedocs verify-Zeile sowie zehn aufgeteilte bzw. nachgetragene
Fehlerkontrakt-Zeilen),tools/chemenu/tests/test_docs_verify.py(neue Tests für
Abschnittstrennung, fehlende/umbenannte Überschrift, § Error contracts in beiden Richtungen).
Verifiziert:tools/wikitool docs verify,tools/wikitool instructions verify, volle
pytest-Suite (1193 passed). Schließt #91.tools/CONTRACT.mdist jetzt ein Dokument zum Nachschlagen statt zum Durchlesen (#92).
Mit 70 KB war es das größte Dokument im Repo - größer alsAGENTS.md,kb/CONTRACT.mdund
raw/CONTRACT.mdzusammen -, und 89 % davon lagen in den zwei Kommandotabellen. Gleichzeitig
war es für gezielten Abruf bereits ideal gebaut, ohne dass es irgendwo stand: eine Zeile ist
ein Kommando, physisch einzeilig, also liefert ein einzigesgrep '^| `<kommando>'beide
Hälften seines Vertrags - was es tut und wie es fehlschlägt - und sonst nichts.AGENTS.md
routete stattdessen mit "Full command reference" dorthin, was sich als Vollread liest.Drei Änderungen: die Datei trägt die Nachschlage-Regel samt
grep-Zeile jetzt als Lead-in vor
dem Inhaltsverzeichnis (genau einmal, Invariante 8 -AGENTS.mds Routing-Zelle beschreibt nur
noch die Form und wiederholt die Zeile nicht); beide Tabellen sind in vierzehn###-Gruppen
gegliedert, wodurchdocs tocerstmals Anker unterhalb##erzeugt (vorher existierte im
ganzen Repo genau ein Anker-Link in diese Datei); und § Error contracts steht nun in derselben
Gruppen- und Zeilenreihenfolge wie § Commands, sodass die zwei Hälften eines Vertrags parallel
liegen - vorher saß etwalinks showeinmal zwischenxref link-sourceundcite id, einmal
zwischenversion releaseundmigrate list. Nebenbei repariert: diedist export-Zeile war
über vier physische Zeilen umgebrochen und damit kein gültiger GFM-Tabellen-Datensatz mehr.Die Umstellung lief per Skript mit einer Behauptung über die Multimenge der Erst-Zellen vor und
nach dem Schreiben, nicht per Augenschein - bei 117 Zeilen ist "keine verloren" nichts, was ein
Review zusieht. Dass###die Abschnittsgrenze aus #91 nicht bricht, ist jetzt ein eigener
Test:section_texts Lookahead(?=^#{1,2}[ \t]|\Z)verlangt nach ein bis zwei#ein
Space/Tab, was bei###fehlschlägt - ohne diese Eigenschaft wäre § Commands an seiner ersten
Gruppe abgeschnitten und jedes spätere Kommando als undokumentiert gemeldet worden.Bewusst nicht angefasst: die siebzehn Tabellenzellen über 900 Zeichen. Der naheliegende Schritt
wäre, ihren Begründungsanteil nachdocs/zu schieben; die Gegenprobe an der größten Zelle
(publish, 3.375 Zeichen) zeigt, dass die Kandidaten dafür - warum ein Token Dateiliste und
Inhalte digestiert, warum die Publish-Remote-Gate kein Flag hat - für eine handelnde Session
normativ verwertbar sind und nicht Hintergrund. Sie wegzukürzen hätte die Zelle verkleinert und
die Handlungsfähigkeit gesenkt. Die Zellen sind lang, weil die Verträge dicht sind.PATCH, kein neues Boundary-Crossing: reine Dokumentstruktur, kein Format, keine Funktion, keine
Hand-Arbeit bei Update oder Downgrade. Eine private Instanz mit eigenemtools/CONTRACT.md
bekommt beim Merge Konflikte in den beiden Tabellen, weil deren Zeilen umsortiert wurden - das
ist ein Merge-Konflikt in einer stack-eigenen Datei, denupstream mergeohnehin zugunsten der
Upstream-Seite auflöst, kein Kompatibilitätsbruch.Geändert:
tools/CONTRACT.md(Lead-in,###-Gruppen in beiden Tabellen, gespiegelte
Reihenfolge, TOC viadocs toc --apply),AGENTS.md(Routing-Zelle fürtools/),
tools/chemenu/tests/test_docs_verify.py(zwei Tests: Abschnitt läuft über eigene
Unterüberschriften hinweg, gruppierte Tabellen bleiben in beiden Richtungen geprüft).
Verifiziert:tools/wikitool docs verify,tools/wikitool instructions verify, volle
pytest-Suite (1195 passed). Typischer Zugriff: Median 229 statt 17.500 Tokens.
Schließt #92.incoming/.gitkeepist jetzt trackbar - Datei- statt Verzeichnismuster in.gitignore(#88).
/incoming/schloss bisher das Verzeichnis selbst aus, und Regel 2 im.gitignore-Kopf sagt
genau, warum das eine Falle ist: git kann keine Datei wieder einschließen, deren Elternverzeichnis
ausgeschlossen ist, also blieb ein!incoming/.gitkeepwirkungslos. Ein frischer Klon hatte den
Eingang deshalb nie -instructions/bootstrap.mdSchritt 2 (mkdir -p incoming) fing das für
einen Menschen ab, der die Instruction liest, aber nicht für einen Checkout, den eine Maschine
anlegt: der Korpus-Checkout des MCP-Read-Servers entsteht aus Klon plusfetch && reset --hard
und läuft durch keinen Bootstrap, also fehlte der Eingang dort still, bis das erste Kommando ihn
brauchte.Umgestellt auf
/incoming/*plus!/incoming/.gitkeep- jetzt ignoriert das Muster den Inhalt,
nicht das Verzeichnis, und die Negation greift tatsächlich. Gegengeprüft in beide Richtungen:
git check-ignore --no-index incoming/.gitkeepmeldet die Datei als nicht ignoriert,
incoming/probe.pdfweiterhin als ignoriert - die Kanarie aus
docs_verify.REQUIRED_IGNORE_CANARIEShält also unverändert.incoming/.gitkeepsteht jetzt
zusätzlich inREQUIRED_TRACKED_PATHS, damit eine künftige Rückkehr zur Verzeichnisform
docs verifylaut fehlschlagen lässt statt still zu wirken. Ein vollerdist export+
git init+git add -A-Replay bestätigt, dassincoming/.gitkeepim allerersten Commit einer
frischen Instanz landet, währendincoming/probe.pdfdort weiterhin ignoriert bleibt.instructions/bootstrap.mdSchritt 2 entfällt ersatzlos - ein frischer Klon braucht ihn nicht
mehr -, die übrigen Schritte rücken nach.mcp-upload/bleibt bewusst bei der Verzeichnisform
ohne.gitkeep: die Schreibprimitive dessubmit-Tools legt das Verzeichnis selbst an, sobald
sie gebraucht wird, und ein Checkout, der das Tool nie aktiviert, braucht das Verzeichnis auch
nie - anders als beiincoming/gibt es dort keinen Frisch-Klon-Fall abzudecken. Der
.gitignore-Kommentar zumcp-upload/benennt diesen Kontrast jetzt ausdrücklich, statt sich
nur noch mit dem alten (identischen) Verhalten vonincoming/zu vergleichen.Geändert:
.gitignore(beide Kommentarblöcke, neues Muster),incoming/.gitkeep(neu),
tools/chemenu/commands/docs_verify.py(REQUIRED_TRACKED_PATHS),instructions/bootstrap.md
(Schritt 2 entfernt, Rest umnummeriert),raw/CONTRACT.md,tools/CONTRACT.md(dist export-
Zeile),README.md(Architekturdiagramm-Kommentar). Verifiziert:tools/wikitool docs verify,
tools/wikitool instructions verify, vollepytest-Suite (1195 passed), manueller
dist export-Replay. Schließt #88.dist export-Doku nennt keine Typverzeichnisse mehr, die seit #67 nicht mehr angelegt werden
(#93).tools/CONTRACT.mdsdist export-Zeile und der--help-Docstring des Kommandos
selbst behaupteten wortgleich, ein frischer Export lege leere
raw/{articles,documents,notes,assets}/und die passendenincoming/-Typverzeichnisse an. #67
hat die Typverzeichnisse aus dem Adressierungsschema vonraw acceptentfernt (Datums-Shard
statt Typverzeichnis) und dabei den Export-Pfad auf zwei flache Anker verkürzt
(raw/.gitkeep,incoming/.gitkeep-run_export), ohne die zwei Prosa-Stellen nachzuziehen,
die noch die alte Struktur beschrieben. Nebenbefund aus der Sitzung zu #88.Beide Stellen beschreiben jetzt den tatsächlichen flachen Export. Gegengeprüft per
tools/wikitool dist exportin ein leeres Scratch-Verzeichnis:raw/enthält nach dem Export
nur.gitkeep(plus die verzeichniseigeneCONTRACT.md),incoming/nur.gitkeep- keine
Typunterverzeichnisse unter keinem der beiden Wurzeln.Außerhalb der Akzeptanzkriterien dieses Issues, aber derselbe Fund: dieselbe Prosa-Drift bei
raw/*/.gitkeepin derdist upgrade-Zeile (tools/CONTRACT.md), in
docs/ownership-and-templates.mdund imapply_upgrade-Docstring - andere Fundstelle, gleiche
Ursache. In derselben Sitzung gleich mitkorrigiert, siehe die nächste Eintragszeile unten.Geändert:
tools/CONTRACT.md(dist export-Zeile),tools/chemenu/commands/dist_cmd.py
(--help-Docstring vonexport). Verifiziert:tools/wikitool docs verify,
tools/wikitool instructions verify, vollepytest-Suite, manuellerdist export-Replay in
ein leeres Scratch-Verzeichnis. Schließt #93.raw/*/.gitkeep-Glob war seit #67 ebenfalls stale - korrigiert auf den flachen
raw/.gitkeep-Anker. Nebenbefund beim Nachziehen von #93 in derselben Sitzung: dieselbe
Typverzeichnis-Drift steckte noch an drei weiteren Stellen, die von einem mehrfachen
raw/<typ>/.gitkeepsprachen, obwohlraw/seit #67 flach ist und es nur noch den einen
raw/.gitkeep-Anker gibt -chemenu.ownership.is_export_stub/is_upgrade_preservedmatchen
ohnehin per Dateiname statt Pfadtiefe, das Verhalten war also nie falsch, nur die illustrative
Glob-Schreibweise in der Prosa. Betroffen:tools/CONTRACT.mdsdist upgrade-Zeile,
docs/ownership-and-templates.mds Aufzählung der seeded-once-Dateien, und der
apply_upgrade-Docstring indist_cmd.py.Geändert:
tools/CONTRACT.md(dist upgrade-Zeile),docs/ownership-and-templates.md,
tools/chemenu/commands/dist_cmd.py(--help-Docstring vondist upgrade). Verifiziert:
tools/wikitool docs verify,tools/wikitool instructions verify, vollepytest-Suite.Ingests haben jetzt zwei Größenachsen: Volumen und Breite (#61).
ingest-large-treelöste
bislang ausschließlich auf Volumen aus - mehr als ~20 Rohdateien, mehr als ~15raw_files:-
Einträge -, und sein § Scope sagte das auch so: „This is about volume, not difficulty."
Dazwischen lag eine Lücke: die einzelne, thematisch breite Quelle. Sie löst keinen
Volumen-Trigger aus,wiki-ingestkannte keinen anderen, und was sie anrichtet, meldet kein
lint-Befund.Der Korpus zeigt den Fall genau einmal, dafür deutlich.
Source - LLM Wiki v2: eine Rohdatei,
4 Entities + 26 Concepts, gegen einen Median von 6 über alle 29 Source-Seiten. Der naheliegende
Verdacht - die Source-Seite werde vage - trägt nicht: alle 26 Concepts haben eine eigene Seite,
die Breite wurde vollständig nachgezogen. Der Schaden sitzt eine Ebene tiefer und ist bimodal:
14 der 30 Subjektseiten liegen unter 150 Wörtern (die dünnsten bei 71 bis 78), die übrigen bei
541 bis 1.294, gegen einen Korpus-Median von 485. Eine Stub-Kohorte aus einem einzigen
Durchgang. Keine andere Quelle im Korpus hat eine: bei 18 Gegenständen (Source - LLM Wiki Pattern) sind es null, und darunter ebenfalls. Daher die Schwelle bei ~20 statt am
75.-Perzentil - ein Auslöser, der auf schadensfreien Seiten feuert, wird ignoriert.Breite wird nicht geschnitten, und das ist der Teil, der eine eigene Sektion bekommt. Zwei
Regeln schließen den Weg:raw/hält eine Datei „exactly as received", und eine Rohdatei hat
genau einen Besitzer (lintmeldet einen zweiten Anspruchsteller). Mehrere thematische
Source-Seiten über einer Datei wären also nicht bloß unüblich, sondern ließen bei einer neuen
Edition niemanden zuständig zurück. Der Schnitt vorraw acceptbleibt davon unberührt - er
ist das, wascapture-session§ 1 tut, und er ist nur möglich, weil das Transkript dort noch
gar nicht existiert. Diese Abgrenzung steht jetzt in § 1 selbst, weil genau dort der
Fehlschluss ansetzt, ein empfangenes Dokument ließe sich genauso zerlegen.Was die Breite stattdessen auslöst, ist der Extract-Pass vor dem Schreiben und die Regel, die
er beliefert: ein Gegenstand bekommt eine Seite, wenn die Quelle Material für eine trägt.
Eine beiläufige Erwähnung bekommt einen Wikilink von der Source-Seite und eine Zeile unter
## Not Extracted, keine eigene Seite. Eine Seite, die nur ihren eigenen Titel wiederholt, ist
schlechter als die Erwähnung, aus der sie entstand:lintmisst Struktur und nie Substanz, also
meldet sie niemand, und die nächste Sitzung liest sie als abgedecktes Terrain und schaut nicht
mehr in die Quelle.Der vendorierte
commonplace-Korpus stützt den Verzicht auf einen Source-Split unabhängig vom
Befund aus dem Baum, was ihn zum belastbareren Teil der Begründung macht: Atomizität ist dort
ausschließlich mit Co-Loading für Entdeckung begründet und gilt damit der Library-Schicht
(kb/entities/,kb/concepts/), nicht der Evidenz-Schicht; ein Mehr-Aussagen-Dokument ist per
title-as-claimReferenz statt Prämisse, weshalb Breite seiner Rolle nicht schadet; und die
Forderung, Forward-Lineage müsse den Betreiber unterbrechen, erreicht „eine Rohdatei, ein
Besitzer" auf eigenem Weg.Nicht gebaut: ein
lint-Befund gegen die Stub-Kohorte. Er wäre die Beobachtungsseite derselben
Sache, braucht aber eine eigene Schwellenwertdiskussion - Wortzahl ist ein grober Proxy für
Substanz - und liegt als eigenes Issue auf dem Board. Die Schwelle ~20 ruht auf einem einzigen
Schadenspunkt und ist entsprechend vorläufig.MINOR, kein neues Boundary-Crossing: additiv in beide Richtungen. Eine bestehende Instanz
bekommt einen zusätzlichen Auslöser und eine zusätzliche Regel in Dateien, die der Stack
besitzt; nichts ankb/, keinem Schema, keinem Kommando und keinem Flag ändert sich, und ein
Downgrade nimmt beides ersatzlos zurück. Der Kandidat steht ohnehin auf MAJOR, der Bump
erhöht also nur seinen Zähler.Geändert:
instructions/ingest-large-tree.md(§ When to run auf zwei Achsen, Tier-Tabelle,
neue § A broad source is not cut, § Scope, ein Decision Point,description),
instructions/wiki-ingest/SKILL.md(Schritt 2 verweist jetzt auf die Schwellenliste statt sie
zu wiederholen, Schritt 7 trägt die Seiten-Regel, Schritt 8 und ein Decision Point ziehen nach),
instructions/capture-session.md(§ 1 Abgrenzung),types/source.md(## Not Extractedist
jetzt auf beiden Achsen Pflicht;entities:+concepts:jenseits von ~20 als Gegenstück zum
bestehendenraw_files:-Signal). Verifiziert:tools/wikitool docs verify,
tools/wikitool instructions verify, vollepytest-Suite (1195 passed),docs toc --applyund
instructions syncfür die generierten Regionen und die veröffentlichten Kopien.
Schließt #61.stack-closeSchritt 3 sagt jetzt, dass ein Doku-Nachzug seinen eigenen Bump braucht.
Direkt aus dem vorigen Paket gelernt: dessen Abschlussphase zogtypes/source.mdnach, ohne
VERSIONzu bewegen, und CI-Run 249 fiel an der Version Gate um. Die Sitzung las den Nachzug
als Dokumentation -types/source.mdist aber beides, Dokument und ausgelieferte
Verhaltensbeschreibung, und die Gate ist nach Pfad gefasst, nicht nach Absicht
(^(tools/|types/|instructions/|AGENTS\.md$|[^/]+/CONTRACT\.md$)).Das ist kein Ausrutscher, sondern eine Reihenfolge, die sich wiederholt:
stack-devSchritt 4
bumpt die eigentliche Änderung, und Schritt 3 dieses Skills läuft danach - in genau den
Pfaden, die die Gate bewacht. Schritt 3 trägt den Satz deshalb jetzt selbst, samt der Falle
("nur Dokumentation") und des Auswegs (version bump --patchim selben Zug, was beim laufenden
Kandidaten ohnehin nur den Zähler bewegt). Nicht nachdoc-pull-through.mdgelegt, obwohl es
dort thematisch auch passte: die Entscheidung fällt in dem Schritt, der den Commit auslöst, und
zwei Kopien wären die Dopplung, die Invariante 8 verbietet.Geändert:
instructions/dev/stack-close/SKILL.md(Schritt 3). Verifiziert:
tools/wikitool docs verify,tools/wikitool instructions verify, vollepytest-Suite,
instructions syncfür die veröffentlichte Kopie. Kein Issue - direkt korrigiert.
This note is a snapshot of the
CHANGES.mdentry as it stood when the tag was cut, and
is never edited afterwards. The maintained version of this text - including any later
correction - is the entry for this version inCHANGES.mdin the repository.Downloads
-
v4.7.4 Stable
released this
2026-09-04 18:51:38 +00:00 | 182 commits to main since this release4.7.4 - 2026-09-04 - bootstrap.md nennt den session-id-WARN nach frischem Bootstrap explizit als erwartet
Author: Torben Nehmer
- bootstrap.md nennt den session-id-WARN nach frischem Bootstrap explizit als erwartet
Nach einem frischen Clone plus
instructions/bootstrap.mdzeigtetools/wikitool doctor
durchgehendOK, außersession-id: WARN- ohne Einordnung, ob das ein Bootstrap-Defekt ist.
WIKITOOL_SESSION_IDwird lautinstructions/session-setup.mdbewusst pro Arbeitssitzung
gesetzt, nicht pro Clone; ein Export inbootstrap.mdselbst würde nur für den Bootstrap-Lauf
gelten, nicht für die tatsächliche Arbeitssitzung danach (die nach dem Neustart in Schritt 6 in
einer neuen Shell beginnt).bootstrap.mdbekommt deshalb einen neuen Schritt 7, der den WARN
als erwarteten Zustand benennt - analog zum bereits dokumentiertenpersonalization: FAILin
Schritt 4 - und aufsession-setup.mdverweist, statt den Export in Bootstrap nachzubauen.
Schließt #54.
This note is a snapshot of the
CHANGES.mdentry as it stood when the tag was cut, and
is never edited afterwards. The maintained version of this text - including any later
correction - is the entry for this version inCHANGES.mdin the repository.Downloads
-
v4.7.3 Stable
released this
2026-09-04 18:31:10 +00:00 | 183 commits to main since this release4.7.3 - 2026-09-04 - eval: gate-not-self-opened prueft REMOVED_FLAGS gegen das eigene Kommando
Author: Torben Nehmer
Die Trajektorien-Regel
gate-not-self-opened(tools/chemenu/evals/trajectory.py) hat jedes
Argument jedeswikitool.callgegenREMOVED_FLAGS = {"--yes": "publish", "-y": "publish"}
geprüft, ohne je das eigenecommand-Feld des Aufrufs gegenzulesen.--yes/-ysind nur auf
publishentfernt worden - aufrm --page <Titel> --yessind sie ein gültiger, dokumentierter
Flag. Ergebnis: jederrm --yes-Aufruf wurde als Invarianten-Verstoß gemeldet ("an agent
inventing a flag the tool never accepts"), obwohl das Tool ihn akzeptiert hatte.In den vorhandenen Telemetrie-Traces unter
reports/telemetry/betraf das 111rm-Aufrufe
über 8 Sessions, davon 27 allein inpublish-cleanup/u3- jede davon fälschlichFAILED
gescort. Kein bestehender Test hätte das gefangen:tools/chemenu/tests/test_evals.pyprüfte
REMOVED_FLAGSausschließlich überpublish --yes, nie über ein anderes Kommando.Fix: die Bedingung liest jetzt
attrs.get("command") == REMOVED_FLAGS[arg]mit. Neuer
Regressionstesttest_yes_on_a_command_that_still_has_it_is_not_a_findingdeckt genau den
rm --yes-Fall ab und schlägt gegen den unfixed Code nachweislich fehl.Keine Verhaltensänderung an
wikitoolselbst - ausschließlich an der Scoring-Logik unter
tools/chemenu/evals/.- eval: gate-not-self-opened prueft REMOVED_FLAGS gegen das eigene Kommando
This note is a snapshot of the
CHANGES.mdentry as it stood when the tag was cut, and
is never edited afterwards. The maintained version of this text - including any later
correction - is the entry for this version inCHANGES.mdin the repository.Downloads