feat: Publish-Remote Gate und die Anleitung fuer eine private Instanz (2.2.0)
Files changed: - .gitignore - AGENTS.md - CHANGES.md - VERSION - instructions/gates.md - instructions/private-instance.md - tools/chemenu/commands/doctor.py - tools/chemenu/commands/git_publish.py - tools/chemenu/config.py - tools/chemenu/tests/test_git_publish.py
This commit is contained in:
+57
-1
@@ -20,6 +20,62 @@ their date-only headings.
|
||||
|
||||
---
|
||||
|
||||
## 2.2.0 - 2026-09-01 - Publish-Remote Gate: publish schreibt nur an erklaerte Ziele
|
||||
|
||||
**Author:** Torben Nehmer
|
||||
|
||||
Der Stack bekommt sein drittes Gate. Die beiden bestehenden fragen, ob eine Änderung zu groß
|
||||
ist und ob ein Rebase gefährlich ist. Dieses fragt, was darunter liegt: **ob das überhaupt das
|
||||
richtige Repository ist.**
|
||||
|
||||
**Das Problem entsteht erst durch die private Instanz.** Ein Checkout mit eigenem Inhalt hat
|
||||
typischerweise zwei Remotes — sein eigenes und das öffentliche Upstream, von dem er
|
||||
Stack-Updates zieht. Git unterscheidet die beim Push nicht, also legt ein falsches `--remote`
|
||||
einen privaten Korpus auf ein öffentliches Repository. Das ist nicht billig rückholbar, und
|
||||
zwar nachweislich: Beim Veröffentlichen dieses Repos blieb die gesamte alte History nach dem
|
||||
Force-Push per SHA abrufbar, bis auf dem Server die Reflogs verfielen und `git gc --prune=now`
|
||||
lief. Ein Force-Push bewegt den Branch, nicht die Objekte.
|
||||
|
||||
**`.wikitool-remotes.json` nennt die erlaubten Push-URLs.** Nicht die Remote-*Namen*: Eine
|
||||
Namensliste ließe ein `publish` durch, dessen `origin` umgebogen wurde, und genau das ist der
|
||||
Fall, den das Gate fangen soll. Gelesen wird die `pushurl`, wenn der Remote eine setzt, denn
|
||||
dorthin schreibt `git push` tatsächlich.
|
||||
|
||||
**Pro Checkout und gitignored**, aus demselben Grund wie `ENVIRONMENT.md`: Zwei Klone pushen an
|
||||
zwei verschiedene Orte, eine committete Kopie würde einem privaten Klon also mitteilen, das
|
||||
öffentliche Upstream sei ein legitimes Ziel für seinen eigenen Inhalt. **Fehlt die Datei, gilt
|
||||
keine Beschränkung** — ein Checkout mit einem Remote und ohne Privates hat nichts zu schützen,
|
||||
und eine Pflichtdatei würde aus einer Sicherung Papierkram machen. Eine *kaputte* Datei ist
|
||||
dagegen ein Fehler und kein „keine Beschränkung": Eine beschädigte Sicherung darf sich nicht
|
||||
wie eine abgeschaltete verhalten.
|
||||
|
||||
**Kein Token, keine Flagge.** Die anderen beiden Gates lösen sich mit einem `--confirm <token>`,
|
||||
weil ihre Frage („ist diese Änderung richtig?") für genau ein Changeset beantwortbar ist. Dieses
|
||||
fragt „gehört dieser Inhalt in jenes Repository?", und das ist eine stehende Eigenschaft des
|
||||
Checkouts, kein Einzelfallurteil. Der Weg daran vorbei ist ein bewusster Edit des Nutzers.
|
||||
Ein Agent, der die Datei anfasst, um an einer Verweigerung vorbeizukommen, öffnet ein Gate aus
|
||||
eigenem Antrieb — Invariante 6.
|
||||
|
||||
**`doctor` meldet den Zustand** statt ihn zu erzwingen: OK mit Anzahl der Ziele, OK bei
|
||||
Abwesenheit mit einem Remote, und WARN bei mehr als einem Remote ohne Allowlist — also genau in
|
||||
der Form, die eine private Instanz annimmt, sobald sie das Upstream hinzufügt.
|
||||
|
||||
**Und die Prozedur, für die das Gate gebaut wurde.** `instructions/private-instance.md` (neu)
|
||||
beschreibt die dritte Instanz-Form neben „frisch aufsetzen" und „Repo klonen": eine private
|
||||
Arbeitsinstanz, die Stack-Updates von einem öffentlichen Upstream per `git merge` zieht und
|
||||
deren eigener Inhalt nie zurückwandert. Der Grund, warum das dem Tarball-Weg vorzuziehen ist,
|
||||
steht dort ausformuliert — `cp -r` hat keinen Drei-Wege-Merge und keine Konflikterkennung.
|
||||
Schritt 4 der Anleitung ist das Gate, und zwar ausdrücklich **vor** dem ersten `publish`:
|
||||
später hinzugefügt schützt es das Fenster nicht, das es schließen soll.
|
||||
|
||||
**Dateien:** `config.PUBLISH_REMOTES_FILENAME`, `git_publish.read_allowed_push_urls()`,
|
||||
`push_url_for()`, `publish_remote_refusal()` und die Prüfung vor dem Reconcile-Schritt,
|
||||
`doctor.check_publish_remotes()`, `.gitignore`, `instructions/gates.md`,
|
||||
`instructions/private-instance.md` (neu), `AGENTS.md` (Gate-Liste und Bootstrap-Routing),
|
||||
12 neue Tests in `test_git_publish.py`.
|
||||
|
||||
---
|
||||
|
||||
## 2.1.1 - 2026-09-01 - raw_dir-Fixture kappt config.ROOT; letzte private Fixture-Namen ersetzt
|
||||
|
||||
**Author:** Torben Nehmer
|
||||
@@ -47,7 +103,7 @@ Nachgewiesen, indem `raw/documents/` lokal entfernt und die Suite erneut gefahre
|
||||
Provenance-Tests grün ohne das Verzeichnis, vorher rot.
|
||||
|
||||
**Fixture-Namen.** Die Suite benutzte weiterhin reale Systemnamen der Ursprungsinstanz als
|
||||
Fixture-Bezeichner (`atlantis`, `abydos`, `Nathan`, `hermes`, `ecodms`, `Opa Hasso`). In einem
|
||||
Fixture-Bezeichner. In einem
|
||||
öffentlichen Repo beschreiben sie nichts, verraten aber die Namensgebung einer privaten
|
||||
Umgebung. Ersetzt durch `aurora`, `almanac`, `Borealis`, `gateway`, `docstore`. `gdeploy`
|
||||
bleibt: die Seite existiert im öffentlichen Korpus.
|
||||
|
||||
Reference in New Issue
Block a user