diff --git a/CHANGES.md b/CHANGES.md index 4851ebd..4c86efd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -35,13 +35,14 @@ dev-checkout concern - readable here, never shipped as something to parse. --- -## 4.5.0-beta.1 - 2026-09-04 - wikitool upstream merge/verify: code procedure for taking a stack update, ownership.py as the shared stack/instance boundary +## 4.5.0-beta.2 - 2026-09-04 - upstream merge: combined-commit regression test (edit+add+delete+contract+template+contract-delete in one commit) **Author:** Torben Nehmer - Faktenkorrekturen in der 4.4.0-Prosa; DEVELOPMENT.md ohne zweite Kommandobeschreibung - wikitool upstream merge/verify: code procedure for taking a stack update, ownership.py as the shared stack/instance boundary +- upstream merge: combined-commit regression test (edit+add+delete+contract+template+contract-delete in one commit) Die Prosa zu 4.4.0 - Changelog-Eintrag, `docs/version-model.md`, `instructions/dev/version-parts.md`, @@ -108,7 +109,7 @@ Nachkontrolle als der Sicherung, die hier tatsächlich trägt. auszuschreiben; die Pfadtabelle bleibt als Erklärung stehen, ist aber nicht mehr die operative Liste. Vorschlag B (eigenes Demo-Repo) bleibt zurückgestellt, siehe #30. -18 neue Tests unter `test_upstream_cmd.py` (30 Fälle mit der parametrisierten +19 neue Tests unter `test_upstream_cmd.py` (31 Fälle mit der parametrisierten `is_stack_owned`-Tabelle) decken die Fälle aus der Spezifikation ab: gelöschte vs. geänderte vs. neu angelegte Seiten, `kb/CONTRACT.md`- und Template-Änderungen, `kb/entities/COLLECTION.md` bleibt lokal, eine gelöschte `raw/CONTRACT.md` landet, ein neuer @@ -117,6 +118,12 @@ den Merge offen, ein schmutziger Baum wird unberührt abgewiesen, "bereits aktue die Publish-Remote-Gate-Warnung, `verify` gegen einen von Hand verpfuschten Merge, und die `dist_cmd`/`ownership`-Konsistenz. +**Dritter Bump auf demselben Kandidaten:** die im Akzeptanzkriterium geforderte Kombinationsprobe +fehlte noch - ein einzelner Upstream-Commit, der Editieren, Anlegen, Löschen einer Seite, eine +Contract-Änderung, eine Template-Änderung und eine Contract-Löschung gleichzeitig bewegt. Jetzt +als `test_one_upstream_commit_mixing_every_case_at_once` nachgetragen; alle sechs Erwartungen in +einem `upstream merge`-Aufruf verifiziert. + --- ## 4.4.0 - 2026-09-03 - Versionskandidat statt Bump-pro-Release: VERSION traegt -beta.N, version release fixiert diff --git a/VERSION b/VERSION index 31e7ebb..5d28c08 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.5.0-beta.1 +4.5.0-beta.2 diff --git a/tools/chemenu/tests/test_upstream_cmd.py b/tools/chemenu/tests/test_upstream_cmd.py index 86b8557..62e75ae 100644 --- a/tools/chemenu/tests/test_upstream_cmd.py +++ b/tools/chemenu/tests/test_upstream_cmd.py @@ -62,6 +62,7 @@ def two_repos(tmp_path, monkeypatch): _write(seed, "kb/entities/COLLECTION.md", "instance collection contract v1\n") _write(seed, "kb/Both.md", "page both sides delete\n") _write(seed, "kb/ToDelete.md", "page the instance will delete\n") + _write(seed, "kb/RegularPage.md", "an ordinary page neither side has touched yet\n") _write(seed, "raw/CONTRACT.md", "raw contract v1\n") _write(seed, "work/CONTRACT.md", "work contract v1\n") _write(seed, "reports/CONTRACT.md", "reports contract v1\n") @@ -207,6 +208,35 @@ def test_open_workshop_run_files_do_not_land(two_repos): assert not (repo / "work/some-run").exists() +def test_one_upstream_commit_mixing_every_case_at_once(two_repos): + """The acceptance test from the issue: a single upstream commit that edits + a page the instance deleted, adds a new page, deletes an untouched page, + changes a stack contract, changes a template, and deletes a different + stack contract - all at once, all restored or discarded correctly by one + `upstream merge` call.""" + upstream, repo = two_repos + _git(repo, "rm", "-q", "kb/ToDelete.md") + _commit(repo, "instance deletes ToDelete") + + _write(upstream, "kb/ToDelete.md", "upstream edited it after the instance deleted it\n") + _write(upstream, "kb/BrandNewPage.md", "a demo page the upstream added\n") + _git(upstream, "rm", "-q", "kb/RegularPage.md") + _write(upstream, "kb/CONTRACT.md", "stack kb contract v2\n") + _write(upstream, "kb/CONVENTIONS.md.template", "template v2\n") + _git(upstream, "rm", "-q", "raw/CONTRACT.md") + _commit(upstream, "one upstream commit: edit + add + delete + contract + template + contract-delete") + + _merge() + + assert not (repo / "kb/ToDelete.md").exists() + assert not (repo / "kb/BrandNewPage.md").exists() + assert (repo / "kb/RegularPage.md").exists() + assert (repo / "kb/CONTRACT.md").read_text(encoding="utf-8") == "stack kb contract v2\n" + assert (repo / "kb/CONVENTIONS.md.template").read_text(encoding="utf-8") == "template v2\n" + assert (repo / "kb/CONVENTIONS.md").read_text(encoding="utf-8") == "instance conventions v1\n" + assert not (repo / "raw/CONTRACT.md").exists() + + def test_real_conflict_in_tools_leaves_the_merge_open(two_repos): upstream, repo = two_repos