Add compiler/resolver/illustrious_resolver.py: resolve_scene(scene,
knowledge_base, config, logger=None) -> CompilerResult, per MASTER_SPEC §17. No
LLM; no concept or tag is invented.
- normalize_concept (§17.3): NFKC + lowercase, unifying underscores/spaces so
natural concepts, snake_case ids, and spaced aliases share one lookup key. The
resolver builds its own normalized index over the Knowledge Base.
- Per-concept pipeline in scene discovery order (§17.8): normalize -> direct
alias resolution (no chains; skipped when allow_aliases is false) -> canonical
lookup -> recursive expansion -> tag generation.
- Expansion (§17.5): own tags first, then depth-first in list order per expand
target, inserted immediately after; capped by max_expansion_depth; skipped when
expansion_enabled is false; defensive path-based cycle detection -> SC0003.
- Deduplication after expansion keeps the first occurrence (SC0007).
- Unknown concept -> SC0001 warning (continue); deprecated -> SC0006 (continue);
invalid category -> SC0008 (stop); circular expansion -> SC0003 (stop).
- Every ResolvedTag keeps its entry's category and full traceability
(source_concept = originating scene concept, knowledge_base_entry = generating
entry). Verbose logging of each decision.
Tests (no Ollama): normalization, alias resolution + disable, expansion order,
nested/depth-capped/disabled expansion, traceability, dedup, unknown/deprecated,
circular/invalid-category stops, category preservation, and determinism.
Co-authored-by: kunail0804 <kunail0804@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>