From 6b300aa78274f6fee604561555dfac286e7281c8 Mon Sep 17 00:00:00 2001 From: Torben Nehmer Date: Wed, 9 Sep 2026 07:50:18 +0200 Subject: [PATCH] source_type ist Instanzsache: Profilkatalog, Setup-Frage, evolve-subtypes-Instruction (schliesst #68) Files changed: - CHANGES.md - VERSION - instructions/evolve-subtypes.md - instructions/kb-profiles.md - instructions/setup-instance.md - kb/sources/COLLECTION.md --- CHANGES.md | 54 ++++++++++++++- VERSION | 2 +- instructions/evolve-subtypes.md | 114 ++++++++++++++++++++++++++++++++ instructions/kb-profiles.md | 24 +++++++ instructions/setup-instance.md | 18 +++++ kb/sources/COLLECTION.md | 2 +- 6 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 instructions/evolve-subtypes.md diff --git a/CHANGES.md b/CHANGES.md index 62a58a0..471d00b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -35,7 +35,7 @@ dev-checkout concern - readable here, never shipped as something to parse. --- -## 4.8.0-beta.8 - 2026-09-08 - raw accept: Datums-Shard statt Typverzeichnis, fidelity/authority am Drop-Punkt (schliesst #67) +## 4.8.0-beta.9 - 2026-09-09 - source_type ist Instanzsache: Profilkatalog, Setup-Frage, evolve-subtypes-Instruction (#68) **Author:** Torben Nehmer @@ -49,6 +49,7 @@ dev-checkout concern - readable here, never shipped as something to parse. - kb/concepts/ bekommt Areas: layout: fuer concept, Area-Titel aus jedem Type-Spec, Schwellen-Empfehlung im lint (schliesst #59) - source_type: Default streichen, unclassified als sichtbares Fach, layout: fuer source (schliesst #66) - raw accept: Datums-Shard statt Typverzeichnis, fidelity/authority am Drop-Punkt (schliesst #67) +- source_type ist Instanzsache: Profilkatalog, Setup-Frage, evolve-subtypes-Instruction (#68) Das Label `status/incoming` gibt es seit heute in Gitea: der Mensch legt einen @@ -527,6 +528,57 @@ hochgestuft, nur damit der Report leiser wird. Schließt #67. +**`source_type` ist Instanzsache: Profilkatalog, Setup-Frage, `evolve-subtypes`-Instruction** +(#68, Paket C von vier — A ist #66, B ist #67, D ist #69): reine Doku- und Instruction-Arbeit, +kein Korpus-Sweep. + +Befund: `source_type`s sieben Werte (`transcript`, `analysis`, `article`, `document`, `notes`, +`tracker`, `unclassified`) beschreiben *diese* Instanz, nicht den Stack — gegen drei +hypothetische Zielinstanzen (Handball-Verein, Produktentwicklung, Pen-&-Paper) hat die Liste +fast nichts gemeinsam, während `fidelity`/`authority` (#67) in allen vieren dieselben Werte +bleiben. Architektonisch war das längst wahr (`types/source.md` trägt `root: kb`, `dist export` +liefert es nur als `.template`), nur stellte nichts die Frage: `instructions/kb-profiles.md` +riet im `entities`-Abschnitt „Adapt the area list first", sagte im `sources`-Abschnitt aber kein +Wort zu `source_type`. Zweiter Befund, aus #66 mitgenommen: das `unclassified`-Fach bekam einen +beratenden `lint`-Befund, aber nie eine Prozedur, es wieder zu leeren. + +Umgesetzt: + +- `kb-profiles.md`s `sources`-Abschnitt behandelt `source_type` jetzt wie `entities` seine Area- + Liste: als das, was zuerst anzupassen ist, mit zwei ausformulierten Domänenprofilen + (Handball-Verein, Pen-&-Paper) als Anschauung, und dem ausdrücklichen Gegenbeispiel + `fidelity`/`authority` — die sind Stack-Vokabular und stehen nicht zur Wahl. +- `instructions/setup-instance.md` Schritt 5 bekommt einen neuen Unterschritt: nach dem + Anwendungsgebiet fragen, `source_type`-Vorschlag ableiten, Enum und `layout:` in derselben + Bearbeitung setzen. Mit der Ansage, dass der Betreiber zum Setup-Zeitpunkt null Quellen hat und + seine Taxonomie vor jedem Material rät — das Ergebnis ist ein Startpunkt, keine Festlegung, und + `unclassified` bleibt in jedem Vorschlag erhalten. +- Neue Instruction `instructions/evolve-subtypes.md`, `manual: true`: benennt die + Weiterentwicklungsschleife, die werkzeugseitig schon vollständig existierte (Fach sehen → + Wert samt `layout:` ergänzen → `touch`/`move --reconcile` → `index rebuild`/`migrate verify`), + über alle drei Subtype-Achsen (`entity_type`, `concept_type`, `source_type` — alle drei tragen + `subtype_field:` **und** `layout:`; `comparison` keins von beidem). Zwei Regeln im Body: Wert + und Sweep sind untrennbar (ein deklarierter Wert ohne Seite lädt zum Raten ein — genau der + `notes`-Fall aus #66), und eine Aufnahmeschwelle von ≥3 Seiten, mit `spec`/`image` aus #66 als + Gegenbeispiel und einer benannten-Ausnahme-Klausel für Fälle wie `tracker` bei zwei Seiten. + `manual: true` verhindert, dass eine Taxonomie-Änderung in einen laufenden Ingest hineinstolpert + — erwähnt aus `kb-profiles.md`, `setup-instance.md` und `kb/sources/COLLECTION.md`, aus keinem + Skill, keiner AGENTS.md, keiner CLAUDE.md verlinkt. +- `kb/sources/COLLECTION.md` benennt `evolve-subtypes.md` an der `unclassified/`-Zeile. + +Die vom Vorbereitungs-Body übernommene, ursprünglich vierte Maßnahme entfiel: die +`corpus-policy.md`-Floor-Ausnahme für `unclassified` steht dort bereits seit #66. + +**MINOR**, geprüft gegen den Drop-in-Test: eine Instanz kopiert `instructions/` und `types/` +über sich, nichts wird umbenannt oder entfernt, kein Kommando, kein Flag, kein +maschinengelesenes Format. Kein `--breaking`, kein Migrationsdokument. `4.8.0-beta.9` desselben +Kandidaten. + +Geändert: `instructions/kb-profiles.md`, `instructions/setup-instance.md`, +`instructions/evolve-subtypes.md` (neu), `kb/sources/COLLECTION.md`. + +Schließt #68. + --- ## 4.7.4 - 2026-09-04 - bootstrap.md nennt den session-id-WARN nach frischem Bootstrap explizit als erwartet diff --git a/VERSION b/VERSION index 346f8e3..67708b3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.8.0-beta.8 +4.8.0-beta.9 diff --git a/instructions/evolve-subtypes.md b/instructions/evolve-subtypes.md new file mode 100644 index 0000000..565f7ce --- /dev/null +++ b/instructions/evolve-subtypes.md @@ -0,0 +1,114 @@ +--- +type: types/instruction.md +name: evolve-subtypes +description: Extend or drain a page type's subtype vocabulary - entity_type, concept_type, or source_type - once real material has outgrown it, and the invariants that keep the resulting values honest. +manual: true +--- +# Extend a subtype vocabulary, or drain its catch-all + +A subtype field (`entity_type`, `concept_type`, `source_type`) partitions one page type into +areas via that type-spec's `layout:` - `types/type-spec.md` has the anatomy. Every one of these +three enums is instance-owned content, not stack vocabulary: `entity.md`, `concept.md` and +`source.md` all carry `root: kb` and ship only as `.template`, so an instance's own list of +values is exactly as much its own decision as its collection contracts are +([kb-profiles.md](kb-profiles.md) is the palette that seeds it). This instruction is the +procedure for changing that list once it is running, not for choosing it the first time - +[setup-instance.md](setup-instance.md) does that. + +The tooling for this loop already exists end to end; this file only names the sequence and the +two rules that keep it from repeating what created `kb/sources/`'s old `notes` catch-all in the +first place (Gitea #66): a schema `default:` that the compiler applied whenever nobody +disagreed, silently turning the least specific value into the collection point for everything +unclear. + +## When to run + +- A `wikitool lint` advisory finding reports pages sitting in a subtype's catch-all value (for + `source`, that is `unclassified` - visible in the catalog, carrying no default) and there are + now enough of them to warrant a real value. +- A real ingest keeps producing pages that do not fit any existing value for a subtype field, + and forcing them into the nearest existing one would misclassify them. +- The catch-all itself needs draining after a value was added, so it does not become a second, + quieter collection point. + +Not for renaming or removing a value that pages already carry under - that moves pages and is a +corpus migration ([migrate-corpus.md](migrate-corpus.md)), not this loop. Not for the one-time +choice of an instance's starting vocabulary - that is +[setup-instance.md](setup-instance.md)'s KB-language step, seeded from +[kb-profiles.md](kb-profiles.md). + +## Steps + +1. **See what has actually collected in the catch-all**, before touching anything: + + ```bash + tools/wikitool lint + tools/wikitool search --field source_type=unclassified # or the equivalent _type + ``` + + Read every page the search returns. A count alone does not say whether the pages share one + real category or three - that judgment is the reason this step exists rather than being + folded into the next one. + +2. **Apply the value-and-sweep rule: a new value is added and populated in the same pass, never + one without the other.** A declared value that no page carries yet is a category that invites + a guess the next time someone has to pick between it and the catch-all - which is exactly how + the old `notes` default absorbed 22 of 29 source pages before anyone noticed. So: + + 1. Count real candidates first: `tools/wikitool search --field _type=` + will find nothing yet, so count by reading the catch-all's pages from step 1 instead. + 2. **Apply the ≥3-page admission threshold.** A value is admitted *after* it has proven + itself against real material, never in expectation of some. `spec` and `image` are the + cautionary case: both were added to `source_type` ahead of any matching page, both sat at + zero for a year, and both were removed in Gitea #66. A smaller count is only ever an + operator's explicit, named exception (`tracker` at two pages in #66, kept because the + corpus was expected to grow into it from ongoing issue ingests) - never a reason to lower + the threshold itself. + 3. Add the enum value in the type-spec's schema (`types/.schema.yaml`) and its `layout:` + entry (`types/.md`) in the same edit - a value with no `layout:` line has nowhere to be + moved to. + 4. Reclassify every candidate page in the same pass: + + ```bash + tools/wikitool touch --page "" --set <x>_type=<new-value> + tools/wikitool move --reconcile + ``` + + 5. Rebuild and check: + + ```bash + tools/wikitool index rebuild + tools/wikitool migrate verify --from HEAD --fail-on-error + tools/wikitool lint --fail-on-error + ``` + + `migrate verify` on a subtype sweep should report moved pages and zero findings - a + `<x>_type` change alone touches no wikilink, citation, footnote or H1. + +3. **Draining the catch-all is the same loop, run without step 2.2's threshold** - a page + sitting in `unclassified` (or the equivalent) already has an intended home; the only question + is which existing value it belongs to, which step 1's read-through already answered. Skip + straight to reclassifying it (step 2.4) and rebuilding (step 2.5). + +4. **Record it** with `tools/wikitool log append`, describing what moved and why, the same way + any other corpus change is logged. + +## Decision points + +- **The catch-all is empty and lint reports nothing?** Nothing to do - an empty catch-all is the + success state, not a problem this instruction exists to fix. +- **A candidate page could plausibly fit two existing values?** Resolve it by rereading the + collection's `COLLECTION.md` for the distinguishing rule (for `sources`, authorship decides + `analysis` vs. `document`) before inventing a third value - a genuine gap in the existing + values is rarer than an under-read contract. +- **More than one subtype field needs the same treatment?** Run this loop once per field; do not + try to batch an `entity_type` change and a `source_type` change into one pass, since their + admission thresholds are independent judgments about unrelated material. + +## Scope + +Covers `entity_type`, `concept_type` and `source_type` - the three subtype fields with both +`subtype_field:` and `layout:` declared. `comparison` has neither and is out of scope by +construction. Does not cover the stack-owned capture fields `fidelity`/`authority` on `source` +pages: those are fixed vocabulary the stack defines, not an instance's taxonomy - see +`types/source.md`. diff --git a/instructions/kb-profiles.md b/instructions/kb-profiles.md index 3b608fa..ed3a94d 100644 --- a/instructions/kb-profiles.md +++ b/instructions/kb-profiles.md @@ -152,6 +152,30 @@ against. Not optional in the way the others are. An instance may rewrite its authoring rules and may not rename or drop it. +**`source_type` is a palette too, and the part most likely to be wrong for another domain - +adapt its value list first**, the same way `entities`' area list is called out above. This +repo's own list (`transcript, analysis, article, document, notes, tracker, unclassified`) +describes *what a private-projects instance ingests*; it says nothing about what a source is in +a different domain. Two worked lists, to show how little the values carry over: + +| Instance | Plausible `source_type` values | +|---|---| +| Handball club and federation | `satzung` (bylaws), `protokoll` (minutes), `korrespondenz`, `spielbericht` (match report), `verbandsmitteilung` | +| Tabletop game master | `regelwerk` (rulebook), `abenteuermodul` (module), `sessionlog`, `handout`, `weltenbau` (worldbuilding) | + +Adopting one means copying the value list into `types/source.schema.yaml`'s enum and giving each +value a `layout:` line in `types/source.md` - the same "copy the text in, do not point at this +page" rule as every other profile here. Keep the visible catch-all value (`unclassified` above) +in whatever list is adopted: a subtype field without one silently reintroduces the old +`default:`-driven collection point that Gitea #66 removed the moment nobody names an edge case. +Growing the list later, or draining the catch-all, is +[evolve-subtypes.md](evolve-subtypes.md). + +**Not up for choice: `fidelity` and `authority`.** Unlike `source_type`, these two capture +fields are stack vocabulary - `types/source.md`'s `capture_fields:` - because they held the same +few values across every domain this catalogue tried, where `source_type` did not. An instance +adapts the *value list* above; it does not touch `fidelity`'s or `authority`'s enums. + ### `comparisons` Structured head-to-head evaluations of two or more things that already have pages. diff --git a/instructions/setup-instance.md b/instructions/setup-instance.md index 1662139..527014a 100644 --- a/instructions/setup-instance.md +++ b/instructions/setup-instance.md @@ -100,6 +100,24 @@ bereit für den ersten `Ingest`. durch das eigene Vokabular ersetzen - sie ist Material des deutschen Profils, nicht des Stacks. + 5. Den Nutzer nach dem Anwendungsgebiet fragen und daraus einen `source_type`-Vorschlag + ableiten. [kb-profiles.md](kb-profiles.md) hält dafür zwei ausformulierte Domänenprofile + als Anschauung bereit, neben dem Wert, den dieses Repo selbst nutzt. Der Vorschlag ist ein + **Startpunkt, keine Festlegung** - zum Setup-Zeitpunkt hat der Betreiber null Quellen und + rät seine Taxonomie, bevor er auch nur eine Datei gesehen hat, und das ist der + schlechteste Moment, ein Enum festzuzurren. Vorschlag umgesetzt heißt: das Enum in + `types/source.schema.yaml` **und** die passende `layout:`-Zeile je Wert in + `types/source.md` in derselben Bearbeitung setzen - eine ohne die andere lässt einen Wert + ohne Zielverzeichnis zurück. Der sichtbare Auffangwert (`unclassified`) bleibt in jedem + Vorschlag erhalten; er ist kein Sammelbecken, sondern das Fach für eine Quelle, deren + Kategorie noch nicht feststeht. Die Liste später erweitern oder das Fach leeren: + [evolve-subtypes.md](evolve-subtypes.md) - nicht Teil dieses Schritts, aber der Weg dahin, + sobald echtes Material vorliegt. + + **Unverändert lassen:** `fidelity` und `authority` auf `source`-Seiten. Die sind + Stack-Vokabular, keine Instanzentscheidung - [kb-profiles.md](kb-profiles.md) sagt das im + selben Abschnitt. + **Vor dem ersten Ingest entscheiden.** Die `sections:`-Namen in `kb/CONVENTIONS.md` sind die Überschriften, die `xref` und `cite` in jede Seite schreiben; sie danach zu ändern ist eine Migration jeder vorhandenen Seite (`section_aliases:` trägt die alten Namen, siehe diff --git a/kb/sources/COLLECTION.md b/kb/sources/COLLECTION.md index fa045ee..bba0f7c 100644 --- a/kb/sources/COLLECTION.md +++ b/kb/sources/COLLECTION.md @@ -37,7 +37,7 @@ Default** (Gitea #66): `wikitool new source` verweigert ohne einen expliziten We | `documents/` | Eingelesene Dokumente, Handbücher, Spezifikationen | | `notes/` | Echte eigene Notizen ohne Dialogform - Cheat Sheets, Merkzettel | | `trackers/` | Exporte aus einem Issue-Tracker oder vergleichbaren System | -| `unclassified/` | Sichtbares Fach für eine Quelle, deren Kategorie noch nicht feststeht - beratender `lint`-Befund, kein Sammelbecken | +| `unclassified/` | Sichtbares Fach für eine Quelle, deren Kategorie noch nicht feststeht - beratender `lint`-Befund, kein Sammelbecken. Es wieder zu leeren, oder das Enum um einen neuen Wert zu erweitern: [instructions/evolve-subtypes.md](../../instructions/evolve-subtypes.md) | Das sind Areas, keine Collections: sie erben diesen Contract und tragen keine eigene `COLLECTION.md`. Die Zuordnung trifft niemand von Hand - sie steht als `layout:` in