publish/sync scheitern an Überschneidungen nur in generierten Dateien und an nicht überlappender ungespeicherter Arbeit #180

Closed
opened 2026-10-05 16:45:54 +00:00 by torben · 5 comments
Owner

Abgetrennt aus #178 (dort am 2026-10-05 gegen den Baum 8ce202a gefunden und auf MVP reduziert; der Befund galt unabhängig vom Intake). Am 2026-10-06 gegen den Baum 40839d9 nachgeprüft, am selben Tag gebaut (8.0.0-beta.46) und geschlossen.

Problem (bis 8.0.0-beta.45)

reconcile() in tools/chemenu/commands/git_publish.py kannte generierte Dateien nicht, obwohl dieselbe Datei sie mit is_generated() schon für den Mass-Update-Gate ausnahm. Jedes Ingest berührt mindestens kb/index.md und kb/log.md. Deshalb scheiterte reconcile (hinter sync und beiden Reconciles von publish) an drei Formen derselben Lage:

  1. Ungespeichertes Ingest, <remote>/main hatte sich bewegt (ff-possible): git merge --ff-only verweigerte wegen der lokal geänderten kb/index.md/kb/log.md, publish endete mit Exit 1.
  2. Beide Seiten mit Commits (diverged, z. B. ein gestrandeter Commit nach fehlgeschlagenem Push, oder der Retry-Pfad nach abgelehntem Push): die generierten Dateien zählten als Überlappung → Rebase-Review-Gate (Exit 42); nach Freigabe scheiterte git rebase an den zwei Anhängen am Ende von kb/log.md → Exit 1.
  3. diverged mit ungespeicherten Änderungen: git rebase verweigerte bei jeder geänderten getrackten Datei, auch einer nicht überlappenden. Typisch: gestrandeter Commit + neues ungespeichertes Ingest → publish Exit 1.

Außerdem fing is_generated() jede Datei, die auf /INDEX.md endet - auch eine unter raw/, die der neue Pfad sonst verworfen hätte.

Entscheidungen

  1. Fall 3 wird mit abgedeckt (Betreiber, 2026-10-06). Ohne ihn hätte ein ungespeichertes Ingest über einem gestrandeten Commit - der im Betrieb wahrscheinlichste Fall - weiter scheitern müssen.
  2. Versionsteil --patch, Drop-in: kein Befehl, Flag, Dateiformat oder Zustandsfile ändert sich; was vorher mit Exit 1 oder 42 endete, geht durch, und kein Lauf, der vorher ohne Gate und Fehler durchging, ändert sein Ergebnis. Ein vor dem Update ausgestellter --confirm-rebase-Token kann danach veraltet sein, weil overlap_files keine generierten Dateien mehr enthält - der Gate fragt dann neu. Die Vorversion ignoriert einen liegengebliebenen Sicherungs-Ref.

Umsetzung

