Files
07b0f9a18b feat(knowledge-base): define KB file format, entry rules, and categories (#8) (#51)
Formalize the Knowledge Base on-disk format and tighten the entry schema per
MASTER_SPEC §15.3-§15.10, §18.2.

- compiler/common/categories.py: single source of truth for the 19 canonical
  categories (lowercase identifiers of the §18.2 list) plus is_valid_category.
- knowledge_base_entry.schema.json (v1.1): category restricted to the 19; tags
  require at least one item; expand entries must be snake_case canonical ids;
  aliases uniqueItems.
- knowledge_base/README.md: by-domain file layout, the "each file is a JSON array
  of entries" format, and contributor field rules (id/alias global uniqueness,
  tag order, expansion targets, one-tag minimum).
- examples/knowledge_base.example.json: worked file demonstrating an alias and an
  expansion.

Cross-entry rules (global uniqueness, expand targets exist) are deferred to the
KB validation tooling (#9); this issue defines per-entry structure only.

Tests: 19-category constant and schema-enum consistency, entry validation
(category/tags/id/expand/unknown-field), and the worked example (array shape,
per-entry validity, alias+expansion present, expand targets resolve).

Co-authored-by: kunail0804 <kunail0804@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 19:23:50 +02:00

45 lines
1.3 KiB
Python

"""The 19 canonical compiler categories (MASTER_SPEC §18.2, Appendix C.1).
Categories are defined by the compiler, not by the Knowledge Base (§15.5). This
module is their single source of truth: the Knowledge Base entry schema, the
Knowledge Base validation tooling, and the Category Splitter all draw the valid
category set from here so they cannot drift apart.
The §18.2 list is authoritative and uses Title-Case display names; we use the
lowercase identifier form here for machine use (Category Map keys and
``ResolvedTag.category``). The two forms correspond one-to-one, in order.
"""
from __future__ import annotations
# Ordered lowercase identifiers for the 19 categories of §18.2. Order is the
# authoritative spec order and is significant (e.g. category ordering downstream).
CANONICAL_CATEGORIES: tuple[str, ...] = (
"character",
"appearance",
"hair",
"face",
"eyes",
"expression",
"body",
"clothing",
"accessories",
"pose",
"action",
"interaction",
"objects",
"environment",
"camera",
"lighting",
"style",
"quality",
"miscellaneous",
)
_CATEGORY_SET = frozenset(CANONICAL_CATEGORIES)
def is_valid_category(category: str) -> bool:
"""Return True when ``category`` is one of the 19 canonical categories."""
return category in _CATEGORY_SET