mirror of
https://github.com/TheTom/turboquant_plus.git
synced 2026-10-22 02:53:13 -05:00
Compressed history of v0.1.4 → v0.3.2 in one alpha-ship commit so the
framework is testable end-to-end by friends. Detailed per-version
discussion lives in refract/CHANGELOG.md.
What ships
----------
Four scoring axes vs the model's own fp16-KV reference:
- Axis A (Trajectory, v0.1.4) — decode-time token IDs via patched
llama-completion, no detokenize round-trip. Replaces the buggy
v0.1.x GTM as the default.
- Axis B (KLD@D) — corpus KL divergence, bit-exact zero on Metal
when ref==cand. Native MLX implementation in addition to the
llama-perplexity subprocess path.
- Axis C (R-NIAH, v0.2.0) — long-context retrieval at multiple
(length, position) cells. Confidence guard for low base_acc.
- Axis D (PLAD, v0.2.0) — perturbation-locality drift across
typo/case/punct/paraphrase. Skipped-perturbation handling.
Composite = harmonic mean. Bands EXCELLENT/PASS/DEGRADED/FAIL.
Four CLI subcommands:
- score — run REFRACT on a candidate KV config
- selftest — 30s preflight: binaries, flags, model probe
- compare — multi-report side-by-side
- repeatability — run N times, report stdev/range health verdict
Three backends:
- llamacpp (production) subprocess wrappers around llama.cpp
- mlx (production) native via mlx-lm; verified end-to-end
on Qwen2.5-3B-Instruct-4bit
- vllm (skeleton) interface defined; plug-in pointers
in module docstring
Reporting
---------
- Text (ANSI colour, terminal)
- JSON schema refract.report.v0.3.1 with framework_version +
environment metadata (backend, llama_cpp_commit, mlx_lm_version)
- HTML (self-contained single file) with hardware info, model
params, repro command, R-NIAH heatmap, PLAD per-perturbation bars
Discoveries from the matrix runs (all logged in CHANGELOG):
- "secret password" needle wording triggers safety refusals on
instruct models. v0.2.1 switched to neutral "rare paint color"
- Thinking-mode models burn n_predict before answering. v0.3.0 added
-rea off + auto-detect at startup
- Symmetric turbo4/turbo4 is the canonical FAIL config; framework
correctly identifies (composite ~19) on gemma-4-26B-A4B-Q8
Documentation
-------------
- README.md what + alpha banner + "where do I go" navigator
- QUICKSTART.md 0 to first PASS in 30 minutes
- INTERPRETATION.md per-axis "what to do if low" guide
- LEADERBOARD.md cross-model rankings + "ranks the quant, not the
model" disclaimer
- PITFALLS.md known traps from today's matrix runs
- LIMITATIONS.md what v0.3 explicitly does not do
- CHANGELOG.md version history with discovery stories
- MATRIX-RESULTS.md the 7-model matrix log
- examples/ 4 sample JSONs + HTML reports + README
Tests
-----
80 → 82 unit tests, all green:
- 17 trajectory tests (incl. R-NIAH/PLAD impls + 4-axis composite)
- 5 strip-noise pinning tests
- 14 unit tests (math + KVConfig)
- 8 JSON schema tests (incl. v0.3.1 framework_version field)
- 6 KLD regex tests
- 5 corpus-identity tests
- 5 tokenize-to-ids tests
- 4 command-construction tests
Verified
--------
- 7-model v0.3.0 matrix end-to-end (~2h on M5 Max 128GB)
- Llama-4 Scout extras + symmetric-turbo negative control
- MLX backend on Qwen2.5-3B-Instruct-4bit
- selftest on llamacpp (no model) and mlx (with model)
- 2-run repeatability on qwen2.5-1.5b: composite stdev = 0.00 on
Trajectory + KLD (bit-exact reproducibility on cheap axes)
Open follow-ups (v0.4)
----------------------
- vLLM backend implementation (skeleton today)
- T-Call axis (tool-call fidelity) building on v0.3 chat-template
- Bundled corpus + prompts distribution
- `refract leaderboard --in dir/ --out LEADERBOARD.md` auto-gen
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
137 lines
4.6 KiB
Python
137 lines
4.6 KiB
Python
"""v0.1.3 regression tests for report.json_report() schema layout.
|
|
|
|
Pins the v0.1.1 schema fix (composite is a scalar, not a nested dict at
|
|
top level) and the v0.1.3 schema bump.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from refract.axes.gtm import GTMResult
|
|
from refract.axes.kld import KLDResult
|
|
from refract.report import json_report
|
|
from refract.score import composite_score
|
|
|
|
|
|
def _build_minimal_report() -> dict:
|
|
gtm = GTMResult(
|
|
score=92.0,
|
|
full_match_rate=0.5,
|
|
median_first_divergence=20,
|
|
mean_prefix_agreement_length=44.0,
|
|
mean_cand_length=48.0,
|
|
mean_ref_length=48.0,
|
|
n_prompts=2,
|
|
n_tokens_each=48,
|
|
per_prompt=[
|
|
{"id": "p1", "ref": "x", "cand": "x"},
|
|
{"id": "p2", "ref": "y", "cand": "z"},
|
|
],
|
|
)
|
|
kld = KLDResult(
|
|
score=99.5, mean_kld=0.005,
|
|
ppl=6.0, rms_dp_pct=1.1, same_topp_pct=98.4,
|
|
base_path="/tmp/base.bin", chunks=32, ctx=512,
|
|
is_self_reference=False,
|
|
corpus={"path": "/tmp/wiki.raw", "size_bytes": 1234,
|
|
"sha256_head": "deadbeef", "sha256_head_bytes": 1234},
|
|
)
|
|
composite = composite_score(gtm.score, kld.score)
|
|
return json_report(
|
|
model="test.gguf",
|
|
reference_label="ctk=f16,ctv=f16",
|
|
candidate_label="ctk=q8_0,ctv=turbo4",
|
|
composite=composite, gtm=gtm, kld=kld,
|
|
)
|
|
|
|
|
|
def test_composite_is_scalar_at_top_level():
|
|
"""v0.1.1 regression: d['composite'] must be a number, not a nested dict.
|
|
v0.1 had this nested as a dict; aggregator scripts printed '{compos…' as
|
|
if it were a number."""
|
|
rep = _build_minimal_report()
|
|
assert isinstance(rep["composite"], float)
|
|
# Sanity: it's the actual harmonic mean of 92 and 99.5
|
|
assert 90 < rep["composite"] < 100
|
|
|
|
|
|
def test_band_is_string_at_top_level():
|
|
rep = _build_minimal_report()
|
|
assert isinstance(rep["band"], str)
|
|
assert rep["band"] in {"EXCELLENT", "PASS", "DEGRADED", "FAIL"}
|
|
|
|
|
|
def test_composite_detail_is_dict():
|
|
rep = _build_minimal_report()
|
|
assert isinstance(rep["composite_detail"], dict)
|
|
# gtm_score / kld_score live inside composite_detail
|
|
assert "gtm_score" in rep["composite_detail"]
|
|
assert "kld_score" in rep["composite_detail"]
|
|
|
|
|
|
def test_axes_block_present():
|
|
rep = _build_minimal_report()
|
|
assert "axes" in rep
|
|
assert "gtm" in rep["axes"]
|
|
assert "kld" in rep["axes"]
|
|
# v0.1.3: GTM block exposes the new mean_cand/mean_ref fields
|
|
assert rep["axes"]["gtm"]["mean_cand_length"] == 48.0
|
|
assert rep["axes"]["gtm"]["mean_ref_length"] == 48.0
|
|
|
|
|
|
def test_schema_is_v0_3_1():
|
|
rep = _build_minimal_report()
|
|
assert rep["schema"] == "refract.report.v0.3.1"
|
|
|
|
|
|
def test_framework_version_present():
|
|
rep = _build_minimal_report()
|
|
assert "framework_version" in rep
|
|
assert isinstance(rep["framework_version"], str)
|
|
|
|
|
|
def test_environment_block_present():
|
|
rep = _build_minimal_report()
|
|
assert "environment" in rep
|
|
assert isinstance(rep["environment"], dict)
|
|
|
|
|
|
# v0.1.4 additions: layman summary + per-axis bands/descriptions.
|
|
|
|
|
|
def test_summary_is_layman_string():
|
|
"""v0.1.4: top-level 'summary' field carries a one-line plain-English
|
|
interpretation of the score band so non-techie consumers can read the
|
|
report without grepping the paper."""
|
|
rep = _build_minimal_report()
|
|
assert isinstance(rep.get("summary"), str)
|
|
assert rep["summary"] # non-empty
|
|
# The summary's content reflects the band; pin a substring of each band
|
|
# so the prose can be edited but the contract holds.
|
|
band_to_substr = {
|
|
"EXCELLENT": "Indistinguishable",
|
|
"PASS": "Minor drift",
|
|
"DEGRADED": "Audit",
|
|
"FAIL": "broken",
|
|
}
|
|
expected = band_to_substr[rep["band"]]
|
|
assert expected.lower() in rep["summary"].lower(), (
|
|
f"summary {rep['summary']!r} does not match band {rep['band']!r}"
|
|
)
|
|
|
|
|
|
def test_axes_carry_per_axis_band():
|
|
"""v0.1.4: each axis block carries its own band, not just the
|
|
composite. Lets the layman see which axis caused a DEGRADED."""
|
|
rep = _build_minimal_report()
|
|
assert rep["axes"]["gtm"]["band"] in {"EXCELLENT", "PASS", "DEGRADED", "FAIL"}
|
|
assert rep["axes"]["kld"]["band"] in {"EXCELLENT", "PASS", "DEGRADED", "FAIL"}
|
|
|
|
|
|
def test_axes_carry_description():
|
|
"""v0.1.4: each axis block has a one-line 'description' so a layman
|
|
knows what 'KLD: DEGRADED' actually means without the paper."""
|
|
rep = _build_minimal_report()
|
|
for ax in ("gtm", "kld"):
|
|
d = rep["axes"][ax].get("description")
|
|
assert isinstance(d, str) and d, f"missing description on axis {ax}"
|