Abgespalten von #10, das die Messung eingerichtet und die Schwelle gesetzt hat. #10 friert den
erreichten Stand ein; dieses Issue ist die Arbeit, die er nicht ersetzt.
Die Coverage-Messung teilt ungedeckte Zeilen in drei Sorten, und nur die dritte ist
Arbeitsvorrat: dünne Typer-Wrapper (Logik liegt daneben und ist dort getestet), Code an der
Netz-/Dateisystem-Naht (interessante Hälfte über eine injizierbare Naht getestet) — und echte
Lücken, wo ungedeckte Zeilen Logik sind, die niemand ausführt.
Die dritte Sorte, Stand CI-Lauf 163 (2026-09-04, Stack 4.7.1, Gesamt 87,0 %):
Modul
Coverage
Statements
ungedeckt
Bewegung seit Lauf 87
chemenu/commands/provenance_cmd.py
44,1 %
127
71
unverändert
chemenu/commands/migrate_cmd.py
64,6 %
198
70
gefallen von 71,1 %
chemenu/type_resolver.py
78,9 %
199
42
78,6 % → 78,9 %
Das ist die einzige der drei Listen, die sich nicht bewegt hat, während alles um sie herum
wuchs. Zwischen Lauf 87 und Lauf 163 ist der gemessene Code um ein Viertel gewachsen und die
Suite um ein Drittel; provenance_cmd.py steht bei exakt denselben 44,1 %, und migrate_cmd.py
ist gefallen, weil das Modul gewachsen ist und die neuen Zeilen ungetestet ankamen.
Warum das mehr ist als eine Zahl
Zwei der drei Module tun Dinge, bei denen ein Fehler nicht als roter Test auffällt, sondern als
beschädigter Korpus:
migrate_cmd.py verändert kb/-Inhalte und schreibt .wikitool-kb.json fort. Der Präzedenzfall
steht in #30: zwei datenzerstörende Bugs in upstream merge sind an grünem pytest, docs verify, instructions verify und grüner CI vorbeigelaufen, weil kein Test den Fall
ausgeübt hat — nicht weil der getestete Fall schlecht geschrieben war. stack-dev Schritt 3
führt genau diesen Fall als Kaveat zur „mechanisch abgedeckten" Phase. migrate_cmd.py ist
dieselbe Sorte Code mit einem Drittel ungedeckter Zeilen.
provenance_cmd.py erzeugt kb/provenance.md, eine generierte Datei unter Invariante 1. Eine
falsche Ausgabe hier ist nicht falsch aussehende Ausgabe, sondern eine Herkunftsangabe, der
eine spätere Sitzung glaubt.
type_resolver.py entscheidet, welcher Typ und damit welches Verzeichnis für eine Seite gilt —
die Frage, die AGENTS.md ausdrücklich dem Tool und nicht der Sitzung überlässt („Never pick a
directory by hand").
Was zu tun ist
Nicht „Coverage auf X heben". Pro Modul die ungedeckten Zeilen durchgehen und entscheiden,
welche der drei Kategorien sie sind — die Aufteilung aus #10 gilt auch innerhalb eines Moduls,
und ein Teil dieser Zeilen wird sich als Wrapper oder als Naht herausstellen. Für den Rest
Tests, die den Fall ausüben, nicht die Zeile berühren.
provenance_cmd.py: ungedeckte Blöcke sind zusammenhängend (u. a. 127–169, 176–184), also
vermutlich ganze Codepfade, nicht Fehlerzweige. Erst lesen, dann kategorisieren.
migrate_cmd.py: zuerst die Zeilen, die seit Lauf 87 dazugekommen sind — dort ist die
Regression entstanden.
type_resolver.py: 42 Zeilen über viele kleine Blöcke verteilt; hier ist der Anteil echter
Fehlerzweige vermutlich am höchsten.
Nach jedem Modul prüfen, ob die Untergrenze in tools/.coveragerc nachgezogen werden
sollte. Nicht automatisch — die Schwelle ist ein Boden gegen Rückfall, kein Ziel, und
sie mitzuziehen macht sie wieder zu der Zahl, die beim nächsten Wrapper gesenkt wird.
Vor dem ersten Test: instructions/dev/testing-conventions.md
— die Suite läuft gegen eine bewusst leere Maschine, und was die autouse-Fixture hermetic_environment schon neutralisiert, muss ein Test nicht selbst herstellen.
Abgrenzung
Nicht in diesem Issue: die dünnen Wrapper (eval_cmd.py 36 %, types_cmd.py 40 %, search.py
49 %, cli.py 54 %, links_cmd.py 61 %). Niedrige Zahlen sind dort das Zeichen für einen guten
Schnitt. search.py ist der Musterfall: ungedeckt ist ausschließlich der Kommandokörper
(Zeilen 117–176), während die Backends unter chemenu/search/, die die Arbeit tun, zwischen
91 % und 98 % liegen.
Ebenfalls nicht: die echte Netzzeile in version.pys fetch_latest(). Die bleibt absichtlich
ungedeckt, dafür nimmt sie einen injizierbaren fetcher.
Version
Reine Testarbeit unter tools/chemenu/tests/ berührt das Version-Gate (^tools/) und braucht
damit einen PATCH-Bump, auch wenn sich am Verhalten nichts ändert. Wenn beim Testschreiben
ein echter Bug auffällt — der wahrscheinliche Ausgang bei migrate_cmd.py —, ist das der
eigentliche Ertrag dieses Issues und gehört in denselben Bump.
## Ausgangslage
Abgespalten von #10, das die Messung eingerichtet und die Schwelle gesetzt hat. **#10 friert den
erreichten Stand ein; dieses Issue ist die Arbeit, die er nicht ersetzt.**
Die Coverage-Messung teilt ungedeckte Zeilen in drei Sorten, und nur die dritte ist
Arbeitsvorrat: dünne Typer-Wrapper (Logik liegt daneben und ist dort getestet), Code an der
Netz-/Dateisystem-Naht (interessante Hälfte über eine injizierbare Naht getestet) — und **echte
Lücken**, wo ungedeckte Zeilen Logik sind, die niemand ausführt.
Die dritte Sorte, Stand CI-Lauf 163 (2026-09-04, Stack 4.7.1, Gesamt 87,0 %):
| Modul | Coverage | Statements | ungedeckt | Bewegung seit Lauf 87 |
|---|---|---|---|---|
| `chemenu/commands/provenance_cmd.py` | **44,1 %** | 127 | 71 | unverändert |
| `chemenu/commands/migrate_cmd.py` | **64,6 %** | 198 | 70 | **gefallen** von 71,1 % |
| `chemenu/type_resolver.py` | **78,9 %** | 199 | 42 | 78,6 % → 78,9 % |
**Das ist die einzige der drei Listen, die sich nicht bewegt hat, während alles um sie herum
wuchs.** Zwischen Lauf 87 und Lauf 163 ist der gemessene Code um ein Viertel gewachsen und die
Suite um ein Drittel; `provenance_cmd.py` steht bei exakt denselben 44,1 %, und `migrate_cmd.py`
ist gefallen, weil das Modul gewachsen ist und die neuen Zeilen ungetestet ankamen.
## Warum das mehr ist als eine Zahl
Zwei der drei Module tun Dinge, bei denen ein Fehler nicht als roter Test auffällt, sondern als
beschädigter Korpus:
- `migrate_cmd.py` verändert `kb/`-Inhalte und schreibt `.wikitool-kb.json` fort. Der Präzedenzfall
steht in #30: zwei datenzerstörende Bugs in `upstream merge` sind an grünem `pytest`,
`docs verify`, `instructions verify` und grüner CI vorbeigelaufen, **weil kein Test den Fall
ausgeübt hat** — nicht weil der getestete Fall schlecht geschrieben war. `stack-dev` Schritt 3
führt genau diesen Fall als Kaveat zur „mechanisch abgedeckten" Phase. `migrate_cmd.py` ist
dieselbe Sorte Code mit einem Drittel ungedeckter Zeilen.
- `provenance_cmd.py` erzeugt `kb/provenance.md`, eine generierte Datei unter Invariante 1. Eine
falsche Ausgabe hier ist nicht falsch aussehende Ausgabe, sondern eine Herkunftsangabe, der
eine spätere Sitzung glaubt.
- `type_resolver.py` entscheidet, welcher Typ und damit welches Verzeichnis für eine Seite gilt —
die Frage, die AGENTS.md ausdrücklich dem Tool und nicht der Sitzung überlässt („Never pick a
directory by hand").
## Was zu tun ist
Nicht „Coverage auf X heben". Pro Modul die ungedeckten Zeilen durchgehen und **entscheiden**,
welche der drei Kategorien sie sind — die Aufteilung aus #10 gilt auch innerhalb eines Moduls,
und ein Teil dieser Zeilen wird sich als Wrapper oder als Naht herausstellen. Für den Rest
Tests, die den Fall ausüben, nicht die Zeile berühren.
- [ ] `provenance_cmd.py`: ungedeckte Blöcke sind zusammenhängend (u. a. 127–169, 176–184), also
vermutlich ganze Codepfade, nicht Fehlerzweige. Erst lesen, dann kategorisieren.
- [ ] `migrate_cmd.py`: zuerst die Zeilen, die seit Lauf 87 dazugekommen sind — dort ist die
Regression entstanden.
- [ ] `type_resolver.py`: 42 Zeilen über viele kleine Blöcke verteilt; hier ist der Anteil echter
Fehlerzweige vermutlich am höchsten.
- [ ] Nach jedem Modul prüfen, ob die Untergrenze in `tools/.coveragerc` nachgezogen werden
sollte. **Nicht automatisch** — die Schwelle ist ein Boden gegen Rückfall, kein Ziel, und
sie mitzuziehen macht sie wieder zu der Zahl, die beim nächsten Wrapper gesenkt wird.
Vor dem ersten Test: [instructions/dev/testing-conventions.md](../src/branch/main/instructions/dev/testing-conventions.md)
— die Suite läuft gegen eine bewusst leere Maschine, und was die autouse-Fixture
`hermetic_environment` schon neutralisiert, muss ein Test nicht selbst herstellen.
## Abgrenzung
Nicht in diesem Issue: die dünnen Wrapper (`eval_cmd.py` 36 %, `types_cmd.py` 40 %, `search.py`
49 %, `cli.py` 54 %, `links_cmd.py` 61 %). Niedrige Zahlen sind dort das Zeichen für einen guten
Schnitt. `search.py` ist der Musterfall: ungedeckt ist ausschließlich der Kommandokörper
(Zeilen 117–176), während die Backends unter `chemenu/search/`, die die Arbeit tun, zwischen
91 % und 98 % liegen.
Ebenfalls nicht: die echte Netzzeile in `version.py`s `fetch_latest()`. Die bleibt absichtlich
ungedeckt, dafür nimmt sie einen injizierbaren `fetcher`.
## Version
Reine Testarbeit unter `tools/chemenu/tests/` berührt das Version-Gate (`^tools/`) und braucht
damit einen **PATCH**-Bump, auch wenn sich am Verhalten nichts ändert. Wenn beim Testschreiben
ein echter Bug auffällt — der wahrscheinliche Ausgang bei `migrate_cmd.py` —, ist das der
eigentliche Ertrag dieses Issues und gehört in denselben Bump.
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.
Ausgangslage
Abgespalten von #10, das die Messung eingerichtet und die Schwelle gesetzt hat. #10 friert den
erreichten Stand ein; dieses Issue ist die Arbeit, die er nicht ersetzt.
Die Coverage-Messung teilt ungedeckte Zeilen in drei Sorten, und nur die dritte ist
Arbeitsvorrat: dünne Typer-Wrapper (Logik liegt daneben und ist dort getestet), Code an der
Netz-/Dateisystem-Naht (interessante Hälfte über eine injizierbare Naht getestet) — und echte
Lücken, wo ungedeckte Zeilen Logik sind, die niemand ausführt.
Die dritte Sorte, Stand CI-Lauf 163 (2026-09-04, Stack 4.7.1, Gesamt 87,0 %):
chemenu/commands/provenance_cmd.pychemenu/commands/migrate_cmd.pychemenu/type_resolver.pyDas ist die einzige der drei Listen, die sich nicht bewegt hat, während alles um sie herum
wuchs. Zwischen Lauf 87 und Lauf 163 ist der gemessene Code um ein Viertel gewachsen und die
Suite um ein Drittel;
provenance_cmd.pysteht bei exakt denselben 44,1 %, undmigrate_cmd.pyist gefallen, weil das Modul gewachsen ist und die neuen Zeilen ungetestet ankamen.
Warum das mehr ist als eine Zahl
Zwei der drei Module tun Dinge, bei denen ein Fehler nicht als roter Test auffällt, sondern als
beschädigter Korpus:
migrate_cmd.pyverändertkb/-Inhalte und schreibt.wikitool-kb.jsonfort. Der Präzedenzfallsteht in #30: zwei datenzerstörende Bugs in
upstream mergesind an grünempytest,docs verify,instructions verifyund grüner CI vorbeigelaufen, weil kein Test den Fallausgeübt hat — nicht weil der getestete Fall schlecht geschrieben war.
stack-devSchritt 3führt genau diesen Fall als Kaveat zur „mechanisch abgedeckten" Phase.
migrate_cmd.pyistdieselbe Sorte Code mit einem Drittel ungedeckter Zeilen.
provenance_cmd.pyerzeugtkb/provenance.md, eine generierte Datei unter Invariante 1. Einefalsche Ausgabe hier ist nicht falsch aussehende Ausgabe, sondern eine Herkunftsangabe, der
eine spätere Sitzung glaubt.
type_resolver.pyentscheidet, welcher Typ und damit welches Verzeichnis für eine Seite gilt —die Frage, die AGENTS.md ausdrücklich dem Tool und nicht der Sitzung überlässt („Never pick a
directory by hand").
Was zu tun ist
Nicht „Coverage auf X heben". Pro Modul die ungedeckten Zeilen durchgehen und entscheiden,
welche der drei Kategorien sie sind — die Aufteilung aus #10 gilt auch innerhalb eines Moduls,
und ein Teil dieser Zeilen wird sich als Wrapper oder als Naht herausstellen. Für den Rest
Tests, die den Fall ausüben, nicht die Zeile berühren.
provenance_cmd.py: ungedeckte Blöcke sind zusammenhängend (u. a. 127–169, 176–184), alsovermutlich ganze Codepfade, nicht Fehlerzweige. Erst lesen, dann kategorisieren.
migrate_cmd.py: zuerst die Zeilen, die seit Lauf 87 dazugekommen sind — dort ist dieRegression entstanden.
type_resolver.py: 42 Zeilen über viele kleine Blöcke verteilt; hier ist der Anteil echterFehlerzweige vermutlich am höchsten.
tools/.coveragercnachgezogen werdensollte. Nicht automatisch — die Schwelle ist ein Boden gegen Rückfall, kein Ziel, und
sie mitzuziehen macht sie wieder zu der Zahl, die beim nächsten Wrapper gesenkt wird.
Vor dem ersten Test: instructions/dev/testing-conventions.md
— die Suite läuft gegen eine bewusst leere Maschine, und was die autouse-Fixture
hermetic_environmentschon neutralisiert, muss ein Test nicht selbst herstellen.Abgrenzung
Nicht in diesem Issue: die dünnen Wrapper (
eval_cmd.py36 %,types_cmd.py40 %,search.py49 %,
cli.py54 %,links_cmd.py61 %). Niedrige Zahlen sind dort das Zeichen für einen gutenSchnitt.
search.pyist der Musterfall: ungedeckt ist ausschließlich der Kommandokörper(Zeilen 117–176), während die Backends unter
chemenu/search/, die die Arbeit tun, zwischen91 % und 98 % liegen.
Ebenfalls nicht: die echte Netzzeile in
version.pysfetch_latest(). Die bleibt absichtlichungedeckt, dafür nimmt sie einen injizierbaren
fetcher.Version
Reine Testarbeit unter
tools/chemenu/tests/berührt das Version-Gate (^tools/) und brauchtdamit einen PATCH-Bump, auch wenn sich am Verhalten nichts ändert. Wenn beim Testschreiben
ein echter Bug auffällt — der wahrscheinliche Ausgang bei
migrate_cmd.py—, ist das dereigentliche Ertrag dieses Issues und gehört in denselben Bump.