entities:/concepts: einer Source-Seite sind nach dem Anlegen unerreichbar, und xref add schreibt dort ein undeklariertes related: #18

Closed
opened 2026-08-31 09:24:02 +00:00 by torben · 1 comment
Owner

Kurz

Die Lücke, die #14 für tags: und raw_files: geschlossen hat, besteht für die eine Feldfamilie fort, auf die #14 ausdrücklich verwiesen hat. Die Sperrliste in touch --set lehnt Page-Ref-Felder mit „use wikitool xref add / xref remove" ab — für die entities:/concepts: einer Source-Seite kann xref das aber nicht.

Das ist ein Loch in einer Designentscheidung von heute (1.4.0), kein Altlastenfund.

Der Ablauf, der es auslöst

Ein Ingest legt die Source-Seite an, bevor die Concept-Seiten existieren — der Skill schreibt sie später, weil ihre Titel erst beim Extrahieren feststehen. Also bleibt concepts: []. Danach:

Versuch Ergebnis
xref link-source --source … --entities A,B Schreibt nur die Zielseiten (sources: + See Also). Die Arrays der Source-Seite rührt es nie an — es validiert nur, dass sie existiert (xref.py:218).
xref add --a "Source - …" --b "A" Schreibt ein undeklariertes related: auf die Source-Seite. types/source.md deklariert page_ref_fields: [entities, concepts]related ist keins davon.
xref remove --a "Source - …" --b "A" Bekommt es nicht weg: strip_frontmatter_ref() läuft nur über die vom Typ deklarierten Felder.
touch --set concepts=… Abgelehnt: „page-reference field - use xref add / xref remove" — verweist auf zwei Befehle, die das Feld nicht bedienen können.

Ergebnis: eine Sackgasse, und unterwegs eine Seite, die das Schema verletzt.

Der Schaden liegt live auf main

8524bce, kb/sources/Source - Conversation - Write-Once Frontmatter Fields and touch --set Session 2026-08-31.md:

entities: [wikitool, llm-wiki-test1, Gitea, AGENTS.md]
concepts: []
related: [Write-Once Frontmatter Fields]   # nicht vom Typ deklariert

lint meldet es als einzigen Schema-Fehler im Korpus:

Additional properties are not allowed ('related' was unexpected)

concepts: ist leer, obwohl die Seite zwei neue Concepts belegt. Die Zuordnung steht ersatzweise als Prosa im Body.

Drei Defekte, eine Ursache

  1. xref add prüft nicht, ob der Typ das Feld kennt. Es sollte ablehnen statt ein undeklariertes Feld zu schreiben — dann wäre der Schema-Fehler nie entstanden. Das ist die eigentliche Ursache.
  2. xref remove kann undeklarierte Reste nicht räumen. Sein Contract-Eintrag verspricht ausdrücklich, „eine Referenz zu klären, die eine von Hand gelöschte oder umbenannte Seite hinterlassen hat, ohne Frontmatter von Hand zu editieren". Für ein Feld außerhalb der Typdeklaration hält es das nicht.
  3. Nichts schreibt die eigenen Ref-Arrays einer Source-Seite. link-source ist die Gegenrichtung. Es fehlt der Hinweg.

Lösungsrichtungen

  • xref link-source schreibt beide Richtungen. Es kennt Quelle und Ziele bereits; der Ingest-Ablauf ruft es ohnehin auf. Naheliegendster Schnitt, und der Name stimmt dann endlich.
  • xref add lehnt undeklarierte Felder ab — mit einer Meldung, die sagt, welche Ref-Felder der Typ kennt. Analog zu der Unterscheidung, die touch --set seit 1.4.0 macht.
  • xref remove räumt auch Felder außerhalb der Deklaration, damit ein einmal entstandener Rest überhaupt entfernbar bleibt. Ohne das ist jeder künftige Fall wieder eine Sackgasse.
  • Die Ablehnungsmeldung in touchs Sperrliste anpassen, sobald xref den Fall wirklich abdeckt — heute verweist sie ins Leere.

Reparatur des Bestandsfalls

Nach dem Fix mit dem Werkzeug selbst. Vorher gibt es keinen Weg, der ohne rm --yes auskommt, und die Seite wird von fünf anderen referenziert (wikitool, llm-wiki-test1, Write-Once Frontmatter Fields, Denylist over Allowlist, Detect-Repair Asymmetry) — löschen und neu anlegen kostet fünf cite add und ein xref link-source und ist die schlechtere Wahl, wenn der Fix ohnehin ansteht.

