diff --git a/CHANGES.md b/CHANGES.md index e84635e..ab5c5a9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -35,6 +35,43 @@ dev-checkout concern - readable here, never shipped as something to parse. --- +## 4.4.1-beta.1 - 2026-09-03 - Faktenkorrekturen in der 4.4.0-Prosa; DEVELOPMENT.md ohne zweite Kommandobeschreibung + +**Author:** Torben Nehmer + + +- Faktenkorrekturen in der 4.4.0-Prosa; DEVELOPMENT.md ohne zweite Kommandobeschreibung + + +Die Prosa zu 4.4.0 - Changelog-Eintrag, `docs/version-model.md`, `instructions/dev/version-parts.md`, +`DEVELOPMENT.md` - entstand ungeprüft: kein maschineller Check liest sie, und die Sitzung, die sie +schrieb, hat den dafür vorgesehenen Modellwechsel aus `stack-dev` Schritt 6 übersprungen. Ein +nachgeholter Durchgang hat drei Fehler gefunden, von denen der erste der teuerste war. + +**Der Befund war an einer Stelle schlicht falsch.** Changelog und `docs/version-model.md` +behaupteten, unter dem alten Modell seien Nummern vergeben worden, die „nie ausgeliefert" wurden - +im Changelog sogar mit einer erfundenen Zahl („fünf Minor-Bumps ... vier nie ausgeliefert"). Das +Gegenteil stimmt: weil `release.yml` auf jede `VERSION`-Bewegung feuerte, wurde **jeder** Bump zu +einem echten, getaggten Release. Der 2026-09-03 hat vier davon in sechs Stunden erzeugt (`4.3.0` +bis `4.3.3`), zwei für reine Prosa-Änderungen. Der Schaden war nie ein Phantom-Release, sondern +dass „Release" aufhörte, etwas zu bedeuten - vier Upgrades an einem Nachmittag sind für einen +Konsumenten kein kleineres Versprechen, sondern ein unleserliches. Beide Stellen tragen jetzt den +tatsächlichen Vorgang samt Beleg. + +Dazu zwei kleinere Korrekturen: `version-parts.md` nannte den Stack weiterhin `2.x` (er steht bei +`4.x`), und `DEVELOPMENT.md` trug eine Tabelle, die für jeden Verify-Befehl ein zweites Mal +beschrieb, was er prüft - eine Kopie dessen, was `tools/CONTRACT.md` hält und `docs verify` dort +gegen die CLI prüft. Die Tabelle ist raus; dass die Datei selbst außerhalb der von diesem Check +abgedeckten Dokumente liegt, steht jetzt an ihrer Stelle. Der Code-seitige Teil davon - ob +`DEVELOPMENT.md` in `docs_verify.STAGE_READMES` gehört - hängt an #47, zusammen mit der Lücke im +Skill, die den übersprungenen Modellwechsel überhaupt erst unauffällig gemacht hat. + +Kein Verhalten geändert, nur Prosa - und bewusst als laufender Kandidat gelassen statt fixiert: +CIs Version-Gate verlangt die `VERSION`-Bewegung, ein Release verlangt sie nicht. Genau dafür gibt +es das Modell aus 4.4.0. + +--- + ## 4.4.0 - 2026-09-03 - Versionskandidat statt Bump-pro-Release: VERSION traegt -beta.N, version release fixiert **Author:** Torben Nehmer @@ -43,12 +80,14 @@ dev-checkout concern - readable here, never shipped as something to parse. - Versionskandidat statt Bump-pro-Release: VERSION traegt -beta.N, version release fixiert -Bisher bekam jeder `version bump` sofort eine fixierte, dauerhafte Nummer, unabhängig davon, ob -je ein Release dazu erschien - fünf Minor-Bumps ohne Release ergaben fünf Nummern, von denen vier -nie ausgeliefert wurden. `VERSION` trägt jetzt zwischen zwei Releases **einen** laufenden -Kandidaten (`X.Y.Z-beta.N`) statt einer neuen Nummer pro Bump: `--major/--minor/--patch` -eskaliert diesen Kandidaten max-wins gegen den letzten Release, statt daneben eine neue Nummer zu -schreiben, und schrittet dabei nie zurück. +Bisher bekam jeder `version bump` sofort eine fixierte Nummer, und weil `release.yml` auf jede +`VERSION`-Bewegung feuert, wurde daraus sofort ein Release: Nummern entstanden in +Commit-Granularität statt in Release-Granularität. Der 2026-09-03 hat so vier Releases in sechs +Stunden erzeugt (`4.3.0` bis `4.3.3`), zwei davon für reine Prosa-Änderungen - alle vier echt, +keines davon eine Einheit, an der ein Konsument sich hätte orientieren können. `VERSION` trägt +jetzt zwischen zwei Releases **einen** laufenden Kandidaten (`X.Y.Z-beta.N`): +`--major/--minor/--patch` eskaliert diesen Kandidaten max-wins gegen den letzten Release, statt +eine neue Nummer danebenzustellen, und geht dabei nie zurück. `Version` versteht den Suffix, mit einer expliziten Ordnung (`4.4.0-beta.1 < 4.4.0-beta.2 < 4.4.0`, numerisch nach `N`, nicht lexikografisch). `CHANGES.md` diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 5b62e32..c32a3fa 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -71,15 +71,13 @@ eine Sitzung ihn tatsächlich durchläuft: lädt Tarball plus Prüfsumme hoch. **CI setzt den Tag, nie eine Sitzung** - das hält Invariante 5 intakt. -## Verify-Befehle im Überblick - -| Befehl | Prüft | -|---|---| -| `cd tools && .venv/bin/python -m pytest -q` | Die gesamte Testsuite, hermetisch gegen eine leere Maschine (siehe `instructions/dev/testing-conventions.md`) | -| `tools/wikitool docs verify` | CLI-Kommandotabelle, Contract-Präsenz, Type-Drift, `.gitignore`-Kanarienvögel, `VERSION`/`CHANGES.md`-Übereinstimmung, Grenzübertritts-Dokumentation | -| `tools/wikitool instructions verify` | Jede Instruction und jeder Skill unter `instructions/`, verwaiste Dateien, `instructions/dev/`-Referenzen von außerhalb | - -Die volle Kommandoreferenz inklusive Fehlerkontrakt: [tools/CONTRACT.md](tools/CONTRACT.md). +Die drei Verify-Befehle stehen oben in Schritt 3; was jeder von ihnen prüft, steht in +[tools/CONTRACT.md](tools/CONTRACT.md) und wird dort von `docs verify` gegen die tatsächliche +CLI gehalten. Hier steht es bewusst **nicht** noch einmal: eine zweite Beschreibung derselben +Befehle ist genau die Kopie, die driftet (AGENTS.md Invariante 8), und dieses Dokument liegt +außerhalb der Dateien, die der Kommandotabellen-Check von `docs verify` abdeckt - hier fällt eine +Drift also niemandem auf. Was `pytest` an dieser Stelle vom Entwickler erwartet, steht in +[instructions/dev/testing-conventions.md](instructions/dev/testing-conventions.md). ## Die CI-Hälfte diff --git a/VERSION b/VERSION index fdc6698..6e5db82 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.4.0 +4.4.1-beta.1 diff --git a/docs/version-model.md b/docs/version-model.md index 0f1a24e..f7e7171 100644 --- a/docs/version-model.md +++ b/docs/version-model.md @@ -83,22 +83,27 @@ matter just as much in practice: how many numbers get handed out along the way t release. For a while the answer was "one per bump," and that turned out to be the wrong grain entirely. -The two things that actually consume a version number are a release and CI's version gate - and -they disagree about granularity. The gate wants `VERSION` to move on every push that touches -stack-shaped paths, which is a *commit*-level question: has this tree changed since the last -push. A release wants to know something else: has *this specific number* been published, ever. -Handing out a fresh number per bump answers the gate's question by accident and the release's -question wrongly - it treats every bump as if it were about to ship, when most of them are steps -toward a release that hasn't happened yet. Four bumps in one session, on the same day, for the -same eventual release, produced four numbers that a version-check feed would have reported as -four different available upgrades, three of which were never real. +Two mechanisms decide when a number gets minted, and they answer different questions. CI's +version gate asks a *commit*-level one: has this tree changed since the last push, and if so +has `VERSION` moved with it. A release asks something else entirely: is this a state worth +handing to someone, under a number they will pin against. Tying the second to the first - every +`VERSION` move firing the release workflow - answers the gate correctly and the release question +by accident, because it treats every bump as if it were about to ship when most bumps are steps +toward a release that has not happened yet. + +The failure mode is not phantom numbers; every one of those releases was real, tagged and +downloadable. It is that "real" stopped meaning anything. On 2026-09-03 this repository cut four +releases in six hours - `4.3.0` through `4.3.3` - for one continuous arc of work, two of them for +prose changes alone. Someone tracking the feed saw four upgrades and had no way to tell which, if +any, was a moment worth stopping for. A release is a promise addressed to a consumer, and a +promise made four times an afternoon is not a smaller promise, it is a less legible one. The fix is not to slow the gate down - it still wants `VERSION` to move every time, and it still -gets that. It's to stop treating every movement as a new number. Between two releases the stack -now carries one running candidate, escalating through `-beta.N` as bumps accumulate, and only -`version release` spends the number for real by fixing it and closing its changelog entry. A -number is proposed by a bump and consumed by a release; conflating the two was the actual defect, -not the arithmetic of any single bump. +gets that. It is to stop treating every movement as a number worth publishing. Between two +releases the stack now carries one running candidate, escalating through `-beta.N` as bumps +accumulate, and only `version release` spends the number for real by fixing it and closing its +changelog entry. A number is proposed by a bump and spent by a release; conflating the two was +the actual defect, not the arithmetic of any single bump. This is also why a candidate never gets to a distributed instance. The promise a released version makes - "install this, and it is exactly what its number says" - has no equivalent for something diff --git a/instructions/dev/version-parts.md b/instructions/dev/version-parts.md index 8866343..209d624 100644 --- a/instructions/dev/version-parts.md +++ b/instructions/dev/version-parts.md @@ -9,7 +9,7 @@ Two questions decide a version bump, and they are **not the same question**: 1. **Is the new version a drop-in replacement for the old one?** This is what the version number itself says. Compatibility is read off the **leftmost non-zero component** - on this - stack (`2.x`) that is MAJOR, on a `0.x` stack it is MINOR. A bump that changes it is called + stack (`4.x`) that is MAJOR, on a `0.x` stack it is MINOR. A bump that changes it is called *boundary-crossing* below, because that is the term `version bump` and `docs verify` use in their own messages. 2. **Must existing content be migrated?** This is a *consequence* a boundary crossing may or @@ -23,11 +23,13 @@ already (see the case study at the end), which is why this file exists. ## The candidate model Between two releases the stack carries **one running candidate**, not a fresh version per -`bump`. Five bumps with no release in between used to mean five numbers, four of which nothing -ever consumed - the release-granularity CI's version gate wants (`VERSION` must move on every -stack-touching push) was being paid at bump granularity instead. A candidate closes that gap -without touching the gate: `VERSION` still moves on every bump, it just escalates the *same* -number instead of handing out a new one. +`bump`. Before that, every bump minted a number *and* a release: CI's version gate requires +`VERSION` to move on every stack-touching push, and `release.yml` fires on every `VERSION` +move, so releases were being cut at commit granularity. 2026-09-03 produced four of them in +six hours (`4.3.0` through `4.3.3`) for one arc of work - all four real, none of them a +meaningful unit to anyone downstream. A candidate closes that gap without touching the gate: +`VERSION` still moves on every bump, it just escalates the *same* number instead of handing out +a new one, and only `version release` turns it into something the release workflow acts on. - **State lives in `VERSION` itself**, as an optional `-beta.N` suffix (`4.4.0-beta.3`). No second state file: the last release is read back out of `CHANGES.md` (the newest entry with no @@ -35,8 +37,8 @@ number instead of handing out a new one. release - derived, not stored. - **`--major`/`--minor`/`--patch` is max-wins escalation**, not a step you can undo. A `--patch` bump on a candidate already at MINOR only advances its bump count (`N`); nothing ever steps a - candidate back down. Declaring the part is still your judgment call, made the same way section - below describes - `escalate()` only ever raises it further. + candidate back down. Declaring the part is still your judgment call, made the same way the + steps below describe - `escalate()` only ever raises it further. - **A candidate is never released.** Pre-release is a dev-checkout state; `release.yml` only acts on a suffix-free `VERSION`, so a distributed instance never sees a `-beta.` version at all, and its parser never has to know the suffix exists.