Upstream-Inhalt wandert in private Instanzen: Merge-Prozedur gehört in Code, und der Korpus vielleicht aus main heraus #30
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Befund
git merge upstream/mainbehandelt einen Korpus, der sich bewegt hat, gefährlich asymmetrisch: eine geänderte, löschungs-kollidierende Seite meldet sich als Konflikt, eine neu angelegte Seite wird stillschweigend gestaged, eine beidseitig gelöschte Seite ist der einzige harmlose Fall..gitattributesmitmerge=ourshilft nicht. Die Prosa-Prozedur in instructions/private-instance.md § "Taking a stack update" schloss das, aber unvollständig — siehe die vier Restbefunde unten, die jetzt alle behoben sind.Scope
Betrifft in erster Linie Downstream-Instanzen, nicht den eigenen Workflow des Betreibers (#41, Kontext; siehe auch #28).
Vorschlag B (Demo-Korpus aus
mainheraus, eigeneschemenu-demo-Repo) ist zurückgestellt — widerspricht dem Ein-Repo-Wunsch des Betreibers (#28). Nicht weiterverfolgen ohne neuen Auslöser.Vorschlag A (
wikitool upstreamals eigenes Kommando) ist umgesetzt.Restbefund (2026-09-04): was eine 1:1-Übersetzung der Prosa mitgenommen hätte
Vier Fehler, die eine wörtliche Übersetzung des Skripts in Code mitgenommen hätte — alle vier sind jetzt als eigener Test abgedeckt:
tools/chemenu/ownership.py: ein Prädikat (is_stack_owned) statt dreier Literal-Listen, gelesen vondist_cmd.pyundupstream_cmd.pygleichermaßen.upstream mergerestauriert über die Vereinigungsmenge vonMERGE_HEAD- undHEAD-Baum, ein Pfad nur inHEADwird als Löschung übernommen. Regressionstest:test_upstream_deletion_of_a_contract_file_lands.tools//types//instructions/endete in einer Sackgasse. Behoben: unaufgelöste Pfade werden vor dem Commit geprüft; bei einem Fund bleibt das Merge offen, exit 1, keine Sackgasse ohne Erklärung. Regressionstest:test_real_conflict_in_tools_leaves_the_merge_open.test_new_stack_template_under_a_content_stage_lands.Zwei weitere Fehler, gefunden im Review nach dem ersten Publish
Beide steckten in der ersten Fassung (
4.5.0-beta.1), beide hätten Daten vernichtet, keiner wurde von den damaligen Tests berührt. Behoben in4.5.0-beta.3, je mit einem Regressionstest, der gegen die alte Fassung nachweislich fehlschlägt.shutil.rmtree) — die wörtliche Übersetzung desrm -rf kb rawaus der Prosa. Fürkb//raw/harmlos, für die von diesem Issue neu aufgenommenen Stages nicht:reports/ist bis auf seinen Contract gitignored und trägt nicht-rekonstruierbare lokale Daten (Telemetrie-Traces füreval score, gespeicherte Eval- und Lint-Berichte). In dieser Instanz standen 497 Trace-Verzeichnisse unterreports/telemetry/— ein einzigerupstream mergehätte sie stillschweigend gelöscht. Die Stage wird jetzt über die getrackten Pfade beider Bäume zurückgesetzt; ignorierte lokale Daten bleiben unberührt. Regressionstest:test_merge_keeps_ignored_local_data_under_a_content_stage.MERGE_HEAD(unverwandte Historien, ignorierte Datei im Weg) ist_tree_paths("MERGE_HEAD")leer, und jeder stack-eigene Pfad inHEADfällt in den Zweig „der Upstream hat ihn gelöscht" —kb/CONTRACT.md,raw/CONTRACT.mdund alle Templates verschwinden. Es wird jetzt nach dem Merge-Aufruf geprüft, dass ein Merge offen ist, sonst Abbruch mit unberührtem Baum. Regressionstest:test_a_merge_git_refuses_to_open_deletes_nothing.Dazu eine Ehrlichkeitskorrektur: die Erfolgsmeldung zählte die wiederhergestellten statt der geänderten Pfade (ein Ein-Datei-Merge meldete vier). Sie fragt jetzt
git diffzwischen Vor- und Nach-Commit und kennzeichnet Löschungen.Spezifikation (umgesetzt wie unten beschrieben)
1. Eine Quelle für das Eigentum:
tools/chemenu/ownership.pyGebaut wie spezifiziert:
CONTENT_STAGES = ("kb", "raw", "work", "reports"),is_stack_owned(relative)wahr für<stage>/CONTRACT.md(nicht rekursiv) und jeden auf.templateendenden Pfad unter einer Content-Stage,EXPORT_STUB_NAMESfürdist exports eigene Stubs.dist_cmd.pyist umgestellt:CONTRACT_ONLY_STAGESleitet sich ausownership.CONTENT_STAGESab,find_leaksfragtownership.is_stack_owned/is_export_stubstatt einer eigenen_CONTENT_ALLOWED_NAMES-Liste. Konsistenztest:test_dist_cmd_contract_only_stages_agree_with_ownership.2.
tools/wikitool upstream mergeImplementiert mit allen elf Schritten aus der Spezifikation: Vorbedingungen (sauberer Baum, kein laufendes Merge, Remote löst auf), Publish-Remote-Gate als WARN bei fehlender
.wikitool-remotes.json, Fetch, "already up to date"-Kurzschluss, offenes--no-commit --no-ff-Merge (mit Abbruch, falls git gar kein Merge eröffnet hat), Content-Stages über ihre getrackten Pfade zurück auf lokal, Stack-Pfade aus der Vereinigungsmenge beider Bäume restauriert (inklusive Löschung), Prüfung auf unaufgelöste Pfade vor dem Commit, Commit, Nachkontrolle mit derselben Logik wieverify(Fund → lauter Fehler, kein automatisches Rollback), Erfolgsbericht über den tatsächlichen Diff.3.
tools/wikitool upstream verifyImplementiert:
--since <rev> [--until HEAD], dieselbe_content_leaks-Funktion wie der Merge-eigene Postcheck, damit Prüfung und Wiederherstellung nicht auseinanderlaufen können.4. Verhältnis zu den Gates
Wie in der Tabelle entschieden: Publish-Remote-Gate unberührt (WARN statt Blockade), Mass-Update-Gate greift bei Merge-Commits strukturell nicht — jetzt als eigener Absatz in instructions/gates.md mit
upstream merges eigener Nachkontrolle als der tatsächlich tragenden Sicherung.upstream mergeist nicht budget-exempt und steht in AGENTS.md § Tool error contract auf der Nicht-idempotent-Liste nebennew,log append,publish.upstream verifyist wiemigrate verifyvon der Iteration-Budget-Gate ausgenommen (run_budget.SKIP_COMMAND_PATHS) — beides nachgemessen, nicht nur behauptet.Tests
23 Tests in
tools/chemenu/tests/test_upstream_cmd.py(35 Fälle inklusive der parametrisiertenis_stack_owned-Tabelle):kb/CONTRACT.md→ landet ✅kb/CONVENTIONS.md.template→ landet, lokalekb/CONVENTIONS.mdbleibt unberührt ✅kb/entities/COLLECTION.md→ landet nicht (instanzeigen seit #39) ✅raw/CONTRACT.md→ die Löschung landet ✅kb/GLOSSARY.md.template) → landet ✅work/-Runs → landen nicht ✅ (auch wenn die Instanz unterwork/gar nichts trackt)tools/→ Merge bleibt offen, exit 1, kein Commit ✅.wikitool-remotes.jsonfehlt → WARN, Merge läuft (und bleibt still, wenn die Datei da ist) ✅upstream verify --sinceauf einem von Hand verpfuschten Merge → exit 1 mit der Seite in der Liste ✅ownership/dist_cmd-Konsistenz ✅Dokumentation
tools/CONTRACT.md: Kommandotabelle und Error-Contract-Tabelle umupstream merge/upstream verifyergänzt (vondocs verifyerzwungen)tools/README.md:ownership.pyim Layout-Baum verzeichnet, keine zweite Kommandotabelleinstructions/private-instance.md: § "Taking a stack update" verweist auf den Befehl statt das Skript auszuschreiben; die Pfadtabelle bleibt als Erklärung; Zusage, dass ignorierte lokale Daten überleben; Decision Points nachgezogenAGENTS.md§ Tool error contract:upstream mergeauf der Nicht-idempotent-Listeinstructions/gates.md: neuer Absatz zum Mass-Update-Blindfleck bei Merge-Commitsdocs/ownership-and-templates.md: neuer Abschnitt, warum die Eigentumsgrenze ein Prädikat und keine Liste istCHANGES.md: Body geschrieben, ein Eintrag über vier Bumps desselben KandidatenVersion
4.4.1-beta.1→4.5.0-beta.1(--minor, Implementierung) →4.5.0-beta.2(--patch, Kombinationsprobe) →4.5.0-beta.3(--patch, die beiden Review-Funde). Drop-in in beide Richtungen, keine Migration.Verifiziert
pytest(939 Tests),wikitool docs verify,wikitool instructions verify,wikitool doctor— grün vor jedem der drei Publishes. CI (Gitea Actions) grün für686c08bundd2b1719(Runs 141–144). Zusätzlich ein End-to-End-Lauf des echten CLI gegen eine nachgebaute private Instanz: Upstream-Commit mit Edit + Add + Delete + Contract + Template + neues Template + offenerwork/-Run + Contract-Löschung; danach Datei für Datei geprüft, dass Content nicht landet, Instanz-Dateien (kb/CONVENTIONS.md,kb/entities/COLLECTION.md) unberührt bleiben, Stack-Dateien landen, die Contract-Löschung übernommen wird, ignorierte lokale Daten überleben, der Baum sauber ist und der zweite Lauf ein No-op meldet. Beide Regressionstests der Review-Funde wurden gegen die alte Fassung laufen gelassen und schlagen dort fehl.Akzeptanzkriterien
ownership.py, Stack-Dateien (<stage>/CONTRACT.md,*.templateunter einer Content-Stage) gegen Instanz-Dateien (kb/CONVENTIONS.md,kb/*/COLLECTION.md) gegen Korpusinhaltownership.pygebaut,dist_cmd.pydarauf umgestellt, Konsistenztest grünupstream mergeimplementiert, alle vier Restbefunde durch je einen Test abgedecktupstream verifyimplementiert,SKIP_COMMAND_PATHSergänztdocs verify+instructions verify+pytestgrünversion bump --minor, Changelog-Body geschriebenVerwandt
#28 (geteilte Ursache, geschlossen), #39 und #40 (gelandet, liefern die Eigentumsgrenze), #7 (
dist upgrade— kannupstream verifykünftig als Nachkontrolle mitnutzen)Vorgeschichte
2.2.0/2.2.1: erste Skript-Prozedur. 2026-09-02: Scope-Klärung, Abhängigkeit zu #39, Vorschlag B verworfen. 2026-09-03: #39/#40 gelandet, Blocker entfernt. 2026-09-04: Restbefund gegen die damalige Prosa-Prozedur erhoben (vier Fehler), Vorschlag A vollständig spezifiziert, drei Zuschnittfragen entschieden (
work/im Stagesatz; Remote-Gate als WARN;verifyals zweites Subkommando). 2026-09-04: umgesetzt (4.5.0-beta.1), Kombinationsprobe nachgetragen (4.5.0-beta.2), Review-Durchgang fand zwei datenvernichtende Fehler in der eigenen Umsetzung und behob sie (4.5.0-beta.3).torben referenced this issue2026-09-01 21:19:07 +00:00
Stand nach der Sitzung vom 2026-09-02
Drei Ergebnisse, eine Neubewertung, ein neues vorgelagertes Issue.
1. Die Prozedur aus 2.2.1 hat ein zweites Leck — in die Gegenrichtung
git checkout HEAD -- kb rawholt alles unter beiden Stages zurück, auch die sechs Maschinerie-Dateien, die dort wohnen:Ändert der Upstream einen davon, wirft die Prozedur das Update still weg — und die Kontrollzeile
git diff --name-only $BEFORE HEAD -- kb rawmeldet dann leer, also „nachweislich funktioniert". Die Kontrolle, die dieses Issue als wichtigsten Teil bezeichnet, bestätigt hier den Fehler.dist_cmd.pykennt die Unterscheidung schon (CONTRACT_ONLY_STAGESplus jedeskb/*/COLLECTION.md). Die Prosa-Prozedur hat sie nicht — die Drift, gegen die Vorschlag A argumentiert, ist also bereits eingetreten.Konsequenz: die Pfadmenge
kb rawist falsch, und zwar auch für ein künftigeswikitool upstream-Kommando. Wer sie hartkodiert, kodiert den Fehler ein zweites Mal.2. Empfehlung: B2, plus ein stark verkleinertes A
B1 fällt raus — aus dem Argument dieses Issues selbst: die Trennung hinge an Disziplin (
main→demobei jeder Stack-Änderung), nicht an Konstruktion. Einmain, in das jemand versehentlich Korpus committet, hat keinen Gate hinter sich. Dieselbe Klasse Lösung wie die Prosa-Prozedur, eine Ebene höher.B2 (eigenes Repo
chemenu-demo), weil:mainträgt keine Seiten, also kann keine ankommen — weder als Konflikt noch still.setup-instance.mdund den Update-Pfad dauerhaft, statt einmal in CI. Als begehbares Beispiel ist ein Repo, das als Wiki durchblätterbar ist, besser als ein Korpus im Maschinen-Repo.A schrumpft dadurch von einem Merge-Treiber auf die Kontrolle:
wikitool upstream verify --since <rev>(oder als Check indoctor), das prüft, ob ein Update Seiten bewegt hat — mit der Pfadmenge aus derselben Quelle wiedist export, nicht aus einem zweiten Satz Literale. Deutlich billiger als das volle Kommando, und es schließt Leck 1 mit.3.
nightly.yml— die offene Frage des Issueslint --fail-on-errorundsources coveragesind Korpus-Checks und haben auf einem seitenfreienmainnichts mehr zu tun; sie ziehen ins Demo-Repo um, das dann die volle Nightly braucht. Inmainbleibendoctor,docs verify,instructions verify,migrate status. Der Content-Pfad-Ausschluss inci.ymlwird fürmaingegenstandslos, sollte aber stehenbleiben —kb/CONTRACT.mdist dort bewusst ausgenommen.4. Der Preis ist mit #28 kein Preis mehr
Das Issue nennt als Kosten, dass
mainzur leeren Hülle wird und das begehbare Beispiel verliert. Mit #28 ist das der Zielzustand: das Fixture ersetzt den Korpus als Testfläche, das Demo-Repo als Beispiel. Umgekehrt bleibt #28 ohne B2 unvollständig, weil daskb/inmainweiter als Testbett missbraucht wird.Re-Labelling:
prio/2 size/M→prio/3 size/LNach
instructions/dev/issue-tracking.mdSchritt 3, mit benanntem Auslöser statt als höfliches Nein:prio/3— der Auslöser ist #39 abgeschlossen, dann #28 abgeschlossen. Vorher lässt sich weder die Pfadmenge sauber ziehen (Leck 1) noch B2 vollziehen, ohne dem Repo die einzige Testfläche zu nehmen. Aktuell wird auch keine Instanz geschädigt: die private Arbeitsinstanz existiert noch nicht (ENVIRONMENT.md).size/L— der Zuschnitt ist gewachsen: zweites Repo, CI-Umzug,upstream verifysamt Tests, plus die Instruction-Nacharbeit.Nach Abschluss geht es weiter bei
Nirgends — #30 ist das Ende der Kette (#39 → #28 → #30). Wenn es geschlossen ist, ist die Trennung Upstream/Instanz vollständig: Eigentum deklariert (#39), Testfläche vom Demo-Korpus gelöst (#28), Auslieferung inhaltsfrei von Bauart (#30). Beim Schließen nach
issue-tracking.mdSchritt 4 festhalten, welche Vorschläge umgesetzt wurden — insbesondere, obupstream verifyein eigenes Kommando oder eindoctor-Check geworden ist.Changelog: Scope-Klarstellung ergänzt (betrifft Downstream, nicht den eigenen Workflow). Vorschlag B zurückgestellt statt offen gegen Vorschlag A abgewogen, weil der Betreiber die Ein-Repo-Struktur für sich selbst will (#28). Abhängigkeit zu #39 (zweites Leck am selben Mechanismus) neu aufgenommen,
status/blockedgesetzt.Changelog: #39/#40 sind gelandet (3.0.0, 4.0.0/4.1.0). Blocker aufgelöst: das zweite Leck aus #39 ist mitgelöst, die Eigentumsgrenze zwischen Stack- und Instanz-Dateien steht jetzt fest und deklariert.
status/blockedentfernt. Vorschlag A kann jetzt spezifiziert werden - nächster Schritt in der vereinbarten Reihenfolge, nach #28/#38/#42.Changelog: Body auf den Umsetzungsstand umgeschrieben. Die Anforderungen sind implementierbar, aber die alten Akzeptanzkriterien hätten zu einer 1:1-Übersetzung der Prosa-Prozedur geführt — die trägt nach #39 noch vier Fehler (Pfadsatz dreifach hartkodiert; vom Upstream gelöschte Maschinerie-Datei wird still ignoriert; echter Konflikt in
tools/endet undiagnostiziert im offenen Merge; ein neuer Stack-Pfad unter einer Content-Stage erreicht die Instanz nie). Alle vier sind jetzt als Restbefund benannt und bekommen je einen Regressionstest.Spezifikation ergänzt:
tools/chemenu/ownership.pyals einzige Quelle des Eigentums (Prädikat statt Literal-Liste,dist_cmd.pywird darauf umgestellt),upstream mergein elf Schritten mit erklärten Fehlerpfaden,upstream verify --sinceals zweites Subkommando aus derselben Funktion. Gate-Verhältnis geklärt: Publish-Remote unberührt (WARN bei fehlender.wikitool-remotes.json), Mass-Update greift bei Merge-Commits strukturell nicht — gehört so ingates.md,upstream mergenicht budget-exempt und auf die Nicht-idempotent-Liste,upstream verifyexempt wiemigrate verify.Drei Zuschnittfragen entschieden:
work/gehört in den geschützten Stagesatz (offener Upstream-Run ist dieselbe Leck-Klasse wie eine neue Seite); Remote-Gate als WARN statt als viertes Gate;verifywird mitgebaut statt als Folge-Issue vertagt.Re-Labelling:
kind/decision→kind/build,prio/waiting→prio/planned. Auslöser ist der Abschluss von #28/#38/#42 plus die jetzt getroffenen Zuschnittentscheidungen — es wartet nichts mehr, nur noch Umsetzungszeit.size/Lbleibt: die Designfragen sind zu, aberownership.pysamtdist_cmd-Refactor, zwei Kommandos, fünfzehn Testfälle und fünf Dokumente sind plausibel mehr als eine Sitzung.Version bleibt
--minor(4.5.0-beta.2gegen den laufenden Kandidaten4.4.1-beta.1): neue Fähigkeit, in beide Richtungen drop-in, keine Migration.Umgesetzt:
tools/chemenu/ownership.py(Eigentumsgrenze als Prädikat),wikitool upstream merge/upstream verify,dist_cmd.pydarauf umgestellt, 19 neue Tests (31 Fälle), Doku intools/CONTRACT.md,tools/README.md,AGENTS.md,instructions/gates.md,instructions/private-instance.mdnachgezogen.pytest/docs verify/instructions verify/doctorgrün. Veröffentlicht als4.5.0-beta.1(Implementierung,686c08b) und4.5.0-beta.2(nachgetragene Kombinationsprobe für das letzte Akzeptanzkriterium,d2b1719).Nachtrag nach Review-Durchgang (
4.5.0-beta.3,1b5ffea). Die Umsetzung aus4.5.0-beta.1trug zwei Fehler, die die damaligen Tests nicht berührt haben und die beide Daten vernichtet hätten:shutil.rmtreeauf die ganze Content-Stage — fürkb//raw/harmlos, für das mit diesem Issue neu aufgenommenereports/nicht: dort liegen 497 Telemetrie-Trace-Verzeichnisse, gitignored und nicht rekonstruierbar. Einupstream mergehätte sie stillschweigend gelöscht.MERGE_HEAD-Guard: hätte git das Merge nicht eröffnet (unverwandte Historien), wärenkb/CONTRACT.md,raw/CONTRACT.mdund alle Templates als „vom Upstream gelöscht" entfernt worden.Beide behoben, je mit einem Regressionstest, der gegen die alte Fassung nachweislich fehlschlägt (nachgemessen, nicht angenommen). Dazu: die Erfolgsmeldung nennt jetzt den tatsächlichen Diff statt der Wiederherstellungsliste,
docs/ownership-and-templates.mderklärt, warum die Grenze ein Prädikat ist, undtools/CONTRACT.md/private-instance.md/gates.mdsind auf das korrigierte Verhalten nachgezogen. Zusätzlich End-to-End gegen das echte CLI in einer nachgebauten privaten Instanz verifiziert — Body oben, Abschnitt „Verifiziert".Body auf den Endstand umgeschrieben. Tests jetzt 23 (35 Fälle), Suite gesamt 939 grün.
torben referenced this issue2026-09-04 18:57:02 +00:00
torben referenced this issue2026-09-04 19:25:03 +00:00