Support reviewed native Krea source profile

Bind the exact older sampler and model-base pair after reviewing its no-op
writable-model scope difference for Krea. Reject mixed revisions, writable
instance overrides and additional multigpu models.

Admit the installed Krea2T revision with unchanged math and extra registrations.
Verify observed loaded call-path code and enhancer constants against admitted
source instead of relying on file hashes alone. Keep native node ports, task
recipes, inference identity/revision limits and existing defaults unchanged.

Validation: 170 host-free tests, required compile, saved-source native control,
enhancer invocation and loaded-code counterexamples. Real runtime/model and
application end-to-end acceptance remain separate.
This commit is contained in:
Kevin Gilper
2026-10-25 20:55:12 -04:00
parent 1253bb629e
commit 0e49792afd
6 changed files with 241 additions and 10 deletions
+28 -1
View File
@@ -148,7 +148,12 @@ The supported source reference is the surviving
The original repository URL currently returns404. The integration verifies the
installed `ComfyUI-Krea2T-Enhancer` class source Git blob
`c46e1c3ed244caaef231c580bb601ea935b3d1c7` and the pinned native text-fusion source
before attachment. It delegates the original helper's two text-fusion paths and
before attachment. The separately reviewed source blob
`31e24388a8d495a524f46371659d3087e2302664` is also admitted: its basic enhancer
functions, class and numeric constants are identical, with only additional
imports/registrations for independent utilities. Loaded helper code and constants
must match the admitted source; a matching file alone is insufficient.
It delegates the original helper's two text-fusion paths and
bounded token delta; no upstream numeric implementation is bundled here. The
separate package retains its own MIT notice. Model and task-weight terms remain
separate from plugin code; this source compatibility check makes no commercial
@@ -229,5 +234,27 @@ guider, evaluation, batch and grounded-wrapper control flow with loading/device
boundaries and neural/VAE work explicitly substituted. Failure/short-schedule
cleanup evidence is source evidence, not installed-runtime or model acceptance.
Two exact native source pairs are admitted. The original pair binds sampler blob
`a7cc3419e325e7d55aac8c7d5ce6d65f620fc511` to model-base SHA256
`e7d08a4450287c76994b109437fbd03d721cf373fc8214bb9c30c478db060ffe`.
The reviewed earlier API pair binds sampler blob
`17f7bb8babdeec605586cc08df2ab1c4f1c92fd4` to model-base SHA256
`5722b46418c6b7475041733d659bbd71f11f1dacb4d0aaff2b21aeb2c82d5542`.
Mixed pairs reject. The earlier sampler omits the writable-model scope; Krea's
inherited writable-model request in the newer source returns None. The consumer
rejects instance writable-model overrides and additional multigpu models, keeping
this equivalence limited to the exact Krea path. Changes to other model families
do not establish their compatibility. Helper and numerical-sampling pins remain
unchanged.
At active binding, the consumer compiles the admitted source without executing
its module body and compares the observed, unwrapped loaded call-path code with
it, including nested code and exception regions. It also checks loaded enhancer
constants and native fusion methods. This detects stale or replaced function
bodies despite matching files; it is not a whole-runtime or model-state proof.
Device behavior, actual tokenizer/tensors, effect and task quality still require
installed-host validation. Node labels, caller revisions and inference-handle
limitations are unchanged.
To roll back this source addition, retain the previous checkout/package; no old
saved graph is rewritten and no model/recipe is migrated by these nodes.
+52
View File
@@ -0,0 +1,52 @@
"""Compare loaded Python function bodies with admitted source without executing it.
This observes the imported callable's code, rather than assuming a file hash
proves which code was loaded. Dependency/device/model state needs separate host
verification. No upstream implementation is copied or executed by compilation.
"""
import inspect
import types
def _constant(value):
if isinstance(value, types.CodeType):
return ('code', _code_key(value))
if isinstance(value, tuple):
return tuple(_constant(item) for item in value)
if isinstance(value, frozenset):
return frozenset(_constant(item) for item in value)
return value
def _code_key(code):
# Filename/line tables are debugging coordinates. Preserve executable byte
# code, constants, closure layout and exception regions, including nesting.
return (code.co_argcount, code.co_posonlyargcount, code.co_kwonlyargcount,
code.co_nlocals, code.co_stacksize, code.co_flags, code.co_code,
tuple(_constant(item) for item in code.co_consts), code.co_names,
code.co_varnames, code.co_freevars, code.co_cellvars,
getattr(code, 'co_exceptiontable', b''))
def verify_loaded_functions(module, source, names):
compiled = compile(source, '<v12-admitted-source>', 'exec', dont_inherit=True)
codes = {}
def collect(code, prefix=()):
for value in code.co_consts:
if isinstance(value, types.CodeType):
path = (*prefix, value.co_name)
codes['.'.join(path)] = value
collect(value, path)
collect(compiled)
for name in names:
value = module
for part in name.split('.'):
value = getattr(value, part, None)
if isinstance(value, (classmethod, staticmethod)):
value = value.__func__
value = inspect.unwrap(value)
actual = getattr(value, '__code__', None)
expected = codes.get(name)
if (not isinstance(actual, types.CodeType) or expected is None
or _code_key(actual) != _code_key(expected)):
raise RuntimeError('V12 loaded function differs from admitted source: ' + name)
+46 -3
View File
@@ -14,11 +14,20 @@ import uuid
from .native import GROUNDING_BLOB, _signature
from .studies import NativeStudies
from .compatibility import verify_loaded_functions
SAMPLERS_BLOB = 'a7cc3419e325e7d55aac8c7d5ce6d65f620fc511'
EULER_SHA256 = 'cfc4221ed0bc1f84a6f5689d3ec440cad3008c2541ab8f5e2599d1a73fac74ce'
HELPERS_SHA256 = '53c82235bfea0c4edf3cd5219f080c44c45ac1c9a6c3171f2aae151e18b56b91'
MODEL_BASE_SHA256 = 'e7d08a4450287c76994b109437fbd03d721cf373fc8214bb9c30c478db060ffe'
# Exact paired API profiles. The second omits writable_models around sampling;
# Krea's inherited writable-model request in the first is a no-op. Other model
# families and arbitrary cross-pairs are outside this native Krea boundary.
CONSUMER_SOURCE_PROFILES = {
(SAMPLERS_BLOB, MODEL_BASE_SHA256): 'native-krea-writable-scope-v1',
('17f7bb8babdeec605586cc08df2ab1c4f1c92fd4',
'5722b46418c6b7475041733d659bbd71f11f1dacb4d0aaff2b21aeb2c82d5542'): 'native-krea-pre-writable-scope-v1',
}
_lock = threading.Lock()
_busy = set()
_MISSING = object()
@@ -32,6 +41,13 @@ def _source_bytes(obj):
return Path(inspect.getfile(obj)).read_bytes().replace(b'\r\n', b'\n')
def _consumer_source_profile(samplers_blob, model_base_sha256):
profile = CONSUMER_SOURCE_PROFILES.get((samplers_blob, model_base_sha256))
if profile is None:
raise RuntimeError('V12 native guider/model source pair is unverified')
return profile
def load_consumer_host():
import comfy.samplers as samplers
import comfy.sampler_helpers as helpers
@@ -39,14 +55,40 @@ def load_consumer_host():
import comfy.k_diffusion.sampling as euler
data = _source_bytes(samplers)
blob = hashlib.sha1(b'blob ' + str(len(data)).encode() + b'\0' + data).hexdigest()
if blob != SAMPLERS_BLOB:
raise RuntimeError('V12 native guider/sampler source revision is unverified')
for module, expected in ((euler, EULER_SHA256), (helpers, HELPERS_SHA256), (model_base, MODEL_BASE_SHA256)):
model_data = _source_bytes(model_base)
profile = _consumer_source_profile(blob, hashlib.sha256(model_data).hexdigest())
for module, expected in ((euler, EULER_SHA256), (helpers, HELPERS_SHA256)):
if hashlib.sha256(_source_bytes(module)).hexdigest() != expected:
raise RuntimeError('V12 native evaluation dependency source revision is unverified')
verify_loaded_functions(samplers, data, (
'CFGGuider.sample', 'CFGGuider.outer_sample', 'CFGGuider.inner_sample',
'CFGGuider.predict_noise', 'CFGGuider.inner_set_conds', 'CFGGuider.set_conds',
'KSAMPLER.sample', 'KSamplerX0Inpaint.__call__', 'process_conds',
'calc_cond_batch', '_calc_cond_batch', 'sampling_function', 'cfg_function'))
verify_loaded_functions(model_base, model_data, (
'Krea2.__init__', 'Krea2.extra_conds', 'BaseModel.apply_model',
'BaseModel._apply_model', 'BaseModel.extra_conds',
'BaseModel.process_latent_in', 'BaseModel.process_latent_out'))
if profile == 'native-krea-writable-scope-v1':
verify_loaded_functions(model_base, model_data, ('BaseModel.get_writable_model',))
elif hasattr(model_base.BaseModel, 'get_writable_model'):
raise RuntimeError('V12 loaded model has an unverified writable-model hook')
verify_loaded_functions(helpers, _source_bytes(helpers), ('convert_cond',))
verify_loaded_functions(euler, _source_bytes(euler), (
'sample_euler', 'sample_euler_ancestral', 'sample_euler_ancestral_RF',
'sample_er_sde', 'offset_first_sigma_for_snr', 'sigma_to_half_log_snr'))
return samplers, euler, model_base
def _validate_writable_scope(patcher):
# Both admitted source pairs have the same Krea path only when the primary
# class has no instance writable-model override and no additional GPU model
# can enter the newer writable-model scope. Do not infer other model support.
if ('get_writable_model' in vars(patcher.model)
or patcher.get_additional_models_with_key('multigpu')):
raise RuntimeError('V12 native source profiles do not support extra writable/multigpu models')
def _scalar(value):
if not isinstance(value, Real):
if not callable(getattr(value, 'numel', None)) or value.numel() != 1:
@@ -167,6 +209,7 @@ class NativePhaseGuider:
samplers, euler, model_base = self.host
if type(guider) is not samplers.CFGGuider or type(guider.model_patcher.model) is not model_base.Krea2:
raise RuntimeError('V12 consumer requires the pinned native Krea2 CFGGuider')
_validate_writable_scope(guider.model_patcher)
allowed_samplers = (euler.sample_euler, euler.sample_euler_ancestral,
getattr(euler, 'sample_er_sde', None))
if (type(sampler) is not samplers.KSAMPLER
+21 -4
View File
@@ -14,8 +14,13 @@ import threading
from .ledger import TAP_WIDTH, TAPS
from .native import _signature
from .compatibility import verify_loaded_functions
ENHANCER_BLOB = 'c46e1c3ed244caaef231c580bb601ea935b3d1c7'
ENHANCER_SOURCE_PROFILES = {
ENHANCER_BLOB: 'krea2t-basic-math-v1',
'31e24388a8d495a524f46371659d3087e2302664': 'krea2t-basic-math-extra-registrations-v1',
}
CORE_FUSION_BLOB = 'a904e05e0053d38bda0fdbd70625cd8c5e9b70a2'
WRAPPER_KEY = 'kg_native_enhancer_v12'
_OTHER_KEYS = ('krea2t_prompt_adherence_enhancer', 'krea2t_prompt_adherence_enhancer_advanced')
@@ -31,8 +36,9 @@ def load_enhancer_host():
raise RuntimeError('V12 enhancer requires the pinned original Krea2T enhancer package')
data = Path(inspect.getfile(cls)).read_bytes().replace(b'\r\n', b'\n')
blob = hashlib.sha1(b'blob ' + str(len(data)).encode() + b'\0' + data).hexdigest()
if blob != ENHANCER_BLOB:
if blob not in ENHANCER_SOURCE_PROFILES:
raise RuntimeError('V12 enhancer source revision is unverified')
enhancer_blob = blob
module = sys.modules[cls.__module__]
helper = getattr(module, '_enhanced_txtfusion_forward', None)
compatible = getattr(module, '_is_krea2_dm', None)
@@ -40,12 +46,23 @@ def load_enhancer_host():
or inspect.getfile(helper) != inspect.getfile(cls)
or inspect.getfile(compatible) != inspect.getfile(cls)):
raise RuntimeError('V12 enhancer helper does not belong to the pinned source')
verify_loaded_functions(module, data, (
'_is_krea2_dm', '_chunk_gains', '_run_refiners',
'_run_txtfusion_parts', '_enhanced_txtfusion_forward'))
profile = (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.5, 5.0, 1.1, 4.0, 1.0)
expected_constants = {'KREA2_TAP_LAYERS': TAPS, 'KREA2_TAP_DIM': TAP_WIDTH,
'KREA2_CHUNK_COUNT': 24, 'KREA2_CHUNK_DIM': 1280,
'ENHANCER_PROFILE_12': profile, 'ENHANCER_CHUNK_PROFILE': profile + profile,
'ENHANCER_GLOBAL_MULTIPLIER': 15.0, 'TXTFUSION_TOKEN_REL_CAP': 0.75}
if any(getattr(module, name, None) != value for name, value in expected_constants.items()):
raise RuntimeError('V12 loaded enhancer constants differ from admitted source')
import comfy.ldm.krea2.model as core
data = Path(inspect.getfile(core.TextFusionTransformer)).read_bytes().replace(b'\r\n', b'\n')
blob = hashlib.sha1(b'blob ' + str(len(data)).encode() + b'\0' + data).hexdigest()
if blob != CORE_FUSION_BLOB:
raise RuntimeError('V12 enhancer native text-fusion source revision is unverified')
return helper, compatible
verify_loaded_functions(core, data, ('TextFusionTransformer.forward', 'TextFusionBlock.forward'))
return helper, compatible, enhancer_blob
@contextmanager
@@ -81,7 +98,7 @@ def apply_enhancer(model, enabled=False, strength=1.0):
raise ValueError('V12 enhancer strength must be finite within [0, 2]')
if not enabled or strength == 0:
return model, 'Krea native enhancer V12: OFF; original MODEL retained.'
helper, compatible = load_enhancer_host()
helper, compatible, enhancer_blob = load_enhancer_host()
dm = model.model.diffusion_model
_check_architecture(dm, compatible)
original_options_signature = _signature(model.model_options)
@@ -90,7 +107,7 @@ def apply_enhancer(model, enabled=False, strength=1.0):
raise RuntimeError('V12 enhancer refuses an already enhanced MODEL')
if 'krea2_edit' in original_wrappers:
raise RuntimeError('V12 enhancer must precede the native edit patch, which bypasses inner wrappers')
config = {'enabled': True, 'strength': float(strength), 'source_blob': ENHANCER_BLOB}
config = {'enabled': True, 'strength': float(strength), 'source_blob': enhancer_blob}
def wrapper(executor, *args, **kwargs):
options = kwargs.get('transformer_options')
+92
View File
@@ -0,0 +1,92 @@
"""Source-admission and observed loaded-code regressions; no host or model import."""
import functools
import importlib.util
from pathlib import Path
import sys
from types import ModuleType, SimpleNamespace as NS
import unittest
ROOT = Path(__file__).resolve().parents[1]
SPEC = importlib.util.spec_from_file_location('compatibility_v12_tests', ROOT / 'kg_krea_v12/__init__.py',
submodule_search_locations=[str(ROOT / 'kg_krea_v12')])
PACKAGE = importlib.util.module_from_spec(SPEC)
sys.modules[SPEC.name] = PACKAGE
SPEC.loader.exec_module(PACKAGE)
from compatibility_v12_tests import compatibility, consumer, enhancer
class CompatibilityTests(unittest.TestCase):
def test_exact_core_pairs_admit_but_cross_pairs_and_unknown_reject(self):
pairs = list(consumer.CONSUMER_SOURCE_PROFILES)
self.assertEqual(len(pairs), 2)
for pair in pairs:
self.assertTrue(consumer._consumer_source_profile(*pair))
for pair in ((pairs[0][0], pairs[1][1]), (pairs[1][0], pairs[0][1]), ('unknown', pairs[0][1])):
with self.assertRaisesRegex(RuntimeError, 'source pair is unverified'):
consumer._consumer_source_profile(*pair)
def test_loaded_body_changed_after_disk_read_rejects(self):
source = 'def predict(x):\n return x + 1\n'
module = ModuleType('observed_source_fixture')
exec(compile(source, '<original-loaded-file>', 'exec', dont_inherit=True), module.__dict__)
compatibility.verify_loaded_functions(module, source.encode(), ('predict',))
changed = ModuleType('changed')
exec('def predict(x):\n return x - 1\n', changed.__dict__)
module.predict = changed.predict
with self.assertRaisesRegex(RuntimeError, 'loaded function differs'):
compatibility.verify_loaded_functions(module, source.encode(), ('predict',))
def test_loaded_nested_code_and_exception_cleanup_must_match(self):
source = ('class Guider:\n'
' def sample(self, x):\n'
' def evaluate():\n'
' return x + 1\n'
' try:\n'
' return evaluate()\n'
' finally:\n'
' self.clean = True\n')
module = ModuleType('nested_source_fixture')
exec(compile(source, '<original>', 'exec', dont_inherit=True), module.__dict__)
compatibility.verify_loaded_functions(module, source.encode(), ('Guider.sample',))
other = ModuleType('changed_nested')
exec(compile(source.replace('x + 1', 'x + 2'), '<other>', 'exec', dont_inherit=True), other.__dict__)
module.Guider.sample = other.Guider.sample
with self.assertRaisesRegex(RuntimeError, 'loaded function differs'):
compatibility.verify_loaded_functions(module, source.encode(), ('Guider.sample',))
def test_standard_decorator_unwrap_matches_original_loaded_body(self):
source = 'def step(x):\n return x * 2\n'
module = ModuleType('decorated_source_fixture')
exec(compile(source, '<loaded>', 'exec', dont_inherit=True), module.__dict__)
original = module.step
@functools.wraps(original)
def wrapper(*args, **kwargs):
return original(*args, **kwargs)
module.step = wrapper
compatibility.verify_loaded_functions(module, source.encode(), ('step',))
def test_source_compilation_never_executes_module_body(self):
source = 'must_never_execute()\ndef step(x):\n return x\n'
module = ModuleType('compile_only_fixture')
exec(compile('def step(x):\n return x\n', '<loaded>', 'exec', dont_inherit=True), module.__dict__)
compatibility.verify_loaded_functions(module, source.encode(), ('step',))
def test_extra_writable_or_multigpu_models_reject(self):
patcher = NS(model=NS(), get_additional_models_with_key=lambda name: [])
consumer._validate_writable_scope(patcher)
patcher.model.get_writable_model = lambda *args: object()
with self.assertRaisesRegex(RuntimeError, 'extra writable/multigpu'):
consumer._validate_writable_scope(patcher)
del patcher.model.get_writable_model
patcher.get_additional_models_with_key = lambda name: [object()]
with self.assertRaisesRegex(RuntimeError, 'extra writable/multigpu'):
consumer._validate_writable_scope(patcher)
def test_enhancer_profiles_bind_only_two_reviewed_whole_sources(self):
self.assertEqual(set(enhancer.ENHANCER_SOURCE_PROFILES),
{'c46e1c3ed244caaef231c580bb601ea935b3d1c7',
'31e24388a8d495a524f46371659d3087e2302664'})
if __name__ == '__main__':
unittest.main()
+2 -2
View File
@@ -60,7 +60,7 @@ class EnhancerV12Tests(unittest.TestCase):
self.calls.append((fusion, x, kwargs))
return NS(shape=(1, 2, 2560), value='delegated-helper'), None
host_patch = patch.object(enhancer, 'load_enhancer_host', return_value=(helper, lambda dm: True))
host_patch = patch.object(enhancer, 'load_enhancer_host', return_value=(helper, lambda dm: True, enhancer.ENHANCER_BLOB))
host_patch.start()
self.addCleanup(host_patch.stop)
self.addCleanup(self.assertFalse, enhancer._busy)
@@ -175,7 +175,7 @@ class EnhancerV12Tests(unittest.TestCase):
self.assertEqual(self.calls, [])
def helper(*args, **kwargs):
return NS(shape=(1, 3, 2560)), None
with patch.object(enhancer, 'load_enhancer_host', return_value=(helper, lambda dm: True)):
with patch.object(enhancer, 'load_enhancer_host', return_value=(helper, lambda dm: True, enhancer.ENHANCER_BLOB)):
_, malformed_options, malformed_wrapper = self.attached()
with self.assertRaisesRegex(RuntimeError, 'helper returned'):
malformed_wrapper(Executor(dm), transformer_options=malformed_options)