Files
club-3090/scripts/tests/test-dedup.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

690 lines
31 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# test-dedup.sh — v0.8.0 [F] STEP F5 (club-3090 #147).
#
# Contract test for CONTRACT-4: the §6.3 canonical-tuple-hash dedup +
# bounded label scheme + collision-safe submit path. The test IS the spec;
# the code is fixed to it. NO live Docker / GPU / network and NO real `gh`:
# every `gh` invocation goes through an INJECTED mock `gh_runner`. Fixture
# capture dirs are built in a tmp tree (byte-exact [E] schema, parsed via
# F1's read_capture_bundle for realism, classified via F2/F3's classify).
#
# Coverage (every CONTRACT-4 / Codex-r1 H3+H4 / §6.1 assertion as a
# failing-then-passing check):
# * effective_dedup_hash is 12 hex; substitutes the CLASSIFIER's
# failure_class (NOT the manifest null) into the §6.3 7-tuple; two
# FInputs differing on ANY of the 7 dims -> different hash (Codex-r1
# H3: no dimension droppable).
# * bounded labels ONLY: exactly {loop:dedup-<12hex>, class:<enum>,
# arch:<sanitized>}; NO raw model/engine/kvcalc/topo label; class in
# the 6 §6.1 enum; arch sanitized + length-capped (Codex-r1 H4).
# * submit with a mocked gh_runner: (a) no existing issue -> opens new
# (labels + body has the full 7-tuple json); (b) existing issue body
# tuple MATCHES -> +1 comment, no new issue; (c) existing issue same
# loop:dedup- label but body tuple MISMATCHES (simulated sha12
# collision) -> does NOT +1, opens new (the collision safeguard);
# (d) gh missing/fails -> spools _dedup-queue/<hash>.json, returns
# cleanly, never raises.
# * filing policy: benign-cold-start -> not filed, not spooled-as-issue;
# unknown -> _review-queue/ not the tracker; only should_file=True
# dedups/files; F5 never emits a kv-calc-bug filing.
# * real on-disk capture under .pull-captures/ (>=2 exist): build
# FInput+classify+dedup with a mock gh returning "no existing issue"
# -> opens exactly one issue with a valid bounded label set + a body
# 7-tuple that round-trips (parse back == effective_dedup_tuple).
# * import-time safety: importing dedup then kv-calc --calibration is
# still Overall: 22/22 (100%).
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 hashlib
import json
import re
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 ( # noqa: E402
FInput,
read_capture_bundle,
)
from scripts.lib.profiles.classifier import ( # noqa: E402
ClassificationResult,
FailureClass,
Tier,
classify,
)
from scripts.lib.profiles import dedup as D # noqa: E402
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 capture.py; parsed via F1 for
# realism — same discipline as test-classifier.sh / test-trust-pipeline.sh).
# ---------------------------------------------------------------------------
def mint_fingerprint(m: dict) -> str:
parts = [
m["model"], m["club3090_commit"], m["topology_summary_canonical"],
str(m["quant_label"]), m["kv_calc_version"],
str(m["engine_version"]), m["utc_ts"], m["outcome"],
]
h = hashlib.sha256()
h.update("\x1f".join(str(p) for p in parts).encode("utf-8"))
return h.hexdigest()
def mk_manifest(**over) -> dict:
m = {
"schema": 1,
"slug": "Org/My-Model",
"utc_ts": "20260517T000000Z",
"submission_fingerprint": "PLACEHOLDER",
"model": "Org/My-Model",
"quant_label": "BFloat16",
"arch_family": "LlamaForCausalLM",
"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)
if m["submission_fingerprint"] == "PLACEHOLDER":
m["submission_fingerprint"] = mint_fingerprint(m)
return m
def write_bundle(d: Path, *, manifest=None, pt3=None, pt4=None) -> Path:
d.mkdir(parents=True, exist_ok=True)
man = manifest if manifest is not None else mk_manifest()
arts = {
"manifest.json": man,
"pt1-gate.json": {
"schema": 1, "point": "gate", "slug": man["slug"],
"confidence": "estimated-lower-bound",
"raw_verdict": "fits-clean", "terminal": "confirm→proceed",
"profile_like": "vllm/minimal", "hardware_sm": 8.6,
"predicted_b_breakdown": None,
},
"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": 12.0,
"failure": "torch.cuda.OutOfMemoryError: CUDA out of memory",
"failure_log_excerpt":
"torch.cuda.OutOfMemoryError: CUDA out of memory. "
"Tried to allocate 2048 MiB",
},
"pt4-smoke.json": pt4 if pt4 is not None else {
"point": "smoke", "smoke_capability_set": [],
"results": {}, "partial": False, "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())
repo_root = Path(tempfile.mkdtemp()) # isolated .pull-captures spool root.
# ---------------------------------------------------------------------------
# Mock gh_runner — ZERO network / `gh`. Records argv; returns scripted
# GhResult objects (the real seam: D.GhResult / D.GhRunner).
# ---------------------------------------------------------------------------
class MockGh:
def __init__(self):
self.calls: list[list[str]] = []
self.list_response: str = "[]" # gh issue list --json stdout.
self.list_ok: bool = True
self.comment_ok: bool = True
self.create_ok: bool = True
self.create_stdout: str = (
"https://github.com/noonghunna/club-3090/issues/4242"
)
self.unavailable: bool = False # simulate gh-missing.
def __call__(self, argv):
argv = list(argv)
self.calls.append(argv)
if self.unavailable:
return D.GhResult(False, 127, "", "gh not found (mock)")
if argv[:2] == ["issue", "list"]:
return D.GhResult(self.list_ok,
0 if self.list_ok else 1,
self.list_response if self.list_ok else "",
"" if self.list_ok else "list failed")
if argv[:2] == ["issue", "comment"]:
return D.GhResult(self.comment_ok,
0 if self.comment_ok else 1, "",
"" if self.comment_ok else "comment failed")
if argv[:2] == ["issue", "create"]:
return D.GhResult(self.create_ok,
0 if self.create_ok else 1,
self.create_stdout if self.create_ok else "",
"" if self.create_ok else "create failed")
if argv[:2] == ["label", "create"]:
return D.GhResult(True, 0, "", "")
return D.GhResult(True, 0, "", "")
def oom_classification(fi: FInput) -> ClassificationResult:
"""Real F2/F3 classify on an OOM bundle -> genuine-oom (should_file
True). Asserted, so the test fails loudly if the classifier drifts."""
cl = classify(fi)
assert cl.failure_class is FailureClass.GENUINE_OOM, cl.failure_class
assert cl.should_file is True
return cl
# ===========================================================================
# 1. effective_dedup_hash: 12 hex; classifier's failure_class substituted
# (NOT the manifest null); all 7 dims in the hash (Codex-r1 H3).
# ===========================================================================
b_oom = write_bundle(tmp / "oom")
fi = read_capture_bundle(b_oom)
cl = oom_classification(fi)
eff_t = D.effective_dedup_tuple(fi, cl)
eff_h = D.effective_dedup_hash(fi, cl)
check(re.fullmatch(r"[0-9a-f]{12}", eff_h) is not None,
f"effective_dedup_hash is exactly 12 lowercase hex (got {eff_h!r})")
# F1's pre-classification tuple has failure_class == manifest null (None);
# the EFFECTIVE tuple substitutes the classifier's value at index 5.
f1_tuple = fi.dedup_tuple()
check(f1_tuple[5] is None,
"F1 dedup_tuple()[5] (failure_class) is the manifest null (pre-class)")
check(eff_t[5] == "genuine-oom",
f"effective tuple substitutes the CLASSIFIER's failure_class at [5] "
f"(got {eff_t[5]!r}, not the manifest None)")
check(eff_t[0] == f1_tuple[0] and eff_t[1] == f1_tuple[1]
and eff_t[2] == f1_tuple[2] and eff_t[3] == f1_tuple[3]
and eff_t[4] == f1_tuple[4] and eff_t[6] == f1_tuple[6],
"every OTHER dim is taken verbatim from F1's normalized tuple "
"(single-sourced normalization; only [5] differs)")
# Byte-exact F1 convention: sha256("\x1f".join(str(p)))[:12].
manual = hashlib.sha256(
"\x1f".join(str(p) for p in eff_t).encode("utf-8")
).hexdigest()[:12]
check(eff_h == manual,
f"effective_dedup_hash uses F1's EXACT \\x1f+sha256[:12] convention "
f"(loop_input.py:227-228) — proxy reuse matches the manual hash "
f"({eff_h} == {manual})")
# Differing on a NON-failure_class manifest dim must change the hash.
DIM_OVERRIDES = {
"model": {"model": "Org/Other", "model_id": "Org/Other",
"slug": "Org/Other"},
"quant_label": {"quant_label": "AWQ"},
"arch_family": {"arch_family": "Qwen3MoeForCausalLM"},
"kv_calc_version": {"kv_calc_version": "kvcalc-v0.8.0+deadbeefcafe"},
"engine_version": {"engine_pin": "vllm/vllm-openai:nightly-zzz",
"engine_version": "vllm/vllm-openai:nightly-zzz"},
"topology_class": {"topology_class": "2x24576MiB"},
}
for i, (dim, over) in enumerate(DIM_OVERRIDES.items()):
bo = write_bundle(tmp / f"dim_{i}", manifest=mk_manifest(**over))
fo = read_capture_bundle(bo)
co = oom_classification(fo)
ho = D.effective_dedup_hash(fo, co)
check(ho != eff_h,
f"differing on §6.3 dim `{dim}` -> DIFFERENT hash "
f"(Codex-r1 H3: no dimension droppable) ({ho} != {eff_h})")
# And the failure_class (7th dim, classifier-supplied) also changes it:
# same bundle, a DIFFERENT classifier class -> different hash.
cl_kernel = ClassificationResult(
failure_class=FailureClass.KERNEL_UNSUPPORTED, tier=Tier.TIER2,
fingerprint="0" * 12, should_file=True, route_as_kv_calc_bug=False,
review_queue=False, error_substring="x", matched_rule="seed",
)
check(D.effective_dedup_hash(fi, cl_kernel) != eff_h,
"differing on the classifier's failure_class (the 7th dim) -> "
"DIFFERENT hash (the §6.1 mislabel safeguard)")
# ===========================================================================
# 2. Bounded labels ONLY (Codex-r1 H4): exactly
# {loop:dedup-<12hex>, class:<enum>, arch:<sanitized>}; NO raw
# model/engine/kvcalc/topo label.
# ===========================================================================
labels = D.label_set(eff_h, cl, fi)
check(len(labels) == 3, f"exactly 3 labels (got {labels})")
ldedup = [x for x in labels if x.startswith("loop:dedup-")]
lclass = [x for x in labels if x.startswith("class:")]
larch = [x for x in labels if x.startswith("arch:")]
check(len(ldedup) == 1
and re.fullmatch(r"loop:dedup-[0-9a-f]{12}", ldedup[0]),
f"the dedup label is loop:dedup-<12hex> (got {ldedup})")
ENUM = {c.value for c in FailureClass}
check(len(lclass) == 1 and lclass[0].split(":", 1)[1] in ENUM,
f"class: label value is one of the 6 §6.1 enum (got {lclass})")
check(len(larch) == 1
and re.fullmatch(r"arch:[a-z0-9-]+", larch[0])
and len(larch[0].split(":", 1)[1]) <= D._ARCH_LABEL_VALUE_CAP,
f"arch: label is slug-sanitized + length-capped (got {larch})")
RAW_FORBIDDEN = ("model:", "engine:", "kvcalc:", "topo:", "topology:")
check(not any(x.startswith(p) for x in labels for p in RAW_FORBIDDEN),
"NO raw model:/engine:/kvcalc:/topo: label (those live in the body)")
# A long/awkward arch is still bounded + sanitized.
b_longarch = write_bundle(
tmp / "longarch",
manifest=mk_manifest(arch_family="Some::Weird/Arch With Spaces!!" * 5),
)
fi_la = read_capture_bundle(b_longarch)
cl_la = oom_classification(fi_la)
labs_la = D.label_set(D.effective_dedup_hash(fi_la, cl_la), cl_la, fi_la)
arch_la = [x for x in labs_la if x.startswith("arch:")][0]
check(re.fullmatch(r"arch:[a-z0-9-]+", arch_la)
and len(arch_la.split(":", 1)[1]) <= D._ARCH_LABEL_VALUE_CAP,
f"a long/awkward arch is sanitized + capped (got {arch_la!r})")
# bootstrap_labels: idempotent, gh-guarded, only the 6 class:* values.
mg0 = MockGh()
bs = D.bootstrap_labels(gh_runner=mg0)
check(set(bs.keys()) == ENUM and all(bs.values()),
"bootstrap_labels creates exactly the 6 bounded class:* labels "
"(gh_runner-guarded, --force idempotent)")
check(all(c[:2] == ["label", "create"] and "--force" in c
for c in mg0.calls),
"every bootstrap gh call is `label create --force` (idempotent)")
mg0.unavailable = True
bs2 = D.bootstrap_labels(gh_runner=mg0) # must NOT raise.
check(all(v is False for v in bs2.values()),
"bootstrap_labels with gh unavailable reports not-ok, NEVER raises")
# ===========================================================================
# 3. submit() with a mocked gh_runner.
# ===========================================================================
# (a) no existing issue -> opens new; labels + body 7-tuple json.
mg = MockGh()
mg.list_response = "[]"
r = D.submit(fi, cl, repo_root=repo_root, gh_runner=mg)
check(r.action is D.DedupAction.OPENED and r.reason == "opened-new",
f"(a) no existing issue -> OPENED (got {r.action.value}/{r.reason})")
create_call = [c for c in mg.calls if c[:2] == ["issue", "create"]]
check(len(create_call) == 1, "(a) exactly one `issue create` call")
cc = create_call[0]
for lab in labels:
check(lab in cc, f"(a) new issue carries bounded label {lab!r}")
body_arg = cc[cc.index("--body") + 1]
parsed_body = D.parse_body_tuple(body_arg)
check(parsed_body is not None
and [str(x) for x in parsed_body]
== [str(x) for x in D.effective_dedup_tuple(fi, cl)],
"(a) new-issue body carries the FULL canonical 7-tuple json that "
"round-trips to effective_dedup_tuple")
check(set(r.labels) == set(labels),
"(a) result.labels == the exact bounded label set")
# (b) existing issue, body tuple MATCHES -> +1 comment, no new issue.
match_body = D.build_issue_body(fi, cl)
mg2 = MockGh()
mg2.list_response = json.dumps([{"number": 99, "body": match_body}])
r2 = D.submit(fi, cl, repo_root=repo_root, gh_runner=mg2)
check(r2.action is D.DedupAction.PLUSONE
and r2.reason == "plusone-body-verified" and r2.issue_number == 99,
f"(b) body-tuple MATCH -> PLUSONE on #99 "
f"(got {r2.action.value}/{r2.reason}/{r2.issue_number})")
check(any(c[:2] == ["issue", "comment"] for c in mg2.calls)
and not any(c[:2] == ["issue", "create"] for c in mg2.calls),
"(b) +1 via `issue comment`; NO `issue create` (no new issue)")
ccm = [c for c in mg2.calls if c[:2] == ["issue", "comment"]][0]
check(D._PLUSONE_MARKER in ccm[ccm.index("--body") + 1],
"(b) the +1 comment carries the stable machine-parseable marker")
# (c) existing issue, SAME loop:dedup- label but body tuple MISMATCHES
# (simulated sha12 collision) -> does NOT +1, opens new.
fi_other = read_capture_bundle(
write_bundle(tmp / "collide",
manifest=mk_manifest(model="Org/Totally-Different",
model_id="Org/Totally-Different",
slug="Org/Totally-Different"))
)
cl_other = oom_classification(fi_other)
collide_body = D.build_issue_body(fi_other, cl_other) # DIFFERENT 7-tuple.
mg3 = MockGh()
# The candidate is returned under THIS hash's label (simulating a sha12
# collision: same loop:dedup-<hash> label, different body tuple).
mg3.list_response = json.dumps([{"number": 7, "body": collide_body}])
r3 = D.submit(fi, cl, repo_root=repo_root, gh_runner=mg3)
check(r3.action is D.DedupAction.OPENED and r3.reason == "opened-new",
f"(c) sha12 collision (label hit, body tuple MISMATCH) -> OPENED "
f"new, does NOT +1 (got {r3.action.value}/{r3.reason})")
check(not any(c[:2] == ["issue", "comment"] for c in mg3.calls)
and any(c[:2] == ["issue", "create"] for c in mg3.calls),
"(c) collision safeguard: NEVER +1 on a hash-label match alone; "
"body-tuple mismatch -> open new, no comment")
check(D.body_tuple_matches(collide_body, fi, cl) is False
and D.body_tuple_matches(match_body, fi, cl) is True,
"(c) body_tuple_matches: True only on a full 7-tuple equality")
# (d) gh missing/fails -> spool _dedup-queue/<hash>.json; never raises.
mg4 = MockGh()
mg4.unavailable = True
r4 = D.submit(fi, cl, repo_root=repo_root, gh_runner=mg4)
check(r4.action is D.DedupAction.SPOOLED
and r4.reason.startswith("gh-degraded"),
f"(d) gh unavailable -> SPOOLED (got {r4.action.value}/{r4.reason})")
expected_spool = (repo_root / ".pull-captures" / "_dedup-queue"
/ f"{eff_h}.json")
check(r4.spool_path == expected_spool and expected_spool.is_file(),
f"(d) spooled to .pull-captures/_dedup-queue/{eff_h}.json")
spooled = json.loads(expected_spool.read_text())
check(spooled["kind"] == "would-be-issue"
and spooled["dedup_hash"] == eff_h
and set(spooled["labels"]) == set(labels)
and D.parse_body_tuple(spooled["body"]) is not None,
"(d) spooled payload is a replayable would-be issue (labels + body "
"7-tuple)")
# gh failing on the list step (ok=False, not missing) also spools.
mg4b = MockGh()
mg4b.list_ok = False
r4b = D.submit(fi, cl, repo_root=repo_root, gh_runner=mg4b)
check(r4b.action is D.DedupAction.SPOOLED,
"(d) gh `issue list` non-zero exit also degrades to SPOOLED "
"(never raises / blocks)")
# gh failing on the create step (after a clean list) also spools.
mg4c = MockGh()
mg4c.list_response = "[]"
mg4c.create_ok = False
r4c = D.submit(fi, cl, repo_root=repo_root, gh_runner=mg4c)
check(r4c.action is D.DedupAction.SPOOLED,
"(d) gh `issue create` failure degrades to SPOOLED (never raises)")
# ===========================================================================
# 4. Filing policy (§6.1 acceptance verbatim).
# ===========================================================================
# benign-cold-start -> NOT filed, NOT spooled-as-issue (SUPPRESSED).
cl_benign = ClassificationResult(
failure_class=FailureClass.BENIGN_COLD_START, tier=Tier.TIER2,
fingerprint="0" * 12, should_file=False, route_as_kv_calc_bug=False,
review_queue=False, error_substring="cold start", matched_rule="seed",
)
mgb = MockGh()
rb = D.submit(fi, cl_benign, repo_root=repo_root, gh_runner=mgb)
check(rb.action is D.DedupAction.SUPPRESSED
and rb.reason == "benign-suppressed",
f"benign-cold-start -> SUPPRESSED (got {rb.action.value})")
check(mgb.calls == [],
"benign-cold-start: NO gh I/O at all (not filed)")
check(not (repo_root / ".pull-captures" / "_dedup-queue"
/ f"{rb.dedup_hash}.json").is_file()
or rb.spool_path is None,
"benign-cold-start: NOT spooled-as-issue (§6.1 acceptance)")
# unknown -> _review-queue/ spool, NOT the tracker.
cl_unknown = ClassificationResult(
failure_class=FailureClass.UNKNOWN, tier=Tier.NONE_UNKNOWN,
fingerprint="0" * 12, should_file=False, route_as_kv_calc_bug=False,
review_queue=True, error_substring="???", matched_rule=None,
)
mgu = MockGh()
ru = D.submit(fi, cl_unknown, repo_root=repo_root, gh_runner=mgu)
check(ru.action is D.DedupAction.REVIEW_QUEUED
and ru.reason == "unknown-review-queued",
f"unknown -> REVIEW_QUEUED (got {ru.action.value})")
check(mgu.calls == [], "unknown: NO gh I/O (never the issue tracker)")
rq = (repo_root / ".pull-captures" / "_review-queue"
/ f"{ru.dedup_hash}.json")
check(ru.spool_path == rq and rq.is_file(),
f"unknown -> spooled to .pull-captures/_review-queue/ (NOT the "
f"tracker, NOT a kv-calc bug)")
rqp = json.loads(rq.read_text())
check(rqp["kind"] == "review-queue",
"unknown review-queue spool is marked kind=review-queue")
# only should_file=True dedups/files (the genuine-oom path above did).
check(cl.should_file is True and r.action is D.DedupAction.OPENED,
"only should_file=True classes dedup-or-file (genuine-oom OPENED)")
# F5 NEVER emits a kv-calc-bug filing: even a route_as_kv_calc_bug=True
# classification is deduped as a normal failure issue (kv-calc-bug is
# F3-Tier-1's calibration signal, a DIFFERENT pipeline F5 does not touch).
cl_kvbug = ClassificationResult(
failure_class=FailureClass.GENUINE_OOM, tier=Tier.TIER1,
fingerprint="0" * 12, should_file=True, route_as_kv_calc_bug=True,
review_queue=False, error_substring="oom",
matched_rule="tier1-oom-fastpath",
predicted_vs_actual_delta_mib=512,
)
mgk = MockGh()
mgk.list_response = "[]"
rk = D.submit(fi, cl_kvbug, repo_root=repo_root, gh_runner=mgk)
check(rk.action is D.DedupAction.OPENED,
"route_as_kv_calc_bug=True still just OPENS a normal deduped "
"failure issue (F5 NEVER files a kv-calc bug)")
ckk = [c for c in mgk.calls if c[:2] == ["issue", "create"]][0]
joined = " ".join(ckk).lower()
check("kv-calc-bug" not in joined and "calibration bug" not in joined,
"F5's filed issue is NOT a kv-calc-bug filing (boundary held)")
# ===========================================================================
# 4b. v0.8.2 CONTRACT-1.1 — F5 protocol lift (V1 RED-LINE).
#
# * a real schema==1 bundle -> identical effective_dedup_hash /
# effective_dedup_tuple PRE/POST the protocol retype (byte-identity);
# * the FENCED `dedup.py` `FInput.dedup_hash(_EffProxy())` unbound-class
# idiom STILL produces F1's byte-exact serialization (NOT "tidied");
# * a schema==2 gate-only FInputGate flows through F5 via the protocol
# (effective hash deterministic + STABLE with null topology —
# CONTRACT-1.1; review-queued, NOT public-filed for `unknown`).
# ===========================================================================
from scripts.lib.profiles.loop_input import ( # noqa: E402
BaseCaptureBundle,
read_gate_bundle,
)
# (a) schema==1 byte-identity: the effective tuple/hash are a pure function
# of F1's normalized tuple + the classifier class — pinned so a
# protocol-lift regression fails LOUDLY.
_fi_id = read_capture_bundle(write_bundle(tmp / "id-s1"))
_cl_id = oom_classification(_fi_id)
_et1 = D.effective_dedup_tuple(_fi_id, _cl_id)
_eh1 = D.effective_dedup_hash(_fi_id, _cl_id)
_et2 = D.effective_dedup_tuple(read_capture_bundle(tmp / "id-s1"), _cl_id)
_eh2 = D.effective_dedup_hash(read_capture_bundle(tmp / "id-s1"), _cl_id)
import hashlib as _hl2 # noqa: E402
_exp_et = list(_fi_id.dedup_tuple())
_exp_et[5] = "genuine-oom"
_exp_eh = _hl2.sha256("\x1f".join(str(p) for p in _exp_et)
.encode("utf-8")).hexdigest()[:12]
check(_et1 == _et2 == tuple(_exp_et) and _eh1 == _eh2 == _exp_eh,
f"V1 RED-LINE: schema==1 effective_dedup_tuple/hash byte-identical "
f"+ pinned ({_exp_eh}) — the protocol lift is a pure static retype")
check(isinstance(_fi_id, BaseCaptureBundle),
"V1: the schema==1 FInput F5 consumes satisfies BaseCaptureBundle")
# (b) the FENCED unbound-class idiom: effective_dedup_hash MUST equal F1's
# OWN dedup_hash() of the substituted tuple (proves dedup.py:~277
# still reuses FInput.dedup_hash unbound, NOT finput.dedup_hash() which
# would hash the unsubstituted fc=None tuple).
class _Probe:
def dedup_tuple(self):
return _et1
from scripts.lib.profiles.loop_input import FInput as _FI # noqa: E402
check(D.effective_dedup_hash(_fi_id, _cl_id)
== _FI.dedup_hash(_Probe()), # type: ignore[arg-type]
"V1 RED-LINE: effective_dedup_hash reuses F1's UNBOUND dedup_hash on "
"the SUBSTITUTED tuple (the dedup.py fence holds — NOT tidied to "
"finput.dedup_hash() which would hash the fc=None tuple)")
# Negative control: hashing the UN-substituted tuple (fc=None) differs —
# the exact silent-corruption the fence prevents.
check(D.effective_dedup_hash(_fi_id, _cl_id) != _fi_id.dedup_hash(),
"V1 RED-LINE: the substituted hash != F1's fc=None hash (a 'tidy' "
"to finput.dedup_hash() WOULD silently corrupt + defeat the §6.1 "
"mislabel safeguard — proven divergent)")
# (c) a schema==2 gate-only FInputGate flows through F5 via the protocol.
_gd = tmp / "f5-gate"
_gd.mkdir(parents=True, exist_ok=True)
_gman = {
"schema": 2, "slug": "Org/Gate", "utc_ts": "20260518T000000Z",
"club3090_commit": "cafef00d", "outcome": "hard-block",
"abort_reason": "engine-support-unknown/no-arch-row",
"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": "engine-support-unknown/no-arch-row",
"detail": "x", "is_gate_only": True,
}
(_gd / "manifest.json").write_text(json.dumps(_gman), encoding="utf-8")
(_gd / "pt1-gate.json").write_text(json.dumps(_gp), encoding="utf-8")
_fg = read_gate_bundle(_gd)
_clg = classify(_fg) # /no-arch-row -> kernel-unsupported, should_file
check(_clg.failure_class is FailureClass.KERNEL_UNSUPPORTED
and _clg.should_file is True,
"V1: gate-only /no-arch-row classifies kernel-unsupported "
"(public-filed) through the protocol")
_egh1 = D.effective_dedup_hash(_fg, _clg)
_egh2 = D.effective_dedup_hash(read_gate_bundle(_gd), _clg)
check(re.fullmatch(r"[0-9a-f]{12}", _egh1) is not None
and _egh1 == _egh2,
f"V1: gate-only effective_dedup_hash is 12-hex + DETERMINISTIC with "
f"NULL topology (str(None)=='None' — the L3 fold; got {_egh1})")
# unknown gate bundle -> REVIEW-QUEUED (no public issue, but a spool).
(_gd2 := tmp / "f5-gate-rq").mkdir(parents=True, exist_ok=True)
_g2m = dict(_gman); _g2m["abort_reason"] = "disk-short"
_g2p = dict(_gp); _g2p["abort_reason"] = "disk-short"
(_gd2 / "manifest.json").write_text(json.dumps(_g2m), encoding="utf-8")
(_gd2 / "pt1-gate.json").write_text(json.dumps(_g2p), encoding="utf-8")
_fg2 = read_gate_bundle(_gd2)
_clg2 = classify(_fg2)
_rq_gh = MockGh()
_rq = D.submit(_fg2, _clg2, repo_root=repo_root, gh_runner=_rq_gh)
check(_clg2.failure_class is FailureClass.UNKNOWN
and _rq.action is D.DedupAction.REVIEW_QUEUED
and _rq.spool_path is not None
and _rq_gh.calls == [],
f"V1: gate-only disk-short -> unknown -> REVIEW-QUEUED spool "
f"(NOT a public issue; ZERO gh I/O — filing-policy returns before "
f"any gh call) (action={_rq.action})")
# ===========================================================================
# 5. REAL on-disk capture(s) under .pull-captures/ (>=2 exist).
# Build FInput + classify + dedup with a mock gh returning "no existing
# issue" -> opens exactly one issue with a valid bounded label set + a
# body 7-tuple that round-trips. NO real gh.
# ===========================================================================
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)
# `.pull-captures/` is gitignored runtime state — populated only after a
# real on-rig pull, ALWAYS absent on a fresh clone / in CI / after cleanup.
# The real-data invariant is that any captures present round-trip; their
# EXISTENCE is not a CI precondition. Skip (never fail) when absent; the
# round-trip assertions below run on whatever IS present.
if real_dirs:
print(f"real-data: round-tripping {len(real_dirs)} on-disk "
f".pull-captures/ bundle(s)")
else:
print("real-data: SKIP — no on-disk .pull-captures/ corpus "
"(gitignored runtime state; expected absent in CI / fresh "
"clone). Round-trip assertions run only on present bundles.")
for rd in real_dirs:
rfi = read_capture_bundle(rd)
rcl = classify(rfi)
# Use a classification that should_file so the submit path exercises
# the open/dedup branch (the real captures are `partial` successes the
# classifier may map to unknown/benign; force a fileable class so we
# exercise the OPEN path deterministically — the real-data check here
# is that the canonical tuple round-trips, not the classifier verdict).
rcl_file = ClassificationResult(
failure_class=FailureClass.GENUINE_OOM, tier=Tier.TIER1,
fingerprint=rcl.fingerprint, should_file=True,
route_as_kv_calc_bug=False, review_queue=False,
error_substring=rcl.error_substring,
matched_rule="tier1-oom-fastpath",
)
mgr = MockGh()
mgr.list_response = "[]" # no existing issue.
rr = D.submit(rcl_file and rfi, rcl_file, repo_root=repo_root,
gh_runner=mgr)
check(rr.action is D.DedupAction.OPENED,
f"REAL {rd.name}: mock 'no existing issue' -> opens exactly one "
f"issue (got {rr.action.value})")
creates = [c for c in mgr.calls if c[:2] == ["issue", "create"]]
check(len(creates) == 1,
f"REAL {rd.name}: exactly ONE issue create call")
exp_labels = D.label_set(D.effective_dedup_hash(rfi, rcl_file),
rcl_file, rfi)
check(set(rr.labels) == set(exp_labels)
and all(any(p in lab for p in ("loop:dedup-", "class:", "arch:"))
for lab in rr.labels)
and not any(lab.startswith(("model:", "engine:", "kvcalc:",
"topo:")) for lab in rr.labels),
f"REAL {rd.name}: a valid bounded label set "
f"({sorted(rr.labels)})")
cbody = creates[0][creates[0].index("--body") + 1]
rt = D.parse_body_tuple(cbody)
check(rt is not None
and [str(x) for x in rt]
== [str(x) for x in D.effective_dedup_tuple(rfi, rcl_file)],
f"REAL {rd.name}: body 7-tuple round-trips to "
f"effective_dedup_tuple (no real gh; mocked)")
# ===========================================================================
if failures:
print(f"\n{len(failures)} assertion(s) failed.", file=sys.stderr)
sys.exit(1)
print("\nAll F5 §6.3 canonical-tuple-hash dedup (CONTRACT-4) "
"assertions passed.")
PY
echo "test-dedup.sh OK"