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 and 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.
| Action | Purpose | Required claim fields |
|---|---|---|
hire | Worker classification (W-2 vs 1099) | worker_type, worker_facts.provides_tools, worker_facts.reimburses_expenses, worker_facts.indefinite_relationship |
economic_nexus | US sales-tax nexus check | state, sales_data.amount, sales_data.transactions, tax_decision |
trade_tax | Trader set-off or capital gains | loss_head, offset_head, loss_amount — or — asset_type, dates.buy, dates.sell, claimed_rate |
corporate_action | Related-party loans or startup valuations | lender_type, borrower_role, interest_rate, market_rate — or — investment_round="convertible_note" plus investment_amount, cap_price, discount, next_round_price |
remit_money | International remittance (LRS/TCS) | remittance_amount_usd, purpose, fy_usage |
expense_claim | Input Tax Credit eligibility | expense_category, amount, tax_paid |
pay_invoice | Withholding / TDS on vendor payment | service_type, amount, ytd_payment |
| Alias | Canonical action |
|---|---|
hire_worker | hire |
worker_classification | hire |
sales_tax_check | economic_nexus |
sales_tax_assessment | economic_nexus |
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:
true only when every selected guard passes. Treat any false as a hard block.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.One or more human-readable block reasons when
allowed is false.Names of the guards that actually executed (for example,
["worker_classification"]). Empty when the intent was rejected before any guard ran.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, but 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.
| Action | Aliases | Runs |
|---|---|---|
hire | hire_worker, worker_classification | ClassificationGuard |
economic_nexus | sales_tax_check, sales_tax_assessment | NexusGuard |
trade_tax | — | SpeculationGuard, CapitalGainsGuard |
corporate_action | — | RelatedPartyGuard, ValuationGuard |
remit_money | — | RemittanceGuard |
expense_claim | — | InputCreditGuard |
pay_invoice | — | TDSGuard |
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.
| Action | Required fields |
|---|---|
hire | worker_type, worker_facts.provides_tools, worker_facts.reimburses_expenses, worker_facts.indefinite_relationship |
economic_nexus | state, sales_data.amount, sales_data.transactions, tax_decision |
trade_tax (trader set-off) | loss_head, offset_head, loss_amount |
trade_tax (capital gains) | asset_type, dates.buy, dates.sell, claimed_rate |
corporate_action (loans) | lender_type, borrower_role, interest_rate, market_rate |
corporate_action (valuation) | investment_round, investment_amount, cap_price, discount, next_round_price |
remit_money | remittance_amount_usd, purpose, fy_usage |
expense_claim | expense_category, amount, tax_paid |
pay_invoice | service_type, amount, ytd_payment |
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.
| Jurisdiction | Available methods |
|---|---|
US | verify_us_payroll(entry) — runs PayrollGuard gross-to-net check |
INDIA | verify_india_crypto(losses, gains) — runs CryptoTaxGuard set-off check |
INDIA | verify_india_deposit(**kwargs) — runs DepositRateGuard FD rate check |
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.
Response format
- Verified
- Blocked (hallucination)
- Blocked (invalid payload)
VERIFIED or BLOCKED.Whether the payload is safe to forward to the execution API.
Risk code when blocked:
TAX_LOGIC_HALLUCINATION, INVALID_PAYLOAD, or VERIFIER_ERROR.Human-readable explanation of why the payload was blocked.
The validated payload (JSON-serialized) when execution is permitted.
Standalone guard usage
You can also use specific guards individually found inqwed_tax.jurisdictions and qwed_tax.guards.