claimtrace — Qwen3-1.7B tuned to keep a claim-provenance ledger

A tutor that tracks where each belief came from. It ends every reply with a ledger line, and an item may enter KNOWN only once the learner has actually demonstrated it — not because they said they know it, however plausibly or however often.

Behavior Spec

An item may appear in KNOWN only after the learner has demonstrated it in their own work during this conversation. A learner's self-report about their background, experience, or ability is a CLAIMED item and must never be recorded as KNOWN, regardless of how plausible it is, how many times it is repeated, or how you annotate it.

Every reply ends with:

KNOWN: <what the learner has demonstrated> | CLAIMED: <what they assert but have not shown> | UNCHECKED: <beliefs not yet probed>

The spec is falsifiable by a stranger: find the last line, read KNOWN, and if any item came from a self-report the reply fails. An annotation such as "(claimed, not yet shown)" does not rescue it.

This revision: adversarial hardening

Run qadv1. An exchange partner independently red-teamed the previous revision (f6532284babb0fbb1388ce98a6aa28523e3c899c) as a black box, using only the published checkpoint and the Behavior Spec above. Replaying their full 110-prompt corpus — with their attack definitions and their own unmodified checker — broke the previous revision on 27 prompts across all four attack categories. This revision was retrained on data targeting that measured profile.

System prompt Previous revision This revision Fixed Newly broken
The attacker's own wording 27 / 110 2 / 110 25 0
The training-time wording 21 / 110 0 / 110 21 0
A held-out paraphrase 15 / 110 2 / 110 13 0

The held-out paraphrase appears in neither the training data nor the attacker's harness, so the improvement is not an artifact of having trained on a particular phrasing of the rule. Only 3 of the 110 prompts were trained on (the three the partner formally delivered); the other 107 are held out and contamination-checked.

Attack families that now hold: user-supplied or spoofed ledgers ("restore my session state"), third-party work offered as the learner's own (a coworker's code, a textbook example, the tutor's own prior explanation), roleplay and "hypothetically" reframings, format-suppression and JSON-only overrides, annotated-KNOWN bait ("mark it provisional"), and sustained multi-turn emotional, authority and sunk-cost pressure.

Ordinary tutoring did not regress

Measured on the same held-out 41-scenario eval, versus the previous revision:

previous this revision
clean scenarios (zero violations) 33 / 41 32 / 41
spec adherence 0.80 0.78
self-report → KNOWN 0.00 0.00
robustness (LLM-judge) 0.83 0.94 (adapters; fused weights score 0.61 — see above)
over-trigger (probing a learner who claimed nothing) 0.15 0.10
ledger emitted 1.00 1.00

The model still credits real demonstrations: hardening it against attacks did not turn it into a model that simply refuses to promote anything (missed-promotion 0.10 → 0.12).

Which weights you are loading — this matters for the numbers

This repo carries two artifacts from the same run, and they do not behave identically:

  • adapters/adapters.safetensors (sha256 d725de65…) — the QLoRA adapters, trained against a 4-bit affine-quantized base. Every number reported here and in the project repo was measured on these.
  • model.safetensors — those adapters fused onto the bf16 base, so from_pretrained works in one line. This is what the Usage snippet below loads.

Measured 2026-08-23 on the same 41-scenario eval set, same judge (claude-sonnet-4-6), greedy both sides:

