Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions payment-dispute-evidence-guard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Payment Dispute Evidence Guard

This module adds a dependency-free revenue-control slice for issue #20. It evaluates whether synthetic processor dispute packets are ready to leave finance before revenue is recognized, released, or defended through a payment processor response.

The guard is intentionally offline: it uses no credentials, no payment processor API, no bank data, no real customer records, and no external network calls.

## What It Checks

- Processor response deadline and urgent response windows.
- Required evidence completeness: contract, invoice, delivery proof, usage logs, terms acceptance, customer communication, and redacted receipt.
- Prior refunds and credit memos that already offset a disputed amount.
- Duplicate processor case IDs across exported response packets.
- Customer notification timing after dispute receipt.
- Sensitive receipt leakage such as full payment card numbers.
- Finance-ready decisions: `RELEASE_RESPONSE`, `REVIEW_BEFORE_RESPONSE`, and `HOLD_RESPONSE`.

## Requirement Map

| Issue #20 revenue requirement | Coverage in this module |
| --- | --- |
| Secure payment integrations | Validates dispute packets before processor response export without calling live processors. |
| Billing engine controls | Compares dispute amounts, recognized revenue, refunds, and credit memos before release. |
| Institutional invoicing | Links account, invoice, and customer notice evidence for finance review. |
| Audit-ready operations | Emits JSON and Markdown reviewer packets with findings and remediation steps. |
| Predictable recurring revenue | Holds risky dispute packets before duplicate recovery, missed windows, or unredacted evidence distort revenue. |

## Files

- `src/disputeGuard.mjs` - deterministic decision engine.
- `data/dispute-packets.json` - synthetic reviewer packets.
- `test/disputeGuard.test.mjs` - Node test coverage.
- `scripts/run-demo.mjs` - generates reviewer artifacts.
- `scripts/render-demo-video.mjs` - renders the SVG demo into a short WebM review video.
- `artifacts/` - generated JSON, Markdown, and SVG outputs after running the demo.

## Validation

```bash
npm test
npm run demo
npm run demo:video
```

The demo writes:

- `artifacts/dispute-review-report.json`
- `artifacts/dispute-review-report.md`
- `artifacts/dispute-review-demo.svg`
- `artifacts/dispute-review-demo.webm`

## Review Notes

