raw accept: Stem-Eindeutigkeit im Typverzeichnis erzwingen, --replaces als einziger Weg daran vorbei (schliesst #64)
CI / verify (push) Successful in 55s
Release / release (push) Successful in 35s

Files changed:
- CHANGES.md
- VERSION
- instructions/wiki-ingest/SKILL.md
- raw/CONTRACT.md
- tools/CONTRACT.md
- tools/chemenu/commands/raw_cmd.py
- tools/chemenu/tests/test_raw_cmd.py
This commit is contained in:
2026-09-05 08:51:41 +02:00
parent 36d2128f29
commit 0b3c496fff
7 changed files with 454 additions and 7 deletions
+43 -1
View File
@@ -35,7 +35,7 @@ dev-checkout concern - readable here, never shipped as something to parse.
---
## 4.8.0-beta.3 - 2026-09-05 - raw accept: incoming/ als abgeleiteter Rohablage-Eingang (schliesst #58)
## 4.8.0-beta.4 - 2026-09-05 - raw accept: Stem-Eindeutigkeit im Typverzeichnis erzwingen, --replaces als einziger Weg daran vorbei (schliesst #64)
**Author:** Torben Nehmer
@@ -44,6 +44,7 @@ dev-checkout concern - readable here, never shipped as something to parse.
- page move: eine kb-Seite folgt ihrem Subtype ins Verzeichnis, das ihr Type-Spec berechnet
- kb/CONTRACT.md: Tiefe 1 als Grenze - Katalog liest nur eine Area-Ebene
- raw accept: incoming/ als abgeleiteter Rohablage-Eingang (schliesst #58)
- raw accept: Stem-Eindeutigkeit im Typverzeichnis erzwingen, --replaces als einziger Weg daran vorbei (schliesst #64)
<!-- /wikitool:bumps -->
Das Label `status/incoming` gibt es seit heute in Gitea: der Mensch legt einen
@@ -258,6 +259,47 @@ unangetastet, keine fremde Instanz muss migrieren, vorwärts wie rückwärts rei
Schließt #58.
`raw accept` prüfte Kollisionen bisher nur auf einzelnen Dateipfaden
(`dst.exists()`), nie auf dem Bundle-Verzeichnis selbst. Weil der Bundle-Name
aus dem Stem der Primärdatei entsteht, konnte eine zweite, unabhängige Quelle
wortlos in das Bundle einer ersten wandern, sobald die Dateinamen zufällig
nicht kollidierten — verifiziert mit einem Wegwerf-Test: `handbuch.txt` +
`anhang.md` ohne `--page` landeten unbemerkt in einem bestehenden
`raw/documents/handbuch/`. `lint` meldete nichts, weil beide Quellen ihre
Dateien korrekt abdeckten.
Die Menge der Namen auf `raw/<typ>/`-Ebene — Dateistämme plus
Bundle-Verzeichnisnamen — ist jetzt eindeutig erzwungen (`_occupied_stems` in
`raw_cmd.py`), unter Ausnahme dessen, was der Aufruf selbst schon besitzt: ein
Bundle, das über `--page` wächst, oder ein bereits registriertes, sich
fortsetzendes Bundle. Ein belegter Stem wird mit Exit 1 abgelehnt und nennt
beide Auswege, ohne einen zu empfehlen — `--replaces` oder Umbenennen in
`incoming/`.
`--replaces <raw-pfad>` ist der einzige sanktionierte Weg, eine Rohdatei
wortwörtlich zu ersetzen: genau eine eingehende Datei, identischer Dateiname,
gleiches Typverzeichnis, Ablehnung bei mehr als einem Owner. `raw_files:`
bleibt unverändert, es wird keine `kb/`-Seite geschrieben, und die Altfassung
lebt ausschließlich in `git log --follow` weiter — kein Archivverzeichnis,
kein Hash im Dateinamen, kein neues Frontmatter-Feld. Nach einem Ersatz nennt
das Kommando die Source-Seite und ihre zitierenden Seiten, damit deren
Nachzug im selben Commit passiert wie die Ersetzung.
`raw/CONTRACT.md` § Rules trägt beide Regeln aus dieser Entscheidung
(unveränderlich, aber ersetzbar als Ganzes); `instructions/wiki-ingest/SKILL.md`
benennt den Kollisionsfall als Haltepunkt, an dem eine Sitzung die Meldung dem
Menschen vorlegt statt selbst zu entscheiden — dieselbe Klasse wie AGENTS.md
Invariante 6, auch ohne dass hier ein Exit-42-Gate greift.
Geändert: `tools/chemenu/commands/raw_cmd.py` (`_occupied_stems`,
`_stem_collision_message`, `--replaces`/`_replace`),
`tools/chemenu/tests/test_raw_cmd.py` (16 neue Tests), `raw/CONTRACT.md`,
`tools/CONTRACT.md`, `instructions/wiki-ingest/SKILL.md`. MINOR: `raw accept`
wurde nie released (letztes Release `v4.7.4`), die Verschärfung kostet also
keine Kompatibilitätsfrage, solange sie vor `4.8.0` landet.
Schließt #64.
---
## 4.7.4 - 2026-09-04 - bootstrap.md nennt den session-id-WARN nach frischem Bootstrap explizit als erwartet