Grundsatz: Der mechanische Pfad greift nur, wo git sonst gescheitert wäre. ff-possible versucht zuerst git merge --ff-only wie zuvor; diverged nimmt den bisherigen git rebase unverändert, wenn nichts Ungespeichertes im Weg liegt (getrackt geändert, oder eine ungetrackte generierte Datei) und keine generierte Datei auf beiden Seiten committet ist. Dort läuft auch kein Rebuild - index rebuild stempelt das heutige Datum in kb/index.md, und jeder sync endete sonst mit einer geänderten Datei.

  • Generiert heißt kb/: is_generated() gilt nur noch für kb/index.md, kb/log.md, kb/provenance.md und kb/**/INDEX.md (wie AGENTS.md Invariante 1). Eine INDEX.md unter raw/ zählt im Mass-Update-Gate und geht in den Rebase-Review-Gate.
  • Überlappung: generierte Pfade zählen nicht; nur überlappende nicht generierte Dateien führen in den Rebase-Review-Gate, dessen overlap_files, Token und Diff keine generierten Dateien mehr enthalten.
  • Beiseitelegen: Im mechanischen Pfad werden alle ungespeicherten generierten Dateien beiseitegelegt (danach ohnehin alle neu erzeugt): von kb/log.md die Bytes über die HEAD-Fassung hinaus, der Rest auf HEAD zurückgesetzt bzw. gelöscht. Im ff-possible-Fall nur, wenn mindestens eine davon mit einer eingehenden Datei kollidiert.
  • Fall 3: git rebase --autostash, nach dem Beiseitelegen, damit der Autostash nur nicht generierte Änderungen enthält; rebase --abort spielt ihn ebenfalls zurück.
  • Vorbedingungen, alle vor dem ersten Schreibschritt geprüft; ist eine verletzt, endet reconcile mit conflict und ändert nichts: die Arbeitsfassung von kb/log.md beginnt byte-genau mit der HEAD-Fassung; keine ungespeicherte nicht generierte Datei liegt in touched_files(base, remote_tip); keine ungetrackte Datei liegt auf einem eingehend angelegten Pfad.
  • Konflikte beim Rebase, Schritt für Schritt (git diff --name-only --diff-filter=U, GIT_EDITOR=true): nur generierte Dateien im Konflikt → Katalog/Provenance nehmen Stage 2 (die onto-Seite), kb/log.md Stage 2 plus den Rest von Stage 3 über Stage 1 hinaus (Vorbedingung: Stage 3 beginnt mit Stage 1); eine nicht generierte Datei im Konflikt → rebase --abort, Zurückspielen, conflict. Ein dadurch leer gewordener lokaler Commit wird von git rebase --continue selbst verworfen (mit git 2.56 geprüft).
  • Danach: Neu erzeugt wird, wenn etwas beiseitegelegt oder aufgelöst wurde oder beide Seiten eine generierte Datei committet haben (ein textuell sauberer Merge zweier Kataloge kann trotzdem falsch sein). Erst kommen die Log-Bytes ans Ende von kb/log.md, dann index_build.write_index und provenance_cmd.write_provenance_index (aus index rebuild und sources rebuild-index herausgezogen); Einstieg git_publish.regenerate_generated. Die neu erzeugten Dateien bleiben als ungespeicherte Änderung liegen: sync überlässt sie dem nächsten publish, der proaktive Reconcile von publish läuft vor dem Staging, und der Retry-Pfad nach abgelehntem Push committet sie über git_publish.commit_regenerated vor dem zweiten Push.
  • Sicherung: vor dem ersten Schreibschritt ein Commit des ganzen Arbeitsbaums (getrackt und ungetrackt, über eine Scratch-Kopie des Index, eigene Identität wikitool) unter refs/wikitool/reconcile-backup; bei Erfolg gelöscht, bei Fehlerausgang behalten und gemeldet. Ein Ausnahmefehler mitten im Rebase bricht ihn ab und spielt die generierten Dateien zurück.

Bewusst nicht behandelt: Ein publish --path <X>, dessen Umfang die generierten Dateien nicht einschließt, committet den neu erzeugten Katalog nicht; der gepushte Stand trägt dann bis zum nächsten publish ohne --path den Katalog der eingehenden Seite, die neu erzeugten Dateien liegen lokal als ungespeicherte Änderung. --path ist eine bewusste Teilmenge, und den Umfang still zu erweitern hätte genau das unterlaufen.

Akzeptanzkriterien

