Files
Ethanfel 011c915fa7 release: ship H3 correctness fixes and research tools in 1.8.5
Publish the existing H3 merge/export and autotuner correctness fixes, offline character and AV calibration tools, provenance audits, and regression coverage. Add a dictionary-preserving storage hook for offline mapped TIES exports.

Keep scoring weights and defaults unchanged, retain NP/CT as opt-in, and exclude the rejected F08 search-admission prototype. Validate the exact staged tree: 1052 Python tests, 69 subtests, 3 JS tests, and real ComfyUI CPU export round trips pass; 3 CUDA-only tests skipped.
2026-09-09 12:10:02 +02:00

213 lines
11 KiB
Python

"""Offline checks for the research harness; no server or model files required."""
import json
import struct
import hashlib
import shutil
import subprocess
import pytest
from scripts.h3_merge_study import header, check_gpu_headroom
from scripts.h3_render_study import graph, PROMPTS
from scripts.h3_study_record import collect_merge_run
from scripts.h3_benchmark import case_matrix, EXPORT_RUNS, successful
from scripts.h3_av_review import validate_labels, output_video, DIMENSIONS
from scripts import h3_av_review
from scripts.h3_study_record import collect_render_run
def test_local_profile_uses_requested_quantization_and_limited_resolution():
result = graph(PROMPTS["cup"], 123, [], "study", profile="local")
assert result["1"]["inputs"]["unet_name"] == "minimax_h3_fl2va_pruned_int8_convrot.safetensors"
assert result["2"]["inputs"]["clip_name"] == "qwen3vl_32b_minimax_h3_nvfp4_awq.safetensors"
assert result["2"]["inputs"]["type"] == "minimax"
assert (result["5"]["inputs"]["width"], result["5"]["inputs"]["height"]) == (640, 384)
assert result["5"]["inputs"]["length"] % 17 == 5
assert result["6"]["inputs"]["noise_seed"] == 123
assert result["8"]["inputs"]["steps"] == 20
assert result["13"]["inputs"]["audio"] == ["12", 0]
assert not any("Lora" in n["class_type"] for n in result.values())
def test_adapter_chain_controls_both_schedule_and_guider_without_prompt_changes():
result = graph(PROMPTS["boxing"], 456, [("a.safetensors", .8), ("b.safetensors", -.3)], "study", "local")
assert result["20"]["inputs"]["model"] == ["1", 0]
assert result["21"]["inputs"]["model"] == ["20", 0]
assert result["21"]["inputs"]["strength_model"] == -.3
assert result["8"]["inputs"]["model"] == result["9"]["inputs"]["model"] == ["21", 0]
assert result["5"]["inputs"]["prompt"] == PROMPTS["boxing"]
assert result["6"]["inputs"]["noise_seed"] == 456
def test_checkpoint_header_reader_does_not_require_tensor_payload(tmp_path):
payload = json.dumps({"layer.weight": {"shape": [8, 16], "dtype": "I8", "data_offsets": [0, 128]}}).encode()
path = tmp_path / "shape-only.safetensors"
path.write_bytes(struct.pack("<Q", len(payload)) + payload)
assert header(path)["layer.weight"]["shape"] == [8, 16]
def test_checkpoint_header_rejects_unreasonable_allocation(tmp_path):
path = tmp_path / "bad.safetensors"
path.write_bytes(struct.pack("<Q", 2**40))
with pytest.raises(ValueError, match="header size"):
header(path)
def test_headless_study_refuses_retained_gpu_cache_before_large_allocations():
with pytest.raises(RuntimeError, match="idle model caches"):
check_gpu_headroom("tune", 2 * 1024**3)
with pytest.raises(RuntimeError, match="6 GiB"):
check_gpu_headroom("merge", 5 * 1024**3)
check_gpu_headroom("tune", 24 * 1024**3)
check_gpu_headroom("merge", 8 * 1024**3)
def test_durable_record_preserves_timestamp_precision_and_export_identity(tmp_path):
export = tmp_path / "merged.safetensors"
export.write_bytes(b"synthetic fixture")
manifest = {"checkpoint_mtime_ns": 1788468997480069696, "adapters": [],
"export": str(export), "export_size": export.stat().st_size}
(tmp_path / "manifest.json").write_text(json.dumps(manifest))
record = collect_merge_run(tmp_path)
assert json.loads(json.dumps(record))["checkpoint_mtime_ns"] == 1788468997480069696
assert len(record["export_sha256"]) == 64
export.write_bytes(b"changed")
with pytest.raises(ValueError, match="Export size"):
collect_merge_run(tmp_path)
def test_mapped_record_separates_rounding_from_export_error_and_rejects_stale_audit(tmp_path):
export = tmp_path / "merged.safetensors"
export.write_bytes(b"fixture")
manifest = {"adapters": [], "mapped_export": True, "export": str(export), "export_size": 7}
manifest_path = tmp_path / "manifest.json"
manifest_path.write_text(json.dumps(manifest))
check_path = tmp_path / "dense_export_check.json"
check = dict(groups_checked=1, all_targets=True,
manifest_sha256=hashlib.sha256(manifest_path.read_bytes()).hexdigest(),
export_sha256=hashlib.sha256(export.read_bytes()).hexdigest(),
results=[dict(finite=True, exact_stored_values=True, relative_export_error=0.,
relative_storage_rounding_error=.0016, relative_fp32_reference_error=.0016)])
check_path.write_text(json.dumps(check))
report = collect_merge_run(tmp_path)["dense_precision"]
assert report["exact_stored_components"] == 1
assert report["max_relative_export_error"] == 0.
assert report["max_relative_storage_rounding_error"] == .0016
export.write_bytes(b"changed") # Same length: only a fresh hash catches this.
with pytest.raises(ValueError, match="mismatched dense"):
collect_merge_run(tmp_path)
def test_frozen_av_matrix_has_matched_controls_and_disjoint_holdout():
exports = {pair: {mode: {"api_name": f"{pair}-{mode}.safetensors"} for mode in modes}
for pair, modes in EXPORT_RUNS.items()}
jobs, cases = case_matrix(exports)
assert len(jobs) == 48 and len(cases) == 56
assert (jobs, cases) == case_matrix(exports)
assert len({j["id"] for j in jobs}) == 48
assert all(j["seed"] == 2026090803 for j in jobs[:12])
calibration = [j for j in jobs if j["stage"] == "calibration"]
heldout = [j for j in jobs if j["stage"] == "heldout"]
assert {j["prompt"] for j in calibration}.isdisjoint(j["prompt"] for j in heldout)
assert {j["seed"] for j in calibration}.isdisjoint(j["seed"] for j in heldout)
for stage, prompt, seed in {(c["stage"], c["prompt"], c["seed"]) for c in cases}:
group = [c for c in cases if (c["stage"], c["prompt"], c["seed"]) == (stage, prompt, seed)]
for pair in EXPORT_RUNS:
assert {c["variant"] for c in group if c["pair"] == pair} == {
"base", "combat", "second", "additive", "winner", "np", "ct"}
for control in ("base", "combat"):
assert len({c["job_id"] for c in group if c["variant"] == control}) == 1
def test_benchmark_never_treats_failed_history_as_completed(tmp_path):
assert not successful(tmp_path)
(tmp_path / "history.json").write_text(json.dumps({"status": {"status_str": "error"}}))
with pytest.raises(RuntimeError, match="do not auto-resubmit"):
successful(tmp_path)
def test_heldout_h3_prompt_is_structured_and_keeps_sound_observable():
text = PROMPTS["padwork"]
assert text.startswith("integrated_multimodal_description: [Shot 1]")
assert text.count("[Shot") == 1
assert text.index("overall_soundscape:") < text.index("non_diegetic_music:")
assert "No speech" in text and text.endswith("non_diegetic_music: N/A")
def test_av_labels_require_explicit_full_review_and_exact_media_identity():
key = {"review_id": "r", "plan_sha256": "p", "cases": [{"blind_id": "C01", "media_sha256": "m"}]}
row = {"blind_id": "C01", "media_sha256": "m", "full_video_reviewed": True,
"audio_listened": True, "scores": {d: 3 for d in DIMENSIONS}}
labels = {"review_id": "r", "plan_sha256": "p", "reviewer": "test-only fixture", "ratings": [row]}
assert len(validate_labels(labels, key)) == 1
for field, invalid, error in (("audio_listened", False, "both"), ("full_video_reviewed", False, "both"),
("media_sha256", "wrong", "hash")):
with pytest.raises(ValueError, match=error):
validate_labels({**labels, "ratings": [{**row, field: invalid}]}, key)
for value in (float("nan"), True, 5, -1, 3.5):
with pytest.raises(ValueError, match="integer"):
validate_labels({**labels, "ratings": [{**row, "scores": {**row["scores"], "audio": value}}]}, key)
with pytest.raises(ValueError, match="repeated"):
validate_labels({**labels, "ratings": [row, row]}, key)
with pytest.raises(ValueError, match="another"):
validate_labels({**labels, "plan_sha256": "other"}, key)
def test_review_rejects_output_path_escape(tmp_path):
history = {"status": {"status_str": "success"}, "outputs": {"14": {"images": [
{"type": "output", "subfolder": "..", "filename": "unexpected.mp4"}]}}}
with pytest.raises(ValueError, match="path"):
output_video(history, tmp_path)
def test_render_record_requires_matching_media_hash_and_full_av_profile(tmp_path, monkeypatch):
video = tmp_path / "clip.mp4"
video.write_bytes(b"synthetic stream fixture, not a real render")
monkeypatch.setattr(h3_av_review, "output_video", lambda history: video)
metrics = {"video_sha256": hashlib.sha256(video.read_bytes()).hexdigest(), "decoded_frames": 124}
probe = {"streams": [{"codec_type": "video", "width": 640, "height": 384, "r_frame_rate": "24/1"},
{"codec_type": "audio", "sample_rate": "32000", "channels": 2}]}
audit = tmp_path / "media-audit"
audit.mkdir()
(audit / "metrics.json").write_text(json.dumps(metrics))
(audit / "probe.json").write_text(json.dumps(probe))
(tmp_path / "manifest.json").write_text('{}')
(tmp_path / "prompt_api.json").write_text('{}')
(tmp_path / "history.json").write_text(json.dumps({"status": {"messages": [
["execution_start", {"timestamp": 1000}], ["execution_success", {"timestamp": 3000}]]}}))
assert collect_render_run(tmp_path)["elapsed_seconds"] == 2
(audit / "metrics.json").write_text(json.dumps({**metrics, "decoded_frames": 123}))
with pytest.raises(ValueError, match="profile"):
collect_render_run(tmp_path)
(audit / "metrics.json").write_text(json.dumps({**metrics, "video_sha256": "different"}))
with pytest.raises(ValueError, match="different media"):
collect_render_run(tmp_path)
def test_review_page_does_not_embed_private_method_mapping(tmp_path, monkeypatch):
run = tmp_path / "SECRET_METHOD_JOB"
run.mkdir()
(run / "history.json").write_text('{}')
video = tmp_path / "source.mp4"
video.write_bytes(b"synthetic bytes for page construction only")
monkeypatch.setattr(h3_av_review, "output_video", lambda history: video)
def fake_remux(command, **kwargs):
Path(command[-1]).write_bytes(video.read_bytes())
from pathlib import Path
real_run = subprocess.run
monkeypatch.setattr(h3_av_review.subprocess, "run", fake_remux)
plan = {"root": str(tmp_path), "cases": [{"stage": "calibration", "seed": 3, "pair": "combat_cinema",
"prompt": "boxing", "variant": "SECRET_METHOD", "job_id": run.name}],
"prompt_text": {"boxing": "A harmless synthetic test prompt."}}
plan_path = tmp_path / "plan.json"
plan_path.write_text(json.dumps(plan))
out = tmp_path / "review"
h3_av_review.build(plan_path, out, "calibration", 3)
page = (out / "review.html").read_text()
assert "SECRET_METHOD" not in page and str(video) not in page
assert "SECRET_METHOD" in (out / "private-key.json").read_text()
assert "data:video/mp4;base64," in page
if shutil.which("node"):
script = page.split('<script>', 1)[1].split('</script>', 1)[0]
real_run(['node', '--check'], input=script, text=True, check=True, capture_output=True)