Teilpaket von #140. D17 ist entschieden (Betreiber, 2026-09-28).
Stand
Abgeschlossen am 2026-09-29 im Kandidaten 7.1.0-beta.32 (Richtung 8.0.0, #140 D19). dist upgrade --latest [--expect <version>] lädt das neueste Release aus dem Feed, prüft es und spielt es über den bestehenden Upgrade-Pfad ein.
Geprüft: pytest in tools/ komplett grün (1579 Tests, danach test_dist_upgrade.py mit 64 Tests nach dem letzten Zusatztest), docs verify und instructions verify grün. CI grün auf cf89231 (Läufe 427 und 428) und auf dem Doku-Nachzug 94deccb (Lauf 429). Gegen den echten Gitea-Feed wurde --latest nicht ausgeführt: Das Ursprungs-Repo hat keinen Stamp, dist upgrade verweigert dort. Der erste echte Lauf ist das Update einer Instanz auf 8.0.0.
Warum
Echte Installationen beziehen ihre Updates aus dem Gitea-Feed (#140 D7). Vorher lud dist upgrade nichts selbst herunter („Never downloads anything“). Der Agent musste Tarball und .sha256 vorher holen, und zwar genau mit den Shell-Konstrukten (curl, sha256sum, tar), die #153 aus den Anleitungen entfernt. Unter Windows hätte er dafür zusätzlich pwsh-Syntax gebraucht. version check kannte den Feed bereits: aus dem Stamp oder aus WIKITOOL_UPDATE_URL.
Ausgangslage vor der Umsetzung
Feed:version.update_url() (Env → Stamp → DEFAULT_UPDATE_URL, immer …/releases/latest). version._fetch_latest_object() liefert das ganze Release-Objekt aus einer Anfrage. fetch_latest_notes begründet, warum nie eine /releases/tags/<tag>-URL zusammengesetzt wird.
Feed-Antwort (live geprüft, v7.0.0):assets[] mit name und browser_download_url, z. B. chemenu-stack-7.0.0.tar.gz und ….tar.gz.sha256. tag_name trägt ein v, das Version.parse akzeptiert. Den Namen setzt .gitea/workflows/release.yml (name="chemenu-stack-${VERSION}").
Upgrade-Pfad:run_upgrade() prüft zuerst die lokalen Vorbedingungen, dann löst _resolved_source() die Quelle auf (Sidecar-Prüfung, Entpacken in ein TemporaryDirectory). fail() wirft typer.Exit; with-Blöcke räumen also auch im Fehlerfall auf.
Entscheidungen
E1 Name:dist upgrade --latest. <source> ist optional; genau eines von beiden ist Pflicht. Beides oder keins ergibt Exit 1 vor jeder Prüfung.
E2 Kein --version <v>. Eine beliebige Version zu holen hieße, eine Tags-URL aus der latest-URL zu raten (Invariante 7). Ein Downgrade wird ohnehin verweigert; eine andere Version als die neueste hat keinen Anwendungsfall.
E3 Reihenfolge: lokale Vorbedingungen → Feed abfragen → Feed-Version gegen --expect und VERSION prüfen, vor jedem Download (gleich → No-op „Already at …“, älter → Downgrade-Ablehnung, Pre-Release ohne --pre → Ablehnung) → Asset-Paar im Release-Objekt suchen, fehlt eines → Exit 1 vor dem ersten Download → beide in ein TemporaryDirectory(prefix="wikitool-upgrade-") laden → Summe prüfen → bestehender Pfad. Zusätzlich: VERSION im Tarball muss der Feed-Version entsprechen, sonst Exit 1 und nichts wird angewendet.
Die „strikte“ Summenprüfung brauchte keinen eigenen Modus in _verify_sha256_sidecar: auf diesem Pfad ist die Summe immer vorhanden, weil ihr Fehlen schon bei der Asset-Suche abgelehnt wird.
E4 Asset-Suche nach exaktem Namen über das assets-Feld des schon geholten Release-Objekts; die URL kommt aus browser_download_url, nie zusammengesetzt. Die Fehlermeldung nennt die vorhandenen Assets und die Release-Seite. Der Name steht als version.ARCHIVE_NAME in Python; test_release_asset_names_match_the_workflow hält ihn mit release.yml zusammen.
E5 Token nur an denselben Origin (Schema, Host, Port; Default-Ports normalisiert), und dann als unredirected Header, damit ein Redirect ihn nicht mitnimmt.
E6 Kein https-Zwang. Die sha256 kommt vom selben Host und schützt nur vor Übertragungsfehlern; die Echtheit hängt am Vertrauen in den Feed-Host. Steht in INSTALL.md, in upgrade-instance.md Schritt 4 und im Record.
E7 Netzcode in version.py:fetch_latest_assets/LatestRelease, token_for_asset, download_asset (gestreamt, 60 s Socket-Timeout, Fehler als VersionError mit URL). Der Docstring von fetch_latest nennt drei Befehle.
E8 --dry-run lädt, prüft und klassifiziert, schreibt nichts und räumt auf.
E9 Nicht Teil dieses Pakets: Die upstream merge-Verweise im Record und in der fail()-Meldung von run_upgrade bleiben für #153; ebenso der Neuschnitt von INSTALL.md.
E10 (Betreiber 2026-09-29, Variante B) --expect <version>, nur mit --latest: meldet der Feed eine andere Version, Exit 1 vor dem Download, Meldung nennt beide Versionen und verweist auf version notes. Verglichen wird die geparste Version (v-Präfix egal, -beta.N zulässig). upgrade-instance.md übergibt die Version aus Schritt 2 in Dry-Run und echtem Lauf. Die Ablehnungstexte für lokal geänderte Dateien nennen auf diesem Pfad dist upgrade --latest --expect <version> … als Wiederholungszeile.
tools/chemenu/commands/dist_cmd.py: --latest/--expect, _query_feed, _downloaded_source, gemeinsame Versionsprüfung _version_gate; Record mit Synopsis dist upgrade (<source> | --latest [--expect <version>]) …, network: yes, neuen Notes, sechs neuen Failure-Einträgen und Beispiel dist upgrade --latest --expect 8.0.0 --dry-run.
tools/chemenu/commands/version_cmd.py: Record-Note und Modul-Docstring nennen dist upgrade --latest als dritten Feed-Aufrufer.
tools/CONTRACT.md über docs contract --apply.
instructions/upgrade-instance.md: Schritt 4 erklärt --latest und den Tarball als Offline-Alternative; Schritte 5–7 nutzen --latest --expect <version from step 2>. Schrittnummern unverändert.
INSTALL.md: drei Befehle mit Netzzugriff, --latest/--expect, Echtheitshinweis, Sonderfall „erster Sprung auf ein Release, das --latest kennt“ (ohne Versionsnummer, weil der Kandidat noch 7.1.0-beta.N heißt).
Tests: test_dist_upgrade.py mit lokalem http.server (Anfrage- und Authorization-Log, tempfile.tempdir umgelenkt); test_cli.py nimmt dist upgrade in die Menge der network: yes-Befehle auf.
Version: version bump --minor --impact high, CHANGES-Prosa.
Nachzug beim Abschluss: EVALS.md sagte, die echten urllib-Zeilen in version.py blieben ungetestet; das stimmt nicht mehr (Lauf gegen lokalen http.server), korrigiert in 94deccb.
Akzeptanzkriterien
Gegen einen lokalen Test-Feed lädt dist upgrade --latest das neueste Release, prüft die sha256 und führt das Upgrade durch; jede Datei stimmt per Digest mit dem Baum nach dist upgrade <tarball> überein (test_latest_yields_the_same_tree_as_the_archive_it_downloaded).
Falsche oder fehlende .sha256 → Exit 1, nichts geschrieben, kein wikitool-upgrade-*-Eintrag im Temp-Verzeichnis.
Feed nicht erreichbar → Exit 1 mit Feed-URL, nie „aktuell“.
Installierte Version ist die neueste → erfolgreicher No-op ohne Asset-Anfrage.
Tarball- oder Summen-Asset fehlt → Exit 1 ohne Download, vorhandene Assets genannt.
Feed-Version ≠ --expect → Exit 1 ohne Asset-Anfrage, beide Versionen genannt; --expect ohne --latest → Exit 1.
WIKITOOL_UPDATE_TOKEN erreicht keine Download-URL auf einem anderen Origin.
Ein Test hält den Asset-Namen in release.yml und im Code zusammen.
INSTALL.md führt dist upgrade --latest bei den Befehlen mit Netzzugriff; docs verify, instructions verify, pytest und CI grün.
Modelle
Entwurf, Versionsteil und E1–E10: Opus (Vorbereitung am 2026-09-29). Umsetzung, Tests, Bump, CHANGES-Prosa und Doku-Nachzug: Sonnet 5.5. Abschluss (dieser Text, docs/-/Doku-Prüfung, CI): Opus 5.5.
Version
minor, 7.1.0-beta.32; landet im 8.0.0-Kandidaten (#140 D19).
Teilpaket von #140. D17 ist entschieden (Betreiber, 2026-09-28).
## Stand
**Abgeschlossen am 2026-09-29** im Kandidaten 7.1.0-beta.32 (Richtung 8.0.0, #140 D19). `dist upgrade --latest [--expect <version>]` lädt das neueste Release aus dem Feed, prüft es und spielt es über den bestehenden Upgrade-Pfad ein.
Geprüft: `pytest` in `tools/` komplett grün (1579 Tests, danach `test_dist_upgrade.py` mit 64 Tests nach dem letzten Zusatztest), `docs verify` und `instructions verify` grün. CI grün auf `cf89231` (Läufe 427 und 428) und auf dem Doku-Nachzug `94deccb` (Lauf 429). Gegen den echten Gitea-Feed wurde `--latest` nicht ausgeführt: Das Ursprungs-Repo hat keinen Stamp, `dist upgrade` verweigert dort. Der erste echte Lauf ist das Update einer Instanz auf 8.0.0.
## Warum
Echte Installationen beziehen ihre Updates aus dem Gitea-Feed (#140 D7). Vorher lud `dist upgrade` nichts selbst herunter („Never downloads anything“). Der Agent musste Tarball und `.sha256` vorher holen, und zwar genau mit den Shell-Konstrukten (`curl`, `sha256sum`, `tar`), die #153 aus den Anleitungen entfernt. Unter Windows hätte er dafür zusätzlich pwsh-Syntax gebraucht. `version check` kannte den Feed bereits: aus dem Stamp oder aus `WIKITOOL_UPDATE_URL`.
## Ausgangslage vor der Umsetzung
- **Feed:** `version.update_url()` (Env → Stamp → `DEFAULT_UPDATE_URL`, immer `…/releases/latest`). `version._fetch_latest_object()` liefert das ganze Release-Objekt aus *einer* Anfrage. `fetch_latest_notes` begründet, warum nie eine `/releases/tags/<tag>`-URL zusammengesetzt wird.
- **Feed-Antwort (live geprüft, v7.0.0):** `assets[]` mit `name` und `browser_download_url`, z. B. `chemenu-stack-7.0.0.tar.gz` und `….tar.gz.sha256`. `tag_name` trägt ein `v`, das `Version.parse` akzeptiert. Den Namen setzt `.gitea/workflows/release.yml` (`name="chemenu-stack-${VERSION}"`).
- **Upgrade-Pfad:** `run_upgrade()` prüft zuerst die lokalen Vorbedingungen, dann löst `_resolved_source()` die Quelle auf (Sidecar-Prüfung, Entpacken in ein `TemporaryDirectory`). `fail()` wirft `typer.Exit`; `with`-Blöcke räumen also auch im Fehlerfall auf.
## Entscheidungen
- **E1 Name:** `dist upgrade --latest`. `<source>` ist optional; genau eines von beiden ist Pflicht. Beides oder keins ergibt Exit 1 vor jeder Prüfung.
- **E2 Kein `--version <v>`.** Eine beliebige Version zu holen hieße, eine Tags-URL aus der `latest`-URL zu raten (Invariante 7). Ein Downgrade wird ohnehin verweigert; eine andere Version als die neueste hat keinen Anwendungsfall.
- **E3 Reihenfolge:** lokale Vorbedingungen → Feed abfragen → Feed-Version gegen `--expect` und `VERSION` prüfen, **vor jedem Download** (gleich → No-op „Already at …“, älter → Downgrade-Ablehnung, Pre-Release ohne `--pre` → Ablehnung) → Asset-Paar im Release-Objekt suchen, fehlt eines → Exit 1 vor dem ersten Download → beide in ein `TemporaryDirectory(prefix="wikitool-upgrade-")` laden → Summe prüfen → bestehender Pfad. Zusätzlich: `VERSION` im Tarball muss der Feed-Version entsprechen, sonst Exit 1 und nichts wird angewendet.
Die „strikte“ Summenprüfung brauchte keinen eigenen Modus in `_verify_sha256_sidecar`: auf diesem Pfad ist die Summe immer vorhanden, weil ihr Fehlen schon bei der Asset-Suche abgelehnt wird.
- **E4 Asset-Suche nach exaktem Namen** über das `assets`-Feld des schon geholten Release-Objekts; die URL kommt aus `browser_download_url`, nie zusammengesetzt. Die Fehlermeldung nennt die vorhandenen Assets und die Release-Seite. Der Name steht als `version.ARCHIVE_NAME` in Python; `test_release_asset_names_match_the_workflow` hält ihn mit `release.yml` zusammen.
- **E5 Token nur an denselben Origin** (Schema, Host, Port; Default-Ports normalisiert), und dann als unredirected Header, damit ein Redirect ihn nicht mitnimmt.
- **E6 Kein https-Zwang.** Die sha256 kommt vom selben Host und schützt nur vor Übertragungsfehlern; die Echtheit hängt am Vertrauen in den Feed-Host. Steht in `INSTALL.md`, in `upgrade-instance.md` Schritt 4 und im Record.
- **E7 Netzcode in `version.py`:** `fetch_latest_assets`/`LatestRelease`, `token_for_asset`, `download_asset` (gestreamt, 60 s Socket-Timeout, Fehler als `VersionError` mit URL). Der Docstring von `fetch_latest` nennt drei Befehle.
- **E8 `--dry-run`** lädt, prüft und klassifiziert, schreibt nichts und räumt auf.
- **E9 Nicht Teil dieses Pakets:** Die `upstream merge`-Verweise im Record und in der `fail()`-Meldung von `run_upgrade` bleiben für #153; ebenso der Neuschnitt von `INSTALL.md`.
- **E10 (Betreiber 2026-09-29, Variante B) `--expect <version>`,** nur mit `--latest`: meldet der Feed eine andere Version, Exit 1 vor dem Download, Meldung nennt beide Versionen und verweist auf `version notes`. Verglichen wird die geparste Version (`v`-Präfix egal, `-beta.N` zulässig). `upgrade-instance.md` übergibt die Version aus Schritt 2 in Dry-Run und echtem Lauf. Die Ablehnungstexte für lokal geänderte Dateien nennen auf diesem Pfad `dist upgrade --latest --expect <version> …` als Wiederholungszeile.
## Umgesetzt
1. `tools/chemenu/version.py`: Asset-Suche, Download, Origin-Regel, Namenskonstante, Docstring.
2. `tools/chemenu/commands/dist_cmd.py`: `--latest`/`--expect`, `_query_feed`, `_downloaded_source`, gemeinsame Versionsprüfung `_version_gate`; Record mit Synopsis `dist upgrade (<source> | --latest [--expect <version>]) …`, `network: yes`, neuen Notes, sechs neuen Failure-Einträgen und Beispiel `dist upgrade --latest --expect 8.0.0 --dry-run`.
3. `tools/chemenu/commands/version_cmd.py`: Record-Note und Modul-Docstring nennen `dist upgrade --latest` als dritten Feed-Aufrufer.
4. `tools/CONTRACT.md` über `docs contract --apply`.
5. `instructions/upgrade-instance.md`: Schritt 4 erklärt `--latest` und den Tarball als Offline-Alternative; Schritte 5–7 nutzen `--latest --expect <version from step 2>`. Schrittnummern unverändert.
6. `INSTALL.md`: drei Befehle mit Netzzugriff, `--latest`/`--expect`, Echtheitshinweis, Sonderfall „erster Sprung auf ein Release, das `--latest` kennt“ (ohne Versionsnummer, weil der Kandidat noch 7.1.0-beta.N heißt).
7. Tests: `test_dist_upgrade.py` mit lokalem `http.server` (Anfrage- und `Authorization`-Log, `tempfile.tempdir` umgelenkt); `test_cli.py` nimmt `dist upgrade` in die Menge der `network: yes`-Befehle auf.
8. Version: `version bump --minor --impact high`, CHANGES-Prosa.
9. Nachzug beim Abschluss: `EVALS.md` sagte, die echten `urllib`-Zeilen in `version.py` blieben ungetestet; das stimmt nicht mehr (Lauf gegen lokalen `http.server`), korrigiert in `94deccb`.
## Akzeptanzkriterien
- [x] Gegen einen lokalen Test-Feed lädt `dist upgrade --latest` das neueste Release, prüft die sha256 und führt das Upgrade durch; jede Datei stimmt per Digest mit dem Baum nach `dist upgrade <tarball>` überein (`test_latest_yields_the_same_tree_as_the_archive_it_downloaded`).
- [x] Falsche oder fehlende `.sha256` → Exit 1, nichts geschrieben, kein `wikitool-upgrade-*`-Eintrag im Temp-Verzeichnis.
- [x] Feed nicht erreichbar → Exit 1 mit Feed-URL, nie „aktuell“.
- [x] Installierte Version ist die neueste → erfolgreicher No-op ohne Asset-Anfrage.
- [x] Tarball- oder Summen-Asset fehlt → Exit 1 ohne Download, vorhandene Assets genannt.
- [x] Tarball-`VERSION` ≠ Feed-Version → Exit 1, nichts geschrieben.
- [x] Feed-Version ≠ `--expect` → Exit 1 ohne Asset-Anfrage, beide Versionen genannt; `--expect` ohne `--latest` → Exit 1.
- [x] `WIKITOOL_UPDATE_TOKEN` erreicht keine Download-URL auf einem anderen Origin.
- [x] Ein Test hält den Asset-Namen in `release.yml` und im Code zusammen.
- [x] `INSTALL.md` führt `dist upgrade --latest` bei den Befehlen mit Netzzugriff; `docs verify`, `instructions verify`, `pytest` und CI grün.
## Modelle
Entwurf, Versionsteil und E1–E10: Opus (Vorbereitung am 2026-09-29). Umsetzung, Tests, Bump, CHANGES-Prosa und Doku-Nachzug: Sonnet 5.5. Abschluss (dieser Text, `docs/`-/Doku-Prüfung, CI): Opus 5.5.
## Version
minor, 7.1.0-beta.32; landet im 8.0.0-Kandidaten (#140 D19).
Changelog: Zur Umsetzung vorbereitet. Neu im Body: „Befund am Baum“ (Feed-Form live gegen v7.0.0 geprüft) und die Entscheidungen E1–E9 (Name --latest, kein --version, Reihenfolge mit Versionsprüfung vor dem Download, Asset-Suche nach exaktem Namen, Token nur an denselben Origin, upstream-Verweise bleiben bei #153). E10 (Absicherung zwischen Notes und Swap) ist offen. Umfang um Dateiliste und Testplan ergänzt, dazu vier Akzeptanzkriterien: Asset fehlt, Versionsabweichung, Token-Origin, Guard-Test gegen release.yml.
**Changelog:** Zur Umsetzung vorbereitet. Neu im Body: „Befund am Baum“ (Feed-Form live gegen v7.0.0 geprüft) und die Entscheidungen E1–E9 (Name `--latest`, kein `--version`, Reihenfolge mit Versionsprüfung vor dem Download, Asset-Suche nach exaktem Namen, Token nur an denselben Origin, `upstream`-Verweise bleiben bei #153). E10 (Absicherung zwischen Notes und Swap) ist offen. Umfang um Dateiliste und Testplan ergänzt, dazu vier Akzeptanzkriterien: Asset fehlt, Versionsabweichung, Token-Origin, Guard-Test gegen `release.yml`.
Changelog: E10 entschieden (Betreiber): --expect <version> statt reiner Anleitungs-Prüfung. Umfang, Failure-Einträge, Testplan und ein Akzeptanzkriterium nachgezogen; Stand: Umsetzung läuft, Halt nach dem Publish vor stack-close.
**Changelog:** E10 entschieden (Betreiber): `--expect <version>` statt reiner Anleitungs-Prüfung. Umfang, Failure-Einträge, Testplan und ein Akzeptanzkriterium nachgezogen; Stand: Umsetzung läuft, Halt nach dem Publish vor `stack-close`.
Abgeschlossen: Stand auf „abgeschlossen“ mit CI-Läufen 427/428/429 gesetzt, E3-Abweichung (kein eigener strikter Summenmodus) begründet, EVALS.md-Nachzug (94deccb) und Modelle je Phase ergänzt.
Abgeschlossen: Stand auf „abgeschlossen“ mit CI-Läufen 427/428/429 gesetzt, E3-Abweichung (kein eigener strikter Summenmodus) begründet, `EVALS.md`-Nachzug (`94deccb`) und Modelle je Phase ergänzt.
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.
Teilpaket von #140. D17 ist entschieden (Betreiber, 2026-09-28).
Stand
Abgeschlossen am 2026-09-29 im Kandidaten 7.1.0-beta.32 (Richtung 8.0.0, #140 D19).
dist upgrade --latest [--expect <version>]lädt das neueste Release aus dem Feed, prüft es und spielt es über den bestehenden Upgrade-Pfad ein.Geprüft:
pytestintools/komplett grün (1579 Tests, danachtest_dist_upgrade.pymit 64 Tests nach dem letzten Zusatztest),docs verifyundinstructions verifygrün. CI grün aufcf89231(Läufe 427 und 428) und auf dem Doku-Nachzug94deccb(Lauf 429). Gegen den echten Gitea-Feed wurde--latestnicht ausgeführt: Das Ursprungs-Repo hat keinen Stamp,dist upgradeverweigert dort. Der erste echte Lauf ist das Update einer Instanz auf 8.0.0.Warum
Echte Installationen beziehen ihre Updates aus dem Gitea-Feed (#140 D7). Vorher lud
dist upgradenichts selbst herunter („Never downloads anything“). Der Agent musste Tarball und.sha256vorher holen, und zwar genau mit den Shell-Konstrukten (curl,sha256sum,tar), die #153 aus den Anleitungen entfernt. Unter Windows hätte er dafür zusätzlich pwsh-Syntax gebraucht.version checkkannte den Feed bereits: aus dem Stamp oder ausWIKITOOL_UPDATE_URL.Ausgangslage vor der Umsetzung
version.update_url()(Env → Stamp →DEFAULT_UPDATE_URL, immer…/releases/latest).version._fetch_latest_object()liefert das ganze Release-Objekt aus einer Anfrage.fetch_latest_notesbegründet, warum nie eine/releases/tags/<tag>-URL zusammengesetzt wird.assets[]mitnameundbrowser_download_url, z. B.chemenu-stack-7.0.0.tar.gzund….tar.gz.sha256.tag_nameträgt einv, dasVersion.parseakzeptiert. Den Namen setzt.gitea/workflows/release.yml(name="chemenu-stack-${VERSION}").run_upgrade()prüft zuerst die lokalen Vorbedingungen, dann löst_resolved_source()die Quelle auf (Sidecar-Prüfung, Entpacken in einTemporaryDirectory).fail()wirfttyper.Exit;with-Blöcke räumen also auch im Fehlerfall auf.Entscheidungen
dist upgrade --latest.<source>ist optional; genau eines von beiden ist Pflicht. Beides oder keins ergibt Exit 1 vor jeder Prüfung.--version <v>. Eine beliebige Version zu holen hieße, eine Tags-URL aus derlatest-URL zu raten (Invariante 7). Ein Downgrade wird ohnehin verweigert; eine andere Version als die neueste hat keinen Anwendungsfall.--expectundVERSIONprüfen, vor jedem Download (gleich → No-op „Already at …“, älter → Downgrade-Ablehnung, Pre-Release ohne--pre→ Ablehnung) → Asset-Paar im Release-Objekt suchen, fehlt eines → Exit 1 vor dem ersten Download → beide in einTemporaryDirectory(prefix="wikitool-upgrade-")laden → Summe prüfen → bestehender Pfad. Zusätzlich:VERSIONim Tarball muss der Feed-Version entsprechen, sonst Exit 1 und nichts wird angewendet.Die „strikte“ Summenprüfung brauchte keinen eigenen Modus in
_verify_sha256_sidecar: auf diesem Pfad ist die Summe immer vorhanden, weil ihr Fehlen schon bei der Asset-Suche abgelehnt wird.assets-Feld des schon geholten Release-Objekts; die URL kommt ausbrowser_download_url, nie zusammengesetzt. Die Fehlermeldung nennt die vorhandenen Assets und die Release-Seite. Der Name steht alsversion.ARCHIVE_NAMEin Python;test_release_asset_names_match_the_workflowhält ihn mitrelease.ymlzusammen.INSTALL.md, inupgrade-instance.mdSchritt 4 und im Record.version.py:fetch_latest_assets/LatestRelease,token_for_asset,download_asset(gestreamt, 60 s Socket-Timeout, Fehler alsVersionErrormit URL). Der Docstring vonfetch_latestnennt drei Befehle.--dry-runlädt, prüft und klassifiziert, schreibt nichts und räumt auf.upstream merge-Verweise im Record und in derfail()-Meldung vonrun_upgradebleiben für #153; ebenso der Neuschnitt vonINSTALL.md.--expect <version>, nur mit--latest: meldet der Feed eine andere Version, Exit 1 vor dem Download, Meldung nennt beide Versionen und verweist aufversion notes. Verglichen wird die geparste Version (v-Präfix egal,-beta.Nzulässig).upgrade-instance.mdübergibt die Version aus Schritt 2 in Dry-Run und echtem Lauf. Die Ablehnungstexte für lokal geänderte Dateien nennen auf diesem Pfaddist upgrade --latest --expect <version> …als Wiederholungszeile.Umgesetzt
tools/chemenu/version.py: Asset-Suche, Download, Origin-Regel, Namenskonstante, Docstring.tools/chemenu/commands/dist_cmd.py:--latest/--expect,_query_feed,_downloaded_source, gemeinsame Versionsprüfung_version_gate; Record mit Synopsisdist upgrade (<source> | --latest [--expect <version>]) …,network: yes, neuen Notes, sechs neuen Failure-Einträgen und Beispieldist upgrade --latest --expect 8.0.0 --dry-run.tools/chemenu/commands/version_cmd.py: Record-Note und Modul-Docstring nennendist upgrade --latestals dritten Feed-Aufrufer.tools/CONTRACT.mdüberdocs contract --apply.instructions/upgrade-instance.md: Schritt 4 erklärt--latestund den Tarball als Offline-Alternative; Schritte 5–7 nutzen--latest --expect <version from step 2>. Schrittnummern unverändert.INSTALL.md: drei Befehle mit Netzzugriff,--latest/--expect, Echtheitshinweis, Sonderfall „erster Sprung auf ein Release, das--latestkennt“ (ohne Versionsnummer, weil der Kandidat noch 7.1.0-beta.N heißt).test_dist_upgrade.pymit lokalemhttp.server(Anfrage- undAuthorization-Log,tempfile.tempdirumgelenkt);test_cli.pynimmtdist upgradein die Menge dernetwork: yes-Befehle auf.version bump --minor --impact high, CHANGES-Prosa.EVALS.mdsagte, die echtenurllib-Zeilen inversion.pyblieben ungetestet; das stimmt nicht mehr (Lauf gegen lokalenhttp.server), korrigiert in94deccb.Akzeptanzkriterien
dist upgrade --latestdas neueste Release, prüft die sha256 und führt das Upgrade durch; jede Datei stimmt per Digest mit dem Baum nachdist upgrade <tarball>überein (test_latest_yields_the_same_tree_as_the_archive_it_downloaded)..sha256→ Exit 1, nichts geschrieben, keinwikitool-upgrade-*-Eintrag im Temp-Verzeichnis.VERSION≠ Feed-Version → Exit 1, nichts geschrieben.--expect→ Exit 1 ohne Asset-Anfrage, beide Versionen genannt;--expectohne--latest→ Exit 1.WIKITOOL_UPDATE_TOKENerreicht keine Download-URL auf einem anderen Origin.release.ymlund im Code zusammen.INSTALL.mdführtdist upgrade --latestbei den Befehlen mit Netzzugriff;docs verify,instructions verify,pytestund CI grün.Modelle
Entwurf, Versionsteil und E1–E10: Opus (Vorbereitung am 2026-09-29). Umsetzung, Tests, Bump, CHANGES-Prosa und Doku-Nachzug: Sonnet 5.5. Abschluss (dieser Text,
docs/-/Doku-Prüfung, CI): Opus 5.5.Version
minor, 7.1.0-beta.32; landet im 8.0.0-Kandidaten (#140 D19).
Changelog: Zur Umsetzung vorbereitet. Neu im Body: „Befund am Baum“ (Feed-Form live gegen v7.0.0 geprüft) und die Entscheidungen E1–E9 (Name
--latest, kein--version, Reihenfolge mit Versionsprüfung vor dem Download, Asset-Suche nach exaktem Namen, Token nur an denselben Origin,upstream-Verweise bleiben bei #153). E10 (Absicherung zwischen Notes und Swap) ist offen. Umfang um Dateiliste und Testplan ergänzt, dazu vier Akzeptanzkriterien: Asset fehlt, Versionsabweichung, Token-Origin, Guard-Test gegenrelease.yml.Changelog: E10 entschieden (Betreiber):
--expect <version>statt reiner Anleitungs-Prüfung. Umfang, Failure-Einträge, Testplan und ein Akzeptanzkriterium nachgezogen; Stand: Umsetzung läuft, Halt nach dem Publish vorstack-close.Abgeschlossen: Stand auf „abgeschlossen“ mit CI-Läufen 427/428/429 gesetzt, E3-Abweichung (kein eigener strikter Summenmodus) begründet,
EVALS.md-Nachzug (94deccb) und Modelle je Phase ergänzt.