page move: eine kb-Seite folgt ihrem Subtype ins Verzeichnis, das ihr Type-Spec berechnet
#56
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?
Umgesetzt und publiziert am 2026-09-04, Commit
9e41431, Stack-Kandidat4.8.0-beta.1. Aufgeworfen in der Sitzung zur Ordnerorganisation; Nachbarn: #57 (Katalogtiefe), #59 (layout:fürconcept, hing hieran), #58 (incoming/), #16 (raw rename).Was das Problem war
Nichts im Stack bewegte eine Seite zwischen Verzeichnissen.
renameschrieb nie über eine Verzeichnisgrenze (target.path.parent / f"{new}.md"), undnew_page._target_dirrechnete die Platzierung ausschließlich beim Anlegen. Änderte sichentity_typespäter, blieb die Datei still am alten Ort — und nichts meldete das: wederlint_core.pynochdoctor.pyverglichen den Ist-Ort einer Seite mit dem, was ihr Type-Spec berechnen würde. Der Zustand war unbehebbar und unsichtbar.Gegen den realen Bestand geprüft: 3 Seiten lagen tatsächlich falsch — die drei aus #57 (
kb/entities/projects/{kfchou,vanillaflava,yugasun}/*.md).Was gebaut wurde
Eine Platzierungslogik, ein Ort.
TypeResolver.compute_target_dir(plusTypeResolver.subtype_dirfür denlayout:-Teil) intools/chemenu/type_resolver.py;new_page._target_dirund_page_subdirdelegieren nur noch dorthin.lintundmoverufen dieselbe Methode.wikitool move— top-level registriert, wierename/rm:move --page "<Titel>"bewegt eine Seite an den berechneten Ort. Kein--to <dir>; das Ziel ist abgeleitet, nicht wählbar.move --reconcilewendet dieselbe Regel auf den ganzen Bestand an, überlint_core.find_misplaced— dieselbe Funktion, die der Lint-Befund nutzt.--reconcile-Lauf meldet „Nothing to move".lint-Befundmisplaced_pagesmit Ist- und Soll-Pfad, plus dem Kommando zum Beheben. Advisory, nicht inHARD_ERROR_KEYS.migrate verifyauf Titel-Schlüsselung. Siehe „Der Fund unterwegs" unten.--op moveinlog_append.VALID_OPS, mit den zugehörigen Zeilen intools/CONTRACT.md,instructions/page-lifecycle.md(neuer Abschnitt „Move") undinstructions/publish-cycle.md.Entscheidungen
move, keinpage-Unterbefehlsbaum.renameundrm— die Geschwister derselben Seitenlebenszyklus-Familie — sind top-level; ein Sub-App für genau ein Kommando daneben wäre eine zweite Konvention für dieselbe Sache. Der ursprüngliche Titel dieses Issues sagt nochpage move; gebaut istwikitool move.lintauf jeder Instanz mit handplatzierten Seiten sofort rot gewesen — auf dieser hier ab Tag eins, wegen der drei #57-Seiten. Ein handplatzierter Bestand ist keine kaputte Seite, und es gibt keine Version, ab der „nicht im berechneten Verzeichnis" falsch wird. Begründung steht im Kommentarblock überHARD_ERROR_KEYS, nebenorphan_pages/redundant_see_also.kb/ist in diesem Commit unverändert. Die drei realen Seiten bleiben liegen; #57 zieht sie hoch — jetzt mitmove --reconcilestatt Handarbeit, zusammen mit seinem eigenenkb/CONTRACT.md-Satz und dergroup_pages-Ablehnung, die #56 nicht mitliefert.git mv-mit-mv-Fallback. Der ursprüngliche Vorschlag übernahm das aus #16, wo es hingehört: eine frisch abgelegte Rohdatei kann ungetrackt sein. Für kb-Seiten trägt das Argument nicht —renameundrmbewegen bzw. löschen längst überPath.rename/unlink, undpublishstaged ohnehin übergit add -A, womit der Endzustand identisch ist.movefolgt dem Präzedenzfall. Damit entfällt auch das gemeinsame Kleinstprimitiv, das dieses Issue und #16 laut ursprünglichem Text geteilt hätten: #16 schreibt es allein, wenn es drankommt.Der Fund unterwegs
migrate verifyschlüsselte Seiten über den repo-relativen Pfad (_shapes_at_revision/_shapes_now). Ein reiner Move ergab „N removed, N added, 0 compared, 0 findings" und lief grün durch — der eine mechanische Check, für deninstructions/migrate-corpus.mdSchritt 4 existiert, hätte bei genau der Operation nichts geprüft, die dieses Issue einführt. Ohne #59s Vorbehalt wäre das erst bei 80 verschobenen Concept-Seiten aufgefallen, und dann als grüner Lauf.Behoben:
PageShapeträgt zusätzlich den Pfad, beide Shape-Dicts schlüsseln über den Titel (die einzige Identität einer Seite, AGENTS.md Invariante 2), undCorpusDiff.movedmeldet einen reinen Ortswechsel separat — informativ, nie als Finding.compare()bleibt agnostisch gegenüber dem Schlüssel; die Titel-Schlüsselung sitzt bei den Aufrufern inmigrate_cmd.py.Ein eigener Bug dabei — die „nachher"-Seite lieferte absolute statt repo-relative Pfade in
moved— wurde vom neuen Regressionstest gefangen, nicht von Augenmaß.Was verifiziert wurde
pytest: 998/998 grün lokal (vorher 975; 23 neue Tests übertest_page_ops.py,test_lint.py,test_type_resolver.py,test_corpus_diff.py,test_migrate_cmd.py).tools/wikitool docs verify: grün (51 Kommandos dokumentiert, beide Richtungen).tools/wikitool instructions verify: grün (20 Instructions, 7 Skills, 14 publizierte Kopien deckungsgleich).setup-instance-Replay gegen einen frischendist export. Der parallelerelease-Lauf 177 lief folgenlos durch und legte korrekt keine Release an —4.8.0-beta.1ist ein Kandidat, neueste Release bleibtv4.7.4.move --page "wiki-skills" --dry-runundmove --reconcile --dry-runmelden genau die drei #57-Seiten, ohne zu schreiben.lint --jsonlistet dieselben drei untermisplaced_pages.Akzeptanzkriterien
move --page "<Titel>"bewegt die Datei an den Ort, dennewfür dieselbe Frontmatter berechnet hätte; die Platzierungslogik existiert genau einmal, geteilt mitnew_page._target_dirüberTypeResolver.compute_target_dir.--dry-runzeigt Quell- und Zielpfad, ohne zu schreiben.move --reconcile: identische Menge der Seitentitel, jede Seite unter ihrem berechneten Verzeichnis, Body und Frontmatter unverändert — alle drei Eigenschaften geprüft, nicht nur die dritte.--reconcileist idempotent: ein zweiter Lauf bewegt nichts und meldet das.lintmeldet eine falsch platzierte Seite mit Ist- und Soll-Pfad. Zwei Tests: einer feuert, einer schweigt auf korrekt platzierten Seiten. Dazu ein dritter, der festhält, dass der Befundlintnicht rot macht.migrate verify --from HEADmeldet nach einem reinen Move keine Seite als removed/added, sondern vergleicht sie als dieselbe. Regressionstest mit 3 verschobenen Seiten:compared == 3, added == 0, removed == 0.Ein Test deckt die nicht versionierte Datei ab (Gestrichen — keingit mvscheitert,mvgreift).git mv/mv-Fallback gebaut, siehe Entscheidung 4. Es gibt keinen Codepfad zu testen.tools/CONTRACT.mdfür Kommando und Fehlerkontrakt;docs verifyerzwingt die Kommandozeile in beide Richtungen. (Anmerkung: die Fehlerkontrakt-Tabelle prüftdocs verifynicht mechanisch — das Kriterium überschätzte das Werkzeug. Die Zeile steht, geprüft ist sie von Hand.)instructions/page-lifecycle.mdbeschreibt den Verschiebefall (neuer Abschnitt „Move", plus--op moveim Abschluss).Was das für die Nachbarn heißt
--minor-Argument hing, steht. Dasstatus/blockeddort kann weg.kb/CONTRACT.md,group_pagesmeldet statt still zu falten — ist unberührt.git mv-Primitiv allein, falls es eines braucht; dieses Issue liefert keines.Offen für später: der Kandidat
4.8.0-beta.1wird mitversion releasegeschlossen, wenn er reif ist — nicht Teil dieses Pakets.Changelog: Umgesetzt (
move --page/--reconcile,lint-Befund advisory,migrate verifyauf Titel-Schlüsselung umgestellt,CHANGES.md4.8.0-beta.1 geschrieben). Keingit mv-Fallback gebaut (Path.rename wie rename/rm). Publish steht noch aus, pausiert auf Nutzeranweisung — Schließen folgt nachstack-close.Changelog: Abschluss-Rewrite. Body auf Endzustand: Befund in die Vergangenheit gesetzt, die vier Entscheidungen (top-level
movestattpage move; Lint-Befund advisory; Bestand unangetastet; keingit mv-Fallback) stehen als getroffen statt als Vorschlag, Verifikation benannt (998 Tests,docs verify,instructions verify, CI-Lauf 176 success, Trockenlauf gegen den echten Bestand). Kriterium 7 (git mv/mv-Test) gestrichen mit Begründung; Kriterium 8 um die Anmerkung ergänzt, dassdocs verifynur die Kommando-, nicht die Fehlerkontrakt-Tabelle mechanisch prüft. Neuer Abschnitt zu den Folgen für #59/#57/#16. Schließt das Issue.torben referenced this issue2026-09-08 17:32:39 +00:00