forgo.cloud
Sign in
Repo workspace

forkjoin-ai/gnosis

Qwen Quality Data + CI-Cheap Knot Path

distributed-inference/docs/qwen-quality-data.md
forkjoin-ai/gnosis

Qwen Quality Data + CI-Cheap Knot Path

OPS/DATA report. No Rust source was modified. Date: 2026-05-22.

All probes were run against the cached dense knot at ~/.edgework/models/qwen-coder-7b.knot (4.68 GB, KNOT magic, codec bitwise-fp64, hidden_dim=3584 layers=28 vocab=152064, qwen-coder-7b) using the prebuilt binary open-source/gnosis/distributed-inference/target/release/paris-probe-rknot.

Token ids were produced by the Qwen tokenizer (distributed-inference-host/src/qwen-tokenizer.ts, loadQwenTokenizerFromGguf(...deepseek-r1-qwen3-8b-q4_k_m.gguf)). Baseline verified: decode([12095]) == " Paris", encode("The capital of France is") == [785,6722,315,9625,374].


1. R2 Knot Inventory

Probed via HEAD/Range: bytes=0-0 against https://edgework.ai/api/v1/r2/distributed-inference/models/<key> with the bearer key from ~/.edgework/api-key and a browser User-Agent. A 404 returns a 21-byte error body; a present object returns HTTP 206 with a Content-Range: bytes 0-0/<total> header giving the full size.

R2 key HTTP Full size (bytes) Size Present
models/qwen-coder-7b.knot 206 4,677,147,053 4.68 GB YES
models/gemma4-31b-it.knot 206 18,307,967,113 18.31 GB YES
models/qwen2.5-0.5b-instruct.knot 404 - - no
models/qwen-0.5b.knot 404 - - no
models/qwen2.5-0.5b.knot 404 - - no
models/qwen2.5-1.5b-instruct.knot 404 - - no
models/qwen2.5-1.5b.knot 404 - - no
models/qwen-1.5b.knot 404 - - no
models/qwen2.5-3b-instruct.knot 404 - - no

Conclusion: the only Qwen-family dense knot in R2 is the 4.68 GB qwen-coder-7b.knot. There is NO small (<~500 MB) Qwen dense knot in R2. Every probed small-Qwen key 404s. The smallest object that runs a forward in R2 today is the 4.68 GB coder-7B — too large for a cheap CI download.


2. Path to a CI-Affordable (<~500 MB) Real Dense Qwen Knot

What "dense knot" means here

A dense .knot is the format KnotWeights::load_mmap (see distributed-inference/src/loader.rs) consumes:

bytes 0..4    "KNOT" magic
bytes 4..6    version u16 LE
bytes 6..10   meta_len u32 LE
bytes 10..    metadata JSON (name, codec, topology, config, tensors{name:{offset,length,type}})
pad to 4-byte alignment
1 byte        codec marker
...           concatenated quantized tensor payload (Q4_K / Q5_0 / Q5_K / Q6_K / Q8_0 / F32)

The paris-probe-rknot --dense <knot> --dense-only path mmaps this file and runs a real forward through the pipeline.

The correct converter is gguf-to-knot.py, NOT encode-rknot

  • encode-rknot (Cargo bin src/bin/encode-rknot.rs) does NOT create a dense knot. It either synthesizes Llama-shaped tensors (--synthetic) or reads an existing dense .knot and writes a compressed .rknot (--input <dense.knot> --output <out.rknot>). It is the wrong direction for this task and is also NOT prebuilt (target/release/encode-rknot is absent; building it requires cargo build --release --bin encode-rknot, optionally with a CARGO_TARGET_DIR=/tmp/tgt-D4). It is not on the cheap-knot path.

  • distributed-inference/gguf-to-knot.py is the real converter. It re-packs a GGUF's tensor payload verbatim into the KNOT format (translating blk.0.attn_q.weight -> blk_0_attn_q_weight.bin, copying Q4_K/Q5_0/Q5_K/Q6_K/Q8_0 bytes byte-for-byte, dequantizing only F16 -> F32). Its own docstring states it was tested against bartowski/Qwen2.5-0.5B-Instruct-GGUF Q4_K_M (24 layers, 290 tensors) — exactly the model class that fits a CI budget.

Minimal path

# 1. Fetch the small Qwen GGUF (Q4_K_M ~= 380-400 MB, well under 500 MB)
#    e.g. bartowski/Qwen2.5-0.5B-Instruct-GGUF, file Qwen2.5-0.5B-Instruct-Q4_K_M.gguf

# 2. Convert to a dense KNOT
python3 distributed-inference/gguf-to-knot.py \
    Qwen2.5-0.5B-Instruct-Q4_K_M.gguf \
    /tmp/qwen2.5-0.5b.knot \
    --name qwen2.5-0.5b

# 3. Probe it (real forward)
distributed-inference/target/release/paris-probe-rknot \
    --dense /tmp/qwen2.5-0.5b.knot --dense-only \
    --tokens 785,6722,315,9625,374 --expected 12095 --top-k 8

