From 30e9922cc70b9de0cd47b5014d70957766f80def Mon Sep 17 00:00:00 2001 From: katlark Date: Thu, 21 May 2026 13:05:09 +0100 Subject: [PATCH] Add trial promotion abuse guard --- README.md | 6 + trial-promotion-abuse-guard/README.md | 43 +++ .../acceptance-notes.md | 25 ++ trial-promotion-abuse-guard/demo.js | 27 ++ trial-promotion-abuse-guard/index.js | 320 ++++++++++++++++++ trial-promotion-abuse-guard/package.json | 11 + trial-promotion-abuse-guard/reports/demo.mp4 | Bin 0 -> 32486 bytes .../reports/promotion-abuse-packet.json | 162 +++++++++ .../reports/promotion-abuse-report.md | 26 ++ .../reports/summary.png | Bin 0 -> 51290 bytes .../reports/summary.svg | 17 + .../requirements-map.md | 21 ++ trial-promotion-abuse-guard/sample-data.js | 164 +++++++++ trial-promotion-abuse-guard/test.js | 39 +++ 14 files changed, 861 insertions(+) create mode 100644 trial-promotion-abuse-guard/README.md create mode 100644 trial-promotion-abuse-guard/acceptance-notes.md create mode 100644 trial-promotion-abuse-guard/demo.js create mode 100644 trial-promotion-abuse-guard/index.js create mode 100644 trial-promotion-abuse-guard/package.json create mode 100644 trial-promotion-abuse-guard/reports/demo.mp4 create mode 100644 trial-promotion-abuse-guard/reports/promotion-abuse-packet.json create mode 100644 trial-promotion-abuse-guard/reports/promotion-abuse-report.md create mode 100644 trial-promotion-abuse-guard/reports/summary.png create mode 100644 trial-promotion-abuse-guard/reports/summary.svg create mode 100644 trial-promotion-abuse-guard/requirements-map.md create mode 100644 trial-promotion-abuse-guard/sample-data.js create mode 100644 trial-promotion-abuse-guard/test.js diff --git a/README.md b/README.md index d338cf6..733d372 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,8 @@ # deepevents.ai deepevents.ai main codebase + +## Revenue infrastructure controls + +- `trial-promotion-abuse-guard/` checks free-trial reuse, coupon stacking, + consortium discount eligibility, and trial-to-paid readiness before discount + leakage reaches invoice-facing revenue. diff --git a/trial-promotion-abuse-guard/README.md b/trial-promotion-abuse-guard/README.md new file mode 100644 index 0000000..c199380 --- /dev/null +++ b/trial-promotion-abuse-guard/README.md @@ -0,0 +1,43 @@ +# Trial Promotion Abuse Guard + +This module is a focused revenue-control slice for issue #20. It checks whether +free trials, coupons, consortium discounts, and trial-to-paid conversions are +safe to release into invoice-facing revenue. + +The guard is intentionally self-contained and uses only synthetic data. It does +not call payment processors, billing providers, or customer systems. + +## What It Catches + +- Repeat free trials on the same institution domain. +- Repeat trial attempts using the same payment fingerprint. +- Disposable-domain trials. +- Coupon stacking above policy. +- Consortium discounts without an active roster entry. +- Trial-to-paid conversion attempts without verified payment. +- Discount leakage before invoice release. + +## Local Review + +```sh +npm run check +npm test +npm run demo +``` + +The demo writes reviewer artifacts under `reports/`: + +- `promotion-abuse-packet.json` +- `promotion-abuse-report.md` +- `summary.svg` +- `summary.png` +- `demo.mp4` + +`demo.mp4` is a short H.264 reviewer preview generated from the checked-in +summary frame. + +## Reviewer Outcome + +Finance gets a deterministic decision packet showing which promotions can be +approved, which need a hold, which should be rejected, and how much discount +leakage was prevented before the invoice is released. diff --git a/trial-promotion-abuse-guard/acceptance-notes.md b/trial-promotion-abuse-guard/acceptance-notes.md new file mode 100644 index 0000000..f45f21d --- /dev/null +++ b/trial-promotion-abuse-guard/acceptance-notes.md @@ -0,0 +1,25 @@ +# Acceptance Notes + +## Included Checks + +- Duplicate free-trial attempts by institution domain and payment fingerprint. +- Disposable-domain trial rejection. +- Coupon stacking above the configured policy limit. +- Discount cap enforcement with prevented-leakage cents. +- Consortium discount hold when roster evidence is expired. +- Trial-to-paid hold when payment verification is missing. +- Clean discount approval path for a valid lab account. + +## Validation + +Run from this directory: + +```sh +npm run check +npm test +npm run demo +``` + +The test suite verifies both blocking behavior and one clean approval path. The +demo regenerates the finance review packet and visual summary from the checked-in +sample data. diff --git a/trial-promotion-abuse-guard/demo.js b/trial-promotion-abuse-guard/demo.js new file mode 100644 index 0000000..23143e2 --- /dev/null +++ b/trial-promotion-abuse-guard/demo.js @@ -0,0 +1,27 @@ +const fs = require("node:fs"); +const path = require("node:path"); +const {buildMarkdownReport, buildSummarySvg, evaluatePromotionControls, money} = require("./index"); +const {sampleData} = require("./sample-data"); + +const reportsDir = path.join(__dirname, "reports"); +fs.mkdirSync(reportsDir, {recursive: true}); + +const result = evaluatePromotionControls(sampleData); +const packetPath = path.join(reportsDir, "promotion-abuse-packet.json"); +const reportPath = path.join(reportsDir, "promotion-abuse-report.md"); +const svgPath = path.join(reportsDir, "summary.svg"); + +fs.writeFileSync(packetPath, `${JSON.stringify(result, null, 2)}\n`); +fs.writeFileSync(reportPath, buildMarkdownReport(result)); +fs.writeFileSync(svgPath, buildSummarySvg(result)); + +console.log("Trial promotion abuse guard demo"); +console.log(`Digest: ${result.digest}`); +console.log(`Events reviewed: ${result.metrics.totalEvents}`); +console.log(`Approved: ${result.metrics.approvedEvents}`); +console.log(`Held: ${result.metrics.heldEvents}`); +console.log(`Rejected: ${result.metrics.rejectedEvents}`); +console.log(`Discount leakage prevented: ${money(result.metrics.discountLeakagePreventedCents)}`); +console.log(`Wrote ${path.relative(process.cwd(), packetPath)}`); +console.log(`Wrote ${path.relative(process.cwd(), reportPath)}`); +console.log(`Wrote ${path.relative(process.cwd(), svgPath)}`); diff --git a/trial-promotion-abuse-guard/index.js b/trial-promotion-abuse-guard/index.js new file mode 100644 index 0000000..914c9e9 --- /dev/null +++ b/trial-promotion-abuse-guard/index.js @@ -0,0 +1,320 @@ +const crypto = require("node:crypto"); + +function stableStringify(value) { + if (Array.isArray(value)) { + return `[${value.map((item) => stableStringify(item)).join(",")}]`; + } + if (value && typeof value === "object") { + return `{${Object.keys(value) + .sort() + .map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`) + .join(",")}}`; + } + return JSON.stringify(value); +} + +function digestFor(value) { + return crypto.createHash("sha256").update(stableStringify(value)).digest("hex"); +} + +function verifiedPayment(account) { + return Boolean(account?.paymentMethod?.verified); +} + +function centsForDiscount(subtotalCents, discountPct) { + return Math.round((subtotalCents * discountPct) / 100); +} + +function severityStatus(reasons) { + if (reasons.some((reason) => reason.severity === "reject")) { + return "rejected"; + } + if (reasons.some((reason) => reason.severity === "hold")) { + return "hold"; + } + if (reasons.some((reason) => reason.severity === "review")) { + return "review"; + } + return "approved"; +} + +function addReason(reasons, severity, code, message) { + reasons.push({severity, code, message}); +} + +function buildPromotionContext(accounts) { + return { + trialsByDomain: new Map(), + trialsByPaymentFingerprint: new Map(), + accountById: new Map(accounts.map((account) => [account.id, account])), + }; +} + +function rememberTrial(account, context) { + if (!account) { + return; + } + const domainTrials = context.trialsByDomain.get(account.domain) ?? []; + domainTrials.push(account.id); + context.trialsByDomain.set(account.domain, domainTrials); + + const fingerprint = account.paymentMethod?.fingerprint; + if (fingerprint) { + const paymentTrials = context.trialsByPaymentFingerprint.get(fingerprint) ?? []; + paymentTrials.push(account.id); + context.trialsByPaymentFingerprint.set(fingerprint, paymentTrials); + } +} + +function validateTrialStart(event, account, policy, context) { + const reasons = []; + const domainTrials = context.trialsByDomain.get(account.domain) ?? []; + if (policy.disposableDomains.includes(account.domain)) { + addReason( + reasons, + "reject", + "disposable_domain", + "Trial uses a disposable or non-institutional email domain.", + ); + } + if (domainTrials.length >= policy.maxTrialsPerInstitutionDomain) { + addReason( + reasons, + "hold", + "domain_trial_reuse", + `Domain ${account.domain} already has ${domainTrials.length} trial workspace.`, + ); + } + const fingerprint = account.paymentMethod?.fingerprint; + const paymentTrials = fingerprint ? context.trialsByPaymentFingerprint.get(fingerprint) ?? [] : []; + if (fingerprint && paymentTrials.length >= policy.maxTrialsPerPaymentFingerprint) { + addReason( + reasons, + "hold", + "payment_trial_reuse", + "Payment fingerprint was already used for a previous trial.", + ); + } + return reasons; +} + +function validatePromotion(event, account, invoice, policy) { + const reasons = []; + const coupons = event.coupons ?? []; + let requestedDiscountPct = 0; + const definitions = coupons.map((coupon) => { + const definition = policy.promotions[coupon]; + if (!definition) { + addReason(reasons, "reject", "unknown_coupon", `Coupon ${coupon} is not configured.`); + return null; + } + requestedDiscountPct += definition.discountPct; + return {coupon, ...definition}; + }).filter(Boolean); + + if (definitions.length > policy.maxStackedPromotions) { + addReason( + reasons, + "hold", + "coupon_stack_exceeds_policy", + `${definitions.length} coupons were stacked; policy allows ${policy.maxStackedPromotions}.`, + ); + } + + for (const definition of definitions) { + if (!definition.eligiblePlans.includes(account.plan)) { + addReason( + reasons, + "hold", + "plan_not_eligible", + `${definition.coupon} is not eligible for the ${account.plan} plan.`, + ); + } + if (definition.requires.includes("verified_payment") && !verifiedPayment(account)) { + addReason(reasons, "hold", "payment_not_verified", `${definition.coupon} requires a verified payment method.`); + } + if (definition.requires.includes("paid_plan") && account.lifecycle !== "active") { + addReason(reasons, "hold", "requires_paid_plan", `${definition.coupon} can only be used by active paid accounts.`); + } + if ( + definition.requires.includes("active_consortium_roster") && + account.consortiumMembership?.status !== "active" + ) { + addReason( + reasons, + "hold", + "consortium_roster_not_active", + `${definition.coupon} requires an active consortium roster entry.`, + ); + } + } + + if (requestedDiscountPct > policy.maxCombinedDiscountPct) { + addReason( + reasons, + "hold", + "discount_cap_exceeded", + `Requested discount ${requestedDiscountPct}% exceeds ${policy.maxCombinedDiscountPct}% policy cap.`, + ); + } + + const approvedDiscountPct = reasons.length === 0 ? requestedDiscountPct : Math.min(requestedDiscountPct, policy.maxCombinedDiscountPct); + const requestedDiscountCents = invoice ? centsForDiscount(invoice.subtotalCents, requestedDiscountPct) : 0; + const approvedDiscountCents = invoice ? centsForDiscount(invoice.subtotalCents, approvedDiscountPct) : 0; + const discountLeakagePreventedCents = reasons.length > 0 ? Math.max(0, requestedDiscountCents - approvedDiscountCents) : 0; + + return { + reasons, + requestedDiscountPct, + approvedDiscountPct, + requestedDiscountCents, + approvedDiscountCents, + discountLeakagePreventedCents, + }; +} + +function validateTrialConversion(event, account, invoice, policy) { + const promotionResult = validatePromotion(event, account, invoice, policy); + const reasons = [...promotionResult.reasons]; + if (!verifiedPayment(account)) { + addReason(reasons, "hold", "conversion_payment_missing", "Trial cannot convert until a verified payment method is present."); + } + return {...promotionResult, reasons}; +} + +function evaluatePromotionControls(input) { + const policy = input.policy; + const accounts = input.accounts; + const invoices = new Map(input.invoices.map((invoice) => [invoice.id, invoice])); + const context = buildPromotionContext(accounts); + const sortedEvents = [...input.events].sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp)); + const decisions = []; + + for (const event of sortedEvents) { + const account = context.accountById.get(event.accountId); + const invoice = event.invoiceId ? invoices.get(event.invoiceId) : undefined; + const base = { + eventId: event.id, + eventType: event.type, + accountId: event.accountId, + accountName: account?.name ?? "Unknown account", + invoiceId: event.invoiceId ?? null, + timestamp: event.timestamp, + }; + + if (!account) { + const reasons = [{severity: "reject", code: "unknown_account", message: "Event references an unknown account."}]; + decisions.push({...base, status: "rejected", reasons}); + continue; + } + + if (event.type === "trial_started") { + const reasons = validateTrialStart(event, account, policy, context); + decisions.push({...base, status: severityStatus(reasons), reasons}); + rememberTrial(account, context); + continue; + } + + if (event.type === "promotion_applied") { + const promotion = validatePromotion(event, account, invoice, policy); + decisions.push({...base, status: severityStatus(promotion.reasons), ...promotion}); + continue; + } + + if (event.type === "trial_conversion") { + const conversion = validateTrialConversion(event, account, invoice, policy); + decisions.push({...base, status: severityStatus(conversion.reasons), ...conversion}); + continue; + } + + const reasons = [{severity: "review", code: "unknown_event_type", message: `Unhandled event type ${event.type}.`}]; + decisions.push({...base, status: "review", reasons}); + } + + const metrics = { + totalEvents: decisions.length, + approvedEvents: decisions.filter((decision) => decision.status === "approved").length, + heldEvents: decisions.filter((decision) => decision.status === "hold").length, + rejectedEvents: decisions.filter((decision) => decision.status === "rejected").length, + reviewedEvents: decisions.filter((decision) => decision.status === "review").length, + discountLeakagePreventedCents: decisions.reduce( + (total, decision) => total + (decision.discountLeakagePreventedCents ?? 0), + 0, + ), + requestedDiscountCents: decisions.reduce((total, decision) => total + (decision.requestedDiscountCents ?? 0), 0), + approvedDiscountCents: decisions.reduce((total, decision) => total + (decision.approvedDiscountCents ?? 0), 0), + }; + + const result = { + generatedAt: "2026-05-21T12:00:00Z", + control: "trial-promotion-abuse-guard", + metrics, + decisions, + }; + result.digest = digestFor(result); + return result; +} + +function money(cents) { + return `$${(cents / 100).toFixed(2)}`; +} + +function buildMarkdownReport(result) { + const lines = [ + "# Trial Promotion Abuse Guard", + "", + `Digest: \`${result.digest}\``, + "", + "## Summary", + "", + `- Events reviewed: ${result.metrics.totalEvents}`, + `- Approved: ${result.metrics.approvedEvents}`, + `- Held: ${result.metrics.heldEvents}`, + `- Rejected: ${result.metrics.rejectedEvents}`, + `- Discount leakage prevented: ${money(result.metrics.discountLeakagePreventedCents)}`, + "", + "## Decisions", + "", + "| Event | Account | Status | Reason codes |", + "| --- | --- | --- | --- |", + ]; + + for (const decision of result.decisions) { + const codes = decision.reasons.length ? decision.reasons.map((reason) => reason.code).join(", ") : "none"; + lines.push(`| ${decision.eventId} | ${decision.accountName} | ${decision.status} | ${codes} |`); + } + + lines.push("", "## Finance Action"); + lines.push( + "Hold rejected or held trials/promotions before invoice release, route consortium exceptions to finance review, and only let approved discount cents reach revenue reporting.", + ); + return `${lines.join("\n")}\n`; +} + +function buildSummarySvg(result) { + const escapedDigest = result.digest.slice(0, 16); + return ` + + + Trial Promotion Abuse Guard + Revenue control packet ${escapedDigest} + + Approved: ${result.metrics.approvedEvents} + Held: ${result.metrics.heldEvents} + Rejected: ${result.metrics.rejectedEvents} + Leakage prevented: ${money(result.metrics.discountLeakagePreventedCents)} + + + Checks + Trial reuse + Coupon stacking + Consortium eligibility +`; +} + +module.exports = { + buildMarkdownReport, + buildSummarySvg, + evaluatePromotionControls, + money, +}; diff --git a/trial-promotion-abuse-guard/package.json b/trial-promotion-abuse-guard/package.json new file mode 100644 index 0000000..16557a5 --- /dev/null +++ b/trial-promotion-abuse-guard/package.json @@ -0,0 +1,11 @@ +{ + "name": "trial-promotion-abuse-guard", + "version": "1.0.0", + "private": true, + "type": "commonjs", + "scripts": { + "check": "node --check index.js && node --check sample-data.js && node --check test.js && node --check demo.js", + "test": "node test.js", + "demo": "node demo.js" + } +} diff --git a/trial-promotion-abuse-guard/reports/demo.mp4 b/trial-promotion-abuse-guard/reports/demo.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..83b32df6cddbb5ab9ed4c720bc83482283548e4f GIT binary patch literal 32486 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 + + + Trial Promotion Abuse Guard + Revenue control packet 10e4c417b4549c81 + + Approved: 2 + Held: 4 + Rejected: 1 + Leakage prevented: $1310.00 + + + Checks + Trial reuse + Coupon stacking + Consortium eligibility + \ No newline at end of file diff --git a/trial-promotion-abuse-guard/requirements-map.md b/trial-promotion-abuse-guard/requirements-map.md new file mode 100644 index 0000000..35cd11a --- /dev/null +++ b/trial-promotion-abuse-guard/requirements-map.md @@ -0,0 +1,21 @@ +# Requirements Map + +| Issue #20 requirement | Implementation evidence | +| --- | --- | +| Tiered subscription billing | Validates plan eligibility before discounts are applied to Pro, Lab, or Institution plans. | +| Free trials and coupons | Detects domain/payment trial reuse, disposable-domain trials, missing payment readiness, and coupon stacking. | +| Consortium pricing | Requires active consortium roster evidence before the consortium discount is released. | +| AI compute and top-ups | Checks compute top-up promotion eligibility against paid-plan and verified-payment requirements. | +| Usage and revenue visibility | Emits requested, approved, and prevented discount cents in the generated packet. | +| Institutional auditability | Produces JSON, Markdown, SVG, and demo artifacts from deterministic synthetic data. | + +## Scope Boundary + +This is not another billing ledger, usage meter, payment webhook validator, +payment failover module, dispute guard, tax exemption gate, SLA credit module, +royalty settlement, revenue forecast, FX reconciliation, procurement control, +invoice acceptance gate, sanctions/export-control gate, consortium roster +engine, plan-proration module, or AI compute idempotency meter. + +This slice focuses on the promotion and trial boundary before discounts become +invoice-facing revenue. diff --git a/trial-promotion-abuse-guard/sample-data.js b/trial-promotion-abuse-guard/sample-data.js new file mode 100644 index 0000000..2921375 --- /dev/null +++ b/trial-promotion-abuse-guard/sample-data.js @@ -0,0 +1,164 @@ +const sampleData = { + policy: { + maxTrialsPerInstitutionDomain: 1, + maxTrialsPerPaymentFingerprint: 1, + maxStackedPromotions: 1, + maxCombinedDiscountPct: 20, + disposableDomains: ["maildrop.test", "tempinbox.test"], + promotions: { + "LAB-LAUNCH-20": { + discountPct: 20, + eligiblePlans: ["pro", "lab", "institution"], + requires: ["verified_payment"], + }, + "CONSORTIUM-30": { + discountPct: 30, + eligiblePlans: ["institution"], + requires: ["active_consortium_roster", "verified_payment"], + }, + "COMPUTE-TOPUP-15": { + discountPct: 15, + eligiblePlans: ["pro", "lab", "institution"], + appliesTo: "ai_compute_topup", + requires: ["paid_plan", "verified_payment"], + }, + }, + }, + accounts: [ + { + id: "acct-alpha", + name: "Alpha Neuro Lab", + domain: "alpha-university.edu", + plan: "lab", + lifecycle: "trial", + seats: 8, + paymentMethod: {verified: true, fingerprint: "pm-alpha-main"}, + }, + { + id: "acct-alpha-shadow", + name: "Alpha Neuro Lab Sandbox", + domain: "alpha-university.edu", + plan: "lab", + lifecycle: "trial", + seats: 5, + paymentMethod: {verified: true, fingerprint: "pm-alpha-main"}, + }, + { + id: "acct-temp", + name: "Temporary Trial Workspace", + domain: "maildrop.test", + plan: "pro", + lifecycle: "trial", + seats: 1, + paymentMethod: {verified: false, fingerprint: null}, + }, + { + id: "acct-consortium-expired", + name: "Northern Consortium Pilot", + domain: "northern-consortium.edu", + plan: "institution", + lifecycle: "active", + seats: 42, + paymentMethod: {verified: true, fingerprint: "pm-northern"}, + consortiumMembership: {status: "expired", rosterId: "consortium-2025"}, + }, + { + id: "acct-clean", + name: "Harbor Methods Lab", + domain: "harbor.edu", + plan: "lab", + lifecycle: "active", + seats: 12, + paymentMethod: {verified: true, fingerprint: "pm-harbor"}, + }, + { + id: "acct-convert", + name: "Vector Bio Trial", + domain: "vectorbio.org", + plan: "pro", + lifecycle: "trial", + seats: 2, + paymentMethod: {verified: false, fingerprint: null}, + }, + ], + invoices: [ + { + id: "inv-stack", + accountId: "acct-alpha-shadow", + subtotalCents: 240000, + lineItems: ["lab_subscription", "ai_compute_topup"], + }, + { + id: "inv-consortium", + accountId: "acct-consortium-expired", + subtotalCents: 950000, + lineItems: ["institution_subscription"], + }, + { + id: "inv-clean", + accountId: "acct-clean", + subtotalCents: 180000, + lineItems: ["lab_subscription"], + }, + { + id: "inv-convert", + accountId: "acct-convert", + subtotalCents: 59000, + lineItems: ["pro_subscription"], + }, + ], + events: [ + { + id: "evt-alpha-trial", + accountId: "acct-alpha", + type: "trial_started", + timestamp: "2026-05-01T09:30:00Z", + }, + { + id: "evt-alpha-shadow-trial", + accountId: "acct-alpha-shadow", + type: "trial_started", + timestamp: "2026-05-19T10:00:00Z", + }, + { + id: "evt-temp-trial", + accountId: "acct-temp", + type: "trial_started", + timestamp: "2026-05-20T08:00:00Z", + }, + { + id: "evt-alpha-stack", + accountId: "acct-alpha-shadow", + invoiceId: "inv-stack", + type: "promotion_applied", + coupons: ["LAB-LAUNCH-20", "COMPUTE-TOPUP-15"], + timestamp: "2026-05-20T10:15:00Z", + }, + { + id: "evt-consortium-expired", + accountId: "acct-consortium-expired", + invoiceId: "inv-consortium", + type: "promotion_applied", + coupons: ["CONSORTIUM-30"], + timestamp: "2026-05-20T10:30:00Z", + }, + { + id: "evt-convert-missing-payment", + accountId: "acct-convert", + invoiceId: "inv-convert", + type: "trial_conversion", + coupons: ["LAB-LAUNCH-20"], + timestamp: "2026-05-20T11:00:00Z", + }, + { + id: "evt-clean-lab-discount", + accountId: "acct-clean", + invoiceId: "inv-clean", + type: "promotion_applied", + coupons: ["LAB-LAUNCH-20"], + timestamp: "2026-05-20T11:15:00Z", + }, + ], +}; + +module.exports = {sampleData}; diff --git a/trial-promotion-abuse-guard/test.js b/trial-promotion-abuse-guard/test.js new file mode 100644 index 0000000..1f2a6e9 --- /dev/null +++ b/trial-promotion-abuse-guard/test.js @@ -0,0 +1,39 @@ +const assert = require("node:assert/strict"); +const {evaluatePromotionControls, money} = require("./index"); +const {sampleData} = require("./sample-data"); + +const result = evaluatePromotionControls(sampleData); +const byId = new Map(result.decisions.map((decision) => [decision.eventId, decision])); + +assert.equal(result.metrics.totalEvents, 7); +assert.equal(result.metrics.approvedEvents, 2); +assert.equal(result.metrics.heldEvents, 4); +assert.equal(result.metrics.rejectedEvents, 1); + +assert.equal(byId.get("evt-alpha-shadow-trial").status, "hold"); +assert.deepEqual( + byId.get("evt-alpha-shadow-trial").reasons.map((reason) => reason.code).sort(), + ["domain_trial_reuse", "payment_trial_reuse"], +); + +assert.equal(byId.get("evt-temp-trial").status, "rejected"); +assert.equal(byId.get("evt-temp-trial").reasons[0].code, "disposable_domain"); + +assert.equal(byId.get("evt-alpha-stack").status, "hold"); +assert(byId.get("evt-alpha-stack").discountLeakagePreventedCents > 0); +assert.equal(money(byId.get("evt-alpha-stack").discountLeakagePreventedCents), "$360.00"); + +assert.equal(byId.get("evt-consortium-expired").status, "hold"); +assert.equal(byId.get("evt-consortium-expired").reasons[0].code, "consortium_roster_not_active"); + +assert.equal(byId.get("evt-convert-missing-payment").status, "hold"); +assert( + byId + .get("evt-convert-missing-payment") + .reasons.some((reason) => reason.code === "conversion_payment_missing"), +); + +assert.equal(byId.get("evt-clean-lab-discount").status, "approved"); +assert.match(result.digest, /^[a-f0-9]{64}$/); + +console.log("trial promotion abuse guard tests passed");