The registry validator's security lint flags E702 (multiple statements per
line) as a warning today and an error soon; expand them now so future
publishes stay clean. Pure reformatting - no behavior change.
Researched how Krea 2's 12-layer text conditioning is designed, from
authoritative sources, so the tables can be improved against the real design:
- Krea 2 Technical Report: the 12 taps are a learned "shallow attention layer
that aggregates hidden features across layers" for "coarse-to-fine text
representations," explicitly inspired by UniFusion.
- UniFusion (the method): Layerwise Attention Pooling over "every third layer"
(matches hidden_states[2,5,8,...,35]); empirically favors EARLY-TO-MIDDLE
layers, with the penultimate contributing LEAST.
- This is misaligned with the shipped tables, which spike the deep taps:
the table's biggest spike (tap 8/layer 26) is only the model's #5, it
suppresses tap 4/layer 14 (the model's #3 and a UniFusion-favored layer),
and over-weights tap 11/layer 35 (penultimate, ranked nearly last). The
model's own learned projector (Stage 0) corroborates.
README section 3.5 adds the sourced design basis and three improvement
directions (track the learned weighting, differentiate recipes along the
coarse-to-fine axis, and add per-tap magnitude normalization so early-layer
gains actually bite). Full research + per-tap comparison in local_records.
Ran a render-based derivation for the style role on the model: held the real
style settings fixed, varied only the 12 layers across seven candidates,
rendered and scored look-transfer minus subject-leak.
- The shipped STYLE table scored best (objective 0.106); the shallow-tap table
was worst - render evidence supports spiking the effective deep taps.
- But differences were small and every output was nearly the same bowl: at
realistic style settings the layer table is a second-order knob. The primary
look-vs-subject control is strength and the shape/global split.
Bottom line committed to the README: the reliable way to set the layers is
render-based measurement (conditioning analysis alone misleads); applying it
shows the shipped tables are directionally right and, for the style role,
near-optimal. The durable deliverable is the render harness, which can
re-derive or verify the layers for any future checkpoint. Full result + images
in local_records.
Ran the decisive test on the model: isolate specific taps (shape=1, global=0),
render, measure. Result flipped the conditioning-level read:
- Mechanism confirmed live (feature width 30720 = 12x2560, split engages).
- Clean-stimuli Stage 1 does show proportional selectivity (shallow taps lean
palette, middle lean texture) - but render validation shows it is
practically irrelevant: the deep taps' large magnitude dominates the pixel
effect. Spiking taps 7/8/10 reproduced the reference entirely; spiking the
shallow taps did nothing.
- So the shipped tables spiking 7/8/10 target the effective (high-leverage)
taps, which the model's projector also emphasizes; the effective taps move
palette+texture+subject together and do not cleanly separate.
The load-bearing lesson for reliable derivation: conditioning-level analysis
misleads because magnitude and the nonlinear diffusion path dominate - the
layers can only be derived reliably from renders. README Stage 1/2 updated;
full arc + validation images in local_records.
Installed V10 + the probe node on the render box, generated a controlled
reference set, and ran the encode-only selectivity harness on the real Krea 2
model. First actual measurement of the 12 text-layer taps:
- Mechanism confirmed live: probe reports feature width 30720 (= 12 x 2560),
divisible by 12, so the tap split engages on the model (no fallback). Tap
magnitude rises with depth.
- No strong per-tap specialization: after removing the depth-magnitude
confound, every tap carries essentially the same attribute mix (palette
0.20 / structure 0.33 / texture 0.35 / lighting 0.12; cross-tap std-dev
~0.01). Taps differ by overall magnitude (depth), not by which attribute
they encode - only a faint depth gradient in the design direction, far too
weak to justify the tables' 5x spikes. The "tap 8 = palette" premise is not
supported.
Caveats recorded honestly (seq-mean signature, weak palette axis from a
near-neutral base, single scene). README Stage 1 updated with the result;
raw signatures + full write-up in local_records. Also fixes the probe graph
generator to supply the V10 card's full widget set (API validation).
Replaces "borrow a template + eyeball renders" with a staged pipeline for
setting the 12 layer-gain values, cheapest/most-targeted first:
- Stage 0 (done, local): extract_model_prior.py reads Krea 2's own learned
per-tap weighting (txtfusion.projector [1,12]) from the checkpoint;
compare_to_model_prior.py scores each shipped table against it. Finding:
the model leans hardest on taps 7>9>4>10>8 but the tables spike 8>10>7
(rank-corr only +0.58..+0.64) - the borrowed template does not track how
the model uses the taps. model_prior.json records the values.
- Stage 1 (harness ready, no render): probe_node/ is a tiny ComfyUI node
that saves per-tap conditioning signatures; probe_selectivity.py does a
variance decomposition (eta^2) of each tap against palette/structure/
texture/lighting over a controlled reference set; generate_probe_graphs.py
builds the encode-only graphs. The selectivity math passes a synthetic
self-test (recovers an injected tap->attribute map exactly). Running it for
real needs V10 + the probe node installed on a box, plus controlled image
sets - it renders nothing (text-encoder passes only).
- Stages 2-3 (documented, need a V10 box): metric-scored render validation,
then black-box optimization of the 12-gain vector against a stated
objective, held-out validated.
README section 4 rewritten as the methodology. All scripts run/validate
locally; tooling stays under docs/ (excluded from registry packs).
Traced the real provenance (Kevin's Codex dev sessions) and verified the
mechanism against the Krea 2 model on the render box. Two earlier claims
(07d2f0b) were wrong and are now fixed across the docs:
1. Mechanism: the 12 "deepstack chunks" are the 12 TEXT-encoder layer taps
Krea 2 conditions on (comfy/text_encoders/krea2.py: hidden_states
[2,5,8,...,35], (B,12,seq,2560) flattened to 30720), NOT the 3 vision
deepstack taps (qwen3vl.py deepstack_visual_indexes=[5,11,17]) the name
implies. 30720 % 12 == 0, so the node's split lands on the taps and the
per-layer gains do apply (no fallback) - confirmed from the model weights
(txtfusion.projector [1,12], layerwise blocks at 2560).
2. Provenance: the 12 values were NOT derived by a per-chunk sweep. They
were adopted from the third-party ComfyUI-ConditioningKrea2Rebalance node
(DEFAULT_WEIGHTS spike 8>10>7, matching STYLE_LAYER_PULL) plus the
shallow=structure/deep=appearance principle; only the scalar shape (0.45
->0.35) and cap (->0.9) were empirically tuned. The four role tables are
scalings of one template, so their agreement is design self-consistency,
not independent measurement - the "convergent evidence" framing is
withdrawn.
docs/deepstack-layers/ rewritten to separate verified mechanism, traced
provenance, and the still-unrun single-tap sweep. Corrections propagated to
the V9 technical paper (5.2 + architecture note + glossary), the V10 guide
and companion, custom_recipes/README, the V10 node doc, and CHANGELOG. Full
evidence chain preserved in local_records (gitignored).
SaveImage prefix now targets output/claude-generations/krea-deepstack-sweep/
on the render box, per Kevin's instruction that generated images go to a
dedicated folder and nothing else is opened. The tool only downloads back
the images it just generated.
New docs/deepstack-layers/ is the authoritative, reproducible account of
the 12 layers values, at three separated confidence levels:
1. Structure (verified from code): the values are gains on 12 equal
deepstack chunks - features from 12 successive Qwen3-VL encoder-depth
bands. Shown in kg_krea_v9/clip_hooks.py (the deepstack feature list)
and conditioning.py (the 12-way width split).
2. Semantics (convergent evidence): analyze_tables.py reads the live
tables and shows the four independently-tuned appearance tables
(style/palette/material/lighting) agree chunk-for-chunk - 0-4 carry
structure (monotonic depth ramp, all suppress), 5-6 transition, 7/8/10
carry appearance (all spike, chunk 8 strongest, then 10, then 7). Four
tables tuned for four different jobs converging is the measurement
encoded as data, not an assertion.
3. Precise response curve (fresh measurement): generate_sweep.py is a
turnkey single-chunk-spike sweep (the paper's section 16.4 method),
emitting each spike as a V10 custom recipe validated against the real
node code. Dry-run works anywhere; rendering needs the V10 nodes on a
ComfyUI box (single-chunk tables are not V9-expressible), so the
measured-verdict table is staged pending a V10-equipped render box.
SCORING.md defines the rubric.
Cross-linked from technical paper 5.2, the recipe guide, and
custom_recipes/README. Tooling lives under docs/ (excluded from registry
packs by .comfyignore). sweep_out/ is gitignored.