Files
club-3090/scripts/tests/test-classifier.sh
T
noonghunnaandClaude Opus 4.7 20f1557d29 feat(pull): v0.8.2 STEP V1 — capture-on-hard-block pt1-gate emitter + BaseCaptureBundle protocol lift
CONTRACT-1.1 capture-on-hard-block (additive only; zero v0.8.0 decision-logic
change — the safetensors/GGUF paths are byte-unchanged):

- capture.py: new SEPARATE emit_gate_capture() (the emit_override_capture
  byte-preserving precedent — NOT invoked by emit_capture()) writing a
  pt1-gate.json + schema:2 manifest.json (outcome:hard-block, exact shipped
  abort_reason, failure_class:null) per the per-abort-stratum key table
  (model/arch/quant null pre-deriver; topology best-effort/nullable, capture-
  only resolve; post-C0 always null). New shared write_last_marker() helper
  (atomic tmp+os.replace) called from BOTH emit_capture() and the gate
  emitter (centralization mandate — gate-only is the commonest failure).
- pull.py: pass-through capture on the 7 terminal hard-block return paths
  (deriver / profile-like / hardware-sm-undetermined / C0 / C2a / no-fit-model
  / C1) — emits a bundle before the existing `return res`; the decision is
  byte-unchanged; injectable gate_capture_fn; never raises.
- loop_input.py: BaseCaptureBundle typing.Protocol (Optional[dict] pt2-5);
  FInput satisfies it by construction (verified: no isinstance(finput,FInput)
  anywhere in F2/F5 — pure static retype, schema==1 byte-identical incl.
  dedup_hash); new FInputGate + read_gate_bundle() (schema==2; validates ONLY
  the always-present row + outcome==hard-block + failure_class is None — does
  NOT reuse the 22-key validator); FInputGate.dedup_tuple() uses .get(k,None)
  (behaviour-neutral schema-1, crash-safe schema-2, deterministic null-topo).
- classifier.py / dedup.py: F2+F5 parameter annotations retyped FInput ->
  BaseCaptureBundle. The dedup.py FInput.dedup_hash(_EffProxy()) unbound-class
  idiom is FENCED (unchanged — not tidied). Additive gate_abort_reason
  _match_condition kind (reads pt1_gate.abort_reason; bool like sibling kinds;
  no enum/routing change).
- failure_fingerprints.yml: seeded gate_abort_reason rules keyed on the
  verified shipped abort_reason strings — only engine-support-unknown/
  no-arch-row -> kernel-unsupported (public-filed); runtime-incompatible /
  disk-short / hard-block / catch-alls -> unknown (review-queued, not filed).
- tests: extended test-{pull,pullemit-capture,loop-input,classifier,dedup}.sh
  with the V1 RED-LINE proofs (emit_capture() still writes ONLY pt1-4; a
  schema==1 bundle yields byte-identical FInput / ClassificationResult /
  dedup_hash / effective_dedup_hash pre/post the protocol lift; the dedup
  fence holds) + gate-emitter / read_gate_bundle / gate_abort_reason routing
  / shared .last marker coverage; all 22 shipped test-*.sh green in the CI
  condition (gitignored .pull-captures absent), kv-calc --calibration 11/11.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-18 16:43:28 +00:00

