6 Commits
Author SHA1 Message Date
f356e13bef fix(analyzer): preserve relations, positions, and conjunctions (bug 3) (#146)
The Analyzer collapsed relational phrasing to the bare noun ("a bunch of money
in her hand" -> just "money", losing the held relationship) and could drop the
later half of "X and Y" enumerations, especially on NSFW input. The reference
Knowledge Base already covers the relational tags (holding money, hand on own
hip, in mouth, 400+ holding_* tags), so the loss was entirely at the analysis
step.

- System prompt: add "Relations, positions, and holding", "Conjunctions and
  enumerations", and "Completeness (including explicit content)" sections, and
  cross-reference them from "Objects". Held/worn/positioned objects now also
  yield the relational concept (holding <object>); every conjunct survives;
  explicit content gets the same full fidelity.
- Regression tests: relational (holding money, hand on own hip) and conjunction
  (holding sword + holding shield) cases prove the reference KB resolves these
  concepts end to end, so the improved Analyzer output compiles.

Co-authored-by: kunail0804 <kunail0804@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 16:28:30 +02:00
af775d48c0 feat(fidelity): preserve dropped modifiers + full list transcription (#86) (#137)
Closes #111, #112, #113.

- Resolver recovers leading modifiers dropped by the head-noun reduction as
  <modifier> <head-noun> compounds (open white shirt -> white shirt + open
  shirt). KB-only, deterministic, no bare-word invention; goldens unchanged.
- Analyzer system prompt instructs full list transcription; a deterministic
  post-parse check warns SC0021 when a tag-list yields fewer concepts than items.
- Data-driven fidelity regression suite locks both failure modes.

Co-authored-by: kunail0804 <kunail0804@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 15:59:00 +02:00
5e146d5a55 feat!: v1.1 — Resolver emits a flat prompt, drop categories (#85)
* feat!: collapse pipeline — Resolver emits a flat prompt, drop categories (v1.1)

BREAKING CHANGE: the Category Splitter and Prompt Builder stages and nodes are
removed. The Resolver is now the translator from Scene JSON to prompt: it resolves
concepts to Knowledge Base tags and joins them into one flat comma-separated
prompt string, in resolution order (which naturally leads with character concepts).

Resolver node outputs are now (prompt, warnings, errors, json) — the json being
the traceable resolved tags so a translation problem is inspectable. Node count
drops from 8 to 6. The CategoryMap/PromptOutput models and their schemas are
removed; the `category` field remains on entries and resolved tags for
traceability only. Debug Viewer simplified to scene/warnings/errors.

Goldens, example scenes/workflow, integration/performance/repo-layout/release
tests, benchmark script, and the docs (README + wiki) are updated to the flat
prompt. Version bumped to 1.1.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* build: drop removed splitter/builder packages from pyproject

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: kunail0804 <kunail0804@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 00:00:48 +02:00
54b76ca75a fix(compiler): recover lost scene detail via 16.4k Danbooru KB + harden analyzer (#79)
* fix: recover concept detail lost in resolver and harden analyzer parsing

Three shippability fixes for the v1 pipeline:

P2 (main): the Illustrious Resolver did exact-key KB lookup only, so any
compound concept the analyzer emits ("white summer dress", "black business
suit") missed and was dropped silently as SC0001. Add a deterministic
head-noun fallback (§17.2): on a miss, drop leading modifiers and look up the
longest remaining suffix ("white summer dress" -> "dress"). No tag/concept is
invented. Emits SC0019 (Concept Reduced) so the reduction is visible.

P1a: the analyzer required the entire model response to be a single JSON
document, so any surrounding prose ("Sure! Here is the scene:") failed parsing
and, with the prompt reused unchanged, every retry failed identically ->
empty output. Extract the first balanced top-level {...} object from
surrounding text (string-aware brace scan); the object bytes are unchanged and
must still validate, so this is unwrapping, not JSON repair.

P1b: the node's "raw" output was to_raw_json(result.data) -- a re-serialization
of the parsed Scene, so on failure it was empty and the model's actual text was
invisible. Capture the last raw model text in analyzer metadata and surface it
as the node's raw output.

Regenerated goldens: unknown_concepts "hologram jacket" now resolves to
"jacket" via head-noun fallback (intended).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: add entry rating + resolver.include_nsfw gating

Foundations for the Danbooru-vocab KB: a per-entry `rating` (general|explicit,
default general) and a `resolver.include_nsfw` config flag (default false). The
resolver omits explicit-rated entries from lookup and expansion unless enabled,
so a gated concept is reported as unknown (SC0001). Schema, model, config, and
example config updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: generate KB from embedded Danbooru vocab (188 -> 16.4k tags)

Replace the coverage ceiling of the 188-entry hand KB by importing a large,
validated Danbooru tag vocabulary. This is the fix for the core "detail loss"
symptom: compound concepts the analyzer emits ("red dress", "sunflower field",
"train station platform") are now real tags that resolve instead of being
dropped.

- scripts/build_vocab.py: one-time dev step that filters the Raffle node's
  categorized tag dump (drops artist/character/copyright/attribution categories
  and subjective adjectives, keeps only id-pattern-valid tags) into a committed,
  self-contained snapshot at data/danbooru_vocab.txt (16.4k tags).
- scripts/generate_kb_from_vocab.py: additive, non-destructive generator. Writes
  knowledge_base/gen_<category>.json, mapping the Raffle categories to the 19
  canonical categories and tagging NSFW categories rating=explicit. Skips any tag
  already defined as a hand-curated id/alias, so the curated canonicalization
  (female + aliases) and expansions (school_uniform -> blazer, pleated_skirt) are
  preserved and always win.

Result: 16.4k additive entries + 188 curated. Plain natural-language concepts
now resolve broadly via curated aliases + head-noun fallback with no analyzer
prompt change; NSFW gated behind resolver.include_nsfw; golden and dataset tests
stay green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* style: ruff format build_vocab.py

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(security): drop untrusted CLI path in build_vocab (SonarCloud S8707)

The --source CLI argument fed an untrusted path to the file system (taint).
The script is a one-time dev step; hard-code the source path constant instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: kunail0804 <kunail0804@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 19:45:32 +02:00
584cffb1c5 test(regression): add golden tests and reference dataset (#28) (#72)
Add golden tests for the ten reference scenes (MASTER_SPEC §26.7, §26.8),
guarding determinism across changes.

- tests/regression/golden_scenes.py: the ten reference scenes (single character,
  two characters, interaction, indoor, outdoor, fantasy, modern, unknown
  concepts, ambiguous concepts, complex multi-character) plus the shared no-LLM
  pipeline runner.
- tests/regression/golden/*.json: the golden prompt outputs for each scene.
- scripts/regenerate_goldens.py: the deliberate, documented way to regenerate the
  goldens when a change is intended to alter output (never automatic).
- tests/regression/test_golden.py: asserts exact equality against the goldens and
  determinism across repeated runs.
- tests/regression/golden/README.md: documents regeneration and the regression
  convention (every fixed bug adds a permanent test that is never removed).

Co-authored-by: kunail0804 <kunail0804@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 13:45:35 +02:00
72a60aa28b chore: initialize repository structure and tooling (#1) (#45)
Scaffold the Phase 0 foundation per MASTER_SPEC §24:

- Directory layout: nodes/, compiler/{analyzer,validator,resolver,splitter,
  builder,common}/, knowledge_base/, schemas/, prompts/, config/,
  tests/{analyzer,resolver,validator,integration,regression}/, examples/,
  scripts/, docs/.
- pyproject.toml targeting Python 3.11+, jsonschema as the single runtime dep,
  ruff + pytest as dev deps, explicit package list, and ruff/pytest config.
- ruff for linting and formatting; pytest with repo root on pythonpath.
- GitHub Actions CI running install, ruff lint, ruff format check, and pytest
  on Python 3.11 and 3.12 for pushes and pull requests.
- docs/ skeleton and CONTRIBUTING.md referencing the wiki.
- Layout test asserting the §24 structure and package importability.

Co-authored-by: kunail0804 <kunail0804@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 16:59:32 +02:00