Die Tests stehen in tools/chemenu/tests/test_git_publish.py, Abschnitt "Reconciling around generated files"; die Fixture wiki_repo baut den Katalog mit den ausgelieferten Funktionen.

  • Fall 1: Ein ungespeichertes Ingest, während <remote>/main ein anderes Ingest bekommen hat, wird von publish ohne Gate und ohne Fehler publiziert. (test_case_1_an_uncommitted_ingest_publishes_over_an_ingest_that_landed_meanwhile, test_case_1_on_sync_leaves_the_regenerated_catalog_uncommitted)
  • Fall 2: Zwei Ingests auf divergierten Ständen mit Commits, die außer generierten Dateien nichts gemeinsam haben, führen bei publish/sync nicht ins Rebase-Review-Gate und enden mit Exit 0; überlappende nicht generierte Dateien führen weiterhin hinein. (test_case_2_*)
  • Fall 2 im Retry-Pfad: Wird der Push abgelehnt, weil <remote>/main zwischen proaktivem Reconcile und Push ein Ingest bekommen hat, endet publish mit Exit 0, und der gepushte Tip erfüllt das Katalog-Kriterium unten. (test_case_2_in_the_retry_path_commits_the_regenerated_catalog_before_the_push)
  • Fall 3: Gestrandeter lokaler Commit + ungespeichertes Ingest, dessen nicht generierte Dateien keine eingehende Datei berühren → publish endet mit Exit 0; die ungespeicherten Seiten sind im gepushten Stand. Dasselbe vor sync: Exit 0, die ungespeicherten Seiten liegen danach unverändert im Arbeitsbaum. (test_case_3_*, auch ohne generierte Dateien: kein Rebuild)
  • Invariante: Jede nicht generierte Datei im Arbeitsbaum ist nach reconcile byte-identisch zu vorher - ungespeicherte Arbeit geht nie verloren, auch nicht bei einem Fehlerausgang (getestet mit einem erzwungenen Abbruch mitten im Rebase). (test_uncommitted_work_survives_an_abort_in_the_middle_of_the_rebase, als Ausnahme und als gemeldeter Fehlschlag; dazu: Branch unbewegt, kein Rebase offen, Stash-Liste leer, Sicherungs-Ref hält die ungespeicherte Seite)
  • Jeder Log-Eintrag beider Seiten steht danach genau einmal in kb/log.md, eingehende zuerst; kb/index.md, jedes INDEX.md und kb/provenance.md gleichen Byte für Byte dem, was index rebuild/sources rebuild-index am selben Tag auf dem Ergebnis erzeugen. (in jedem Fall-Test geprüft, beim publish an einem frischen Klon des gepushten Tips)
  • Ist eine Vorbedingung verletzt (Log nicht nur angehängt, eine nicht generierte Datei kollidiert - getrackt geändert oder ungetrackt auf einem eingehend angelegten Pfad), verhält sich reconcile wie zuvor und lässt Arbeitsbaum und Branch unverändert. (vier Tests: Log von Hand geändert, Log in einem lokalen Commit umgeschrieben, ungespeicherte Änderung an eingehend geänderter Seite, ungetrackte Datei auf eingehendem Pfad)
  • Tritt keiner der Fälle 1-3 ein, ist das Ergebnis von reconcile identisch zu zuvor; insbesondere läuft kein Rebuild (bestehende reconcile-/sync-Tests unverändert grün). (alle bestehenden Tests unverändert grün; test_a_plain_fast_forward_regenerates_nothing)
  • Eine Datei raw/<…>/INDEX.md gilt nicht als generiert: weder im Mass-Update-Zähler noch im Reconcile. (test_an_index_md_outside_kb_is_not_generated, test_an_index_md_under_raw_still_goes_to_review_when_both_sides_change_it)
  • pytest, docs verify, instructions verify grün; CI grün. (siehe Verifikation)

Geänderte Stellen

  • tools/chemenu/commands/git_publish.py: is_generated, reconcile und die neuen Helfer (Abschnitt "Reconciling around generated files"), _run mit env, Retry-Pfad in publish_command, _reconcile_summary, Records von sync/publish
  • tools/chemenu/commands/index_build.py (write_index), tools/chemenu/commands/provenance_cmd.py (write_provenance_index)
  • tools/CONTRACT.md (per docs contract --apply), instructions/session-setup.md (sync-Absatz), instructions/gates.md (Rebase-Review: was ihn nicht auslöst), CHANGES.md
  • tools/chemenu/tests/test_git_publish.py: 16 neue Tests, Fixture wiki_repo

Geprüft und unverändert gelassen, weil sie nichts über den Reconcile behaupten: kb/CONTRACT.md § Generated files, README.md, tools/README.md, docs/why-gates-are-code.md (der Rebase-Review ist dort kein benannter Gate).

Verifikation

  • 8.0.0-beta.46, Commit d4638ba: lokal pytest 2322 bestanden / 3 übersprungen, auf leerer Maschine identisch; docs verify, instructions verify grün; CI-Runs 559 und 560 grün.
  • 8.0.0-beta.47, Commit fa106ee (Abschlussphase: eine Note im sync-Record beschrieb die Änderung - "no longer" - statt des Verhaltens): docs verify, instructions verify, die betroffenen Tests grün; CI-Runs 561 und 562 grün.

Priorität

