Adds everything validated in the latest round of testing:
- multiple detections of the same class share one identical template
- a full tag's text runs to the next newline, never implicitly split
- typo detection is per-tag (not per-model or all-or-nothing), verified
within a single multi-class model's own detections too
- no code-level cap on chain length; verified with 7 chained models
- 800-generation stress test: ~0.24ms/generation, ~0 net memory growth,
fully deterministic, zero log output when everything resolves cleanly
- no stale cross-generation state; removing a model from the chain
produces an accurate orphaned-tag warning, not a false positive
Brief aside in the fallback-pool section: the pre-existing left-to-right
sort option doesn't affect [CLASS=...]-tagged classes and only slightly
stabilizes the untagged fallback pool, so the existing guidance stands.
Pre-existing SD.Next feature, unrelated to this patch, that overlays
each detection with its class name and confidence score on a second
output image. Worth calling out here since it pairs directly with
[CLASS=name] tagging as a visual way to confirm labels without reading
logs.
Notes explicitly that the warning can't distinguish a misspelled
[CLASS=name] tag from a correctly-spelled one that simply found no
matching detection this generation - both produce identical warning
text. Also notes the practical upside either way: it reliably signals
"this class's prompt was not applied this run," which is useful on its
own even without knowing the cause.
Detailer.merge() (pre-existing, unrelated to this patch) collapses all
detections from a model pass into one box and keeps only the first
detection's label, order-dependent. Verified with the real merge() code:
tagging two classes on a model that can report both in one pass, with
"Merge detailers" enabled, silently drops one class's prompt and the
surviving one flips between runs. Conceptually incompatible with
per-class tagging, not something to "fix" here.
Clarifies that the fallback pool is filled positionally with no
understanding of a line's content, so relying on two or more untagged
lines to land on distinct classes reproduces the exact order-instability
problem [CLASS=name] tags exist to solve. Expected behavior, not a bug.
A blank spacer line between a [CLASS=...] line and a plain fallback
line (common when formatting the prompt for readability) was being
counted as an empty fallback entry, silently pushing the real fallback
text out of position and handing untagged detections an empty prompt.
Explains the problem, syntax, fallback/typo-warning behavior, and the
implementation, so it's readable directly on the branch instead of only
in an external write-up.
Previously each detailer model in the chain warned independently about
[CLASS=name] tags absent from its own detections, so a tag meant for a
different model in the same chain (e.g. [CLASS=pussy] when the current
pass is a face-only model) was flagged as if it were a typo.
Now prompt/negative are resolved once before the model loop (they don't
vary per model), and matched class names are accumulated across every
model's detections. Only tags that never matched anywhere in the whole
chain trigger a single warning at the end, so legitimate multi-model
class targeting stays silent while genuine typos are still caught.
Catches typos in class tags (e.g. [CLASS=hnad] vs an actual detected
label of "hand") by logging a warning listing which tags went unmatched
and which labels were actually detected in that pass, instead of
silently falling back to the positional prompt with no signal.
Detailer prompts previously mapped to multi-class YOLO detections purely
by line order/index, so results were unstable when detection order
varied between runs. Lines prefixed with [CLASS=name] (comma-separated
for multiple classes) now target detections by their YOLO label
directly; untagged lines remain the positional fallback for detections
with no matching class tag, preserving prior behavior when no tags are
used.