Gitea-Wiki als generierter Spiegel von docs/: CI schreibt ihn bei jedem Release #192

Closed
opened 2026-10-06 17:45:57 +00:00 by torben · 3 comments
Owner

Paket E aus #185 (E1, N1 (a)). Die Struktur, die gespiegelt wird, steht seit #187 (geschlossen 2026-10-06). Betrifft nur das Ursprungs-Repo; nichts davon wird ausgeliefert.

Stand: Gebaut und veröffentlicht als 9.0.0-beta.13: Commit 90ea0ee (Konverter, Push-Skript, Workflows, Tests, Doku) und Commit 1a954be (Workflows fordern permissions: wiki: write an), CI-Läufe 607/608 und 612 grün, darin der neue --check-Schritt. Der erste Dispatch-Lauf 609 scheiterte mit HTTP 403 beim Anlegen der ersten Wiki-Seite, weil dem Job-Token der Scope wiki fehlte; mit wiki: write gelang Dispatch-Lauf 613 (Wiki angelegt und gefüllt, 10 Seiten für v8.0.0), und der zweite Dispatch, Lauf 615, meldete „Wiki already matches v8.0.0“ ohne neuen Commit. Ein Secret ist nicht nötig. Beim Abschluss nachgezogen: docs/dev/development.md nennt den Token-Scope und das Anlegen der ersten Seite über die API (Commit 765ebe9, nur Doku, kein Bump; CI-Lauf 616 grün). Alle Kriterien erfüllt; der erste echte Lauf des Release-Jobs wiki-mirror ist der 9.0.0-Release.

Was gebaut wurde

