--- type: types/source.md source_type: transcript author: Claude Code (claude-opus-5) raw_files: ['raw/notes/Conversation Transcript - Versioning, CI-CD and Content Migration Session 2026-08-30.md'] source_language: en date: 2026-08-30 tags: [versioning, ci-cd, migration, gitea, wikitool, release] entities: [wikitool, Chemenu, Act Runner, Gitea Actions, Gitea, Gitea MCP Server, Claude Code] concepts: [KB Stack Versioning, KB Migration, Mass-Update Gate, CI Integration] summary: Sitzung, die Stack-Versionierung mit CI und Release-Artefakten baut, sie um eine getrennte KB-Versionierung mit Migrationskette ergaenzt und die Gitea-Actions-Pipeline in Betrieb nimmt fidelity: verbatim authority: reporting --- # Source: Conversation - Versioning CI-CD and Content Migration Session 2026-08-30 **Autor:** Claude Code (claude-opus-5) **Datum:** 2026-08-30 **Raw-Dateien:** raw/notes/Conversation Transcript - Versioning, CI-CD and Content Migration Session 2026-08-30.md **Typ:** Notes ## Zusammenfassung Das Transkript ist eine vom Assistenten am Sitzungsende rekonstruierte Zusammenfassung, kein wörtliches Protokoll; Befehlsausgaben darin sind echt, Torbens Fragen und Entscheidungen sind eng wiedergegeben, die Begründungen des Assistenten verdichtet. Die Sitzung lief vom 2026-08-29 bis 2026-08-30 und deckt drei Arbeitspakete ab, die sich als dieselbe Mechanik von verschiedenen Seiten erwiesen: Versionierung des Stacks mit CI und Release-Artefakten (ausgeliefert als `0.1.0`, dann `1.0.0`), eine darauf aufsetzende Content-Migrationsstrategie und schließlich das Inbetriebnehmen der Pipeline. Resultierende Commits: `2508f7a`, `7d63d61`, `c3034ab`, `db03b08`, `aace3e7`, `401d700`, `b94166b`. Der erste Entwurf versionierte nur den Stack. Torben verwarf ihn mit der Frage, wo die aktuelle Version einer KB gespeichert wird und wie eine KB über mehrere Versionen hinweg aktualisiert wird. Das legte einen Fehler offen: Stack- und Content-Version waren zusammengeworfen, obwohl eine Instanz Maschinerie `1.4.0` tragen kann, während ihr Inhalt noch in `1.2.0`-Form vorliegt - genau der Zustand, den jedes Upgrade durchläuft. Der zweite Entwurf trennt drei Fakten in drei Dateien und baut die Migrationskette als geordnetes Intervall. Er wurde freigegeben und umgesetzt. Parallel wurde die Gitea-Actions-Pipeline gegen den Runner auf `ci-runner.example.net` gebracht. Die Diagnose über den neu verfügbaren Gitea-MCP-Server ergab das Gegenteil der Annahme: Die Runner hatten die Workflows die ganze Zeit angenommen und scheiterten am Checkout, weil `actions/checkout` eine JavaScript-Action ist, die act_runner mit `node` im Job-Container ausführt - und das gepinnte `debian:trixie-slim` bringt keins mit. Der erste Lauf, der bis `pytest` kam, fand einen echten Fehler in zwei Tests, die auf jeder Entwicklermaschine monatelang grün gewesen waren. ## Kernaussagen - **Die Version beschreibt den Stack; der Content hat seine eigene Version.** Drei Fakten, drei Dateien: `VERSION` (welche Maschinerie installiert ist, geschrieben von `version bump`), `.wikitool-release.json` (woher sie kam, erzeugt von `dist export`) und `.wikitool-kb.json` (in welcher Form der Inhalt vorliegt, geschrieben von `migrate done`). Getrennte Dateien, weil der Release-Stempel erzeugt ist und nie von Hand geändert werden darf, der KB-Zustand dagegen veränderlicher Instanzzustand ist. - **Kompatibilität ist die linkeste Nicht-Null-Komponente** - dieselbe Regel, die Cargos Caret-Ranges verwenden. Sie gilt einheitlich für `0.x` und `1.x`; ab `1.0.0` liest sie sich als gewöhnliches Semver. Keine Pre-Release-Suffixe, weil eine zweite Ordnungsregel vom Release-Feed, von der Migrationskette und von der Kompatibilitätsprüfung gleichermaßen befolgt werden müsste. - **Die Migrationskette ist ein Intervall, keine Fallunterscheidung.** `migrate status` bildet `(kb_version, VERSION]` aus den Migrationsdokumenten und ordnet aufsteigend; von `1.3.1` nach `2.0.0` laufen `1.4.0`, `1.7.0`, `2.0.0` nacheinander. Dass keine Migration auf `1.3.x` zielt, ist kein Sonderfall, sondern schlicht nicht im Intervall. `migrate done` verweigert jede Version, die nicht das nächste Glied ist - damit ist ein Sprung unmöglich und ein unterbrochenes mehrstufiges Upgrade fortsetzbar. - **Zählen, nicht Mengen vergleichen.** `kb_scan.extract_wikilinks()` liefert ein Set. Das ist richtig für `lint` (löst der Verweis auf?) und falsch für eine Migrationsprüfung (ist einer verschwunden?). Drei der vier Defekte, die die frühere Übersetzung fand, hatten unveränderte Link-Mengen und nur veränderte Zählungen. - **Der Runner nahm die Workflows immer an.** `actions/checkout` ist eine JavaScript-Action, die act_runner mit `node` **im Job-Container** ausführt; das gepinnte `debian:trixie-slim` hat keins, daher `exec: "node": executable file not found in $PATH` und `exitcode '127'`. Die Lösung war eine Zeile in einer apt-Liste: `nodejs` **vor** dem Checkout installieren, plus `actions/checkout@v7`. `runs-on: linux-docker` blieb, weil die Läufe 46-51 bewiesen, dass das Label routet und den Container startet. - **Ein CI-Lauf ist Evidenz, ein lokaler Lauf ist Gewohnheit.** Lauf 52 kam als erster bis `pytest` und ließ zwei von 630 Tests fallen: `config.default_author()` ruft `git config user.name` mit `cwd=config.ROOT`, das Fixture-Root ist kein Repository, also antwortete die globale git-Konfiguration dessen, der die Suite ausführte. Im Container als root gibt es keine. Behoben in den Tests, nicht durch eine git-Identität für CI: Das hätte den Lauf grün gemacht und den Fehler stehen gelassen. - **Das Origin-Repository ist privat, und Gitea antwortet anonym identisch** mit `404` für ein unsichtbares und für ein nicht existierendes Repository. `curl` beweist damit nichts über den CI-Zustand; Läufe werden über den Gitea-MCP-Server gelesen. `WIKITOOL_UPDATE_TOKEN` ist dadurch Voraussetzung statt Ausnahme. - **`${{ gitea.token }}` genügt für Releases, Tags und Asset-Uploads.** Kein Actions-Secret mit `write:repository` nötig. Belegt dadurch, dass `release.yml` beim Versionssprung auf `1.0.1` von selbst feuerte und `llm-wiki-stack-1.0.1.tar.gz` samt `.sha256` hochlud. - **`paths-ignore` scheitert bewusst offen.** Die Liste steht zweimal statt einmal über einen YAML-Anker, weil GitHubs Parser Anker ablehnt und Gitea sie nicht dokumentiert akzeptiert; es gibt keine `!**/CONTRACT.md`-Negation, weil Gitea negierte Filtermuster nicht dokumentiert; und `kb/CONTRACT.md` ist absichtlich nicht ausgenommen, weil es unter einem Content-Verzeichnis liegt, aber zum Stack gehört. Alles Unvorhergesehene löst weiterhin CI aus. - **Die verworfene Methodik lag im git-Verlauf.** Der geschlossene Workshop `translate-kb-de` wurde aus `de0862f` zurückgeholt und trug eine vollständige Arbeitsweise: Einheiten nach dem Iterationsbudget geschnitten, Batches getrennt davon nach dem Mass-Update Gate, Frontmatter/H1/ Wikilink-Ziele/Cite-IDs vor allem anderen gegen `HEAD` geprüft, `lint` über jede Einheit vollständig gelesen, und Zusammenfassungen von der orchestrierenden Sitzung geschrieben statt von einem Subagenten übernommen. ## Aufgaben - [ ] Gitea-Issue #7 - `dist upgrade` bauen (in dieser Sitzung bewusst zurückgestellt) - [ ] Gitea-Issue #8 - Testsuite gegen stille Umgebungsabhängigkeiten härten - [ ] Gitea-Issue #9 - nächtlichen Drift-Check einrichten - [ ] Gitea-Issue #10 - Coverage - [ ] Gitea-Issue #11 - bestätigen, dass Gitea die `paths-ignore`-Muster wie erwartet auswertet; ausdrücklich als Beobachtung geführt, nicht als Bauaufgabe - der Beleg kommt beim nächsten reinen Content-Publish von selbst ## Nicht übernommen - **Die turn-für-turn-Struktur des Transkripts.** Der Verlauf der Sitzung ist Chronologie, keine dauerhafte Aussage; die Entscheidungen wurden auf die Concept- und Entity-Seiten gehoben, die Reihenfolge blieb hier. - **Die Commit-Hashes einzelner Zwischenschritte** (`2508f7a`, `7d63d61`, `db03b08`) über die Zusammenfassung hinaus. Der git-Verlauf und `CHANGES.md` führen sie bereits; eine zweite Kopie in `kb/` wäre der driftende Doppeleintrag, den der Stack sonst überall vermeidet. - **Die Modul- und Dateiliste der Implementierung** (`corpus_diff.py`, `kb_state.py`, `migrate_cmd.py`) unterhalb dessen, was die Concept-Seiten zum Verständnis brauchen. Die Codestruktur ist im Repository nachlesbar und veraltet in `kb/` schneller als dort. - **Die Zahlen der Verifikationsläufe** (248 verglichene Seiten, 2,2 s, 630 Tests, 29 gezählte Dateien am Mass-Update Gate). Sie belegen einen Stichtag, nicht eine Eigenschaft; nur die Negativkontrolle `'Docker' 2->1` bei gleichzeitig stillem `lint` wurde übernommen, weil sie die Aussage trägt, auf der die Strategie ruht. - **Die Korrektur der Modellzuschreibung** in der Kopfzeile des Transkripts (erste Fassung nannte „Claude Sonnet 5", das Sitzungslog `claude-opus-5`). Sie betrifft die Quelle selbst und ist über `author:` bereits festgehalten. ## Verwandte Entities - [[wikitool]] - [[Chemenu]] - [[Act Runner]] - [[Gitea Actions]] - [[Gitea]] - [[Gitea MCP Server]] - [[Claude Code]] ## Verwandte Concepts - [[KB Stack Versioning]] - [[KB Migration]] - [[Mass-Update Gate]] - [[CI Integration]]