Files changed: - AGENTS.md - CHANGES.md - VERSION - instructions/CONTRACT.md - instructions/capture-session.md - instructions/claude-code-model-selection.md - instructions/dev/issue-tracking.md - instructions/dev/testing-conventions.md - instructions/dev/version-parts.md - instructions/evolve-subtypes.md - instructions/gates.md - instructions/german-terminology.md - instructions/ingest-large-tree.md - instructions/kb-profiles.md - instructions/link-taxonomy.md - instructions/mcp-read-server.md - instructions/migrate-corpus.md - instructions/migrations/3.0.0-authoring-conventions.md - instructions/migrations/4.0.0-link-taxonomy.md - instructions/private-instance.md - instructions/session-setup.md - instructions/setup-instance.md - kb/CONTRACT.md - kb/CONVENTIONS.md - kb/concepts/COLLECTION.md - raw/CONTRACT.md - tools/CONTRACT.md - tools/chemenu/commands/docs_verify.py - tools/chemenu/commands/instructions_cmd.py - tools/chemenu/tests/test_docs_verify.py - tools/chemenu/tests/test_instructions_cmd.py - tools/chemenu/tests/test_toc.py - tools/chemenu/toc.py - types/type-spec.md
6.3 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: a schema default: that the compiler applied whenever nobody
disagreed, silently turning the least specific value into the collection point for everything
unclear.
Contents
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 eventually removed again unused. A smaller count is only ever an operator's explicit, named exception (trackersurvived that same cleanup at two pages, 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.