Files changed: - CHANGES.md - VERSION - instructions/evolve-subtypes.md - instructions/kb-profiles.md - instructions/setup-instance.md - kb/sources/COLLECTION.md
6.1 KiB
type, name, description, manual
| type | name | description | manual |
|---|---|---|---|
| types/instruction.md | evolve-subtypes | 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. | 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 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 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 lintadvisory finding reports pages sitting in a subtype's catch-all value (forsource, that isunclassified- 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), not this loop. Not for the one-time choice of an instance's starting vocabulary - that is setup-instance.md's KB-language step, seeded from kb-profiles.md.
Steps
-
See what has actually collected in the catch-all, before touching anything:
tools/wikitool lint tools/wikitool search --field source_type=unclassified # or the equivalent <x>_typeRead 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.
-
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
notesdefault absorbed 22 of 29 source pages before anyone noticed. So:-
Count real candidates first:
tools/wikitool search --field <x>_type=<candidate-guess>will find nothing yet, so count by reading the catch-all's pages from step 1 instead. -
Apply the ≥3-page admission threshold. A value is admitted after it has proven itself against real material, never in expectation of some.
specandimageare the cautionary case: both were added tosource_typeahead 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 (trackerat 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. -
Add the enum value in the type-spec's schema (
types/<t>.schema.yaml) and itslayout:entry (types/<t>.md) in the same edit - a value with nolayout:line has nowhere to be moved to. -
Reclassify every candidate page in the same pass:
tools/wikitool touch --page "<Title>" --set <x>_type=<new-value> tools/wikitool move --reconcile -
Rebuild and check:
tools/wikitool index rebuild tools/wikitool migrate verify --from HEAD --fail-on-error tools/wikitool lint --fail-on-errormigrate verifyon a subtype sweep should report moved pages and zero findings - a<x>_typechange alone touches no wikilink, citation, footnote or H1.
-
-
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). -
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.mdfor the distinguishing rule (forsources, authorship decidesanalysisvs.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_typechange and asource_typechange 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.