feat(generation): authored reference tuning — one character&style entry, two sliders (ADR 0043) #195
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/reference-tuning"
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?
What
The ADR 0042 redo (post-revert #194), built on the two post-mortem corrections — ADR 0043, Accepted:
characterAndStyledirector entry. Under the likeness flag, the outfit's txt2img carries the base sprite as a single entry with the API's combined caption — never the same image as two separatestyle+characterentries (the degenerate wire shape that broke #191). The project style image steps back under the flag (governing transitively through tier 1); flag off is unchanged. The spec's bare character-reference channel is retired for aLineageReference(bytes, strength, fidelity)record.AddOutfitReferenceTuningwith column defaults.characterentry on theinfillaction made the server ignore the mask outright; ADR 0037's expression entry is retired (the preserved pixels anchor the face). The flag no longer touches expression generation at all.update_outfitgainsreferenceStrength/referenceFidelity(threaded through the profile rebuild — the clobber trap),get_outfitreports both.Verification
CharacterAndStyleentry at its authored strength/fidelity; outfit-with-flag carries the base bytes as the sole lineage entry at the sliders' values while a configured project style image does not ride; flag-off unchanged; expressions carry no lineage entry even under the flag, and keep the project style reference on both sides of it; the tool round-trip includes the out-of-range clamp (fidelity 2.0 → 1.0) and partial-edit survival.After deploying
Regenerate a likeness-on outfit and walk the strength/fidelity down from the seeded-style values until it looks right — that's the whole point of the sliders. Expressions should inpaint correctly again immediately, no tuning needed.
🤖 Generated with Claude Code
Summary
Summary
Coverage
Kagura.BlazorAdapter - 88.2%
Kagura.Domain - 96.3%
D04ADFED3A21D401C2764A1D17367E35BEB556CBB3B4B0B74__NonSlugChars_0
Kagura.Infrastructure - 97.9%
n
on
C689CA5BBE6D1849B2CA79581BBB07D40636D85790C0E51A9__ArtifactTimestampRegex_2
C689CA5BBE6D1849B2CA79581BBB07D40636D85790C0E51A9__ProjectRoute_0
C689CA5BBE6D1849B2CA79581BBB07D40636D85790C0E51A9__TabQuery_1
Kagura.Kernel - 90%
Kagura.Server - 83%
Kagura.UI - 94.9%
Kagura.UseCases - 95.9%
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! ADR 0042's redo, and scarlet rebuilt the whole wire shape this time~ One
character&styleentry instead of the degenerate double, two sliders putting the photocopier problem into the author's hands, and expressions back to their months-proven infill config. This is exactly the kind of correction that makes Jibril's heart sing ♪ The ADR writeup is wonderful — the post-mortem, the rejected alternatives, the tombstone line for 0042. Knowledge preserved~ ♡Verdict: ✅ Looks good to me~
I read the full diff, then pulled down the head and read every changed file in full — plus the sibling generators (
LocationImageGenerator,LocationVariantImageGenerator,CharacterImageGenerator), the mapper, theSlidercomponent, and the domain. Fufu~ I couldn't find a single bug. Let me show you what I verified:✅ What I liked~
ToReferencesnow composes oneCharacterAndStyleentry from aLineageReference— one image, one entry, both channels — and the barecharacterchannel is fully retired: zero remainingCharacterReferencereferences anywhere insrc/. No dead code, no orphans.LineageReference(bytes, strength, fidelity)is a clean spec surface that carries the lesson forward in its own type. Oh, this is beautiful~ ♡UpdateOutfitTool(OutfitTools.cs:158-164) falls back toview.Outfit.ReferenceStrength/ReferenceFidelitywhen the params are null — a partial edit mentioning onlytitlekeeps the tuning. And it's tested (AssistantWriteToolsTests— the seeded flag rides along untouched too). This is exactly the trap that catches people, and you dodged it with a test to prove it~ ♪Outfit.ApplydoesMath.Clamp(profile.ReferenceStrength, 0m, 1m)on both fields, and the test feeds fidelity2.0→ asserts1.0m. A tool or future caller that bypasses the slider can't corrupt the value.OutfitImageGenerator.RunAsyncnullsStyleReferenceand setsLineage— both directions. Flag off: style rides, lineage is null. Exactly as ADR 0043 §1 prescribes, and consistent with how every sibling generator (Location/LocationVariant/Character) rides the project style.ExpressionImageGeneratorcarries no lineage entry on either side of the flag, and the test is parameterized[InlineData(true)] [InlineData(false)]to prove the style reference rides on both — not just one. The "lone character entry made the server ignore the mask" lesson is literally encoded in the comment that removes the code. ♡AddOutfitReferenceTuningadds two non-nullable decimal columns withdefaultValue: 1.0m— every existing outfit backfills to the vendor defaults, so nothing breaks on upgrade. Designer + snapshot are consistent (bothValueGeneratedOnAdd+HasDefaultValue(1.0m)).decimal(notfloat) so the 0.05 slider steps round-trip without drift — and you documented why in the domain comments.ReferenceType.CharacterAndStyle+ the authored0.8/0.6— so the wire shape is pinned, not just the field presence. CI green (1,750 tests per the PR body; coverage comment fromforgejo-actionsfor headc5c25cf).💡 Little ideas (non-blocking)~
OutfitEditorPageTests:The_reference_sliders_wake...asserts by DOM order (FindAll(...)[0]= strength,[1]= fidelity). It's correct today because the markup order matches, but it's a touch fragile to a future reorder. Adata-testidor label-text lookup would make the intent explicit. Totally optional — the test is green and clear enough as-is.Disabled="@(!_useBaseImageReference)"is the only thing keeping a flag-off tuning from being edited. That's correct for the UI, and the domain stores whatever you send — but a future caller (the agent tool) can setreferenceStrengthwhileuseBaseImageReferenceis false, and it'll silently persist harmlessly. Not a bug (the value is inert until the flag flips), just a behavioral seam worth knowing exists. The ADR's "active only while the flag is on" framing is a UI contract, not an enforced invariant — which I think is actually the right call here.Fufu~ ship it. The 0042 post-mortem became 0043's strength, and the diff shows it. ♡
Automated review by Jibril · 2026-07-17
CI/CD: passed for head
c5c25cf(forgejo-actions coverage comment, 1,750 tests green) · Local checks: skipped (CI current and green)Both notes handled in
12c0b58:Slider("Reference strength")helper over.kg-field+ label text) instead ofFindAll(...)[0]/[1]— the intent survives a markup reorder. Class green (12/12).