Akzeptanzkriterien

  • Nach einem Ingest, der Concepts erst nach der Source-Seite anlegt, trägt die Source-Seite ihre concepts: — ohne Frontmatter-Handeditierung. Das ist der Test.
  • xref add auf ein vom Typ nicht deklariertes Ref-Feld wird abgelehnt und nennt die Felder, die der Typ kennt.
  • xref remove räumt ein undeklariertes Ref-Feld, das eine ältere Version hinterlassen hat.
  • Die betroffene Seite auf main ist repariert: related: weg, concepts: gefüllt, lint ohne Schema-Fehler.
  • Zeilen in tools/CONTRACT.md für jedes geänderte Kommando und seinen Fehlerkontrakt.
  • Changelog, MINOR.

Warum prio/1

Ein Schema-Fehler liegt veröffentlicht auf main, und der Zustand ist mit den vorhandenen Kommandos nicht rückgängig zu machen. Zusätzlich ist es der laufende Gegenbeweis zu der Aussage, die #14 zu schließen behauptet: eine Feldklasse, die new einmal schreibt und danach niemand mehr.

## Kurz Die Lücke, die #14 für `tags:` und `raw_files:` geschlossen hat, besteht für **die eine Feldfamilie fort, auf die #14 ausdrücklich verwiesen hat.** Die Sperrliste in `touch --set` lehnt Page-Ref-Felder mit „use `wikitool xref add` / `xref remove`" ab — für die `entities:`/`concepts:` einer Source-Seite kann `xref` das aber nicht. Das ist ein Loch in einer Designentscheidung von heute (1.4.0), kein Altlastenfund. ## Der Ablauf, der es auslöst Ein Ingest legt die Source-Seite an, **bevor** die Concept-Seiten existieren — der Skill schreibt sie später, weil ihre Titel erst beim Extrahieren feststehen. Also bleibt `concepts: []`. Danach: | Versuch | Ergebnis | |---|---| | `xref link-source --source … --entities A,B` | Schreibt **nur die Zielseiten** (`sources:` + See Also). Die Arrays der Source-Seite rührt es nie an — es validiert nur, dass sie existiert (`xref.py:218`). | | `xref add --a "Source - …" --b "A"` | Schreibt ein **undeklariertes `related:`** auf die Source-Seite. `types/source.md` deklariert `page_ref_fields: [entities, concepts]` — `related` ist keins davon. | | `xref remove --a "Source - …" --b "A"` | Bekommt es nicht weg: `strip_frontmatter_ref()` läuft nur über die **vom Typ deklarierten** Felder. | | `touch --set concepts=…` | Abgelehnt: „page-reference field - use `xref add` / `xref remove`" — verweist auf zwei Befehle, die das Feld nicht bedienen können. | Ergebnis: eine Sackgasse, und unterwegs eine Seite, die das Schema verletzt. ## Der Schaden liegt live auf main `8524bce`, `kb/sources/Source - Conversation - Write-Once Frontmatter Fields and touch --set Session 2026-08-31.md`: ```yaml entities: [wikitool, llm-wiki-test1, Gitea, AGENTS.md] concepts: [] related: [Write-Once Frontmatter Fields] # nicht vom Typ deklariert ``` `lint` meldet es als einzigen Schema-Fehler im Korpus: ``` Additional properties are not allowed ('related' was unexpected) ``` `concepts:` ist leer, obwohl die Seite zwei neue Concepts belegt. Die Zuordnung steht ersatzweise als Prosa im Body. ## Drei Defekte, eine Ursache 1. **`xref add` prüft nicht, ob der Typ das Feld kennt.** Es sollte ablehnen statt ein undeklariertes Feld zu schreiben — dann wäre der Schema-Fehler nie entstanden. Das ist die eigentliche Ursache. 2. **`xref remove` kann undeklarierte Reste nicht räumen.** Sein Contract-Eintrag verspricht ausdrücklich, „eine Referenz zu klären, die eine von Hand gelöschte oder umbenannte Seite hinterlassen hat, ohne Frontmatter von Hand zu editieren". Für ein Feld außerhalb der Typdeklaration hält es das nicht. 3. **Nichts schreibt die eigenen Ref-Arrays einer Source-Seite.** `link-source` ist die Gegenrichtung. Es fehlt der Hinweg. ## Lösungsrichtungen - **`xref link-source` schreibt beide Richtungen.** Es kennt Quelle und Ziele bereits; der Ingest-Ablauf ruft es ohnehin auf. Naheliegendster Schnitt, und der Name stimmt dann endlich. - **`xref add` lehnt undeklarierte Felder ab** — mit einer Meldung, die sagt, welche Ref-Felder der Typ kennt. Analog zu der Unterscheidung, die `touch --set` seit 1.4.0 macht. - **`xref remove` räumt auch Felder außerhalb der Deklaration**, damit ein einmal entstandener Rest überhaupt entfernbar bleibt. Ohne das ist jeder künftige Fall wieder eine Sackgasse. - Die Ablehnungsmeldung in `touch`s Sperrliste anpassen, sobald `xref` den Fall wirklich abdeckt — heute verweist sie ins Leere. ## Reparatur des Bestandsfalls Nach dem Fix mit dem Werkzeug selbst. **Vorher gibt es keinen Weg, der ohne `rm --yes` auskommt**, und die Seite wird von fünf anderen referenziert (`wikitool`, `llm-wiki-test1`, `Write-Once Frontmatter Fields`, `Denylist over Allowlist`, `Detect-Repair Asymmetry`) — löschen und neu anlegen kostet fünf `cite add` und ein `xref link-source` und ist die schlechtere Wahl, wenn der Fix ohnehin ansteht. ## Akzeptanzkriterien - [ ] Nach einem Ingest, der Concepts erst nach der Source-Seite anlegt, trägt die Source-Seite ihre `concepts:` — ohne Frontmatter-Handeditierung. Das ist der Test. - [ ] `xref add` auf ein vom Typ nicht deklariertes Ref-Feld wird abgelehnt und nennt die Felder, die der Typ kennt. - [ ] `xref remove` räumt ein undeklariertes Ref-Feld, das eine ältere Version hinterlassen hat. - [ ] Die betroffene Seite auf `main` ist repariert: `related:` weg, `concepts:` gefüllt, `lint` ohne Schema-Fehler. - [ ] Zeilen in `tools/CONTRACT.md` für jedes geänderte Kommando **und** seinen Fehlerkontrakt. - [ ] Changelog, **MINOR**. ## Warum prio/1 Ein Schema-Fehler liegt veröffentlicht auf `main`, und der Zustand ist mit den vorhandenen Kommandos nicht rückgängig zu machen. Zusätzlich ist es der laufende Gegenbeweis zu der Aussage, die #14 zu schließen behauptet: eine Feldklasse, die `new` einmal schreibt und danach niemand mehr.
torben added the prio/blockingsize/S labels 2026-08-31 09:24:09 +00:00
Author
Owner

