Test plan: Output Guardrail Engine¶
Expands on spec.md's Scope and Acceptance Criteria into concrete scenarios. Two of the three Open Questions are unresolved (grounding source/mechanism per app; shared vs. per-app tone/brand checks) — scenarios that depend on them are marked blocked rather than guessing at an answer. Threshold/which-checks-run configuration is owned by Feature 3 (Policy & Configuration Console) and reason-code delivery is owned by Feature 4 (Observability, Audit & Feedback Loop); scenarios here treat both as dependencies to verify against, not to re-test.
Scenarios¶
- Every response is screened before reaching the user.
- Given a scoped app (corehcm, superagent, edm, onb, comp, advisor, frontend) generates a response
- When the response is ready to send to the user
-
Then it passes through the output-checkpoint service first, and no path exists for a generated response to reach the user without a checkpoint decision.
-
Policy-violating content is blocked.
- Given a generated response contains content that violates configured policy (e.g., disallowed advice, prohibited content category)
- When it reaches the checkpoint
-
Then the checkpoint decision is
block, a reason code specific to the policy violated is attached, and the app shows its fallback response instead of the original. -
Hallucinated/ungrounded system-of-record claim is caught. (blocked on Open Question 1 — grounding source/mechanism per app)
- Given a response makes a factual claim about a system-of-record value (e.g., PTO balance, employment status) that contradicts or cannot be verified against the grounding source for that app
- When it reaches the checkpoint
- Then the checkpoint flags it with a hallucination reason code.
-
Cannot be finalized until Open Question 1 defines which system-of-record facts are checkable per app at launch, per spec.md's Risks table mitigation (scope checkable facts, expand incrementally).
-
Response with correct, grounded system-of-record claim passes.
- Given a response makes a factual claim about a system-of-record value that matches the grounding source
- When it reaches the checkpoint
-
Then the checkpoint decision is
allow— confirming the hallucination check doesn't over-fire on correct answers (negative path for scenario 3). -
PII or regulated data in a response is caught.
- Given a generated response contains PII or other regulated data (e.g., SSN, another employee's compensation) that should not be surfaced to the requesting user
- When it reaches the checkpoint
-
Then the checkpoint decision is
blockormodify(per policy) with a PII-specific reason code, and no unredacted regulated data reaches the user. -
Tone/brand deviation is caught. (blocked on Open Question 2 — shared vs. per-app configurable checks)
- Given a generated response deviates from the configured tone/brand standard
- When it reaches the checkpoint
- Then the checkpoint decision reflects that deviation with a tone/brand reason code.
-
Cannot be finalized until Open Question 2 resolves whether the standard is one shared check or configured per app — the scenario's precondition (which standard applies) depends on the answer.
-
Clean response passes through unmodified.
- Given a generated response has no policy violation, no ungrounded claim, no PII/regulated data, and no tone/brand deviation
- When it reaches the checkpoint
-
Then the checkpoint decision is
allowand the original response reaches the user unchanged — confirming the engine doesn't over-block, per the Risks table's over-blocking risk. -
Fallback response shown per scoped app.
- Given a checkpoint decision of
blockfor a given scoped app - When the app receives that decision
- Then it shows that app's defined fallback response, not the withheld original and not a generic/no-op failure.
-
Exact fallback copy per app is an Open Question — this scenario verifies the mechanism (block → fallback shown) works per app, not specific copy, until that's defined.
-
Reason codes are distinct per block type.
- Given checkpoint decisions across all four check types (policy, hallucination, PII, tone/brand)
- When decisions are inspected
-
Then each decision carries a reason code that identifies which check type triggered it, distinguishable from the others.
-
Every checkpoint decision is available to Feature 4.
- Given any checkpoint decision (
allow,block, ormodify) - When the decision is made
- Then it is emitted in the format/inventory Feature 4 (Observability, Audit & Feedback Loop) defines for consumption — verify against Feature 4's inventory once defined; until then, verify only that a reason-coded decision record is produced and available for logging.
- Given any checkpoint decision (
-
Checks run per Feature 3 configuration, not hardcoded.
- Given Feature 3's policy console configures thresholds and which checks are enabled for a given app/tenant
- When a response from that app/tenant is screened
- Then only the enabled checks run, at the configured thresholds — a disabled check never fires, and a threshold change (no code change) shifts detection sensitivity accordingly.
-
Service reachable by all scoped apps under
x_novaw_guardrails.- Given each scoped app (corehcm, superagent, edm, onb, comp, advisor, frontend)
- When it calls the output-checkpoint service
- Then the call succeeds and is scoped under
x_novaw_guardrails— confirming no app is left uncovered.
Out of scope for this pass¶
- Input screening (prompt injection, jailbreak, PII on the way in) — see ../input-guardrail-engine/spec.md.
- Sensitive-conversation category classification and human handoff — see ../sensitive-conversation-detection-routing/spec.md.
- Exact fallback-response copy per app — not yet defined (Open Question 3); scenario 8 tests the mechanism only.