diff --git a/CHANGES.md b/CHANGES.md index a13bba6..dc2e043 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -35,7 +35,7 @@ dev-checkout concern - readable here, never shipped as something to parse. --- -## 5.0.0-beta.15 - 2026-09-11 - incoming/.gitkeep als Datei- statt Verzeichnismuster trackbar (schliesst #88) +## 5.0.0-beta.17 - 2026-09-11 - raw/*/.gitkeep-Glob in dist-upgrade-Doku auf den flachen raw/.gitkeep-Anker korrigiert **Author:** Torben Nehmer @@ -68,6 +68,8 @@ dev-checkout concern - readable here, never shipped as something to parse. - docs verify prueft die Kommando- und Fehlerkontrakttabelle in tools/CONTRACT.md getrennt, 10 fehlende Fehlerkontrakt-Zeilen nachgetragen (schliesst #91) - tools/CONTRACT.md als Nachschlage-Dokument strukturiert: ###-Gruppen in beiden Tabellen, spiegelnde Reihenfolge, Lead-in-Regel - incoming/.gitkeep als Datei- statt Verzeichnismuster trackbar (schliesst #88) +- dist export-Doku: Typverzeichnis-Behauptung nach #67 korrigiert (schliesst #93) +- raw/*/.gitkeep-Glob in dist-upgrade-Doku auf den flachen raw/.gitkeep-Anker korrigiert @@ -1344,6 +1346,44 @@ Zeile), `README.md` (Architekturdiagramm-Kommentar). Verifiziert: `tools/wikitoo `tools/wikitool instructions verify`, volle `pytest`-Suite (1195 passed), manueller `dist export`-Replay. Schließt #88. +**`dist export`-Doku nennt keine Typverzeichnisse mehr, die seit #67 nicht mehr angelegt werden +(#93).** `tools/CONTRACT.md`s `dist export`-Zeile und der `--help`-Docstring des Kommandos +selbst behaupteten wortgleich, ein frischer Export lege leere +`raw/{articles,documents,notes,assets}/` und die passenden `incoming/`-Typverzeichnisse an. #67 +hat die Typverzeichnisse aus dem Adressierungsschema von `raw accept` entfernt (Datums-Shard +statt Typverzeichnis) und dabei den Export-Pfad auf zwei flache Anker verkürzt +(`raw/.gitkeep`, `incoming/.gitkeep` - `run_export`), ohne die zwei Prosa-Stellen nachzuziehen, +die noch die alte Struktur beschrieben. Nebenbefund aus der Sitzung zu #88. + +Beide Stellen beschreiben jetzt den tatsächlichen flachen Export. Gegengeprüft per +`tools/wikitool dist export` in ein leeres Scratch-Verzeichnis: `raw/` enthält nach dem Export +nur `.gitkeep` (plus die verzeichniseigene `CONTRACT.md`), `incoming/` nur `.gitkeep` - keine +Typunterverzeichnisse unter keinem der beiden Wurzeln. + +Außerhalb der Akzeptanzkriterien dieses Issues, aber derselbe Fund: dieselbe Prosa-Drift bei +`raw/*/.gitkeep` in der `dist upgrade`-Zeile (`tools/CONTRACT.md`), in +`docs/ownership-and-templates.md` und im `apply_upgrade`-Docstring - andere Fundstelle, gleiche +Ursache. In derselben Sitzung gleich mitkorrigiert, siehe die nächste Eintragszeile unten. + +Geändert: `tools/CONTRACT.md` (`dist export`-Zeile), `tools/chemenu/commands/dist_cmd.py` +(`--help`-Docstring von `export`). Verifiziert: `tools/wikitool docs verify`, +`tools/wikitool instructions verify`, volle `pytest`-Suite, manueller `dist export`-Replay in +ein leeres Scratch-Verzeichnis. Schließt #93. + +**`raw/*/.gitkeep`-Glob war seit #67 ebenfalls stale - korrigiert auf den flachen +`raw/.gitkeep`-Anker.** Nebenbefund beim Nachziehen von #93 in derselben Sitzung: dieselbe +Typverzeichnis-Drift steckte noch an drei weiteren Stellen, die von einem *mehrfachen* +`raw//.gitkeep` sprachen, obwohl `raw/` seit #67 flach ist und es nur noch den einen +`raw/.gitkeep`-Anker gibt - `chemenu.ownership.is_export_stub`/`is_upgrade_preserved` matchen +ohnehin per Dateiname statt Pfadtiefe, das Verhalten war also nie falsch, nur die illustrative +Glob-Schreibweise in der Prosa. Betroffen: `tools/CONTRACT.md`s `dist upgrade`-Zeile, +`docs/ownership-and-templates.md`s Aufzählung der seeded-once-Dateien, und der +`apply_upgrade`-Docstring in `dist_cmd.py`. + +Geändert: `tools/CONTRACT.md` (`dist upgrade`-Zeile), `docs/ownership-and-templates.md`, +`tools/chemenu/commands/dist_cmd.py` (`--help`-Docstring von `dist upgrade`). Verifiziert: +`tools/wikitool docs verify`, `tools/wikitool instructions verify`, volle `pytest`-Suite. + --- ## 4.7.4 - 2026-09-04 - bootstrap.md nennt den session-id-WARN nach frischem Bootstrap explizit als erwartet diff --git a/VERSION b/VERSION index badccdb..dd20b3e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.0-beta.15 +5.0.0-beta.17 diff --git a/docs/ownership-and-templates.md b/docs/ownership-and-templates.md index 0c04eb2..19a5d0d 100644 --- a/docs/ownership-and-templates.md +++ b/docs/ownership-and-templates.md @@ -92,7 +92,7 @@ becomes visible once an upgrade is a command rather than a hand-run copy: `kb//COLLECTION.md`, `ENVIRONMENT.md`, the `root: kb` type-specs - are never written by an upgrade at all. The distribution ships only the `.template` beside them, so the filled file is out of reach by construction rather than by a rule someone has to remember. -- **Seeded-once files** - `.wikitool-kb.json`, `CHANGES.md`, `kb/log.md`, `raw/*/.gitkeep` - are +- **Seeded-once files** - `.wikitool-kb.json`, `CHANGES.md`, `kb/log.md`, `raw/.gitkeep` - are written into a *new* instance by `dist export` and belong to the instance from then on. They are the awkward category: they sit in the release stamp's file list like any other shipped file, so an upgrade has to exclude them deliberately (`chemenu.ownership.is_export_stub` and diff --git a/tools/CONTRACT.md b/tools/CONTRACT.md index 0ac197f..b6b4b66 100644 --- a/tools/CONTRACT.md +++ b/tools/CONTRACT.md @@ -184,8 +184,8 @@ tools/wikitool --help | Command | Purpose | |---------|---------| -| `dist export [--dry-run] [--source-repo U] [--source-commit SHA] [--release-url U] [--update-url U]` | Write a contentless, distributable copy of this repo's machinery into an empty `` directory: `AGENTS.md`/`README.md`/`EVALS.md` with any `...` region removed, `instructions/` (minus `instructions/dev/`), `types/` (the `root: kb` page type-specs and their schemas re-keyed as `.template`, the stack's own verbatim), `docs/` verbatim, `tools/` (no venv/caches), the `.github/hooks/`+`.vibe/` session-tracing config plus `.claude/settings.json`, `kb/CONTRACT.md` (no pages, no areas), empty `raw/{articles,documents,notes,assets}/` and the matching `incoming/{articles,documents,notes,assets}/` (`incoming/.gitkeep` is trackable and survives becoming a git repository, so a plain clone gets the directory without any bootstrap step re-creating it), `VERSION`, `USER.md.template`/`SOUL.md.template` plus `kb/CONVENTIONS.md.template` and each collection's contract re-keyed as `kb//COLLECTION.md.template` (the templates ship; the filled `USER.md`/`SOUL.md`/`kb/CONVENTIONS.md`/`kb//COLLECTION.md`/`types/.md` never do - all of them bind their instance and none are the stack's to decide, and `find_leaks` refuses a plan carrying one), and a generated `.wikitool-release.json` stamp (version, export date, origin, and a sha256 per exported file - the base a later upgrade would compare against). The four origin options only fill stamp fields: `export` never calls git and cannot discover them. Refuses a non-empty target, and a tree with no `VERSION`. See `instructions/setup-instance.md`. One-way: there is no command that reconstructs a distributed instance into a dev instance - work on the stack in the origin repo (or a new dev instance exported from it) instead | -| `dist upgrade [--dry-run] [--keep-local] [--prune] [--pre]` | Apply a stack update `dist export` produced - the write half of `version check`. Never downloads anything: `` is an already-fetched export directory or `.tar.gz` release archive (verified against a sibling `.sha256` if one is present; WARNs, does not block, if it is absent), which must unpack to exactly one top-level directory - the shape `.gitea/workflows/release.yml` packs. The write set is exactly the *new* `.wikitool-release.json`'s `files` block, minus what an export re-seeds from a blank template every time (`kb/log.md`, `raw/*/.gitkeep` - `chemenu.ownership.is_export_stub`) or seeds once and the instance owns from then on (`.wikitool-kb.json`, `CHANGES.md` - `chemenu.ownership.is_upgrade_preserved`), plus the stamp itself, always rewritten. Every candidate path is classified against the *local* `.wikitool-release.json`'s recorded digest for it: unchanged is overwritten silently, absent from the old stamp is created, and locally modified or locally deleted is **never** silently overwritten - the run aborts with the full list unless `--keep-local` says to proceed and leave every one of them untouched. After a `--keep-local` run the new stamp is still written whole, so it records the release's digest for files that were deliberately *not* written: the stamp is the baseline for the next comparison, not a literal inventory of what is on disk. That is what keeps a skipped file diverging - and therefore reported - on every later run, rather than quietly reading as current once it has been skipped once. A path in the old stamp but not the new one is reported as no longer part of the release and left alone unless `--prune` is passed, which removes it only if it is still unchanged since installation. Reports the migration chain the new machinery would owe (`chemenu.kb_state.chain` over the *new* tree's `instructions/migrations/`, read via a `directory` argument to `load_migrations`) but never runs any of it - there is no `migrate run`. Refuses before touching the source at all when: `VERSION` or `.wikitool-release.json` (with a `files` block) is missing locally, `.wikitool-kb.json` is missing, a migration is already outstanding against the *installed* machinery, or the working tree is dirty (not being a git repository at all is a WARN, not a refusal). Refuses after reading the source when: it carries no `VERSION`/`.wikitool-release.json`/`files` block, its version is older than or equal to the installed one (equal is a no-op success), or it is a pre-release (`-beta.N`) without `--pre`. Reports, but does not block on, a crossed compatibility boundary. Never touches git - no commit, no push (invariant 5). See `INSTALL.md` § "Eine Instanz aktualisieren" | +| `dist export [--dry-run] [--source-repo U] [--source-commit SHA] [--release-url U] [--update-url U]` | Write a contentless, distributable copy of this repo's machinery into an empty `` directory: `AGENTS.md`/`README.md`/`EVALS.md` with any `...` region removed, `instructions/` (minus `instructions/dev/`), `types/` (the `root: kb` page type-specs and their schemas re-keyed as `.template`, the stack's own verbatim), `docs/` verbatim, `tools/` (no venv/caches), the `.github/hooks/`+`.vibe/` session-tracing config plus `.claude/settings.json`, `kb/CONTRACT.md` (no pages, no areas), the two flat anchors `raw/.gitkeep` and `incoming/.gitkeep` (both roots are flat now that a file's location under `raw/` is a date shard rather than a hand-picked type, so a fresh export no longer creates any type subdirectories under either root; `incoming/.gitkeep` is trackable and survives becoming a git repository, so a plain clone gets the directory without any bootstrap step re-creating it), `VERSION`, `USER.md.template`/`SOUL.md.template` plus `kb/CONVENTIONS.md.template` and each collection's contract re-keyed as `kb//COLLECTION.md.template` (the templates ship; the filled `USER.md`/`SOUL.md`/`kb/CONVENTIONS.md`/`kb//COLLECTION.md`/`types/.md` never do - all of them bind their instance and none are the stack's to decide, and `find_leaks` refuses a plan carrying one), and a generated `.wikitool-release.json` stamp (version, export date, origin, and a sha256 per exported file - the base a later upgrade would compare against). The four origin options only fill stamp fields: `export` never calls git and cannot discover them. Refuses a non-empty target, and a tree with no `VERSION`. See `instructions/setup-instance.md`. One-way: there is no command that reconstructs a distributed instance into a dev instance - work on the stack in the origin repo (or a new dev instance exported from it) instead | +| `dist upgrade [--dry-run] [--keep-local] [--prune] [--pre]` | Apply a stack update `dist export` produced - the write half of `version check`. Never downloads anything: `` is an already-fetched export directory or `.tar.gz` release archive (verified against a sibling `.sha256` if one is present; WARNs, does not block, if it is absent), which must unpack to exactly one top-level directory - the shape `.gitea/workflows/release.yml` packs. The write set is exactly the *new* `.wikitool-release.json`'s `files` block, minus what an export re-seeds from a blank template every time (`kb/log.md`, `raw/.gitkeep` - `chemenu.ownership.is_export_stub`) or seeds once and the instance owns from then on (`.wikitool-kb.json`, `CHANGES.md` - `chemenu.ownership.is_upgrade_preserved`), plus the stamp itself, always rewritten. Every candidate path is classified against the *local* `.wikitool-release.json`'s recorded digest for it: unchanged is overwritten silently, absent from the old stamp is created, and locally modified or locally deleted is **never** silently overwritten - the run aborts with the full list unless `--keep-local` says to proceed and leave every one of them untouched. After a `--keep-local` run the new stamp is still written whole, so it records the release's digest for files that were deliberately *not* written: the stamp is the baseline for the next comparison, not a literal inventory of what is on disk. That is what keeps a skipped file diverging - and therefore reported - on every later run, rather than quietly reading as current once it has been skipped once. A path in the old stamp but not the new one is reported as no longer part of the release and left alone unless `--prune` is passed, which removes it only if it is still unchanged since installation. Reports the migration chain the new machinery would owe (`chemenu.kb_state.chain` over the *new* tree's `instructions/migrations/`, read via a `directory` argument to `load_migrations`) but never runs any of it - there is no `migrate run`. Refuses before touching the source at all when: `VERSION` or `.wikitool-release.json` (with a `files` block) is missing locally, `.wikitool-kb.json` is missing, a migration is already outstanding against the *installed* machinery, or the working tree is dirty (not being a git repository at all is a WARN, not a refusal). Refuses after reading the source when: it carries no `VERSION`/`.wikitool-release.json`/`files` block, its version is older than or equal to the installed one (equal is a no-op success), or it is a pre-release (`-beta.N`) without `--pre`. Reports, but does not block on, a crossed compatibility boundary. Never touches git - no commit, no push (invariant 5). See `INSTALL.md` § "Eine Instanz aktualisieren" | | `version show [--json]` | Print this instance's stack version and where it came from (development tree, or a distribution with its export date and origin). Bare `wikitool version` is an alias for this. Read-only, offline, and **exempt from the Iteration Budget Gate** | | `version check [--url U] [--timeout S] [--json]` | Ask the origin's release feed whether a newer stack exists, and whether the step crosses a compatibility boundary (`state: current\|update\|migration\|ahead`). **The only command in `wikitool` that makes a network call** - never reached implicitly from another command, needs no key, times out, and reports an unreachable feed as an error rather than as "up to date". The feed is `$WIKITOOL_UPDATE_URL`, else the release stamp's, else the built-in origin; `$WIKITOOL_UPDATE_TOKEN` is only needed if that feed is not readable anonymously. Read-only and exempt from the budget gate | | `version notes [--version X.Y.Z]` | Print one version's `CHANGES.md` entry, for use as release notes (default: this tree's `VERSION`). Read-only and exempt from the budget gate | diff --git a/tools/chemenu/commands/dist_cmd.py b/tools/chemenu/commands/dist_cmd.py index 0a1f549..e179330 100644 --- a/tools/chemenu/commands/dist_cmd.py +++ b/tools/chemenu/commands/dist_cmd.py @@ -557,8 +557,8 @@ def export_command( tools/ (no venv/caches), the .github/hooks/+.vibe session-tracing config plus .claude/settings.json, kb/CONTRACT.md plus a COLLECTION.md.template per collection and - kb/CONVENTIONS.md.template (no pages, no areas), empty - raw/{articles,documents,notes,assets}/, VERSION, the USER.md/SOUL.md + kb/CONVENTIONS.md.template (no pages, no areas), the flat + raw/.gitkeep and incoming/.gitkeep anchors, VERSION, the USER.md/SOUL.md personalization templates (never the filled files), and a .wikitool-release.json stamp. The --source-*/--release-url/--update-url options only fill fields in that stamp: `export` never calls git and cannot @@ -828,7 +828,7 @@ def upgrade_command( `version check`. Never downloads anything: `source` is an already-fetched export directory or `.tar.gz` archive. Writes exactly the new release stamp's `files` block, minus what an export re-seeds every time - (`kb/log.md`, `raw/*/.gitkeep`) or seeds once and the instance owns from + (`kb/log.md`, `raw/.gitkeep`) or seeds once and the instance owns from then on (`.wikitool-kb.json`, `CHANGES.md`), classifying every candidate against the *old* stamp's recorded digest: unchanged files are overwritten silently, new files are created, and a locally modified or