consilium

package
v0.14.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 18, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package consilium owns the deterministic consilium engine for the `specscore` CLI: the vote-schema types and validator, the roster resolver and validator, the gate-knob and roster config loaders for the `consilium:` block in specscore.yaml, and the gate-rule arbiter that turns a panel's votes into a deterministic verdict.

See `spec/features/cli/consilium/README.md` for the full Feature contract.

This file currently scopes the package to the Vote type and its validator (REQ:vote-schema-types-and-validation). The gate engine, roster resolution, and config loaders land in follow-on tasks.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ValidateRoster

func ValidateRoster(roster []RosterEntry) error

ValidateRoster enforces REQ:roster-validation over an already-resolved roster (defaults − exclude ∪ custom): each of the three groups (builders/customers/adversaries) MUST have ≥1 member; the total roster MUST be ≤12; no custom name may collide with a default slug (case-insensitive); and every custom entry (one carrying a Path) MUST resolve to a markdown file conforming to the custom-role contract. The first violation is returned as a single clear error naming the specific violation; a valid roster returns nil.

Types

type Denominators

type Denominators struct {
	Builders    int
	Customers   int
	Adversaries int
}

Denominators holds the per-group counts used as the consensus denominators, after high-confidence abstain exclusion (step 2).

type GateKnobs

type GateKnobs struct {
	AdversaryVetoConfidence string // high | medium | low
	CostCeiling             string // low | medium
	ComplexityCeiling       string // low | medium
	MinMedianConfidence     string // low | medium | high
	RequireAllBuilders      bool
	RequireAllCustomers     bool
}

GateKnobs is the resolved set of the six consilium gate knobs the arbiter applies (REQ:gate-knob-config-schema). Every field is populated: a value supplied by config, otherwise the strict baseline.

func LoadGate

func LoadGate(projectRoot string) (GateKnobs, error)

LoadGate reads <projectRoot>/specscore.yaml and resolves the gate knobs: the strict baseline merged knob-by-knob with any `consilium.gate` mapping. When the file does not exist, or has no `consilium.gate` mapping, the strict baseline is returned. An unknown knob key or an out-of-enum value fails with an error naming the key path (e.g. `consilium.gate.cost_ceiling`), the offending value, and the accepted enum.

func ResolveGate

func ResolveGate(projectRoot, overridePath string) (GateKnobs, error)

ResolveGate resolves the effective gate knobs the arbiter applies: the specscore.yaml-resolved baseline (LoadGate) merged knob-by-knob with an optional `--gate` override file. The override file is a YAML document with a top-level `gate:` mapping of knobs (the shape `consilium config --print-gate` emits and accepts verbatim). An empty overridePath skips the override step. Override knobs are validated with the same enum rules; violations name the override key path (e.g. `gate.cost_ceiling`).

func StrictBaseline

func StrictBaseline() GateKnobs

StrictBaseline returns the strict-baseline gate knobs applied knob-by-knob when a knob is absent from config.

type Group

type Group string

Group is one of the three fixed roster groups. The values double as the accepted enum for a custom role's `group:` key.

const (
	GroupBuilders    Group = "builders"
	GroupCustomers   Group = "customers"
	GroupAdversaries Group = "adversaries"
)

type Result

type Result struct {
	Verdict       Verdict
	RuleTrace     []string
	ExcludedVotes []string
	Denominators  Denominators
}

Result is the deterministic output of the gate engine. RuleTrace lists the rule names of the steps that fired, in evaluation order, ending in the terminal-verdict rule. ExcludedVotes lists the role slugs excluded in step 2. Denominators are the per-group counts after exclusion.

func Evaluate

func Evaluate(votes []Vote, roster []RosterEntry, knobs GateKnobs) Result

Evaluate runs the gate algorithm (REQ:gate-engine-rule-order) over the votes against the roster and knobs, producing a deterministic Result. It is a pure function: no clock, no randomness, no I/O.

Steps run in order: step 1 computes denominators; step 2 excludes high-confidence abstain votes (decrementing denominators and recording ExcludedVotes); step 3 caps the verdict at needs-human-review on any low/medium-confidence abstain (low-abstain-veto); step 4 fires adversary-veto; steps 5–13 run the approval-count and median gates.

