QWED Math Engine — fail-closed on mode ambiguity, eigenvalue cardinality, and IRR convergence
Released: July 24, 2026 · Jump to details · PR #217 · PR #218 · PR #219Three core-verifier fixes tighten the math engine’s fail-closed contract.verify_statistics(statistic="mode"),verify_matrix_operation(operation="eigenvalues"), andverify_irr()no longer produceVERIFIEDwhen the underlying claim is ambiguous, under-specified, or numerically unproven. Callers seeBLOCKEDorCORRECTION_NEEDEDwith structured diagnostics instead of a best-effort answer.
What changed
verify_statistics(statistic="mode")requires a unique mode. When two or more values tie for the maximum frequency, the engine returnsBLOCKEDwith anambiguous_modeslist instead of heuristically picking one. Only a unique mode can produceVERIFIED.verify_matrix_operation(operation="eigenvalues")requires cardinality match. The claimed eigenvalue list length must equal the calculated count (counting algebraic multiplicity). Mismatched lengths returnCORRECTION_NEEDEDwithcalculated_count/claimed_count. Previously the value comparison usedzip, which silently truncated to the shorter list.verify_irr()requires proof of Newton-Raphson convergence.BLOCKEDis now returned when cash flows have more than one sign change (multi-root ambiguity per Descartes’ rule), zero sign changes (no real IRR), all-zero cash flows (IRR undefined), the Newton derivative stalls at zero, or the method fails to converge within 100 iterations. Successful results includeconverged: trueanditerations_used.
Before and after
Ambiguous modeWhat this means for you
Existing code that already treated non-VERIFIED statuses as unverified continues to work. New policy code should read the structured diagnostic fields on BLOCKED/CORRECTION_NEEDED results — ambiguous_modes, calculated_count/claimed_count, and converged/iterations_used — to explain why a claim was rejected and to satisfy audit requirements. See Math engine — Fail-closed semantics for the full state tables and response schemas.
QWED-Finance — v2.1.0 released
Released: July 22, 2026 · GitHub PR #40qwed-financev2.1.0 is now the current release. This is a version-sync release: the Python package, npm wrapper, GitHub Action, and quickstart workflow reference are all realigned soQWED Finance Guardreports a single consistent version across PyPI, npm, and SARIF output in GitHub Advanced Security.
What changed
qwed-financePython package is now v2.1.0 on PyPI (qwed_finance.__version__ == "2.1.0").@qwed-ai/financenpm package version bumped to 2.1.0 to match.- GitHub Action auto-syncs its reported version from the installed package — the
QWED Finance Guardname in workflow logs and theversionfield on SARIF uploads to the GitHub Security tab now both read2.1.0instead of a hardcodedv2.0. - Quickstart
qwed-verify.ymlworkflow is re-pinned from the stale v1.1.4 SHA to the v2.1.0 SHA (QWED-AI/qwed-finance@19ce969f21d1fc2019da4d89fff23bc108e15a98 # v2.1.0).
What this means for you
Upgrade your dependency to pick up the current release:QWED-UCP — v0.3.0 released
Released: July 20, 2026 · GitHub PR #38qwed-ucpv0.3.0 is now the current release. This version ships the typedTrustStatusenum on every verification result, alongside the fail-closed middleware and internal-error handling delivered over the v0.2.x series.
What changed
qwed-ucpPython package is now v0.3.0 on PyPI.- Express middleware
qwed-ucp-middlewarepackage version bumped to match. TrustStatusenum is confirmed as available from v0.3.0 onward — see Trust status for the full state table and usage.- GitHub Action should now be pinned to
QWED-AI/qwed-ucp@v0.3.0.
What this means for you
Upgrade your dependency to pick up the current release:result.verified continues to work unchanged. New code should branch on result.status (a TrustStatus) to distinguish FAILED from ENGINE_ERROR, UNVERIFIABLE, and other non-VERIFIED verdicts.
QWED-UCP — Express middleware fails closed on internal verification errors
Released: July 18, 2026 · GitHub PR #36When a guard raised an unexpected exception, the Express middleware previously logged the error and callednext()— letting an unverified checkout through to the downstream handler. That defeated the trust boundary. Thecatchblock now short-circuits withHTTP 500,X-QWED-Verified: false, andcode: "INTERNAL_VERIFICATION_ERROR"so an internal crash can no longer be mistaken for a passing verification.
What changed
- Express middleware
catchblock is now fail-closed. On any exception raised duringverifyCheckoutLocally(), the middleware returns:The underlying exception is logged server-side viaconsole.errorbut is not included in the response body — raw stack traces, file paths, and internal messages stay out of client-visible output. X-QWED-Verified: falseis set on the 500 response so upstream policy layers can treat it the same as a 422 failure.- npm package fix.
qwed-ucp-middleware.jsis now included in the publishedfilesarray. Previous versions installed via npm were missing the entrypoint thatindex.jsrequired at runtime.
What this means for you
Existing integrations that already branched onX-QWED-Verified or on the response status keep working — they just start seeing a new 500 path that was previously invisible. New integrations should treat both 4xx and 5xx responses from the middleware as an unverified request. See Express.js middleware — Fail-closed on internal verification errors for the full response contract.
QWED-UCP — typed TrustStatus enum on every verification result
Released: July 15, 2026 · GitHub PR #33
Verification results previously exposed a singleverified: boolthat collapsed “proof disproved,” “proof could not be established,” “input outside supported semantics,” and “verifier engine crashed” into the sameFalsebucket. Every result dataclass now also carries a typedstatus: TrustStatusfield so downstream policy code can make trust-aware decisions without parsing error strings.
What changed
- New
TrustStatusenum exported fromqwed_ucpwith seven states:VERIFIED,FAILED,UNVERIFIABLE,UNSUPPORTED,PARTIAL,ENGINE_ERROR, andQUARANTINED(reserved). statusfield on every result —GuardResult,UCPVerificationResult, and each per-guard result type (MoneyGuardResult,StateGuardResult,SchemaGuardResult,LineItemsGuardResult,DiscountGuardResult,CurrencyGuardResult,RefundGuardResult,TipGuardResult,FeeGuardResult,AttestationResult).UCPVerifier.verify_checkout()now surfacesENGINE_ERRORwhen any guard raises an exception, instead of silently collapsing toverified=False.verified: boolis preserved as a backward-compatible derived field:result.verifiedisTrueonly whenresult.status == TrustStatus.VERIFIED. Existing constructors that passverified=True/verified=Falsecontinue to produce the correspondingVERIFIED/FAILEDstatus.
What this means for you
Existing code that readsresult.verified or constructs results with verified=... keeps working unchanged. New policy code should branch on result.status to distinguish a disproved proof from a crashed verifier — see Trust status for the full state table and an example.
QWED-UCP — middleware fails closed on empty and non-JSON request bodies
Released: July 14, 2026 · GitHub PR #32The FastAPI and Express middleware previously forwarded requests with an empty body, malformed JSON, or a non-object JSON payload to the downstream handler without running any guards. On a/checkout-sessionsroute that defeated the trust boundary — an attacker could send{}’s worth of nothing and skip verification. Both middlewares now reject those requests withHTTP 422,X-QWED-Verified: false, andcode: "UNPARSEABLE_REQUEST"before the handler runs.
What changed
- FastAPI: returns a distinct message per case:
- Empty body →
"Empty request body: cannot verify empty payload" - Malformed or non-UTF-8 body →
"Malformed request body: expected JSON" - Top-level non-object JSON →
"Invalid request body: expected JSON object"
- Empty body →
- Express: all three cases return
"Empty or non-JSON request body: cannot verify unparseable payload". - Non-protected methods and paths (for example,
GET /healthor aPOSTto a route outsideverify_paths) still pass through untouched.
What this means for you
If you deploy QWED-UCP as middleware in front of a UCP merchant server, unparseable requests can no longer bypass the guards. See FastAPI middleware, Express.js middleware, and the troubleshooting entry for the exact response shape and how to configure protected paths.QWED-A2A — persistent signing key and JWKS discovery endpoint
Released: July 10, 2026 · GitHub PR #29A2ACryptoServiceno longer generates an ephemeral ECDSA P-256 key per process. The signing key is now loaded from theQWED_A2A_SIGNING_KEY_PEMenvironment variable (or thepem_keyconstructor argument) so attestation JWTs issued before a restart remain verifiable afterwards. A new/.well-known/jwks.jsonendpoint publishes the current public key for external consumers.
What changed
- Persistent signing key —
A2ACryptoServicereads an unencrypted PKCS#8 P-256 PEM fromQWED_A2A_SIGNING_KEY_PEMon first use. The derivedkey_idis a SHA-256 fingerprint of the public key, so it stays stable as long as the PEM does. - Fail-closed on missing key —
sign_verdict,verify_attestation,get_public_key_jwk, andA2AVerificationInterceptor.intercept()all raiseRuntimeErrorwhen the PEM is missing, malformed, or uses a curve other thanSECP256R1. The FastAPI gateway surfaces this asHTTP 503 Signing key unavailable. - JWKS endpoint — A new
wellknown_routerexposesGET /.well-known/jwks.jsonfor downstream services and auditors to fetch the current public key without an out-of-band exchange. get_public_key_jwk()— Returns the current public key as a JWK (kty,crv,x,y,kid,use,alg).
Breaking changes
What this means for you
If you deploy the QWED-A2A gateway, you now get audit continuity across restarts and rolling deployments — a JWT signed by an earlier process is still verifiable by the next one, provided the PEM is unchanged. External services can also verify attestations by fetching/.well-known/jwks.json directly. See Crypto attestations and Deployment for the full setup, JWKS shape, and key rotation guidance.
QWED-Tax — structured 3-layer diagnostics for TDS, ITC, and GST-RCM
Released: June 21, 2026 · GitHub PR #45
QWED-Tax adopts the same 3-layer DiagnosticResult contract introduced in QWED-Verification v5.2.0 — as an independent model, no cross-package dependency. The first three guards (TDS, Input Tax Credit, GST reverse-charge) now expose a structured diagnostic in addition to their existing dict response.
What’s new
- Tri-state status — Every diagnostic resolves to
VERIFIED,UNVERIFIABLE, orBLOCKED. NoHEURISTICorAMBIGUOUSmiddle ground. - Three disclosure layers — A short agent-safe summary (no statute IDs or detection logic), a structured developer evidence block (constraint ID, statute, jurisdiction, audit trace, deduction, net payable), and an optional proof reference.
- Proof reference is the authority bit — A deterministic sha256 hash of the audit trace, present only when a result is
VERIFIED. Absent onUNVERIFIABLEandBLOCKED. - First migrations —
TDSGuard,InputCreditGuard, andGSTGuard(reverse-charge) each expose the new diagnostic format alongside their existing return shape.
Compatibility
Additive release. The legacy dict API on every guard is unchanged — the diagnostic format is opt-in. Existing integrations continue to work without modification. The remaining nine QWED-Tax guards (CapitalGains, Classification, Speculation, Setoff, Crypto, Valuation, Remittance, PoEM, Withholding) will migrate in follow-up releases.What this means for you
If you’ve already adopted the QWED-Verification diagnostic contract, the same response shape now applies to TDS, ITC, and GST-RCM checks — including the proof-reference authority bit you can gate execution on. See the Verification Diagnostics guide for the response shape and the tax guards reference for guard-by-guard coverage.QWED-Tax — exact paise comparison, edge-case input rejection, and strict payload schemas
Released: June 21, 2026 · GitHub PR #44Three input-strictness fixes ship together.CryptoTaxGuard.verify_flat_tax_ratenow compares quantized paise values exactly instead of within a 0.1 tolerance,ValuationGuardandRemittanceGuardreject the edge-case numeric inputs that previously slipped through, and every QWED-Tax Pydantic input model now forbids unexpected fields.
What changed
CryptoTaxGuard.verify_flat_tax_rate— TheDecimal("0.1")tolerance was removed. Both the computedexpected_taxand the caller’sclaimed_taxare now quantized to two decimal places usingROUND_HALF_UPand compared with an exact==. A 1-paise (0.01) deviation correctly returnsverified=False.ValuationGuard.verify_conversion— Added explicit range checks:discountmust be in[0, 1), andcap,next_round_price, andinvestmentmust all be strictly positive.DivisionByZerois now caught alongsideInvalidOperationso a degeneratecap = 0ordiscount = 1no longer crashes — it fails closed with a structured{"verified": False, "error": "..."}response. The previous behavior allowed adiscount > 1to produce a negative share count.RemittanceGuard.verify_lrs_limit— After numeric parsing,amount_usdandfinancial_year_usageare now checked for negativity. Negative inputs return{"verified": False, "error": "BLOCKED: ..."}instead of being summed into the limit check, where a negative usage could mask a transaction that exceeds the $250,000 LRS cap.- Input models —
Address,WorkArrangement,WorkerClassificationParams,ContractorPayment,TaxEntry,DeductionEntry,PayrollEntry, andVerificationResultare now configured withmodel_config = ConfigDict(extra="forbid"). Any payload with an unexpected key raises a PydanticValidationErrorat the boundary.QWEDTaxMiddlewarealready surfaces this asstatus: "BLOCKED"withrisk: "INVALID_PAYLOAD".
Breaking changes
What this means for you
If your agent forwards Indian VDA tax claims, startup conversion math, or LRS remittance requests through QWED-Tax, audit the calling code for: (1) tax claims that aren’t pre-quantized to two decimal places, (2) discount/cap/investment inputs that can legitimately be zero or out of range, (3) negative remittance amounts being passed defensively, and (4) AI payloads that include fields not declared on the QWED-Tax input models. See the CryptoTaxGuard, ValuationGuard, RemittanceGuard, and middleware integration guide for the updated contracts.Audit reference
QWED-Tax — middleware never returns full “verified” and ReciprocityGuard no longer always-passes
Released: June 21, 2026 · GitHub PR #43Two fail-closed fixes ship together. The Gusto interceptor middleware no longer overstates a gross-to-net arithmetic pass as full tax verification, andReciprocityGuardno longer returnsverified=Truefor arrangements with no reciprocity agreement.
ARITHMETIC_VERIFIED is a pre-conformance middleware-layer status, not part of the DiagnosticResult tri-state vocabulary (VERIFIED / UNVERIFIABLE / BLOCKED) introduced in v5.2.0. The middleware will migrate to DiagnosticResult when engine-conformance work lands. Until then, treat ARITHMETIC_VERIFIED as a distinct middleware signal — it is not equivalent to VERIFIED.What changed
QWEDTaxMiddleware.process_ai_payroll_request— The success response is nowstatus: "ARITHMETIC_VERIFIED"withexecution_permitted: false. The middleware only verifies gross-to-net math; classification, withholding legality, reciprocity, and filing checks are still required before execution. The response includeschecks_run(what was verified) andchecks_not_run(what is still required) so callers can decide what to run next.TaxPreFlightreport — Every report now includes achecks_not_runlist covering both unselected guards and known gaps (checks not yet implemented for the action). For example,action="hire"reportspayroll_arithmetic,withholding_legality,reciprocity, andfiling_obligationsas known gaps.ReciprocityGuard— The Z3 solver was removed (the prior expression was tautologically satisfiable and ignored thesame_stateparameter). The guard is now a deterministic lookup against the reciprocity-pair table with explicit fail-closed paths: same state → verified, known pair → verified, no agreement →verified=False, unknown state →verified=False. A newverify_reciprocity(residence_state, work_state, same_state=None)method takes string inputs;determine_withholding_state(arrangement)is kept for backwards compatibility.
The reciprocity-pair table covers only the pairs modeled within the
State enum’s 8-state scope (NJ, PA, MD, VA). Pennsylvania has additional reciprocity agreements (with IN, MI, OH, VA, WV, WI) that are not modeled here because those states are not in the enum. VA-PA in particular is a known gap — callers will receive verified=False for that pair until the enum and table are extended.Breaking changes
What this means for you
If your agent forwards payroll payloads to Gusto/Avalara based on aVERIFIED status from the middleware, those calls will start blocking until you run the remaining guards (ClassificationGuard, WithholdingGuard, ReciprocityGuard.verify_reciprocity, Form1099Guard) yourself. See the tax integration guide for the updated response shape and the ReciprocityGuard reference for the new lookup contract.
Audit reference
QWED-Tax — fail-closed on ambiguous classification and unverified claims
Released: June 21, 2026 · GitHub PR #42
Six more QWED-Tax guards now refuse to sign off when they can’t independently prove a result. Ambiguous worker classifications, unparseable trade dates, unknown set-off heads, and reverse-charge inputs the guard doesn’t recognize all return verified=False with a structured error instead of a quiet pass.
Bug fixes
- CapitalGainsGuard — Unparseable acquisition or disposal dates and unknown asset types now block instead of being coerced into a sentinel value that flowed through to
verified=True. SLAB-rate verification can no longer succeed without an income bracket — slab rates can’t be proven from the claim alone. - ClassificationGuard — Mixed employee/contractor signals now return
verified=Falsewith an “ambiguous classification” error. The guard only returnsCONTRACTORwhen no employee indicators are present. - SpeculationGuard — Set-off verification now requires a known income source (
intraday,f&o,futures,options,delivery,business,capital_gains). Unrecognized sources are blocked instead of silently treated as non-speculative. - InterHeadAdjustmentGuard — Set-off eligibility now runs against an explicit allowlist of heads. Salary loss set-off is added to the prohibition matrix, and unknown heads are blocked rather than defaulting to allow.
- GSTGuard (RCM) — Unrecognized service or entity types in reverse-charge checks now surface as a
verified=Falseerror naming the unknown value, instead of being coerced toOTHERorINDIVIDUALand potentially suppressing a statutory RCM obligation. The verifier also gained an optional claim parameter — when you pass aclaimed_is_rcmvalue, the guard compares it to the computed result and only returnsverified=Trueon an exact match. Calls without the claim get acomputed_only=Trueflag so calculation and verification are no longer conflated. - CryptoTaxGuard — Zero VDA income now verifies a claimed tax of zero, instead of returning
verified=Trueregardless of claim. Negative VDA income (a loss) returnsverified=Falsewith a message directing the caller to useverify_set_offfor loss treatment — the method does not internally invokeverify_set_off, so callers must handle theverified=Falsebranch explicitly.
What this means for you
If your agent relied on any of these guards returningverified=True for inputs they don’t model — ambiguous worker status, unknown set-off heads, unrecognized RCM service types, or capital-gains transactions with malformed dates — those calls now block. Surface the error to a human reviewer or extend the guard’s configured rules before re-running.
See the QWED-Tax guards reference for the updated contracts on each guard.
QWED-Tax — fail-closed on unknown tax rules
Released: June 19, 2026
Tax guards no longer silently pass when they encounter a service, asset, jurisdiction, or payment type they don’t model. Six guards now return verified=False with a structured error instead of an unsafe default.
What changed
- TDSGuard — unrecognized payment categories no longer return “verified, zero deduction.” This closes a path where an agent could classify a payment into an unknown bucket and have it execute with no withholding.
TaxPreFlightnow blocks these payments. - CapitalGainsGuard — unknown asset class or holding term fails closed instead of returning “no hard constraint.”
- NexusGuard — states not in the configured risk list now require manual review instead of being treated as low-risk.
- AddressGuard — unknown state codes fail closed with “manual review required” instead of “assumed valid.”
- Form1099Guard (US) — unmodeled payment types return
filing_required=Nonewith a manual-determination flag, instead of defaulting to “no filing required.” - InputCreditGuard (GST) —
verified=Trueremains the legal default (ITC is allowed unless specifically blocked), but unknown categories now carry an explicitunverified_category=Trueflag in the result and anaudit_traceentry ofcategory_match: "default_allow"so downstream consumers can distinguish known-eligible from default-allowed.
What this means for you
If your agent currently relies on averified=True response for inputs the guards don’t model, those calls will start blocking. Add explicit rules for the categories you care about, or route unverified results to human review.
See the tax guards reference and tax integration guide for the updated contracts.
QWED-Infra — ecosystem policy framework adopted
Released: June 17, 2026No runtime behavior changes. Affects contributors and anyone consuming the repository’s CI.qwed-infranow ships with the shared QWED governance baseline:QWED_RULES.md, contributor guidance, PR template, CodeRabbit config, and a boundary-check workflow that is consistent with the other QWED repositories.
QWED-MCP — boundary-check parity with QWED-Infra
Released: June 18, 2026Theqwed-mcpboundary-check tool now catches the same import-alias, module-alias, wildcard-import,eval/execalias, andshell=Truepatterns thatqwed-infradoes, and fails closed when the scan root is missing.
What this means for you
If you runqwed-mcp boundary checks in CI, expect to catch additional bypass patterns that previously slipped through. Existing passing scans should continue to pass; previously hidden findings may now surface as failures.
See the MCP tools reference for the current rule set.
QWED Open Responses v0.3.0 — version sync and dependency fix
Released: June 12, 2026AlignsNo API changes. Upgrade to pick up the dependency fix.qwed-open-responseswith the rest of the QWED package versions and patches a transitiveqsCVE flagged by Dependabot.
v5.2.0 — Structured Verification Diagnostics
Released: June 19, 2026 · GitHub Release · Minor
Introduces the unified 3-layer DiagnosticResult model — the diagnostic contract that all QWED verification engines will conform to. This is an additive release: no existing engine return types are changed. Engine conformance is tracked in blocked issues (#129, #130, #131, #133, #134, #162, #163, #164, #190, #205).
New: DiagnosticResult model
Three disclosure layers:
- Layer 1 — Agent-Safe:
agent_message: str— agent/model-facing summary, no internals leaked - Layer 2 — Developer:
developer_fields: dict— structured evidence (constraint_id,advisory_checks,methods_used, evidence) - Layer 3 — Proof:
proof_ref: Optional[str]— sha256 hash of retained proof artifact; the authority bit
Key design
- Tri-state status —
VERIFIED/UNVERIFIABLE/BLOCKEDonly. NoHEURISTICorAMBIGUOUSproliferation; richer distinctions live indeveloper_fields.constraint_id proof_refis the authority bit — present = admissible for control flow, None = reject. No separateauthoritativeboolean needed (resolves #190 design debate)- VERIFIED requires proof — structurally enforced in
__post_init__; “VERIFIED without proof” is impossible to construct - Frozen dataclasses —
DiagnosticResultandAdvisoryCheckarefrozen=True; post-construction mutation blocked - Advisory checks never influence verdicts —
AdvisoryCheck.advisory_only=Trueenforced via__post_init__ compute_proof_ref()— deterministic sha256 hashing of JSON-serialized evidencefrom_legacy_dict()— migration helper for ad-hoc engine dicts (fail-closed states only; raises for legacy VERIFIED)
Version propagation
Tests
83 new tests covering: status taxonomy, all 3 layers, authority contract, fail-closed enforcement, advisory checks, proof hashing determinism, serialization round-trip, legacy migration, frozen dataclass immutability, and realistic scenarios drawn from the 10 blocked issues.Compatibility
Additive release. No breaking changes. ExistingVerificationResult dataclasses and ad-hoc engine dicts continue to work. DiagnosticResult is opt-in — engines migrate incrementally.
Included PRs
- #206 — feat(diagnostics): unified 3-layer DiagnosticResult model (#204)
- #207 — release: v5.2.0 version propagation
Older entries: Changelog Archive