Files

5.3 KiB

name, description
name description
gguf-lora-adapter-fit-census Read-only census before applying a GGUF LoRA/adapter to a llama.cpp (or fork) endpoint: Hub metadata, declared base provenance, runtime flag support, and the behavioural probe that proves the effect.

GGUF LoRA / adapter fit census (read-only, before you promise a file to a payload)

A 3 MB adapter is a payload change: it edits the compute graph at load. Do the census before editing an endpoint's trio, and prove the EFFECT behaviourally — no metadata, card table, or health gate can see it.

1. Census the Hub repo first (no auth for public repos)

curl -sS "https://huggingface.co/api/models/<org>/<repo>?blobs=true" | python3 -c "
import json,sys; d=json.load(sys.stdin)
print(d.get('pipeline_tag'), d.get('library_name'))
print([t for t in d.get('tags',[])][:20])          # base_model / base_model:adapter rows matter
for s in d['siblings']: print(s['rfilename'], s.get('size'), (s.get('lfs') or {}).get('oid'))"
curl -sS "https://huggingface.co/<org>/<repo>/raw/main/README.md" > /tmp/card.md   # grep for --lora flags
  • base_model / base_model_relation: adapter name the pack the adapter was built for.
  • A file with lfs.oid = None is a plain git object: pin the sha256 of the Hub's bytes, not an LFS oid. Fetcher law still applies: curl -fsSL --fail-with-body, byte count, sha256, --verify-only, no resume.

2. Read the adapter's own GGUF KV section (settles provenance in one read)

Small python read of the KV pairs — no torch, no download beyond the adapter itself: magic GGUF, u32 ver, u64 n_tensors, u64 n_kv; key = u64 len + bytes; type u32 (0 u8,1 i8,2 u16,3 i16,4 u32,5 i32,6 f32,7 bool,8 str,9 array,10 u64,11 i64,12 f64); array = u32 elem_type + u64 count.

Keys worth printing: general.type (adapter), adapter.type (lora), adapter.lora_alpha, and whatever provenance the publisher wrote — e.g. PrismML/abliteration packs carry prism.abliterate.base_gguf, base_sha256, direction_row, target_layers, target_embedding, sites, basis.

Provenance is metadata, not a gate. The loader matches tensor names, not hashes, so an adapter fit against a sibling quantization of the same model still applies — which is a decision to surface to the operator, not a failure to hide. Compare base_sha256 against the sha the endpoint's own fetcher pins; if they differ, say so in the PR body, the env header and the endpoint page, and prove the effect behaviourally instead.

Two publisher facts that decide whether a fork can carry the file at all: the build it was verified on, and what it deliberately does NOT touch (an embedding rank is the usual crash — token_embd left alone is a graph constraint, not an omission).

3. Ask the runtime binary, not your memory

<llama-server> --help | grep -iE "lora|adapter"

Expect --lora FNAME, --lora-scaled FNAME:SCALE,..., --lora-init-without-apply (+ POST /lora-adapters for runtime scale). Prefer --lora-scaled <file>:<scale> as ONE argv token so a scale can never reach the engine without its file, and follow the endpoint's existing opt-out convention (the MMPROJ_FILE= shape: :-less default so an explicitly empty value means "off, on purpose"). Gate the deployer on the file's existence with the adapter's OWN fetcher named in the error text.

4. Prove the effect: refusal/behaviour probe, before AND after

The probe is not a bench, so the no-bench law does not block it — and the before half must be captured while the old shape is still live.

  • Same prompts, temperature low, both before and after; classify with a refusal-marker regex and print only the opening characters, never the generated body.
  • Budget ≥ 2 048 tokens on a thinking model. A 600-token request can be swallowed whole by the reasoning channel: content comes back empty with finish_reason: length and reasoning_content full — which reads exactly like a refusal that never happened.
  • A leading ⚠️ Disclaimer/hedge after the adapter is style, not the circuit: judge the marker sentence, not the tone.

5. Post-deploy reads (the ledger is the instrument)

  • Boot log shows llama_adapter_lora_init_impl: loading lora adapter from '<file>' and then dumps the adapter's KV block — the provenance mismatch is printed at every start, so the runbook should point at the journal instead of restating it.
  • Confirm the flag on argv: tr '\0' ' ' < /proc/$(systemctl show <svc> -p MainPID --value)/cmdline; confirm systemctl show <svc> -p DropInPaths --value is empty (a leftover bench drop-in outranks everything you just deployed).
  • Shape must be untouched by an adapter: n_slots / n_ctx_slot / KV lines unchanged, and /metrics still answering (a llama.cpp endpoint is invisible to Prometheus without --metrics).
  • Root units log to the journal; rootless podman storage is read WITHOUT sudo (sudo podman inspect sees a different storage namespace and reports "no such object").

Yields

One sentence per question: does the file exist and at what size/sha; which pack it declares as its base and whether that matches the served payload; which flag the runtime actually offers; what the before/after probe classified. Anything else is a decision for the operator, and the rollback should be one env line on a file the endpoint already loads.