This is a distinct slice from subscription pricing, usage metering, grant milestones, FX settlement, tax/VAT, event sponsorship, and cost-center allocation work. It focuses only on payment-processor dispute evidence readiness and revenue-release risk.
43 changes: 43 additions & 0 deletions payment-dispute-evidence-guard/artifacts/dispute-review-demo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
127 changes: 127 additions & 0 deletions payment-dispute-evidence-guard/artifacts/dispute-review-report.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
{
"generatedAt": "2026-06-27T08:00:00Z",
"summary": {
"totalPackets": 4,
"totalNetAmountAtRiskCents": 580000,
"decisions": {
"RELEASE_RESPONSE": 1,
"REVIEW_BEFORE_RESPONSE": 1,
"HOLD_RESPONSE": 2
},
"findings": 10,
"overallDecision": "HOLD_RESPONSE"
},
"results": [
{
"id": "DSP-1001",
"accountId": "lab-north-42",
"invoiceId": "INV-2026-0418",
"processorCaseId": "chdp_91a7_release",
"netAmountAtRiskCents": 120000,
"hoursUntilDue": 74,
"findingCount": 0,
"highestSeverity": "info",
"decision": "RELEASE_RESPONSE",
"findings": []
},
{
"id": "DSP-1002",
"accountId": "quantum-cohort-8",
"invoiceId": "INV-2026-0442",
"processorCaseId": "chdp_91a7_hold",
"netAmountAtRiskCents": 260000,
"hoursUntilDue": -41,
"findingCount": 5,
"highestSeverity": "critical",
"decision": "HOLD_RESPONSE",
"findings": [
{
"severity": "critical",
"code": "RESPONSE_WINDOW_EXPIRED",
"message": "The processor response deadline has already passed.",
"remediation": "Hold revenue release and escalate to finance counsel before submitting a late dispute packet."
},
{
"severity": "critical",
"code": "MISSING_DISPUTE_EVIDENCE",
"message": "Missing dispute evidence: deliveryProof, usageLogs, customerCommunication, redactedReceipt.",
"remediation": "Attach the missing evidence before any dispute response leaves the revenue workflow."
},
{
"severity": "critical",
"code": "SENSITIVE_RECEIPT_DATA",
"message": "Receipt evidence appears to contain a full payment card number.",
"remediation": "Redact card, bank, and token data before exporting the response packet."
},
{
"severity": "warning",
"code": "CUSTOMER_NOTICE_MISSING",
"message": "No customer notification timestamp is recorded for this dispute.",
"remediation": "Notify the billing contact or document why notice is blocked before release."
},
{
"severity": "critical",
"code": "DUPLICATE_PROCESSOR_CASE",
"message": "Processor case chdp_91a7_hold appears in more than one packet.",
"remediation": "Merge or split the evidence packets before any response is submitted."
}
]
},
{
"id": "DSP-1003",
"accountId": "bio-modeling-lab",
"invoiceId": "INV-2026-0461",
"processorCaseId": "chdp_91a7_credit",
"netAmountAtRiskCents": 0,
"hoursUntilDue": 124,
"findingCount": 1,
"highestSeverity": "warning",
"decision": "REVIEW_BEFORE_RESPONSE",
"findings": [
{
"severity": "warning",
"code": "DISPUTE_ALREADY_OFFSET",
"message": "Prior refunds or credit memos fully offset the disputed amount.",
"remediation": "Avoid duplicate recovery. Link the refund and credit memo evidence before responding."
}
]
},
{
"id": "DSP-1004",
"accountId": "materials-ai-consortium",
"invoiceId": "INV-2026-0490",
"processorCaseId": "chdp_91a7_hold",
"netAmountAtRiskCents": 200000,
"hoursUntilDue": 34,
"findingCount": 4,
"highestSeverity": "critical",
"decision": "HOLD_RESPONSE",
"findings": [
{
"severity": "warning",
"code": "RESPONSE_WINDOW_URGENT",
"message": "The processor response deadline is within 34 hours.",
"remediation": "Route to a reviewer before release and confirm the packet can be submitted before cutoff."
},
{
"severity": "warning",
"code": "CUSTOMER_NOTICE_LATE",
"message": "Customer notice was recorded after 73 hours.",
"remediation": "Have finance confirm late notice is acceptable for this account and region."
},
{
"severity": "warning",
"code": "RECOGNIZED_REVENUE_EXCEEDS_RISK",
"message": "Recognized revenue is higher than the current net disputed amount.",
"remediation": "Confirm whether deferred revenue or a reserve adjustment is needed before release."
},
{
"severity": "critical",
"code": "DUPLICATE_PROCESSOR_CASE",
"message": "Processor case chdp_91a7_hold appears in more than one packet.",
"remediation": "Merge or split the evidence packets before any response is submitted."
}
]
}
]
}
31 changes: 31 additions & 0 deletions payment-dispute-evidence-guard/artifacts/dispute-review-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Payment Dispute Evidence Guard Demo

Generated at: 2026-06-27T08:00:00Z

## Summary

- Total packets: 4
- Net amount at risk: $5800.00
- Overall decision: HOLD_RESPONSE
- Release: 1
- Review before response: 1
- Hold response: 2
- Findings: 10

## Packet Decisions

| Packet | Invoice | Processor case | Net risk | Decision | Findings |
| --- | --- | --- | ---: | --- | --- |
| DSP-1001 | INV-2026-0418 | chdp_91a7_release | $1200.00 | RELEASE_RESPONSE | none |
| DSP-1002 | INV-2026-0442 | chdp_91a7_hold | $2600.00 | HOLD_RESPONSE | RESPONSE_WINDOW_EXPIRED, MISSING_DISPUTE_EVIDENCE, SENSITIVE_RECEIPT_DATA, CUSTOMER_NOTICE_MISSING, DUPLICATE_PROCESSOR_CASE |
| DSP-1003 | INV-2026-0461 | chdp_91a7_credit | $0.00 | REVIEW_BEFORE_RESPONSE | DISPUTE_ALREADY_OFFSET |
| DSP-1004 | INV-2026-0490 | chdp_91a7_hold | $2000.00 | HOLD_RESPONSE | RESPONSE_WINDOW_URGENT, CUSTOMER_NOTICE_LATE, RECOGNIZED_REVENUE_EXCEEDS_RISK, DUPLICATE_PROCESSOR_CASE |

## Controls Covered