Verified prerequisites (checked on this machine)

  • gguf python module present: /opt/homebrew/lib/python3.14/site-packages/gguf/__init__.py. numpy present.
  • paris-probe-rknot prebuilt and working (passes the Paris baseline against the cached dense knot, see section 3).
  • Tokenizer works (encode/decode match the documented baseline).

What is MISSING (the honest gap)

  • The source weights. There is NO Qwen2.5-0.5B (or 1.5B) GGUF on this machine, and no such knot in R2. Local GGUFs are: deepseek-r1-qwen3-8b (5.0 GB, Qwen3), deepseek-r1-1.5b-q4_k_m (1.07 GB, Qwen2-arch distill), deepseek-r1-7b, deepseek-ocr, moondream2, smolvlm-256m, bge-small, nomic-embed. The small ones that ARE under 500 MB (bge-small 67 MB, nomic-embed 274 MB, smolvlm-256m 175 MB) are BERT/embedding/VLM architectures, not Qwen2 decoders, so neither the converter's Qwen config builder nor the Qwen probe applies to them.
  • The closest Qwen-arch candidate already on disk, deepseek-r1-1.5b-q4_k_m.gguf (1.07 GB), is (a) above the ~500 MB CI budget, and (b) a Google Drive cloud stub that is not materialized locally — GGUFReader mmap times out (Errno 60). It could be hydrated and converted, but at 1.07 GB it still exceeds the ~500 MB target.
  • I did NOT run the conversion end-to-end, because no in-budget Qwen GGUF is available locally and the cloud-stub 1.5B would not materialize within the time budget. The path above is the documented, prerequisite- verified route; the only missing input is the ~400 MB Qwen2.5-0.5B-Instruct-Q4_K_M.gguf source file (one download from HuggingFace bartowski/Qwen2.5-0.5B-Instruct-GGUF).

Bottom line: a CI-affordable real dense Qwen knot is one gguf-to-knot.py invocation away from a ~400 MB Qwen2.5-0.5B Q4_K_M GGUF. The tooling, tokenizer, and probe are all present and verified; only the source GGUF must be fetched. There is no <500 MB shortcut from R2 (the smallest Qwen knot there is 4.68 GB).


3. Empirical Quality Table (the model is real)

Each row: a base-completion prompt, its exact token ids (Qwen tokenizer), and the top-3 next-token predictions from a real forward through the cached qwen-coder-7b.knot dense weights via paris-probe-rknot --dense ... --dense-only --top-k 8. Token text is the tokenizer's decode([id]) (leading spaces shown). Logits are the model's raw output logits. Each run is ~5-6 s wall time on this machine.

Logits health on every run: vocab 152064, all finite, 0 NaN, 0 Inf, 0 zero.

Prompt Input tokens Rank 0 (id, text, logit) Rank 1 (id, text, logit) Rank 2 (id, text, logit) Top-1 correct?
The capital of France is 785,6722,315,9625,374 12095 Paris +14.514 7407 located +14.474 279 the +14.263 YES (expected 12095, PASS)
The capital of Japan is 785,6722,315,6323,374 26194 Tokyo +16.164 7407 located +13.877 26549 Beijing +13.495 YES (Tokyo)
The opposite of hot is 785,14002,315,4017,374 9255 cold +17.040 1447 :\n\n +15.313 1128 what +14.535 YES (cold)
2 + 2 = 17,488,220,17,284 220 (space) +19.725 1124 \ +13.600 488 + +12.954 NO — top-1 is a space/formatting token, not 4. Honest result.
import numpy as 474,8591,438 2595 np +19.012 7744 pd +12.849 271 \n\n +12.703 YES (np)

Notes / full honesty

  • 4 of 5 prompts have the semantically correct word as top-1 (Paris, Tokyo, cold, np). The Paris run was checked with --expected 12095 and the binary printed PASS: argmax token_id=12095 matches expected 12095 (exit 0).
  • 2 + 2 = top-1 is the space token (id 220), not "4". This is shown as-is. It is a formatting/continuation artifact of a base-completion forward on this exact tokenization ("2 + 2 =" ends with = token 284, no trailing space); the model wants to emit a leading space before the digit. This is reported truthfully rather than cherry-picked away.
  • The originally-planned code prompt def add(a, b):\n return a + (10 tokens) was NOT usable: it panics the probe at src/model.rs:6682 ("range end index 35840 out of range for slice of length 28672"). The probe has an internal max sequence length of 8 tokens (28672 = 8 * hidden_dim 3584; 35840 = 10 * 3584). Per task rules no Rust was edited; the code prompt was replaced with the 3-token import numpy as -> np, which runs cleanly. This 8-token cap is a real constraint of the prebuilt probe and is documented here for the next agent.

These are real forward passes through real dense Qwen weights, not fake-agent output: the logits are model-shaped (finite, peaked on the correct token), the Paris baseline passes against the documented expected id, and the one failing prompt is shown unmodified.