Behoben in 1.6.0 (ce03749). Alle drei Defekte, plus die Reparatur des Bestandsfalls mit dem Werkzeug selbst.

1. xref link-source schreibt beide Richtungen

Welches Feld ein Ziel bekommt, folgt seiner Collection: kb/entities/entities:, kb/concepts/concepts:. Das Verzeichnis ist der Feldname, also braucht eine neue Collection hier keine Code-Änderung — sie braucht einen Typ, der das passende Feld deklariert. Kein Typ-zu-Feld-Mapping, das driften kann.

Ein Ziel, dessen Collection zu keinem deklarierten Ref-Feld der Source-Seite passt, wird einseitig verlinkt und in der Ausgabe benannt statt stillschweigend übergangen.

2. xref add lehnt ein nicht deklariertes related: ab

$ tools/wikitool xref add --a "Source - Conversation - Write-Once …" --b "wikitool" …
ERROR 'Source - …' is a types/source.md page, whose type does not declare
a `related:` field, so `xref add` has nothing to write there.
  Reference fields this type declares: entities, concepts
  For a source page, `wikitool xref link-source --source "Source - …"
--entities <titles>` is the command that fills them.

Die Prüfung läuft für beide Seiten, bevor eine davon geschrieben wird — eine Ablehnung darf keinen halben Link hinterlassen. Dafür gibt es einen eigenen Test.

3. xref remove räumt undeklarierte Reste

Gesweept wird jetzt zusätzlich jedes auf der Seite vorhandene Feld, das irgendein Typ als Ref-Feld deklariert — die Namen kommen aus den Type-Specs, nicht aus einer Konstante. Ein undeklariertes Feld, das dabei leer wird, fällt ganz weg statt als related: [] stehenzubleiben: der Schlüssel war für diesen Typ nie gültig, und ein leeres Array hielte die Seite weiter schemawidrig.

Weil rename und rm denselben Helfer benutzen, gilt es auch dort.

Bestandsfall repariert — ohne rm --yes

$ tools/wikitool xref remove --a "Source - …" --b "Write-Once Frontmatter Fields"
OK Unlinked …

$ tools/wikitool xref link-source --source "Source - …" \
    --entities "Write-Once Frontmatter Fields,Denylist over Allowlist"
OK Linked source … to 2 page(s)

Ergebnis:

entities: [wikitool, llm-wiki-test1, Gitea, AGENTS.md]
concepts: [Write-Once Frontmatter Fields, Denylist over Allowlist]
# related: weg

lint meldet keinen Schema-Fehler mehr im Korpus. Die referenzierende Concept-Seite ist byte-identisch durch den Zyklus gekommen — xref remove hat ihren Rückverweis korrekt beidseitig geräumt, link-source ihn identisch wiederhergestellt.

