Documentation
¶
Overview ¶
Package consensus implements ensemble voting over multi-model risk verdicts (roadmap P3-33). The motivating use-case: before a critical-risk tool fires (BadUSB execute, SubGHz TX > +10 dBm, BLE spam) run a Haiku-class classifier *and* a Sonnet-class classifier; require agreement; escalate to the operator on disagreement.
The package is deliberately tiny: it reasons over the *outputs* of per-model prospective critiques, not over the model calls themselves. Orchestration lives in the agent (which already knows how to call its providers and wire the per-tier model map). The agent invokes this package once per critical-tool dispatch.
Design notes:
- Pure logic. No I/O, no Anthropic SDK, no goroutines. Trivially unit-testable.
- Risk classifications are normalised to lowercase ASCII. Partial matches are rejected — `risk=ok` and `risk=okay` count as different verdicts.
- An empty-Risk verdict is treated as "abstain" (the model failed to produce a parseable critique). If at least one non-abstain verdict exists, abstentions are excluded from the vote — the dissent payload still records them so the operator sees who abstained.
- Unanimity is the only "passing" outcome. Two-of-three is not consensus by design; the operator should know about a split.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DisagreementMessage ¶
DisagreementMessage produces a structured `<consensus-disagreement>` block for an agent's tool result when Vote returned Unanimous=false AND there are at least two non-abstain dissenting verdicts. Returns "" otherwise — the agent is responsible for treating "no message" as "no escalation needed".
The block includes one line per non-abstaining verdict so the operator can see exactly which model said what. Abstentions are reported as a tally rather than per-model lines because they don't carry a verdict to compare.
Types ¶
type Result ¶
Result is the aggregated decision. Unanimous reports whether every non-abstain verdict agreed; AgreedRisk is set only when Unanimous is true. Verdicts is always the input list (preserved for reporting). Abstentions count is exposed so the operator can see when a "Unanimous" outcome was actually a one-vote consensus because the rest of the panel abstained.
func Vote ¶
Vote tallies a slice of Verdicts.
Outcomes:
- 0 verdicts: Unanimous=false, AgreedRisk="" (no input).
- all abstain: Unanimous=false, AgreedRisk="" (no signal).
- one non-abstain: Unanimous=true, AgreedRisk=that risk (abstentions don't block; a single voter still passes).
- multiple agree: Unanimous=true, AgreedRisk=shared risk.
- multiple disagree: Unanimous=false, AgreedRisk="".
type Verdict ¶
Verdict is one model's risk classification. Model is the provider/ model identifier ("claude-haiku-4-5"); Risk is the classifier's graded judgement (one of `ok`, `unclear`, `risky` as defined by internal/agent's ProspectiveCritique). Critique is the raw JSON or prose the model returned, preserved so the operator-facing disagreement message can show source-of-truth excerpts on each path.