Files
TheTomandClaude Opus 4.7 a4c59a0b05 REFRACT v0.3.2: alpha release — 4 axes, 4 subcommands, 3 backends, 9 docs
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>
2026-04-30 15:13:04 -05:00

164 lines
7.3 KiB
Markdown
Raw Permalink 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.
# REFRACT INTERPRETATION GUIDE
How to read a REFRACT report card. Targets a reader who knows quants
generally but is new to REFRACT specifically.
## Composite score
A single 0–100 number. **Higher is better.** Computed as the harmonic
mean of every axis that ran (so any single broken axis tanks the
composite — that's intentional, the framework is fail-loud).
| Band | Range | Meaning |
|-----------|--------|--------------------------------------------------|
| EXCELLENT | 90–100 | Within reference noise. Indistinguishable. |
| PASS | 80–90 | Minor drift; safe to deploy in most uses. |
| DEGRADED | 60–80 | Visible drift; audit on your workload first. |
| FAIL | 0–60 | Material quality loss; treat as broken. |
## Per-axis interpretation
Each axis has its own 0–100 score and its own band. The **Diagnosis**
block in the report card translates the per-axis pattern into plain
English. Below is the deeper "what to do about it" guide per axis.
### Axis A: Trajectory (formerly GTM)
Measures: **Token-level agreement with fp16**. Greedy-decodes N tokens
under both reference and candidate KV configs, captures token IDs at
decode time, computes prefix agreement length / candidate length.
- **EXCELLENT (90–100):** the model decodes essentially the same tokens
under both configs. KV quantization is doing nothing visible in the
short-context greedy regime.
- **PASS (80–90):** tokens diverge after 5–10 steps but the leading
context matches. Common for fine-grained quants. Safe.
- **DEGRADED (60–80):** divergence within first few tokens on most
prompts. Suspect a softmax-shift class of error: e.g. K rotation
collisions, V rotation breaking with insufficient bits.
- **FAIL (0–60):** model decodes essentially different text under
cand. The KV scheme is wrecking next-token distributions.
**Remediation when low:** try a higher-bit V cache; switch from
symmetric to asymmetric turbo; try non-rotating V. If cand and ref
diverge at step 1 (median_first_divergence near 0), the problem is
purely at the per-token distribution level.
### Axis B: KLD@D (corpus KL divergence)
Measures: **Distribution-level divergence from fp16** on natural-text
inputs, averaged per token across a corpus. Bit-exact zero on Metal
when cand == ref, so any non-zero value is real signal not float
jitter.
- **EXCELLENT (90–100, KLD < 0.05 nats):** distributions essentially
match. The candidate doesn't measurably move the model.
- **PASS (80–90, KLD ~0.05–0.2 nats):** small but measurable drift.
Most quants land here.
- **DEGRADED (60–80, KLD ~0.2–0.5 nats):** material distribution
shift. Argmax may still match (so trajectory could be high) but
the second/third choices have moved.
- **FAIL (< 60, KLD > 0.5 nats):** large divergence; the per-token
predictive distributions are fundamentally different.
**Remediation when low:** measure the noise floor first
(`--measure-floor`) to confirm the reference itself is deterministic
on your build. If floor passes, the candidate is genuinely lossy at
the distribution level. Try a higher-bit baseline (q8 instead of q4)
or a non-rotating V scheme.
**Note:** KLD@D is the best-disciplined axis. If KLD says broken,
trust it. If KLD says clean while Trajectory says broken, the bug is
likely in chat-template handling or in the test workload not the
quant itself.
### Axis C: R-NIAH (Retrieval Needle-In-A-Haystack)
Measures: **Long-context retrieval quality vs fp16**. Inserts a
sentinel fact into a long context at fractional positions; checks
whether the candidate retrieves it as well as the reference does.
Score per (length, position) cell, aggregated.
- **EXCELLENT (100):** candidate retrieves wherever the reference
does. Either the model is robust at long context OR the model can't
retrieve at all under either config (check `confidence` field).
- **PASS / DEGRADED / FAIL (< 100):** candidate loses retrieval at
cells where the reference still finds the needle. Inspect the
per-cell breakdown for the (length, position) where it breaks.
**Remediation when low:** revert to a higher-bit KV at long contexts;
or add a runtime guard that switches KV schemes by sequence length.
**Confidence:** the JSON includes `confidence: low` when
`base_acc_avg < 0.2` — the model isn't engaging retrieval at all and
R-NIAH = 100 is then a noise-floor reading. Re-check on a stronger
model or with a different needle.
### Axis D: PLAD (Perturbation-Locality Aware Drift)
Measures: **Robustness to small prompt changes vs fp16**. Generates
anchor completions, perturbs each prompt minimally (typo, casing,
punctuation, paraphrase), measures how much the candidate's output
drifts vs how much the reference's drifts.
Per-perturbation breakdown is the actionable signal:
- **typo low** → candidate is brittle to typos. Consider input
sanitization or higher-bit fallback when typos are detected.
- **case low** → candidate is sensitive to capitalization changes.
- **punct low** → candidate's output flips on terminal punctuation
(sometimes acts as an EOS-like signal).
- **paraphrase low** → candidate is sensitive to lexical substitution.
Less common; usually the most worrying signal.
**Confidence:** if a perturbation can't apply to your prompts (e.g.,
no ≥4-char words → typo skipped, no synonyms in table → paraphrase
skipped), it's listed in `skipped_perturbations` and excluded from
the band.
## Pattern recognition (Diagnosis block)
The Diagnosis block fires plain-English sentences for the most common
patterns. Some examples and what they imply:
- **"Per-token distribution is broken but high-level surfaces are
intact"** → Trajectory and KLD low, R-NIAH and PLAD intact. The
quant is producing different tokens at decode time but reasoning
and retrieval still work. Common for aggressive turbo schemes.
Likely safe if you don't depend on exact text reproduction.
- **"Long-context retrieval degraded"** → R-NIAH low, others high.
Candidate fails specifically at long context. Affects RAG,
summarization, code understanding. Unsafe for those workloads.
- **"Brittleness to small input changes"** → PLAD low, others high.
Candidate flips its output under input variations. Affects
real-user deployments where prompts have typos or slight
paraphrasing. Stress-test before shipping.
- **"Catastrophic"** → every measured axis < 60. Treat as
non-functional; revert to higher-bit config.
## Composite vs per-axis: which to trust
If composite says PASS but one axis is DEGRADED, **read the per-axis
band first**. Composite is a summary; per-axis tells you *what kind
of failure* you have. A 95 composite hides a 99/99/99/85 reality
where the model is actually brittle to perturbations.
For shipping decisions:
- All 4 axes ≥ 80 → safe
- One axis 60–80 → audit the specific surface that's degraded;
decide based on whether that surface matters to your workload
- One axis < 60 → ship only if you understand the failure and have
mitigations
- Multiple axes < 60 → don't ship
## Cross-version comparisons
Reports embed `framework_version`. Comparing scores across versions
is fine for the same model+candidate, but a "+1.5 composite" between
v0.2.0 and v0.3.0 may be partly attributable to methodology changes
(e.g., chat-template handling). Apples-to-apples requires same
version on both sides.