fix(quant): a tap is only a tap when its rig is running
Four gates, all bought with the 2026-10-29 incident: the rig's calibration boot died of an OOM, the chain's health loop expired without failing, and the pusher fed four rounds of 10M tokens (86 minutes of prefill) into RESTORED PRODUCTION, recording nothing. - run-qwen38-bf16.sh: --ngram-placement becomes a knob whose calib default is `disk` (the 95.37 GiB table pin is what starved that boot: 230.22 GiB pinned of 246, 8.06 GiB available) while kldref and score keep `ram`. calib writes .rig-boot into the tap dir and retires it on a non-zero exit, so a dead boot cannot leave the tap looking rig-authorized. - calib-push.py: refuses before the first prompt unless the marker exists, names this container, and that container is running. With the driver's existing tap-progress gate, a push can no longer spend hours feeding an endpoint that is not the rig. - qwen38-calib-window.sh: the calibration window as a gated chain — stop on a failed phase instead of falling through the health wait, bank the 336 GiB reference container into trash only when both phases exit 0 and the tap holds grams, and print the whole plan on --dry-run. - kld-gate-qwen38.sh: two-report mode (candidate vs the served payload) for the disk where the 172.8 GiB FP8 anchor cannot live, plus the laws the report always carried and the gate never read: a p99.9 tail ceiling and every by_source slice passing mean, tail and top-1. - frank-archon.md: the pipeline laws (marker, n-gram tier, three-metric acceptance) and a Files section that names the live campaign instead of the retired swift15 era. Tests: 587/0 — 13 new behavioral cases (dry-run argv, marker refusals, two-report gate math).
This commit is contained in:
1 parent
3e5a37a21f
commit
c238e32d6f
6 files changed
+523
-56
No files matched your search
+114
-50
@@ -1,44 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
# kld-gate-qwen38.sh — RUNS ON DANKSERVER (or anywhere the reports are). The campaign's
|
||||
# acceptance gate: three KLD reports against ONE reference recording, one verdict.
|
||||
# acceptance gate: one verdict from the KLD reports of the containers that ride one reference
|
||||
# recording.
|
||||
#
|
||||
# The reference is the BF16 container built from the vendor checkpoint (run-qwen38-bf16.sh
|
||||
# kldref, in the same drained window that records the calibration grams). Every scored
|
||||
# container is measured against that one recording, so the KL scale runs from 0 = the
|
||||
# checkpoint itself downward in faithfulness. Three containers ride it:
|
||||
# checkpoint itself downward in faithfulness.
|
||||
#
|
||||
# fp8.json the published FP8-native release — the achievable end of the interval
|
||||
# iq4r.json the payload frank-archon serves — the bar to beat
|
||||
# cand.json the arm under test — the subject
|
||||
# TWO MODES, because the disk decides how many anchors can exist at once:
|
||||
#
|
||||
# The FP8 number is what makes the interval absolute instead of relative: "half the gap"
|
||||
# is half of the distance between the 4-bit payload and the near-lossless release, not half
|
||||
# of an invented distance to the checkpoint. That is also why the FP8 payload is FETCHED and
|
||||
# scored, never converted: it is a second opinion about what this checkpoint tolerates, not a
|
||||
# step of the campaign. It lands LAST (disk sequencing) — by then the 335 GiB bf16 container
|
||||
# is gone, so its 172.8 GiB fits.
|
||||
# gate IQ4R.json CAND.json candidate vs the served payload
|
||||
# gate FP8.json IQ4R.json CAND.json the same, inside the absolute interval
|
||||
#
|
||||
# The law, in order of severity, on the mean KL of one slice (--slice all | a corpus source):
|
||||
# 1. KL(fp8) < KL(iq4r) the anchors are ordered. If the near-lossless
|
||||
# release does NOT sit closer to the checkpoint than
|
||||
# the 4-bit payload, the corpus, the tokenizer or the
|
||||
# boot shape is wrong and no arm number means anything.
|
||||
# 2. KL(fp8) < KL(cand) < KL(iq4r) the candidate lies strictly inside the interval —
|
||||
# outside it, something is mis-measured, not better
|
||||
# 3. KL(cand) <= KL(iq4r) - R x gap it closes at least R (--recover, default 0.5) of the
|
||||
# gap = KL(iq4r) - KL(fp8): at least half the way from
|
||||
# what is served toward the release (agreed 2026-10-27)
|
||||
# 4. top-1(cand) >= top-1(iq4r) the agreement the harness keys on does not fall
|
||||
# iq4r.json is the payload frank-archon serves — the bar to beat. When the FP8-native release
|
||||
# (172.8 GiB, fetched last because of the peak-disk law) is on disk, pass its report first:
|
||||
# "half the gap" is then half of the distance between the 4-bit payload and the near-lossless
|
||||
# release, not half of an invented distance to the checkpoint. Without it the gate still
|
||||
# answers the campaign's question — does the candidate beat what is served — and says so.
|
||||
#
|
||||
# The law, on the summary of one slice (--slice all | a corpus source):
|
||||
#
|
||||
# candidate vs served (2 reports)
|
||||
# 1. mean KL(cand) < mean KL(iq4r) the served payload is beaten on the corpus
|
||||
# 2. p99.9(cand) <= p99.9(iq4r) and the tail is no worse — a mean can hide a few
|
||||
# positions taking the whole hit
|
||||
# 3. top-1(cand) >= top-1(iq4r) the agreement the harness keys on does not fall
|
||||
# 4. every source slice passes 1-3 a win bought by regressing one distribution
|
||||
# (code, prose, tools) is not a win
|
||||
#
|
||||
# inside the interval (3 reports), laws 1-4 above (1-3 renumbered to the interval and the
|
||||
# recovery fraction, as agreed 2026-10-27) plus:
|
||||
# 5. p99.9(cand) <= p99.9(iq4r) the tail law
|
||||
# 6. every source slice passes the slice law
|
||||
#
|
||||
# Booting the containers is NOT this script's job: `run-qwen38-bf16.sh score RAD OUT.json`
|
||||
# writes the reports and owns the single engine argv (same pin, --tp 2, --kv-cache-dtype fp8,
|
||||
# same step size, --deterministic, no speculation) that makes the three numbers comparable.
|
||||
# same step size, --deterministic, no speculation) that makes the numbers comparable.
|
||||
# This script is arithmetic, so it re-runs against old reports and is testable without a GPU.
|
||||
#
|
||||
# Usage: kld-gate-qwen38.sh FP8.json IQ4R.json CAND.json [--slice NAME] [--recover F]
|
||||
# Usage: kld-gate-qwen38.sh IQ4R.json CAND.json [--slice NAME]
|
||||
# kld-gate-qwen38.sh FP8.json IQ4R.json CAND.json [--slice NAME] [--recover F]
|
||||
set -uo pipefail
|
||||
|
||||
[ "$#" -ge 3 ] || { echo "usage: kld-gate-qwen38.sh FP8.json IQ4R.json CAND.json [--slice NAME] [--recover F]" >&2; exit 2; }
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "usage: kld-gate-qwen38.sh IQ4R.json CAND.json [--slice NAME]" >&2
|
||||
echo " kld-gate-qwen38.sh FP8.json IQ4R.json CAND.json [--slice NAME] [--recover F]" >&2
|
||||
exit 2
|
||||
fi
|
||||
python3 - "$@" <<'PY'
|
||||
import json, sys
|
||||
|
||||
@@ -52,13 +61,15 @@ while i < len(a):
|
||||
else:
|
||||
files.append(a[i])
|
||||
i += 1
|
||||
if len(files) != 3:
|
||||
sys.exit("usage: kld-gate-qwen38.sh FP8.json IQ4R.json CAND.json [--slice NAME] [--recover F]")
|
||||
if len(files) not in (2, 3):
|
||||
sys.exit("usage: kld-gate-qwen38.sh IQ4R.json CAND.json [--slice NAME]\n"
|
||||
" kld-gate-qwen38.sh FP8.json IQ4R.json CAND.json [--slice NAME] [--recover F]")
|
||||
o = dict(zip(opts[0::2], opts[1::2]))
|
||||
slice_ = o.get("--slice", "all")
|
||||
recover = float(o.get("--recover", 0.5))
|
||||
if not 0.0 < recover <= 1.0:
|
||||
sys.exit(f"--recover must be in (0,1], got {recover}")
|
||||
interval = len(files) == 3
|
||||
|
||||
|
||||
def die(msg):
|
||||
@@ -66,11 +77,15 @@ def die(msg):
|
||||
raise SystemExit(2)
|
||||
|
||||
|
||||
def read(path):
|
||||
def load(path):
|
||||
try:
|
||||
d = json.load(open(path))
|
||||
return json.load(open(path))
|
||||
except Exception as e:
|
||||
die(f"cannot read the KLD report {path}: {e}")
|
||||
|
||||
|
||||
def summary(path, d):
|
||||
"""The slice this gate grades: 'all', or one corpus source."""
|
||||
if slice_ == "all":
|
||||
g = d.get("all")
|
||||
else:
|
||||
@@ -80,23 +95,25 @@ def read(path):
|
||||
f"{', '.join(sorted(d.get('by_source') or {})) or '(none)'}")
|
||||
if g is None or "kld" not in g or "top1_agreement" not in g:
|
||||
die(f"{path} has no {slice_!r} summary — wrong report version?")
|
||||
return d, g
|
||||
return g
|
||||
|
||||
|
||||
docs = {label: load(path) for label, path in
|
||||
zip(("fp8", "iq4r", "cand") if interval else ("iq4r", "cand"), files)}
|
||||
rows = []
|
||||
for label, path in zip(("fp8", "iq4r", "cand"), files):
|
||||
d, g = read(path)
|
||||
rows.append((label, path, d.get("model", "?"), g["kld"]["mean"], g["kld"]["p99_9"],
|
||||
g["top1_agreement"], g["positions"]))
|
||||
for label, path in zip(("fp8", "iq4r", "cand") if interval else ("iq4r", "cand"), files):
|
||||
g = summary(path, docs[label])
|
||||
rows.append((label, path, docs[label].get("model", "?"), g["kld"]["mean"],
|
||||
g["kld"]["p99_9"], g["top1_agreement"], g["positions"]))
|
||||
|
||||
print(f"reference: BF16 container; slice: {slice_}")
|
||||
print(f"reference: BF16 container; slice: {slice_}; "
|
||||
+ ("inside the FP8 interval" if interval else "candidate vs served (no FP8 anchor)"))
|
||||
print(f"{'':6} {'model':38} {'KL mean':>10} {'KL p99.9':>10} {'top-1':>8} positions")
|
||||
for label, path, model, kl, p999, top1, n in rows:
|
||||
print(f"{label:6} {str(model)[:38]:38} {kl:10.6f} {p999:10.4f} {100*top1:7.2f}% {n}")
|
||||
r = {label: (kl, top1) for label, _p, _m, kl, _q, top1, _n in rows}
|
||||
kl_fp8, kl_iq4r, kl_cand = r["fp8"][0], r["iq4r"][0], r["cand"][0]
|
||||
t_iq4r, t_cand = r["iq4r"][1], r["cand"][1]
|
||||
gap = kl_iq4r - kl_fp8
|
||||
r = {label: (kl, p999, top1) for label, _p, _m, kl, p999, top1, _n in rows}
|
||||
kl_cand, p_cand, t_cand = r["cand"]
|
||||
kl_iq4r, p_iq4r, t_iq4r = r["iq4r"]
|
||||
ok = True
|
||||
|
||||
|
||||
@@ -106,17 +123,64 @@ def law(n, text, passed):
|
||||
print(f" [{'PASS' if passed else 'FAIL'}] {n}. {text}")
|
||||
|
||||
|
||||
law(1, f"anchors ordered: fp8 {kl_fp8:.6f} < iq4r {kl_iq4r:.6f} (gap {gap:.6f})",
|
||||
gap > 0)
|
||||
law(2, f"candidate inside the interval: {kl_fp8:.6f} < {kl_cand:.6f} < {kl_iq4r:.6f}",
|
||||
kl_fp8 < kl_cand < kl_iq4r)
|
||||
need = kl_iq4r - recover * gap
|
||||
law(3, f"candidate closes {100*max((kl_iq4r - kl_cand)/gap, 0):.1f}% of the "
|
||||
f"{gap:.6f} gap (needs {100*recover:.0f}%, i.e. KL <= {need:.6f})"
|
||||
if gap > 0 else "gap is not positive; cannot score recovery",
|
||||
gap > 0 and kl_cand <= need)
|
||||
law(4, f"candidate top-1 {100*t_cand:.2f}% >= served iq4r top-1 {100*t_iq4r:.2f}%",
|
||||
t_cand >= t_iq4r)
|
||||
def tail_law(n):
|
||||
law(n, f"candidate KL p99.9 {p_cand:.4f} <= served iq4r {p_iq4r:.4f}",
|
||||
p_cand <= p_iq4r)
|
||||
|
||||
|
||||
# --- the slice law: every corpus source must pass the metric laws -------------
|
||||
def slice_law(n):
|
||||
"""A win that regresses one source class is not a win: check them all."""
|
||||
mine = docs["cand"].get("by_source") or {}
|
||||
theirs = docs["iq4r"].get("by_source") or {}
|
||||
if not mine or not theirs:
|
||||
law(n, "no per-source summaries to check", True)
|
||||
return
|
||||
missing = sorted(set(theirs) - set(mine))
|
||||
extra = sorted(set(mine) - set(theirs))
|
||||
if missing or extra:
|
||||
law(n, "same source slices in both reports"
|
||||
+ (f" (missing from cand: {', '.join(missing)})" if missing else "")
|
||||
+ (f" (only in cand: {', '.join(extra)})" if extra else ""), False)
|
||||
return
|
||||
bad = []
|
||||
for src in sorted(theirs):
|
||||
c, q = mine[src], theirs[src]
|
||||
worse_mean = c["kld"]["mean"] >= q["kld"]["mean"]
|
||||
worse_tail = c["kld"]["p99_9"] > q["kld"]["p99_9"]
|
||||
worse_top1 = c["top1_agreement"] < q["top1_agreement"]
|
||||
if worse_mean or worse_tail or worse_top1:
|
||||
why = ",".join(m for m, w in (("mean", worse_mean), ("p99.9", worse_tail),
|
||||
("top-1", worse_top1)) if w)
|
||||
bad.append(f"{src} ({why})")
|
||||
law(n, "every source slice passes (mean, p99.9, top-1)"
|
||||
+ (f" — regressed: {'; '.join(bad)}" if bad else ""), not bad)
|
||||
|
||||
|
||||
if interval:
|
||||
kl_fp8 = r["fp8"][0]
|
||||
gap = kl_iq4r - kl_fp8
|
||||
law(1, f"anchors ordered: fp8 {kl_fp8:.6f} < iq4r {kl_iq4r:.6f} (gap {gap:.6f})",
|
||||
gap > 0)
|
||||
law(2, f"candidate inside the interval: {kl_fp8:.6f} < {kl_cand:.6f} < {kl_iq4r:.6f}",
|
||||
kl_fp8 < kl_cand < kl_iq4r)
|
||||
need = kl_iq4r - recover * gap
|
||||
law(3, f"candidate closes {100*max((kl_iq4r - kl_cand)/gap, 0):.1f}% of the "
|
||||
f"{gap:.6f} gap (needs {100*recover:.0f}%, i.e. KL <= {need:.6f})"
|
||||
if gap > 0 else "gap is not positive; cannot score recovery",
|
||||
gap > 0 and kl_cand <= need)
|
||||
law(4, f"candidate top-1 {100*t_cand:.2f}% >= served iq4r top-1 {100*t_iq4r:.2f}%",
|
||||
t_cand >= t_iq4r)
|
||||
tail_law(5)
|
||||
slice_law(6)
|
||||
else:
|
||||
law(1, f"candidate beats the served payload: KL {kl_cand:.6f} < iq4r {kl_iq4r:.6f}",
|
||||
kl_cand < kl_iq4r)
|
||||
tail_law(2)
|
||||
law(3, f"candidate top-1 {100*t_cand:.2f}% >= served iq4r top-1 {100*t_iq4r:.2f}%",
|
||||
t_cand >= t_iq4r)
|
||||
slice_law(4)
|
||||
|
||||
print("KLD GATE " + ("PASS" if ok else "FAIL"))
|
||||
sys.exit(0 if ok else 1)
|
||||
PY
|
||||
Reference in new issue
Block a user