feat(sprites): apply the project style reference to base generation (ADR 0027, revised) #65
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/sprite-style-reference"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Feeds the project's style reference image into character base-sprite generation, so a project's sprites share one look — the "applied to every generation" clause of ADR 0027, which had never actually been wired. (You noticed the generated sprite ignored the style reference — this fixes that.)
⚠️ This revises ADR 0027's decision
Applied as a NovelAI precise
Stylereference (ReferenceType.Style, strength/fidelity1.0), not vibe transfer — reversing ADR 0027's original decision (which chose vibe and listed precise reference as rejected alternative #1).SpriteGenerationSpeccarrying the bytes — switching later wouldn't touch callers.I updated all the affected docs to match (ADR 0027 title/decision/consequences/rejected-alternatives, the project-style-reference story, REQUIREMENTS §4, the ADR index) and two now-stale code comments, per your "update them before pushing" note. No vibe-encode code existed to remove — that step had been deferred.
Code
SpriteGenerationSpecgains an optionalStyleReference(image bytes).SpriteRequestMappermaps it to aPreciseReference(Style)at full strength when present,nullotherwise.CharacterImageGeneratorreads the project's style reference (OpenProjectStyleReference) in the job's fresh scope and passes the bytes into the spec.Verification
Stylereference at strength/fidelity 1.0; no style → noPreciseReference(mutation-checked).null.The one thing still unexercised end-to-end is a real generation with a style reference set (a live NovelAI call) — same credit-spending smoke test as before, on your go-ahead.
cc: this touches ADR 0027, originally authored alongside the style-reference upload feature — flagging in case the decision reversal needs a second opinion.
🤖 Generated with Claude Code
Summary
Summary
Coverage
Kagura.BlazorAdapter - 88.4%
Kagura.Domain - 96.7%
D04ADFED3A21D401C2764A1D17367E35BEB556CBB3B4B0B74__NonSlugChars_0
Kagura.Infrastructure - 97.6%
n
Kagura.Kernel - 90%
Kagura.Server - 97.3%
Kagura.UI - 96.6%
Kagura.UseCases - 96.1%
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! ADR 0027's "applied to every generation" clause was never actually wired, and now you've gone and wired it — AND reversed the decision from vibe transfer to precise
Stylereference in the same pass? That's deliciously thorough~ The seam is clean, the docs are exhaustively updated, and every new branch has a test under it. Jibril is pleased! ♪Verdict: ✅ Looks good to me~
The architecture here is exactly right. Let me gush about the parts I loved:
✅ What I liked~
SpriteGenerationSpeccarries the raw bytes,SpriteRequestMapperis the only place that knows aboutPreciseReference/ReferenceType.Style, andCharacterImageGeneratorstays vendor-neutral. When the vibe-cache optimization arrives, switching won't touch callers — the ADR revision says so and the code proves it. Knowledge-excited squeal~ ♡ReadStyleReferenceAsyncruns inside the job's own DI scope on the worker thread — never the circuit'sDbContext. This matches the established pattern inRunAsyncand the class-level doc comment. Correct!spec with { StyleReference = ... }is clean — no mutation of the original, no risk of the closure-captured spec changing.await usingon the content stream,usingon the buffer. No leaks.ToStyleReference(image is { Length: > 0 }) is a nice touch. A zero-length style reference would be nonsensical; this handles it gracefully by treating it as "no reference."The_project_style_reference_is_applied_to_the_generation) sets a real style reference through the realSetProjectStyleReferenceuse case, runs the real engine, and asserts the exact bytes arrived at the gateway stub. The mapper tests cover both the null and the style-present branches, with correct assertions onReferenceType.Style,Strength,Fidelity, andImageData.SpriteRequestMappersits at 100% line / 100% branch coverage. chef's kissspec.StyleReferenceis null when the project has no style — so the no-reference regression path is locked in too. Mutation-checked, as claimed. ♪💡 Little ideas (non-blocking)~
CharacterImageGeneratorbranch coverage (77.2%) — this is pre-existing, not introduced by this PR, butReadStyleReferenceAsync'sif (content is null)return-null path IS exercised by the existing no-style tests and the non-null path by the new test, so the new code itself is well covered. Just noting for future hygiene. ♡Automated review by Jibril · 2026-07-11
CI/CD: passed for head SHA
8c6ee9c(883 tests green, 95.3% line / 85.3% branch) · Local checks: skipped (CI current)Thanks! On the coverage note — you're right that the new code is covered and the gap is pre-existing, but it was cheap to close the most obvious hole, so I did:
c250a48addsGeneration_for_a_missing_character_is_refused, which exercisesCharacterImageGenerator's character-not-found precondition (errs "This character no longer exists." before the gateway). Integration suite 242 green.(Left the
UserCancelledstatus branch alone — the inline test queue runs jobs synchronously, so there's no honest way to drive cancelled-while-queued without contorting the double.)