War prio/planned (Betreiber, 2026-10-06), vorher prio/waiting mit dem Auslöser "eine Instanz wird von mehr als einem Checkout oder einer parallelen Sitzung aus beschrieben".

Abgetrennt aus #178 (dort am 2026-10-05 gegen den Baum `8ce202a` gefunden und auf MVP reduziert; der Befund galt unabhängig vom Intake). Am 2026-10-06 gegen den Baum `40839d9` nachgeprüft, am selben Tag gebaut (`8.0.0-beta.46`) und geschlossen. ## Problem (bis `8.0.0-beta.45`) `reconcile()` in `tools/chemenu/commands/git_publish.py` kannte generierte Dateien nicht, obwohl dieselbe Datei sie mit `is_generated()` schon für den Mass-Update-Gate ausnahm. Jedes Ingest berührt mindestens `kb/index.md` und `kb/log.md`. Deshalb scheiterte `reconcile` (hinter `sync` und beiden Reconciles von `publish`) an drei Formen derselben Lage: 1. **Ungespeichertes Ingest, `<remote>/main` hatte sich bewegt** (`ff-possible`): `git merge --ff-only` verweigerte wegen der lokal geänderten `kb/index.md`/`kb/log.md`, `publish` endete mit **Exit 1**. 2. **Beide Seiten mit Commits** (`diverged`, z. B. ein gestrandeter Commit nach fehlgeschlagenem Push, oder der Retry-Pfad nach abgelehntem Push): die generierten Dateien zählten als Überlappung → **Rebase-Review-Gate (Exit 42)**; nach Freigabe scheiterte `git rebase` an den zwei Anhängen am Ende von `kb/log.md` → Exit 1. 3. **`diverged` mit ungespeicherten Änderungen:** `git rebase` verweigerte bei *jeder* geänderten getrackten Datei, auch einer nicht überlappenden. Typisch: gestrandeter Commit + neues ungespeichertes Ingest → `publish` Exit 1. Außerdem fing `is_generated()` jede Datei, die auf `/INDEX.md` endet - auch eine unter `raw/`, die der neue Pfad sonst verworfen hätte. ## Entscheidungen 1. **Fall 3 wird mit abgedeckt** (Betreiber, 2026-10-06). Ohne ihn hätte ein ungespeichertes Ingest über einem gestrandeten Commit - der im Betrieb wahrscheinlichste Fall - weiter scheitern müssen. 2. **Versionsteil `--patch`, Drop-in:** kein Befehl, Flag, Dateiformat oder Zustandsfile ändert sich; was vorher mit Exit 1 oder 42 endete, geht durch, und kein Lauf, der vorher ohne Gate und Fehler durchging, ändert sein Ergebnis. Ein vor dem Update ausgestellter `--confirm-rebase`-Token kann danach veraltet sein, weil `overlap_files` keine generierten Dateien mehr enthält - der Gate fragt dann neu. Die Vorversion ignoriert einen liegengebliebenen Sicherungs-Ref. ## Umsetzung **Grundsatz:** Der mechanische Pfad greift nur, wo git sonst gescheitert wäre. `ff-possible` versucht zuerst `git merge --ff-only` wie zuvor; `diverged` nimmt den bisherigen `git rebase` unverändert, wenn nichts Ungespeichertes im Weg liegt (getrackt geändert, oder eine ungetrackte generierte Datei) und keine generierte Datei auf beiden Seiten committet ist. Dort läuft auch kein Rebuild - `index rebuild` stempelt das heutige Datum in `kb/index.md`, und jeder `sync` endete sonst mit einer geänderten Datei. - **Generiert heißt `kb/`:** `is_generated()` gilt nur noch für `kb/index.md`, `kb/log.md`, `kb/provenance.md` und `kb/**/INDEX.md` (wie AGENTS.md Invariante 1). Eine `INDEX.md` unter `raw/` zählt im Mass-Update-Gate und geht in den Rebase-Review-Gate. - **Überlappung:** generierte Pfade zählen nicht; nur überlappende *nicht* generierte Dateien führen in den Rebase-Review-Gate, dessen `overlap_files`, Token und Diff keine generierten Dateien mehr enthalten. - **Beiseitelegen:** Im mechanischen Pfad werden alle ungespeicherten generierten Dateien beiseitegelegt (danach ohnehin alle neu erzeugt): von `kb/log.md` die Bytes über die `HEAD`-Fassung hinaus, der Rest auf `HEAD` zurückgesetzt bzw. gelöscht. Im `ff-possible`-Fall nur, wenn mindestens eine davon mit einer eingehenden Datei kollidiert. - **Fall 3:** `git rebase --autostash`, nach dem Beiseitelegen, damit der Autostash nur nicht generierte Änderungen enthält; `rebase --abort` spielt ihn ebenfalls zurück. - **Vorbedingungen**, alle vor dem ersten Schreibschritt geprüft; ist eine verletzt, endet `reconcile` mit `conflict` und ändert nichts: die Arbeitsfassung von `kb/log.md` beginnt byte-genau mit der `HEAD`-Fassung; keine ungespeicherte nicht generierte Datei liegt in `touched_files(base, remote_tip)`; keine ungetrackte Datei liegt auf einem eingehend angelegten Pfad. - **Konflikte beim Rebase**, Schritt für Schritt (`git diff --name-only --diff-filter=U`, `GIT_EDITOR=true`): nur generierte Dateien im Konflikt → Katalog/Provenance nehmen Stage 2 (die `onto`-Seite), `kb/log.md` Stage 2 plus den Rest von Stage 3 über Stage 1 hinaus (Vorbedingung: Stage 3 beginnt mit Stage 1); eine nicht generierte Datei im Konflikt → `rebase --abort`, Zurückspielen, `conflict`. Ein dadurch leer gewordener lokaler Commit wird von `git rebase --continue` selbst verworfen (mit git 2.56 geprüft). - **Danach:** Neu erzeugt wird, wenn etwas beiseitegelegt oder aufgelöst wurde oder beide Seiten eine generierte Datei committet haben (ein textuell sauberer Merge zweier Kataloge kann trotzdem falsch sein). Erst kommen die Log-Bytes ans Ende von `kb/log.md`, dann `index_build.write_index` und `provenance_cmd.write_provenance_index` (aus `index rebuild` und `sources rebuild-index` herausgezogen); Einstieg `git_publish.regenerate_generated`. Die neu erzeugten Dateien bleiben als ungespeicherte Änderung liegen: `sync` überlässt sie dem nächsten `publish`, der proaktive Reconcile von `publish` läuft vor dem Staging, und der Retry-Pfad nach abgelehntem Push committet sie über `git_publish.commit_regenerated` vor dem zweiten Push. - **Sicherung:** vor dem ersten Schreibschritt ein Commit des ganzen Arbeitsbaums (getrackt und ungetrackt, über eine Scratch-Kopie des Index, eigene Identität `wikitool`) unter `refs/wikitool/reconcile-backup`; bei Erfolg gelöscht, bei Fehlerausgang behalten und gemeldet. Ein Ausnahmefehler mitten im Rebase bricht ihn ab und spielt die generierten Dateien zurück. **Bewusst nicht behandelt:** Ein `publish --path <X>`, dessen Umfang die generierten Dateien nicht einschließt, committet den neu erzeugten Katalog nicht; der gepushte Stand trägt dann bis zum nächsten `publish` ohne `--path` den Katalog der eingehenden Seite, die neu erzeugten Dateien liegen lokal als ungespeicherte Änderung. `--path` ist eine bewusste Teilmenge, und den Umfang still zu erweitern hätte genau das unterlaufen. ## Akzeptanzkriterien Die Tests stehen in `tools/chemenu/tests/test_git_publish.py`, Abschnitt "Reconciling around generated files"; die Fixture `wiki_repo` baut den Katalog mit den ausgelieferten Funktionen. - [x] Fall 1: Ein ungespeichertes Ingest, während `<remote>/main` ein anderes Ingest bekommen hat, wird von `publish` ohne Gate und ohne Fehler publiziert. (`test_case_1_an_uncommitted_ingest_publishes_over_an_ingest_that_landed_meanwhile`, `test_case_1_on_sync_leaves_the_regenerated_catalog_uncommitted`) - [x] Fall 2: Zwei Ingests auf divergierten Ständen mit Commits, die außer generierten Dateien nichts gemeinsam haben, führen bei `publish`/`sync` nicht ins Rebase-Review-Gate und enden mit Exit 0; überlappende *nicht* generierte Dateien führen weiterhin hinein. (`test_case_2_*`) - [x] Fall 2 im Retry-Pfad: Wird der Push abgelehnt, weil `<remote>/main` zwischen proaktivem Reconcile und Push ein Ingest bekommen hat, endet `publish` mit Exit 0, und der gepushte Tip erfüllt das Katalog-Kriterium unten. (`test_case_2_in_the_retry_path_commits_the_regenerated_catalog_before_the_push`) - [x] Fall 3: Gestrandeter lokaler Commit + ungespeichertes Ingest, dessen nicht generierte Dateien keine eingehende Datei berühren → `publish` endet mit Exit 0; die ungespeicherten Seiten sind im gepushten Stand. Dasselbe vor `sync`: Exit 0, die ungespeicherten Seiten liegen danach unverändert im Arbeitsbaum. (`test_case_3_*`, auch ohne generierte Dateien: kein Rebuild) - [x] **Invariante:** Jede nicht generierte Datei im Arbeitsbaum ist nach `reconcile` byte-identisch zu vorher - ungespeicherte Arbeit geht nie verloren, auch nicht bei einem Fehlerausgang (getestet mit einem erzwungenen Abbruch mitten im Rebase). (`test_uncommitted_work_survives_an_abort_in_the_middle_of_the_rebase`, als Ausnahme und als gemeldeter Fehlschlag; dazu: Branch unbewegt, kein Rebase offen, Stash-Liste leer, Sicherungs-Ref hält die ungespeicherte Seite) - [x] Jeder Log-Eintrag beider Seiten steht danach genau einmal in `kb/log.md`, eingehende zuerst; `kb/index.md`, jedes `INDEX.md` und `kb/provenance.md` gleichen Byte für Byte dem, was `index rebuild`/`sources rebuild-index` am selben Tag auf dem Ergebnis erzeugen. (in jedem Fall-Test geprüft, beim `publish` an einem frischen Klon des gepushten Tips) - [x] Ist eine Vorbedingung verletzt (Log nicht nur angehängt, eine nicht generierte Datei kollidiert - getrackt geändert oder ungetrackt auf einem eingehend angelegten Pfad), verhält sich `reconcile` wie zuvor und lässt Arbeitsbaum und Branch unverändert. (vier Tests: Log von Hand geändert, Log in einem lokalen Commit umgeschrieben, ungespeicherte Änderung an eingehend geänderter Seite, ungetrackte Datei auf eingehendem Pfad) - [x] Tritt keiner der Fälle 1-3 ein, ist das Ergebnis von `reconcile` identisch zu zuvor; insbesondere läuft kein Rebuild (bestehende `reconcile`-/`sync`-Tests unverändert grün). (alle bestehenden Tests unverändert grün; `test_a_plain_fast_forward_regenerates_nothing`) - [x] Eine Datei `raw/<…>/INDEX.md` gilt nicht als generiert: weder im Mass-Update-Zähler noch im Reconcile. (`test_an_index_md_outside_kb_is_not_generated`, `test_an_index_md_under_raw_still_goes_to_review_when_both_sides_change_it`) - [x] `pytest`, `docs verify`, `instructions verify` grün; CI grün. (siehe Verifikation) ## Geänderte Stellen - `tools/chemenu/commands/git_publish.py`: `is_generated`, `reconcile` und die neuen Helfer (Abschnitt "Reconciling around generated files"), `_run` mit `env`, Retry-Pfad in `publish_command`, `_reconcile_summary`, Records von `sync`/`publish` - `tools/chemenu/commands/index_build.py` (`write_index`), `tools/chemenu/commands/provenance_cmd.py` (`write_provenance_index`) - `tools/CONTRACT.md` (per `docs contract --apply`), `instructions/session-setup.md` (`sync`-Absatz), `instructions/gates.md` (Rebase-Review: was ihn nicht auslöst), `CHANGES.md` - `tools/chemenu/tests/test_git_publish.py`: 16 neue Tests, Fixture `wiki_repo` Geprüft und unverändert gelassen, weil sie nichts über den Reconcile behaupten: `kb/CONTRACT.md` § Generated files, `README.md`, `tools/README.md`, `docs/why-gates-are-code.md` (der Rebase-Review ist dort kein benannter Gate). ## Verifikation - `8.0.0-beta.46`, Commit `d4638ba`: lokal `pytest` 2322 bestanden / 3 übersprungen, auf leerer Maschine identisch; `docs verify`, `instructions verify` grün; CI-Runs [559](https://gitea.nehmer.net/torben/chemenu/actions/runs/559) und [560](https://gitea.nehmer.net/torben/chemenu/actions/runs/560) grün. - `8.0.0-beta.47`, Commit `fa106ee` (Abschlussphase: eine Note im `sync`-Record beschrieb die Änderung - "no longer" - statt des Verhaltens): `docs verify`, `instructions verify`, die betroffenen Tests grün; CI-Runs [561](https://gitea.nehmer.net/torben/chemenu/actions/runs/561) und [562](https://gitea.nehmer.net/torben/chemenu/actions/runs/562) grün. ## Priorität War `prio/planned` (Betreiber, 2026-10-06), vorher `prio/waiting` mit dem Auslöser "eine Instanz wird von mehr als einem Checkout oder einer parallelen Sitzung aus beschrieben".
torben added the prio/waitingsize/Marea/workflowkind/defect labels 2026-10-05 16:45:54 +00:00
torben added kind/decision and removed kind/defect labels 2026-10-06 06:00:43 +00:00
Author
Owner

