Kein Kommando schreibt raw_files: einer bestehenden Seite
#14
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?
Der Anlass
Beim Zurückbenennen der Rohdatei aus #12 (
5426a6e) mussteraw_files:der Source-Seite von Hand korrigiert werden. Es gibt keinwikitool-Kommando dafür.touchschreibt die Felder, die die Seite selbst beschreiben (modified:,summary:,provenance:,confidence_base:) —raw_files:gehört nicht dazu.xref add/remove/link-sourcefassen die Page-Ref-Arrays an (related:,sources:,entities:,concepts:).raw_files:ist keins davon: es zeigt auf einen Pfad, nicht auf einen Seitentitel.new source --set raw_files=…schreibt das Feld einmal, beim Anlegen. Danach nie wieder.Invariante 1 verbietet das Hand-Editieren hier nicht — ihre Liste nennt Katalog,
log.md,provenance.md, die Skill-Verzeichnisse, die beiden JSON-Dateien und die Page-Ref-Arrays, undraw_files:steht in keiner davon. Trotzdem widerspricht es dem Kernprinzip: „anything mechanical is done bytools/wikitool, never by hand". Eine Pfadkorrektur in einem Frontmatter-Array ist genau das.Wann das auftritt
Nicht nur beim Reparieren eines Bugs. Jedes Mal, wenn eine Rohdatei ihren Pfad ändert:
raw/CONTRACT.md(notes/→documents/, wenn sich herausstellt, dass es ein Dokument war)raw/-Struktur nachträglich umbaut (sieheinstructions/ingest-large-tree.md)lintundsources coveragemelden den gebrochenen Zustand zuverlässig (Broken raw_files references), aber nichts kann ihn beheben. Das ist die Asymmetrie, die dieses Issue schließen soll: eine Prüfung ohne zugehörige Reparatur schickt den Agenten in genau die Hand-Edits, gegen die der Rest des Stacks gebaut ist.Vorschlag für den Schnitt
wikitool sources relink --page "<Titel>" --from <alter-pfad> --to <neuer-pfad>— und/oder ein additives--add/--remove.Offene Fragen für die Umsetzung:
page-lifecycle.mdgenau diese Frage überwikitool rename, das beides tut. Analog wäre einraw rename <alt> <neu>, dasgit mvund jede referenzierende Source-Seite anfasst, die geschlossenere Form — und die einzige, bei der der Zwischenzustand „Datei weg, Referenz zeigt ins Leere" nie entsteht.raw/liegt (_check_raw_files_existkann das schon).lintführt das als eigenen Befund (duplicate_raw_file_owners), das Kommando sollte es nicht stillschweigend erzeugen.sources rebuild-indexdanach automatisch, oder dem Aufrufer überlassen? Die anderen Kommandos überlassen es ihm.Nicht Teil davon
Rohdateien mit einem
raw-Unterbefehl generell zu verwalten.raw/ist unveränderlich; das hier ist der eng begrenzte Fall, dass ein Pfad sich ändert, während der Inhalt derselbe bleibt.Akzeptanzkriterien
raw_files:einer bestehenden Seite, ohne dass jemand Frontmatter anfasst.5426a6e— Rohdatei umbenannt, eine Source-Seite referenziert sie — ist der Test.tools/CONTRACT.mdfür Kommando und Fehlerkontrakt;docs verifyerzwingt beide Richtungen.instructions/page-lifecycle.mderwähnt den Rohdatei-Fall, oder sagt ausdrücklich, dass er woanders steht. Heute schweigt es dazu, und sein Scope-Abschnitt grenzt nur gegen Contracts/Instructions/Type-Specs ab.Hinweis
Der Anlassfall selbst ist erledigt und braucht keine Nacharbeit:
sources coveragemeldet 0 unabgedeckt und 0 gebrochene Referenzen,lintist sauber über 255 Seiten. Dieses Issue ist die Lücke im Werkzeug, nicht der Schaden.Zweiter Fall derselben Lücke, anderes Feld:
tags:.Beim Ingest des Transkripts zu diesem Fix (Commit
8764799) musstetags:auf zwei neu angelegten Seiten von Hand gesetzt werden.newnimmt das Feld nur bei der Erstellung entgegen; wird es dort vergessen, gibt es keinen Weg zurück —touchschreibt nur die Felder, die die Seite selbst beschreiben (modified:,summary:,provenance:,confidence_base:), undtags:gehört nicht dazu.Wie
raw_files:fällttags:nicht unter Invariante 1 — die Liste dort nennt Katalog,log.md,provenance.md, die Skill-Verzeichnisse, die beiden JSON-Dateien und die Page-Ref-Arrays. Und wie beiraw_files:ist die Handeditierung trotzdem der einzige Weg.Das verschiebt den Zuschnitt dieses Issues. Es geht nicht um ein Kommando für
raw_files:, sondern um eine Klasse: Frontmatter-Felder, die beinewschreibbar sind und danach nie wieder. Einsources relinkwürderaw_files:lösen undtags:offen lassen, und beim nächsten Feld stünde derselbe Kommentar hier.Zwei Zuschnitte, die beide mehr treffen als ein Einzelkommando:
touch --set field=valuemit derselben Coercion und Schema-Validierung, dienew --setschon hat (_coerce_set_value+_validate_or_fail). Deckttags:,raw_files:und jedes künftige skalare oder Array-Feld ab, das kein Page-Ref-Array ist. Die Page-Ref-Arrays blieben ausdrücklich beixref, weil dort die Gegenrichtung mitgepflegt wird.raw rename <alt> <neu>zusätzlich, für den Fall, dass die Datei sich bewegt —git mvplus jede referenzierende Source-Seite in einem Schritt, damit der Zwischenzustand „Datei weg, Referenz zeigt ins Leere" nie entsteht. Das ist der Teil, den (1) nicht abdeckt.Vorschlag: Titel und Scope auf (1) erweitern, (2) als zweiten Akzeptanzpunkt behalten.
Verwandt: der Ingest hat das Muster als Concept-Seite
Detect-Repair Asymmetryabgelegt — ein Check meldet einen Defekt zuverlässig (lint,sources coverage), kein Befehl behebt ihn, also bleibt die Handeditierung. Das ist die Verallgemeinerung dieses Issues.Dritter Fall in drei Ingests, wieder
tags:.Beim Ingest des dritten Transkripts (Commit
8d47e7e) hatte ein--set tags=-Aufruf ein Komma am Ende; alles nach dem Trennzeichen fiel weg.kb/concepts/Diff-Reviewable Agent Edits.mdträgt deshalb nur[agent-workflow]statt der vorgesehenen Liste.Interessant ist nicht der Tippfehler, sondern dass es keinen Weg zurück gab. Der Agent hat die drei Auswege korrekt durchgespielt und alle drei verworfen:
touchkanntags:nicht setzen.rm+newhätte die bereits geschriebeneconcepts:-Referenz der Source-Seite gebrochen.Also blieb: so lassen. Der Tag ist gültig, die Seite über Titel, Summary und drei Backlinks auffindbar — aber die Kategorisierung ist dauerhaft dünner als beabsichtigt, wegen eines Kommas.
Drei Fälle in drei aufeinanderfolgenden Ingests, an zwei verschiedenen Feldern (
raw_files:,tags:zweimal), von drei verschiedenen Agenten. Das ist kein Ausrutscher, sondern die Fehlerrate einer Schnittstelle, die einen Wert genau einmal entgegennimmt.Verschärfend: das Fenster ist genau ein Kommando breit.
newist lauttools/CONTRACT.mdnicht idempotent, ein Retry also nicht ohne Weiteres möglich — wer imnew-Aufruf danebengreift, hat den Zustand festgeschrieben, bevor er ihn prüfen konnte. Eintouch --setbehebt nicht nur die drei beobachteten Fälle, es machtnewvon einer einmaligen Chance zu einem korrigierbaren Schritt.Das stützt den Vorschlag aus dem vorigen Kommentar:
touch --set field=value, mit derselben Coercion und Schema-Validierung wienew --set(_coerce_set_value+_validate_or_fail), Page-Ref-Arrays weiterhin ausschließlich überxref.raw renamebleibt als zweiter, unabhängiger Punkt für den Fall, dass die Datei sich bewegt.Hinweis für die Umsetzung: mindestens ein Testfall sollte ein Arrayfeld mit Escape und mit wiederholtem
--setabdecken, sonst erbttouch --setdas Komma-Problem aus #12 gleich mit.Umgesetzt in 1.4.0 (
dbe2f73).Die drei Entscheidungen
Torben vorgelegt und entschieden:
--setschreiben?--setfür eine Liste mit Werten?--add/--removefür einzelne Elementeraw renamein diesem Durchgang?Was
touchjetzt kann--set field=valueersetzt den Wert auf der Platte. Wiederholtes--setfür dasselbe Arrayfeld hängt innerhalb eines Aufrufs an,\,ist ein literales Komma — dieselben Regeln wienew --set.--add/--removeändern einzelne Elemente, ohne dass man die bestehende Liste kennen muss.--addist idempotent.--removeauf ein nicht vorhandenes Element gelingt und sagt es. Wiexref removeidempotent, aber nie stillschweigend — ein stiller No-op sieht genauso aus wie eine erfolgreiche Entfernung, und genau so verschwindet ein Tippfehler.Gesperrt, jeweils mit Nennung des zuständigen Kommandos:
type:(page-lifecycle),confidence:(abgeleitet), und die Page-Ref-Arrays (xref).Deny statt Allow, weil eine Allowlist eine zweite Kopie des Schemas wäre — und die Kopie ist die, die driftet. Ein neu in einen Type-Spec aufgenommenes Feld bliebe stumm unbeschreibbar, bis jemand daran denkt. Invariante 8, angewandt auf eine Konstante.
Ein unbekanntes Feld wird bewusst anders abgelehnt als ein gesperrtes — nicht mit einem Verweis auf ein anderes Kommando, sondern mit der Liste dessen, was die Seite tatsächlich hat:
Der Anlassfall ist repariert
kb/concepts/Diff-Reviewable Agent Edits.mdtrug wegen eines Kommas am Ende eines--set tags=-Werts nur[agent-workflow]und war nicht mehr korrigierbar. Am echten Korpus:Die Seite trägt jetzt
[agent-workflow, context-engineering, tooling].Umbau nebenbei
_coerce_set_value,_parse_set_fieldsund_check_raw_files_existsind vonnew_page.pynachcommands/_util.pygewandert. Zwei Kommandos, eine Implementierung — sonst hättetouch --setdas Komma-Problem aus #12 gleich mit geerbt. Ein Test deckt genau das ab.raw_files:bekommt beim Schreiben durchtouchdieselbe Existenzprüfung wie beinew.tests/test_touch.pyruft den Typer-Callback jetzt über einen Helfer mit Vollbelegung auf — ein direkt aufgerufener Callback bekommt für ausgelassene ArgumenteOptionInfo-Objekte, und ohne den Helfer kostet jede neue Option eine Änderung an sieben Aufrufstellen. Dieselbe Falle, diedist_cmd.pydurch die Trennung von Wrapper und Logik vermeidet.Prüfungen
674 Tests grün, auch mit leerem
HOMEund ohne globale git-Config.docs verify,instructions verify,lintsauber. Contract-Zeilen für Kommando und Fehlerkontrakt ergänzt.Übrig
raw renameals #16 (prio/2,size/S) — der Fall, dass die Datei sich bewegt. Zweistufig ist er jetzt möglich, aber zwischengit mvundtouch --setzeigt die Referenz kurz ins Leere.