REJECTION_POLICIES.md¶
Status: shipped in 0.6.0
Shipped: raise, collect, skip, log, callback, quarantine.
See Supported vs planned and the
rejection policies guide.
RowGuard Rejection Policies¶
Purpose¶
Rejection policies determine what RowGuard does after a row fails validation.
Validation always happens first. A rejection policy never changes whether a row is valid; it only determines how execution proceeds after a rejection.
Core Principle¶
Database Row
│
▼
Row Adapter
│
▼
Pydantic Validation
│
├── Accepted
└── Rejected
│
▼
Rejection Policy
Validation and rejection handling are intentionally separate concerns.
Built-in Policies¶
raise (default)¶
Stop immediately and raise RowValidationError.
Use when:
API requests
transactional reads
strict correctness
rowguard.select(
session=session,
table=users,
model=UserRead,
on_reject="raise",
)
collect¶
Continue processing and accumulate rejected rows.
result = rowguard.select(
session=session,
table=users,
model=UserRead,
on_reject="collect",
)
print(result.models)
print(result.rejected)
Best for:
audits
migrations
reporting
data quality jobs
skip¶
Discard rejected rows while recording aggregate statistics.
Useful when invalid rows are expected but should not stop processing.
Statistics should still include:
rows rejected
validation errors
rejection rate
callback¶
Invoke a user callback for every rejected row.
def on_reject(row):
...
rowguard.select(
...,
on_reject=on_reject,
)
Callbacks receive a RejectedRow, not a formatted string.
quarantine¶
Write rejected rows to a dedicated sink.
Possible sinks:
SQL table
CSV
Parquet
JSONL
Kafka
S3
Blob storage
Quarantine writers should respect redaction settings.
Policy Comparison¶
Policy |
Stops Execution |
Retains Rows |
Typical Use |
|---|---|---|---|
raise |
Yes |
Optional |
APIs |
collect |
No |
Yes |
Audits |
skip |
No |
No |
Streaming |
callback |
No |
User-defined |
Custom workflows |
quarantine |
No |
External |
Data governance |
Thresholds¶
Execution may terminate after configured limits.
Examples:
max_rejections=100
max_rejection_rate=0.02
Threshold failures should raise a dedicated execution exception that includes summary statistics.
Retry and Repair¶
Future repair workflows may be layered on top of rejection policies.
Rejected Row
│
▼
Repair Callback
│
▼
Revalidate
Repair is never implicit.
Streaming¶
Policies behave consistently during streaming.
raise: stop immediately
collect: retain until stream completes
skip: continue
callback: invoke before next row
quarantine: write before continuing
Accepted rows are yielded only after validation.
Async¶
Async APIs preserve the same semantics.
Only callback and quarantine handlers may become asynchronous.
Validation behavior is identical.
Diagnostics¶
Recommended metrics:
rows accepted
rows rejected
rejection rate
policy name
callback failures
quarantine failures
Security¶
Rejected rows may contain sensitive values.
Policies should support:
value redaction
disabled raw row retention
encrypted quarantine storage
structured logging
Testing¶
Tests should verify:
every built-in policy
thresholds
callback failures
quarantine failures
streaming
async parity
statistics
redaction
MVP Scope¶
Shipped in 0.4.0:
raise
collect
skip
statistics
diagnostics
Shipped in 0.6.0:
callback
quarantine
log
threshold support (
max_rejections,max_rejection_rate)
Deferred further:
retry queues
distributed quarantine
policy composition
conditional routing
Design Principles¶
Validation determines acceptance.
Policies determine behavior after rejection.
Policies must be deterministic.
Sync and async behavior should match.
Privacy must be configurable.
Rejection handling should remain observable.