Changelog: Am Baum 40839d9 nachgeprüft. Neu: Fall 3 (diverged + ungespeicherte, nicht überlappende Änderung → git rebase verweigert; im Scratch-Repo nachgestellt) als offene Frage; is_generated() wird auf kb/ eingeengt (sonst würde eine raw/**/INDEX.md verworfen); kein Rebuild ohne Kollision (Last Updated in kb/index.md würde jeden sync verschmutzen); der Retry-Pfad in publish_command muss neu erzeugte Dateien vor dem zweiten Push committen; Sicherung vor dem ersten Schreibschritt; Konfliktauflösung über Stages 1/2/3 präzisiert. Akzeptanzkriterien: Retry-Pfad, unveränderter Lauf ohne Kollision und raw/-INDEX.md neu. Korrigiert: sources rebuild-index liegt in provenance_cmd.py. Neu gelabelt kind/defect → kind/decision wegen der offenen Frage.

**Changelog:** Am Baum `40839d9` nachgeprüft. Neu: Fall 3 (`diverged` + ungespeicherte, nicht überlappende Änderung → `git rebase` verweigert; im Scratch-Repo nachgestellt) als offene Frage; `is_generated()` wird auf `kb/` eingeengt (sonst würde eine `raw/**/INDEX.md` verworfen); kein Rebuild ohne Kollision (`Last Updated` in `kb/index.md` würde jeden `sync` verschmutzen); der Retry-Pfad in `publish_command` muss neu erzeugte Dateien vor dem zweiten Push committen; Sicherung vor dem ersten Schreibschritt; Konfliktauflösung über Stages 1/2/3 präzisiert. Akzeptanzkriterien: Retry-Pfad, unveränderter Lauf ohne Kollision und `raw/`-`INDEX.md` neu. Korrigiert: `sources rebuild-index` liegt in `provenance_cmd.py`. Neu gelabelt `kind/defect` → `kind/decision` wegen der offenen Frage.
torben added prio/plannedkind/build and removed prio/waitingkind/decision labels 2026-10-06 06:23:10 +00:00
torben changed title from publish/sync scheitern, wenn sich lokale und eingehende Änderungen nur in generierten Dateien überschneiden to publish/sync scheitern an Überschneidungen nur in generierten Dateien und an nicht überlappender ungespeicherter Arbeit 2026-10-06 06:23:16 +00:00
Author
Owner

