Chemenu 2.1.0 - deterministischer Wissenskompiler
CI / verify (push) Failing after 32s
Release / release (push) Successful in 38s

Chemenu kompiliert Rohnotizen zu einem verlinkten, quellengebundenen Wiki:
raw/ -> types/ + tools/ -> kb/ -> reports/. Was mechanisch ist, macht
tools/wikitool; was Urteil braucht, macht ein Agent unter Contracts, deren
Grenzen in Code durchgesetzt sind statt im Prompt.

Dieser Commit ist der Startpunkt der oeffentlichen Historie. Die vorherige
Entwicklung fand in einer privaten Instanz statt und ist nicht Teil dieses
Repositorys; ihre Erzaehlung steht vollstaendig in CHANGES.md, das mit 44
Eintraegen von 0.1.0 bis 2.1.0 erhalten geblieben ist.

Der mitgelieferte Korpus ist ein Testbett und eine Demo: 170 Seiten ueber den
Stack selbst - Gates, Lint, Versionierung, Suche, das Wiki-Muster. Er
dokumentiert das Werkzeug mit den eigenen Mitteln des Werkzeugs.

Lizenz: AGPL-3.0 fuer den Stack (tools/, types/), CC-BY-4.0 fuer die Inhalte.
Die Grenze zwischen beiden ist der Dateiplan, den dist export berechnet -
siehe NOTICE.
This commit is contained in:
2026-09-01 16:24:34 +02:00
commit 18ae28f918
368 changed files with 50628 additions and 0 deletions
+285
View File
@@ -0,0 +1,285 @@
---
type: types/entity.md
entity_type: technology
tags: [ci-cd, workflows, automation, gitea]
created: 2026-07-25
modified: 2026-09-01
related: [Gitea, Act Runner, Docker, Gitea MCP Server, Ambient Environment Dependency, CI Integration]
sources: [Source - Conversation - Versioning CI-CD and Content Migration Session 2026-08-30, Source - Conversation - Issue Triage Labels and TODO Retirement Session 2026-08-31, Source - Conversation - Hardening the Test Suite Against Silent Environment Dependencies Session 2026-08-31, Source - Conversation - Nightly Drift-Check Workflow and doctor's Bootstrap Gap Session 2026-08-31]
confidence: 0.90
confidence_base: 0.90
provenance: sourced
summary: CI/CD-Workflow-Plattform, in Gitea integriert; fuehrt YAML-Workflows ueber den Act Runner aus, samt Release-Pipeline, belegten paths-ignore-Filtern und einem nightly.yml-Drift-Check, dessen schedule-Ausloesung seit 2026-09-01 (Run 90) belegt ist
---
# Gitea Actions
**Typ:** Technology (CI/CD Platform)
## Beschreibung
Gitea Actions ist das CI/CD-Workflow-Automatisierungssystem, das in Gitea integriert ist. Es ermöglicht die Definition von Build-, Test- und Deployment-Pipelines als Code in YAML-Workflow-Dateien. Die Workflows werden vom [[Act Runner]] ausgeführt.
## Kerndaten
- **Typ:** CI/CD-Workflow-Automatisierung
- **Status:** Aktiv (Stand 2026-07-12)
- **Runner:** [[Act Runner]]
- **Workflow-Syntax:** GitHub Actions kompatibles YAML
## Architektur
### Workflow-Ausführung
1. **Auslöser:** Push, PR, Zeitplan oder manuelle Auslösung
2. **Runner-Auswahl:** Basierend auf Routing-Labels (`linux-docker`, `container-builder`, `k3s-deploy`)
3. **Job-Container:** Isoliertes Bridge-Netz pro Job
4. **Secret-Injektion:** Runtime-Abruf aus 1Password
5. **Cache:** Built-in Actions Cache Server auf Port 8088
### Schlüsselkomponenten
- **Runner:** `act_runner`-Docker-Container im Host-Network-Modus
- **Cache Server:** Built-in, zugänglich via statische IP-Konfiguration
- **Job-Container:** Kurzlebige Docker-Container pro Workflow-Job
- **Actions:** Wiederverwendbare Workflow-Komponenten
## Konfiguration
### Cache-Konfiguration
```yaml
# In act_runner config.yaml
cache:
enabled: true
host: "192.0.2.10" # static IP of ci-runner.example.net
port: 8088
```
**Wichtig:** `cache.host` ist die Adresse, die Job-Container verwenden, um den Cache-Server zu erreichen, nicht die Listen-Adresse des Servers.
### Workflow-Beispiel
```yaml
name: Build and Deploy
on: [push]
permissions:
packages: write # Required for registry pushes
jobs:
build:
runs-on: linux-docker
steps:
- uses: actions/checkout@v4
- name: Load secrets
uses: 1password/load-secrets-action@v2
with:
vault: CI-CD
env:
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
- name: Build with BuildKit
run: |
docker buildx create --driver remote tcp://$HOST_IP:1234
docker buildx build --push ...
```
## Validierte Szenarien
### Szenario A: Arch-Paketbuilds
- **Basis-Image:** `archlinux:base-devel`
- **Herausforderung:** `makepkg` benötigt Root
- **Lösung:** Erstelle non-Root-Benutzer `builder` on-the-fly
- **Artefakte:** `actions/upload-artifact@v3` (v4 nicht vollständig unterstützt)
- **Hinweis:** Gitea Actions v4 hat begrenzte Artefakt-Unterstützung
### Szenario B: Container-Builds
- **Basis-Image:** `debian:trixie-slim` (Standard)
- **Vermeidet:** Alpine Linux (musl libc inkompatibel mit 1Password CLI)
- **Verbindung:** Dynamische IP-Erkennung via `ip route | awk '/default/ { print $3 }'`
### Szenario C: K3s-Deployments
-Cluster
- **Authentifizierung:** Kubeconfig aus 1Password-Vault
- **Muster:** `kubectl wait --for=delete pod -l ...` für zuverlässige Ressourcenverwaltung
### Szenario D: Test- und Release-Pipeline eines Python-Werkzeugs
- **Basis-Image:** `debian:trixie-slim`, trägt python3 3.13[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]
- **Erster Schritt:** `apt-get install nodejs`, **vor** dem Checkout - Voraussetzung für jede
JavaScript-Action, siehe [[Act Runner]][^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]
- **Checkout:** `actions/checkout@v7`[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]
- **Release:** `${{ gitea.token }}` genügt für das Anlegen von Release und Tag sowie für
Asset-Uploads; kein Actions-Secret mit `write:repository`
nötig[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]
- **Auslöser des Release-Workflows:** eine Änderung an der `VERSION`-Datei, siehe
[[KB Stack Versioning]]
### Läufe eines Workflows auf ihre Ursache prüfen
Bei einem privaten Repository lässt sich der Lauf-Zustand nicht anonym über HTTP feststellen;
[[Gitea]] antwortet einem anonymen Aufrufer identisch mit `404`, ob das Repository unsichtbar
oder nicht vorhanden
ist[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]. Läufe, ihr
Ausgang und ihre Logs werden über den [[Gitea MCP Server]] gelesen.
## Auslöser filtern
`paths-ignore` schließt Pfade von einem Workflow aus. Für die Filterlisten gelten hier drei
Festlegungen, die alle Ableitungen aus Undokumentiertem
vermeiden[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]:
- **Keine YAML-Anker**, um eine Liste zwischen zwei Workflows zu teilen. GitHubs Parser lehnt
Anker ab, und für Gitea ist nicht dokumentiert, dass er sie annimmt. Die Liste steht lieber
zweimal.
- **Keine negierten Muster** wie `!**/CONTRACT.md`. Gitea dokumentiert die Unterstützung
negierter Filtermuster nicht.
- **Die Muster scheitern offen.** Alles Unvorhergesehene löst weiterhin einen Lauf aus; das ist
die richtige Richtung für einen Filter, dessen Auswertung nicht bewiesen ist.
Dass die Filter greifen, ist seit 2026-08-31 beobachtet und nicht mehr angenommen. Commit
`f916376` war ein reiner Content-Publish - `kb/index.md`, `kb/log.md`, `kb/provenance.md`, acht
Seiten unter `kb/*/**` und eine Datei unter `raw/notes/`, sämtlich auf der Ignore-Liste - und
erzeugte zu seiner `head_sha` keinen einzigen Lauf[^s-conversation-issue-triage-labels-and-todo-retirement-session-2026-08-31]:
| Commit | Inhalt | Läufe |
|---|---|---|
| `6f54c31` | Stack (1.1.0) | 59 |
| `adfa220` | Stack (1.1.1) | 60, 61 |
| `f916376` | nur `kb/` und `raw/` | keine |
| `40adbb7` | Stack (1.2.0) | 62, 63 |
Die Stack-Commits davor und danach erzeugten je zwei Läufe, CI und Release, weil `VERSION` sich
bewegt hatte. Der Unterschied ist also der Filter und kein untätiger Runner; Gitea wertet diese
Muster wie GitHub aus[^s-conversation-issue-triage-labels-and-todo-retirement-session-2026-08-31]. Der Befund steht im Kommentarkopf von
`.gitea/workflows/ci.yml`, damit er nicht erneut für eine Annahme gehalten wird, und schloss
Gitea-Issue #11[^s-conversation-issue-triage-labels-and-todo-retirement-session-2026-08-31].
Als Folgewirkung bleibt die stärkste Hälfte der Begründung für den nächtlichen Drift-Check
(Issue #9) stehen: Weil der Filter greift, läuft `lint --fail-on-error` bei einem
Content-Publish tatsächlich nicht mehr. Ob dieser Gitea-Build `on: schedule` überhaupt
auswertet, ist davon unberührt - ~~und weiter offen~~ (Stand 2026-08-31; seit 2026-09-01
geklärt, siehe unten)[^s-conversation-issue-triage-labels-and-todo-retirement-session-2026-08-31].
`.gitea/workflows/nightly.yml` (seit 2026-08-31) implementiert diesen Drift-Check: `on:
schedule` (`17 3 * * *` UTC) plus `workflow_dispatch`, kein Push-Trigger, dieselbe Runner-Form
wie `ci.yml`. Diese Gitea-Instanz läuft **1.26.1** - weit über der 1.20-Version, die
Actions-Schedules einführte, was den Trigger plausibel, aber nicht bewiesen
macht[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31].
Zwei `workflow_dispatch`-Testläufe bestätigten zunächst nur, dass der Job selbst durchläuft
(Run 85, alle sieben Schritte grün) - ~~keiner davon ist ein `schedule`-Lauf. **Offen bleibt
weiterhin**, ob der Cron-Trigger auf diesem Stand tatsächlich feuert - frühestens ab
2026-09-01 03:17 UTC zu beobachten, an einem Lauf mit `"event":"schedule"`, nicht an einem
weiteren `workflow_dispatch`-Erfolg~~ (Stand
2026-08-31)[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31].
**Bestätigt seit 2026-09-01:** Run 90 ist der erste Lauf der Repository-Historie mit
`"event":"schedule"` - gestartet `2026-09-01T03:17:35Z`, exakt zur konfigurierten Cron-Zeit,
abgeschlossen `03:17:38Z`, alle sieben Schritte grün. Dieser Gitea-1.26.1-Stand wertet
`on: schedule` auf dem Default-Branch also tatsächlich aus; der im Issue vorgesehene externe
Fallback (ein externer Cron gegen die Actions-API) war nicht nötig.
Gitea-Issue #9 ist damit
geschlossen.
## Bekannte Probleme und Lösungen
### Der Job-Container ist keine konfigurationsfreie Maschine (Beobachtet 2026-08-31)
**Beobachtung:** `actions/checkout@v7` legt im Job-Container selbst eine globale
git-Konfiguration an. Aus dem Log von Lauf 79 des Chemenu-CI (damals `llm-wiki-test1`):
`Copying '/root/.gitconfig' to '/tmp/<uuid>/.gitconfig'` und `Temporarily overriding
HOME='/tmp/<uuid>' before making global git config changes`. Ein `git config --global --add
safe.directory` im eigenen Setup-Schritt schreibt zusätzlich
hinein[^s-conversation-hardening-the-test-suite-against-silent-environment-dependencies-session-2026-08-31].
**Warum das zählt:** Ein CI-Container gilt gern als neutrale Umgebung - "hier ist nichts
konfiguriert, also fällt auf, was von der Maschine gelesen wird". Für git stimmt das nicht mehr.
Ein Test oder Guard, der sich darauf verlässt, hört still auf zu greifen: kein roter Lauf, keine
Meldung, nur eine Prüfung, die nichts mehr prüft.
**Konsequenz:** Wer Umgebungsunabhängigkeit prüfen will, stellt sie explizit her
(`GIT_CONFIG_GLOBAL=/dev/null`, eigenes `HOME`) statt sie vom Container zu erwarten. Siehe
[[Ambient Environment Dependency]].
### `doctor` prüft eine Instanz, ein Checkout ist noch keine (Behoben 2026-08-31)
**Problem:** Der erste `workflow_dispatch`-Lauf von `nightly.yml` scheiterte am `doctor`-Schritt:
`FAIL git-identity: 'git config user.name' is not set` und `FAIL skills: No skills published
yet`[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31].
**Grundursache:** `doctor` fragt, ob eine *arbeitsfähige Instanz* korrekt konfiguriert ist, nicht
ob ein Checkout vollständig ist. `.agents/skills/` und `.claude/skills/` sind generiert und
bewusst nicht committet (siehe `instructions/bootstrap.md`), existieren also erst nach
`wikitool instructions sync`; und der Job-Container hat keine git-Konfiguration, unabhängig
davon, ob `WIKI_AUTHOR` gesetzt ist - das deckt nur die separate `author`-Prüfung, nicht
`git-identity`[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31].
Weil `doctor` den Job abbrach, wurde `instructions verify` nie erreicht - der Fehlschlag stand
vor dem eigentlichen Prüfzweck des Laufs, nicht in
ihm[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31].
**Lösung:** Vor `doctor` eine echte git-Identität setzen (`git config --global user.name/
user.email`) und `tools/wikitool instructions sync` laufen lassen - ein Mechanismus deckt beide
Prüfungen ab, statt zwei separate (git-Identität, `WIKI_AUTHOR`) je eine. Jeder Workflow, der
`doctor` oder `instructions verify` auf einem frischen Checkout aufruft, braucht denselben
Bootstrap[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31].
### JavaScript-Actions ohne `node` im Job-Image (Behoben 2026-08-30)
**Problem:** Jeder Lauf scheiterte an `actions/checkout` mit
`exec: "node": executable file not found in $PATH` und `exitcode '127'`.
**Grundursache:** act_runner führt JavaScript-Actions mit `node` im Job-Container aus; das
gepinnte `debian:trixie-slim` bringt keins mit. Das Runner-Label `linux-docker` war nie das
Problem - es routete und startete den Container von Anfang
an[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30].
**Lösung:** `nodejs` als erster Schritt vor dem Checkout installieren, Checkout auf
`actions/checkout@v7` heben. Ausführlich auf der Seite [[Act Runner]].
### Actions Cache Server-Konnektivität (Behoben 2026-07-12)
**Problem:** `setup-go@v6` und andere Cache-verwendende Actions zeigten Timeout bei Versuch, den Cache-Server unter `172.18.0.2:39329` (interne Docker-Bridge-IP) zu erreichen.
**Grundursache:** Runner-Container befand sich in seinem eigenen Bridge-Netz (`act_runner_default`), während sich jeder Job-Container in einem isolierten temporären Bridge-Netz befand. Diese Netze konnten ohne Host-Routing nicht miteinander kommunizieren.
**Lösung:**
1. Änderte Runner-Container zu `network_mode: host`
2. Setzte `cache.host` auf statische IP `192.0.2.10`
3. Cache-URL automatisch als `ACTIONS_CACHE_URL` injiziert
4. Vollständiger Neustart erforderlich: `docker compose down && docker compose up -d`
## Beziehungen
- **Teil von:** [[Gitea]]-Ökosystem
- **Ausgeführt von:** [[Act Runner]]
- **Nutzt:** [[Docker]] für Container
- **beobachtet über:** [[Gitea MCP Server]]
- **zeigte:** [[Ambient Environment Dependency]]
- **implementiert:** [[CI Integration]]
## Vorteile
- GitHub Actions kompatible Syntax
- Selbstgehostet, volle Kontrolle
- Integriert mit Gitea-Ökosystem
- Zero-Trust-ready mit 1Password-Integration
- Keine Vendor-Lock-in
## Siehe auch
- [[Gitea]] - Git-Dienst
- [[Act Runner]] - Runner-Implementierung
- Host-VM
- Secrets-Verwaltung
- Build-System
- [[Docker]] - Container-Plattform
concept
- [[Gitea MCP Server]]
- [[Source - Conversation - Issue Triage Labels and TODO Retirement Session 2026-08-31]]
- [[Source - Conversation - Hardening the Test Suite Against Silent Environment Dependencies Session 2026-08-31]]
- [[Ambient Environment Dependency]]
- [[CI Integration]]
## Fußnoten
[^s-conversation-versioning-ci-cd-and-content-migration-session-2026-08-30]: [[Source - Conversation - Versioning CI-CD and Content Migration Session 2026-08-30]]
[^s-conversation-issue-triage-labels-and-todo-retirement-session-2026-08-31]: [[Source - Conversation - Issue Triage Labels and TODO Retirement Session 2026-08-31]]
[^s-conversation-nightly-drift-check-workflow-and-doctor-s-bootstrap-gap-session-2026-08-31]: [[Source - Conversation - Nightly Drift-Check Workflow and doctor's Bootstrap Gap Session 2026-08-31]]
[^s-conversation-hardening-the-test-suite-against-silent-environment-dependencies-session-2026-08-31]: [[Source - Conversation - Hardening the Test Suite Against Silent Environment Dependencies Session 2026-08-31]]