From 66cb8c5e618f7c11c7aaffe4209bb5ae5d6d316d Mon Sep 17 00:00:00 2001
From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com>
Date: Sun, 21 Jun 2026 18:47:55 +0000
Subject: [PATCH 1/2] docs: document TaxDiagnosticResult tri-state model and
proof references
---
tax/guards.mdx | 104 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/tax/guards.mdx b/tax/guards.mdx
index 7718611..e0ef3b5 100644
--- a/tax/guards.mdx
+++ b/tax/guards.mdx
@@ -27,6 +27,110 @@ Several guards attach a structured, machine-readable `audit_trace` to their verd
Guards currently emitting `audit_trace` include **InputCreditGuard** (ITC), **TDSGuard** (Sec 194J/194C/194H/194I), and **GSTGuard** (RCM). Rule identifiers and statute strings are centralized in `qwed_tax/audit.py`.
+## Structured diagnostics (`TaxDiagnosticResult`)
+
+`TaxDiagnosticResult` is an opt-in, three-layer model that converts a guard's legacy dict return into a typed, tri-state verdict with a cryptographic proof reference. The legacy `{"verified": ..., "audit_trace": ...}` dict is unchanged — `to_diagnostic()` is additive, so existing callers keep working.
+
+Use it when you need a single, uniform shape across guards (for API responses, gating logic, or audit pipelines) instead of branching on guard-specific keys.
+
+### The three layers
+
+| Layer | Field | Purpose |
+| --- | --- | --- |
+| 1. Agent-safe | `agent_message: str` | Short, model-facing summary. No statute IDs, no rule IDs, no detection logic — safe to feed back to an LLM for correction. |
+| 2. Developer | `developer_fields: dict` | Structured evidence: `constraint_id`, `statute`, `jurisdiction`, `audit_trace`, plus guard-specific fields like `deduction`, `net_payable`, `allowable_credit`. |
+| 3. Proof | `proof_ref: Optional[str]` | `sha256:…` hash of the retained proof artifact. Present **only** when `status == VERIFIED`. This is the authority bit. |
+
+### Status states
+
+`TaxDiagnosticStatus` is a strict tri-state:
+
+- **`VERIFIED`** — the tax decision was deterministically proven. `proof_ref` MUST be present. Downstream gates MAY admit for control flow.
+- **`UNVERIFIABLE`** — the decision could not be proven (insufficient evidence, computation-only mode, unknown rule). `proof_ref` MUST be `None`. Gates MUST NOT admit.
+- **`BLOCKED`** — verification could not even be attempted (missing fields, parse error, unsupported service). `proof_ref` MUST be `None`. Gates MUST NOT admit.
+
+Richer distinctions (e.g. "below threshold" vs. "unknown service") live in `developer_fields.constraint_id`, not in the status.
+
+
+ **Authority contract.** `proof_ref is not None` is the **only** signal that a verdict is admissible for control flow. A `VERIFIED` status without a `proof_ref` is structurally impossible — the dataclass raises in `__post_init__`. Do not infer authority from any other field.
+
+
+### Calling `to_diagnostic()`
+
+`TDSGuard`, `InputCreditGuard`, and `GSTGuard` expose a `to_diagnostic()` static method that converts their existing dict result into a `TaxDiagnosticResult`.
+
+```python
+from qwed_tax.guards.tds_guard import TDSGuard
+from qwed_tax.diagnostics import TaxDiagnosticStatus
+
+guard = TDSGuard()
+raw = guard.calculate_deduction(service="professional_fees", amount=50_000)
+
+diag = TDSGuard.to_diagnostic(raw)
+
+if diag.status is TaxDiagnosticStatus.VERIFIED:
+ # diag.proof_ref is guaranteed non-None here
+ submit_payment(net_payable=diag.developer_fields["net_payable"])
+else:
+ # diag.proof_ref is None — never admit for control flow
+ escalate(diag.agent_message, constraint_id=diag.constraint_id)
+```
+
+The same shape applies to `InputCreditGuard.to_diagnostic()` (ITC) and `GSTGuard.to_diagnostic()` (RCM).
+
+### Proof references
+
+`compute_proof_ref(evidence)` returns a deterministic `sha256:…` hash over a JSON-serialized evidence dict. `trace_proof_ref(trace)` is a convenience wrapper for the output of `build_trace()`. Both fail closed if the evidence is not JSON-serializable.
+
+```python
+from qwed_tax.audit import build_trace, trace_proof_ref, TDS_194J
+
+trace = build_trace(TDS_194J, outcome="DEDUCTION_REQUIRED", inputs={"amount": "50000"})
+proof = trace_proof_ref(trace)
+# "sha256:9f4c…"
+```
+
+The proof reference binds a verdict to the exact evidence that justified it. If any input, rule, or outcome changes, the hash changes — making verdict/evidence drift structurally detectable in downstream audit logs.
+
+### Constructing results directly
+
+For custom guards or wrapper code, use the factory methods rather than the raw constructor:
+
+```python
+from qwed_tax.diagnostics import TaxDiagnosticResult
+
+# VERIFIED — proof_ref is computed from evidence
+diag = TaxDiagnosticResult.verified(
+ agent_message="Tax deduction verified.",
+ developer_fields={"constraint_id": "TDS_194J", "deduction": "5000"},
+ evidence=trace,
+)
+
+# UNVERIFIABLE — no proof was established
+diag = TaxDiagnosticResult.unverifiable(
+ agent_message="Amount is below the deduction threshold; no TDS required.",
+ developer_fields={"constraint_id": "TDS_194J_BELOW_THRESHOLD"},
+)
+
+# BLOCKED — verification could not be attempted
+diag = TaxDiagnosticResult.blocked(
+ agent_message="Unknown service type. Cannot determine deduction.",
+ developer_fields={"constraint_id": "TDS_UNKNOWN"},
+)
+```
+
+### Advisory checks
+
+`TaxAdvisoryCheck` attaches non-proof-bearing analysis as metadata. The `advisory_only=True` invariant is enforced in `__post_init__` — advisory checks populate `developer_fields["advisory_checks"]` and **never** influence `status` or `proof_ref`. Use them to surface useful context (e.g. "supplier GSTIN appears inactive") without making it part of the verdict.
+
+### Serialization
+
+`TaxDiagnosticResult` is frozen and provides `to_dict()` / `from_dict()` for API responses. `to_dict()` includes a flat `is_authoritative` boolean for clients that don't want to inspect `proof_ref` directly.
+
+### Migration status
+
+`to_diagnostic()` is currently available on **TDSGuard**, **InputCreditGuard**, and **GSTGuard** — the three guards that already emit `audit_trace`. The remaining guards still return their legacy dict shapes; subsequent releases will extend `to_diagnostic()` coverage.
+
## United States (IRS)
### ClassificationGuard (IRS common law)
From 166ed6bff798e496ffeb1aa09d1ebce21eb12d44 Mon Sep 17 00:00:00 2001
From: Rahul
Date: Mon, 22 Jun 2026 02:34:09 +0530
Subject: [PATCH 2/2] fix: correct diag.constraint_id access + make verified()
snippet self-contained
---
tax/guards.mdx | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tax/guards.mdx b/tax/guards.mdx
index e0ef3b5..a49f8a0 100644
--- a/tax/guards.mdx
+++ b/tax/guards.mdx
@@ -73,7 +73,7 @@ if diag.status is TaxDiagnosticStatus.VERIFIED:
submit_payment(net_payable=diag.developer_fields["net_payable"])
else:
# diag.proof_ref is None — never admit for control flow
- escalate(diag.agent_message, constraint_id=diag.constraint_id)
+ escalate(diag.agent_message, constraint_id=diag.developer_fields["constraint_id"])
```
The same shape applies to `InputCreditGuard.to_diagnostic()` (ITC) and `GSTGuard.to_diagnostic()` (RCM).
@@ -100,6 +100,8 @@ For custom guards or wrapper code, use the factory methods rather than the raw c
from qwed_tax.diagnostics import TaxDiagnosticResult
# VERIFIED — proof_ref is computed from evidence
+from qwed_tax.audit import build_trace, TDS_194J
+trace = build_trace(TDS_194J, outcome="DEDUCTION_REQUIRED", inputs={"amount": "50000"})
diag = TaxDiagnosticResult.verified(
agent_message="Tax deduction verified.",
developer_fields={"constraint_id": "TDS_194J", "deduction": "5000"},