Telemetrie-Default nach Installationsform: Tarball opt-in, Clone opt-out - plus Byte-Deckel je Session und Retention ueber die Anzahl der Session-Verzeichnisse
#55
chemenu.telemetry.writer.enabled() war eine Zeile - Telemetrie immer an, WIKI_TRACE=0 das
einzige Opt-out. Für dieses Entwicklungs-Repo richtig: die Traces sind hier das Messinstrument,
mit dem der Stack sich selbst bewertet (eval score, L2). Für eine ausgelieferte Instanz war es
die falsche Voreinstellung - dort hat niemand Telemetrie bestellt, und niemand liest EVALS.md,
bevor die erste Datei geschrieben ist.
Was nicht das Problem war: es verlässt nichts die Maschine. reports/ ist gitignored, kein
Exporter konfiguriert, herstellerseitige aus (enable_otel, enable_telemetry). Es ging um zwei
andere Dinge:
Prompts und Assistant-Antworten im Klartext auf der Platte des Instanzbetreibers - im
Dev-Repo eine bewusste Entscheidung, in einer fremden Instanz eine Voreinstellung, die der
Betreiber nie getroffen hat.
Keinerlei Mengenbegrenzung. Einziger Deckel war WIKI_TRACE_MAX_CONTENT (60 KiB pro
Attribut). Kein Limit pro Trace, keine Retention, kein Prune.
Was umgesetzt wurde
Erledigt in 5.0.0-beta.9, Commit 82a22ea (plus 42646d8, README-Nachzug). Alle vier
Entscheidungen wurden am 2026-09-10 mit dem Betreiber getroffen; die verworfenen Alternativen
stehen in der Kommentarhistorie.
1 - Erkennung der Installationsform: .wikitool-release.json
Vorhanden → ausgeliefert → Default aus. Fehlt → Dev-Checkout → Default an. Der Stamp ist
maschinengeschrieben (Invariante 1) und war bereits der Marker (dist_cmd.py: "has no .wikitool-release.json - not a distribution export"). .git schied aus (setup-instance.md
Schritt 2 macht auch die Tarball-Instanz zum Git-Repo), instructions/dev/ hätte den
Telemetrie-Default an die Skill-Schicht gekoppelt.
Zwei beabsichtigte Folgen: die private Instanz fällt auf die opt-in-Seite (ihr Baum stammt aus
einem dist export und trägt den Stamp - eine konsumierende Instanz, kein Messstand), und der
Marker wird gegen config.ROOT aufgelöst, nicht gegen config._PACKAGE_ROOT.
Umsetzungsdetail, das erst beim Bauen auffiel: RELEASE_STAMP_FILENAME ist nach config.py
gewandert und wird von version.py nur noch re-exportiert. chemenu.telemetry muss ohne venv
importierbar bleiben (ein Hook-Handler tut das bei jedem Tool-Call), durfte also nicht version.py importieren - und eine zweite Kopie des Dateinamens wäre Invariante 8 gewesen. Alle
bestehenden Aufrufer über version_mod.RELEASE_STAMP_FILENAME bleiben unverändert gültig.
2 - Mengenbegrenzung: zwei unabhängige Deckel, beide fail-silent
a) Byte-Deckel pro Session-Trace. Default 5 MiB, WIKI_TRACE_MAX_SESSION_BYTES überschreibt.
Ein stat vor jedem Append. Zum Vergleich: größter Trace in diesem Checkout 36 KB, Baum gesamt
1,9 MB.
b) Verhalten am Limit. Ab Limit wird nichts mehr geschrieben außer einem einmaligen telemetry.limit-Event (neu in schema.OPTIONAL_EVENTS), ausgelost per open(<session>/.limit, "x") - dieselbe Ein-Schreiber-Wahl wie bei _seed_session_header.
Rotation wurde verworfen (macht reader.py und eval score mehrdateifähig).
c) Retention über die Anzahl der Session-Verzeichnisse. Default 250, WIKI_TRACE_KEEP_SESSIONS überschreibt. Läuft nur beim Anlegen eines neuen
Session-Verzeichnisses, sortiert nach mtime wie reader.sessions().
Korrektur gegenüber dem ursprünglichen Entwurf, gefunden beim Testschreiben: die Retention reserviert den Platz der gerade entstehenden Session (behält keep - 1 des Bestands), statt
auf keep zu trimmen und die neue danach als keep + 1 landen zu lassen. Die naive Variante
konvergiert unter einem stetigen Zustrom einzelner neuer Sessions nie zurück auf keep - jeder
Lauf räumt nur, was der vorige über dem Limit gelassen hat, und der Bestand pendelt dauerhaft
bei keep + 1.
Der Default 250 liegt bewusst über dem Bestand dieses Checkouts zum Zeitpunkt der Umsetzung (229
Verzeichnisse): der Deckel greift in Zukunft, der Altbestand blieb unangetastet.
Löschregel: entfernt werden ausschließlich trace.jsonl und .limit der überzähligen
Verzeichnisse; rmdir nur, wenn danach leer, nie rmtree. Alles andere unter reports/ bleibt
byte-identisch - reports/ hält lokale, nicht rekonstruierbare Daten, die eval score liest.
3 - Opt-in: .wikitool-telemetry.json, im Setup-Interview gefragt
Alle drei Schlüssel optional. Vorrang: Umgebungsvariable > Datei > Formdefault.
Per-Checkout und gitignored wie .wikitool-remotes.json: die Zustimmung, Klartext-Prompts auf diese Platte zu schreiben, gehört dem Checkout, nicht dem Korpus. Nicht von dist export
ausgeliefert, kein .template; setup-instance.md Schritt 10 schreibt sie aus der Antwort des
Betreibers.
Cache-Detail: policy.resolve() cacht nur die dateisystemseitige Hälfte (Stamp +
Konfigurationsdatei), gekeyt auf den aufgelösten Root. Die Umgebungsvariablen werden bei jedem
Aufruf frisch gelesen - sie kosten keine I/O, und ein Test, der eine davon mitten im Lauf
umsetzt, muss den neuen Wert sofort sehen, nicht einen gecachten. Das war im Entwurf noch als
"alles cachen, gekeyt auf den Root" formuliert und wäre so falsch gewesen.
4 - Versionsteil: --minor auf den laufenden Kandidaten
Drop-in-Test bestanden, vorwärts wie rückwärts: additiv, kein Hand-Work, kein Migrationsskript;
die alte Version ignoriert Datei und Variablen. 5.0.0-beta.8 → 5.0.0-beta.9. Der Kandidat
hatte die Grenze längst überschritten (Confidence-Entfernung), der --minor eskaliert ihn nicht
(max-wins) und brauchte weder --breaking noch ein zweites Boundary-Gespräch.
Akzeptanzkriterien
In einem Baum ohne.wikitool-release.json, ohne gesetzte Umgebungsvariable, schreibt
ein wikitool-Aufruf einen Trace.
In einem Baum mit.wikitool-release.json, ohne Umgebungsvariable und ohne Opt-in,
schreibt derselbe Aufruf nichts - und legt reports/telemetry/ gar nicht erst an.
Zusätzlich zum Unit-Test von Hand gegen einen frischen dist export durchgespielt.
WIKI_TRACE überschreibt beide Defaults in beide Richtungen.
.wikitool-telemetry.json mit "enabled": true schaltet in der ausgelieferten Instanz
auf, ohne gesetzte Umgebungsvariable; WIKI_TRACE=0 schlägt die Datei.
Nach Erreichen des Byte-Deckels beendet ein weiterer Aufruf seine Arbeit unverändert mit
Exit 0; die Trace-Datei überschreitet die Grenze um höchstens ein Event, und telemetry.limit steht dort genau einmal, auch nach weiteren Aufrufen.
Die Durchsetzung löscht ausschließlich trace.jsonl/.limit der überzähligen
Verzeichnisse. Der Test mit einer fremden Datei im gelöschten Verzeichnis prüft, dass diese
byte-identisch stehen bleibt und das Verzeichnis nicht entfernt wird.
Das Verzeichnis der laufenden Session wird von deren eigenem Retention-Lauf nie entfernt.
wikitool doctor meldet den Telemetrie-Zustand: an/aus, warum, Menge gegen beide Deckel -
und nie FAIL.
Der MCP-Server startet in einer ausgelieferten Instanz ohne Opt-in ohne WIKI_TRACE=0 und
verweigert im Dev-Checkout weiterhin. check_trace_destination liest jetzt policy.resolve() statt WIKI_TRACE selbst - es gibt genau eine Stelle, die den Zustand
auflöst.
EVALS.md, INSTALL.md, INSTALL-MCP.md, reports/CONTRACT.md, tools/CONTRACT.md
beschreiben Default, Opt-in und beide Deckel; docs verify und instructions verify grün. Nachgezogen in 42646d8:README.md § "Telemetry and evaluation" behauptete weiter
"Every wikitool call appends an event" - in einer ausgelieferten Instanz ab jetzt falsch.
Beim stack-close-Durchgang gefunden, nicht beim ersten Publish.
Der neue Default ist im Testlauf festgenagelt, nicht geerbt: jeder Telemetrie-Test setzt
die Installationsform explizit, die neuen Variablen stehen in _WIKITOOL_ENV, und policy.reset_cache() hängt in hermetic_environment.
CI-Replay prüft, dass im exportierten Baum kein reports/telemetry/ entsteht
(.gitea/workflows/ci.yml, § "The distribution works as a fresh instance").
Was verifiziert wurde
pytest: 1118 Tests grün (vorher 1095, also 23 neue), zweimal gelaufen - normal und gegen
eine leere Maschine nach testing-conventions.md Schritt 6, mit identischem Ergebnis.
tools/wikitool docs verify und tools/wikitool instructions verify: grün.
tools/wikitool doctor: neuer telemetry-Check meldet im Dev-Checkout "on (no
.wikitool-release.json - dev checkout, default on); 231/250 session(s), 378.242 byte(s)".
Hand-Replay eines dist export in einen frischen Baum (Identität, Personalization,
Conventions, instructions sync, index rebuild, doctor, docs verify, instructions verify, lint --fail-on-error): doctor meldet dort "off
(.wikitool-release.json present - distributed instance, default off)", und reports/telemetry/ existiert nach dem gesamten Durchlauf nicht.
CI: Runs 228 und 229 auf 82a22ea, Run 230 auf 42646d8, dazu der Nightly-Lauf 231 - alle
vier success, inklusive des setup-instance.md-Replays gegen einen frischen dist export.
Ein Nebenbefund ohne Handlungsbedarf: pytest --cov lässt 271 unabhängige Tests
(test_xref.py, test_type_resolver.py, test_types_cmd.py, …) fehlschlagen, die ohne --cov
grün sind. Bestand schon vor dieser Änderung und ist von ihr unabhängig - eigenes Issue wert,
falls die Coverage-Zahl je gebraucht wird.
Berührte Stellen
tools/chemenu/telemetry/policy.py (neu), tools/chemenu/telemetry/writer.py, tools/chemenu/telemetry/schema.py, tools/chemenu/commands/doctor.py, tools/chemenu/mcp/server.py, tools/chemenu/config.py, tools/chemenu/version.py, .gitignore, .gitea/workflows/ci.yml, tools/chemenu/tests/conftest.py, tools/chemenu/tests/test_telemetry_policy.py (neu), test_telemetry_emit.py, test_doctor.py, test_mcp_server.py, EVALS.md, README.md, INSTALL.md, INSTALL-MCP.md, reports/CONTRACT.md, tools/CONTRACT.md, instructions/setup-instance.md, CHANGES.md, VERSION. Nicht berührt: dist_cmd.ROOT_FILES - die Konfigurationsdatei ist per-Checkout und
wird nicht ausgeliefert.
## Worum es ging
`chemenu.telemetry.writer.enabled()` war eine Zeile - Telemetrie immer an, `WIKI_TRACE=0` das
einzige Opt-out. Für dieses Entwicklungs-Repo richtig: die Traces sind hier das Messinstrument,
mit dem der Stack sich selbst bewertet (`eval score`, L2). Für eine ausgelieferte Instanz war es
die falsche Voreinstellung - dort hat niemand Telemetrie bestellt, und niemand liest `EVALS.md`,
bevor die erste Datei geschrieben ist.
**Was nicht das Problem war:** es verlässt nichts die Maschine. `reports/` ist gitignored, kein
Exporter konfiguriert, herstellerseitige aus (`enable_otel`, `enable_telemetry`). Es ging um zwei
andere Dinge:
1. **Prompts und Assistant-Antworten im Klartext auf der Platte** des Instanzbetreibers - im
Dev-Repo eine bewusste Entscheidung, in einer fremden Instanz eine Voreinstellung, die der
Betreiber nie getroffen hat.
2. **Keinerlei Mengenbegrenzung.** Einziger Deckel war `WIKI_TRACE_MAX_CONTENT` (60 KiB *pro
Attribut*). Kein Limit pro Trace, keine Retention, kein Prune.
## Was umgesetzt wurde
Erledigt in `5.0.0-beta.9`, Commit `82a22ea` (plus `42646d8`, README-Nachzug). Alle vier
Entscheidungen wurden am 2026-09-10 mit dem Betreiber getroffen; die verworfenen Alternativen
stehen in der Kommentarhistorie.
### 1 - Erkennung der Installationsform: `.wikitool-release.json`
Vorhanden → ausgeliefert → Default **aus**. Fehlt → Dev-Checkout → Default **an**. Der Stamp ist
maschinengeschrieben (Invariante 1) und war bereits *der* Marker (`dist_cmd.py`: "has no
`.wikitool-release.json` - not a distribution export"). `.git` schied aus (`setup-instance.md`
Schritt 2 macht auch die Tarball-Instanz zum Git-Repo), `instructions/dev/` hätte den
Telemetrie-Default an die Skill-Schicht gekoppelt.
Zwei beabsichtigte Folgen: die private Instanz fällt auf die opt-in-Seite (ihr Baum stammt aus
einem `dist export` und trägt den Stamp - eine konsumierende Instanz, kein Messstand), und der
Marker wird gegen `config.ROOT` aufgelöst, nicht gegen `config._PACKAGE_ROOT`.
Umsetzungsdetail, das erst beim Bauen auffiel: `RELEASE_STAMP_FILENAME` ist nach `config.py`
gewandert und wird von `version.py` nur noch re-exportiert. `chemenu.telemetry` muss ohne venv
importierbar bleiben (ein Hook-Handler tut das bei jedem Tool-Call), durfte also nicht
`version.py` importieren - und eine zweite Kopie des Dateinamens wäre Invariante 8 gewesen. Alle
bestehenden Aufrufer über `version_mod.RELEASE_STAMP_FILENAME` bleiben unverändert gültig.
### 2 - Mengenbegrenzung: zwei unabhängige Deckel, beide fail-silent
**a) Byte-Deckel pro Session-Trace.** Default 5 MiB, `WIKI_TRACE_MAX_SESSION_BYTES` überschreibt.
Ein `stat` vor jedem Append. Zum Vergleich: größter Trace in diesem Checkout 36 KB, Baum gesamt
1,9 MB.
**b) Verhalten am Limit.** Ab Limit wird nichts mehr geschrieben außer einem einmaligen
`telemetry.limit`-Event (neu in `schema.OPTIONAL_EVENTS`), ausgelost per
`open(<session>/.limit, "x")` - dieselbe Ein-Schreiber-Wahl wie bei `_seed_session_header`.
Rotation wurde verworfen (macht `reader.py` und `eval score` mehrdateifähig).
**c) Retention über die Anzahl der Session-Verzeichnisse.** Default 250,
`WIKI_TRACE_KEEP_SESSIONS` überschreibt. Läuft nur beim Anlegen eines neuen
Session-Verzeichnisses, sortiert nach `mtime` wie `reader.sessions()`.
Korrektur gegenüber dem ursprünglichen Entwurf, gefunden beim Testschreiben: die Retention
**reserviert den Platz der gerade entstehenden Session** (behält `keep - 1` des Bestands), statt
auf `keep` zu trimmen und die neue danach als `keep + 1` landen zu lassen. Die naive Variante
konvergiert unter einem stetigen Zustrom einzelner neuer Sessions nie zurück auf `keep` - jeder
Lauf räumt nur, was der *vorige* über dem Limit gelassen hat, und der Bestand pendelt dauerhaft
bei `keep + 1`.
Der Default 250 liegt bewusst über dem Bestand dieses Checkouts zum Zeitpunkt der Umsetzung (229
Verzeichnisse): der Deckel greift in Zukunft, der Altbestand blieb unangetastet.
**Löschregel:** entfernt werden ausschließlich `trace.jsonl` und `.limit` der überzähligen
Verzeichnisse; `rmdir` nur, wenn danach leer, nie `rmtree`. Alles andere unter `reports/` bleibt
byte-identisch - `reports/` hält lokale, nicht rekonstruierbare Daten, die `eval score` liest.
### 3 - Opt-in: `.wikitool-telemetry.json`, im Setup-Interview gefragt
```json
{ "enabled": true, "max_session_bytes": 5242880, "keep_sessions": 250 }
```
Alle drei Schlüssel optional. **Vorrang: Umgebungsvariable > Datei > Formdefault.**
Per-Checkout und gitignored wie `.wikitool-remotes.json`: die Zustimmung, Klartext-Prompts auf
*diese* Platte zu schreiben, gehört dem Checkout, nicht dem Korpus. Nicht von `dist export`
ausgeliefert, kein `.template`; `setup-instance.md` Schritt 10 schreibt sie aus der Antwort des
Betreibers.
Cache-Detail: `policy.resolve()` cacht nur die **dateisystemseitige Hälfte** (Stamp +
Konfigurationsdatei), gekeyt auf den aufgelösten Root. Die Umgebungsvariablen werden bei jedem
Aufruf frisch gelesen - sie kosten keine I/O, und ein Test, der eine davon mitten im Lauf
umsetzt, muss den neuen Wert sofort sehen, nicht einen gecachten. Das war im Entwurf noch als
"alles cachen, gekeyt auf den Root" formuliert und wäre so falsch gewesen.
### 4 - Versionsteil: `--minor` auf den laufenden Kandidaten
Drop-in-Test bestanden, vorwärts wie rückwärts: additiv, kein Hand-Work, kein Migrationsskript;
die alte Version ignoriert Datei und Variablen. `5.0.0-beta.8` → `5.0.0-beta.9`. Der Kandidat
hatte die Grenze längst überschritten (Confidence-Entfernung), der `--minor` eskaliert ihn nicht
(max-wins) und brauchte weder `--breaking` noch ein zweites Boundary-Gespräch.
## Akzeptanzkriterien
- [x] In einem Baum **ohne** `.wikitool-release.json`, ohne gesetzte Umgebungsvariable, schreibt
ein `wikitool`-Aufruf einen Trace.
- [x] In einem Baum **mit** `.wikitool-release.json`, ohne Umgebungsvariable und ohne Opt-in,
schreibt derselbe Aufruf nichts - und legt `reports/telemetry/` gar nicht erst an.
Zusätzlich zum Unit-Test von Hand gegen einen frischen `dist export` durchgespielt.
- [x] `WIKI_TRACE` überschreibt beide Defaults in **beide** Richtungen.
- [x] `.wikitool-telemetry.json` mit `"enabled": true` schaltet in der ausgelieferten Instanz
auf, ohne gesetzte Umgebungsvariable; `WIKI_TRACE=0` schlägt die Datei.
- [x] Nach Erreichen des Byte-Deckels beendet ein weiterer Aufruf seine Arbeit unverändert mit
Exit 0; die Trace-Datei überschreitet die Grenze um höchstens ein Event, und
`telemetry.limit` steht dort genau einmal, auch nach weiteren Aufrufen.
- [x] Die Durchsetzung löscht ausschließlich `trace.jsonl`/`.limit` der überzähligen
Verzeichnisse. Der Test mit einer fremden Datei im gelöschten Verzeichnis prüft, dass diese
byte-identisch stehen bleibt und das Verzeichnis nicht entfernt wird.
- [x] Das Verzeichnis der laufenden Session wird von deren eigenem Retention-Lauf nie entfernt.
- [x] `wikitool doctor` meldet den Telemetrie-Zustand: an/aus, warum, Menge gegen beide Deckel -
und nie `FAIL`.
- [x] Der MCP-Server startet in einer ausgelieferten Instanz ohne Opt-in ohne `WIKI_TRACE=0` und
verweigert im Dev-Checkout weiterhin. `check_trace_destination` liest jetzt
`policy.resolve()` statt `WIKI_TRACE` selbst - es gibt genau eine Stelle, die den Zustand
auflöst.
- [x] `EVALS.md`, `INSTALL.md`, `INSTALL-MCP.md`, `reports/CONTRACT.md`, `tools/CONTRACT.md`
beschreiben Default, Opt-in und beide Deckel; `docs verify` und `instructions verify` grün.
**Nachgezogen in `42646d8`:** `README.md` § "Telemetry and evaluation" behauptete weiter
"Every `wikitool` call appends an event" - in einer ausgelieferten Instanz ab jetzt falsch.
Beim `stack-close`-Durchgang gefunden, nicht beim ersten Publish.
- [x] Der neue Default ist im Testlauf festgenagelt, nicht geerbt: jeder Telemetrie-Test setzt
die Installationsform explizit, die neuen Variablen stehen in `_WIKITOOL_ENV`, und
`policy.reset_cache()` hängt in `hermetic_environment`.
- [x] CI-Replay prüft, dass im exportierten Baum kein `reports/telemetry/` entsteht
(`.gitea/workflows/ci.yml`, § "The distribution works as a fresh instance").
## Was verifiziert wurde
- `pytest`: 1118 Tests grün (vorher 1095, also 23 neue), zweimal gelaufen - normal und gegen
eine leere Maschine nach `testing-conventions.md` Schritt 6, mit identischem Ergebnis.
- `tools/wikitool docs verify` und `tools/wikitool instructions verify`: grün.
- `tools/wikitool doctor`: neuer `telemetry`-Check meldet im Dev-Checkout "on (no
.wikitool-release.json - dev checkout, default on); 231/250 session(s), 378.242 byte(s)".
- Hand-Replay eines `dist export` in einen frischen Baum (Identität, Personalization,
Conventions, `instructions sync`, `index rebuild`, `doctor`, `docs verify`,
`instructions verify`, `lint --fail-on-error`): `doctor` meldet dort "off
(.wikitool-release.json present - distributed instance, default off)", und
`reports/telemetry/` existiert nach dem gesamten Durchlauf nicht.
- CI: Runs 228 und 229 auf `82a22ea`, Run 230 auf `42646d8`, dazu der Nightly-Lauf 231 - alle
vier `success`, inklusive des `setup-instance.md`-Replays gegen einen frischen `dist export`.
Ein Nebenbefund ohne Handlungsbedarf: `pytest --cov` lässt 271 unabhängige Tests
(`test_xref.py`, `test_type_resolver.py`, `test_types_cmd.py`, …) fehlschlagen, die ohne `--cov`
grün sind. Bestand schon vor dieser Änderung und ist von ihr unabhängig - eigenes Issue wert,
falls die Coverage-Zahl je gebraucht wird.
## Berührte Stellen
`tools/chemenu/telemetry/policy.py` (neu), `tools/chemenu/telemetry/writer.py`,
`tools/chemenu/telemetry/schema.py`, `tools/chemenu/commands/doctor.py`,
`tools/chemenu/mcp/server.py`, `tools/chemenu/config.py`, `tools/chemenu/version.py`,
`.gitignore`, `.gitea/workflows/ci.yml`, `tools/chemenu/tests/conftest.py`,
`tools/chemenu/tests/test_telemetry_policy.py` (neu), `test_telemetry_emit.py`,
`test_doctor.py`, `test_mcp_server.py`, `EVALS.md`, `README.md`, `INSTALL.md`, `INSTALL-MCP.md`,
`reports/CONTRACT.md`, `tools/CONTRACT.md`, `instructions/setup-instance.md`, `CHANGES.md`,
`VERSION`. Nicht berührt: `dist_cmd.ROOT_FILES` - die Konfigurationsdatei ist per-Checkout und
wird nicht ausgeliefert.
torben
changed title from Telemetrie-Default nach Installationsform: Tarball opt-in, Clone opt-out - plus eine Mengenbegrenzung, deren Metrik noch offen ist to Telemetrie-Default nach Installationsform: Tarball opt-in, Clone opt-out - plus Byte-Deckel je Session und Retention ueber die Anzahl der Session-Verzeichnisse2026-09-10 20:40:01 +00:00
Changelog: Alle vier Entscheidungen getroffen, der Abschnitt "Zu entscheiden" ist durch "Entscheidungen" plus einen Umsetzungsplan ersetzt. Gewählt: (1) .wikitool-release.json als Marker, gegen config.ROOT aufgelöst; (2) Byte-Deckel je Session-Trace (5 MiB) und Retention über die Anzahl der Session-Verzeichnisse (250), Verhalten am Limit = Stopp plus genau ein telemetry.limit-Event, Rotation und Alters-Retention verworfen; (3) Opt-in in .wikitool-telemetry.json, per-Checkout und gitignored, Vorrang Env > Datei > Formdefault, im Setup-Interview gefragt; (4) --minor auf den laufenden 5.0.0-Kandidaten, Drop-in-Test in beide Richtungen bestanden.
Der Retention-Default 250 liegt bewusst über dem heutigen Bestand dieses Checkouts (229 Session-Verzeichnisse, 1,9 MB): der Deckel greift in Zukunft, der Altbestand wird nicht angefasst.
Neu unter den Akzeptanzkriterien: das Opt-in per Datei, die Nicht-Löschung des eigenen Session-Verzeichnisses, doctor meldet nie FAIL, genau eine Stelle im Code löst den Zustand auf (mcp/server.py liest WIKI_TRACE heute selbst — Invariante 8), und der CI-Replay als End-to-End-Prüfung, dass im exportierten Baum kein reports/telemetry/ entsteht. Titel nachgezogen ("Metrik noch offen" gilt nicht mehr), kind/decision → kind/build, size/L → size/M: die offenen Designfragen vor dem ersten Commit sind weg, es bleiben mehrere Dateien plus eigener Testaufwand.
Noch nichts implementiert — die Sitzung hält vor der Umsetzung an.
**Changelog:** Alle vier Entscheidungen getroffen, der Abschnitt "Zu entscheiden" ist durch "Entscheidungen" plus einen Umsetzungsplan ersetzt. Gewählt: (1) `.wikitool-release.json` als Marker, gegen `config.ROOT` aufgelöst; (2) Byte-Deckel je Session-Trace (5 MiB) **und** Retention über die Anzahl der Session-Verzeichnisse (250), Verhalten am Limit = Stopp plus genau ein `telemetry.limit`-Event, Rotation und Alters-Retention verworfen; (3) Opt-in in `.wikitool-telemetry.json`, per-Checkout und gitignored, Vorrang Env > Datei > Formdefault, im Setup-Interview gefragt; (4) `--minor` auf den laufenden 5.0.0-Kandidaten, Drop-in-Test in beide Richtungen bestanden.
Der Retention-Default 250 liegt bewusst über dem heutigen Bestand dieses Checkouts (229 Session-Verzeichnisse, 1,9 MB): der Deckel greift in Zukunft, der Altbestand wird nicht angefasst.
Neu unter den Akzeptanzkriterien: das Opt-in per Datei, die Nicht-Löschung des eigenen Session-Verzeichnisses, `doctor` meldet nie `FAIL`, genau eine Stelle im Code löst den Zustand auf (`mcp/server.py` liest `WIKI_TRACE` heute selbst — Invariante 8), und der CI-Replay als End-to-End-Prüfung, dass im exportierten Baum kein `reports/telemetry/` entsteht. Titel nachgezogen ("Metrik noch offen" gilt nicht mehr), `kind/decision` → `kind/build`, `size/L` → `size/M`: die offenen Designfragen vor dem ersten Commit sind weg, es bleiben mehrere Dateien plus eigener Testaufwand.
Noch nichts implementiert — die Sitzung hält vor der Umsetzung an.
Implemented and tested, ready to publish (waiting on the Mass-Update Gate, not yet pushed):
tools/chemenu/telemetry/policy.py (new): resolves enabled, max_session_bytes, keep_sessions in one place, cached per resolved root (filesystem-derived half only; WIKI_TRACE/WIKI_TRACE_MAX_SESSION_BYTES/WIKI_TRACE_KEEP_SESSIONS stay live).
writer.py: enabled() delegates to policy; emit() enforces the byte cap (_mark_limit_once, single-writer .limit sentinel) and the retention pass (_enforce_retention, reserves the about-to-be-created session's own slot so the count actually converges to keep instead of drifting to keep+1).
mcp/server.py: check_trace_destination now reads the same policy instead of WIKI_TRACE a second time (was an invariant-8 violation).
doctor.py: new telemetry check, never FAIL.
config.py: RELEASE_STAMP_FILENAME moved here (canonical, stdlib-safe for the telemetry package); version.py re-exports it. New TELEMETRY_FILENAME = ".wikitool-telemetry.json".
CI: asserts reports/telemetry/ does not exist after the fresh-instance replay.
Tests: test_telemetry_policy.py (new), extended test_telemetry_emit.py, test_doctor.py, test_mcp_server.py. Full suite 1118 passed, twice (normal + empty-machine per testing-conventions.md). docs verify/instructions verify clean. Manually replayed a dist export fresh-instance setup: telemetry defaults off, reports/telemetry/ never created.
Version bumped --minor (5.0.0-beta.8 → 5.0.0-beta.9, drop-in both directions, no new boundary crossing) with CHANGES.md prose.
tools/wikitool publish hit the Mass-Update Gate as expected (22 files) - session is showing the user the gate output now for --confirm.
Implemented and tested, ready to publish (waiting on the Mass-Update Gate, not yet pushed):
- `tools/chemenu/telemetry/policy.py` (new): resolves `enabled`, `max_session_bytes`, `keep_sessions` in one place, cached per resolved root (filesystem-derived half only; `WIKI_TRACE`/`WIKI_TRACE_MAX_SESSION_BYTES`/`WIKI_TRACE_KEEP_SESSIONS` stay live).
- `writer.py`: `enabled()` delegates to policy; `emit()` enforces the byte cap (`_mark_limit_once`, single-writer `.limit` sentinel) and the retention pass (`_enforce_retention`, reserves the about-to-be-created session's own slot so the count actually converges to `keep` instead of drifting to `keep+1`).
- `mcp/server.py`: `check_trace_destination` now reads the same policy instead of `WIKI_TRACE` a second time (was an invariant-8 violation).
- `doctor.py`: new `telemetry` check, never `FAIL`.
- `config.py`: `RELEASE_STAMP_FILENAME` moved here (canonical, stdlib-safe for the telemetry package); `version.py` re-exports it. New `TELEMETRY_FILENAME = ".wikitool-telemetry.json"`.
- Docs: `EVALS.md`, `INSTALL.md`, `INSTALL-MCP.md`, `reports/CONTRACT.md`, `tools/CONTRACT.md`, `instructions/setup-instance.md` (new step 10, renumbered 10-14 → 11-15).
- CI: asserts `reports/telemetry/` does not exist after the fresh-instance replay.
- Tests: `test_telemetry_policy.py` (new), extended `test_telemetry_emit.py`, `test_doctor.py`, `test_mcp_server.py`. Full suite 1118 passed, twice (normal + empty-machine per testing-conventions.md). `docs verify`/`instructions verify` clean. Manually replayed a `dist export` fresh-instance setup: telemetry defaults off, `reports/telemetry/` never created.
- Version bumped `--minor` (`5.0.0-beta.8` → `5.0.0-beta.9`, drop-in both directions, no new boundary crossing) with `CHANGES.md` prose.
`tools/wikitool publish` hit the Mass-Update Gate as expected (22 files) - session is showing the user the gate output now for `--confirm`.
Changelog: Geschlossen. Body auf den Endzustand umgeschrieben - "Umsetzungsplan" ist raus (ausgeführt), alle dreizehn Akzeptanzkriterien abgehakt, dazu ein Abschnitt "Was verifiziert wurde" mit den vier grünen CI-Läufen (228/229 auf 82a22ea, 230 auf 42646d8, Nightly 231) und dem Hand-Replay gegen einen frischen dist export.
Zwei Abweichungen vom geplanten Entwurf sind im Body dokumentiert, weil sie beide erst beim Bauen auffielen: die Retention reserviert den Platz der entstehenden Session (keep - 1) statt auf keep zu trimmen - die naive Variante pendelt dauerhaft bei keep + 1, weil jeder Lauf nur räumt, was der vorige übrig ließ; und policy.resolve() cacht nur die dateisystemseitige Hälfte, nicht die Umgebungsvariablen, die sonst nach einem monkeypatch im selben Prozess eingefroren wären. Dazu ein Umbau, den der Plan nicht vorsah: RELEASE_STAMP_FILENAME wohnt jetzt in config.py und wird von version.py re-exportiert, weil chemenu.telemetry ohne venv importierbar bleiben muss und eine zweite Kopie des Dateinamens Invariante 8 verletzt hätte.
Nachzügler in 42646d8: README.md § "Telemetry and evaluation" behauptete weiter "Every wikitool call appends an event". Beim stack-close-Durchgang gefunden, nicht beim ersten Publish - prosa-only, daher ohne Bump.
Modelle dieser Sitzung: Design/Entscheidungen/Versionsteil, mechanische Mitte (Code, Tests, Bump) und diese Abschlussphase liefen alle drei auf Opus 5; der in stack-dev Schritt 3 angebotene Wechsel auf Sonnet wurde nicht gezogen.
**Changelog:** Geschlossen. Body auf den Endzustand umgeschrieben - "Umsetzungsplan" ist raus (ausgeführt), alle dreizehn Akzeptanzkriterien abgehakt, dazu ein Abschnitt "Was verifiziert wurde" mit den vier grünen CI-Läufen (228/229 auf `82a22ea`, 230 auf `42646d8`, Nightly 231) und dem Hand-Replay gegen einen frischen `dist export`.
Zwei Abweichungen vom geplanten Entwurf sind im Body dokumentiert, weil sie beide erst beim Bauen auffielen: die Retention **reserviert den Platz der entstehenden Session** (`keep - 1`) statt auf `keep` zu trimmen - die naive Variante pendelt dauerhaft bei `keep + 1`, weil jeder Lauf nur räumt, was der vorige übrig ließ; und `policy.resolve()` cacht nur die dateisystemseitige Hälfte, nicht die Umgebungsvariablen, die sonst nach einem `monkeypatch` im selben Prozess eingefroren wären. Dazu ein Umbau, den der Plan nicht vorsah: `RELEASE_STAMP_FILENAME` wohnt jetzt in `config.py` und wird von `version.py` re-exportiert, weil `chemenu.telemetry` ohne venv importierbar bleiben muss und eine zweite Kopie des Dateinamens Invariante 8 verletzt hätte.
Nachzügler in `42646d8`: `README.md` § "Telemetry and evaluation" behauptete weiter "Every `wikitool` call appends an event". Beim `stack-close`-Durchgang gefunden, nicht beim ersten Publish - prosa-only, daher ohne Bump.
Modelle dieser Sitzung: Design/Entscheidungen/Versionsteil, mechanische Mitte (Code, Tests, Bump) und diese Abschlussphase liefen alle drei auf Opus 5; der in `stack-dev` Schritt 3 angebotene Wechsel auf Sonnet wurde nicht gezogen.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Worum es ging
chemenu.telemetry.writer.enabled()war eine Zeile - Telemetrie immer an,WIKI_TRACE=0daseinzige Opt-out. Für dieses Entwicklungs-Repo richtig: die Traces sind hier das Messinstrument,
mit dem der Stack sich selbst bewertet (
eval score, L2). Für eine ausgelieferte Instanz war esdie falsche Voreinstellung - dort hat niemand Telemetrie bestellt, und niemand liest
EVALS.md,bevor die erste Datei geschrieben ist.
Was nicht das Problem war: es verlässt nichts die Maschine.
reports/ist gitignored, keinExporter konfiguriert, herstellerseitige aus (
enable_otel,enable_telemetry). Es ging um zweiandere Dinge:
Dev-Repo eine bewusste Entscheidung, in einer fremden Instanz eine Voreinstellung, die der
Betreiber nie getroffen hat.
WIKI_TRACE_MAX_CONTENT(60 KiB proAttribut). Kein Limit pro Trace, keine Retention, kein Prune.
Was umgesetzt wurde
Erledigt in
5.0.0-beta.9, Commit82a22ea(plus42646d8, README-Nachzug). Alle vierEntscheidungen wurden am 2026-09-10 mit dem Betreiber getroffen; die verworfenen Alternativen
stehen in der Kommentarhistorie.
1 - Erkennung der Installationsform:
.wikitool-release.jsonVorhanden → ausgeliefert → Default aus. Fehlt → Dev-Checkout → Default an. Der Stamp ist
maschinengeschrieben (Invariante 1) und war bereits der Marker (
dist_cmd.py: "has no.wikitool-release.json- not a distribution export")..gitschied aus (setup-instance.mdSchritt 2 macht auch die Tarball-Instanz zum Git-Repo),
instructions/dev/hätte denTelemetrie-Default an die Skill-Schicht gekoppelt.
Zwei beabsichtigte Folgen: die private Instanz fällt auf die opt-in-Seite (ihr Baum stammt aus
einem
dist exportund trägt den Stamp - eine konsumierende Instanz, kein Messstand), und derMarker wird gegen
config.ROOTaufgelöst, nicht gegenconfig._PACKAGE_ROOT.Umsetzungsdetail, das erst beim Bauen auffiel:
RELEASE_STAMP_FILENAMEist nachconfig.pygewandert und wird von
version.pynur noch re-exportiert.chemenu.telemetrymuss ohne venvimportierbar bleiben (ein Hook-Handler tut das bei jedem Tool-Call), durfte also nicht
version.pyimportieren - und eine zweite Kopie des Dateinamens wäre Invariante 8 gewesen. Allebestehenden Aufrufer über
version_mod.RELEASE_STAMP_FILENAMEbleiben unverändert gültig.2 - Mengenbegrenzung: zwei unabhängige Deckel, beide fail-silent
a) Byte-Deckel pro Session-Trace. Default 5 MiB,
WIKI_TRACE_MAX_SESSION_BYTESüberschreibt.Ein
statvor jedem Append. Zum Vergleich: größter Trace in diesem Checkout 36 KB, Baum gesamt1,9 MB.
b) Verhalten am Limit. Ab Limit wird nichts mehr geschrieben außer einem einmaligen
telemetry.limit-Event (neu inschema.OPTIONAL_EVENTS), ausgelost peropen(<session>/.limit, "x")- dieselbe Ein-Schreiber-Wahl wie bei_seed_session_header.Rotation wurde verworfen (macht
reader.pyundeval scoremehrdateifähig).c) Retention über die Anzahl der Session-Verzeichnisse. Default 250,
WIKI_TRACE_KEEP_SESSIONSüberschreibt. Läuft nur beim Anlegen eines neuenSession-Verzeichnisses, sortiert nach
mtimewiereader.sessions().Korrektur gegenüber dem ursprünglichen Entwurf, gefunden beim Testschreiben: die Retention
reserviert den Platz der gerade entstehenden Session (behält
keep - 1des Bestands), stattauf
keepzu trimmen und die neue danach alskeep + 1landen zu lassen. Die naive Variantekonvergiert unter einem stetigen Zustrom einzelner neuer Sessions nie zurück auf
keep- jederLauf räumt nur, was der vorige über dem Limit gelassen hat, und der Bestand pendelt dauerhaft
bei
keep + 1.Der Default 250 liegt bewusst über dem Bestand dieses Checkouts zum Zeitpunkt der Umsetzung (229
Verzeichnisse): der Deckel greift in Zukunft, der Altbestand blieb unangetastet.
Löschregel: entfernt werden ausschließlich
trace.jsonlund.limitder überzähligenVerzeichnisse;
rmdirnur, wenn danach leer, niermtree. Alles andere unterreports/bleibtbyte-identisch -
reports/hält lokale, nicht rekonstruierbare Daten, dieeval scoreliest.3 - Opt-in:
.wikitool-telemetry.json, im Setup-Interview gefragtAlle drei Schlüssel optional. Vorrang: Umgebungsvariable > Datei > Formdefault.
Per-Checkout und gitignored wie
.wikitool-remotes.json: die Zustimmung, Klartext-Prompts aufdiese Platte zu schreiben, gehört dem Checkout, nicht dem Korpus. Nicht von
dist exportausgeliefert, kein
.template;setup-instance.mdSchritt 10 schreibt sie aus der Antwort desBetreibers.
Cache-Detail:
policy.resolve()cacht nur die dateisystemseitige Hälfte (Stamp +Konfigurationsdatei), gekeyt auf den aufgelösten Root. Die Umgebungsvariablen werden bei jedem
Aufruf frisch gelesen - sie kosten keine I/O, und ein Test, der eine davon mitten im Lauf
umsetzt, muss den neuen Wert sofort sehen, nicht einen gecachten. Das war im Entwurf noch als
"alles cachen, gekeyt auf den Root" formuliert und wäre so falsch gewesen.
4 - Versionsteil:
--minorauf den laufenden KandidatenDrop-in-Test bestanden, vorwärts wie rückwärts: additiv, kein Hand-Work, kein Migrationsskript;
die alte Version ignoriert Datei und Variablen.
5.0.0-beta.8→5.0.0-beta.9. Der Kandidathatte die Grenze längst überschritten (Confidence-Entfernung), der
--minoreskaliert ihn nicht(max-wins) und brauchte weder
--breakingnoch ein zweites Boundary-Gespräch.Akzeptanzkriterien
.wikitool-release.json, ohne gesetzte Umgebungsvariable, schreibtein
wikitool-Aufruf einen Trace..wikitool-release.json, ohne Umgebungsvariable und ohne Opt-in,schreibt derselbe Aufruf nichts - und legt
reports/telemetry/gar nicht erst an.Zusätzlich zum Unit-Test von Hand gegen einen frischen
dist exportdurchgespielt.WIKI_TRACEüberschreibt beide Defaults in beide Richtungen..wikitool-telemetry.jsonmit"enabled": trueschaltet in der ausgelieferten Instanzauf, ohne gesetzte Umgebungsvariable;
WIKI_TRACE=0schlägt die Datei.Exit 0; die Trace-Datei überschreitet die Grenze um höchstens ein Event, und
telemetry.limitsteht dort genau einmal, auch nach weiteren Aufrufen.trace.jsonl/.limitder überzähligenVerzeichnisse. Der Test mit einer fremden Datei im gelöschten Verzeichnis prüft, dass diese
byte-identisch stehen bleibt und das Verzeichnis nicht entfernt wird.
wikitool doctormeldet den Telemetrie-Zustand: an/aus, warum, Menge gegen beide Deckel -und nie
FAIL.WIKI_TRACE=0undverweigert im Dev-Checkout weiterhin.
check_trace_destinationliest jetztpolicy.resolve()stattWIKI_TRACEselbst - es gibt genau eine Stelle, die den Zustandauflöst.
EVALS.md,INSTALL.md,INSTALL-MCP.md,reports/CONTRACT.md,tools/CONTRACT.mdbeschreiben Default, Opt-in und beide Deckel;
docs verifyundinstructions verifygrün.Nachgezogen in
42646d8:README.md§ "Telemetry and evaluation" behauptete weiter"Every
wikitoolcall appends an event" - in einer ausgelieferten Instanz ab jetzt falsch.Beim
stack-close-Durchgang gefunden, nicht beim ersten Publish.die Installationsform explizit, die neuen Variablen stehen in
_WIKITOOL_ENV, undpolicy.reset_cache()hängt inhermetic_environment.reports/telemetry/entsteht(
.gitea/workflows/ci.yml, § "The distribution works as a fresh instance").Was verifiziert wurde
pytest: 1118 Tests grün (vorher 1095, also 23 neue), zweimal gelaufen - normal und gegeneine leere Maschine nach
testing-conventions.mdSchritt 6, mit identischem Ergebnis.tools/wikitool docs verifyundtools/wikitool instructions verify: grün.tools/wikitool doctor: neuertelemetry-Check meldet im Dev-Checkout "on (no.wikitool-release.json - dev checkout, default on); 231/250 session(s), 378.242 byte(s)".
dist exportin einen frischen Baum (Identität, Personalization,Conventions,
instructions sync,index rebuild,doctor,docs verify,instructions verify,lint --fail-on-error):doctormeldet dort "off(.wikitool-release.json present - distributed instance, default off)", und
reports/telemetry/existiert nach dem gesamten Durchlauf nicht.82a22ea, Run 230 auf42646d8, dazu der Nightly-Lauf 231 - allevier
success, inklusive dessetup-instance.md-Replays gegen einen frischendist export.Ein Nebenbefund ohne Handlungsbedarf:
pytest --covlässt 271 unabhängige Tests(
test_xref.py,test_type_resolver.py,test_types_cmd.py, …) fehlschlagen, die ohne--covgrün sind. Bestand schon vor dieser Änderung und ist von ihr unabhängig - eigenes Issue wert,
falls die Coverage-Zahl je gebraucht wird.
Berührte Stellen
tools/chemenu/telemetry/policy.py(neu),tools/chemenu/telemetry/writer.py,tools/chemenu/telemetry/schema.py,tools/chemenu/commands/doctor.py,tools/chemenu/mcp/server.py,tools/chemenu/config.py,tools/chemenu/version.py,.gitignore,.gitea/workflows/ci.yml,tools/chemenu/tests/conftest.py,tools/chemenu/tests/test_telemetry_policy.py(neu),test_telemetry_emit.py,test_doctor.py,test_mcp_server.py,EVALS.md,README.md,INSTALL.md,INSTALL-MCP.md,reports/CONTRACT.md,tools/CONTRACT.md,instructions/setup-instance.md,CHANGES.md,VERSION. Nicht berührt:dist_cmd.ROOT_FILES- die Konfigurationsdatei ist per-Checkout undwird nicht ausgeliefert.
Telemetrie-Default nach Installationsform: Tarball opt-in, Clone opt-out - plus eine Mengenbegrenzung, deren Metrik noch offen istto Telemetrie-Default nach Installationsform: Tarball opt-in, Clone opt-out - plus Byte-Deckel je Session und Retention ueber die Anzahl der Session-VerzeichnisseChangelog: Alle vier Entscheidungen getroffen, der Abschnitt "Zu entscheiden" ist durch "Entscheidungen" plus einen Umsetzungsplan ersetzt. Gewählt: (1)
.wikitool-release.jsonals Marker, gegenconfig.ROOTaufgelöst; (2) Byte-Deckel je Session-Trace (5 MiB) und Retention über die Anzahl der Session-Verzeichnisse (250), Verhalten am Limit = Stopp plus genau eintelemetry.limit-Event, Rotation und Alters-Retention verworfen; (3) Opt-in in.wikitool-telemetry.json, per-Checkout und gitignored, Vorrang Env > Datei > Formdefault, im Setup-Interview gefragt; (4)--minorauf den laufenden 5.0.0-Kandidaten, Drop-in-Test in beide Richtungen bestanden.Der Retention-Default 250 liegt bewusst über dem heutigen Bestand dieses Checkouts (229 Session-Verzeichnisse, 1,9 MB): der Deckel greift in Zukunft, der Altbestand wird nicht angefasst.
Neu unter den Akzeptanzkriterien: das Opt-in per Datei, die Nicht-Löschung des eigenen Session-Verzeichnisses,
doctormeldet nieFAIL, genau eine Stelle im Code löst den Zustand auf (mcp/server.pyliestWIKI_TRACEheute selbst — Invariante 8), und der CI-Replay als End-to-End-Prüfung, dass im exportierten Baum keinreports/telemetry/entsteht. Titel nachgezogen ("Metrik noch offen" gilt nicht mehr),kind/decision→kind/build,size/L→size/M: die offenen Designfragen vor dem ersten Commit sind weg, es bleiben mehrere Dateien plus eigener Testaufwand.Noch nichts implementiert — die Sitzung hält vor der Umsetzung an.
Implemented and tested, ready to publish (waiting on the Mass-Update Gate, not yet pushed):
tools/chemenu/telemetry/policy.py(new): resolvesenabled,max_session_bytes,keep_sessionsin one place, cached per resolved root (filesystem-derived half only;WIKI_TRACE/WIKI_TRACE_MAX_SESSION_BYTES/WIKI_TRACE_KEEP_SESSIONSstay live).writer.py:enabled()delegates to policy;emit()enforces the byte cap (_mark_limit_once, single-writer.limitsentinel) and the retention pass (_enforce_retention, reserves the about-to-be-created session's own slot so the count actually converges tokeepinstead of drifting tokeep+1).mcp/server.py:check_trace_destinationnow reads the same policy instead ofWIKI_TRACEa second time (was an invariant-8 violation).doctor.py: newtelemetrycheck, neverFAIL.config.py:RELEASE_STAMP_FILENAMEmoved here (canonical, stdlib-safe for the telemetry package);version.pyre-exports it. NewTELEMETRY_FILENAME = ".wikitool-telemetry.json".EVALS.md,INSTALL.md,INSTALL-MCP.md,reports/CONTRACT.md,tools/CONTRACT.md,instructions/setup-instance.md(new step 10, renumbered 10-14 → 11-15).reports/telemetry/does not exist after the fresh-instance replay.test_telemetry_policy.py(new), extendedtest_telemetry_emit.py,test_doctor.py,test_mcp_server.py. Full suite 1118 passed, twice (normal + empty-machine per testing-conventions.md).docs verify/instructions verifyclean. Manually replayed adist exportfresh-instance setup: telemetry defaults off,reports/telemetry/never created.--minor(5.0.0-beta.8→5.0.0-beta.9, drop-in both directions, no new boundary crossing) withCHANGES.mdprose.tools/wikitool publishhit the Mass-Update Gate as expected (22 files) - session is showing the user the gate output now for--confirm.Changelog: Geschlossen. Body auf den Endzustand umgeschrieben - "Umsetzungsplan" ist raus (ausgeführt), alle dreizehn Akzeptanzkriterien abgehakt, dazu ein Abschnitt "Was verifiziert wurde" mit den vier grünen CI-Läufen (228/229 auf
82a22ea, 230 auf42646d8, Nightly 231) und dem Hand-Replay gegen einen frischendist export.Zwei Abweichungen vom geplanten Entwurf sind im Body dokumentiert, weil sie beide erst beim Bauen auffielen: die Retention reserviert den Platz der entstehenden Session (
keep - 1) statt aufkeepzu trimmen - die naive Variante pendelt dauerhaft beikeep + 1, weil jeder Lauf nur räumt, was der vorige übrig ließ; undpolicy.resolve()cacht nur die dateisystemseitige Hälfte, nicht die Umgebungsvariablen, die sonst nach einemmonkeypatchim selben Prozess eingefroren wären. Dazu ein Umbau, den der Plan nicht vorsah:RELEASE_STAMP_FILENAMEwohnt jetzt inconfig.pyund wird vonversion.pyre-exportiert, weilchemenu.telemetryohne venv importierbar bleiben muss und eine zweite Kopie des Dateinamens Invariante 8 verletzt hätte.Nachzügler in
42646d8:README.md§ "Telemetry and evaluation" behauptete weiter "Everywikitoolcall appends an event". Beimstack-close-Durchgang gefunden, nicht beim ersten Publish - prosa-only, daher ohne Bump.Modelle dieser Sitzung: Design/Entscheidungen/Versionsteil, mechanische Mitte (Code, Tests, Bump) und diese Abschlussphase liefen alle drei auf Opus 5; der in
stack-devSchritt 3 angebotene Wechsel auf Sonnet wurde nicht gezogen.