feat: publish gate lists the staged state; a missing or unreachable remote stops before the commit (#159)
CI / verify (push) Successful in 2m11s
Release / release (push) Successful in 38s

Files changed:
- CHANGES.md
- INSTALL.md
- VERSION
- instructions/publish-cycle.md
- instructions/setup-instance.md
- tools/CONTRACT.md
- tools/chemenu/commands/git_publish.py
- tools/chemenu/tests/test_git_publish.py
This commit is contained in:
torben committed 2026-09-30 20:51:10 +02:00
1 parent 08dde007dd
commit eadc052f6c
8 files changed
+487 -206

No files matched your search

+45 -2
View File
@@ -59,11 +59,13 @@ concern - readable here, never shipped as something to parse.
---
## 8.0.0-beta.9 - 2026-09-30 - bug-report instruction: step 1 no longer calls every bundle unpseudonymised
## 8.0.0-beta.10 - 2026-09-30 - publish: the gate lists the staged state; a missing or unreachable remote stops before the commit
**Author:** Torben Nehmer
**Breaking Change:** Page titles must form valid, unique file names on Windows and macOS: new and rename refuse forbidden characters, reserved names (including INDEX and COLLECTION), a trailing dot or space, and titles that collide with another page by case or Unicode normalization; lint reports existing violations as hard errors - rename each affected page with tools/wikitool rename
**Breaking Change:**
- Page titles must form valid, unique file names on Windows and macOS: new and rename refuse forbidden characters, reserved names (including INDEX and COLLECTION), a trailing dot or space, and titles that collide with another page by case or Unicode normalization; lint reports existing violations as hard errors - rename each affected page with tools/wikitool rename
- publish without --no-push now exits 1 before committing when the remote is unreachable or not configured, where it used to commit locally and fail at the push - an offline session or a local-only instance must pass --no-push
**Migration:** none required - No page format changes; the rule only refuses titles, and each affected page is renamed individually with tools/wikitool rename
@@ -82,6 +84,7 @@ concern - readable here, never shipped as something to parse.
- Live tracker suite: WIKITOOL_TASKS_CONFIG override, real-tracker tests for Super Productivity and CalDAV, nightly workflow and test image
- Bug-report collector: tools/bugreport.py and instructions/bug-report.md
- Bug-report collector can pseudonymise identities, in two stages
- publish: the gate lists the staged state; a missing or unreachable remote stops before the commit
**Low impact**
- version bump no longer points at version release in its output
@@ -116,6 +119,46 @@ concern - readable here, never shipped as something to parse.
- bug-report instruction: step 1 no longer calls every bundle unpseudonymised
<!-- /wikitool:bumps -->
### publish: the gate lists the staged state; a missing or unreachable remote stops before the commit (Gitea #159)
**The Mass-Update Gate counted a path twice.** `collect_changes` read `git status --porcelain`, which
reports the index and the working tree separately. A path staged as deleted that sits in the working
tree again (`git rm -r raw`, then `git restore --source=HEAD -- raw/CONTRACT.md`) appears as `D ` and
`??`; the gate counted both, while `git add -A` cancels them out and the commit held neither. The list
a human approved therefore named a deletion and a new file that were never committed. `collect_changes`
now stages into a scratch copy of the index (`GIT_INDEX_FILE`) and reads `git diff --cached --no-renames`
from it, so the list is the state the commit will hold. The real index and the working tree stay
byte-identical, also when the computation fails; `git add` writes the new blobs into the object store,
where `gc` collects the unreferenced ones.
- The digest in the `--confirm` token is now the blob id of the staged content instead of a sha256 over
the working-tree file, so the token binds to exactly what is committed. A deletion still has none.
- A rename is listed as its old path deleted plus its new path added, which is what the commit holds and
what the "deletions by name" note has to see. The `renamed` status is gone from the scale line.
- `_numstat`, `_untracked_stat`, `_changed_files`, `parse_porcelain_entries` and `parse_porcelain_z` are
removed; nothing else called them. The "Files changed:" list in the commit message comes from the same
list and is correct for the same reason.
- With `--path`, the list is restricted to that subtree even when more is staged, as the commit is.
**One message for two states became three.** A failed fetch was reported as "No remote configured, or
origin could not be reached". It is now `no-remote`, `remote-lacks-branch` (the remote answers and has no
such branch yet - the first publish of an instance) or `unreachable`, told apart by `git remote get-url`
and the exit code of `git ls-remote --exit-code`, each with its own message. `sync` exits 0 in all three.
**`publish` stops before the commit when it cannot publish.** Without `--no-push`, `unreachable` and
`no-remote` end the call with exit 1 at the reconcile - before the gate, `git add` and the commit, and
also on a clean tree, where it used to say "Nothing to commit". It used to commit and fail at the push,
which left a commit that only a hand-made `git push` could send. The messages name `--no-push` as the
way to a local commit; the next `publish` that reaches the remote sends that commit along. `remote-lacks-branch`
is unaffected, so the first publish of an instance still commits and pushes. The Publish-Remote Gate,
which runs first when `.wikitool-remotes.json` exists, is unchanged, and so is the retry after a rejected
push: a remote that has become unreachable by then reports the original push error.
This is a **breaking** change in the sense of the version model: an offline session, or an instance that
stays local, has to pass `--no-push` on every `publish`. No content changes, so `**Migration:**` stays
"none required". `instructions/publish-cycle.md` has the new decision point, `setup-instance.md` step 4
and `INSTALL.md` say what a local-only instance now sees without the flag.
### bug-report instruction: step 1 no longer calls every bundle unpseudonymised
Step 1 told the agent to announce that the bundle "is not pseudonymised" and then, one paragraph