Das Gitea-Wiki von torben/chemenu zeigt die Doku des jeweils letzten Releases. Es ist ein Spiegel, nie eine Quelle: Jede Änderung im Wiki wird beim nächsten Lauf überschrieben, und keine Sitzung schreibt hinein (Invariante 5 – das Wiki ist ein eigenes Git-Repo, ein Push dorthin neben publish wäre genau das Verbotene). Geschrieben wird nur von CI.

  1. Auslöser, zwei Wege, ein Ablauf:
    • Automatisch: ein eigener Job wiki-mirror in .gitea/workflows/release.yml, needs: release, der nur läuft, wenn der Job release ein Release erzeugt hat (also nicht bei einem -beta.N-Kandidaten; dafür hat release outputs: für skip, version, tag). Weil es ein eigener Job ist, lässt ein Fehlschlag des Spiegels das Release stehen – das Release ist das Produkt, der Spiegel eine Ansicht. Der Job meldet im Log ausdrücklich „Release vX is published; only the wiki mirror failed“ und scheitert rot.
    • Von Hand (D1): .gitea/workflows/wiki-mirror.yml mit workflow_dispatch, Eingabe tag (Vorgabe: das neueste Release, über die Release-API ermittelt). Er checkt den Workflow-Commit aus (Konverter und Push-Skript von dort) und den Tag in ein zweites Verzeichnis als Eingabe, und läuft dann wie der Job. Zweck: den Spiegel ohne Release erstmals füllen und verifizieren, und einen fehlgeschlagenen Spiegel nachholen, ohne ein Release zu wiederholen.
    • Beide rufen dieselben zwei Skripte auf (Punkt 2 und 3); kein Ablaufschritt steht doppelt im YAML. Beide Jobs fordern permissions: contents: write und wiki: write an.
  2. Konverter .gitea/scripts/wiki_mirror.py (neben dem vorhandenen start-radicale.sh). Entschieden: dort, nicht unter tools/ – dist export kopiert .gitea/ überhaupt nicht (nur ROOT_FILES und die Stufen), also braucht es keinen Eintrag in dist_cmd.TOOLS_DEV_ONLY und keine Änderung an tools/chemenu/commands/dist_cmd.py. Reines Python 3 aus der Standardbibliothek, kein Import aus chemenu. Aufruf: wiki_mirror.py --source <baum> --out <verzeichnis> --version <X.Y.Z> [--check]. Eingabe: der Baum am Tag. Ausgabe: ein Verzeichnis, das 1:1 der Inhalt des Wiki-Repos wird. --check schreibt nichts und scheitert nur bei Kollision oder unauflösbarem Link.
    • Seitenmenge: jede *.md unter docs/ (einschließlich docs/dev/ – das Ursprungs-Wiki zeigt beide Zielgruppen, E2), dazu README.md (als Home.md) und INSTALL.md (als Install.md, falls vorhanden). Andere Dateien unter docs/ werden nicht gespiegelt (heute gibt es keine). Die Regel gilt für jeden Baum, auch für v8.0.0 mit flachem docs/*.md und DEVELOPMENT.md an der Wurzel (dort keine gespiegelte Datei; ein Link darauf wird zur Tag-URL).
    • Seitennamen: flach, weil Gitea-Wiki-Seiten in Unterverzeichnissen nicht verlässlich gelistet werden. Regel: die Pfadsegmente unterhalb von docs/, .md entfernt, jedes Segment mit großem Anfangsbuchstaben, sonst unverändert, mit - verbunden; eine README.md steht für ihr Verzeichnis. Beispiele: docs/how-to/ingest-a-source.md → How-to-Ingest-a-source.md; docs/how-to/README.md → How-to.md; docs/reference/commands/pages.md → Reference-Commands-Pages.md, docs/reference/commands/README.md → Reference-Commands.md; docs/dev/development.md → Dev-Development.md. Deterministisch; zwei Quellen auf denselben Namen – auch nur in Groß-/Kleinschreibung verschieden – brechen den Lauf mit beiden Pfaden in der Meldung ab, ebenso eine Kollision mit Home, Install oder _Sidebar.
    • Links: relative Links zwischen gespiegelten Dateien werden auf den Wiki-Seitennamen ohne .md umgeschrieben (Anker bleiben, [x](../reference/commands/pages.md#foo) → [x](Reference-Commands-Pages#foo)). Relative Links auf alles andere (AGENTS.md, tools/CONTRACT.md, tools/chemenu/telemetry/schema.py, .vibe/hooks.toml, LICENSE …) werden zu absoluten Repo-URLs auf den Release-Tag (https://gitea.nehmer.net/torben/chemenu/src/tag/v<version>/<pfad>), damit sie zum gespiegelten Stand passen. Ein relativer Link, dessen Ziel im Baum nicht existiert, bricht ab. Externe Links (https:, mailto:) und reine Anker (#foo) bleiben. Links in Code-Blöcken und Inline-Code werden nicht angefasst.
      • Beim Bau geprüft: Gitea löst einen nackten Seitennamen im Wiki richtig auf. Die gerenderte Home-Seite des Wikis verlinkt Install auf /torben/chemenu/wiki/Install und Knowledge-and-commitment auf /torben/chemenu/wiki/Knowledge-and-commitment; die absolute Wiki-URL ist nicht nötig, die Regel bleibt.
    • Generiert: _Sidebar.md – Home, Install, dann die Bereiche in fester Reihenfolge (Tutorials, How-to, Reference mit Commands als Unterliste, Explanation), zuletzt der Entwicklerteil (Dev-…); Seiten ohne Bereich (flaches docs/ alter Tags) unter einer eigenen Gruppe „Documentation“; innerhalb einer Gruppe nach Seitenname sortiert. Auf jeder Seite ein Kopfhinweis als erste Zeile: „Generated from <pfad> at v – edit the repository, not this wiki.“ mit <pfad> als Tag-URL.
    • Generierte Regionsmarker (<!-- wikitool:… -->) und <!-- dist:strip-… -->-Marker in README.md/INSTALL.md bleiben als HTML-Kommentare stehen (Gitea rendert sie nicht); der Inhalt zwischen den Strip-Markern bleibt, weil das Ursprungs-Wiki die Entwicklerseite zeigt.
  3. Push .gitea/scripts/wiki-push.sh <ausgabe> <version>: Klon von …/chemenu.wiki.git, Arbeitsbaum außer .git/ leeren, Ausgabe des Konverters hineinkopieren, git add -A. Invariante: Danach enthält der Wiki-Baum genau die Dateien der Konverter-Ausgabe – keine übrig gebliebene Seite, keine fehlende. Ist der Index danach gegenüber HEAD unverändert, endet das Skript mit 0 ohne Commit („Wiki already matches v“). Sonst ein Commit „Mirror docs at v“ (Autor: ein fester CI-Name, nicht der Betreiber) und Push.
  4. CI-Prüfung bei jedem Push: ci.yml hat einen Schritt, der wiki_mirror.py --check gegen den Arbeitsbaum ausführt (Version aus VERSION). So fällt ein Link, den der Spiegel nicht auflösen kann, beim Publish auf und nicht erst beim Release.
  5. Voraussetzungen, im Build geklärt:
    • Das Wiki war eingeschaltet, aber leer. Ergebnis (Lauf 609): Der Klon eines nicht existierenden Wiki-Repos scheitert mit „wiki doesn't exist, please initialize the wiki by creating a new page first“, ein Push legt es also nicht an; wiki-push.sh legt die erste Seite über die API an (POST /repos/{owner}/{repo}/wiki/new) und klont danach. Mit dem richtigen Token gelungen (Lauf 613).
    • Ob ${{ gitea.token }} aufs Wiki-Repo schreiben darf. Ergebnis: Das Wiki hat in Gitea einen eigenen Token-Scope wiki, getrennt von contents; permissions: contents: write allein reicht nicht (Lauf 609: POST /wiki/new → HTTP 403). Mit permissions: wiki: write im Job (in release.yml und wiki-mirror.yml, Commit 1a954be) gelingt Anlegen, Klon und Push (Lauf 613). Eine Obergrenze in den Actions-Einstellungen des Repos greift nicht. Ein Secret ist nicht nötig; wiki-push.sh nennt in der Fehlermeldung bei leerem Token den Scope.

Entscheidung

D1 – Verifikation des Live-Teils: per Dispatch, nicht erst beim Release (Betreiber, 2026-10-07: Variante (a)). Das letzte Release ist v8.0.0, das nächste (9.0.0) schneidet der Betreiber. Ohne Dispatch liefe der Push-Pfad – leeres Wiki, Token-Recht, kein Commit beim zweiten Lauf – erst beim Release zum ersten Mal, und ein fehlgeschlagener Spiegel ließe sich nur mit dem nächsten Release nachholen. Mit wiki-mirror.yml verifiziert die Build-Sitzung den ganzen Pfad mit einem Dispatch auf v8.0.0; das öffentliche Wiki zeigt danach die Doku von 8.0.0, was der Definition „Doku des letzten Releases“ entspricht. Verworfen: (b) nur der Release-Job – weniger Code, aber Live-Kriterien und Issue bis 9.0.0 offen.

Version

PATCH, auf dem laufenden Kandidaten also der nächste -beta.N. Konverter und Workflows liegen unter .gitea/ und erreichen keine Instanz – version-parts.md: was nur das Ursprungs-Repo betrifft, ist kein Stack-Bruch. Aber die Tests liegen unter tools/chemenu/tests/, und das Version-Gate in ci.yml verlangt für jede Änderung unter tools/ einen Bump; ein Drop-in ist es trivial, weil nichts Ausgeliefertes sich ändert. Changelog: Bump-Titel genügt. Gebaut als 9.0.0-beta.13. Die Folge-Commits 1a954be (nur .gitea/) und 765ebe9 (nur docs/dev/) brauchen keinen Bump.

Dateien

  • neu: .gitea/scripts/wiki_mirror.py, .gitea/scripts/wiki-push.sh, .gitea/workflows/wiki-mirror.yml, tools/chemenu/tests/test_wiki_mirror.py (lädt das Skript per importlib über den Pfad)
  • geändert: .gitea/workflows/release.yml (Outputs des Jobs release, neuer Job wiki-mirror), .gitea/workflows/ci.yml (Schritt --check), docs/dev/development.md, README.md, VERSION/CHANGES.md per version bump

Akzeptanzkriterien

  • Tests des Konverters: die Namensregel liefert für jede Datei unter docs/ im heutigen Baum einen eindeutigen Namen, und zweimal auf denselben Baum angewandt ist die Ausgabe Byte für Byte gleich; jeder relative Link in der Ausgabe ist ein erzeugter Seitenname oder eine Tag-URL; eine absichtlich erzeugte Kollision (auch eine nur in Groß-/Kleinschreibung) und ein Link auf eine nicht vorhandene Datei brechen jeweils mit Exit ≠ 0 ab und nennen die Pfade; Links in Code-Blöcken bleiben unverändert; ein flaches docs/ ohne Bereiche (Form von v8.0.0) wird ohne Fehler gespiegelt. (27 Tests in test_wiki_mirror.py, grün in den CI-Läufen 607, 612 und 616.)
  • dist export in ein leeres Verzeichnis enthält weder .gitea/ noch wiki_mirror.py noch den Test. (Lokal geprüft; .gitea/ steht nicht in ROOT_FILES, der Test in TOOLS_DEV_ONLY.)
  • Der --check-Schritt in ci.yml läuft im CI-Lauf des Publish grün. (Läufe 607, 612 und 616.)
  • Nach einem Dispatch von wiki-mirror.yml auf v8.0.0 enthält das Wiki genau die Seiten aus Punkt 2 für diesen Tag und _Sidebar.md, jede Seite mit Kopfhinweis und Version; ein Link auf AGENTS.md führt auf src/tag/v8.0.0/AGENTS.md; ein Link zwischen zwei gespiegelten Seiten öffnet die Wiki-Seite. (Lauf 613: 10 Seiten, alle mit Commit „Mirror docs at v8.0.0“; gerenderte Home-Seite: Links auf Wiki-Seiten zeigen auf /torben/chemenu/wiki/<Name>, Links auf nicht gespiegelte Dateien auf src/tag/v8.0.0/<pfad>.)
  • Ein zweiter Dispatch auf denselben Tag erzeugt keinen Commit im Wiki-Repo. (Lauf 615: „Wiki already matches v8.0.0“.)
  • Der Job release hängt nicht von wiki-mirror ab (needs zeigt nur in die andere Richtung): ein Fehlschlag des Spiegels lässt Release und Tag bestehen, und das Run-Log benennt ihn als Spiegel-Fehler. Der Job selbst läuft erstmals beim 9.0.0-Release; bis dahin belegt der Dispatch denselben Skriptpfad. (Strukturell erfüllt; der erste echte Lauf ist 9.0.0.)
Paket E aus #185 (E1, N1 (a)). Die Struktur, die gespiegelt wird, steht seit #187 (geschlossen 2026-10-06). Betrifft nur das Ursprungs-Repo; nichts davon wird ausgeliefert. **Stand:** Gebaut und veröffentlicht als `9.0.0-beta.13`: Commit `90ea0ee` (Konverter, Push-Skript, Workflows, Tests, Doku) und Commit `1a954be` (Workflows fordern `permissions: wiki: write` an), CI-Läufe 607/608 und 612 grün, darin der neue `--check`-Schritt. Der erste Dispatch-Lauf 609 scheiterte mit HTTP 403 beim Anlegen der ersten Wiki-Seite, weil dem Job-Token der Scope `wiki` fehlte; mit `wiki: write` gelang Dispatch-Lauf 613 (Wiki angelegt und gefüllt, 10 Seiten für `v8.0.0`), und der zweite Dispatch, Lauf 615, meldete „Wiki already matches v8.0.0“ ohne neuen Commit. Ein Secret ist nicht nötig. Beim Abschluss nachgezogen: `docs/dev/development.md` nennt den Token-Scope und das Anlegen der ersten Seite über die API (Commit `765ebe9`, nur Doku, kein Bump; CI-Lauf 616 grün). Alle Kriterien erfüllt; der erste echte Lauf des Release-Jobs `wiki-mirror` ist der 9.0.0-Release. ## Was gebaut wurde Das Gitea-Wiki von `torben/chemenu` zeigt die Doku des jeweils letzten Releases. Es ist ein **Spiegel, nie eine Quelle**: Jede Änderung im Wiki wird beim nächsten Lauf überschrieben, und keine Sitzung schreibt hinein (Invariante 5 – das Wiki ist ein eigenes Git-Repo, ein Push dorthin neben `publish` wäre genau das Verbotene). Geschrieben wird nur von CI. 1. **Auslöser, zwei Wege, ein Ablauf:** - **Automatisch:** ein eigener Job `wiki-mirror` in `.gitea/workflows/release.yml`, `needs: release`, der nur läuft, wenn der Job `release` ein Release erzeugt hat (also nicht bei einem `-beta.N`-Kandidaten; dafür hat `release` `outputs:` für `skip`, `version`, `tag`). Weil es ein eigener Job ist, lässt ein Fehlschlag des Spiegels das Release stehen – das Release ist das Produkt, der Spiegel eine Ansicht. Der Job meldet im Log ausdrücklich „Release vX is published; only the wiki mirror failed“ und scheitert rot. - **Von Hand (D1):** `.gitea/workflows/wiki-mirror.yml` mit `workflow_dispatch`, Eingabe `tag` (Vorgabe: das neueste Release, über die Release-API ermittelt). Er checkt den Workflow-Commit aus (Konverter und Push-Skript von dort) und den Tag in ein zweites Verzeichnis als Eingabe, und läuft dann wie der Job. Zweck: den Spiegel ohne Release erstmals füllen und verifizieren, und einen fehlgeschlagenen Spiegel nachholen, ohne ein Release zu wiederholen. - Beide rufen dieselben zwei Skripte auf (Punkt 2 und 3); kein Ablaufschritt steht doppelt im YAML. Beide Jobs fordern `permissions: contents: write` und `wiki: write` an. 2. **Konverter** `.gitea/scripts/wiki_mirror.py` (neben dem vorhandenen `start-radicale.sh`). **Entschieden:** dort, nicht unter `tools/` – `dist export` kopiert `.gitea/` überhaupt nicht (nur `ROOT_FILES` und die Stufen), also braucht es keinen Eintrag in `dist_cmd.TOOLS_DEV_ONLY` und keine Änderung an `tools/chemenu/commands/dist_cmd.py`. Reines Python 3 aus der Standardbibliothek, kein Import aus `chemenu`. Aufruf: `wiki_mirror.py --source <baum> --out <verzeichnis> --version <X.Y.Z> [--check]`. Eingabe: der Baum am Tag. Ausgabe: ein Verzeichnis, das 1:1 der Inhalt des Wiki-Repos wird. `--check` schreibt nichts und scheitert nur bei Kollision oder unauflösbarem Link. - **Seitenmenge:** jede `*.md` unter `docs/` (einschließlich `docs/dev/` – das Ursprungs-Wiki zeigt beide Zielgruppen, E2), dazu `README.md` (als `Home.md`) und `INSTALL.md` (als `Install.md`, falls vorhanden). Andere Dateien unter `docs/` werden nicht gespiegelt (heute gibt es keine). Die Regel gilt für jeden Baum, auch für `v8.0.0` mit flachem `docs/*.md` und `DEVELOPMENT.md` an der Wurzel (dort keine gespiegelte Datei; ein Link darauf wird zur Tag-URL). - **Seitennamen:** flach, weil Gitea-Wiki-Seiten in Unterverzeichnissen nicht verlässlich gelistet werden. **Regel:** die Pfadsegmente unterhalb von `docs/`, `.md` entfernt, jedes Segment mit großem Anfangsbuchstaben, sonst unverändert, mit `-` verbunden; eine `README.md` steht für ihr Verzeichnis. Beispiele: `docs/how-to/ingest-a-source.md` → `How-to-Ingest-a-source.md`; `docs/how-to/README.md` → `How-to.md`; `docs/reference/commands/pages.md` → `Reference-Commands-Pages.md`, `docs/reference/commands/README.md` → `Reference-Commands.md`; `docs/dev/development.md` → `Dev-Development.md`. Deterministisch; zwei Quellen auf denselben Namen – **auch nur in Groß-/Kleinschreibung verschieden** – brechen den Lauf mit beiden Pfaden in der Meldung ab, ebenso eine Kollision mit `Home`, `Install` oder `_Sidebar`. - **Links:** relative Links zwischen gespiegelten Dateien werden auf den Wiki-Seitennamen ohne `.md` umgeschrieben (Anker bleiben, `[x](../reference/commands/pages.md#foo)` → `[x](Reference-Commands-Pages#foo)`). Relative Links auf alles andere (`AGENTS.md`, `tools/CONTRACT.md`, `tools/chemenu/telemetry/schema.py`, `.vibe/hooks.toml`, `LICENSE` …) werden zu absoluten Repo-URLs **auf den Release-Tag** (`https://gitea.nehmer.net/torben/chemenu/src/tag/v<version>/<pfad>`), damit sie zum gespiegelten Stand passen. Ein relativer Link, dessen Ziel im Baum nicht existiert, bricht ab. Externe Links (`https:`, `mailto:`) und reine Anker (`#foo`) bleiben. Links in Code-Blöcken und Inline-Code werden nicht angefasst. - *Beim Bau geprüft:* Gitea löst einen nackten Seitennamen im Wiki richtig auf. Die gerenderte Home-Seite des Wikis verlinkt `Install` auf `/torben/chemenu/wiki/Install` und `Knowledge-and-commitment` auf `/torben/chemenu/wiki/Knowledge-and-commitment`; die absolute Wiki-URL ist nicht nötig, die Regel bleibt. - **Generiert:** `_Sidebar.md` – `Home`, `Install`, dann die Bereiche in fester Reihenfolge (Tutorials, How-to, Reference mit Commands als Unterliste, Explanation), zuletzt der Entwicklerteil (`Dev-…`); Seiten ohne Bereich (flaches `docs/` alter Tags) unter einer eigenen Gruppe „Documentation“; innerhalb einer Gruppe nach Seitenname sortiert. Auf jeder Seite ein Kopfhinweis als erste Zeile: „*Generated from `<pfad>` at v<version> – edit the repository, not this wiki.*“ mit `<pfad>` als Tag-URL. - Generierte Regionsmarker (`<!-- wikitool:… -->`) und `<!-- dist:strip-… -->`-Marker in `README.md`/`INSTALL.md` bleiben als HTML-Kommentare stehen (Gitea rendert sie nicht); der Inhalt zwischen den Strip-Markern bleibt, weil das Ursprungs-Wiki die Entwicklerseite zeigt. 3. **Push** `.gitea/scripts/wiki-push.sh <ausgabe> <version>`: Klon von `…/chemenu.wiki.git`, Arbeitsbaum außer `.git/` leeren, Ausgabe des Konverters hineinkopieren, `git add -A`. **Invariante:** Danach enthält der Wiki-Baum genau die Dateien der Konverter-Ausgabe – keine übrig gebliebene Seite, keine fehlende. Ist der Index danach gegenüber `HEAD` unverändert, endet das Skript mit 0 ohne Commit („Wiki already matches v<version>“). Sonst ein Commit „Mirror docs at v<version>“ (Autor: ein fester CI-Name, nicht der Betreiber) und Push. 4. **CI-Prüfung bei jedem Push:** `ci.yml` hat einen Schritt, der `wiki_mirror.py --check` gegen den Arbeitsbaum ausführt (Version aus `VERSION`). So fällt ein Link, den der Spiegel nicht auflösen kann, beim Publish auf und nicht erst beim Release. 5. **Voraussetzungen, im Build geklärt:** - Das Wiki war eingeschaltet, aber leer. **Ergebnis (Lauf 609):** Der Klon eines nicht existierenden Wiki-Repos scheitert mit „wiki doesn't exist, please initialize the wiki by creating a new page first“, ein Push legt es also nicht an; `wiki-push.sh` legt die erste Seite über die API an (`POST /repos/{owner}/{repo}/wiki/new`) und klont danach. **Mit dem richtigen Token gelungen (Lauf 613).** - Ob `${{ gitea.token }}` aufs Wiki-Repo schreiben darf. **Ergebnis:** Das Wiki hat in Gitea einen eigenen Token-Scope `wiki`, getrennt von `contents`; `permissions: contents: write` allein reicht nicht (Lauf 609: `POST /wiki/new` → HTTP 403). Mit `permissions: wiki: write` im Job (in `release.yml` und `wiki-mirror.yml`, Commit `1a954be`) gelingt Anlegen, Klon und Push (Lauf 613). Eine Obergrenze in den Actions-Einstellungen des Repos greift nicht. Ein Secret ist nicht nötig; `wiki-push.sh` nennt in der Fehlermeldung bei leerem Token den Scope. ## Entscheidung **D1 – Verifikation des Live-Teils: per Dispatch, nicht erst beim Release** (Betreiber, 2026-10-07: Variante (a)). Das letzte Release ist `v8.0.0`, das nächste (`9.0.0`) schneidet der Betreiber. Ohne Dispatch liefe der Push-Pfad – leeres Wiki, Token-Recht, kein Commit beim zweiten Lauf – erst beim Release zum ersten Mal, und ein fehlgeschlagener Spiegel ließe sich nur mit dem nächsten Release nachholen. Mit `wiki-mirror.yml` verifiziert die Build-Sitzung den ganzen Pfad mit einem Dispatch auf `v8.0.0`; das öffentliche Wiki zeigt danach die Doku von 8.0.0, was der Definition „Doku des letzten Releases“ entspricht. Verworfen: (b) nur der Release-Job – weniger Code, aber Live-Kriterien und Issue bis 9.0.0 offen. ## Version **PATCH**, auf dem laufenden Kandidaten also der nächste `-beta.N`. Konverter und Workflows liegen unter `.gitea/` und erreichen keine Instanz – `version-parts.md`: was nur das Ursprungs-Repo betrifft, ist kein Stack-Bruch. Aber die Tests liegen unter `tools/chemenu/tests/`, und das Version-Gate in `ci.yml` verlangt für jede Änderung unter `tools/` einen Bump; ein Drop-in ist es trivial, weil nichts Ausgeliefertes sich ändert. Changelog: Bump-Titel genügt. **Gebaut als `9.0.0-beta.13`.** Die Folge-Commits `1a954be` (nur `.gitea/`) und `765ebe9` (nur `docs/dev/`) brauchen keinen Bump. ## Dateien - neu: `.gitea/scripts/wiki_mirror.py`, `.gitea/scripts/wiki-push.sh`, `.gitea/workflows/wiki-mirror.yml`, `tools/chemenu/tests/test_wiki_mirror.py` (lädt das Skript per `importlib` über den Pfad) - geändert: `.gitea/workflows/release.yml` (Outputs des Jobs `release`, neuer Job `wiki-mirror`), `.gitea/workflows/ci.yml` (Schritt `--check`), `docs/dev/development.md`, `README.md`, `VERSION`/`CHANGES.md` per `version bump` ## Akzeptanzkriterien - [x] Tests des Konverters: die Namensregel liefert für jede Datei unter `docs/` im heutigen Baum einen eindeutigen Namen, und zweimal auf denselben Baum angewandt ist die Ausgabe Byte für Byte gleich; jeder relative Link in der Ausgabe ist ein erzeugter Seitenname oder eine Tag-URL; eine absichtlich erzeugte Kollision (auch eine nur in Groß-/Kleinschreibung) und ein Link auf eine nicht vorhandene Datei brechen jeweils mit Exit ≠ 0 ab und nennen die Pfade; Links in Code-Blöcken bleiben unverändert; ein flaches `docs/` ohne Bereiche (Form von `v8.0.0`) wird ohne Fehler gespiegelt. *(27 Tests in `test_wiki_mirror.py`, grün in den CI-Läufen 607, 612 und 616.)* - [x] `dist export` in ein leeres Verzeichnis enthält weder `.gitea/` noch `wiki_mirror.py` noch den Test. *(Lokal geprüft; `.gitea/` steht nicht in `ROOT_FILES`, der Test in `TOOLS_DEV_ONLY`.)* - [x] Der `--check`-Schritt in `ci.yml` läuft im CI-Lauf des Publish grün. *(Läufe 607, 612 und 616.)* - [x] Nach einem Dispatch von `wiki-mirror.yml` auf `v8.0.0` enthält das Wiki genau die Seiten aus Punkt 2 für diesen Tag und `_Sidebar.md`, jede Seite mit Kopfhinweis und Version; ein Link auf `AGENTS.md` führt auf `src/tag/v8.0.0/AGENTS.md`; ein Link zwischen zwei gespiegelten Seiten öffnet die Wiki-Seite. *(Lauf 613: 10 Seiten, alle mit Commit „Mirror docs at v8.0.0“; gerenderte Home-Seite: Links auf Wiki-Seiten zeigen auf `/torben/chemenu/wiki/<Name>`, Links auf nicht gespiegelte Dateien auf `src/tag/v8.0.0/<pfad>`.)* - [x] Ein zweiter Dispatch auf denselben Tag erzeugt keinen Commit im Wiki-Repo. *(Lauf 615: „Wiki already matches v8.0.0“.)* - [x] Der Job `release` hängt nicht von `wiki-mirror` ab (`needs` zeigt nur in die andere Richtung): ein Fehlschlag des Spiegels lässt Release und Tag bestehen, und das Run-Log benennt ihn als Spiegel-Fehler. Der Job selbst läuft erstmals beim 9.0.0-Release; bis dahin belegt der Dispatch denselben Skriptpfad. *(Strukturell erfüllt; der erste echte Lauf ist 9.0.0.)*
torben added the prio/plannedsize/Marea/workflowkind/buildstatus/blocked labels 2026-10-06 17:45:57 +00:00
torben added kind/decision and removed kind/buildstatus/blocked labels 2026-10-07 20:18:37 +00:00
Author
Owner

Changelog: Body gegen den Baum von 45ae04c geprüft. status/blocked entfernt (#187 seit 2026-10-06 geschlossen). Namensregel auf beliebige Tiefe verallgemeinert – docs/reference/commands/ deckte <bereich>-<name> nicht ab – und Kollision um Groß-/Kleinschreibung erweitert. Konverter-Ort entschieden: .gitea/scripts/ (wird von dist export nicht kopiert, also keine Änderung an TOOLS_DEV_ONLY). Auslöser als eigener Job needs: release festgelegt. Neu: --check-Schritt in ci.yml, Invariante für den Push, Datei-Liste. Version korrigiert: PATCH ist ohnehin fällig, weil die Tests unter tools/ das Version-Gate auslösen. D1 (Verifikation des Live-Pfads) vom Betreiber entschieden: (a), zusätzlicher Dispatch-Workflow wiki-mirror.yml und gemeinsames wiki-push.sh; Live-Kriterien per Dispatch auf v8.0.0, Konverter muss das flache docs/ alter Tags können. Body baubereit, kind/build.

**Changelog:** Body gegen den Baum von `45ae04c` geprüft. `status/blocked` entfernt (#187 seit 2026-10-06 geschlossen). Namensregel auf beliebige Tiefe verallgemeinert – `docs/reference/commands/` deckte `<bereich>-<name>` nicht ab – und Kollision um Groß-/Kleinschreibung erweitert. Konverter-Ort entschieden: `.gitea/scripts/` (wird von `dist export` nicht kopiert, also keine Änderung an `TOOLS_DEV_ONLY`). Auslöser als eigener Job `needs: release` festgelegt. Neu: `--check`-Schritt in `ci.yml`, Invariante für den Push, Datei-Liste. Version korrigiert: PATCH ist ohnehin fällig, weil die Tests unter `tools/` das Version-Gate auslösen. D1 (Verifikation des Live-Pfads) vom Betreiber entschieden: (a), zusätzlicher Dispatch-Workflow `wiki-mirror.yml` und gemeinsames `wiki-push.sh`; Live-Kriterien per Dispatch auf `v8.0.0`, Konverter muss das flache `docs/` alter Tags können. Body baubereit, `kind/build`.
torben added kind/build and removed kind/decision labels 2026-10-07 20:33:32 +00:00
Author
Owner

Build-Sitzung: Gebaut und veröffentlicht als 9.0.0-beta.13 (Commits 90ea0ee, 1a954be). Neu: .gitea/scripts/wiki_mirror.py, .gitea/scripts/wiki-push.sh, .gitea/workflows/wiki-mirror.yml, tools/chemenu/tests/test_wiki_mirror.py; geändert: release.yml (Job wiki-mirror), ci.yml (--check), docs/dev/development.md, README.md. Abweichung vom Plan: Das Job-Token braucht den eigenen Scope permissions: wiki: write (nicht contents); ein Secret ist nicht nötig. CI grün (Läufe 607/608, 612); Dispatch auf v8.0.0 füllte das Wiki (Lauf 613), der zweite Dispatch erzeugte keinen Commit (Lauf 615). Body ist auf dem Stand, alle Kriterien erfüllt.

Build-Sitzung: Gebaut und veröffentlicht als `9.0.0-beta.13` (Commits `90ea0ee`, `1a954be`). Neu: `.gitea/scripts/wiki_mirror.py`, `.gitea/scripts/wiki-push.sh`, `.gitea/workflows/wiki-mirror.yml`, `tools/chemenu/tests/test_wiki_mirror.py`; geändert: `release.yml` (Job `wiki-mirror`), `ci.yml` (`--check`), `docs/dev/development.md`, `README.md`. Abweichung vom Plan: Das Job-Token braucht den eigenen Scope `permissions: wiki: write` (nicht `contents`); ein Secret ist nicht nötig. CI grün (Läufe 607/608, 612); Dispatch auf `v8.0.0` füllte das Wiki (Lauf 613), der zweite Dispatch erzeugte keinen Commit (Lauf 615). Body ist auf dem Stand, alle Kriterien erfüllt.
Author
Owner

Abschluss: docs/dev/development.md nennt jetzt den Token-Scope wiki: write und das Anlegen der ersten Wiki-Seite über die API (Commit 765ebe9, CI-Lauf 616 grün). Sonst war kein Dokument veraltet: Der Changelog-Eintrag 9.0.0-beta.13 stimmt, und an tools/CONTRACT.md oder einem Stufenvertrag wurde nichts geändert. Body im Endstand, alle Kriterien erfüllt.

Abschluss: `docs/dev/development.md` nennt jetzt den Token-Scope `wiki: write` und das Anlegen der ersten Wiki-Seite über die API (Commit `765ebe9`, CI-Lauf 616 grün). Sonst war kein Dokument veraltet: Der Changelog-Eintrag `9.0.0-beta.13` stimmt, und an `tools/CONTRACT.md` oder einem Stufenvertrag wurde nichts geändert. Body im Endstand, alle Kriterien erfüllt.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#192