-
v4.1.0 Stable
released this
2026-09-03 04:22:53 +00:00 | 80 commits to main since this release4.1.0 - 2026-09-03 - Link-Taxonomie: Lint-Findings hart ab kb_version 4.0.0, outbound: an das Type-Spec gebunden, part-of/composition als Inversenpaar
Author: Torben Nehmer
Der Rest von Issue #40, nachdem die Korpus-Migration durch ist: die beiden aufgeschobenen
Lint-Findings werden hart, und die drei Befunde aus dem Abschlusskommentar des Migrationslaufs
werden aufgelöst.unlabelled_edgesundunauthorised_labelssind harte Fehler — aber ankb_version
gebunden, nicht an ein Datum. Der Weg, denlegacy_citation_markersgenommen hat, war ein
Umlegen in einer späteren Version: eine Instanz, die die Zitat-Migration noch schuldete, lebte
danach mit rotem Lint. Das Ledger kann die Frage inzwischen beantworten, also tut es das.
Unterhalbkb_version4.0.0 bleiben beide beratend — genau das Fenster, in dem
instructions/migrations/4.0.0-link-taxonomy.mdder Instanz sagt, sie solle den halb
konvertierten Korpus Einheit für Einheit publizieren; ein Check, der dabei fehlschlägt, würde
den Korpus verweigern, dessen Fortschritt er misst. Ab 4.0.0 ist eine kahle Titelangabe in
related:keine Seite mehr, die auf ihre Umstellung wartet, sondern eine Kante, deren Autor
nicht gesagt hat, was sie behauptet.hard_error_keys()liefert die jeweils geltende Menge,
HARD_ERROR_KEYSbleibt die vollständige.outbound:ist an das Type-Spec gebunden.kb/sources/undkb/comparisons/
autorisierten Label, die dort strukturell nicht schreibbar waren: keiner der beiden Type-Specs
führte einrelated:. Folgenlos war das nicht — die einzige Comparison-Seite des Korpus trug
- **compares-with:** [[amd-pstate]]als handgeschriebene Prosa, ohne Marker-Region, ohne
Frontmatter, fürlintunsichtbar. Also ein Identifier zurück im Fließtext, gut vier Stunden
nachdem 4.0.0 genau das beendet hatte. Eine leere Autorisierung liest sich als Lizenz.Aufgelöst nach dem, was die beiden Contracts jeweils selbst sagen:
comparisonbekommt ein
related:(diecompares-with-Kante gegen jedes Subjekt ist die eine Aussage, für die die
Seite existiert),kb/sources/verliert seinenoutbound:-Block ersatzlos (dessen Contract
sagt ausdrücklich, seine Verknüpfungen seien der mechanische Provenance-Pfad und keine
Autorenkanten). Neu prüftdocs verifydie Kombination: einoutbound:-Block auf einer
Collection, in die kein Typ mitrelated:schreibt, ist ein Befund und nennt beide Richtungen
der Reparatur.composition/part-ofist das dritte Inversenpaar, nebendepends-on/required-by
undruns-on/hosts. Aus der Messung, nicht vom Schreibtisch: der u3-Lauf hatte entschieden,
die Gegenseite einescompositionbekommesee-also, weilpart-ofein Spiegel wäre. Ist es
nicht — der Satz des Elternteils zählt seine Teile auf, der des Kindes benennt das Ganze, zu
dem es gehört, und ein Leser, der auf dem Kind landet, braucht den zweiten. Übrig blieben 16
see-also-Kanten für eine Beziehung, für die der Katalog ein Wort hat; sie sind aufpart-of
umgestellt. Ein Inversenpaar macht die Gegenkante weiterhin nicht zur Pflicht — Richtung
wird verfasst, nicht gespiegelt —, es legt nur fest, welches Label sie trägt, wenn jemand sie
schreibt.Stack- und Korpusänderung laufen hier in einem Zug, entgegen der sonstigen Trennung. Der
neuedocs verify-Check würde eine bestehende 4.0.x-Instanz beim bloßen Kopieren der neuen
Maschinerie fehlschlagen lassen, weil derenkb/sources/COLLECTION.mddenoutbound:-Block
noch trägt — nach instructions/dev/version-parts.md
Schritt 1 ein Grenzübertritt. Statt dafür eine5.0.0zu lösen, ist die Ursache mitbeseitigt:
die Collection-Contracts dieser Instanz sind angepasst, unddist exportleitet die
COLLECTION.md.templatedaraus ab, also liefert jede neue Distribution die korrigierte Form
aus. Für eine bereits bestehende 4.0.x-Instanz bleibt eine Handbewegung übrig, und sie wird
hier benannt statt versteckt: die zweioutbound:-Zeilen auskb/sources/COLLECTION.md
löschen. Das neuerelated:imcomparison-Type-Spec erreicht sie ohnehin nicht — die vier
Page-Type-Specs gehören seit 4.0.0 der Instanz und werden nur als.templateausgeliefert.Offen aus #40 bleibt nichts mehr; Befund 2 des Migrationslaufs (dem Katalog fehlt ein Register
für Urheberschaft) ist als eigenes Issue erfasst.Downloads
-
v4.0.1 Stable
released this
2026-09-02 21:14:49 +00:00 | 82 commits to main since this release4.0.1 - 2026-09-02 - Issue-Board: vier Pflicht-Label-Familien und Body-als-Wahrheit
Author: Torben Nehmer
Das Issue-Schema aus 1.2.1 hatte zwei Pflichtachsen und einen ausdrücklich begründeten Verzicht
auf eine dritte: eine Taxonomie mit mehr Achsen brauche eigene Pflege, und das Board habe einen
einzigen Betreuer. Diese Begründung ist entfallen, weil die Pflege inzwischen maschinell
passiert - Body-Rewrites und Kommentare laufen über eine LLM-Sitzung, Menschen fassen in der
Regel nur Labels an. Damit sind vier Achsen bezahlbar (Issue #41).Pflicht auf jedem offenen Issue sind jetzt vier Label:
area/(kb,distribution,
corpus,workflow,process- keinarea/tools, Tooling wird nach der bedienten Domäne
einsortiert, nicht nach Codeort),kind/(decision,build,defect),prio/
(blocking,planned,waiting- reine Umbenennung von1/2/3) undsize/(S,M,
L;XSentfällt). Dazu zwei optionale Flags:status/blockedfür Abhängigkeit von einem
anderen offenen Issue,status/unconfirmedfür einen ungeprüften Verdacht, unter demsize
undpriovorläufig sind. Einunconfirmed-Issue endet in der Triage entweder ohne Flag und
mit verbindlichen Werten oder geschlossen mit Begründung - die Prozessentsprechung zu
Invariante 3.Der Issue-Body ist ab jetzt aktuelle Wahrheit, nicht Ursprungstext. Die Umsetzung eines
Issues zieht sich über mehrere, zeitlich getrennte Sitzungen, und der Body ist das einzige, was
sie verbindet: eine Sitzung muss aus ihm allein rekonstruieren können, was entschieden und was
offen ist. Er wird deshalb umgeschrieben statt ergänzt. Jeder Rewrite bekommt einen Kommentar,
der ausschließlich benennt, was sich geändert hat - keine Vollkopie des alten Stands, weil ein
Mensch zwei Fließtexte nicht diffen kann und eine Kopie pro Revision damit keine Historie ist,
sondern nur eine weitere Kopie.Geändert: instructions/dev/issue-tracking.md (Schritte 2,
3, 5 neu; Schritt 4 umarea/undkind/erweitert; der Entscheidungspunkt „Two labels feel
too coarse?" entfällt) und die Beschreibungszeile ininstructions/dev/stack-dev/SKILL.md. Für
eine ausgelieferte Instanz ändert sich nichts:dist exportschließtinstructions/dev/
vollständig aus, weshalb dies ein PATCH ist und kein MINOR - dieselbe Begründung wie bei
1.2.1. Noch offen aus #41:kb/concepts/Issue Label Scheme.mdbeschreibt weiterhin das
zweiachsige Schema und braucht eine eigenewiki-manage-Sitzung.Downloads
-
v4.0.0 Stable
released this
2026-09-02 16:42:22 +00:00 | 90 commits to main since this release4.0.0 - 2026-09-02 - Prosa ist kein Identifier: Link-Taxonomie als Enum, generierte Regionen mit Markern
Author: Torben Nehmer
Breaking Change: Beziehungslabel sind Enum-Werte in related: statt Freitext im Body-Bullet, toolgefuehrte Abschnitte liegen zwischen Marker-Paaren statt hinter ihrer Ueberschrift, und xref add schreibt nur noch eine Kante statt beider Richtungen. tools/chemenu/sections.py ist geloescht. Eine bestehende Instanz muss sections: in kb/CONVENTIONS.md auf links/footnotes umstellen, outbound: in jede COLLECTION.md eintragen, die {section.*}-Variablen aus ihren Page-Type-Templates entfernen und den Korpus umstellen - sonst scaffoldet new die Variablen woertlich in neue Seiten. Ablauf: instructions/migrations/4.0.0-link-taxonomy.md
Der Stack benutzte an drei Stellen Prosa als Identifier, und jede hat messbar etwas
gekostet. Die Überschrift eines Abschnitts war seine Adresse (^## Beziehungen$), was die
KB-Sprache zu einer Compiler-Konstante machte und das Ende der Region zur Schätzung - sie lief
bis zur nächsten Überschrift, davor bis zum Dateiende, und hat auf acht Seiten still Inhalt
gelöscht. Das Beziehungslabel stand nur im Body-Bullet, also konnte nichts das Vokabular prüfen:
gemessen am Korpus 152 distinkte Label in 337 Bullets gegen dreizehn dokumentierte, 102 davon
genau einmal vorkommend. Undxref addspiegelte jede Kante, was## Siehe auchmit 555
Bullets ohne Label füllte - 353 davon beweisbar redundant.Was jetzt Identifier ist. Eine Region liegt zwischen
<!-- wikitool:links -->bzw.
<!-- wikitool:footnotes -->und wird vollständig aus dem Frontmatter gerendert, Überschrift
eingeschlossen. Ein Label ist ein Maschinenwert inrelated:(- depends-on: Hermes), gezogen
ausinstructions/link-taxonomy.mdund pro Ziel autorisiert von der Quell-Collection
(outbound:imCOLLECTION.md, Commonplaces ADR-019). Der Body-Bullet ist eine Darstellung
dieser Daten, nicht ihr zweiter Aufbewahrungsort.Gelöscht, ersatzlos:
tools/chemenu/sections.pykomplett,heading_re, der
Alias-Mechanismus,PRE_CONVENTIONS_NAMES,cite_block_heading,provenance.__getattr__, die
{section.*}-Template-Variablen,xrefs Abschnittssuche. Kein Überschriftentext liegt mehr in
Python - bis auf zwei kosmetische Fallbacks, und die sind harmlos geworden: der Marker trägt die
Identität, also rendert ein falscher Default falsche Wörter statt Struktur zu zerlegen, und der
nächste Write repariert es.Kanten sind direktional, und das war keine Geschmacksfrage. Die per-Collection-Autorisierung
ist mit einer automatisch gespiegelten Gegenkante logisch unverträglich: die Spiegelhälfte
entsteht in einer Collection, deren Regeln der Autor nie gelesen hat. Entweder schriebe das
Werkzeug unautorisierte Kanten, oder die Regel "die Quellcollection entscheidet" löst sich auf.
Der Navigationseinwand wird dabei besser beantwortet als vorher:wikitool links show --page
berechnet die Eingangssicht über den Korpus, vollständig und ohne Pflege, und das gerenderte
Bullet ist ein gewöhnlicher[[wikilink]]- ein Backlink-Panel zeigt es ohnehin. Die erzwungene
Gegenkante garantierte nie Vollständigkeit, nur dass jemand daran gedacht hat.Der Orphan-Check meldet dadurch mehr, und das ist die Prüfung bei der Arbeit: sie misst jetzt
Erreichbarkeit statt "istxrefgelaufen".obligation:trennt zwei Achsen, die vorher eine waren.migration_kind:sagt wie
gearbeitet wird, neuobligation: required|offeredob überhaupt. Eineoffered-Migration ist
ein Angebot für eine Datei, die der Instanz gehört - sie blockiert nie, steht nicht in der Kette,
undmigrate doneverbucht sie im Ledger, ohnekb_versionzu bewegen. Genau daran hing ein
Entwurfsfehler, den erst der Test gezeigt hat: Offers gegenkb_versionzu filtern hätte jede
Offer verschwinden lassen, sobald irgendein unbeteiligter Pflichtschritt lief. Dazu ist die
Erkennungshälfte aktiviert, die seit ihrer Einführung ungelesen dalag - die sha256 pro Datei in
.wikitool-release.jsonbeantwortet jetzt "editiert oder nur empfangen", also ob eine Offer
kopiert werden darf oder von Hand abgeglichen werden muss.types/teilt sich entlangroot:.root: kbheißt Wissensseite heißt Instanz: die vier
Page-Type-Specs samt Schemas gehen als.template,instruction/lint-report/type-spec
verbatim. Damit ist die deutsche Prosa in jenen vier Dateien korrekt statt Migrationsschuld -
es war die richtige Sprache an einem Ort mit falsch deklariertem Eigentümer. Was der Stack von
der Type-Schicht noch verlangt, ist eine Zeile: ein Type-Specname: source, dessen Schema
raw_filesfordert.STACK_REQUIRED_COLLECTIONSentfällt als separate Liste - die pflichtige
Collection wird aus dembase_dirdieses Typs abgeleitet.Warum das MAJOR ist. Vorwärts:
sections:hat eine andere Form,outbound:fehlt, und die
in 3.0.0 übernommenen Page-Type-Templates enthalten{section.*}-Variablen, die es nicht mehr
gibt -newschriebe sie wörtlich in neue Seiten. Rückwärts: 4.0.0 schreibt gelabelte Kanten,
die 3.0.0s Schema alstype: stringablehnt. Beide Hälften des Drop-in-Tests fallen.Der Korpus dieser Instanz ist noch nicht umgestellt. Diese Version liefert die Maschinerie;
lintmeldet die 480 noch ungelabelten Kanten als Findings, nicht als Fehler, weil das genau das
Fenster ist, für das.wikitool-kb.jsonexistiert.malformed_edgesundunbalanced_markers
sind dagegen sofort hart - keines beschreibt eine unkonvertierte Seite, nur eine kaputte. Die
Beförderung der beiden anderen kommt, wenn der Korpus sie bestehen kann.Downloads
-
v3.0.0 Stable
released this
2026-09-02 13:05:10 +00:00 | 91 commits to main since this release3.0.0 - 2026-09-02 - Autorenkonventionen nach Eigentum geschnitten: kb/CONVENTIONS.md, deklarierte Collections
Author: Torben Nehmer
Breaking Change: kb/CONTRACT.md ist um alles gekuerzt, was eine Instanz selbst entscheidet; das steht jetzt in einer neuen, instanzeigenen kb/CONVENTIONS.md, aus der der Compiler die drei toolgefuehrten Abschnittsnamen liest. Eine bestehende Instanz muss diese Datei anlegen, auf jedem kb/*/COLLECTION.md profile: und required_by_stack: deklarieren und kb/CONTRACT.md aus dem Release nachziehen - sonst FAILt doctor und docs verify bricht. Ablauf: instructions/migrations/3.0.0-authoring-conventions.md
kb/CONTRACT.mdwar eine Datei mit zwei Autoritäten. Der eine Teil ist code-erzwungen und in
jeder Instanz gleich; der andere - § Language komplett, das Beziehungslabel-Vokabular, die
Tonfall-Beispiele samt deutscher Buzzword-Liste, die Confidence-Rubrik, das ADR-Präfix - ist
Konvention, die jede Instanz für sich entscheidet, und wurde trotzdem als bindender Contract
verbatim ausgeliefert. Wer bei Schritt 5 vonsetup-instance.md"Englisch" antwortete, hatte
danachkb/CONTRACT.md, vier Type-Specs undtools/chemenu/sections.pylokal geändert -
undprivate-instance.mds Decision Point sagt für so einen Merge-Konflikt: Upstream-Seite
nehmen. Für diese Instanz hieß das: KB-Sprache zurück auf Deutsch.Der Schnitt läuft jetzt danach, wer den Satz ändern darf.
kb/CONTRACT.mdbehält, was
wikitoolerzwingt; neu daneben liegtkb/CONVENTIONS.md, die genauso bindet und der
Instanz gehört. Unterschied ist Eigentum, nicht Autorität - deshalb liefert die Distribution nur
kb/CONVENTIONS.md.template, exakt derUSER.md/SOUL.md-Split ein Verzeichnis tiefer. Dazu
instructions/kb-profiles.md: der Katalog erprobter Profile, ausdrücklich Palette und kein
Enum. Übernommen wird der Text in die Instanzdatei, nie ein Verweis auf den Katalog - ein
Verweis wäre wieder genau die Konstruktion, die dieser Release beendet.sections.pyhält keine Überschrift mehr.RELATIONSHIPS = "Beziehungen"war die Stelle,
an der die Konvention in Code übergelaufen war: solange sie dort stand, konnte kein Template die
Sprache umstellen. Neu isttools/chemenu/conventions.py, das die drei Namen aus
kb/CONVENTIONS.mdliest;sections.pylöst sie per PEP 562 bei jedem Zugriff auf, wie
configseine Pfade - ein Modulkonstante hätte den Wert an den Baum gebunden, in dem der Prozess
gestartet ist. Aus demselben Grund istprovenance.CITE_BLOCK_HEADINGein__getattr__und
render_cite_block(heading=None)löst innerhalb des Aufrufs auf. Der Alias-Mechanismus, den das
Modul schon hatte, ist der Migrationspfad: erkannt wird die kanonische Form plus die
deklariertensection_aliases:plus das, was dieser Stack vor der Konventionsdatei geschrieben
hat. Ohne Datei antwortet dieser Fallback - richtig für jeden Korpus, der ihn erreichen kann,
denn der wurde unter genau diesen Namen geschrieben;doctorist die laute Hälfte davon.Die vier Page-Type-Specs schreiben
## {section.relationships}statt einer Überschrift.
Neue Template-Variablen{section.relationships}/{section.see_also}/{section.footnotes},
gefüllt aus der Instanzdeklaration. Damit ändert eine anderssprachige Instanz keine Datei unter
tools/odertypes/mehr - was Schritt 5 vonsetup-instance.mdvon fünf Editierstellen
über drei Schichten auf eine Entscheidung reduziert.COLLECTION.mdbekommt Frontmatter. Bisher wurde eine Collection rein an der Dateipräsenz
erkannt; die Deklaration brauchte einen Träger, sonst wäre der Ortsschnitt nur durch einen
Prosaschnitt ersetzt worden.profile:nennt den übernommenen Katalogeintrag (Freitext - eine
selbst angelegte Collection hat dort keinen),required_by_stack:sagt, obwikitooldie
Collection namentlich auflöst. Das zweite ist nicht die Wahl der Instanz:docs verify
prüft es beidseitig gegenkb_collections.STACK_REQUIRED_COLLECTIONS. Heute steht dort genau
sources-sources coverage, die[^cite-id]-Auflösung undkb/provenance.mdhängen an dem
Namen,entitiesan keinem.Das zweite Leck der Merge-Prozedur ist zu.
git checkout HEAD -- kb rawholte alles unter
beiden Stages auf den Vor-Merge-Stand - auchkb/CONTRACT.mdundraw/CONTRACT.md. Änderte der
Upstream einen davon, warf die Prozedur das Update still weg, und die Kontrollzeile meldete dabei
leer, bestätigte den Fehler also, statt ihn zu fangen.private-instance.mdnimmt die
Upstream-Seite jetzt für die drei Maschinerie-Pfade unter den Content-Stages zurück
(kb/CONTRACT.md,kb/CONVENTIONS.md.template,raw/CONTRACT.md) und schließt sie aus der
Kontrollzeile aus. Dieselbe Altlast in der Tarball-Richtung:INSTALL.mdSchritt 3 fasstekb/
gar nicht an und zogkb/CONTRACT.mddamit nie nach - jetzt ausdrücklich benannt.Verworfen, gemessen:
sources/auskb/herausziehen. Der Graph ist einwurzelig
(kb_scan.iter_kb_pagesmacht einrglobüberkb/, darauf sitzen Link-Graph, Orphan-Check,
index rebuildundsearch), und Source-Seiten sind darin der dichteste Knotentyp. Ein Hoist
machte jede Graph-Operation dauerhaft zweiwurzelig, um ein Verzeichnis umzubenennen. Vor allem
aber kann der Ort Eigentum ohnehin nicht kodieren, sobald Collections offen sind: eine selbst
angelegte liegt im selbenkb/wie die Defaults. Eigentum ist eine deklarierte Eigenschaft -
daher das Frontmatter oben. Gitea #39 trägt die Ablehnung im Volltext.Warum das MAJOR ist. Die Rückwärtshälfte des Drop-in-Tests hält - 2.5.0 ignoriert beide neuen
Deklarationen folgenlos. Die Vorwärtshälfte nicht: nach dem Kopieren der Maschinerie FAILt
doctorauf der fehlendenkb/CONVENTIONS.md,docs verifybricht auf den undeklarierten
Collections, undkb/CONTRACT.mdmuss aus dem Release nachgezogen werden. Ein Shim war die
Alternative (doctornur WARN, Pflichtfelder tolerant) und wurde verworfen: er hätte genau den
Zustand normalisiert, in dem eine Instanz glaubt, sie habe entschieden, während in Wahrheit der
Fallback antwortet - für eine englische Instanz hieße das## Beziehungenin englischen Seiten.
Die Handarbeit ist eine Datei und zwei Frontmatter-Zeilen je Collection; keine einzigekb/-Seite
ändert sich, weshalbmigrate done 3.0.0 --pages 0ehrlich und kein Platzhalter ist.Downloads
-
v2.5.0 Stable
released this
2026-09-02 07:20:31 +00:00 | 93 commits to main since this release2.5.0 - 2026-09-02 - Versionsstelle: Kompatibilitaet statt Inhaltsmigration, Breaking-Change-Vermerk erzwungen
Author: Torben Nehmer
Die Doku des Stacks führte für die Wahl der Versionsstelle zwei Fragen zusammen, die nicht
dieselbe sind: muss der Korpus migriert werden? und ist die neue Version ein
Drop-in-Ersatz? An allen drei Stellen, die einer Session vor dem Bump begegnen - die Tabelle
instack-dev, der Modul-Docstring inversion.py,INSTALL.md§ Version und Updates -
stand nur die erste. Nurversion bump --helpformulierte es richtig, also ausgerechnet die
Stelle, die man erst liest, wenn die Entscheidung gefallen ist. Bei2.0.0hat genau diese
Lücke zu1.9.0geführt (Gitea #26; der Eintrag zu2.0.0trägt den Fall im Volltext).Die Regel, jetzt an einer Stelle. Neu ist
instructions/dev/version-parts.md: der Drop-in-Test in zwei Hälften - vorwärts (kopieren,
fertig, keine Handarbeit durch Nutzer oder Migrationsskript) und rückwärts (die alte Version
lässt sich noch zurückinstallieren) -, der Katalog der Brüche, die die Grenze bei völlig
unangetastetemkb/überschreiten (Update-Pfad, Artefaktname, Import-Name, Flags, Envvars,
Shape maschinengelesener Dateien), und der Fall2.0.0als Fallbeispiel.instructions/dev/,
also nicht in einer ausgelieferten Instanz - die Datei entscheidet, wer den Stack entwickelt.
Die ausgelieferten Artefakte tragen deshalb die Kurzform der Regel, aber keinen Verweis auf
sie:instructions verifymeldet einen solchen Verweis, weil er nachdist exportins Leere
zeigen würde.Breaking Changes sind teuer, also genehmigungspflichtig.
stack-devhat einen
Entscheidungspunkt bekommen: stellt sich eine Änderung als nicht drop-in heraus, wird nicht
aus eigener Initiative über die Grenze gebumpt. Vorgelegt werden der konkrete Bruch, was jede
bestehende Instanz von Hand tun muss, und die Alternativen - Bruch per Shim vermeiden,
aufschieben und mit dem nächsten bündeln, oder in einen kompatiblen und einen brechenden Teil
mit Deprecation-Fenster spalten -, dazu eine Empfehlung. Dann Freigabe abwarten.--breakingist neu und bei jedem Grenzübertritt Pflicht. Es schreibt eine
**Breaking Change:**-Zeile in den Eintrag, vor die Migrationszeile: das ist, was der Operator
einer bestehenden Instanz beim Lesen der Release-Notes zuerst braucht.docs verifyprüft den
neuesten grenzüberschreitenden Eintrag darauf, analog zu**Migration:** none requiredund aus
demselben Grund - eine Prosa-Regel driftet, ein Marker nicht. Auf einem kompatiblen Bump wird
--breakingverweigert, damit es keine Gewohnheit wird. Beide Prüfungen bleiben getrennt:
check_migration_for_boundaryfragt, ob der Inhalt sich bewegt,check_breaking_change_for_boundary,
ob dem Operator gesagt wurde, dass der Tausch keiner zum Drüberkopieren ist. Ein Rebranding
besteht die erste und fällt durch die zweite.Was ausdrücklich nicht passiert:
docs verifyprüft weiterhin nicht, ob die Stelle
richtig gewählt wurde. Kein Validator unterscheidet ein umbenanntes Flag von einem neuen; das
bleibt Urteil, und dieser Eintrag existiert, weil das Urteil eine Anleitung braucht, keinen
Automaten.Berührt:
instructions/dev/version-parts.md(neu),instructions/dev/stack-dev/SKILL.md,
tools/chemenu/version.py,tools/chemenu/commands/version_cmd.py,
tools/chemenu/commands/docs_verify.py,tools/CONTRACT.md,INSTALL.md. Sechs neue Tests.Downloads
-
v2.4.1 Stable
released this
2026-09-02 05:30:49 +00:00 | 97 commits to main since this release2.4.1 - 2026-09-02 - INSTALL-MCP.md: Menschendoku fuer den Leseserver, und sie wird mit ausgeliefert
Author: Torben Nehmer
Nachtrag zu 2.4.0. Der Server war ausgeliefert und für Menschen nur über
tools/CONTRACT.mdund
eine Instruktion beschrieben — beide für Agenten geschrieben.INSTALL-MCP.mdschließt das,
nebenINSTALL.mdund in derselben Form: Voraussetzungen, sechs Schritte, Verifikation,
Troubleshooting.Was drinsteht, das sonst nirgends zusammen stand: die Client-Konfiguration als JSON-Block;
dassWIKI_TRACE=0nicht optional ist und wie die Startverweigerung aussieht; dass
--host 0.0.0.0bewusst nicht der Default ist; und der Verweis auf die
Traefik-ForwardAuth-Middleware unter https://gitea.nehmer.net/torben/gitea-mcp-forward-auth
samt dem, was sie erwartet (Bearer-Token gegen SHA-256-Hashes,AUTH_PROXY_TOKEN_HASHES_DIR).
Der Verifikationsabschnitt ist ein lauffähiges Skript — wörtlich so ausgeführt, bevor es hier
landete.dist exportliefert die Datei mit.ROOT_FILESist eine Allowlist, also hätte sie sonst
keine Instanz erreicht: ein ausgelieferter Server, dessen Bedienungsanleitung im Ursprungs-Repo
zurückbleibt, ist einer, den der Empfänger durch Quelltextlesen findet.INSTALL.mdbekommt
zusätzlichCHEMENU_ROOTundWIKI_TRACE/WIKI_TRACE_DIRin seine Konfigurationstabelle —
beide waren seit 2.3.0 bzw. seit jeher wirksam und dort nicht aufgeführt.Dateien:
INSTALL-MCP.md(neu),INSTALL.md,README.md,
tools/chemenu/commands/dist_cmd.py.Downloads
-
v2.4.0 Stable
released this
2026-09-02 05:22:23 +00:00 | 98 commits to main since this release2.4.0 - 2026-09-02 - MCP-Leseserver: zweiter Konsument auf demselben Kern
Author: Torben Nehmer
Letzter Schritt der Sequenz aus #36, inhaltlich Issue #19.
chemenubekommt einen zweiten
Konsumenten:search,types,describe_type,lintundstatusüber MCP. Kein CLI mit
angeschraubter Netzwerkschnittstelle — CLI und Server sind zwei Adapter auf dem Kern, den 2.3.0
freigelegt hat.tools/chemenu/mcp/, im Repo statt als eigenes Artefakt. Der Golden-Test, der die
Serverantworten gegen die--json-Formen der CLI hält, läuft nur mit beiden Seiten in einer
Testsuite; getrennt würde aus einem Contract eine Versionsabsprache. Der Test ruftwikitoolals
Subprozess gegen denselben Baum auf, überCHEMENU_ROOT— womit er nebenbei die Root-Auflösung
von außen mitprüft.Zwei Transports.
stdiozum Entwickeln und Testen ohne Netz,streamable-httpfür die
Auslieferung — der einzige, vor den sich die Authentifizierungs-Middleware überhaupt setzen kann,
weil sie ein HTTP-Reverse-Proxy ist.sseist über das SDK erreichbar und wird bewusst nicht
angeboten: der abgelöste Remote-Transport, jetzt darauf zu bauen verschiebt den Wechsel nur.
--host/--portgibt es, weil der Default auf Loopback bindet und ein Container hinter einem
Proxy eine Adresse braucht, die der Proxy erreicht — eine Eigenschaft der Software, nicht einer
Installation. Beide Transports sind gegen den echten Korpus gegengeprüft.Kein Schreibpfad, strukturell. Weder der Server noch
chemenu.apiimportiert irgendetwas
unterchemenu.commands, also existierennew,touch,xref,cite,publish,migrate
undversion bumpin dieser Reichweite gar nicht, statt aus einer Liste gefiltert zu werden. Ein
Test importiert das Servermodul in einem frischen Interpreter und sieht insys.modulesnach;
ein zweiter ruft alle fünf Tools auf und vergleicht den Dateibaum,HEADund
git status --porcelainvorher/nachher.Jede Antwort trägt ihren Commit.
commitundas_ofin jedem Payload;nullheißt, der
bediente Baum hat uncommittete Änderungen und die Antwort entspricht keiner Revision. Der Stempel
ist die Revision, aus der die Seiten tatsächlich gelesen wurden — zwischen Laden und Stempeln
kann der Baum sich bewegen, deshalb reicht der Ladepfad seine Revision durch, statt noch einmal
zu fragen. Das war beim ersten Durchlauf falsch:types/lint/statuslasen die zuletzt
gecachte Revision und stempeltennull, obwohl der Baum sauber war.Telemetrie in den bedienten Baum wird beim Start verweigert, nicht stillschweigend
umgeleitet. Tracing ist per Default an und schreibt nachreports/telemetry/im Repo — genau das
Verzeichnis, das der Sync pergit reset --hardwegräumen darf.WIKI_TRACE=0oder
WIKI_TRACE_DIRaußerhalb des Korpus. Heute schreibt auf diesem Pfad nichts (der Emitter hängt an
cli.main()und den Gates), die Sperre ist gegen später.Fehler an der Protokollgrenze. Ein
ChemenuErrorwird zumToolErrordes SDK — eine
absichtliche Ablehnung, deren Text den Aufrufer erreicht. Alles andere bleibt ein Absturz, dessen
Text auf dem Server bleibt. Ein kaputtes Prädikat ist das Argument des Aufrufers, also muss die
Zeile mitreisen, die sagt, was stattdessen zu schreiben ist.Bewusst nicht enthalten: Authentifizierung und Rate Limiting (Middleware vor dem Prozess),
Deployment (private Infrastruktur), der Iteration Budget Gate — er begrenzt eine Agenten-Session
und nicht einen Nutzer, weshalb Retrieval von ihm befreit ist; ihn hier als Rate Limiter zu
benutzen würde ihn dazu verwässern.Die Abhängigkeit ist optional (
tools/requirements-mcp.txt): eine Instanz, die nur die CLI
benutzt, soll dafür nicht pydantic, starlette, uvicorn und cryptography installieren müssen. CI
installiert sie, denn ein übersprungener Golden-Test ist genau der Weg, auf dem Server und CLI
unbemerkt auseinanderlaufen.Betrieb und Sync-Mechanismus: instructions/mcp-read-server.md.
Polling (git fetch && git reset --hard) statt Webhook — kein eingehender Endpunkt, keine
Signaturprüfung.reset --hardist dort tragend und keine Bequemlichkeit: ein abgedrifteter Baum
antwortet zwar richtig, parst aber bei jeder Anfrage neu und stempelt jede Antwort mitnull.Dateien:
chemenu/mcp/(neu:server.py,__main__.py),chemenu/api.py,
tools/requirements-mcp.txt(neu),instructions/mcp-read-server.md(neu),tools/CONTRACT.md,
tools/README.md,.gitea/workflows/ci.yml,tests/test_mcp_server.py(neu).Downloads
-
v2.2.2 Stable
released this
2026-09-01 17:18:21 +00:00 | 102 commits to main since this release2.2.2 - 2026-09-01 - Doku-Verdrahtung: Publish-Remote Gate im Werkzeugvertrag, Projektseite auf oeffentlich
Author: Torben Nehmer
Nachziehen dessen, was 2.2.0 und die Veröffentlichung offen gelassen haben. Gefunden durch eine
Durchsicht auf lose Enden, nicht durch einen Fehlschlag —docs verifydeckt den Fall nicht ab,
weil es Kommando-Namen gegeneinander prüft, nicht ob ein neuer Fehlerfall beschrieben ist.tools/CONTRACT.mdkannte das Publish-Remote-Gate nicht. Der Werkzeugvertrag ist die Stelle,
an der pro Kommando steht, was ein Fehlschlag bedeutet und ob ein Retry sicher ist — und
publishhatte seit 2.2.0 einen dritten Weg zu Exit 42, der dort nirgends stand. Ergänzt in
beiden Richtungen: in der Kommandozeile (URL statt Remote-Name,pushurlwird gelesen, fehlende
Datei heißt unbeschränkt, kaputte Datei ist ein Fehler) und im Fehlerkontrakt, wo der
entscheidende Unterschied zu den anderen beiden Gates steht — es gibt keine--confirm-Zeile,
die der Agent nachreichen könnte.instructions/gates.mdverwies nicht auf die Prozedur, für die das Gate gebaut wurde.
Jetzt verlinkt, mit dem Hinweis auf Schritt 4: Das Gate gehört vor den erstenpublish, später
hinzugefügt schützt es das Fenster nicht, das es schließen soll.Die Projektseite beschrieb sich selbst falsch.
kb/entities/projects/Chemenu.mdnannte
Chemenu ein „persönliches IT-Wissens-Wiki" mit dem Zweck „Persönliche IT-Wissensbasis" — seit
der Veröffentlichung schlicht unzutreffend, und es ist die Seite, die ein Fremder über das
Projekt liest. Neu gefasst: deterministischer Wissenskompiler, diese Instanz seit 2026-09-01
öffentlich als Testbett und Demo, Lizenz benannt.Die historische Aussage über die monolithische
AGENTS.md(~30 KB) bleibt — sie war zu ihrer
Zeit korrekt und ist belegt. Sie ist jetzt als Ausgangspunkt datiert statt als Gegenwart
formuliert, dieselbe Unterscheidung, die #29 für die Issue-Texte trifft: ein Pfad als Wegweiser
wird nachgezogen, ein Pfad als Beleg bleibt stehen und bekommt ein Datum.Dateien:
tools/CONTRACT.md,instructions/gates.md,
kb/entities/projects/Chemenu.md,kb/entities/INDEX.md(generiert).Downloads
-
v2.2.1 Stable
released this
2026-09-01 17:06:03 +00:00 | 103 commits to main since this release2.2.1 - 2026-09-01 - private-instance: der Demo-Korpus wandert beim Merge doch mit - Prozedur korrigiert
Author: Torben Nehmer
instructions/private-instance.mdbehauptete in 2.2.0, eingit merge upstream/mainlöse
Änderungen am Demo-Korpus stillschweigend auf, weil die private Instanz ihn einmal gelöscht hat:
deleted-in-ours, unmodified-in-theirs. Das war nicht gemessen, sondern angenommen — und es
ist falsch. Ein Nachbau mit einem Upstream, der seinen Korpus bewegt, zeigt drei verschiedene
Verhalten:Upstream tut git merge upstream/maintutändert eine Seite, die du gelöscht hast CONFLICT (modify/delete)— und lässt die Upstream-Fassung im Arbeitsbaum liegen. Eingit add -Abeim Auflösen holt die Demo-Seite zurück.legt eine neue Seite an staged sie stillschweigend. Kein Konflikt, keine Meldung. löscht eine Seite, die du auch gelöscht hast nichts. Der einzige harmlose Fall. Die mittlere Zeile ist die gefährliche, weil nichts sie ankündigt. Ein Upstream, der einen
Demo-Korpus ausliefert und ihn als Testbett benutzt, legt Seiten an — und jede einzelne
landet in der privaten Instanz und taucht dort inlint,index,searchund
confidence decayauf. Genau diese Doppelnutzung beschreibt Issue #28.Korrigiert: Die Update-Prozedur hält den Merge mit
--no-commitoffen, zwingtkb/und
raw/danach auf den eigenen Stand zurück (git rm --cached,rm -rf,git checkout HEAD --)
und schließt ihn erst dann. Solange der Merge offen ist, zeigtHEADnoch auf den Commit davor,
und genau das macht den Schritt sauber. Anschließend eine Kontrolle, die man nicht überlesen
kann:git diff --name-only $BEFORE HEAD -- kb raw # muss leer seinDas Rezept ist wörtlich so nachgespielt worden, wie es jetzt in der Datei steht — mit einem
Upstream, der gleichzeitig eine Seite ändert, eine anlegt, eine löscht und dasselbe unter
raw/tut. Ergebnis: Stack aktualisiert, nur eigener Inhalt übrig, Kontrolle leer,
Arbeitsbaum sauber.Auch die Decision Points korrigiert. „Konflikt in
kb/per Hand als keep deleted
auflösen" stand vorher da und ist der Rat, der in die Falle führt:git add -Acommittet die
Fassung, die git im Arbeitsbaum liegen gelassen hat.Dateien:
instructions/private-instance.md.Downloads
-
v2.2.0 Stable
released this
2026-09-01 16:09:37 +00:00 | 105 commits to main since this release2.2.0 - 2026-09-01 - Publish-Remote Gate: publish schreibt nur an erklaerte Ziele
Author: Torben Nehmer
Der Stack bekommt sein drittes Gate. Die beiden bestehenden fragen, ob eine Änderung zu groß
ist und ob ein Rebase gefährlich ist. Dieses fragt, was darunter liegt: ob das überhaupt das
richtige Repository ist.Das Problem entsteht erst durch die private Instanz. Ein Checkout mit eigenem Inhalt hat
typischerweise zwei Remotes — sein eigenes und das öffentliche Upstream, von dem er
Stack-Updates zieht. Git unterscheidet die beim Push nicht, also legt ein falsches--remote
einen privaten Korpus auf ein öffentliches Repository. Das ist nicht billig rückholbar, und
zwar nachweislich: Beim Veröffentlichen dieses Repos blieb die gesamte alte History nach dem
Force-Push per SHA abrufbar, bis auf dem Server die Reflogs verfielen undgit gc --prune=now
lief. Ein Force-Push bewegt den Branch, nicht die Objekte..wikitool-remotes.jsonnennt die erlaubten Push-URLs. Nicht die Remote-Namen: Eine
Namensliste ließe einpublishdurch, dessenoriginumgebogen wurde, und genau das ist der
Fall, den das Gate fangen soll. Gelesen wird diepushurl, wenn der Remote eine setzt, denn
dorthin schreibtgit pushtatsächlich.Pro Checkout und gitignored, aus demselben Grund wie
ENVIRONMENT.md: Zwei Klone pushen an
zwei verschiedene Orte, eine committete Kopie würde einem privaten Klon also mitteilen, das
öffentliche Upstream sei ein legitimes Ziel für seinen eigenen Inhalt. Fehlt die Datei, gilt
keine Beschränkung — ein Checkout mit einem Remote und ohne Privates hat nichts zu schützen,
und eine Pflichtdatei würde aus einer Sicherung Papierkram machen. Eine kaputte Datei ist
dagegen ein Fehler und kein „keine Beschränkung": Eine beschädigte Sicherung darf sich nicht
wie eine abgeschaltete verhalten.Kein Token, keine Flagge. Die anderen beiden Gates lösen sich mit einem
--confirm <token>,
weil ihre Frage („ist diese Änderung richtig?") für genau ein Changeset beantwortbar ist. Dieses
fragt „gehört dieser Inhalt in jenes Repository?", und das ist eine stehende Eigenschaft des
Checkouts, kein Einzelfallurteil. Der Weg daran vorbei ist ein bewusster Edit des Nutzers.
Ein Agent, der die Datei anfasst, um an einer Verweigerung vorbeizukommen, öffnet ein Gate aus
eigenem Antrieb — Invariante 6.doctormeldet den Zustand statt ihn zu erzwingen: OK mit Anzahl der Ziele, OK bei
Abwesenheit mit einem Remote, und WARN bei mehr als einem Remote ohne Allowlist — also genau in
der Form, die eine private Instanz annimmt, sobald sie das Upstream hinzufügt.Und die Prozedur, für die das Gate gebaut wurde.
instructions/private-instance.md(neu)
beschreibt die dritte Instanz-Form neben „frisch aufsetzen" und „Repo klonen": eine private
Arbeitsinstanz, die Stack-Updates von einem öffentlichen Upstream pergit mergezieht und
deren eigener Inhalt nie zurückwandert. Der Grund, warum das dem Tarball-Weg vorzuziehen ist,
steht dort ausformuliert —cp -rhat keinen Drei-Wege-Merge und keine Konflikterkennung.
Schritt 4 der Anleitung ist das Gate, und zwar ausdrücklich vor dem erstenpublish:
später hinzugefügt schützt es das Fenster nicht, das es schließen soll.Dateien:
config.PUBLISH_REMOTES_FILENAME,git_publish.read_allowed_push_urls(),
push_url_for(),publish_remote_refusal()und die Prüfung vor dem Reconcile-Schritt,
doctor.check_publish_remotes(),.gitignore,instructions/gates.md,
instructions/private-instance.md(neu),AGENTS.md(Gate-Liste und Bootstrap-Routing),
12 neue Tests intest_git_publish.py.Downloads