Real-library audit (270 records) traced the data damage to:
- identity matching on ANY shared token ("Zwerg", "der Zwerg", "Mann") with
"longer text wins" merging (Arthag b02 = Kolon's species/relationships), and
- csRosterCanonicalName renaming a sheet to the first cast name among its
aliases, which saved 16 whole-sheet copies (Zwerg/Kolon = Arthag b03,
Fremder = Mann, Alchimist = Promos ...).
Fixes:
- static/js/character-identity.js + core/character_records.py: generic labels
are never identity evidence; csFindMergeKey, csConsolidateAliasDuplicates,
csRosterCanonicalName, clSameIdentity use it; own name always wins; clUpsert
writes to the exact-name record before any alias scan; no seed rename onto a
name that has its own record.
- _charsheets_parse: in cast-target mode drop other cast members' names from
aliases / first / last name (Kolon: "Sharraz Garthai"), strip reasoning
leakage ("Warte:", "Der Text sagt ...") from every text field.
- _character_scene_evidence: only a quote naming the character is used,
otherwise its own mannerisms (16 panels showed another character's scene).
- _character_age_category: Junge/Mädchen/boy/girl, number words, Sommer/
Winter ages, evidence clause, age-tagged quotes; "15 Jahre älter" is no age.
- scripts/audit_character_records.py (read-only) and
scripts/clean_character_records.py (dry run by default, --apply backs up).
Tests: tests/test_character_record_hygiene.py, tests/character-identity.test.mjs.
Docs: architecture/character-extraction.md, Manual, CHANGELOG.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Portrait backdrop measured 0/4 -> 4/4 plain on the failing character, no
change on the one that already passed. After the portrait passes, the vision
model describes hair, facial hair and eyes, and the turnaround and story
prompts are rebuilt with it -- a character with no hair in his sheet got a
different haircut on the sheet and failed the same-person check 3/3.
Costume cut and colours restored for armed characters. v1.41.0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Measured with the image check: full-body turnarounds 0/5 -> 10/10 (Karyla),
12/12 on Karyla, Darrag and Eolan after the face fixes. The 4-step model
loses the tail of a ~3000-char prompt. Scars are left out of image prompts:
any scar wording, even "fully healed", rendered as fresh gashes. v1.40.0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The job checks the portrait crop, then the turnaround, story panel and
same-person against the sheet, re-renders on failure (up to 3 attempts) and
keeps the attempt with the fewest faults. ReActor transfers the profile's face
onto the turnaround and the largest face in the story panel. If the checker is
down, retries stop and the pair is marked unverified. The outcome is saved
with the pair and shown on the character page.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The model only reports observations; expectations come from the sheet and the
comparison is in code. Fail-safe: an unreachable checker or unreadable answer
is a failure. Calibrated 14/14 on panels with known defects using the already
loaded LLM; Ling 3.0 Flash VL (free) scored 8/14 with 6 unreadable answers.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- fix: base-appearance matched pair lost its concept image + metadata on reload; visual save
wrote base concept art to the record root; one save path for base and forms now
- fix: extraction no longer lets the LLM author image_prompt (source of avatar/concept drift);
avatar-only generation uses the deterministic prompt and flags an existing pair
- fix: prompt writes and Physical/Clothing edits go to the active form; review endpoint checks
each form's own pair; fingerprint parity with the browser incl. visual_* overrides
- feat: appearance forms panel (add/rename/delete/show, per-form stale flag, generate one/all)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>