Registry builds and canary sets
A canary family only works on the model it was selected on — neuron L13.4209.pos means nothing on different weights. This page covers the two ways to get canaries for your model:
- Registry builds (Enterprise): build a neuron registry for an open-weight model you run, with canary families selected and measured on it. The result is private to your account.
- Account canary sets (Growth and up, plus 1 set on the Developer trial): define your own family from registry neurons you can see, then measure it on your own labeled examples.
Registry builds
A build runs on a trace worker that serves the exact weights you name:
- Corpus pass. Records every MLP neuron's strongest activations over a named corpus plus each family's eval set.
- Canary families. For each family, picks up to 3 member neurons that separate positive from negative examples on a training split. It then measures precision and recall on a held-out split (alternate pairs of the eval set).
- Registry neurons. Takes the canary members plus the most selective neurons at every depth. For each one it records the top examples, the ablation effect (zero the neuron, re-run, measure the change in the predicted token's logit) and a label.
Labels come from the agent labeler when the worker has one configured (LABELER_URL). Otherwise they come from a transparent heuristic (heuristic-topk@1). Every neuron names its labeler. A neuron with no consistent pattern stays unexplained. The ablation stats and precision/recall are measured; labels are estimates.
curl $API/v1/trace/registry-builds -H "Authorization: Bearer $PRV_ENTERPRISE_KEY" -H "Content-Type: application/json" \
-d '{"hf_id":"Qwen/Qwen2.5-0.5B-Instruct","revision":"7ae55760","families":["prompt_injection"]}'
# → 202 {"build_id":"tjob_…","status":"pending","poll_url":"/v1/trace/registry-builds/tjob_…", …}
curl $API/v1/trace/registry-builds/tjob_… -H "Authorization: Bearer $PRV_ENTERPRISE_KEY"
# → {"status":"completed","result":{"model_version_id":"qwen2.5-0.5b-instruct@7ae55760-…","neurons":128,
# "labeler":"heuristic-topk@1 …","canary_sets":[{"family":"prompt_injection","member_count":2,
# "validation":{"precision":0.5625,"recall":0.9,"n":20,"grade":"fixture",…}}], …}}
| Field | |
| --- | --- |
| hf_id | A Hugging Face repo id. Dense causal LMs only (Qwen, Llama 3.x, Mistral, Gemma). |
| revision | A commit (7–40 hex). A branch like main is rejected (400): a registry describes exact weights. |
| corpus_ref | A corpus the worker ships, by name (default default). Never a URL or a path. |
| families | Canary families to select, from the worker's eval sets (default: all of them). |
| registry_size | How many neurons to describe (16–200,000, default 4,096). |
- Private by construction. The model, its neurons and its families belong to your account. They never appear in the public registry, and other accounts can't see them. If the worker's model id is already taken (for example by the public model), the build lands under a suffixed id. Your build never overwrites someone else's model. Rebuilding replaces your previous build of the same model.
- Polling. Builds take minutes on a small model on CPU and hours for an 8B registry. The API polls the worker in the background.
GET /v1/trace/registry-buildslists your builds, andGET /v1/trace/modelslists public models plus your private builds. The dashboard's Trace → Builds page shows both. - Failures are reported, not hidden. Unknown weights, a crashed corpus pass or a worker error fail the build with the reason in
error. No model row is written. - Sandbox. The fixture backend can't run a corpus pass. It replays the recorded build of the fixture model (
Qwen/Qwen2.5-0.5B-Instruct@7ae55760, measured bygen_fixtures.py) and says so inbuild_notes. Any other model fails withtrace_fixture_miss. - What it doesn't compute. Circuit edges between neurons come from attribution traces, not from a build.
Use a private build with the self-hosted sidecar: your worker reads the canaries your build selected and signs the readings.
Account canary sets
Define a family from neurons in a registry you can see, with a trip threshold per member. A reading's score is the max over members of min(1, activation / threshold), and it trips at 1.
curl $API/v1/trace/canary-sets -H "Authorization: Bearer $PRV_GROWTH_KEY" -H "Content-Type: application/json" \
-d '{"family":"wire_fraud","model":"qwen2.5-0.5b-instruct@7ae55760","members":[{"layer":16,"idx":1495,"pole":"pos","threshold":12}]}'
# → 201 {"set_id":"cs_…","kind":"account","version":1,"validation":null,"members":[…], …}
- Private. Members are visible only to your account. They are masked on every public surface, including public share links of your own traces.
- Overrides the curated family. For your readings, your set replaces a curated set with the same family name. Other accounts keep the curated one. Policies can name your family like any other (
{"fact":"canary","set":"wire_fraud",…}). - Members you can use. Public registry neurons and neurons of your own private builds. Curated canary members are masked and can't be reused. A masked neuron gets the same
400as a neuron that doesn't exist, so the API never reveals which neurons are canaries. - One set per family per model. A second set for the same family and model returns
409canary_set_exists. UsePUT /v1/trace/canary-sets/:set_idinstead. Changing members bumpsversionand clears the old precision/recall, because they no longer describe the set. GET /v1/trace/canary-setslists the curated families plus your own.DELETEremoves one of yours. A policy that still names a deleted family fails closed withcanary_unavailableunless a curated set exists.
Measure it
A new set has no stats. Measure it on labeled examples you supply, with both positives (label 1, should trip) and negatives (0):
curl $API/v1/trace/canary-sets/cs_…/validate -H "Authorization: Bearer $PRV_GROWTH_KEY" -H "Content-Type: application/json" \
-d '{"examples":[{"messages":[{"role":"user","content":"…"}],"label":1},{"messages":[…],"label":0}]}'
# → {"validation":{"precision":…,"recall":…,"n":2,"grade":"account","eval_set":"account-supplied:sha256:…"},
# "confusion":{"tp":…,"fp":…,"fn":…,"tn":…},"results":[{"index":0,"label":1,"tripped":true,"score":1}, …]}
- Every example is a real reading through the trace backend, metered as one
trace_canary_read. Any backend failure aborts the whole run, so you never get stats from a subset. - The example text is never stored or echoed. The set records only the stats and a hash of the eval set.
- Small eval sets give noisy stats.
nis always shown, so judge them accordingly. In the sandbox only the three recorded fixture prompts have readings. Anything else returns503.
Curated sets for hosted Qwen3-8B
The curated families for the hosted model come from the same pipeline, run on a GPU by an operator. The result is imported into the public registry only after its held-out stats are reviewed:
python python/trace-worker/scripts/build_registry.py --hf-id Qwen/Qwen3-8B --revision <commit> --grade curated --out qwen3-8b.json
pnpm --filter @provenance/api trace:import-registry --file qwen3-8b.json --kind curated
The importer refuses any curated family without measured validation graded curated. Until that run happens, the sandbox carries fixture-grade example families, labeled as such everywhere.
Pricing
Registry builds are Enterprise. Account canary sets are unlimited on Growth and up. A Developer account can create 1 set (canary_set, then 402 usage_limit_reached); updates and deletes are free. Validation runs and canary re-reads meter trace_canary_read against your plan's monthly allowance, then $0.002 each. See billing.