Export der ganzen KB und Index im Ziel: include: "all" und optionales index als Routing ab einer index.md #217

Closed
opened 2026-10-13 11:52:30 +00:00 by torben · 3 comments
Owner

Befund aus der Prüfung von Hand auf dem Windows-Arbeitsrechner (Betreiber, 2026-10-13, Stand 10.0.0), beim Einrichten eines Exportziels nach #214. Design abgeschlossen am 2026-10-16. Abgeschlossen am 2026-10-16: gebaut in 10.1.0-beta.21 (Commit db09e89, CI-Läufe 756 und 757 grün), Doku-Nachzug beim Abschluss in 10.1.0-beta.22 (Commit 39514be, CI-Läufe 758 und 759 grün).

Befund

  • Der Betreiber wollte die ganze KB nach OneDrive exportieren und fand keinen Weg dafür. Das How-to sagte: „Only what a target's include selects is written; there is no "everything".“ (docs/how-to/export-to-a-synced-folder.md § Pick the pages and the format). Derselbe Satz stand in der Feldbeschreibung config_shapes.py (EXPORT, Feld targets), aus der die Referenz-Region in docs/reference/configuration.md erzeugt wird. Der Text war also Code, nicht nur docs/-Prosa.
  • Gefunden hat er dann include: [["collection:*"]]. Das ist fast alles: collection ist der erste Pfadteil unter kb/ (search/filters.py, collection_of). Eine .md direkt unter kb/, die keine Meta-Datei ist, zählt für search als Seite (kb_scan.is_page_path), hat aber die Collection None und fällt heraus. Eine solche Datei entsteht nur von Hand, lint meldet sie nicht. Im Demo-Korpus gibt es keine.
  • Im Ziel lagen nur die Seiten, ohne Index (#214 Entscheidung 8). Wer den Ordner in OneDrive öffnete, hatte keinen Einstieg außer der Ordnerstruktur.

Entscheidungen

  1. Eigene Form include: "all" (Betreiber, 2026-10-16). include ist entweder der String "all" oder wie bisher eine nicht leere Liste nicht leerer Auswahlen. "all" wählt genau die Seiten, die search ohne Prädikat kennt (search.service.load_pages_by_path), also auch eine verirrte Seite direkt unter kb/, nie eine generierte oder Meta-Datei (kb/index.md, kb/log.md, kb/provenance.md, kb/CONTRACT.md, kb/CONVENTIONS.md, INDEX.md, COLLECTION.md).
    • #214 Entscheidung 3 bleibt: „alle Seiten“ ist eine Benennung, weil sie ausdrücklich in der Zieldefinition steht. Ein fehlendes include, [] und [[]] bleiben Fehler der Sektion, ebenso jeder andere String ("All", "*", "everything"). Erwogen und verworfen: ein fehlendes oder leeres include als „alles“ zu lesen. Ein vergessenes Feld an einem Ziel mit after_publish: true würde dann nach dem nächsten publish die ganze KB ohne Rückfrage in einen Speicher schreiben, den Dritte lesen. So bricht dieselbe Lücke laut ab.
    • [["collection:*"]] funktioniert weiter, wird aber nicht als Weg dokumentiert.
    • Die Fehlermeldung für ein ungültiges include nennt beide erlaubten Formen (auch die für eine einzelne ungültige Auswahl).
  2. doctor bleibt unverändert (Betreiber, 2026-10-16). Keine „all pages“-Angabe in der export-Zeile.
  3. Optionaler Index im Ziel (Betreiber, 2026-10-16), neues Feld index je Ziel, Boolean, Default false, für beide Handler. Mit index: true erzeugt der Lauf Routing-Dateien aus den ausgewählten Seiten, nach derselben Hierarchie wie der Katalog unter kb/ (catalog.group_pages, Schwelle catalog.SHARD_THRESHOLD):
    • index.md im Wurzelverzeichnis des Ziels, der Einstieg: Gesamtzahl, Tabelle der Collections mit Seitenzahl und Link auf deren INDEX.md, je Collection mit Bereichen die Tabelle der Bereiche mit Link (auf die eigene Bereichsdatei oder den Anker in der INDEX.md der Collection).
    • <collection>/INDEX.md je Collection, <collection>/<bereich>/INDEX.md für einen Bereich, den der Katalog in eine eigene Datei auslagern würde. Tabellen: Seite (Link) | Typ | Zusammenfassung | Zuletzt geändert.
    • Nur was exportiert wird: Eine Collection oder ein Bereich ohne ausgewählte Seite erscheint nicht (group_pages legt leere Collections von der Festplatte an; die werden verworfen). Eine Seite direkt unter kb/ steht in einer eigenen Tabelle in index.md („Pages outside any collection“), ohne eigene Datei.
    • #214 Entscheidung 8 („Keine generierten Index-Dateien“) gilt damit nur noch für index: false. Die Dateien unter kb/ werden nicht kopiert: Bei einer Teilauswahl nennen sie Seiten, die nicht exportiert werden, deren Titel die KB damit verlassen würden, und ihre Links zeigten ins Leere.
  4. Inhalt eines Index im Ziel: deterministisch und ohne Agenten-Text. Kein date.today() (das bräche „unverändert heißt unberührt“), keine wikitool-/search-Hinweise, kein <!-- Generated … -->-Kommentar (er stünde vor dem Frontmatter und bräche den Marker). Die Zusammenfassung kommt aus dem Frontmatter-Feld summary, sonst ist die Zelle leer (nie „TODO: add summary“). „Zuletzt geändert“ kommt aus modified, date oder created, sonst leer, nie aus der mtime der Datei. Gebaut: anchor und type_label wanderten von commands/index_build.py nach catalog.py (der Katalog importiert sie von dort), der Index selbst entsteht in tools/chemenu/export_index.py.
  5. Die Links im Index sind immer relative Markdown-Links, unabhängig von links:. Ein Index ohne Links routet nicht. links: text gilt weiter für die Seiten.
  6. Feste Beschriftungen auf Englisch, wie im Katalog unter kb/ (Page, Type, Summary, Last Modified, Pages, Collection, Area, Überschrift Index). Bereichstitel kommen wie im Katalog aus dem layout: der Type-Specs und sind damit in der KB-Sprache. Eine Übersetzung bräuchte einen neuen Schlüssel neben sections: in kb/CONVENTIONS.md. Das wäre ein eigenes Paket, falls gewünscht; es ist nicht angelegt.
  7. Marker und Commit. Jede Index-Datei beginnt mit einem Frontmatter, dessen einziger Schlüssel wikitool_export: "kind=index instance=<…> commit=<…>" ist, unabhängig von frontmatter:. INDEX_KIND = "index" steht neben PAGES_KIND in guideline_export.py (die eine Stelle, an der definiert ist, was ein Export ist). commit ist der neueste Commit der Seiten, die diese Datei auflistet; dafür liefert guideline_export.page_commit_history neben den Commits je Seite die Rangfolge der Commits aus demselben einen git log (page_commits bleibt als Hülle darum). So ändert sich die INDEX.md einer Collection nur, wenn sich eine ihrer Seiten ändert. index.md listet alle und ändert sich bei jedem Commit an einer ausgewählten Seite; das ist hinzunehmen. is_export/file_is_export, raw accept und die Digest-Sperre greifen ohne eigene Änderung.
  8. Index-Dateien sind gewöhnliche Dateien des Laufs. Sie stehen mit Digest im Manifest, werden atomar geschrieben, und der Spiegel entfernt sie, sobald sie nicht mehr erzeugt werden (index aus, Bereich unter die Schwelle gefallen, Collection leer). Beim Handler command bekommt der Konverter sie zusammen mit den Seiten. Die Ausgabe des Laufs nennt sie über ihren Pfad.
  9. Kollision von Groß- und Kleinschreibung. Die bestehende Prüfung in page_export.render (zwei Dateien, die sich nur in der Schreibweise unterscheiden) umfasst die Index-Pfade. Eine Seite kb/<c>/index.md neben <c>/INDEX.md ist ein Fehler des Ziels vor dem Schreiben, der beide nennt. OneDrive auf Windows würde sie zu einer Datei machen. Dasselbe gilt für eine verirrte Seite kb/Index.md neben index.md.

Konfiguration (Ausschnitt)

"targets": {
  "ganze-kb": {
    "handler": "markdown",
    "path": "C:\\Users\\<user>\\OneDrive - <Firma>\\Chemenu-KB",
    "include": "all",
    "index": true,
    "after_publish": true
  }
}

Akzeptanzkriterien

Veröffentlicht in 10.1.0-beta.21, Commit db09e89. Belegt durch pytest (3149 bestanden, 4 übersprungen), docs verify, instructions verify lokal und durch den CI-Lauf 756 (ci.yml) sowie den Lauf 757 (release.yml), beide grün auf diesem Commit. Die Tests stehen in test_export_run.py (Abschnitt „include "all" and the index files“) und test_config_shapes.py.

  • Alles: Mit include: "all" liegt im Ziel genau eine Datei je Seite aus load_pages_by_path. Der Testkorpus enthält eine verirrte Seite direkt unter kb/ (sie ist im Ziel) sowie kb/index.md, kb/log.md, kb/provenance.md, kb/CONTRACT.md, kb/CONVENTIONS.md, eine INDEX.md und eine COLLECTION.md (keine davon ist im Ziel).
  • Fehler: Ein fehlendes include, [], [[]], "All", "*" und "everything" sind je ein Fehler der Sektion (doctor FAIL, export run Exit 1, ohne Wirkung auf das Ziel). Die Meldung nennt "all" und die Listenform.
  • index: Ein nicht boolescher Wert ist ein Fehler der Sektion. Ohne index oder mit false liegt im Ziel keine Datei namens index.md oder INDEX.md.
  • Erreichbar: Mit index: true liegt index.md im Wurzelverzeichnis des Ziels. Jeder Link in jeder Index-Datei zeigt auf eine existierende Datei im Ziel (Anker eingeschlossen), und jede exportierte Seite ist von index.md aus über Links erreichbar. Getestet mit einem Bereich über SHARD_THRESHOLD (eigene Datei) und einem darunter (Anker).
  • Nur Exportiertes: Bei einer Teilauswahl nennt keine Index-Datei den Titel einer nicht exportierten Seite, und es gibt keine Index-Datei und keinen Tabelleneintrag für eine Collection oder einen Bereich ohne exportierte Seite.
  • Marker: Jede Index-Datei beginnt mit ---, ihr Frontmatter ist gültiges YAML mit wikitool_export als einzigem Schlüssel und kind=index darin. file_is_export ist für sie wahr, und raw accept lehnt sie ab (incoming/ und raw/ danach byte-gleich).
  • Idempotent: Ein zweiter Lauf ohne Änderung ändert keine mtime im Ziel, auch nicht die der Index-Dateien. Kein Index enthält ein Datum, das nicht aus einem Frontmatter stammt.
  • Lokal: Nach einem Commit, der nur eine Seite in Collection A ändert, ist die INDEX.md von Collection B byte-gleich.
  • Abschalten: Wird index von true auf false gesetzt, sind die Index-Dateien nach dem nächsten Lauf weg, und alle anderen Dateien im Ziel sind byte-gleich.
  • Kollision: Eine Seite kb/<c>/index.md mit index: true lässt das Ziel vor dem Schreiben scheitern, die Meldung nennt beide Pfade, und das Ziel ist byte-gleich.
  • links: text: Mit index: true enthalten die Seiten keinen Markdown-Link auf eine exportierte Seite, die Index-Dateien relative Links.
  • command: Das Eingabeverzeichnis des Konverters enthält mit index: true die Index-Dateien.
  • Doku und CI: Die Doku unter „Betroffene Dateien“ ist nachgezogen; pytest, docs verify und instructions verify sind lokal grün, der CI-Lauf 756 auf dem veröffentlichten Commit auch.

Abschlussprüfung

Gegen den veröffentlichten Stand gelesen: docs/explanation/architecture.md (Leser, der nicht fragen kann, bekommt eine Kopie), instructions/publish-cycle.md und docs/reference/commands/instance-health.md (die doctor-Zeile) bleiben richtig. Drei Stellen waren durch dieses Paket ungenau geworden und sind in 10.1.0-beta.22 (39514be, CI-Läufe 758 und 759 grün) nachgezogen: instructions/setup-instance.md und die Einleitung von docs/how-to/export-to-a-synced-folder.md boten nur „part of kb/“ an und nennen jetzt „part or all“, der Modul-Docstring von page_export.py behauptete, ein Commit an einer Seite schreibe nur deren Datei neu, und nennt jetzt die Index-Dateien, die sie listen. INSTALL.md nennt den Export nicht und brauchte nichts.

Versionsteil

MINOR. Drop-in-Test (instructions/dev/version-parts.md):

  • Vorwärts: Jede bestehende Konfiguration bleibt gültig und bedeutet dasselbe. index hat den Default false, und ein Lauf ohne die neuen Werte schreibt dasselbe wie vorher.
  • Rückwärts: Eine ältere Version liest eine Konfiguration mit "include": "all" oder index als fehlerhafte Sektion. doctor meldet FAIL, export run endet mit Exit 1, und publish stoppt vor dem Commit, wenn ein Ziel after_publish setzt. Das ist laut, nicht still. Mit der Konfiguration von vorher ist man wieder am Ausgangspunkt. Index-Dateien, die die neue Version ins Ziel geschrieben hat, stehen im Manifest. Die alte Version entfernt sie beim nächsten Lauf als „nicht mehr exportiert“.

Gebumpt als 10.1.0-beta.21 (laufender Kandidat, --minor), der Nachzug als 10.1.0-beta.22 (--patch, low).

Betroffene Dateien und Flächen

  • Code: tools/chemenu/config_shapes.py (EXPORT_INCLUDE_ALL, _export_include_problem, index, Feldbeschreibung, Beispiel), tools/chemenu/page_export.py (Target.include/index, select, render mit Index und Kollisionsprüfung, run), tools/chemenu/export_index.py (neu), tools/chemenu/guideline_export.py (INDEX_KIND, page_commit_history, export_marker), tools/chemenu/catalog.py und tools/chemenu/commands/index_build.py (geteilte Helfer, ROOT_COLLECTION), tools/chemenu/commands/export_cmd.py (Notizen des export run-Vertrags).
  • Tests: tools/chemenu/tests/test_export_run.py, tools/chemenu/tests/test_config_shapes.py, tools/chemenu/tests/test_index_build.py (Importe).
  • Generiert: Region wikitool:reference-config-export in docs/reference/configuration.md, tools/CONTRACT.md, docs/reference/commands/exports.md.
  • Steuerebene: raw/CONTRACT.md § „An export never comes back in“ (Datei statt Seite), instructions/setup-instance.md (Exportumfang, beim Abschluss).
  • Docs: docs/how-to/export-to-a-synced-folder.md, docs/reference/configuration.md (Prosa), tools/README.md (Modulzeilen).
  • CHANGES.md über version bump; die Bump-Zeilen sind der ganze Eintrag.

Bezug

#214 (Exporte; Entscheidungen 3, 8 und 13), #218 (Rohdokumente im Export)

Befund aus der Prüfung von Hand auf dem Windows-Arbeitsrechner (Betreiber, 2026-10-13, Stand 10.0.0), beim Einrichten eines Exportziels nach #214. Design abgeschlossen am 2026-10-16. **Abgeschlossen am 2026-10-16:** gebaut in 10.1.0-beta.21 (Commit `db09e89`, CI-Läufe 756 und 757 grün), Doku-Nachzug beim Abschluss in 10.1.0-beta.22 (Commit `39514be`, CI-Läufe 758 und 759 grün). ## Befund - Der Betreiber wollte die **ganze** KB nach OneDrive exportieren und fand keinen Weg dafür. Das How-to sagte: „Only what a target's `include` selects is written; there is no \"everything\".“ (`docs/how-to/export-to-a-synced-folder.md` § Pick the pages and the format). Derselbe Satz stand in der Feldbeschreibung `config_shapes.py` (`EXPORT`, Feld `targets`), aus der die Referenz-Region in `docs/reference/configuration.md` erzeugt wird. Der Text war also Code, nicht nur `docs/`-Prosa. - Gefunden hat er dann `include: [["collection:*"]]`. Das ist **fast** alles: `collection` ist der erste Pfadteil unter `kb/` (`search/filters.py`, `collection_of`). Eine `.md` direkt unter `kb/`, die keine Meta-Datei ist, zählt für `search` als Seite (`kb_scan.is_page_path`), hat aber die Collection `None` und fällt heraus. Eine solche Datei entsteht nur von Hand, `lint` meldet sie nicht. Im Demo-Korpus gibt es keine. - Im Ziel lagen nur die Seiten, ohne Index (#214 Entscheidung 8). Wer den Ordner in OneDrive öffnete, hatte keinen Einstieg außer der Ordnerstruktur. ## Entscheidungen 1. **Eigene Form `include: "all"` (Betreiber, 2026-10-16).** `include` ist entweder der String `"all"` oder wie bisher eine nicht leere Liste nicht leerer Auswahlen. `"all"` wählt genau die Seiten, die `search` ohne Prädikat kennt (`search.service.load_pages_by_path`), also auch eine verirrte Seite direkt unter `kb/`, nie eine generierte oder Meta-Datei (`kb/index.md`, `kb/log.md`, `kb/provenance.md`, `kb/CONTRACT.md`, `kb/CONVENTIONS.md`, `INDEX.md`, `COLLECTION.md`). - **#214 Entscheidung 3 bleibt:** „alle Seiten“ ist eine Benennung, weil sie ausdrücklich in der Zieldefinition steht. **Ein fehlendes `include`, `[]` und `[[]]` bleiben Fehler der Sektion**, ebenso jeder andere String (`"All"`, `"*"`, `"everything"`). Erwogen und verworfen: ein fehlendes oder leeres `include` als „alles“ zu lesen. Ein vergessenes Feld an einem Ziel mit `after_publish: true` würde dann nach dem nächsten `publish` die ganze KB ohne Rückfrage in einen Speicher schreiben, den Dritte lesen. So bricht dieselbe Lücke laut ab. - `[["collection:*"]]` funktioniert weiter, wird aber nicht als Weg dokumentiert. - Die Fehlermeldung für ein ungültiges `include` nennt beide erlaubten Formen (auch die für eine einzelne ungültige Auswahl). 2. **`doctor` bleibt unverändert (Betreiber, 2026-10-16).** Keine „all pages“-Angabe in der `export`-Zeile. 3. **Optionaler Index im Ziel (Betreiber, 2026-10-16), neues Feld `index`** je Ziel, Boolean, Default `false`, für beide Handler. Mit `index: true` erzeugt der Lauf Routing-Dateien aus den **ausgewählten** Seiten, nach derselben Hierarchie wie der Katalog unter `kb/` (`catalog.group_pages`, Schwelle `catalog.SHARD_THRESHOLD`): - `index.md` im Wurzelverzeichnis des Ziels, der Einstieg: Gesamtzahl, Tabelle der Collections mit Seitenzahl und Link auf deren `INDEX.md`, je Collection mit Bereichen die Tabelle der Bereiche mit Link (auf die eigene Bereichsdatei oder den Anker in der `INDEX.md` der Collection). - `<collection>/INDEX.md` je Collection, `<collection>/<bereich>/INDEX.md` für einen Bereich, den der Katalog in eine eigene Datei auslagern würde. Tabellen: Seite (Link) | Typ | Zusammenfassung | Zuletzt geändert. - **Nur was exportiert wird:** Eine Collection oder ein Bereich ohne ausgewählte Seite erscheint nicht (`group_pages` legt leere Collections von der Festplatte an; die werden verworfen). Eine Seite direkt unter `kb/` steht in einer eigenen Tabelle in `index.md` („Pages outside any collection“), ohne eigene Datei. - #214 Entscheidung 8 („Keine generierten Index-Dateien“) gilt damit nur noch für `index: false`. Die Dateien unter `kb/` werden **nicht** kopiert: Bei einer Teilauswahl nennen sie Seiten, die nicht exportiert werden, deren Titel die KB damit verlassen würden, und ihre Links zeigten ins Leere. 4. **Inhalt eines Index im Ziel: deterministisch und ohne Agenten-Text.** Kein `date.today()` (das bräche „unverändert heißt unberührt“), keine `wikitool`-/`search`-Hinweise, kein `<!-- Generated … -->`-Kommentar (er stünde vor dem Frontmatter und bräche den Marker). Die Zusammenfassung kommt aus dem Frontmatter-Feld `summary`, sonst ist die Zelle leer (nie „TODO: add summary“). „Zuletzt geändert“ kommt aus `modified`, `date` oder `created`, sonst leer, **nie** aus der mtime der Datei. Gebaut: `anchor` und `type_label` wanderten von `commands/index_build.py` nach `catalog.py` (der Katalog importiert sie von dort), der Index selbst entsteht in `tools/chemenu/export_index.py`. 5. **Die Links im Index sind immer relative Markdown-Links**, unabhängig von `links:`. Ein Index ohne Links routet nicht. `links: text` gilt weiter für die Seiten. 6. **Feste Beschriftungen auf Englisch, wie im Katalog unter `kb/`** (`Page`, `Type`, `Summary`, `Last Modified`, `Pages`, `Collection`, `Area`, Überschrift `Index`). Bereichstitel kommen wie im Katalog aus dem `layout:` der Type-Specs und sind damit in der KB-Sprache. Eine Übersetzung bräuchte einen neuen Schlüssel neben `sections:` in `kb/CONVENTIONS.md`. Das wäre ein eigenes Paket, falls gewünscht; es ist nicht angelegt. 7. **Marker und Commit.** Jede Index-Datei beginnt mit einem Frontmatter, dessen einziger Schlüssel `wikitool_export: "kind=index instance=<…> commit=<…>"` ist, unabhängig von `frontmatter:`. `INDEX_KIND = "index"` steht neben `PAGES_KIND` in `guideline_export.py` (die eine Stelle, an der definiert ist, was ein Export ist). `commit` ist der neueste Commit **der Seiten, die diese Datei auflistet**; dafür liefert `guideline_export.page_commit_history` neben den Commits je Seite die Rangfolge der Commits aus demselben einen `git log` (`page_commits` bleibt als Hülle darum). So ändert sich die `INDEX.md` einer Collection nur, wenn sich eine ihrer Seiten ändert. `index.md` listet alle und ändert sich bei jedem Commit an einer ausgewählten Seite; das ist hinzunehmen. `is_export`/`file_is_export`, `raw accept` und die Digest-Sperre greifen ohne eigene Änderung. 8. **Index-Dateien sind gewöhnliche Dateien des Laufs.** Sie stehen mit Digest im Manifest, werden atomar geschrieben, und der Spiegel entfernt sie, sobald sie nicht mehr erzeugt werden (`index` aus, Bereich unter die Schwelle gefallen, Collection leer). Beim Handler `command` bekommt der Konverter sie zusammen mit den Seiten. Die Ausgabe des Laufs nennt sie über ihren Pfad. 9. **Kollision von Groß- und Kleinschreibung.** Die bestehende Prüfung in `page_export.render` (zwei Dateien, die sich nur in der Schreibweise unterscheiden) umfasst die Index-Pfade. Eine Seite `kb/<c>/index.md` neben `<c>/INDEX.md` ist ein Fehler des Ziels vor dem Schreiben, der beide nennt. OneDrive auf Windows würde sie zu einer Datei machen. Dasselbe gilt für eine verirrte Seite `kb/Index.md` neben `index.md`. ## Konfiguration (Ausschnitt) ```json "targets": { "ganze-kb": { "handler": "markdown", "path": "C:\\Users\\<user>\\OneDrive - <Firma>\\Chemenu-KB", "include": "all", "index": true, "after_publish": true } } ``` ## Akzeptanzkriterien Veröffentlicht in 10.1.0-beta.21, Commit `db09e89`. Belegt durch `pytest` (3149 bestanden, 4 übersprungen), `docs verify`, `instructions verify` lokal und durch den CI-Lauf 756 (`ci.yml`) sowie den Lauf 757 (`release.yml`), beide grün auf diesem Commit. Die Tests stehen in `test_export_run.py` (Abschnitt „include "all" and the index files“) und `test_config_shapes.py`. - [x] **Alles:** Mit `include: "all"` liegt im Ziel genau eine Datei je Seite aus `load_pages_by_path`. Der Testkorpus enthält eine verirrte Seite direkt unter `kb/` (sie ist im Ziel) sowie `kb/index.md`, `kb/log.md`, `kb/provenance.md`, `kb/CONTRACT.md`, `kb/CONVENTIONS.md`, eine `INDEX.md` und eine `COLLECTION.md` (keine davon ist im Ziel). - [x] **Fehler:** Ein fehlendes `include`, `[]`, `[[]]`, `"All"`, `"*"` und `"everything"` sind je ein Fehler der Sektion (`doctor` FAIL, `export run` Exit 1, ohne Wirkung auf das Ziel). Die Meldung nennt `"all"` und die Listenform. - [x] **`index`:** Ein nicht boolescher Wert ist ein Fehler der Sektion. Ohne `index` oder mit `false` liegt im Ziel keine Datei namens `index.md` oder `INDEX.md`. - [x] **Erreichbar:** Mit `index: true` liegt `index.md` im Wurzelverzeichnis des Ziels. Jeder Link in jeder Index-Datei zeigt auf eine existierende Datei im Ziel (Anker eingeschlossen), und jede exportierte Seite ist von `index.md` aus über Links erreichbar. Getestet mit einem Bereich über `SHARD_THRESHOLD` (eigene Datei) und einem darunter (Anker). - [x] **Nur Exportiertes:** Bei einer Teilauswahl nennt keine Index-Datei den Titel einer nicht exportierten Seite, und es gibt keine Index-Datei und keinen Tabelleneintrag für eine Collection oder einen Bereich ohne exportierte Seite. - [x] **Marker:** Jede Index-Datei beginnt mit `---`, ihr Frontmatter ist gültiges YAML mit `wikitool_export` als einzigem Schlüssel und `kind=index` darin. `file_is_export` ist für sie wahr, und `raw accept` lehnt sie ab (`incoming/` und `raw/` danach byte-gleich). - [x] **Idempotent:** Ein zweiter Lauf ohne Änderung ändert keine mtime im Ziel, auch nicht die der Index-Dateien. Kein Index enthält ein Datum, das nicht aus einem Frontmatter stammt. - [x] **Lokal:** Nach einem Commit, der nur eine Seite in Collection A ändert, ist die `INDEX.md` von Collection B byte-gleich. - [x] **Abschalten:** Wird `index` von `true` auf `false` gesetzt, sind die Index-Dateien nach dem nächsten Lauf weg, und alle anderen Dateien im Ziel sind byte-gleich. - [x] **Kollision:** Eine Seite `kb/<c>/index.md` mit `index: true` lässt das Ziel vor dem Schreiben scheitern, die Meldung nennt beide Pfade, und das Ziel ist byte-gleich. - [x] **`links: text`:** Mit `index: true` enthalten die Seiten keinen Markdown-Link auf eine exportierte Seite, die Index-Dateien relative Links. - [x] **`command`:** Das Eingabeverzeichnis des Konverters enthält mit `index: true` die Index-Dateien. - [x] **Doku und CI:** Die Doku unter „Betroffene Dateien“ ist nachgezogen; `pytest`, `docs verify` und `instructions verify` sind lokal grün, der CI-Lauf 756 auf dem veröffentlichten Commit auch. ## Abschlussprüfung Gegen den veröffentlichten Stand gelesen: `docs/explanation/architecture.md` (Leser, der nicht fragen kann, bekommt eine Kopie), `instructions/publish-cycle.md` und `docs/reference/commands/instance-health.md` (die `doctor`-Zeile) bleiben richtig. Drei Stellen waren durch dieses Paket ungenau geworden und sind in 10.1.0-beta.22 (`39514be`, CI-Läufe 758 und 759 grün) nachgezogen: `instructions/setup-instance.md` und die Einleitung von `docs/how-to/export-to-a-synced-folder.md` boten nur „part of `kb/`“ an und nennen jetzt „part or all“, der Modul-Docstring von `page_export.py` behauptete, ein Commit an einer Seite schreibe nur deren Datei neu, und nennt jetzt die Index-Dateien, die sie listen. `INSTALL.md` nennt den Export nicht und brauchte nichts. ## Versionsteil **MINOR.** Drop-in-Test (`instructions/dev/version-parts.md`): - Vorwärts: Jede bestehende Konfiguration bleibt gültig und bedeutet dasselbe. `index` hat den Default `false`, und ein Lauf ohne die neuen Werte schreibt dasselbe wie vorher. - Rückwärts: Eine ältere Version liest eine Konfiguration mit `"include": "all"` oder `index` als fehlerhafte Sektion. `doctor` meldet FAIL, `export run` endet mit Exit 1, und `publish` stoppt vor dem Commit, wenn ein Ziel `after_publish` setzt. Das ist laut, nicht still. Mit der Konfiguration von vorher ist man wieder am Ausgangspunkt. Index-Dateien, die die neue Version ins Ziel geschrieben hat, stehen im Manifest. Die alte Version entfernt sie beim nächsten Lauf als „nicht mehr exportiert“. Gebumpt als `10.1.0-beta.21` (laufender Kandidat, `--minor`), der Nachzug als `10.1.0-beta.22` (`--patch`, low). ## Betroffene Dateien und Flächen - **Code:** `tools/chemenu/config_shapes.py` (`EXPORT_INCLUDE_ALL`, `_export_include_problem`, `index`, Feldbeschreibung, Beispiel), `tools/chemenu/page_export.py` (`Target.include`/`index`, `select`, `render` mit Index und Kollisionsprüfung, `run`), `tools/chemenu/export_index.py` (neu), `tools/chemenu/guideline_export.py` (`INDEX_KIND`, `page_commit_history`, `export_marker`), `tools/chemenu/catalog.py` und `tools/chemenu/commands/index_build.py` (geteilte Helfer, `ROOT_COLLECTION`), `tools/chemenu/commands/export_cmd.py` (Notizen des `export run`-Vertrags). - **Tests:** `tools/chemenu/tests/test_export_run.py`, `tools/chemenu/tests/test_config_shapes.py`, `tools/chemenu/tests/test_index_build.py` (Importe). - **Generiert:** Region `wikitool:reference-config-export` in `docs/reference/configuration.md`, `tools/CONTRACT.md`, `docs/reference/commands/exports.md`. - **Steuerebene:** `raw/CONTRACT.md` § „An export never comes back in“ (Datei statt Seite), `instructions/setup-instance.md` (Exportumfang, beim Abschluss). - **Docs:** `docs/how-to/export-to-a-synced-folder.md`, `docs/reference/configuration.md` (Prosa), `tools/README.md` (Modulzeilen). - `CHANGES.md` über `version bump`; die Bump-Zeilen sind der ganze Eintrag. ## Bezug #214 (Exporte; Entscheidungen 3, 8 und 13), #218 (Rohdokumente im Export)
torben added the prio/plannedsize/Sarea/kbkind/decision labels 2026-10-13 11:52:30 +00:00
torben changed title from Export der ganzen KB: ausdrückliche Auswahl „alle Seiten“ – `collection:*` dokumentieren oder ein eigenes `include: "all"` to Export der ganzen KB und Index im Ziel: `include: "all"` und optionales `index` als Routing ab einer `index.md` 2026-10-16 13:17:34 +00:00
torben added size/Mkind/build and removed size/Skind/decision labels 2026-10-16 13:17:34 +00:00
Author
Owner

Changelog: Design abgeschlossen (Betreiber, 2026-10-16). Variante (b) gewählt: include: "all"; fehlendes oder leeres include bleibt ein Fehler. Variante (a), also nur [["collection:*"]] dokumentieren, ist verworfen: Eine Seite direkt unter kb/ fiele heraus, und „there is no everything“ ist Code in config_shapes.py, keine reine Doku. Ebenfalls verworfen: ein fehlendes include als „alles“ zu lesen (Risiko mit after_publish). Die doctor-Zeile entfällt. Neu im Umfang: ein optionaler Index im Ziel (index: true) als Routing ab index.md, der #214 Entscheidung 8 für diesen Fall aufhebt. Akzeptanzkriterien und betroffene Dateien neu, Versionsteil MINOR statt „kein Bump/PATCH“. Labels: kind/decision → kind/build, size/S → size/M.

**Changelog:** Design abgeschlossen (Betreiber, 2026-10-16). Variante (b) gewählt: `include: "all"`; fehlendes oder leeres `include` bleibt ein Fehler. Variante (a), also nur `[["collection:*"]]` dokumentieren, ist verworfen: Eine Seite direkt unter `kb/` fiele heraus, und „there is no everything“ ist Code in `config_shapes.py`, keine reine Doku. Ebenfalls verworfen: ein fehlendes `include` als „alles“ zu lesen (Risiko mit `after_publish`). Die `doctor`-Zeile entfällt. Neu im Umfang: ein optionaler Index im Ziel (`index: true`) als Routing ab `index.md`, der #214 Entscheidung 8 für diesen Fall aufhebt. Akzeptanzkriterien und betroffene Dateien neu, Versionsteil MINOR statt „kein Bump/PATCH“. Labels: `kind/decision` → `kind/build`, `size/S` → `size/M`.
Author
Owner

Changelog: Gebaut und veröffentlicht in 10.1.0-beta.21 (Commit db09e89), CI grün (Läufe 756 und 757). Alle Akzeptanzkriterien abgehakt. Im Body ergänzt: Entscheidung 1 (die Fehlermeldung nennt beide Formen auch bei einer einzelnen ungültigen Auswahl), Entscheidung 4 (anchor und type_label liegen jetzt in catalog.py, der Index in export_index.py), Entscheidung 7 (page_commit_history liefert die Commit-Rangfolge aus demselben git log), Entscheidung 9 (auch eine verirrte Seite kb/Index.md kollidiert mit index.md). Keine Abweichung vom Design.

**Changelog:** Gebaut und veröffentlicht in 10.1.0-beta.21 (Commit `db09e89`), CI grün (Läufe 756 und 757). Alle Akzeptanzkriterien abgehakt. Im Body ergänzt: Entscheidung 1 (die Fehlermeldung nennt beide Formen auch bei einer einzelnen ungültigen Auswahl), Entscheidung 4 (`anchor` und `type_label` liegen jetzt in `catalog.py`, der Index in `export_index.py`), Entscheidung 7 (`page_commit_history` liefert die Commit-Rangfolge aus demselben `git log`), Entscheidung 9 (auch eine verirrte Seite `kb/Index.md` kollidiert mit `index.md`). Keine Abweichung vom Design.
Author
Owner

Changelog: Abgeschlossen. Neu im Body: Abschnitt „Abschlussprüfung“ mit dem Nachzug in 10.1.0-beta.22 (39514be, CI-Läufe 758 und 759 grün; setup-instance.md und How-to nennen „part or all of kb/“, der page_export.py-Docstring die Index-Dateien). Befund in die Vergangenheit gesetzt, Stand-Zeile auf abgeschlossen.

**Changelog:** Abgeschlossen. Neu im Body: Abschnitt „Abschlussprüfung“ mit dem Nachzug in 10.1.0-beta.22 (`39514be`, CI-Läufe 758 und 759 grün; `setup-instance.md` und How-to nennen „part or all of `kb/`“, der `page_export.py`-Docstring die Index-Dateien). Befund in die Vergangenheit gesetzt, Stand-Zeile auf abgeschlossen.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#217