Changelog: Offene Frage 1 entschieden (Betreiber): Fall 3 wird mit abgedeckt - jetzt Entscheidung 1, eigener Entwurfspunkt mit Vorbedingung (keine Überlappung mit touched_files(base, remote_tip), keine ungetrackte Datei auf einem eingehend angelegten Pfad), Akzeptanzkriterium ohne Vorbehalt und um sync ergänzt. Titel erweitert. Neu gelabelt: kind/decision → kind/build (keine offene Frage mehr), prio/waiting → prio/planned (Betreiber: wird jetzt gebaut).

**Changelog:** Offene Frage 1 entschieden (Betreiber): Fall 3 wird mit abgedeckt - jetzt Entscheidung 1, eigener Entwurfspunkt mit Vorbedingung (keine Überlappung mit `touched_files(base, remote_tip)`, keine ungetrackte Datei auf einem eingehend angelegten Pfad), Akzeptanzkriterium ohne Vorbehalt und um `sync` ergänzt. Titel erweitert. Neu gelabelt: `kind/decision` → `kind/build` (keine offene Frage mehr), `prio/waiting` → `prio/planned` (Betreiber: wird jetzt gebaut).
Author
Owner

Changelog: Gebaut und publiziert als 8.0.0-beta.46 (d4638ba), CI-Runs 559/560 grün; alle Akzeptanzkriterien abgehakt, jedes mit den Tests, die es belegen. Entwurf um die Umsetzung präzisiert: im mechanischen Pfad werden alle ungespeicherten generierten Dateien beiseitegelegt (gleiches Ergebnis, weil alle neu erzeugt werden); Rebuild auch, wenn beide Seiten eine generierte Datei committet haben und git sie textuell sauber gemergt hat; Fall 3 über git rebase --autostash; Sicherung als Commit des ganzen Arbeitsbaums unter refs/wikitool/reconcile-backup; eine verletzte Vorbedingung im diverged-Fall meldet conflict mit der Datei statt git's Verweigerung; ein durch die Auflösung leer gewordener Commit wird von git selbst verworfen (geprüft). Neuer Abschnitt "Stand".