- Processor response deadline and urgency checks.
- Required evidence completeness for contract, invoice, delivery, usage, terms, communication, and redacted receipt.
- Prior refund and credit memo offsets to prevent duplicate recovery.
- Duplicate processor case detection across exported packets.
- Customer notice timing before response release.
- Sensitive receipt data redaction before finance exports.
102 changes: 102 additions & 0 deletions payment-dispute-evidence-guard/data/dispute-packets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
[
{
"id": "DSP-1001",
"accountId": "lab-north-42",
"invoiceId": "INV-2026-0418",
"processorCaseId": "chdp_91a7_release",
"processorStatus": "needs_response",
"invoiceAmountCents": 480000,
"disputedAmountCents": 120000,
"revenueRecognizedCents": 120000,
"priorRefundCents": 0,
"creditMemoCents": 0,
"disputeReceivedAt": "2026-06-23T10:00:00Z",
"responseDueAt": "2026-06-30T10:00:00Z",
"customerNotifiedAt": "2026-06-24T09:00:00Z",
"evidence": {
"contract": true,
"invoice": true,
"deliveryProof": true,
"usageLogs": true,
"termsAcceptance": true,
"customerCommunication": true,
"redactedReceipt": true
},
"receiptText": "Receipt INV-2026-0418 paid by card ending 4242. Sponsor contact: billing@example.edu."
},
{
"id": "DSP-1002",
"accountId": "quantum-cohort-8",
"invoiceId": "INV-2026-0442",
"processorCaseId": "chdp_91a7_hold",
"processorStatus": "needs_response",
"invoiceAmountCents": 740000,
"disputedAmountCents": 260000,
"revenueRecognizedCents": 260000,
"priorRefundCents": 0,
"creditMemoCents": 0,
"disputeReceivedAt": "2026-06-19T15:00:00Z",
"responseDueAt": "2026-06-25T15:00:00Z",
"customerNotifiedAt": null,
"evidence": {
"contract": true,
"invoice": true,
"deliveryProof": false,
"usageLogs": false,
"termsAcceptance": true,
"customerCommunication": false,
"redactedReceipt": false
},
"receiptText": "Raw receipt contains card 4111111111111111 and should be redacted before any dispute packet leaves finance."
},
{
"id": "DSP-1003",
"accountId": "bio-modeling-lab",
"invoiceId": "INV-2026-0461",
"processorCaseId": "chdp_91a7_credit",
"processorStatus": "needs_response",
"invoiceAmountCents": 300000,
"disputedAmountCents": 90000,
"revenueRecognizedCents": 90000,
"priorRefundCents": 50000,
"creditMemoCents": 50000,
"disputeReceivedAt": "2026-06-24T12:00:00Z",
"responseDueAt": "2026-07-02T12:00:00Z",
"customerNotifiedAt": "2026-06-26T12:00:00Z",
"evidence": {
"contract": true,
"invoice": true,
"deliveryProof": true,
"usageLogs": true,
"termsAcceptance": true,
"customerCommunication": true,
"redactedReceipt": true
},
"receiptText": "Credit memo CM-2026-0091 and refund RF-2026-0024 already offset this disputed amount."
},
{
"id": "DSP-1004",
"accountId": "materials-ai-consortium",
"invoiceId": "INV-2026-0490",
"processorCaseId": "chdp_91a7_hold",
"processorStatus": "needs_response",
"invoiceAmountCents": 620000,
"disputedAmountCents": 200000,
"revenueRecognizedCents": 250000,
"priorRefundCents": 0,
"creditMemoCents": 0,
"disputeReceivedAt": "2026-06-24T18:00:00Z",
"responseDueAt": "2026-06-28T18:00:00Z",
"customerNotifiedAt": "2026-06-27T18:30:00Z",
"evidence": {
"contract": true,
"invoice": true,
"deliveryProof": true,
"usageLogs": true,
"termsAcceptance": true,
"customerCommunication": true,
"redactedReceipt": true
},
"receiptText": "Dispute packet references sanitized invoice and usage evidence only."
}
]
11 changes: 11 additions & 0 deletions payment-dispute-evidence-guard/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "payment-dispute-evidence-guard",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"demo": "node scripts/run-demo.mjs",
"demo:video": "node scripts/render-demo-video.mjs",
"test": "node --test test/*.test.mjs"
}
}
Loading