Files
chemenu/DEVELOPMENT.md
T
torben a6d07f97c4
CI / verify (push) Successful in 5m19s
CI / pwsh (push) Successful in 1m55s
Release / release (push) Successful in 36s
feat!: installation only from a release, into an empty folder; upstream merge/verify and private-instance.md removed, dist adopt, shell-neutral instructions (#153)
Files changed:
- .gitea/workflows/ci.yml
- .gitea/workflows/release.yml
- AGENTS.md
- CHANGES.md
- DEVELOPMENT.md
- EVALS.md
- INSTALL.md
- README.md
- VERSION
- docs/ownership-and-templates.md
- instructions/CONTRACT.md
- instructions/bootstrap.md
- instructions/dev/dev-setup.md
- instructions/dev/stack-dev/SKILL.md
- instructions/gates.md
- instructions/ingest-large-tree.md
- instructions/kb-profiles.md
- instructions/mcp-read-server.md
- instructions/migrations/3.0.0-authoring-conventions.md
- instructions/preflight.md
- instructions/private-instance.md
- instructions/session-setup.md
- instructions/setup-instance.md
- instructions/upgrade-instance.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/cli.py
- tools/chemenu/cli_contract.py
- tools/chemenu/commands/dist_cmd.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/git_publish.py
- tools/chemenu/commands/upstream_cmd.py
- tools/chemenu/commands/work_cmd.py
- tools/chemenu/config.py
- tools/chemenu/ownership.py
- tools/chemenu/tests/test_cli.py
- tools/chemenu/tests/test_dist_cmd.py
- tools/chemenu/tests/test_instructions_shell.py
- tools/chemenu/tests/test_preflight.py
- tools/chemenu/tests/test_preflight_pwsh.py
- tools/chemenu/tests/test_run_budget.py
- tools/chemenu/tests/test_upstream_cmd.py
- tools/chemenu/toc.py
- tools/preflight.ps1
- tools/preflight.sh
2026-10-01 22:12:09 +02:00

176 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Entwicklung dieses Stacks
Dieses Dokument richtet sich an Menschen, die an `tools/wikitool`, dem Type-Schema oder der
Instruction-/Skill-Schicht selbst arbeiten - nicht an den Konsumenten einer Instanz. Für die
Gegenseite (eine Instanz installieren, aktualisieren, betreiben) siehe [INSTALL.md](INSTALL.md).
**Diese Datei wird nicht ausgeliefert.** Sie ist das menschliche Gegenstück zu
`instructions/dev/`, das `tools/wikitool dist export` vollständig ausschließt: eine
ausgelieferte Instanz hat keinen Release-Workflow, keine CI und kein Issue-Board, also braucht
sie auch keine Anleitung dafür. `dist_cmd.ROOT_FILES` listet sie deshalb bewusst nicht - der
Grund steht dort als Kommentar, damit eine spätere Sitzung die vermeintliche Lücke nicht
"repariert". Und weil sie nicht ausgeliefert wird, darf sie - anders als `README.md`,
`INSTALL.md` oder `EVALS.md`, die `instructions verify` auf genau diesen Punkt prüft - nach
`instructions/dev/` verlinken.
## Entwicklungsumgebung
Am Stack wird in einem Klon dieses Repos gearbeitet. Ein solcher Klon ist **keine Instanz** und
wird nie eine. Instanzen entstehen ausschließlich aus Releases, siehe [INSTALL.md](INSTALL.md).
```bash
git clone https://gitea.nehmer.net/torben/chemenu.git
cd chemenu
```
Danach den Agenten `instructions/bootstrap.md` ausführen lassen: Preflight, dann
`tools/wikitool instructions sync`. Die Agenten-Seite dazu - was hier anders ist als in einer
Instanz und wie `dist export` als Testwerkzeug läuft - steht in
[instructions/dev/dev-setup.md](instructions/dev/dev-setup.md).
Was ein Klon mitbringt und eine Instanz nicht:
- **Den Demo-Korpus.** Rund 170 Seiten, die den Stack selbst dokumentieren: Gates, Lint,
Versionierung, Suche, das Wiki-Muster. Er ist Testbett und begehbares Beispiel, keine
produktive Wissensbasis. Was an ihm geändert werden darf, regelt
[instructions/dev/corpus-policy.md](instructions/dev/corpus-policy.md).
- **Eine Demo-Persona** in `USER.md`/`SOUL.md`. `doctor` meldet beide als ausgefüllt. Sie
beschreiben den Demo-Betrieb, nicht dich.
- **Telemetrie an.** Ohne `.wikitool-release.json` ist der Klon die Messstation, mit der der
Stack sich selbst bewertet ([EVALS.md](EVALS.md) § „Whether it runs at all“).
- **`instructions/dev/`, `commonplace/`, `.gitea/` und diese Datei.** `dist export` liefert
davon nichts aus.
`ENVIRONMENT.md` fehlt nach jedem Klon, weil die Datei gitignored ist: Sie beschreibt einen
Checkout, nicht das Repo. Wer sie anlegt (Vorlage `ENVIRONMENT.md.template`, Schritt 5 in
`instructions/bootstrap.md`), erspart jeder Stack-Sitzung die Fragen nach Harness, `gitea-mcp`
und Remote.
### `dist export` als Build- und Testwerkzeug
`tools/wikitool dist export <leeres Verzeichnis>` schreibt genau den Baum, den ein Release
ausliefert: Maschinerie ohne Wiki-Inhalt, ohne Git-Historie, ohne `instructions/dev/`. Damit
prüft man vor einem Release, was ausgeliefert würde (`--dry-run` listet es nur). Und man spielt
den Installationsweg nach, ohne auf ein Release zu warten: Tarball daraus bauen wie
`.gitea/workflows/release.yml`, dann das Preflight-Skript in einem leeren Verzeichnis mit
`--archive <tarball>` starten. Der CI-Schritt „The distribution works as a fresh instance“ in
`.gitea/workflows/ci.yml` macht genau das.
Für eine echte Instanz ist ein solcher Export kein Weg. Ihm fehlen die Release-Herkunft im
Stamp, und `dist upgrade --latest` vergleicht später gegen einen Stand, den es nie als Release
gab.
### Ein Release-Feed in einem nicht öffentlichen Repo
Wer den Stack in einem eigenen, nicht öffentlichen Repo betreibt und Instanzen von dort
aktualisiert, lässt `WIKITOOL_UPDATE_URL` auf dessen Feed zeigen. Dabei gibt es eine Eigenheit:
Gitea antwortet anonymen Aufrufern für ein unsichtbares Repo mit demselben `404` wie für ein gar
nicht existierendes. Ein fehlendes Release und ein fehlender Zugriff sehen dann identisch aus –
„kein Update gefunden“ wäre in dem Fall schlicht falsch. Dagegen hilft ein Gitea-Token mit
Lesezugriff in `WIKITOOL_UPDATE_TOKEN`. Es geht nur an Downloads auf demselben Host wie der Feed.
## Der Release-Ablauf
Zwischen zwei Releases führt der Stack **einen** laufenden Versionskandidaten statt einer neuen
Nummer pro Bump. Das volle Modell - Zustandsort, Eskalationslogik, warum eine Nummer erst durch
ein Release verbraucht wird - steht in
[instructions/dev/version-parts.md](instructions/dev/version-parts.md) und
[docs/version-model.md](docs/version-model.md). Hier nur der Ablauf, in der Reihenfolge, in der
eine Sitzung ihn tatsächlich durchläuft:
1. **Bump eröffnet oder eskaliert den Kandidaten, gewichtet mit `--impact`.**
```bash
tools/wikitool version bump --minor --title "Was sich geändert hat" --impact medium
```
Schreibt `VERSION` als `X.Y.Z-beta.N` und öffnet (oder aktualisiert) den passenden
`CHANGES.md`-Eintrag. Mehrere Bumps für dieselbe Änderung sind normal - jeder aktualisiert
denselben Eintrag, statt einen neuen zu eröffnen. `--impact high|medium|low` (Default
`medium`) gruppiert den Eintrag; `tools/wikitool version regrade` korrigiert eine Note später,
wenn der Gesamteindruck des Kandidaten den Blick auf einen früheren Bump ändert.
2. **Der Eintrag bekommt seine Prosa - zweigeteilt.** `bump` schreibt nur das Skelett (Heading,
Datum, Autor, die maschinenverwaltete, gruppierte Bump-Titel-Liste, ggf.
Breaking-/Migration-Zeile). Darunter kommen zwei Autorenanteile: eine kurze Zusammenfassung
(ein paar Sätze, worum es in diesem Release geht) direkt unter der Liste, und darunter je Bump
ein eigener `### <Bump-Titel>`-Changeset-Absatz. Details dazu in
[instructions/dev/version-parts.md](instructions/dev/version-parts.md) § The candidate model.
3. **Verify laufen lassen, bevor irgendetwas gepublished wird:**
```bash
cd tools && .venv/bin/python -m pytest -q
tools/wikitool docs verify
tools/wikitool instructions verify
```
4. **`version release` fixiert den Kandidaten**, sobald er ausgeliefert werden soll:
```bash
tools/wikitool version release --title "Zusammenfassender Titel"
```
Streicht den `-beta.N`-Suffix aus `VERSION` und schließt den Changelog-Eintrag. `--title` ist
optional - ohne ihn bleibt der Titel des letzten Bumps stehen; mit ihm bekommt ein Kandidat,
der mehrere Bump-Titel gesammelt hat, eine zusammenfassende Überschrift. Verweigert, wenn der
Kandidat zwei oder mehr Bumps gesammelt hat und die Zusammenfassung aus Schritt 2 noch fehlt -
ein Kandidat mit genau einem Bump ist davon ausgenommen. Committet und pusht nichts
(Invariante 5 in [AGENTS.md](AGENTS.md)).
5. **Publish bewegt `VERSION` auf `main`.**
```bash
tools/wikitool publish --message "..."
```
Das Mass-Update-Gate und das Publish-Remote-Gate gelten wie bei jedem anderen Publish -
siehe [instructions/gates.md](instructions/gates.md).
6. **CI übernimmt den Rest.** `.gitea/workflows/release.yml` reagiert auf jeden Push, der
`VERSION` bewegt: Eine suffixbehaftete `VERSION` (ein Kandidat) lässt den Job sauber
überspringen, bevor er die Releases-API überhaupt anfragt - Betas werden nie veröffentlicht.
Eine suffixfreie `VERSION` baut die Distribution (`dist export`), erzeugt Tag und Release und
lädt Tarball und Prüfsumme hoch, dazu die beiden Preflight-Skripte und die Anleitungen
`setup-instance.md` und `preflight.md`, auf die der Installationssatz in `INSTALL.md` zeigt.
**CI setzt den Tag, nie eine Sitzung** - das hält Invariante 5 intakt.
Die drei Verify-Befehle stehen oben in Schritt 3; was jeder von ihnen prüft, steht in
[tools/CONTRACT.md](tools/CONTRACT.md) und wird dort von `docs verify` gegen die tatsächliche
CLI gehalten. Hier steht es bewusst **nicht** noch einmal: eine zweite Beschreibung derselben
Befehle ist genau die Kopie, die driftet (AGENTS.md Invariante 8), und dieses Dokument liegt
außerhalb der Dateien, die der Kommando-Datensatz-Check von `docs verify` abdeckt - hier fällt eine
Drift also niemandem auf. Was `pytest` an dieser Stelle vom Entwickler erwartet, steht in
[instructions/dev/testing-conventions.md](instructions/dev/testing-conventions.md).
## Die CI-Hälfte
`.gitea/workflows/ci.yml` läuft auf jeden Push/PR gegen `main` (Content-Pfade ausgenommen) und
führt Testsuite, `docs verify`, `instructions verify` sowie einen vollständigen
`setup-instance.md`-Replay aus: ein lokal gebauter Release-Tarball, das Preflight-Skript mit
`--archive` in einem leeren Verzeichnis, dann die Schritte der Anleitung - derselbe Pfad, den
ein neuer Nutzer tatsächlich geht, nur ohne Download. `.gitea/workflows/nightly.yml` ist der Drift-Check gegen die Zeit statt
gegen einen Commit. `.gitea/workflows/release.yml` ist Schritt 6 oben.
Drei weitere Workflows tragen die Live-Tests der Tracker-Adapter (Super Productivity, CalDAV):
`ci.yml` führt in einem eigenen Schritt die CalDAV-Hälfte gegen ein Radicale als Prozess aus,
`tracker-live.yml` läuft nachts und deckt beide Anbieter ab, und `sp-live-image.yml` baut täglich
(bei neuer Version) und monatlich (immer) das Image `chemenu-sp-live` mit der jeweils aktuellen
Super-Productivity-Version. Das Image folgt dem Update-Kanal der Desktop-Clients, nicht einer
festen Version. Einmalig nach dem allerersten Push muss das Paket von Hand dem Repo
`torben/chemenu` zugeordnet werden. Was die Suite schreibt, wie man sie gegen einen eigenen
Tracker laufen lässt und was ein roter Lauf bedeutet, steht in
[instructions/dev/tracker-testing.md](instructions/dev/tracker-testing.md).
## Stack-Entwicklung als eigener Sitzungstyp
Der `stack-dev`-Skill (`instructions/dev/`, nur in diesem Ursprungs-Repo vorhanden) fasst die
Regeln für eine Sitzung, die den Stack selbst statt Wiki-Inhalt bearbeitet: wann
Quellenbindung nicht gilt, wo Design endet und die mechanische Phase beginnt (mit dem
Modellwechsel-Hinweis), und endet mit dem Publish. Die Schlussphase - Issue-Body als Rewrite
statt Kommentar, `docs/`-Veralterung, die Modell-Handover-Zeile über die ganze Sitzung - liegt
seit `4.6.0` in einem eigenen Folge-Skill, `stack-close`, den `stack-dev` an dieser Stelle
übergibt statt sie als weiteren eigenen Schritt zu führen. Siehe
[instructions/dev/issue-tracking.md](instructions/dev/issue-tracking.md) für den
Issue-Tracker selbst.