diff --git a/institutional-sanctions-export-guard/README.md b/institutional-sanctions-export-guard/README.md new file mode 100644 index 00000000..6774b72d --- /dev/null +++ b/institutional-sanctions-export-guard/README.md @@ -0,0 +1,23 @@ +# Institutional Sanctions Export Guard + +This module adds a focused Revenue Infrastructure slice for SCIBASE issue #20. It checks whether institutional and government subscriptions, AI compute bundles, and analytics API exports can be invoiced or activated before compliance clearance. + +The guard holds invoices and entitlements for restricted-party matches, restricted jurisdictions, export-controlled compute or analytics packages without clearance, and unsupported payment rails. Eligible requests can proceed to invoice and revenue recognition. + +## Run + +```bash +npm test +npm run demo +npm run video +npm run check +``` + +## Outputs + +- `reports/eligibility-packet.json` +- `reports/eligibility-report.md` +- `reports/summary.svg` +- `reports/demo.mp4` + +All data is synthetic. The module does not use credentials, private buyers, live sanctions providers, payment rails, bank data, or external APIs. diff --git a/institutional-sanctions-export-guard/acceptance-notes.md b/institutional-sanctions-export-guard/acceptance-notes.md new file mode 100644 index 00000000..77e54577 --- /dev/null +++ b/institutional-sanctions-export-guard/acceptance-notes.md @@ -0,0 +1,16 @@ +# Acceptance Notes + +The implemented slice is intentionally distinct from existing #20 submissions: + +- It is not another subscription ledger, metering ledger, proration guard, renewal true-up, tax exemption module, SLA credit guard, FX settlement guard, dispute guard, receipt privacy guard, cost-share guard, account transfer guard, or analytics usage guard. +- It focuses on institutional/government customer eligibility before invoices, payment-rail handling, AI compute bundles, and analytics license exports are activated. +- It is synthetic-data-only and does not call live sanctions, payment, bank, identity, or customer systems. + +Validation targets: + +- restricted-party and restricted-jurisdiction requests hold invoices and entitlements +- export-controlled compute without clearance creates a high-priority task +- unsupported payment rails route to manual billing review +- eligible institutional customers can activate revenue +- buyer contacts and tax identifiers are redacted from outputs +- summary counts and audit digest are deterministic diff --git a/institutional-sanctions-export-guard/demo.js b/institutional-sanctions-export-guard/demo.js new file mode 100644 index 00000000..2afe19eb --- /dev/null +++ b/institutional-sanctions-export-guard/demo.js @@ -0,0 +1,76 @@ +const fs = require('fs'); +const path = require('path'); +const { + evaluateEligibility, + buildSampleInstitutionalBatch +} = require('./index'); + +const reportsDir = path.join(__dirname, 'reports'); +fs.mkdirSync(reportsDir, { recursive: true }); + +const result = evaluateEligibility(buildSampleInstitutionalBatch()); + +const packetPath = path.join(reportsDir, 'eligibility-packet.json'); +const reportPath = path.join(reportsDir, 'eligibility-report.md'); +const svgPath = path.join(reportsDir, 'summary.svg'); + +fs.writeFileSync(packetPath, `${JSON.stringify(result, null, 2)}\n`); + +const decisions = result.customerDecisions + .map((decision) => `- ${decision.id}: ${decision.decision}${decision.flags.length ? ` (${decision.flags.join(', ')})` : ''}`) + .join('\n'); + +const tasks = result.complianceTasks + .map((task) => `- ${task.id} (${task.priority}): ${task.requiredAction}`) + .join('\n'); + +const markdown = `# Institutional Sanctions Export Guard + +Batch: ${result.batchId} +Generated: ${result.generatedAt} + +## Summary + +- Total requests evaluated: ${result.summary.totalRequests} +- Compliance holds: ${result.summary.complianceHolds} +- Manual billing reviews: ${result.summary.manualReviews} +- Recognizable revenue: $${result.summary.recognizableRevenueUsd} +- Deferred revenue: $${result.summary.deferredRevenueUsd} +- Recommended action: ${result.summary.recommendedAction} +- Audit digest: ${result.auditPacket.auditDigest} + +## Eligibility Decisions + +${decisions} + +## Compliance Tasks + +${tasks} + +## Privacy Notes + +Buyer contacts, tax identifiers, private payment references, and live customer records are not emitted. The packet uses synthetic data only and makes no external sanctions, payment, bank, or identity-provider calls. +`; + +fs.writeFileSync(reportPath, markdown); + +const svg = ` + + + Institutional Sanctions Export Guard + Compliance holds: ${result.summary.complianceHolds} + Manual billing reviews: ${result.summary.manualReviews} + Recognizable revenue: $${result.summary.recognizableRevenueUsd} + Action: ${result.summary.recommendedAction} + Blocks invoices and entitlements until eligibility is cleared. + Synthetic-only audit packet; no live payment or sanctions calls. + ${result.auditPacket.auditDigest} + +`; + +fs.writeFileSync(svgPath, svg); + +console.log(`Wrote ${path.relative(__dirname, packetPath)}`); +console.log(`Wrote ${path.relative(__dirname, reportPath)}`); +console.log(`Wrote ${path.relative(__dirname, svgPath)}`); +console.log(`Recommended action: ${result.summary.recommendedAction}`); diff --git a/institutional-sanctions-export-guard/index.js b/institutional-sanctions-export-guard/index.js new file mode 100644 index 00000000..94d4ba11 --- /dev/null +++ b/institutional-sanctions-export-guard/index.js @@ -0,0 +1,336 @@ +const crypto = require('crypto'); + +const RESTRICTED_JURISDICTIONS = new Set([ + 'restricted-region', + 'embargoed-territory', + 'sanctioned-zone' +]); + +const REVENUE_ENTITLEMENTS = [ + 'institutional-license', + 'ai-compute-bundle', + 'analytics-api-export' +]; + +function stableStringify(value) { + if (Array.isArray(value)) { + return `[${value.map(stableStringify).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 digest(value) { + return `sha256:${crypto.createHash('sha256').update(stableStringify(value)).digest('hex')}`; +} + +function normalize(value) { + return String(value || '').trim().toLowerCase(); +} + +function buyerRef(request) { + return request.publicBuyerRef || `buyer-ref:${request.id}`; +} + +function hasRestrictedJurisdiction(request) { + return RESTRICTED_JURISDICTIONS.has(normalize(request.jurisdiction)); +} + +function hasExportControlGap(request) { + return Boolean( + request.packages.some((item) => item.exportControlled) && + !request.exportClearanceId + ); +} + +function hasPaymentRailGap(request) { + return Boolean(!request.paymentRailAvailable); +} + +function flagsForRequest(request) { + const flags = []; + + if (request.restrictedPartyMatch) { + flags.push('restricted-party-match'); + } + + if (hasRestrictedJurisdiction(request)) { + flags.push('restricted-jurisdiction'); + } + + if (request.packages.some((item) => item.exportControlled)) { + flags.push('export-controlled-compute'); + } + + if (hasExportControlGap(request)) { + flags.push('missing-export-clearance'); + } + + if (hasPaymentRailGap(request)) { + flags.push('payment-rail-unavailable'); + } + + return [...new Set(flags)]; +} + +function decisionForFlags(flags) { + if ( + flags.includes('restricted-party-match') || + flags.includes('restricted-jurisdiction') || + flags.includes('missing-export-clearance') + ) { + return 'compliance-hold'; + } + + if (flags.includes('payment-rail-unavailable')) { + return 'manual-billing-review'; + } + + return 'activate-revenue'; +} + +function evaluateRequest(request) { + const flags = flagsForRequest(request); + const decision = decisionForFlags(flags); + + return { + id: request.id, + buyer: buyerRef(request), + jurisdiction: request.jurisdiction, + customerType: request.customerType, + amountUsd: request.amountUsd, + decision, + flags, + requestedEntitlements: request.packages.map((item) => item.entitlement), + evidenceDigest: digest({ + id: request.id, + buyer: buyerRef(request), + jurisdiction: request.jurisdiction, + customerType: request.customerType, + amountUsd: request.amountUsd, + packages: request.packages, + exportClearanceId: request.exportClearanceId || null, + restrictedPartyMatch: Boolean(request.restrictedPartyMatch), + paymentRailAvailable: Boolean(request.paymentRailAvailable) + }) + }; +} + +function revenueActionForRequest(request, decision) { + if (decision.decision === 'activate-revenue') { + return { + id: `activate-${request.id}`, + requestId: request.id, + buyer: decision.buyer, + invoiceAction: 'issue-invoice', + entitlementAction: 'activate-entitlements', + recognizableAmountUsd: request.amountUsd, + deferredAmountUsd: 0 + }; + } + + if (decision.decision === 'manual-billing-review') { + return { + id: `review-${request.id}`, + requestId: request.id, + buyer: decision.buyer, + invoiceAction: 'manual-review', + entitlementAction: 'defer-activation', + recognizableAmountUsd: 0, + deferredAmountUsd: request.amountUsd, + reviewReasons: decision.flags + }; + } + + return { + id: `hold-${request.id}`, + requestId: request.id, + buyer: decision.buyer, + invoiceAction: 'hold-invoice', + entitlementAction: 'block-entitlements', + recognizableAmountUsd: 0, + deferredAmountUsd: request.amountUsd, + blockedEntitlements: REVENUE_ENTITLEMENTS, + holdReasons: decision.flags + }; +} + +function complianceTaskForDecision(decision) { + if (decision.decision === 'activate-revenue') { + return null; + } + + const exportClearanceNeeded = decision.flags.includes('missing-export-clearance'); + const restrictedPartyNeeded = + decision.flags.includes('restricted-party-match') || + decision.flags.includes('restricted-jurisdiction'); + + return { + id: `task-${decision.id}`, + requestId: decision.id, + buyer: decision.buyer, + priority: decision.decision === 'compliance-hold' ? 'high' : 'normal', + requiredAction: exportClearanceNeeded + ? 'collect-export-clearance-before-revenue-activation' + : restrictedPartyNeeded + ? 'resolve-restricted-party-screening-before-invoicing' + : 'route-to-supported-institutional-payment-rail', + flags: decision.flags, + blockedUntilResolved: decision.decision === 'compliance-hold' + }; +} + +function buildAuditPacket(batch, customerDecisions, revenueActions, complianceTasks) { + const events = [ + ...customerDecisions.map((decision) => ({ + type: 'eligibility-decision', + requestId: decision.id, + buyer: decision.buyer, + decision: decision.decision, + flags: decision.flags + })), + ...revenueActions.map((action) => ({ + type: 'revenue-action', + requestId: action.requestId, + buyer: action.buyer, + invoiceAction: action.invoiceAction, + entitlementAction: action.entitlementAction, + recognizableAmountUsd: action.recognizableAmountUsd, + deferredAmountUsd: action.deferredAmountUsd + })), + ...complianceTasks.map((task) => ({ + type: 'compliance-task', + taskId: task.id, + requestId: task.requestId, + priority: task.priority, + requiredAction: task.requiredAction + })) + ]; + + return { + batchId: batch.batchId, + generatedAt: batch.asOf, + events, + auditDigest: digest({ + batchId: batch.batchId, + generatedAt: batch.asOf, + events + }) + }; +} + +function evaluateEligibility(batch) { + const customerDecisions = batch.requests.map(evaluateRequest); + const revenueActions = batch.requests.map((request, index) => + revenueActionForRequest(request, customerDecisions[index]) + ); + const complianceTasks = customerDecisions + .map(complianceTaskForDecision) + .filter(Boolean); + const auditPacket = buildAuditPacket(batch, customerDecisions, revenueActions, complianceTasks); + + return { + batchId: batch.batchId, + generatedAt: batch.asOf, + customerDecisions, + revenueActions, + complianceTasks, + auditPacket, + summary: { + totalRequests: customerDecisions.length, + complianceHolds: customerDecisions.filter((decision) => decision.decision === 'compliance-hold').length, + manualReviews: customerDecisions.filter((decision) => decision.decision === 'manual-billing-review').length, + recognizableRevenueUsd: revenueActions.reduce( + (total, action) => total + action.recognizableAmountUsd, + 0 + ), + deferredRevenueUsd: revenueActions.reduce( + (total, action) => total + action.deferredAmountUsd, + 0 + ), + recommendedAction: complianceTasks.length > 0 + ? 'pause-institutional-revenue-activation' + : 'activate-eligible-revenue' + } + }; +} + +function buildSampleInstitutionalBatch() { + return { + batchId: 'institutional-eligibility-2026-05-28', + asOf: '2026-05-28T12:55:00Z', + requests: [ + { + id: 'license-cryo-bio-east', + publicBuyerRef: 'buyer-ref:cryo-bio-east', + buyerContact: 'procurement@cryo.example', + taxIdentifier: 'tax-id-998877', + customerType: 'government-lab', + jurisdiction: 'restricted-region', + restrictedPartyMatch: true, + paymentRailAvailable: true, + amountUsd: 120000, + packages: [ + { entitlement: 'institutional-license', exportControlled: false }, + { entitlement: 'ai-compute-bundle', exportControlled: true }, + { entitlement: 'analytics-api-export', exportControlled: true } + ] + }, + { + id: 'license-quantum-lab', + publicBuyerRef: 'buyer-ref:quantum-lab', + customerType: 'institutional-license', + jurisdiction: 'permitted-region', + restrictedPartyMatch: false, + paymentRailAvailable: true, + amountUsd: 64000, + packages: [ + { entitlement: 'institutional-license', exportControlled: false }, + { entitlement: 'ai-compute-bundle', exportControlled: true } + ] + }, + { + id: 'license-field-consortium', + publicBuyerRef: 'buyer-ref:field-consortium', + customerType: 'academic-consortium', + jurisdiction: 'permitted-region', + restrictedPartyMatch: false, + paymentRailAvailable: false, + exportClearanceId: 'clearance-field-2026', + amountUsd: 18000, + packages: [ + { entitlement: 'institutional-license', exportControlled: false }, + { entitlement: 'analytics-api-export', exportControlled: false } + ] + }, + { + id: 'license-open-neuro', + publicBuyerRef: 'buyer-ref:open-neuro', + customerType: 'university', + jurisdiction: 'permitted-region', + restrictedPartyMatch: false, + paymentRailAvailable: true, + exportClearanceId: 'clearance-open-neuro-2026', + amountUsd: 24000, + packages: [ + { entitlement: 'institutional-license', exportControlled: false }, + { entitlement: 'ai-compute-bundle', exportControlled: false }, + { entitlement: 'analytics-api-export', exportControlled: false } + ] + } + ] + }; +} + +module.exports = { + evaluateEligibility, + buildSampleInstitutionalBatch, + digest +}; diff --git a/institutional-sanctions-export-guard/make-demo-video.py b/institutional-sanctions-export-guard/make-demo-video.py new file mode 100644 index 00000000..ee1a7463 --- /dev/null +++ b/institutional-sanctions-export-guard/make-demo-video.py @@ -0,0 +1,71 @@ +from pathlib import Path + +from PIL import Image, ImageDraw, ImageFont + + +ROOT = Path(__file__).resolve().parent +REPORTS = ROOT / "reports" +REPORTS.mkdir(exist_ok=True) +OUTPUT = REPORTS / "demo.mp4" + + +def load_font(size): + for candidate in [ + "C:/Windows/Fonts/arial.ttf", + "C:/Windows/Fonts/segoeui.ttf", + "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", + ]: + path = Path(candidate) + if path.exists(): + return ImageFont.truetype(str(path), size) + return ImageFont.load_default() + + +def frame(progress): + image = Image.new("RGB", (1280, 720), "#18202f") + draw = ImageDraw.Draw(image) + draw.rounded_rectangle((60, 70, 1220, 650), radius=18, fill="#243149", outline="#9ec5ff", width=4) + + title = load_font(44) + heading = load_font(30) + body = load_font(24) + small = load_font(18) + + draw.text((100, 125), "Institutional Sanctions Export Guard", fill="white", font=title) + lines = [ + "Screens institutional subscriptions before invoicing", + "Blocks restricted-party and jurisdiction matches", + "Requires export clearance for AI compute bundles", + "Defers entitlements when payment rails are unsupported", + "Emits finance-ready audit packets", + "Uses synthetic data only" + ] + + visible = min(len(lines), 1 + int(progress * len(lines))) + for index, line in enumerate(lines[:visible]): + y = 205 + index * 54 + draw.text((100, y), line, fill="#e8f1ff", font=heading if index < 3 else body) + + bar_width = int(980 * progress) + draw.rounded_rectangle((100, 590, 1080, 615), radius=10, fill="#33435f") + draw.rounded_rectangle((100, 590, 100 + bar_width, 615), radius=10, fill="#9ec5ff") + draw.text((100, 635), "SCIBASE issue #20 revenue infrastructure slice - synthetic demo", fill="#b9d2ff", font=small) + return image + + +def main(): + try: + import imageio.v3 as iio + except Exception as exc: # pragma: no cover - helper path for local artifact generation + raise SystemExit( + "imageio and imageio-ffmpeg are required to regenerate reports/demo.mp4. " + "The committed demo.mp4 is already generated for review." + ) from exc + + frames = [frame(index / 59) for index in range(60)] + iio.imwrite(OUTPUT, frames, fps=15, codec="libx264", quality=8, macro_block_size=16) + print(f"Wrote {OUTPUT.relative_to(ROOT)}") + + +if __name__ == "__main__": + main() diff --git a/institutional-sanctions-export-guard/package.json b/institutional-sanctions-export-guard/package.json new file mode 100644 index 00000000..9dbbc0d2 --- /dev/null +++ b/institutional-sanctions-export-guard/package.json @@ -0,0 +1,12 @@ +{ + "name": "institutional-sanctions-export-guard", + "version": "1.0.0", + "private": true, + "description": "Dependency-free institutional sanctions and export-control guard for SCIBASE issue #20.", + "scripts": { + "test": "node test.js", + "demo": "node demo.js", + "video": "python make-demo-video.py", + "check": "node --check index.js && node --check test.js && node --check demo.js" + } +} diff --git a/institutional-sanctions-export-guard/reports/demo.mp4 b/institutional-sanctions-export-guard/reports/demo.mp4 new file mode 100644 index 00000000..6420b570 Binary files /dev/null and b/institutional-sanctions-export-guard/reports/demo.mp4 differ diff --git a/institutional-sanctions-export-guard/reports/eligibility-packet.json b/institutional-sanctions-export-guard/reports/eligibility-packet.json new file mode 100644 index 00000000..6bc7c833 --- /dev/null +++ b/institutional-sanctions-export-guard/reports/eligibility-packet.json @@ -0,0 +1,284 @@ +{ + "batchId": "institutional-eligibility-2026-05-28", + "generatedAt": "2026-05-28T12:55:00Z", + "customerDecisions": [ + { + "id": "license-cryo-bio-east", + "buyer": "buyer-ref:cryo-bio-east", + "jurisdiction": "restricted-region", + "customerType": "government-lab", + "amountUsd": 120000, + "decision": "compliance-hold", + "flags": [ + "restricted-party-match", + "restricted-jurisdiction", + "export-controlled-compute", + "missing-export-clearance" + ], + "requestedEntitlements": [ + "institutional-license", + "ai-compute-bundle", + "analytics-api-export" + ], + "evidenceDigest": "sha256:b5c34f1e1733a812dd7a1d543a1e1fe2c28816659d15a05fe851db2f235ee9a6" + }, + { + "id": "license-quantum-lab", + "buyer": "buyer-ref:quantum-lab", + "jurisdiction": "permitted-region", + "customerType": "institutional-license", + "amountUsd": 64000, + "decision": "compliance-hold", + "flags": [ + "export-controlled-compute", + "missing-export-clearance" + ], + "requestedEntitlements": [ + "institutional-license", + "ai-compute-bundle" + ], + "evidenceDigest": "sha256:783eb7d059f9bc8c867355c97858741fc25634ee88e0ff22771586fbc6d998fd" + }, + { + "id": "license-field-consortium", + "buyer": "buyer-ref:field-consortium", + "jurisdiction": "permitted-region", + "customerType": "academic-consortium", + "amountUsd": 18000, + "decision": "manual-billing-review", + "flags": [ + "payment-rail-unavailable" + ], + "requestedEntitlements": [ + "institutional-license", + "analytics-api-export" + ], + "evidenceDigest": "sha256:547a30030f792ccd1f1bd6091ec20cf627e2b107c70bab4c3c2f751bab275c71" + }, + { + "id": "license-open-neuro", + "buyer": "buyer-ref:open-neuro", + "jurisdiction": "permitted-region", + "customerType": "university", + "amountUsd": 24000, + "decision": "activate-revenue", + "flags": [], + "requestedEntitlements": [ + "institutional-license", + "ai-compute-bundle", + "analytics-api-export" + ], + "evidenceDigest": "sha256:56429705181faa284b45fb55a385546a886406905a3778384b536f9b872c51ac" + } + ], + "revenueActions": [ + { + "id": "hold-license-cryo-bio-east", + "requestId": "license-cryo-bio-east", + "buyer": "buyer-ref:cryo-bio-east", + "invoiceAction": "hold-invoice", + "entitlementAction": "block-entitlements", + "recognizableAmountUsd": 0, + "deferredAmountUsd": 120000, + "blockedEntitlements": [ + "institutional-license", + "ai-compute-bundle", + "analytics-api-export" + ], + "holdReasons": [ + "restricted-party-match", + "restricted-jurisdiction", + "export-controlled-compute", + "missing-export-clearance" + ] + }, + { + "id": "hold-license-quantum-lab", + "requestId": "license-quantum-lab", + "buyer": "buyer-ref:quantum-lab", + "invoiceAction": "hold-invoice", + "entitlementAction": "block-entitlements", + "recognizableAmountUsd": 0, + "deferredAmountUsd": 64000, + "blockedEntitlements": [ + "institutional-license", + "ai-compute-bundle", + "analytics-api-export" + ], + "holdReasons": [ + "export-controlled-compute", + "missing-export-clearance" + ] + }, + { + "id": "review-license-field-consortium", + "requestId": "license-field-consortium", + "buyer": "buyer-ref:field-consortium", + "invoiceAction": "manual-review", + "entitlementAction": "defer-activation", + "recognizableAmountUsd": 0, + "deferredAmountUsd": 18000, + "reviewReasons": [ + "payment-rail-unavailable" + ] + }, + { + "id": "activate-license-open-neuro", + "requestId": "license-open-neuro", + "buyer": "buyer-ref:open-neuro", + "invoiceAction": "issue-invoice", + "entitlementAction": "activate-entitlements", + "recognizableAmountUsd": 24000, + "deferredAmountUsd": 0 + } + ], + "complianceTasks": [ + { + "id": "task-license-cryo-bio-east", + "requestId": "license-cryo-bio-east", + "buyer": "buyer-ref:cryo-bio-east", + "priority": "high", + "requiredAction": "collect-export-clearance-before-revenue-activation", + "flags": [ + "restricted-party-match", + "restricted-jurisdiction", + "export-controlled-compute", + "missing-export-clearance" + ], + "blockedUntilResolved": true + }, + { + "id": "task-license-quantum-lab", + "requestId": "license-quantum-lab", + "buyer": "buyer-ref:quantum-lab", + "priority": "high", + "requiredAction": "collect-export-clearance-before-revenue-activation", + "flags": [ + "export-controlled-compute", + "missing-export-clearance" + ], + "blockedUntilResolved": true + }, + { + "id": "task-license-field-consortium", + "requestId": "license-field-consortium", + "buyer": "buyer-ref:field-consortium", + "priority": "normal", + "requiredAction": "route-to-supported-institutional-payment-rail", + "flags": [ + "payment-rail-unavailable" + ], + "blockedUntilResolved": false + } + ], + "auditPacket": { + "batchId": "institutional-eligibility-2026-05-28", + "generatedAt": "2026-05-28T12:55:00Z", + "events": [ + { + "type": "eligibility-decision", + "requestId": "license-cryo-bio-east", + "buyer": "buyer-ref:cryo-bio-east", + "decision": "compliance-hold", + "flags": [ + "restricted-party-match", + "restricted-jurisdiction", + "export-controlled-compute", + "missing-export-clearance" + ] + }, + { + "type": "eligibility-decision", + "requestId": "license-quantum-lab", + "buyer": "buyer-ref:quantum-lab", + "decision": "compliance-hold", + "flags": [ + "export-controlled-compute", + "missing-export-clearance" + ] + }, + { + "type": "eligibility-decision", + "requestId": "license-field-consortium", + "buyer": "buyer-ref:field-consortium", + "decision": "manual-billing-review", + "flags": [ + "payment-rail-unavailable" + ] + }, + { + "type": "eligibility-decision", + "requestId": "license-open-neuro", + "buyer": "buyer-ref:open-neuro", + "decision": "activate-revenue", + "flags": [] + }, + { + "type": "revenue-action", + "requestId": "license-cryo-bio-east", + "buyer": "buyer-ref:cryo-bio-east", + "invoiceAction": "hold-invoice", + "entitlementAction": "block-entitlements", + "recognizableAmountUsd": 0, + "deferredAmountUsd": 120000 + }, + { + "type": "revenue-action", + "requestId": "license-quantum-lab", + "buyer": "buyer-ref:quantum-lab", + "invoiceAction": "hold-invoice", + "entitlementAction": "block-entitlements", + "recognizableAmountUsd": 0, + "deferredAmountUsd": 64000 + }, + { + "type": "revenue-action", + "requestId": "license-field-consortium", + "buyer": "buyer-ref:field-consortium", + "invoiceAction": "manual-review", + "entitlementAction": "defer-activation", + "recognizableAmountUsd": 0, + "deferredAmountUsd": 18000 + }, + { + "type": "revenue-action", + "requestId": "license-open-neuro", + "buyer": "buyer-ref:open-neuro", + "invoiceAction": "issue-invoice", + "entitlementAction": "activate-entitlements", + "recognizableAmountUsd": 24000, + "deferredAmountUsd": 0 + }, + { + "type": "compliance-task", + "taskId": "task-license-cryo-bio-east", + "requestId": "license-cryo-bio-east", + "priority": "high", + "requiredAction": "collect-export-clearance-before-revenue-activation" + }, + { + "type": "compliance-task", + "taskId": "task-license-quantum-lab", + "requestId": "license-quantum-lab", + "priority": "high", + "requiredAction": "collect-export-clearance-before-revenue-activation" + }, + { + "type": "compliance-task", + "taskId": "task-license-field-consortium", + "requestId": "license-field-consortium", + "priority": "normal", + "requiredAction": "route-to-supported-institutional-payment-rail" + } + ], + "auditDigest": "sha256:32c9498352303c377a36cca197d413edce926ebac3c8d1d29d778e41192d3e44" + }, + "summary": { + "totalRequests": 4, + "complianceHolds": 2, + "manualReviews": 1, + "recognizableRevenueUsd": 24000, + "deferredRevenueUsd": 202000, + "recommendedAction": "pause-institutional-revenue-activation" + } +} diff --git a/institutional-sanctions-export-guard/reports/eligibility-report.md b/institutional-sanctions-export-guard/reports/eligibility-report.md new file mode 100644 index 00000000..23949f31 --- /dev/null +++ b/institutional-sanctions-export-guard/reports/eligibility-report.md @@ -0,0 +1,31 @@ +# Institutional Sanctions Export Guard + +Batch: institutional-eligibility-2026-05-28 +Generated: 2026-05-28T12:55:00Z + +## Summary + +- Total requests evaluated: 4 +- Compliance holds: 2 +- Manual billing reviews: 1 +- Recognizable revenue: $24000 +- Deferred revenue: $202000 +- Recommended action: pause-institutional-revenue-activation +- Audit digest: sha256:32c9498352303c377a36cca197d413edce926ebac3c8d1d29d778e41192d3e44 + +## Eligibility Decisions + +- license-cryo-bio-east: compliance-hold (restricted-party-match, restricted-jurisdiction, export-controlled-compute, missing-export-clearance) +- license-quantum-lab: compliance-hold (export-controlled-compute, missing-export-clearance) +- license-field-consortium: manual-billing-review (payment-rail-unavailable) +- license-open-neuro: activate-revenue + +## Compliance Tasks + +- task-license-cryo-bio-east (high): collect-export-clearance-before-revenue-activation +- task-license-quantum-lab (high): collect-export-clearance-before-revenue-activation +- task-license-field-consortium (normal): route-to-supported-institutional-payment-rail + +## Privacy Notes + +Buyer contacts, tax identifiers, private payment references, and live customer records are not emitted. The packet uses synthetic data only and makes no external sanctions, payment, bank, or identity-provider calls. diff --git a/institutional-sanctions-export-guard/reports/summary.svg b/institutional-sanctions-export-guard/reports/summary.svg new file mode 100644 index 00000000..9aa37f7e --- /dev/null +++ b/institutional-sanctions-export-guard/reports/summary.svg @@ -0,0 +1,12 @@ + + + + Institutional Sanctions Export Guard + Compliance holds: 2 + Manual billing reviews: 1 + Recognizable revenue: $24000 + Action: pause-institutional-revenue-activation + Blocks invoices and entitlements until eligibility is cleared. + Synthetic-only audit packet; no live payment or sanctions calls. + sha256:32c9498352303c377a36cca197d413edce926ebac3c8d1d29d778e41192d3e44 + diff --git a/institutional-sanctions-export-guard/requirements-map.md b/institutional-sanctions-export-guard/requirements-map.md new file mode 100644 index 00000000..25b66727 --- /dev/null +++ b/institutional-sanctions-export-guard/requirements-map.md @@ -0,0 +1,25 @@ +# Requirements Map + +## Tiered Subscription Billing + +- Institutional and government license requests are represented as billable revenue requests. +- Invoice issuance is blocked when compliance evidence is missing. +- Payment-rail gaps route requests to manual billing review before activation. + +## AI Compute Billing + +- Export-controlled compute bundles require clearance before entitlement activation. +- Revenue is deferred while compute access is held. +- Audit events preserve why compute access was blocked or activated. + +## Licensing APIs And Analytics + +- Analytics API exports are treated as monetized license packages. +- Restricted-party and restricted-jurisdiction findings block export activation. +- Reports avoid buyer contacts, tax identifiers, private payment references, and live customer data. + +## Revenue Recognition + +- Eligible requests produce recognizable revenue. +- Held or manually reviewed requests defer revenue. +- The audit digest is deterministic for finance and reviewer verification. diff --git a/institutional-sanctions-export-guard/test.js b/institutional-sanctions-export-guard/test.js new file mode 100644 index 00000000..5b7f1665 --- /dev/null +++ b/institutional-sanctions-export-guard/test.js @@ -0,0 +1,100 @@ +const assert = require('assert'); +const { + evaluateEligibility, + buildSampleInstitutionalBatch +} = require('./index'); + +function byId(items, id) { + return items.find((item) => item.id === id); +} + +function testRestrictedPartyBlocksActivationAndInvoice() { + const result = evaluateEligibility(buildSampleInstitutionalBatch()); + const decision = byId(result.customerDecisions, 'license-cryo-bio-east'); + + assert.equal(decision.decision, 'compliance-hold'); + assert.ok(decision.flags.includes('restricted-party-match')); + assert.ok(decision.flags.includes('restricted-jurisdiction')); + + const action = byId(result.revenueActions, 'hold-license-cryo-bio-east'); + assert.equal(action.invoiceAction, 'hold-invoice'); + assert.deepEqual(action.blockedEntitlements, [ + 'institutional-license', + 'ai-compute-bundle', + 'analytics-api-export' + ]); +} + +function testExportControlledPackageRequiresManualClearance() { + const result = evaluateEligibility(buildSampleInstitutionalBatch()); + const decision = byId(result.customerDecisions, 'license-quantum-lab'); + + assert.equal(decision.decision, 'compliance-hold'); + assert.ok(decision.flags.includes('export-controlled-compute')); + assert.ok(decision.flags.includes('missing-export-clearance')); + + const task = byId(result.complianceTasks, 'task-license-quantum-lab'); + assert.equal(task.priority, 'high'); + assert.equal(task.requiredAction, 'collect-export-clearance-before-revenue-activation'); +} + +function testPaymentRailGapRoutesInstitutionalInvoiceWithoutActivation() { + const result = evaluateEligibility(buildSampleInstitutionalBatch()); + const decision = byId(result.customerDecisions, 'license-field-consortium'); + + assert.equal(decision.decision, 'manual-billing-review'); + assert.ok(decision.flags.includes('payment-rail-unavailable')); + + const action = byId(result.revenueActions, 'review-license-field-consortium'); + assert.equal(action.invoiceAction, 'manual-review'); + assert.equal(action.entitlementAction, 'defer-activation'); +} + +function testEligibleCustomerCanActivateRevenue() { + const result = evaluateEligibility(buildSampleInstitutionalBatch()); + const decision = byId(result.customerDecisions, 'license-open-neuro'); + + assert.equal(decision.decision, 'activate-revenue'); + assert.deepEqual(decision.flags, []); + + const action = byId(result.revenueActions, 'activate-license-open-neuro'); + assert.equal(action.invoiceAction, 'issue-invoice'); + assert.equal(action.entitlementAction, 'activate-entitlements'); + assert.equal(action.recognizableAmountUsd, 24000); +} + +function testPrivateBuyerIdentifiersAreRedacted() { + const result = evaluateEligibility(buildSampleInstitutionalBatch()); + const serialized = JSON.stringify(result); + + assert.ok(serialized.includes('buyer-ref:cryo-bio-east')); + assert.ok(!serialized.includes('procurement@cryo.example')); + assert.ok(!serialized.includes('tax-id-998877')); +} + +function testAuditDigestAndSummaryAreDeterministic() { + const first = evaluateEligibility(buildSampleInstitutionalBatch()); + const second = evaluateEligibility(buildSampleInstitutionalBatch()); + + assert.equal(first.summary.totalRequests, 4); + assert.equal(first.summary.complianceHolds, 2); + assert.equal(first.summary.manualReviews, 1); + assert.equal(first.summary.recognizableRevenueUsd, 24000); + assert.equal(first.auditPacket.auditDigest, second.auditPacket.auditDigest); + assert.ok(first.auditPacket.auditDigest.startsWith('sha256:')); +} + +const tests = [ + testRestrictedPartyBlocksActivationAndInvoice, + testExportControlledPackageRequiresManualClearance, + testPaymentRailGapRoutesInstitutionalInvoiceWithoutActivation, + testEligibleCustomerCanActivateRevenue, + testPrivateBuyerIdentifiersAreRedacted, + testAuditDigestAndSummaryAreDeterministic +]; + +for (const test of tests) { + test(); +} + +console.log(`${tests.length} institutional sanctions export guard tests passed`);