Menu

#188 tests: assert the objective guardrail's rule-reduction loop is exhaustively raise-only

closed
nobody
2026-08-02
2026-07-30
Anonymous
No

Originally created by: fu351

What

The raise-only invariant on the pairwise primitive combine() (src/doberman/engine/decision_engine.py:93) is already exhaustively covered by tests/unit/test_verdict_ordering.py (a hypothesis-based property test plus a full VerdictxVerdict matrix, including commutativity and never-de-escalates checks). What's not covered by an exhaustive test is the actual production reduction loop that chains it: ObjectiveGuardrail.evaluate() (src/doberman/engine/objective.py), which folds every built-in rule's GuardrailResult through combine() one at a time. tests/unit/test_objective_guardrail.py only checks a handful of hand-picked rule combinations, not an exhaustive sweep.

Difficulty: level-3

A new test in tests/unit/ that builds a small set of stub Guardrail-shaped rules (each returning a fixed Verdict/Risk), sweeps every combination via itertools.product over a small Verdict list (2-3 stub rules is enough), runs them through ObjectiveGuardrail(rules=...), and asserts the final verdict/risk is never lower than max() over the stub verdicts/risks. Must not change combine(), ObjectiveGuardrail, or any built-in rule — this issue only adds a test.

Starting files

  • src/doberman/engine/objective.pyObjectiveGuardrail.evaluate() (the reduction loop under test).
  • tests/unit/test_objective_guardrail.py — existing hand-picked-rule tests; extend or sit alongside this file.
  • tests/unit/test_verdict_ordering.py — read first: this already exhaustively covers pairwise combine(), so don't duplicate it — this issue targets the loop, not the primitive.

Acceptance criteria

  • [ ] New test asserts the guardrail's combined output verdict/risk is never below max() of the stub rules' individual verdicts/risks, across every combination the itertools.product sweep covers.
  • [ ] Test does not modify combine(), ObjectiveGuardrail, or any built-in rule.
  • [ ] Existing behaviour unchanged (no test weakened, no output format broken)
  • [ ] ruff check . && ruff format --check . and lint-imports pass
  • [ ] pytest passes

How to validate

pytest tests/unit/test_objective_guardrail.py -v

Out of scope

  • Do not touch combine(), max_verdict(), or max_risk() in decision_engine.py.
  • Do not add hypothesis as a new dependency — it's already in the dev extra if you want it, but a plain itertools.product loop is enough here.

Notes for contributors

New here? Start with CONTRIBUTING.md. Issues are labelled level-1 (docs only) through level-10 (new subsystem) — pick one at your level and climb. Comment to claim an issue before starting.

Related

Tickets: #221
Tickets: #227

Discussion

  • Anonymous

    Anonymous - 2026-07-30

    Originally posted by: jasperdingg

    Hi, I would love to work on this issue!

     
  • Anonymous

    Anonymous - 2026-08-02

    Ticket changed by: fu351

    • status: open --> closed
     

Log in to post a comment.