692 lines
32 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -euo pipefail
# test-classifier.sh — v0.8.0 [F] STEP F2 (club-3090 #147).
#
# Contract test for CONTRACT-2 Tier-2 + Appendix A: the §6.1 semantic-
# fingerprint classifier. The test IS the spec; the code is fixed to it.
# NO live Docker / GPU / network — fixture capture dirs are built in a tmp
# tree (byte-exact [E] schema, reused via F1's read_capture_bundle for
# realism) and classified.
#
# Coverage (every CONTRACT-2 / Appendix-A / §6.1 assertion as a
# failing-then-passing check):
# * EACH Appendix A row maps to its STATED §6.1 class:
# Cliff-2 OOM -> genuine-oom
# prefill-cliff GDN OOM -> genuine-oom
# #145 streaming dead -> quant-unsupported (via pt4, boot green)
# AWQ/quant mis-load -> quant-unsupported
# Genesis overlay drift -> overlay-arch-drift
# Ampere/FA3 SM90 kernel -> kernel-unsupported
# cold-start then green -> benign-cold-start (should_file=False)
# served-name 404 ctrl -> benign-cold-start (should_file=False)
# unmatched -> unknown (should_file=False + review_queue)
# * route_as_kv_calc_bug is False for EVERY F2 path incl. genuine-oom
# (Tier-1 is F3 — F2 must hard-wire False).
# * output ALWAYS in the 6-enum unknown — an out-of-enum 7th DB value
# degrades to `unknown` (no 7th value can leak).
# * works with pt3.failure_log_excerpt ABSENT (today's shipped [E]
# schema, bare pt3.failure) AND present (F3 forward-compat).
# * tier seam: F2 only ever emits TIER2 / NONE_UNKNOWN, never TIER1.
# * REAL on-disk .pull-captures/ bundle (a success/`partial`): classify
# returns a valid enum and does NOT misclassify as a fileable failure.
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"
export PYTHONPATH="$ROOT_DIR${PYTHONPATH:+:$PYTHONPATH}"
python3 - "$ROOT_DIR" <<'PY'
from __future__ import annotations
import json
import sys
import tempfile
from pathlib import Path
root = Path(sys.argv[1])
sys.path.insert(0, str(root))
from scripts.lib.profiles.loop_input import read_capture_bundle # noqa: E402
from scripts.lib.profiles.classifier import ( # noqa: E402
FailureClass,
Tier,
classify,
)
ENUM_VALUES = {c.value for c in FailureClass}
failures: list[str] = []
def check(cond: bool, msg: str) -> None:
if cond:
print(f"PASS: {msg}")
else:
print(f"FAIL: {msg}", file=sys.stderr)
failures.append(msg)
# ---------------------------------------------------------------------------
# Byte-exact [E] schema fixtures (mirror scripts/lib/profiles/capture.py),
# parsed back through F1's reader for realism (CONTRACT-1 boundary).
# ---------------------------------------------------------------------------
def mk_manifest(**over) -> dict:
m = {
"schema": 1,
"slug": "Org/My-Model",
"utc_ts": "20260517T000000Z",
"submission_fingerprint": "deadbeef" * 8,
"model": "Org/My-Model",
"quant_label": "BFloat16",
"arch_family": "Qwen3NextForCausalLM",
"topology_class": "1x24576MiB",
"engine_pin": "vllm/vllm-openai:nightly-abc123",
"engine_version": "vllm/vllm-openai:nightly-abc123",
"kv_calc_version": "kvcalc-v0.8.0",
"selected_ctx": 32768,
"kv_format": "fp8_e5m2",
"smoke_capability_set": ["plain-chat", "streaming"],
"topology_summary_canonical": "[(NVIDIA GeForce RTX 3090, 24576)]",
"model_id": "Org/My-Model",
"failure_class": None,
"club3090_commit": "cafef00d",
"outcome": "failed",
"capture_points": ["gate", "download", "boot", "smoke"],
}
m.update(over)
return m
def write_bundle(d: Path, *, manifest=None, pt3=None, pt4=None) -> Path:
d.mkdir(parents=True, exist_ok=True)
arts = {
"manifest.json": manifest if manifest is not None else mk_manifest(),
"pt1-gate.json": {
"schema": 1, "point": "gate", "slug": "Org/My-Model",
"confidence": "estimated-lower-bound",
"raw_verdict": "fits-clean", "terminal": "confirm→proceed",
"profile_like": "vllm/minimal", "hardware_sm": 8.6,
},
"pt2-download.json": {
"point": "download", "ok": True, "files": ["model.safetensors"],
"bytes": 123, "sha_verified": True, "failure": None,
},
"pt3-boot.json": pt3 if pt3 is not None else {
"point": "boot", "ok": False, "seconds": 0.0,
"failure": "server did not become ready before timeout",
},
"pt4-smoke.json": pt4 if pt4 is not None else {
"point": "smoke",
"smoke_capability_set": ["plain-chat", "streaming"],
"results": {"plain-chat": "unsmoked", "streaming": "unsmoked"},
"partial": True, "results_detail": {},
},
}
for name, obj in arts.items():
(d / name).write_text(json.dumps(obj, indent=2), encoding="utf-8")
return d
tmp = Path(tempfile.mkdtemp())
def fi(name, **kw):
return read_capture_bundle(write_bundle(tmp / name, **kw))
def boot_fail(failure=None, excerpt=None):
pt3 = {"point": "boot", "ok": False, "seconds": 0.0,
"failure": failure}
if excerpt is not None:
pt3["failure_log_excerpt"] = excerpt # F3 forward-compat
pt3["actual"] = {"attempted_alloc_mib": 1234, # F2 must NOT read
"gpu_worker_reported_mib": 23456}
return pt3
# ---------------------------------------------------------------------------
# Appendix A — every row maps to its STATED §6.1 class.
# ---------------------------------------------------------------------------
# Row 1: Cliff-2 accumulated-ctx OOM (~21-26K) — torch.cuda.OOM.
r = classify(fi("a1", pt3=boot_fail(
failure="torch.cuda.OutOfMemoryError: CUDA out of memory. Tried to "
"allocate 512.00 MiB")))
check(r.failure_class is FailureClass.GENUINE_OOM,
f"Appendix-A Cliff-2 OOM -> genuine-oom (got {r.failure_class.value})")
check(r.route_as_kv_calc_bug is False,
"genuine-oom route_as_kv_calc_bug=False with NO Tier-1 inputs "
"present (F3 honest-degrade — never a confidently-wrong kv-calc bug)")
check(r.should_file is True,
"genuine-oom should_file=True (classified+filed, not a kv-calc bug)")
check(r.tier is Tier.TIER1,
f"F3: OOM signature -> Tier-1 fast-path decides genuine-oom "
f"(got {r.tier.value})")
check(r.matched_rule == "tier1-oom-fastpath",
"F3: Tier-1 fast-path stamps matched_rule=tier1-oom-fastpath")
check(r.tier1_inputs is not None
and r.tier1_inputs.get("predicted_b_breakdown") is None,
"F3 honest-degrade: tier1_inputs surfaced, predicted side absent "
"(bare pt3.failure, no pt1.predicted_b_breakdown / pt3.actual)")
# Row 2: prefill-cliff OOM (~50-60K, DeltaNet GDN) — works with the F3
# forward-compat failure_log_excerpt PRESENT.
r = classify(fi("a2", pt3=boot_fail(
failure="server did not become ready before timeout",
excerpt="...gated_delta_net forward... torch.cuda.OutOfMemoryError: "
"CUDA out of memory ...")))
check(r.failure_class is FailureClass.GENUINE_OOM,
f"Appendix-A prefill-cliff GDN OOM -> genuine-oom "
f"(got {r.failure_class.value})")
check(r.route_as_kv_calc_bug is False,
"prefill-cliff genuine-oom route_as_kv_calc_bug=False (F2)")
check(r.error_substring and "torch.cuda" in r.error_substring,
"F3 forward-compat: failure_log_excerpt used when PRESENT")
# Row 3: #145 qwen3_coder streaming dead — boot+plain-chat green,
# streaming red. Maps via pt4, NOT a boot failure.
r = classify(fi("a3",
pt3={"point": "boot", "ok": True, "seconds": 80.0, "failure": None},
pt4={"point": "smoke",
"smoke_capability_set": ["plain-chat", "streaming"],
"results": {"plain-chat": "green", "streaming": "red"},
"partial": False,
"results_detail": {"streaming": {"status": 200, "error": ""}}}))
check(r.failure_class is FailureClass.QUANT_UNSUPPORTED,
f"Appendix-A #145 streaming-dead -> quant-unsupported (got "
f"{r.failure_class.value})")
check(r.matched_rule == "streaming-dead-boot-green-145",
"#145 matched via pt4_results rule (not a pt3 boot failure)")
# Row 4: AWQ/quant mis-load on derived (no --quantization).
r = classify(fi("a4", pt3=boot_fail(
failure="ValueError: Model QuantConfig: the AWQ weight is not "
"supported for this dtype")))
check(r.failure_class is FailureClass.QUANT_UNSUPPORTED,
f"Appendix-A AWQ mis-load -> quant-unsupported (got "
f"{r.failure_class.value})")
# Row 5: Genesis-required engine on clean image (overlay drift).
r = classify(fi("a5", pt3=boot_fail(
failure="AttributeError: module 'vllm' has no attribute "
"'genesis_patch' (patch not applied)")))
check(r.failure_class is FailureClass.OVERLAY_ARCH_DRIFT,
f"Appendix-A Genesis overlay drift -> overlay-arch-drift (got "
f"{r.failure_class.value})")
# Row 6: Ampere-unsupported kernel (FA3 / SM90-only path).
r = classify(fi("a6", pt3=boot_fail(
failure="RuntimeError: FlashAttention-3 requires Hopper SM90; "
"compute capability 8.6 not supported on this gpu")))
check(r.failure_class is FailureClass.KERNEL_UNSUPPORTED,
f"Appendix-A Ampere/FA3 SM90 -> kernel-unsupported (got "
f"{r.failure_class.value})")
# Row 7: first-request-after-boot cold start (slow, then green). pt3
# timeout but pt4 green -> benign-cold-start, SUPPRESSED (not filed).
r = classify(fi("a7",
pt3={"point": "boot", "ok": False, "seconds": 0.0,
"failure": "server did not become ready before timeout"},
pt4={"point": "smoke",
"smoke_capability_set": ["plain-chat"],
"results": {"plain-chat": "green"},
"partial": False, "results_detail": {}}))
check(r.failure_class is FailureClass.BENIGN_COLD_START,
f"Appendix-A cold-start-then-green -> benign-cold-start (got "
f"{r.failure_class.value})")
check(r.should_file is False,
"benign-cold-start SUPPRESSED — should_file=False (§6.1 acceptance)")
check(r.route_as_kv_calc_bug is False and r.review_queue is False,
"benign-cold-start never files / never review-queue / never kv-calc")
# Row 8: [E] bug #1 served-model-name 404 — historical negative control.
r = classify(fi("a8",
pt3={"point": "boot", "ok": True, "seconds": 80.0, "failure": None},
pt4={"point": "smoke",
"smoke_capability_set": ["plain-chat"],
"results": {"plain-chat": "red"},
"partial": False,
"results_detail": {"plain-chat": {"status": 404,
"error": "model not found"}}}))
check(r.failure_class is FailureClass.BENIGN_COLD_START,
f"Appendix-A served-name-404 negative control -> benign-cold-start "
f"(got {r.failure_class.value})")
check(r.should_file is False,
"negative-control 404 should_file=False (in-enum benign-cold-start)")
# Row 9: anything unmatched -> unknown -> review queue, never files.
r = classify(fi("a9", pt3=boot_fail(
failure="some entirely novel boot error nobody has classified yet")))
check(r.failure_class is FailureClass.UNKNOWN,
f"Appendix-A unmatched -> unknown (got {r.failure_class.value})")
check(r.should_file is False and r.review_queue is True,
"unknown -> should_file=False + review_queue=True (maintainer queue)")
check(r.route_as_kv_calc_bug is False,
"unknown NEVER auto-files a kv-calc bug (§6.1)")
check(r.tier is Tier.NONE_UNKNOWN,
f"unmatched decided as NONE_UNKNOWN (got {r.tier.value})")
# ---------------------------------------------------------------------------
# Cross-cutting: pt3.failure_log_excerpt ABSENT (today's shipped [E]
# schema) classifies off the bare pt3.failure string.
# ---------------------------------------------------------------------------
r = classify(fi("noexcerpt", pt3={
"point": "boot", "ok": False, "seconds": 0.0,
"failure": "torch.cuda.OutOfMemoryError: CUDA out of memory"}))
check("failure_log_excerpt" not in (read_capture_bundle(
write_bundle(tmp / "noexcerpt2", pt3={
"point": "boot", "ok": False, "seconds": 0.0,
"failure": "torch.cuda.OutOfMemoryError"})).pt3_boot),
"fixture confirms pt3.failure_log_excerpt ABSENT (shipped [E] schema)")
check(r.failure_class is FailureClass.GENUINE_OOM,
"classifies off bare pt3.failure when failure_log_excerpt ABSENT")
# ---------------------------------------------------------------------------
# Out-of-enum guard: no 7th value can ever leak. Point the classifier at a
# poisoned DB whose matcher class is an invalid 7th value -> must degrade
# to `unknown`, and EVERY result must be in the 6-enum.
# ---------------------------------------------------------------------------
poison = tmp / "poison.yml"
poison.write_text(
"schema: 1\n"
"exact_fingerprints: {}\n"
"condition_matchers:\n"
" - id: poisoned\n"
" kind: log_substring\n"
" any: ['poison-signal']\n"
" class: not-a-real-class-7th-value\n",
encoding="utf-8")
r = classify(fi("poisoned", pt3=boot_fail(
failure="this contains a poison-signal token")),
fingerprint_db_path=poison)
check(r.failure_class is FailureClass.UNKNOWN,
f"out-of-enum 7th DB class degrades to `unknown` (got "
f"{r.failure_class.value}) — no 7th value can leak")
check(r.failure_class.value in ENUM_VALUES,
"poisoned-DB result still strictly in the 6-member §6.1 enum")
# ---------------------------------------------------------------------------
# F3 — §6.1 Tier-1 fast-path (CONTRACT-2 A-i/A-ii/A-ii/A-iii). Tier-1 plugs
# IN FRONT of Tier-2: the OOM signature -> always genuine-oom, decided by
# Tier.TIER1. route_as_kv_calc_bug=True ONLY when ALL THREE inputs present
# (pt1.predicted_b_breakdown + pt3.actual.attempted_alloc_mib +
# pt3.actual.gpu_worker_reported_mib); else honest-degrade (False). pt5 >
# pt3-triple > bare precedence. classifier reads structured fields only.
# ---------------------------------------------------------------------------
PRED = {"weights_gb": 9.0, "kv_gb": 12.0, "overhead_gb": 1.5}
def write_f3_bundle(name, *, pt1_extra=None, pt3=None, pt5=None):
d = tmp / name
d.mkdir(parents=True, exist_ok=True)
pt1 = {
"schema": 1, "point": "gate", "slug": "Org/My-Model",
"confidence": "estimated-lower-bound", "raw_verdict": "wont-fit",
"terminal": "override-accepted", "profile_like": "vllm/minimal",
"hardware_sm": 8.6, "predicted_b_breakdown": None,
}
if pt1_extra:
pt1.update(pt1_extra)
arts = {
"manifest.json": mk_manifest(),
"pt1-gate.json": pt1,
"pt2-download.json": {
"point": "download", "ok": True, "files": ["model.safetensors"],
"bytes": 1, "sha_verified": True, "failure": None},
"pt3-boot.json": pt3 if pt3 is not None else {
"point": "boot", "ok": False, "seconds": 0.0,
"failure": "server did not become ready before timeout"},
"pt4-smoke.json": {
"point": "smoke",
"smoke_capability_set": ["plain-chat", "streaming"],
"results": {"plain-chat": "unsmoked", "streaming": "unsmoked"},
"partial": True, "results_detail": {}},
}
if pt5 is not None:
arts["pt5-override-capture.json"] = pt5
for nm, obj in arts.items():
(d / nm).write_text(json.dumps(obj, indent=2), encoding="utf-8")
return read_capture_bundle(d)
# (1) genuine-oom with ALL THREE inputs present -> route_as_kv_calc_bug TRUE
# + a predicted-vs-actual delta. (pt3-triple source.)
fa = write_f3_bundle("f3_all3",
pt1_extra={"predicted_b_breakdown": PRED},
pt3={"point": "boot", "ok": False, "seconds": 3.0,
"failure": "server did not become ready before timeout",
"failure_log_excerpt":
"torch.cuda.OutOfMemoryError: CUDA out of memory. Tried to "
"allocate 2.50 GiB",
"actual": {"attempted_alloc_mib": 2560,
"gpu_worker_reported_mib": 22880}})
r = classify(fa)
check(r.failure_class is FailureClass.GENUINE_OOM
and r.tier is Tier.TIER1,
f"F3 (1): OOM + all-3 -> genuine-oom via Tier-1 (got "
f"{r.failure_class.value}/{r.tier.value})")
check(r.route_as_kv_calc_bug is True,
"F3 (1): all-3-present -> route_as_kv_calc_bug=True (CONTRACT-2 "
"A-ii + §11)")
check(r.predicted_vs_actual_delta_mib == 22880 - int(round(22.5 * 1024)),
f"F3 (1): predicted-vs-actual delta = gpu_worker_peak - sum([B]) "
f"(got {r.predicted_vs_actual_delta_mib})")
check((r.tier1_inputs or {}).get("source") == "pt3+pt1",
f"F3 (1): inputs resolved from the pt3+pt1 triple "
f"(got {(r.tier1_inputs or {}).get('source')})")
# (2) genuine-oom MISSING one input (no gpu_worker peak) -> classified
# genuine-oom but route_as_kv_calc_bug FALSE (honest degrade).
fm = write_f3_bundle("f3_miss",
pt1_extra={"predicted_b_breakdown": PRED},
pt3={"point": "boot", "ok": False, "seconds": 3.0,
"failure": "timeout",
"failure_log_excerpt":
"torch.cuda.OutOfMemoryError: CUDA out of memory. Tried to "
"allocate 2.50 GiB",
"actual": {"attempted_alloc_mib": 2560,
"gpu_worker_reported_mib": None}})
r = classify(fm)
check(r.failure_class is FailureClass.GENUINE_OOM
and r.tier is Tier.TIER1,
"F3 (2): still classified genuine-oom via Tier-1 when an input "
"is missing")
check(r.route_as_kv_calc_bug is False,
"F3 (2): missing gpu_worker_reported_mib -> route_as_kv_calc_bug "
"FALSE (honest degrade, never confidently-wrong)")
check(r.should_file is True,
"F3 (2): genuine-oom still should_file=True (filed as a normal "
"issue, just NOT a kv-calc bug)")
# (3) precedence: pt5 structured fields WIN over the pt3 triple (A-iii).
# pt5 carries its own predicted_b_breakdown + actual; pt3's triple
# would be incomplete, but pt5 supplies all three -> route TRUE, and
# the resolved source is pt5.
fp5 = write_f3_bundle("f3_pt5",
pt1_extra={"predicted_b_breakdown": None},
pt3={"point": "boot", "ok": False, "seconds": 1.0,
"failure": "timeout",
"failure_log_excerpt":
"torch.cuda.OutOfMemoryError: CUDA out of memory",
"actual": {"attempted_alloc_mib": None,
"gpu_worker_reported_mib": None}},
pt5={"point": "override_capture",
"predicted_b_breakdown": PRED,
"actual": {"boot_peak_mib": 23900,
"gpu_worker_reported_mib": 23900},
"predicted_vs_actual_delta_mib": 1376,
"exit_error_summary": "torch.cuda.OutOfMemoryError: CUDA OOM",
"calibration_signal_not_validated": True})
r = classify(fp5)
check(r.failure_class is FailureClass.GENUINE_OOM
and r.tier is Tier.TIER1,
"F3 (3): OOM -> genuine-oom via Tier-1 with pt5 present")
check((r.tier1_inputs or {}).get("source") == "pt5",
f"F3 (3): A-iii precedence — pt5 structured fields WIN over the "
f"pt3 triple (got {(r.tier1_inputs or {}).get('source')})")
check(r.route_as_kv_calc_bug is True,
"F3 (3): pt5 supplies all three -> route_as_kv_calc_bug=True")
# (4) Tier-1 MISS (no OOM signature anywhere) -> falls straight through to
# the UNCHANGED Tier-2 (AWQ quant mis-load -> quant-unsupported, the
# exact F2 behaviour, byte-for-byte unaffected).
fmiss = write_f3_bundle("f3_t1miss",
pt3={"point": "boot", "ok": False, "seconds": 0.0,
"failure": "ValueError: Model QuantConfig: the AWQ weight is not "
"supported for this dtype"})
r = classify(fmiss)
check(r.tier is Tier.TIER2
and r.failure_class is FailureClass.QUANT_UNSUPPORTED,
f"F3 (4): no OOM signature -> Tier-1 misses, falls through to "
f"UNCHANGED Tier-2 (got {r.tier.value}/{r.failure_class.value})")
check(r.route_as_kv_calc_bug is False
and r.predicted_vs_actual_delta_mib is None
and r.tier1_inputs is None,
"F3 (4): a Tier-2 result carries NO Tier-1 telemetry (Tier-1 never "
"ran) — F2 behaviour byte-unchanged")
# ---------------------------------------------------------------------------
# F8-fix — real modern vLLM v0.21.0+ KV-cache-too-large phrasing. The on-rig
# F8 validator induced a GENUINE vLLM KV-cache-too-large failure: vLLM
# nightly bf610c2f raises a CLEAN `ValueError` from
# `_check_enough_kv_cache_memory` — NOT torch.cuda.OutOfMemoryError — so the
# SHIPPED classic-torch-only Tier-1 OOM signature MISSED this real, common,
# kv-calc-relevant failure (it fell through to Tier-2 -> `unknown`, Tier-1
# never fired). These lines are copied VERBATIM from a captured real
# vLLM KV-OOM log (the gpu_worker-available line + the ValueError).
# With the F8-fix the widened signature MUST fire
# Tier-1 -> genuine-oom, and with the new pt3.actual parse + a
# pt1.predicted_b_breakdown all three inputs are present -> route TRUE.
F8_REAL_EXCERPT = (
"f8d-oom-vllm | (EngineCore pid=81) INFO 05-17 05:13:55 "
"[gpu_worker.py:462] Available KV cache memory: 20.89 GiB\n"
"f8d-oom-vllm | (EngineCore pid=81) ERROR 05-17 05:13:55 "
"[core.py:1159] ValueError: To serve at least one request with the "
"models's max seq len (2000000), (22.89 GiB KV cache is needed, which "
"is larger than the available KV cache memory (20.89 GiB). Based on "
"the available memory, the estimated maximum model length is 1825488."
)
# 22.89 GiB -> 23439 MiB ; 20.89 GiB -> 21391 MiB (what [E]'s parse emits;
# the F8-fixed capture.py is what produces pt3.actual on a real bundle).
f8 = write_f3_bundle("f3_f8_real",
pt1_extra={"predicted_b_breakdown": PRED},
pt3={"point": "boot", "ok": False, "seconds": 4.0,
"failure": "server did not become ready before timeout",
"failure_log_excerpt": F8_REAL_EXCERPT,
"actual": {"attempted_alloc_mib": 23439,
"gpu_worker_reported_mib": 21391}})
r = classify(f8)
check(r.failure_class is FailureClass.GENUINE_OOM
and r.tier is Tier.TIER1,
f"F8-fix: real vLLM v0.21.0+ 'KV cache is needed, which is larger "
f"than the available KV cache memory' ValueError -> genuine-oom via "
f"Tier-1 (got {r.failure_class.value}/{r.tier.value})")
check(r.matched_rule == "tier1-oom-fastpath",
"F8-fix: real vLLM KV-OOM stamps the Tier-1 fast-path rule")
check(r.route_as_kv_calc_bug is True,
"F8-fix: real vLLM KV-OOM + all-3 inputs present -> "
"route_as_kv_calc_bug=True (the kv-calc-bug signal this fix unblocks)")
check(r.predicted_vs_actual_delta_mib == 21391 - int(round(22.5 * 1024)),
f"F8-fix: sane non-None predicted-vs-actual delta = gpu_worker "
f"available (21391) - sum([B]) (got "
f"{r.predicted_vs_actual_delta_mib})")
check((r.tier1_inputs or {}).get("source") == "pt3+pt1",
"F8-fix: inputs resolved from the pt3+pt1 triple")
# F8-fix: the older vLLM "No available memory for the cache blocks"
# phrasing must ALSO fire Tier-1 genuine-oom (defensive coverage).
r = classify(fi("f8_cacheblocks", pt3=boot_fail(
failure="ValueError: No available memory for the cache blocks. Try "
"increasing `gpu_memory_utilization` when initializing the "
"engine.")))
check(r.failure_class is FailureClass.GENUINE_OOM
and r.tier is Tier.TIER1,
f"F8-fix: 'No available memory for the cache blocks' -> genuine-oom "
f"via Tier-1 (got {r.failure_class.value}/{r.tier.value})")
# F8-fix CLASSIC NO-REGRESSION: the shipped classic
# torch.cuda.OutOfMemoryError / 'Tried to allocate' / 'peak memory' path
# STILL classifies genuine-oom via Tier-1 (the widening is purely
# additive — the classic alternative is FIRST in the signature regex).
r = classify(fi("f8_classic_noregress", pt3=boot_fail(
failure="torch.cuda.OutOfMemoryError: CUDA out of memory. Tried to "
"allocate 2.50 GiB")))
check(r.failure_class is FailureClass.GENUINE_OOM
and r.tier is Tier.TIER1,
"F8-fix NO-REGRESSION: classic torch.cuda.OutOfMemoryError STILL "
"classifies genuine-oom via Tier-1 (widening is additive)")
# F8-fix honest-degrade preserved: a NON-OOM novel error still falls
# through to unknown (the widened signature does NOT over-match).
r = classify(fi("f8_nonoom", pt3=boot_fail(
failure="RuntimeError: some entirely unrelated novel startup error")))
check(r.failure_class is FailureClass.UNKNOWN
and r.route_as_kv_calc_bug is False,
"F8-fix: a non-OOM novel error STILL -> unknown / kvbug False "
"(widened signature does not over-match; honest-degrade preserved)")
# Sweep every Appendix-A fixture: output ALWAYS ∈ the 6-enum; the kv-calc
# routing gate stays False for EVERY Appendix-A seed (the OOM rows a1/a2
# have NO Tier-1 inputs -> honest degrade; the rest are Tier-2). Only the
# OOM-signature rows (a1 Cliff-2, a2 prefill-cliff GDN) reach Tier-1; every
# non-OOM row still falls through to the unchanged Tier-2 (no F2 regress).
_OOM_ROWS = {"a1", "a2"}
for nm in ("a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9"):
rr = classify(read_capture_bundle(tmp / nm))
check(rr.failure_class.value in ENUM_VALUES,
f"{nm}: failure_class ∈ §6.1 6-enum ({rr.failure_class.value})")
if nm in _OOM_ROWS:
check(rr.tier is Tier.TIER1,
f"{nm}: OOM signature -> F3 Tier-1 fast-path (got "
f"{rr.tier.value})")
else:
check(rr.tier is not Tier.TIER1,
f"{nm}: non-OOM -> never Tier-1 (falls through to "
f"unchanged Tier-2; got {rr.tier.value})")
check(rr.route_as_kv_calc_bug is False,
f"{nm}: route_as_kv_calc_bug False (a1/a2 honest-degrade — no "
f"Tier-1 inputs; rest Tier-2)")
# ---------------------------------------------------------------------------
# v0.8.2 CONTRACT-1.1 M1 — the additive `gate_abort_reason` matcher kind +
# the conservative seed. A gate-only (schema==2) FInputGate has empty
# error text + no pt3/pt4, so it falls through every shipped [E]-bundle
# rule to the new gate rules. Only `engine-support-unknown/no-arch-row` ->
# `kernel-unsupported` (should_file=True, public-filed — the §10-R9 lever);
# `runtime-incompatible`/`disk-short`/`hard-block` -> `unknown`
# (should_file=False + review_queue=True — review-queued, NOT public-filed).
# ---------------------------------------------------------------------------
from scripts.lib.profiles.loop_input import read_gate_bundle # noqa: E402
def _gate_fi(nm, abort_reason):
d = tmp / nm
d.mkdir(parents=True, exist_ok=True)
gm = {
"schema": 2, "slug": "Org/Gate", "utc_ts": "20260518T000000Z",
"club3090_commit": "cafef00d", "outcome": "hard-block",
"abort_reason": abort_reason, "failure_class": None,
"model": "Org/Gate", "model_id": "Org/Gate",
"arch_family": None, "quant_label": None,
"topology_class": None, "topology_summary_canonical": None,
"selected_ctx": None, "kv_format": None,
"smoke_capability_set": None, "engine_pin": None,
"engine_version": None, "kv_calc_version": None,
"submission_fingerprint": None, "is_gate_only": True,
"capture_points": ["gate"],
}
gp = {
"schema": 2, "point": "gate", "slug": "Org/Gate",
"confidence": "ESTIMATED_LOWER_BOUND", "raw_verdict": None,
"profile_like": "vllm/minimal", "hardware_sm": 8.6,
"predicted_b_breakdown": None, "abort_reason": abort_reason,
"detail": "x", "is_gate_only": True,
}
(d / "manifest.json").write_text(json.dumps(gm), encoding="utf-8")
(d / "pt1-gate.json").write_text(json.dumps(gp), encoding="utf-8")
return read_gate_bundle(d)
# /no-arch-row -> kernel-unsupported, PUBLIC-FILED (should_file=True).
rg = classify(_gate_fi("g-narr", "engine-support-unknown/no-arch-row"))
check(rg.failure_class is FailureClass.KERNEL_UNSUPPORTED,
f"M1: engine-support-unknown/no-arch-row -> kernel-unsupported "
f"(the §10-R9 lever) (got {rg.failure_class.value})")
check(rg.should_file is True and rg.review_queue is False,
"M1: /no-arch-row is PUBLIC-FILED (should_file=True, NOT "
"review-queued) — it must aggregate/dedup/volume-rank")
check(rg.matched_rule == "gate-engine-support-no-arch-row",
f"M1: matched the additive gate_abort_reason rule (got "
f"{rg.matched_rule!r})")
check(rg.route_as_kv_calc_bug is False,
"M1: a gate-only bundle is NEVER a kv-calc bug (Tier-1 is F3; no "
"OOM signature on a gate bundle)")
# runtime-incompatible / disk-short / hard-block -> unknown, REVIEW-QUEUED
# (NOT public-filed) — deliberately suppressed (correct-refusal class).
for _ar in ("engine-support-unknown/runtime-incompatible",
"disk-short", "hard-block"):
rq = classify(_gate_fi(f"g-{_ar.replace('/', '-')}", _ar))
check(rq.failure_class is FailureClass.UNKNOWN,
f"M1: {_ar} -> unknown (conservative catch-all) "
f"(got {rq.failure_class.value})")
check(rq.should_file is False and rq.review_queue is True,
f"M1: {_ar} is REVIEW-QUEUED, NOT public-filed "
f"(unknown ∈ _SUPPRESSED_NEVER_FILED; should_file=False, "
f"review_queue=True — never silently dropped)")
# The raw abort_reason SURVIVES redaction into pt1-gate (H2 maintainer-
# distinguishability: a /no-arch-row vs a kernel bug must be tellable).
_h2 = _gate_fi("g-h2", "engine-support-unknown/no-arch-row")
check(_h2.pt1_gate.get("abort_reason")
== "engine-support-unknown/no-arch-row"
and _h2.abort_reason == "engine-support-unknown/no-arch-row",
"M1/H2: the raw abort_reason survives into pt1_gate (a maintainer "
"can distinguish 'add a registry row' from 'file a kernel bug')")
# §6.1-NEUTRALITY: the additive kind does NOT perturb the shipped
# schema==1 path. The SAME [E] bundle classifies byte-identically + a
# schema==1 FInput has NO pt1_gate.abort_reason so the gate rules are
# inert for it (they only fire on a gate-only bundle).
_s1 = fi("neutral-s1", pt3=boot_fail(
failure="torch.cuda.OutOfMemoryError: CUDA out of memory"))
_r1a = classify(_s1)
_r1b = classify(fi("neutral-s1b", pt3=boot_fail(
failure="torch.cuda.OutOfMemoryError: CUDA out of memory")))
check(_r1a.failure_class is FailureClass.GENUINE_OOM
and _r1a.failure_class == _r1b.failure_class
and _r1a.matched_rule == _r1b.matched_rule
and _r1a.tier == _r1b.tier,
"V1: schema==1 classification is byte-identical post-protocol-lift "
"+ the additive gate_abort_reason kind is inert for [E] bundles "
"(no pt1_gate.abort_reason -> the gate rules never fire)")
from scripts.lib.profiles.loop_input import BaseCaptureBundle # noqa: E402
check(isinstance(_s1, BaseCaptureBundle),
"V1: the schema==1 FInput classify() consumed satisfies "
"BaseCaptureBundle (the retype is a pure static change)")
# ---------------------------------------------------------------------------
# REAL on-disk .pull-captures/ bundle (a success/`partial`): classify
# returns a valid enum and does NOT misclassify as a fileable failure.
# ---------------------------------------------------------------------------
real_root = root / ".pull-captures"
real_dirs: list[Path] = []
if real_root.is_dir():
for slug_dir in sorted(real_root.iterdir()):
if not slug_dir.is_dir() or slug_dir.name.startswith("_"):
continue
for ts_dir in sorted(slug_dir.iterdir()):
if ts_dir.is_dir() and (ts_dir / "manifest.json").is_file():
real_dirs.append(ts_dir)
if not real_dirs:
print("SKIP: no real on-disk .pull-captures/ bundle (graceful)")
else:
for rd in real_dirs:
rfi = read_capture_bundle(rd)
rr = classify(rfi)
check(rr.failure_class.value in ENUM_VALUES,
f"REAL {rd.name}: classify -> valid §6.1 enum "
f"({rr.failure_class.value})")
# The one real bundle is boot-ok + all caps green/unsmoked (no
# red, no failure) — a success/`partial`. It must NOT be filed as
# a failure and must NEVER route as a kv-calc bug.
boot_ok = bool((rfi.pt3_boot or {}).get("ok"))
no_red = not any(
v == "red"
for v in ((rfi.pt4_smoke or {}).get("results") or {}).values())
if boot_ok and no_red:
check(rr.route_as_kv_calc_bug is False,
f"REAL success/partial {rd.name}: never a kv-calc bug")
check(rr.failure_class is not FailureClass.GENUINE_OOM,
f"REAL success/partial {rd.name}: NOT misclassified as "
f"genuine-oom")
# ---------------------------------------------------------------------------
if failures:
print(f"\n{len(failures)} assertion(s) failed.", file=sys.stderr)
sys.exit(1)
print("\nAll F2 §6.1 Tier-2 classifier (CONTRACT-2 / Appendix A) "
"assertions passed.")
PY
echo "test-classifier.sh OK"