kb/CONTRACT.md mischt Stack-Regel und Instanz-Konvention: nach Eigentum schneiden, nicht nach Ort #39

Closed
opened 2026-09-02 11:57:49 +00:00 by torben · 1 comment
Owner

Status: umgesetzt und ausgeliefert in 3.0.0 (Commit 502971d, „Autorenkonventionen nach Eigentum geschnitten"). Alle Akzeptanzkriterien unten sind abgehakt und am 2026-09-03 nachverifiziert. Der Anschluss ist unten unter Nach Abschluss geht es weiter bei benannt.

Der Befund

kb/CONTRACT.md ist eine Datei mit zwei Autoritäten. Ein Teil ist code-erzwungen und darf nie abweichen; ein Teil ist Konvention, die jede Instanz für sich entscheidet — und wird trotzdem als bindender Contract ausgeliefert.

Ebene Beispiele
Code-erzwungen Collections-Regeln (docs verify), Generated-Files-Tabelle, provenance:-Enum, Cite-/Footnote-Mechanik, confidence_base vs. abgeleitetes confidence, Orphan-Check, Blockquote-Cap
Instanz-Konvention § Language komplett, Beziehungslabel-Vokabular (hängt ab von, verwendet, …), Ton-Beispiele und Buzzword-Liste (deutsch), Confidence-Rubrik (0.5 / +0.2 pro Quelle / …), ADR-Präfix

Die Sprachentscheidung ist der Extremfall: sie steckt nicht in einer Datei, sondern in vier Schichten.

kb/CONTRACT.md § Language + § Linking (Labels) + § Tone (Beispiele)
types/{entity,concept,source,comparison}.md   → "## Beziehungen", "## Siehe auch", "## Fußnoten"
tools/chemenu/sections.py                     → RELATIONSHIPS = "Beziehungen"   ← Python-Quelltext
instructions/german-terminology.md            → ganze Datei

setup-instance.md Schritt 5 wusste das und löste es als Handarbeit an fünf Stellen über drei Schichten.

Warum das mehr war als Unordnung

Zwei Dokumente widersprachen sich für jede nicht-deutsche Instanz. Wer bei Schritt 5 „Englisch" antwortete, hatte lokal kb/CONTRACT.md, vier Type-Specs und sections.py geändert. private-instance.mds Decision Point sagt für so einen Merge-Konflikt: „Conflict in tools/, types/ or instructions/? You changed the stack locally — take the upstream side and re-file the change as an issue there." Die Upstream-Seite nehmen hieß für diese Instanz: KB-Sprache zurück auf Deutsch.

Und die Merge-Prozedur aus 2.2.1 hatte dadurch ein zweites Leck, in die andere Richtung als das in #30 beschriebene. git checkout HEAD -- kb raw holt alles unter beiden Stages auf den Vor-Merge-Stand — auch diese sechs Maschinerie-Dateien:

kb/CONTRACT.md   kb/{comparisons,concepts,entities,sources}/COLLECTION.md   raw/CONTRACT.md

Änderte der Upstream einen davon, warf die Prozedur das Update still weg. Die Kontrollzeile git diff --name-only $BEFORE HEAD -- kb raw meldete dann leer, also „nachweislich funktioniert", während sie gerade eine Contract-Änderung gefressen hatte. Die Kontrolle, die der wichtigste Teil sein soll, bestätigte hier den Fehler.

dist_cmd.py kannte die Unterscheidung bereits (CONTRACT_ONLY_STAGES plus jedes kb/*/COLLECTION.md werden explizit kopiert). Die Prosa-Prozedur hatte sie nicht.

Vorbild: Commonplace

Gemessen an commonplace/ (vendored, siehe instructions/dev/commonplace-kb.md), drei zusammengehörige Mechanismen:

  1. Die Autoritätsrichtung ist umgedreht. Der Profil-Katalog sagt über sich selbst: „This page is that library: a palette, not an enum. Each COLLECTION.md stays authoritative for the collection's actual contract; a profile entry here is a proven starting point, not a binding source." Das Ausgelieferte ist unverbindliche Referenz, das Instanz-eigene bindet. Bei uns war es andersherum.
  2. Init scaffoldet Templates mit Entscheidungsprompt („theoretical / descriptive / prescriptive — pick one"), nicht fertigen Inhalt zum Zurückeditieren (ADR-021).
  3. Versionsmarker + Drift-Check an der Eigentumsgrenze (.commonplace): bei Drift wird nicht überschrieben, sondern verweigert.

Dazu der Begriff, der die Diagnose trägt: system-definition artifact (bindet) vs. knowledge artifact (informiert).

Disanalogie, die die Kopie begrenzt: ADR-021s Namespace (kb/commonplace/) löst „ausgelieferter Inhalt kollidiert mit Nutzerinhalt" — 195 Methodik-Notizen im kb/notes/ des Nutzers. Chemenu liefert null Seiten aus. Unser Problem war nicht ausgelieferter Inhalt, sondern ausgelieferter Contract. Der Namespace war deshalb die falsche Hälfte; die richtige sind Punkt 1 und 2.

Entscheidung

Der Schnitt lief bis dahin nach Ort — alles über kb/ steht in kb/CONTRACT.md. Er läuft seit 3.0.0 danach, wer den Satz ändern darf.

Datei Bindet Besitzt Distribution Im Merge
kb/CONTRACT.md ja Stack Datei, verbatim — nur noch das Code-Erzwungene muss mergen
kb/CONVENTIONS.md ja Instanz .template nie im Merge
kb/*/COLLECTION.md ja Instanz .template je Default-Collection, adoptiert ein Profil per Referenz
instructions/kb-profiles.md nein Stack Datei — Palette: die heutigen vier Collection-Contracts plus das deutsche Sprachprofil als erprobte Bündel mergt folgenlos

kb/CONVENTIONS.md trägt: KB-Sprache samt Abschnittsnamen, Beziehungslabel-Vokabular, Ton-Beispiele und Buzzword-Liste, Confidence-Rubrik, ADR-Präfix. Die Distribution liefert nur kb/CONVENTIONS.md.templateexakt der USER.md/SOUL.md-Split, den ROOT_FILES und doctors Sentinel-Check schon konnten. Kein neuer Mechanismus, ein vorhandener ein Verzeichnis tiefer.

COLLECTION.md bekam Frontmatter

Bis dahin wurde eine Collection rein an der Dateipräsenz erkannt (kb_collections.py). Die Deklaration brauchte einen Träger, sonst hätten wir den Ortsschnitt durch einen Prosaschnitt ersetzt:

profile: <name aus instructions/kb-profiles.md>
required_by_stack: true|false

required_by_stack: true heißt: Autorenkonventionen darf die Instanz umschreiben, löschen oder umbenennen nicht. Das trifft sources (sources coverage, Cite-Auflösung, provenance.md), nicht entities. Geprüft von docs verify.

Nachtrag aus 4.0.0: required_by_stack: wird nicht auf Treu und Glauben genommen, sondern gegen stack_required_collections() geprüft, das die Menge aus dem base_dir: des source-Type-Specs ableitet. Eine separate Liste im Code gibt es nicht.

Die Stelle, an der es sonst Prosa-Umschichtung geblieben wäre

RELATIONSHIPS = "Beziehungen" in sections.py war der Punkt, an dem die Konvention in Code übergelaufen war. Solange sie dort stand, konnte kein Template die Sprache umstellen. Das Modul las die drei Namen ab 3.0.0 aus den Instanz-Konventionen; der Alias-Mechanismus war der Migrationspfad. In 4.0.0 (#40) ist sections.py ersatzlos entfallen — Marker-Regionen tragen die Identität, der Überschriftentext ist reine Anzeige.

Verworfen: sources/ aus kb/ herausziehen

Erwogen, weil sources sich strukturell von entities unterscheidet. Verworfen, gemessen:

  • Der Graph ist einwurzelig. kb_scan.iter_kb_pages(kb_dir) macht ein kb_dir.rglob("*.md"); darauf sitzen build_link_graph, inbound_links, find_duplicate_title_paths, Orphan-Erkennung, index rebuild, search. Source-Seiten sind der dichteste Knotentyp darin — jedes [^cite-id] löst gegen eine auf. Ein Hoist macht jede Graph-Operation dauerhaft zweiwurzelig, um ein Verzeichnis umzubenennen.
  • kb_collections erzwingt „kein COLLECTION.md außerhalb kb/". Ein Top-Level-sources/ verlöre entweder seinen Contract oder diese Invariante bekäme eine Ausnahme.
  • Der Ort kann Eigentum ohnehin nicht kodieren, sobald Collections offen sind (kb_collections.py: mkdir kb/<name> && $EDITOR kb/<name>/COLLECTION.md add a collection without a code change"; types/type-spec.md:45: „Adding a type must require no code change"). Eine selbst angelegte Collection liegt im selben kb/ wie die Defaults. Eigentum ist eine deklarierte, keine Orts-Eigenschaft — daher das Frontmatter oben.

Sichtbar halten, ohne es zu nehmen: types/type-spec.md kennt bereits root: kb | repo. Eine Seite außerhalb kb/ ist schema-seitig vorgesehen; es fehlt der zweiwurzelige Graph-Walker. Wenn je eine Stage außerhalb kb/ Seiten tragen soll, ist das die Stelle — kein Sonderfall für sources.

Umsetzung

  1. kb/CONTRACT.md schneiden; kb/CONVENTIONS.md + .template; Eintrag in dist_cmd.py; doctor-Check analog zum Personalization-Sentinel.
  2. COLLECTION.md-Frontmatter (profile:, required_by_stack:) in kb_collections.py + docs verify; die vier Default-Contracts als Templates.
  3. sections.py und die vier Type-Specs von den hartkodierten deutschen Namen lösen.
  4. instructions/kb-profiles.md schreiben; setup-instance.md Schritt 5 auf „Profil wählen" umstellen; private-instance.mds Decision Point korrigieren; Version-Bump.

Akzeptanzkriterien

  • Kein Satz in kb/CONTRACT.md, den eine Instanz ändern müsste
  • kb/CONVENTIONS.md ist nicht im Distributions-Dateiplan; nur das Template ist es
  • doctor FAILt auf fehlende CONVENTIONS.md und auf eine mit Template-Sentinel
  • docs verify prüft profile: und required_by_stack: auf jedem COLLECTION.md
  • Eine englischsprachige Instanz ändert keine Datei unter tools/ oder types/
  • setup-instance.md Schritt 5 nennt eine Entscheidung, keine fünf Editierstellen
  • private-instance.mds Decision Point widerspricht dem nicht mehr
  • Version-Bump erfolgt nach instructions/dev/version-parts.md; der Verdacht auf Boundary-Crossing hat sich bestätigt und wurde als 3.0.0 mit Migrationsdokument gelöst

Vorgeschichte

Entschieden in der Sitzung vom 2026-09-02, aus #30 heraus. Die Alternativen (/sources-Hoist, Marker-Blöcke im bestehenden Text, nur die Pfadmenge maschinenlesbar machen) sind oben mit Begründung verworfen.


Nach Abschluss geht es weiter bei

#28 — der kuratierte Fixture-Korpus. Er muss gegen die hier entschiedene Contract-Form autorisiert werden; vorher geschrieben, wird er zweimal geschrieben. Danach #30.

> **Status: umgesetzt und ausgeliefert in `3.0.0`** (Commit `502971d`, „Autorenkonventionen nach Eigentum geschnitten"). Alle Akzeptanzkriterien unten sind abgehakt und am 2026-09-03 nachverifiziert. Der Anschluss ist unten unter *Nach Abschluss geht es weiter bei* benannt. ## Der Befund `kb/CONTRACT.md` ist eine Datei mit zwei Autoritäten. Ein Teil ist code-erzwungen und darf nie abweichen; ein Teil ist Konvention, die jede Instanz für sich entscheidet — und wird trotzdem als bindender Contract ausgeliefert. | Ebene | Beispiele | |---|---| | Code-erzwungen | Collections-Regeln (`docs verify`), Generated-Files-Tabelle, `provenance:`-Enum, Cite-/Footnote-Mechanik, `confidence_base` vs. abgeleitetes `confidence`, Orphan-Check, Blockquote-Cap | | Instanz-Konvention | **§ Language komplett**, Beziehungslabel-Vokabular (`hängt ab von`, `verwendet`, …), Ton-Beispiele und Buzzword-Liste (deutsch), Confidence-Rubrik (0.5 / +0.2 pro Quelle / …), ADR-Präfix | Die Sprachentscheidung ist der Extremfall: sie steckt nicht in einer Datei, sondern in vier Schichten. ``` kb/CONTRACT.md § Language + § Linking (Labels) + § Tone (Beispiele) types/{entity,concept,source,comparison}.md → "## Beziehungen", "## Siehe auch", "## Fußnoten" tools/chemenu/sections.py → RELATIONSHIPS = "Beziehungen" ← Python-Quelltext instructions/german-terminology.md → ganze Datei ``` `setup-instance.md` Schritt 5 wusste das und löste es als **Handarbeit an fünf Stellen über drei Schichten**. ## Warum das mehr war als Unordnung **Zwei Dokumente widersprachen sich für jede nicht-deutsche Instanz.** Wer bei Schritt 5 „Englisch" antwortete, hatte lokal `kb/CONTRACT.md`, vier Type-Specs **und `sections.py`** geändert. `private-instance.md`s Decision Point sagt für so einen Merge-Konflikt: *„Conflict in `tools/`, `types/` or `instructions/`? You changed the stack locally — take the upstream side and re-file the change as an issue there."* Die Upstream-Seite nehmen hieß für diese Instanz: KB-Sprache zurück auf Deutsch. **Und die Merge-Prozedur aus 2.2.1 hatte dadurch ein zweites Leck**, in die andere Richtung als das in #30 beschriebene. `git checkout HEAD -- kb raw` holt *alles* unter beiden Stages auf den Vor-Merge-Stand — auch diese sechs Maschinerie-Dateien: ``` kb/CONTRACT.md kb/{comparisons,concepts,entities,sources}/COLLECTION.md raw/CONTRACT.md ``` Änderte der Upstream einen davon, warf die Prozedur das Update still weg. Die Kontrollzeile `git diff --name-only $BEFORE HEAD -- kb raw` meldete dann *leer*, also „nachweislich funktioniert", während sie gerade eine Contract-Änderung gefressen hatte. Die Kontrolle, die der wichtigste Teil sein soll, bestätigte hier den Fehler. `dist_cmd.py` kannte die Unterscheidung bereits (`CONTRACT_ONLY_STAGES` plus jedes `kb/*/COLLECTION.md` werden explizit kopiert). Die Prosa-Prozedur hatte sie nicht. ## Vorbild: Commonplace Gemessen an `commonplace/` (vendored, siehe `instructions/dev/commonplace-kb.md`), drei zusammengehörige Mechanismen: 1. **Die Autoritätsrichtung ist umgedreht.** Der Profil-Katalog sagt über sich selbst: *„This page is that library: a palette, not an enum. Each `COLLECTION.md` stays authoritative for the collection's actual contract; a profile entry here is a proven starting point, not a binding source."* Das Ausgelieferte ist unverbindliche Referenz, das Instanz-eigene bindet. Bei uns war es andersherum. 2. **Init scaffoldet Templates mit Entscheidungsprompt** („theoretical / descriptive / prescriptive — pick one"), nicht fertigen Inhalt zum Zurückeditieren (ADR-021). 3. **Versionsmarker + Drift-Check** an der Eigentumsgrenze (`.commonplace`): bei Drift wird nicht überschrieben, sondern verweigert. Dazu der Begriff, der die Diagnose trägt: **system-definition artifact** (bindet) vs. **knowledge artifact** (informiert). **Disanalogie, die die Kopie begrenzt:** ADR-021s Namespace (`kb/commonplace/`) löst *„ausgelieferter Inhalt kollidiert mit Nutzerinhalt"* — 195 Methodik-Notizen im `kb/notes/` des Nutzers. **Chemenu liefert null Seiten aus.** Unser Problem war nicht ausgelieferter *Inhalt*, sondern ausgelieferter *Contract*. Der Namespace war deshalb die falsche Hälfte; die richtige sind Punkt 1 und 2. ## Entscheidung Der Schnitt lief bis dahin **nach Ort** — alles über `kb/` steht in `kb/CONTRACT.md`. Er läuft seit 3.0.0 **danach, wer den Satz ändern darf**. | Datei | Bindet | Besitzt | Distribution | Im Merge | |---|---|---|---|---| | `kb/CONTRACT.md` | ja | Stack | Datei, verbatim — nur noch das Code-Erzwungene | **muss** mergen | | `kb/CONVENTIONS.md` | ja | **Instanz** | `.template` | **nie** im Merge | | `kb/*/COLLECTION.md` | ja | **Instanz** | `.template` je Default-Collection, adoptiert ein Profil per Referenz | – | | `instructions/kb-profiles.md` | **nein** | Stack | Datei — Palette: die heutigen vier Collection-Contracts plus das deutsche Sprachprofil als erprobte Bündel | mergt folgenlos | `kb/CONVENTIONS.md` trägt: KB-Sprache samt Abschnittsnamen, Beziehungslabel-Vokabular, Ton-Beispiele und Buzzword-Liste, Confidence-Rubrik, ADR-Präfix. Die Distribution liefert nur `kb/CONVENTIONS.md.template` — **exakt der `USER.md`/`SOUL.md`-Split, den `ROOT_FILES` und `doctor`s Sentinel-Check schon konnten.** Kein neuer Mechanismus, ein vorhandener ein Verzeichnis tiefer. ### `COLLECTION.md` bekam Frontmatter Bis dahin wurde eine Collection rein an der Dateipräsenz erkannt (`kb_collections.py`). Die Deklaration brauchte einen Träger, sonst hätten wir den Ortsschnitt durch einen Prosaschnitt ersetzt: ```yaml profile: <name aus instructions/kb-profiles.md> required_by_stack: true|false ``` `required_by_stack: true` heißt: Autorenkonventionen darf die Instanz umschreiben, löschen oder umbenennen nicht. Das trifft `sources` (`sources coverage`, Cite-Auflösung, `provenance.md`), nicht `entities`. Geprüft von `docs verify`. Nachtrag aus 4.0.0: `required_by_stack:` wird nicht auf Treu und Glauben genommen, sondern gegen `stack_required_collections()` geprüft, das die Menge aus dem `base_dir:` des `source`-Type-Specs ableitet. Eine separate Liste im Code gibt es nicht. ### Die Stelle, an der es sonst Prosa-Umschichtung geblieben wäre `RELATIONSHIPS = "Beziehungen"` in `sections.py` war der Punkt, an dem die Konvention in Code übergelaufen war. Solange sie dort stand, konnte kein Template die Sprache umstellen. Das Modul las die drei Namen ab 3.0.0 aus den Instanz-Konventionen; der Alias-Mechanismus war der Migrationspfad. **In 4.0.0 (#40) ist `sections.py` ersatzlos entfallen** — Marker-Regionen tragen die Identität, der Überschriftentext ist reine Anzeige. ## Verworfen: `sources/` aus `kb/` herausziehen Erwogen, weil `sources` sich strukturell von `entities` unterscheidet. Verworfen, gemessen: - **Der Graph ist einwurzelig.** `kb_scan.iter_kb_pages(kb_dir)` macht ein `kb_dir.rglob("*.md")`; darauf sitzen `build_link_graph`, `inbound_links`, `find_duplicate_title_paths`, Orphan-Erkennung, `index rebuild`, `search`. Source-Seiten sind der dichteste Knotentyp darin — jedes `[^cite-id]` löst gegen eine auf. Ein Hoist macht jede Graph-Operation dauerhaft zweiwurzelig, um ein Verzeichnis umzubenennen. - **`kb_collections` erzwingt „kein `COLLECTION.md` außerhalb `kb/`".** Ein Top-Level-`sources/` verlöre entweder seinen Contract oder diese Invariante bekäme eine Ausnahme. - **Der Ort kann Eigentum ohnehin nicht kodieren**, sobald Collections offen sind (`kb_collections.py`: *„`mkdir kb/<name> && $EDITOR kb/<name>/COLLECTION.md` add a collection without a code change"*; `types/type-spec.md:45`: *„Adding a type must require no code change"*). Eine selbst angelegte Collection liegt im selben `kb/` wie die Defaults. Eigentum ist eine **deklarierte**, keine Orts-Eigenschaft — daher das Frontmatter oben. Sichtbar halten, ohne es zu nehmen: `types/type-spec.md` kennt bereits `root: kb | repo`. Eine Seite außerhalb `kb/` ist schema-seitig vorgesehen; es fehlt der zweiwurzelige Graph-Walker. Wenn je eine Stage außerhalb `kb/` Seiten tragen soll, ist das die Stelle — kein Sonderfall für `sources`. ## Umsetzung 1. [x] `kb/CONTRACT.md` schneiden; `kb/CONVENTIONS.md` + `.template`; Eintrag in `dist_cmd.py`; `doctor`-Check analog zum Personalization-Sentinel. 2. [x] `COLLECTION.md`-Frontmatter (`profile:`, `required_by_stack:`) in `kb_collections.py` + `docs verify`; die vier Default-Contracts als Templates. 3. [x] `sections.py` und die vier Type-Specs von den hartkodierten deutschen Namen lösen. 4. [x] `instructions/kb-profiles.md` schreiben; `setup-instance.md` Schritt 5 auf „Profil wählen" umstellen; `private-instance.md`s Decision Point korrigieren; Version-Bump. ## Akzeptanzkriterien - [x] Kein Satz in `kb/CONTRACT.md`, den eine Instanz ändern müsste - [x] `kb/CONVENTIONS.md` ist nicht im Distributions-Dateiplan; nur das Template ist es - [x] `doctor` FAILt auf fehlende `CONVENTIONS.md` und auf eine mit Template-Sentinel - [x] `docs verify` prüft `profile:` und `required_by_stack:` auf jedem `COLLECTION.md` - [x] Eine englischsprachige Instanz ändert **keine** Datei unter `tools/` oder `types/` - [x] `setup-instance.md` Schritt 5 nennt eine Entscheidung, keine fünf Editierstellen - [x] `private-instance.md`s Decision Point widerspricht dem nicht mehr - [x] Version-Bump erfolgt nach `instructions/dev/version-parts.md`; der Verdacht auf Boundary-Crossing hat sich bestätigt und wurde als `3.0.0` mit Migrationsdokument gelöst ## Vorgeschichte Entschieden in der Sitzung vom 2026-09-02, aus #30 heraus. Die Alternativen (`/sources`-Hoist, Marker-Blöcke im bestehenden Text, nur die Pfadmenge maschinenlesbar machen) sind oben mit Begründung verworfen. --- ## Nach Abschluss geht es weiter bei **#28** — der kuratierte Fixture-Korpus. Er muss gegen die hier entschiedene Contract-Form autorisiert werden; vorher geschrieben, wird er zweimal geschrieben. Danach #30.
torben added the prio/blockingsize/L labels 2026-09-02 11:57:49 +00:00
torben added the area/kbkind/build labels 2026-09-02 21:24:39 +00:00
Author
Owner

Changelog: Body auf den Abschlussstand gezogen — Status-Zeile vorangestellt, alle Umsetzungsschritte und Akzeptanzkriterien abgehakt, Tempus von Plan auf Befund umgestellt. Zwei sachliche Nachträge aus 4.0.0 eingearbeitet: required_by_stack: wird gegen stack_required_collections() geprüft statt auf Treu und Glauben genommen, und sections.py ist inzwischen ersatzlos entfallen statt nur von den deutschen Namen gelöst. Das letzte Akzeptanzkriterium präzisiert: der Boundary-Crossing-Verdacht hat sich bestätigt und wurde als 3.0.0 gelöst.


Abschluss

Umgesetzt und ausgeliefert als 3.0.0, Commit 502971d. Am 2026-09-03 gegen den laufenden Baum nachverifiziert.

Was implementiert wurde, entlang der vier Umsetzungspunkte:

Ergebnis
1 kb/CONVENTIONS.md existiert samt .template, ist nicht im Distributions-Dateiplan, doctor prüft sie (conventions: present, language de, sections Beziehungen, Fußnoten)
2 Alle vier COLLECTION.md tragen profile: und required_by_stack:; docs verify prüft beide, required_by_stack: gegen die aus dem source-Type-Spec abgeleitete Menge
3 instructions/german-terminology.md deklariert sich selbst als Bestandteil des german-Sprachprofils und nicht des Stacks; die vier Page-Type-Specs gehören seit 4.0.0 vollständig der Instanz
4 instructions/kb-profiles.md existiert; setup-instance.md Schritt 5 stellt eine Frage und wählt ein Profil; private-instance.md listet kb/CONTRACT.md, kb/CONVENTIONS.md.template und raw/CONTRACT.md namentlich als die drei Dateien, die der Merge aus MERGE_HEAD zurückholt, und die Kontrollzeile filtert genau diese drei heraus

Was bewusst nicht umgesetzt wurde: der /sources-Hoist aus dem Abschnitt Verworfen. Die Begründung steht im Body und hat sich seither bestätigt — 4.0.0 hat STACK_REQUIRED_TYPES eingeführt und STACK_REQUIRED_COLLECTIONS als separate Liste gestrichen, also ist Eigentum jetzt an genau einer Stelle deklariert statt an zwei. Der zweiwurzelige Graph-Walker bleibt der offene Vorbehalt, falls je eine Stage außerhalb kb/ Seiten tragen soll; ein eigenes Issue hat er nicht, weil es dafür heute keinen Anlass gibt.

Verifiziert: docs verify, instructions verify, doctor und lint --fail-on-error grün; 863 Tests; dist export erzeugt 191 Dateien mit kb/CONVENTIONS.md.template und je einem COLLECTION.md.template, und find_leaks verweigert die gefüllten Namen. Der volle setup-instance.md-Replay gegen einen frischen Export lief bei der Umsetzung durch — eine englische Instanz scaffoldet ## Relationships / ## See Also aus ihrer eigenen kb/CONVENTIONS.md und ändert dabei keine Datei unter tools/ oder types/.

Anschluss laut Body: #28 (kuratierter Fixture-Korpus), danach #30.

**Changelog:** Body auf den Abschlussstand gezogen — Status-Zeile vorangestellt, alle Umsetzungsschritte und Akzeptanzkriterien abgehakt, Tempus von Plan auf Befund umgestellt. Zwei sachliche Nachträge aus 4.0.0 eingearbeitet: `required_by_stack:` wird gegen `stack_required_collections()` geprüft statt auf Treu und Glauben genommen, und `sections.py` ist inzwischen ersatzlos entfallen statt nur von den deutschen Namen gelöst. Das letzte Akzeptanzkriterium präzisiert: der Boundary-Crossing-Verdacht hat sich bestätigt und wurde als `3.0.0` gelöst. --- ## Abschluss Umgesetzt und ausgeliefert als **`3.0.0`**, Commit `502971d`. Am 2026-09-03 gegen den laufenden Baum nachverifiziert. **Was implementiert wurde**, entlang der vier Umsetzungspunkte: | | Ergebnis | |---|---| | 1 | `kb/CONVENTIONS.md` existiert samt `.template`, ist nicht im Distributions-Dateiplan, `doctor` prüft sie (`conventions: present, language de, sections Beziehungen, Fußnoten`) | | 2 | Alle vier `COLLECTION.md` tragen `profile:` und `required_by_stack:`; `docs verify` prüft beide, `required_by_stack:` gegen die aus dem `source`-Type-Spec abgeleitete Menge | | 3 | `instructions/german-terminology.md` deklariert sich selbst als Bestandteil des `german`-Sprachprofils und nicht des Stacks; die vier Page-Type-Specs gehören seit 4.0.0 vollständig der Instanz | | 4 | `instructions/kb-profiles.md` existiert; `setup-instance.md` Schritt 5 stellt eine Frage und wählt ein Profil; `private-instance.md` listet `kb/CONTRACT.md`, `kb/CONVENTIONS.md.template` und `raw/CONTRACT.md` namentlich als die drei Dateien, die der Merge aus `MERGE_HEAD` zurückholt, und die Kontrollzeile filtert genau diese drei heraus | **Was bewusst nicht umgesetzt wurde:** der `/sources`-Hoist aus dem Abschnitt *Verworfen*. Die Begründung steht im Body und hat sich seither bestätigt — 4.0.0 hat `STACK_REQUIRED_TYPES` eingeführt und `STACK_REQUIRED_COLLECTIONS` als separate Liste gestrichen, also ist Eigentum jetzt an genau einer Stelle deklariert statt an zwei. Der zweiwurzelige Graph-Walker bleibt der offene Vorbehalt, falls je eine Stage außerhalb `kb/` Seiten tragen soll; ein eigenes Issue hat er nicht, weil es dafür heute keinen Anlass gibt. **Verifiziert:** `docs verify`, `instructions verify`, `doctor` und `lint --fail-on-error` grün; 863 Tests; `dist export` erzeugt 191 Dateien mit `kb/CONVENTIONS.md.template` und je einem `COLLECTION.md.template`, und `find_leaks` verweigert die gefüllten Namen. Der volle `setup-instance.md`-Replay gegen einen frischen Export lief bei der Umsetzung durch — eine englische Instanz scaffoldet `## Relationships` / `## See Also` aus ihrer eigenen `kb/CONVENTIONS.md` und ändert dabei keine Datei unter `tools/` oder `types/`. Anschluss laut Body: **#28** (kuratierter Fixture-Korpus), danach **#30**.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#39