feat(ccip): automation + reference quality — keep identity flowing hands-free (#114)
CI / lint (push) Successful in 2s
CI / frontend-build (push) Successful in 19s
CI / backend-lint-and-test (push) Successful in 26s
CI / integration (push) Successful in 3m32s

Works through the optional CCIP ideas + the "keep moving even if I forget" ask:

AUTOMATION (no button needed):
- Hourly beat auto-enqueues CCIP backfill — new images get embedded (and errored
  ones retried) on their own; the queue never goes idle waiting for a click.
- CCIP auto-apply: a daily sweep tags confident matches (source='ccip_auto') so
  identity tags keep flowing. ON by default (opt-out, like head auto-apply);
  ml_settings.ccip_auto_apply_enabled + _threshold (0.92, above the suggest cut),
  migration 0064. Vectorized (one matmul + reduceat per image), reversible, skips
  already-applied/rejected. Switch + threshold in the GPU agent card; GET/PATCH
  /api/ml/settings; auto_applied count in /api/ccip/overview.

REFERENCE QUALITY (the over-fire root cause):
- character_references now draws ONLY from single-character images — on a
  multi-character image the tag is image-level, so every figure would otherwise
  pollute each character's prototypes (a 2-char image tagged 'Velma' made
  Daphne's figure a Velma reference). This is the contamination behind residual
  over-firing.
- Cached on a cheap signature (char-tag count + ccip-region count/max-id) so the
  reference load isn't redone on every modal open.

Tests: multi-character image not used as a reference; auto-apply tags a confident
match as ccip_auto.

NEXT (not done, confirmed): comic-panel cropping + SigLIP concept crops ("spot
interesting content").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ttrj5P7upUTueSfoJcxEqa
This commit is contained in:
2026-06-29 22:25:40 -04:00
parent 74b7ceaf47
commit b91a230f12
9 changed files with 324 additions and 3 deletions
@@ -76,6 +76,26 @@
stricter — fewer but more confident matches. 0.85 recommended; below ~0.80
a heavily-tagged character starts matching everything.
</p>
<!-- Auto-apply -->
<div v-if="ml.settings" class="d-flex align-center mt-5" style="gap:12px">
<v-switch
v-model="autoApply" color="accent" hide-details density="compact"
:loading="savingAuto" label="Auto-apply confident matches"
@update:model-value="onSaveAuto"
/>
<v-text-field
v-model.number="autoThreshold" type="number" min="0.80" max="0.99"
step="0.01" density="compact" hide-details variant="outlined"
style="max-width:96px" :disabled="!autoApply" label="at"
@change="onSaveAuto"
/>
</div>
<p class="fc-muted text-caption mt-1 mb-0">
When on, a very-confident character match tags the image on its own (daily,
reversible) — so identity tags keep flowing without review. Stricter than
the suggest cut; 0.92 recommended.
</p>
</MaintenanceTile>
</template>
@@ -97,6 +117,9 @@ const rotating = ref(false)
const backfilling = ref(false)
const threshold = ref(0.85)
const savingThreshold = ref(false)
const autoApply = ref(true)
const autoThreshold = ref(0.92)
const savingAuto = ref(false)
const queue = ref({ pending: 0, leased: 0, done: 0, error: 0 })
let pollTimer = null
@@ -119,8 +142,27 @@ onMounted(async () => {
if (ml.settings?.ccip_match_threshold != null) {
threshold.value = ml.settings.ccip_match_threshold
}
if (ml.settings?.ccip_auto_apply_enabled != null) {
autoApply.value = ml.settings.ccip_auto_apply_enabled
autoThreshold.value = ml.settings.ccip_auto_apply_threshold
}
} catch { /* non-fatal */ }
})
async function onSaveAuto() {
savingAuto.value = true
try {
await ml.patchSettings({
ccip_auto_apply_enabled: autoApply.value,
ccip_auto_apply_threshold: autoThreshold.value,
})
toast({ text: 'Auto-apply settings saved', type: 'success' })
} catch (e) {
toast({ text: `Could not save: ${e.message}`, type: 'error' })
} finally {
savingAuto.value = false
}
}
onUnmounted(() => { if (pollTimer) clearInterval(pollTimer) })
async function onSaveThreshold() {