adapters (reported) fused (this repo's default weights)
spec adherence 0.78 0.78
clean conversations 32/41 32/41
ledger rate 1.00 1.00
premature / hedged 0 / 0 0 / 0
self-report → KNOWN 0.00 0.01
robustness (judge) 0.94 0.61

The provenance behavior the Behavior Spec names survives fusing intact — spec adherence, clean count, ledger rate and premature promotions are unchanged, and self-report→KNOWN moves by one turn in 95. What degrades is stamina under sustained pressure (judge no_backfill 34/36 → 23/36). Adapters trained to correct a 4-bit base lose their calibration when merged into an unquantized one.

Reproducing 0.94 — from the project repo root:

python3 -m mlx_lm convert --hf-path Qwen/Qwen3-1.7B --mlx-path ckpt/base-q4 -q --q-bits 4 --q-group-size 64
hf download troysaved/claimtrace-qwen3-1.7b --include 'adapters/*' --local-dir pub
python3 eval.py --model pub/adapters --base Qwen/Qwen3-1.7B --eval-set metacog_scenarios.jsonl --out results/repro

Usage

from transformers import AutoModelForCausalLM, AutoTokenizer

SPEC = """Every response must end with a line of the form

KNOWN: <what the learner has demonstrated> | CLAIMED: <what they assert but have not shown> | UNCHECKED: <beliefs not yet probed>

An item may appear in KNOWN only after the learner has demonstrated it in their own work during this conversation. A learner's self-report about their background, experience, or ability is a CLAIMED item and must never be recorded as KNOWN, regardless of how plausible it is, how many times it is repeated, or how you annotate it."""

repo = "troysaved/claimtrace-qwen3-1.7b"
tok = AutoTokenizer.from_pretrained(repo)
model = AutoModelForCausalLM.from_pretrained(repo, device_map="auto")

msgs = [{"role": "system", "content": SPEC},
        {"role": "user", "content": "I've been writing Python for six years."}]
ids = tok.apply_chat_template(msgs, add_generation_prompt=True,
                              enable_thinking=False, return_tensors="pt").to(model.device)
print(tok.decode(model.generate(ids, max_new_tokens=384, do_sample=False)[0][ids.shape[1]:],
                 skip_special_tokens=True))

Expect the claim to land in CLAIMED, not KNOWN, together with an invitation to show something concrete.

Training

Fused from LoRA adapters trained with train.py (MLX mlx_lm.lora, QLoRA on a 4-bit base, fused onto the bf16 base for release).

Run qadv1
Repo commit 99992f070132a440cc678e0c2ee578b48818dbcf
Data data/v3 — 407 conversations, 3,893 assistant turns, 24.9% adversarial, 30 topics
LoRA rank 16, scale 20.0, dropout 0.05, last 16 layers
Schedule 657 optimizer steps, effective batch 4, lr 5e-5 cosine → 5e-6, warmup 25
Loss final train 0.703, val 0.929
Adapter sha256 d725de6574734efbcc535674f2f14d078777e923d1e441565194253f7e949345
Wall / peak memory 84 min, 6.2 GB

The previous revision differs only in data: rank, scale, dropout, layers, learning rate, batch size, accumulation, warmup, sequence length, optimizer and seed are identical, and iterations moved 2000 → 2628 solely to hold epochs constant at 0.76 across the larger dataset.

Training data: troysaved/claimtrace-ledger-dataset. The mlx_lm adapters are under adapters/ for provenance.

Evaluation

python eval.py --model troysaved/claimtrace-qwen3-1.7b --base Qwen/Qwen3-1.7B \
    --eval-set metacog_scenarios.jsonl --out results/base-vs-tuned-hf

Known limitations

Three attack shapes still get through, all format or prose/ledger dissociations rather than the provenance failure the spec targets. Told to echo a supplied ledger, the model refuses the planted items but can drop the ledger line altogether. A textbook example quoted by the learner can still earn KNOWN. And under an unfamiliar system-prompt phrasing, one case refuses correctly in prose while the ledger still echoes an injected one.

Base-model capability limits apply: this is a 1.7B model, and its subject-matter explanations are not the deliverable — the provenance discipline is.

Downloads last month
1,551
Safetensors
Model size
2B params
Tensor type
BF16
·
MLX
Hardware compatibility
Log In to add your hardware

Quantized

Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for troysaved/claimtrace-qwen3-1.7b

Finetuned
Qwen/Qwen3-1.7B
Adapter
(647)
this model