examples/legal_contract_review.py
| 1 | """6-step legal contract review reasoning trace. |
| 2 | |
| 3 | Demonstrates a realistic chain-of-thought for a legal advisor AI: |
| 4 | observation -> hypothesis -> retrieval -> deduction -> self-critique -> decision |
| 5 | """ |
| 6 | |
| 7 | from __future__ import annotations |
| 8 | |
| 9 | from quantumshield.identity.agent import AgentIdentity |
| 10 | |
| 11 | from pqc_reasoning_ledger import ReasoningRecorder, TraceVerifier |
| 12 | |
| 13 | |
| 14 | def main() -> None: |
| 15 | print("=" * 72) |
| 16 | print("PQC Reasoning Ledger - Legal Contract Review") |
| 17 | print("=" * 72) |
| 18 | |
| 19 | identity = AgentIdentity.create("legal-advisor-signer") |
| 20 | rec = ReasoningRecorder(identity) |
| 21 | rec.begin_trace( |
| 22 | model_did="did:pqaid:gpt-legal-advisor", |
| 23 | model_version="2.1.0", |
| 24 | task="contract-review", |
| 25 | domain="legal", |
| 26 | actor_did="did:pqaid:acme-corp-counsel", |
| 27 | session_id="sess-20260420-001", |
| 28 | ) |
| 29 | |
| 30 | print("\n[1] Recording reasoning steps during inference...\n") |
| 31 | |
| 32 | s1 = rec.record_observation( |
| 33 | "Contract section 7.2 contains a liquidated damages clause " |
| 34 | "with a $1,000,000 cap per breach." |
| 35 | ) |
| 36 | print(f" [+] step 1 ({s1.kind.value}): {s1.step_id[-12:]}") |
| 37 | |
| 38 | s2 = rec.record_retrieval( |
| 39 | "Retrieved: Truck Rent-A-Center v. Puritan Farms 2nd, 41 N.Y.2d 420 (1977); " |
| 40 | "NY CPLR 3215; Restatement (Second) of Contracts S 356." |
| 41 | ) |
| 42 | print(f" [+] step 2 ({s2.kind.value}): {s2.step_id[-12:]}") |
| 43 | |
| 44 | s3 = rec.record_hypothesis( |
| 45 | "Under NY law, a liquidated damages clause is enforceable if (a) actual " |
| 46 | "damages are difficult to ascertain at contract formation, and (b) the " |
| 47 | "stipulated sum is a reasonable estimate of probable loss.", |
| 48 | confidence=0.85, |
| 49 | ) |
| 50 | print(f" [+] step 3 ({s3.kind.value}): {s3.step_id[-12:]}") |
| 51 | |
| 52 | s4 = rec.record_deduction( |
| 53 | "Projected actual damages from breach in this sector: $900k - $1.3M. " |
| 54 | "The $1M cap is within the reasonable-estimate range, so section 7.2 " |
| 55 | "is likely enforceable.", |
| 56 | confidence=0.80, |
| 57 | ) |
| 58 | print(f" [+] step 4 ({s4.kind.value}): {s4.step_id[-12:]}") |
| 59 | |
| 60 | s5 = rec.record_self_critique( |
| 61 | "I should also verify the clause does not function as a penalty: the cap " |
| 62 | "is below the high end of projected damages, which supports enforceability " |
| 63 | "rather than undermining it." |
| 64 | ) |
| 65 | print(f" [+] step 5 ({s5.kind.value}): {s5.step_id[-12:]}") |
| 66 | |
| 67 | s6 = rec.record_decision( |
| 68 | "RECOMMEND SIGNING with addition of a force-majeure carve-out in section " |
| 69 | "7.2(b) to address supply-chain risks. Liquidated damages provision as " |
| 70 | "drafted is likely enforceable under NY law.", |
| 71 | confidence=0.88, |
| 72 | ) |
| 73 | print(f" [+] step 6 ({s6.kind.value}): {s6.step_id[-12:]}") |
| 74 | |
| 75 | print("\n[2] Sealing trace with ML-DSA-65...\n") |
| 76 | sealed = rec.seal() |
| 77 | print(f" trace_id: {sealed.metadata.trace_id}") |
| 78 | print(f" step_count: {sealed.step_count}") |
| 79 | print(f" final_chain_hash: {sealed.final_chain_hash[:32]}...") |
| 80 | print(f" merkle_root: {sealed.merkle_root[:32]}...") |
| 81 | print(f" algorithm: {sealed.algorithm}") |
| 82 | print(f" signer_did: {sealed.signer_did}") |
| 83 | print(f" signature bytes: {len(sealed.signature) // 2}") |
| 84 | |
| 85 | print("\n[3] Independent verification...\n") |
| 86 | result = TraceVerifier.verify(sealed) |
| 87 | print(f" signature_valid: {result.signature_valid}") |
| 88 | print(f" chain_intact: {result.chain_intact}") |
| 89 | print(f" merkle_root_valid: {result.merkle_root_valid}") |
| 90 | print(f" fully_verified: {result.fully_verified}") |
| 91 | status = "[OK]" if result.fully_verified else "[FAIL]" |
| 92 | print(f"\n {status} legally defensible reasoning trail produced.") |
| 93 | |
| 94 | |
| 95 | if __name__ == "__main__": |
| 96 | main() |
| 97 | |