Sonst

Die Sperrlisten-Meldungen in touch --set nennen für entities:/concepts:/sources: jetzt konkret xref link-source. Der bisherige Verweis auf xref add/xref remove war für genau diese Felder falsch — das war das Loch in der 1.4.0-Entscheidung, das dieses Issue aufgedeckt hat.

689 Tests grün in beiden Umgebungen (sechs neue). Contract-Zeilen für alle drei Kommandos und ihre Fehlerkontrakte aktualisiert.

Was das über den Zuschnitt von 1.4.0 sagt

Die Denylist war richtig, ihr Verweisziel nicht. Eine Sperrliste, die auf ein anderes Kommando zeigt, ist eine Behauptung über dessen Fähigkeiten — und die war ungeprüft. Beim nächsten Mal gehört zu einem solchen Verweis ein Test, der zeigt, dass das genannte Kommando den Fall wirklich abdeckt.

Behoben in **1.6.0** (`ce03749`). Alle drei Defekte, plus die Reparatur des Bestandsfalls mit dem Werkzeug selbst. ## 1. `xref link-source` schreibt beide Richtungen Welches Feld ein Ziel bekommt, folgt seiner **Collection**: `kb/entities/` → `entities:`, `kb/concepts/` → `concepts:`. Das Verzeichnis *ist* der Feldname, also braucht eine neue Collection hier keine Code-Änderung — sie braucht einen Typ, der das passende Feld deklariert. Kein Typ-zu-Feld-Mapping, das driften kann. Ein Ziel, dessen Collection zu keinem deklarierten Ref-Feld der Source-Seite passt, wird einseitig verlinkt und **in der Ausgabe benannt** statt stillschweigend übergangen. ## 2. `xref add` lehnt ein nicht deklariertes `related:` ab ``` $ tools/wikitool xref add --a "Source - Conversation - Write-Once …" --b "wikitool" … ERROR 'Source - …' is a types/source.md page, whose type does not declare a `related:` field, so `xref add` has nothing to write there. Reference fields this type declares: entities, concepts For a source page, `wikitool xref link-source --source "Source - …" --entities <titles>` is the command that fills them. ``` Die Prüfung läuft für **beide** Seiten, bevor eine davon geschrieben wird — eine Ablehnung darf keinen halben Link hinterlassen. Dafür gibt es einen eigenen Test. ## 3. `xref remove` räumt undeklarierte Reste Gesweept wird jetzt zusätzlich jedes auf der Seite vorhandene Feld, das *irgendein* Typ als Ref-Feld deklariert — die Namen kommen aus den Type-Specs, nicht aus einer Konstante. Ein undeklariertes Feld, das dabei leer wird, fällt ganz weg statt als `related: []` stehenzubleiben: der Schlüssel war für diesen Typ nie gültig, und ein leeres Array hielte die Seite weiter schemawidrig. Weil `rename` und `rm` denselben Helfer benutzen, gilt es auch dort. ## Bestandsfall repariert — ohne `rm --yes` ``` $ tools/wikitool xref remove --a "Source - …" --b "Write-Once Frontmatter Fields" OK Unlinked … $ tools/wikitool xref link-source --source "Source - …" \ --entities "Write-Once Frontmatter Fields,Denylist over Allowlist" OK Linked source … to 2 page(s) ``` Ergebnis: ```yaml entities: [wikitool, llm-wiki-test1, Gitea, AGENTS.md] concepts: [Write-Once Frontmatter Fields, Denylist over Allowlist] # related: weg ``` `lint` meldet **keinen Schema-Fehler mehr** im Korpus. Die referenzierende Concept-Seite ist byte-identisch durch den Zyklus gekommen — `xref remove` hat ihren Rückverweis korrekt beidseitig geräumt, `link-source` ihn identisch wiederhergestellt. ## Sonst Die Sperrlisten-Meldungen in `touch --set` nennen für `entities:`/`concepts:`/`sources:` jetzt konkret `xref link-source`. Der bisherige Verweis auf `xref add`/`xref remove` war für genau diese Felder falsch — das war das Loch in der 1.4.0-Entscheidung, das dieses Issue aufgedeckt hat. 689 Tests grün in beiden Umgebungen (sechs neue). Contract-Zeilen für alle drei Kommandos **und** ihre Fehlerkontrakte aktualisiert. ## Was das über den Zuschnitt von 1.4.0 sagt Die Denylist war richtig, ihr Verweisziel nicht. Eine Sperrliste, die auf ein anderes Kommando zeigt, ist eine Behauptung über dessen Fähigkeiten — und die war ungeprüft. Beim nächsten Mal gehört zu einem solchen Verweis ein Test, der zeigt, dass das genannte Kommando den Fall wirklich abdeckt.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#18