Custom detectors
The Phase 2 AV ships seven built-in claim types (process_spawn,
binary_execution, network_exfil, c2_callback,
persistence_install, privesc_attempt, lateral_move, self_tamper).
Anything new is a custom detector — a claim_type string + a primary
HF binding.
1. Pick a claim_type
Use a dotted namespace if it's organisation-specific:
acme.gpu.thermal_runaway
acme.honey.token_touched
acme.payments.duplicate_charge
The server stores the claim_type verbatim and uses it as the row's
transitionType filter for retrieval.
2. Bind it to a primary HF
Add an entry to CLAIM_PRIMARY_HF in
shared/api-core/src/lib/avComposite.ts:
export const CLAIM_PRIMARY_HF: Record<string, HfId> = Object.freeze({
...
"acme.gpu.thermal_runaway": "HF14", // Propagation Velocity — resonance of temp ticks
});
Pick the operator whose mathematical shape matches your signal:
- Count-of-things → HF8 (Pattern Repetition)
- Time-decay → HF6 (Temporal Relevance)
- Cluster prior → HF12 (Network Density)
- Contradiction with prior state → HF9 (Contradiction Index)
- Severity weight → HF16 (Ethical Severity)
3. Have the agent supply the features
The agent's classify_to_hf_scores() in
apps/packages/zeq-av-agent-linux/src/main.rs reads features by name
out of the claim_payload. For a new claim_type, add a match arm:
"acme.gpu.thermal_runaway" => {
if let (Some(spikes), Some(window)) = (
features.get("temp_spikes_in_24_pulses").and_then(|v| v.as_f64()),
features.get("max_window_spikes").and_then(|v| v.as_f64()),
) {
let denom = if window > 0.0 { window } else { 1.0 };
out.push(HfScore { hf_id: "HF14".into(), value: (spikes / denom).clamp(0.0, 1.0) });
}
}
4. (Optional) Server-side feature scraping
If the agent doesn't compute the HF locally, the server falls back to
synthScoreFromPayload() in routes/av.ts. Add the feature mapping
there so server-side scraping picks the right ratio inputs.
5. Wire it in the dashboard
The 20-card spectrum in /apps/zeq-av/ shows HF1–HF20 by ID; a new
claim_type doesn't add a card, it lights up the existing HF card
matching its primary binding. No frontend change is required.
Testing your detector
Use the recipe in outputs/antivirus-phase2-shipped.md
§ "How to verify this for real" — substitute your claim_type and
features. The same curl -X POST /api/av/claim will exercise the new
detector through the full composite + trigger gate + fanout pipeline.