TaxPreFlight
TheTaxPreFlight class routes a transaction intent to the guards required for its action. Every intent must declare a supported action and include a complete, verifiable claim for that action. TaxPreFlight fails closed: it blocks execution whenever the payload is missing required fields, contains non-numeric or non-finite values, or references an unsupported action.
TaxPreFlight is fail-closed. An intent that is empty, not a dict, uses an unsupported action, or does not contain a complete verifiable claim is blocked by default — it never silently passes through.Supported actions
Every intent must include anaction field. TaxPreFlight normalizes the action (trims whitespace, lowercases, and replaces spaces with underscores) before routing. If the action is missing, not a non-empty string, or not in the supported set, the intent is blocked with a report that lists every supported action.
The following legacy action names are accepted and canonicalized automatically:
Fail-closed routing
audit_transaction returns allowed=False whenever routing cannot produce a complete verifiable claim. The three blocking conditions are:
- Empty or invalid payload
- Unsupported action
- Incomplete claim
action field and an empty checks_run list when the intent was rejected before any guard executed.
Intent fields reference
audit_transaction returns a report with the following fields:
boolean
true only when every selected guard passes. Treat any false as a hard block.string | null
The canonical action the intent resolved to (for example,
"hire"). When the caller submits an unsupported action, this echoes back the raw value they sent; when the payload is entirely missing or empty, it is null.string[]
One or more human-readable block reasons when
allowed is false.string[]
Names of the guards that actually executed (for example,
["worker_classification"]). Empty when the intent was rejected before any guard ran.string[]
Checks that were not executed for this action — either guards that weren’t selected because their trigger fields were absent, or known gaps (checks not yet implemented for the action). For example,
action="hire" reports payroll_arithmetic, withholding_legality, reciprocity, and filing_obligations as known gaps; action="pay_invoice" reports itc_eligibility, gst_split, and rcm_applicability. Use this list to decide which follow-up guards or human reviews are still required before execution.string[]
Optional advisory messages emitted by guards (for example, required TDS deduction amounts).
Redacting block reasons in untrusted contexts
report["blocks"] contains human-readable diagnostics that may echo back fields from the original intent — including worker facts, nexus sales figures, remittance purposes, or vendor service types. Treat these strings as internal-only. Log them to your audit trail. Do not render them verbatim in end-user surfaces, demo output, or any context where a downstream consumer could infer protected payroll or customer data.
In example and demo scripts bundled with qwed-tax (examples/verify_tax_expansion.py), outcomes are printed as high-level pass/fail only and verification details are intentionally redacted:
Supported actions
Every intent must setaction to one of the supported values below. Actions are normalized (trimmed, lowercased, spaces converted to underscores) before routing, and the listed aliases are accepted for backwards compatibility.
Any other
action (including missing, empty, or non-string values) is blocked with a message listing the supported actions.
Required fields per action
Each action requires a complete claim shape. If any listed field is missing,null, or empty, the transaction is blocked before guards run — no guard is invoked with partial inputs.
For
trade_tax and corporate_action, at least one of the claim shapes above must be fully present. Providing trigger fields for a claim but omitting any of its required fields is treated as an incomplete claim and fails closed. Startup valuation (corporate_action) additionally only runs when investment_round == "convertible_note"; other rounds are blocked with an explicit message.Numeric inputs must be finite
Guards that work with money —RemittanceGuard and TDSGuard — reject non-numeric, NaN, and infinite values. The surrounding audit_transaction call surfaces these as block reasons so an upstream LLM cannot smuggle through a malformed number.
TDS advisories now block
Whenaction="pay_invoice" requires a TDS deduction, the transaction is blocked and the required deduction is surfaced in both advisories and blocks. The agent must re-issue the payment net of TDS before execution can proceed:
Example: unsupported action
TaxVerifier
TheTaxVerifier class provides jurisdiction-scoped access to guards. Initialize with "US" or "INDIA" to load the appropriate guard set.
The US verifier also includes a
TaxPreFlight instance accessible via us_verifier.preflight for intent-based auditing.QWEDTaxMiddleware (Gusto interceptor)
TheQWEDTaxMiddleware intercepts AI-generated payroll payloads before they reach execution APIs like Gusto. It validates the payload schema using Pydantic models and then runs deterministic gross-to-net verification.
Unexpected fields are rejected. The
PayrollEntry, TaxEntry, DeductionEntry, WorkerClassificationParams, ContractorPayment, WorkArrangement, Address, and VerificationResult models are configured with extra="forbid". Any payload with a key the model doesn’t declare — including typos like "net_pay_calimed" or speculative additions like "override_verification": true — raises a ValidationError at the boundary, which the middleware surfaces as status: "BLOCKED" with risk: "INVALID_PAYLOAD". Strip unknown fields from AI output before calling the middleware.Response format
- Arithmetic verified (still blocked)
- Blocked (hallucination)
- Blocked (invalid payload)
string
ARITHMETIC_VERIFIED when the gross-to-net math passes, BLOCKED otherwise. There is no VERIFIED status — full verification requires legal checks that are not yet implemented in the middleware.boolean
Whether the payload is safe to forward to the execution API. Currently always
false: the middleware fails closed until classification, withholding, reciprocity, and filing checks are wired in.string
Human-readable summary of what was verified and what was skipped (only present on
ARITHMETIC_VERIFIED).string[]
Names of the checks the middleware actually executed (for example,
["gross_to_net_arithmetic"]). Only present on ARITHMETIC_VERIFIED.string[]
Checks the middleware did not run for this payload — currently
worker_classification, withholding_legality, reciprocity, and filing_obligations. Use this list to decide which guards to run separately (or which human reviews to require) before executing.string
Risk code when blocked:
TAX_LOGIC_HALLUCINATION, INVALID_PAYLOAD, or VERIFIER_ERROR.string
Human-readable explanation of why the payload was blocked.
object
The validated payload (JSON-serialized) when the arithmetic check passes.
To move past
ARITHMETIC_VERIFIED, call the remaining guards yourself: ClassificationGuard (worker type), WithholdingGuard (W-4 exempt legality), ReciprocityGuard.verify_reciprocity() (state withholding), and Form1099Guard (filing). Only forward the payload to Gusto/Avalara once every checks_not_run entry has an explicit pass.Standalone guard usage
You can also use specific guards individually found inqwed_tax.jurisdictions and qwed_tax.guards.