Skip to content

fix(VIOL-0100): wire passthrough_on_error through guard config; reject on UDF guards#768

Merged
Muizzkolapo merged 1 commit into
mainfrom
fix/viol-0100-guard-passthrough-wire-through
Jul 6, 2026
Merged

fix(VIOL-0100): wire passthrough_on_error through guard config; reject on UDF guards#768
Muizzkolapo merged 1 commit into
mainfrom
fix/viol-0100-guard-passthrough-wire-through

Conversation

@Muizzkolapo

Copy link
Copy Markdown
Owner

Summary

The passthrough_on_error guard flag was documented and already consumed by the guard evaluator and skip manager, but users could not actually set it: the guard-key allowlist rejected it at config load, and even before that the expander never forwarded it into the runtime guard dict — so the evaluator always fell back to its True default.

This wires the key end to end for SQL-style guards, on the same rails as condition/on_false:

  • Allowlist (consolidated_guard.py): admit passthrough_on_error (only).
  • Parser (GuardConfig): store it as an optional attribute (= True); from_dict extracts it with a bool check; from_string uses the default.
  • Expander (process_guard_config): forward passthrough_on_error in the SQL branch's runtime guard dict.
  • UDF guards: the UDF path always passes records through on error and has no consumer for the flag, so a non-default value on a UDF guard now raises ConfigurationError (fail loud) instead of being silently dropped.

passthrough_on_empty is intentionally left rejected — it has no runtime consumer on any path, so admitting it would deposit a dead key that changes no behavior. A test pins that it stays rejected.

Defaults are unchanged (passthrough_on_error=True); the condition/on_false flow and the semantic-error-always-bypasses rule are untouched.

Verification

  • RED first: parser round-trip and expander-forward tests failed for the right reason (key rejected at the allowlist / dropped by the expander); the passthrough_on_empty rejection test passed as a baseline.
  • GREEN after wiring: tests/core/utils/test_consolidated_guard.py + tests/unit/output/response/test_guard_passthrough_wire_through.py — 31 passed. New tests cover: parser round-trip, default-when-omitted, non-bool rejection, passthrough_on_empty stays rejected, UDF-guard fail-loud, expander SQL forward + default, and evaluator behavior (applies guard behavior when False, passes record when True) via the public evaluate() entry point.
  • No regression: tests/unit/output/response/ (137), tests/unit/workflow/managers/ (133), tests/preprocessing/ excluding a pre-existing circular-import collection quirk (234), plus the guard/evaluator/skip/parity suites — all pass.
  • ruff check clean; ruff format --check clean.

Out of scope (observed, not fixed)

  • tests/preprocessing/staging/test_source_data_protection.py fails to collect on a circular import (InitialStageContext) — reproduces on clean main, unrelated to this change.
  • Docs alignment for the passthrough_on_error example lives in a separate docs.agent-actions/ tree not in this checkout.

…t on UDF guards

The guard key allowlist rejected passthrough_on_error at load, and the
expander never forwarded it, so the value users wrote in an SQL-style
guard block never reached the evaluator, which fell back to its True
default. Admit the key to the allowlist, parse and bool-check it onto
GuardConfig, and forward it in the SQL branch of the runtime guard dict
so the evaluator and skip manager receive the user's value.

UDF-style guards have no consumer for the flag (the UDF path always
passes records through on error), so a non-default value on a UDF guard
now raises rather than being silently dropped.

passthrough_on_empty stays rejected: it has no runtime consumer on any
path, so admitting it would deposit a dead key that changes no behavior.
@Muizzkolapo Muizzkolapo merged commit 86869a9 into main Jul 6, 2026
5 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 6, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant