Policy reference

Status: draft. Policies compare answers locally. They make no service call and do not establish model accuracy or calibration.

Supported Python surface

Import the following from judgevet.policy. Signatures and docstrings are provided by the public facade and generated Python reference. Bounds are inclusive.

Name Arguments or meaning
NoulRule name, minimum=None, maximum=None
ChoiceRule name, choice, min_confidence=None
ScoreRule name, minimum=None, maximum=None, min_confidence=None
Rule Union of the three rule types.
Policy rules: nonempty ordered tuple of uniquely named typed rules.
ValidatedPolicy policy, questions: validates and snapshots constraints.
validate_policy (policy, questions) -> ValidatedPolicy; equivalent validation path.
evaluate_policy (policy, answers) -> PolicyReport; requires a validated policy.
RuleReport question, passed, detail
PolicyReport rules: ordered rule reports; derived passed is their conjunction.
PolicyError Base local error, a ValueError.
PolicyDefinitionError Invalid construction, JSON or question binding.
PolicyAnswerError Missing or malformed selected answer.

judgevet.policy_json exports parse_policy(text, questions) -> ValidatedPolicy. It decodes JSON text and validates against typed questions. It does not read files or stdin. Both facades are available from 0.7.0; these names are not root exports. See compatibility.

Construction and question validation

Names must be nonempty strings. Bounds must be finite nonnegative numbers; booleans are rejected. Noul and confidence bounds are at most 1. Noul and Score rules require at least one bound and require minimum <= maximum when both exist. Confidence can add a minimum only to Choice or Score.

Policy rejects empty rules, untyped entries and duplicate names. It copies its sequence to a tuple. Rules, policies and reports are frozen. Report constructors require unique nonempty question names, boolean outcomes and string details; aggregate reports cannot be empty.

Validation accepts a mapping of typed questions. Each selected question must exist and match the rule type. Choice labels must be strings and the required label must be present. Score criteria must be a nonempty list/tuple; each bound must fit zero through len(criteria) - 1. Rules may select a subset of questions.

ValidatedPolicy snapshots Choice labels and Score scale limits without retaining mutable question objects. Later edits to questions do not change an existing policy's constraints. Construct a new validated policy to adopt new constraints. See validation source.

Evaluation and reports

Evaluation checks every selected answer in rule order. Missing/wrong-type answers raise PolicyAnswerError. Noul probability must be finite and within 0–1. Choice confidence must be finite and within 0–1, and the selected label must belong to the snapshot. Score confidence must be finite and within 0–1; score must be finite and within the snapshotted scale. Confidence is checked even when the rule has no confidence predicate.

Extra answers are ignored. Evaluation checks selected scalars, not all probability distributions or legend metadata. Those remain the answer types' responsibility. Passing malformed values past an answer constructor does not make them valid public policy input.

For valid answers, evaluation returns every RuleReport, including after an unmet rule. detail describes comparisons. PolicyReport.passed is true only when every rule passed. A malformed later answer raises instead of returning a partial report. An unmet rule is a valid decision, not an exception. See evaluation source.

The CLI shares comparisons but retains its legacy malformed-answer checks. Public evaluation checks confidence without a confidence predicate and checks Choice/Score against the question snapshot. Do not assume the legacy CLI wrapper enforces those additional conditions. This distinction concerns malformed answers, not different threshold operators.

JSON grammar

The root object has exactly one member, rules, containing a nonempty array. Each rule has exactly question and pass. question names an existing typed question and may occur only once. pass uses exactly one matching predicate:

Question Required predicate Optional addition
Noul "noul": {"min": number, "max": number} with either or both bounds None
Choice "choice": "exact label" "confidence": {"min": number}
Score "score": {"min": number, "max": number} with either or both bounds "confidence": {"min": number}

The objects in the table are grammar fragments. Unknown fields, duplicate JSON keys, nonfinite values, boolean bounds, wrong types, empty ranges and reversed bounds are rejected. JSON null does not mean an omitted bound. The same question-relative ranges apply as for typed construction.

This complete offline example decodes one policy and compares synthetic answers. It prints nothing when the assertions pass.

from judgevet import Noul, NoulAnswer
from judgevet.policy import evaluate_policy
from judgevet.policy_json import parse_policy

policy = parse_policy(
    '{"rules":[{"question":"clear","pass":{"noul":{"min":0.8}}}]}',
    {"clear": Noul(instructions="Is the text clear?")},
)
assert evaluate_policy(policy, {"clear": NoulAnswer(0.8)}).passed
assert not evaluate_policy(policy, {"clear": NoulAnswer(0.79)}).passed

For construction and file workflows, use the Python policy guide or CLI guide. Error types are detailed in the error reference.