func (Result) Marshal

func (r Result) Marshal() ([]byte, error)

Marshal renders the Result as a deterministic YAML document. The encoding is a pure function of the Result's values: fixed key order (verdict, rule_trace, excluded_votes, denominators), nil slices normalized to empty lists, and no clock/random/map-iteration input. The same Result therefore yields byte-identical output across repeated calls, runs, and processes — the property the snapshot suite gates on (AC:gate-engine-deterministic).

type RosterEntry

type RosterEntry struct {
	Name  string
	Group Group
	Path  string
}

RosterEntry is one resolved roster role: its slug name, its group, and (for custom roles only) the repo-root-relative path to its markdown file. Default roles carry an empty Path.

func ParseCustomRole

func ParseCustomRole(path string) (RosterEntry, error)

ParseCustomRole reads the markdown file at path and validates it against REQ:custom-role-markdown-contract: body-metadata `**Name:**` (matching the filename without `.md`), `**Group:**` in the three-value enum, `**Output Schema Version:** 1`; a `## Role Prompt` H2; and a `## Example Vote` H2 carrying one valid vote (parsed via ParseVotes). On success it returns the role as a RosterEntry whose Path is the input path. Any violation yields a single error naming the missing/invalid field AND the file path.

func ResolveRoster

func ResolveRoster(projectRoot string) ([]RosterEntry, error)

ResolveRoster loads <projectRoot>/specscore.yaml, parses the `consilium.roster` block, and resolves the active roster as (defaults − exclude) ∪ custom, preserving group membership. The result is an ordered list of entries: the surviving defaults in declared order, followed by custom roles in declared order. When the config file or the roster block is absent, the full 9-role default set is returned.

Resolution intentionally does NOT perform roster validation (group floors, ≤12 cap, name collisions, custom-file parsing); that is a separate task that consumes this surface.

type ValidationError

type ValidationError struct {
	// Index is the zero-based position of the offending vote in the bundle.
	Index int
	// Role is the offending vote's role slug when the entry carried one; "".
	Role string
	// Field is the offending field name (e.g. "verdict", "argument").
	Field string
	// Rule is a human-readable description of the rule that was violated.
	Rule string
}

ValidationError is the deterministic error returned by vote validation. Its message names the offending vote (by index, and role when present) and the rule violated, so the malformed-bundle ACs can string-match on both.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Error formats the validation error as `vote[<i>]<(role=<r>)>: <field>: <rule>`. The shape is stable so tests can string-match on it.

type Verdict

type Verdict string

Verdict is one of the three terminal consilium outcomes (REQ:gate-engine-rule-order).

const (
	VerdictShouldImplement    Verdict = "should-implement"
	VerdictShouldNotImplement Verdict = "should-not-implement"
	VerdictNeedsHumanReview   Verdict = "needs-human-review"
)

type Vote

type Vote struct {
	Verdict    string `yaml:"verdict"`
	Confidence string `yaml:"confidence"`
	Cost       string `yaml:"cost"`
	Complexity string `yaml:"complexity"`
	Argument   string `yaml:"argument"`
	// Role is optional metadata used only to make validation errors more
	// legible; it is not one of the five schema fields.
	Role string `yaml:"role,omitempty"`
}

Vote is one expert-panel vote. It carries exactly the five fields defined by REQ:vote-schema-types-and-validation. Role is not part of the vote schema itself; when a votes-file entry carries a `role:` key it is retained so validation errors can name the offending vote by role as well as by index.

func ParseVotes

func ParseVotes(data []byte) ([]Vote, error)

ParseVotes parses a YAML votes bundle (a list of votes) and validates every entry. On success it returns one Vote per entry with fields populated verbatim. Tolerance for malformed votes is zero: a YAML-parse failure, a missing required field, an out-of-enum verdict/confidence/cost/complexity, or an argument longer than 280 characters fails the entire bundle with a *ValidationError (or a parse error) naming the offending vote and rule. A malformed bundle never yields a partial result.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL