Telemetrie-Default nach Installationsform: Tarball opt-in, Clone opt-out - plus Byte-Deckel je Session und Retention ueber die Anzahl der Session-Verzeichnisse #55
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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.