Skip to content

ADR-008: Consistency and likeness as switchable modes

Developers and the owner — read this before tuning quality, and before deciding which mode an event runs in.

  • CONSISTENCY_MODE=1 (default): one anchor portrait first, then all sheets in parallel referencing it. The 12 stickers match each other; the face can drift from the guest.
  • LIKENESS_MODE=classic: the selfie and a face crop are the only face source; no anchor. Closer to the guest; colours can drift between sheets.
  • LIKENESS_MODE=hybrid: classic, plus skin and hair colours pulled to the pack median by code.
  • Status: accepted as flags; the long-term default is an open decision — see Open decisions.

Two quality complaints pull in opposite directions.

  1. The stickers differ from each other: hair length, hair colour, skin tone, stubble and even clothing drifted between sheets, because each sheet was an independent sample with only the selfie as reference.
  2. The stickers are pretty but not very like the guest: with an anchor as the main reference the face is a copy of a copy. The model first interprets the selfie into a portrait, then twelve stickers copy that portrait.

Neither could be settled by argument, only by live runs, and live runs cost money. The practical answer was to keep each scheme behind a flag so the mode can be changed on the server in a minute.

Mode Face source Sheets Consistency mechanism Checks
Consistency (CONSISTENCY_MODE=1, LIKENESS_MODE empty) Anchor portrait (main) + selfie In parallel HARD LOCKS prompt block, skin normalisation to the anchor Anchor verified against the selfie; pack checked against the anchor
Classic (LIKENESS_MODE=classic) Selfie + face crop Sheet 1 first, the others reference it Prompt locks only Each sheet checked against the selfie; a failed figure is redrawn alone
Hybrid (LIKENESS_MODE=hybrid) Selfie + face crop As classic COLOR LOCK in prompts; skin and hair pulled to the pack median in code; despill Pack checked against the selfie
  • LIKENESS_MODE takes precedence over CONSISTENCY_MODE.
  • Shared by all modes: sheet layout, cutting, edge rules, regeneration limits, cost accounting and the cost cap.
  • Skin normalisation shifts the whole face region and is capped (SKIN_NORM_MAX_DE), after patches appeared on very light skin.
  • Decisions about “passed or failed” are made in code from the vision model’s structured answer, not by the model.

Implementation: bot/services/consistency.py, likeness.py, skin_tone.py, appearance.py.

Alternative Why not
A face-segmentation or face-embedding library No wheels for the local Python version, heavy weights and dependency; colour targets are measured from the face box instead.
Pull colours to the selfie itself Station lighting overexposes the photo; the pack would turn pale. Hybrid uses the pack median and lets the selfie nudge it by a small, capped amount.
One mode only The trade-off between sameness and likeness is not resolved yet.
  • Consistency raised the cost of a pack from about $0.25 to about $0.41 and, together with parallel sheets and faster cutting, lowered the time from about 99 s to about 60 s (COST_HISTORY.md, “Cost and time of a pack by stage”).
  • Three code paths must be kept working; each has its own tests with mocked AI.
  • The mode a production server runs in is a line in its .env, not something the repository records. Check the STARTUP likeness=… log line.
  • Classic and hybrid have been validated on few faces; a wider live comparison is still owed.
  • HANDOFF.md: sections on CONSISTENCY_MODE, LIKENESS_MODE=classic, LIKENESS_MODE=hybrid, skin patches.
  • Commits 756f489, edbbf06, 8d3b61b, ecb43e4, 5dbf8ae.

Last verified: 2026-11-13 against ai-sticker-pack@b715418 and ai-stickers-landing@e350ff5.