**Changelog:** Gebaut und publiziert als `8.0.0-beta.46` (`d4638ba`), CI-Runs 559/560 grün; alle Akzeptanzkriterien abgehakt, jedes mit den Tests, die es belegen. Entwurf um die Umsetzung präzisiert: im mechanischen Pfad werden *alle* ungespeicherten generierten Dateien beiseitegelegt (gleiches Ergebnis, weil alle neu erzeugt werden); Rebuild auch, wenn beide Seiten eine generierte Datei committet haben und git sie textuell sauber gemergt hat; Fall 3 über `git rebase --autostash`; Sicherung als Commit des ganzen Arbeitsbaums unter `refs/wikitool/reconcile-backup`; eine verletzte Vorbedingung im `diverged`-Fall meldet `conflict` mit der Datei statt git's Verweigerung; ein durch die Auflösung leer gewordener Commit wird von git selbst verworfen (geprüft). Neuer Abschnitt "Stand".
Author
Owner

Changelog: Endstand. Problem in die Vergangenheit gesetzt ("bis 8.0.0-beta.45"), "Entwurf" ist jetzt "Umsetzung", der Versionsteil steht als Entscheidung 2. Neu: "Bewusst nicht behandelt" (publish --path ohne die generierten Dateien im Umfang), "Geänderte Stellen" mit den geprüften und unverändert gelassenen Dokumenten, "Verifikation" mit beiden Ständen. In der Abschlussphase nachgezogen: 8.0.0-beta.47 (fa106ee), eine Note im sync-Record beschreibt jetzt das Verhalten statt der Änderung; CI 561/562 grün. Geschlossen.

**Changelog:** Endstand. Problem in die Vergangenheit gesetzt ("bis `8.0.0-beta.45`"), "Entwurf" ist jetzt "Umsetzung", der Versionsteil steht als Entscheidung 2. Neu: "Bewusst nicht behandelt" (`publish --path` ohne die generierten Dateien im Umfang), "Geänderte Stellen" mit den geprüften und unverändert gelassenen Dokumenten, "Verifikation" mit beiden Ständen. In der Abschlussphase nachgezogen: `8.0.0-beta.47` (`fa106ee`), eine Note im `sync`-Record beschreibt jetzt das Verhalten statt der Änderung; CI 561/562 grün. Geschlossen.
Author
Owner

Der unter "Bewusst nicht behandelt" festgehaltene publish --path-Fall ist nachgestellt und als #182 abgelegt.

Der unter "Bewusst nicht behandelt" festgehaltene `publish --path`-Fall ist nachgestellt und als #182 abgelegt.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#180