From 21d6863148ec03baeb20e2ccc7a052ff5f5a862e Mon Sep 17 00:00:00 2001 From: SIRXIII Date: Sat, 16 May 2026 10:37:46 -0700 Subject: [PATCH] Add bounty payout eligibility gate --- README.md | 4 + bounty-payout-eligibility-gate/README.md | 30 ++ bounty-payout-eligibility-gate/demo.js | 25 ++ bounty-payout-eligibility-gate/docs/demo.mp4 | Bin 0 -> 71904 bytes bounty-payout-eligibility-gate/docs/demo.svg | 46 +++ .../docs/requirement-map.md | 20 ++ bounty-payout-eligibility-gate/package.json | 13 + .../sample-data.json | 55 +++ .../src/eligibilityGate.js | 315 ++++++++++++++++++ bounty-payout-eligibility-gate/test.js | 92 +++++ 10 files changed, 600 insertions(+) create mode 100644 bounty-payout-eligibility-gate/README.md create mode 100644 bounty-payout-eligibility-gate/demo.js create mode 100644 bounty-payout-eligibility-gate/docs/demo.mp4 create mode 100644 bounty-payout-eligibility-gate/docs/demo.svg create mode 100644 bounty-payout-eligibility-gate/docs/requirement-map.md create mode 100644 bounty-payout-eligibility-gate/package.json create mode 100644 bounty-payout-eligibility-gate/sample-data.json create mode 100644 bounty-payout-eligibility-gate/src/eligibilityGate.js create mode 100644 bounty-payout-eligibility-gate/test.js diff --git a/README.md b/README.md index d338cf6..58d9f2e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ # deepevents.ai deepevents.ai main codebase + +## Scientific Bounty System Modules + +- [Bounty Payout Eligibility Gate](bounty-payout-eligibility-gate/README.md): solver/team payout readiness checks for country support, payout method evidence, tax and institution routing, sanctions risk, IP release guardrails, remediation actions, and signed audit packets. diff --git a/bounty-payout-eligibility-gate/README.md b/bounty-payout-eligibility-gate/README.md new file mode 100644 index 0000000..dd52c99 --- /dev/null +++ b/bounty-payout-eligibility-gate/README.md @@ -0,0 +1,30 @@ +# Bounty Payout Eligibility Gate + +Dependency-free Scientific Bounty System module that evaluates whether a solver team can safely move from reward decision to payout settlement. + +This slice focuses on payout eligibility and compliance readiness, which is separate from challenge intake, scoring, arbitration, appeals, anti-collusion, escrow settlement, sponsor reliability, and amendment consent modules. + +## What it does + +- Checks contributor identity attestations and supported payout countries. +- Validates payout method, tax form, and institution routing evidence. +- Flags sanctions/watchlist risk and unresolved compliance notes. +- Keeps IP release blocked until the team is eligible and settlement is funded. +- Produces sponsor-facing remediation actions by contributor. +- Emits a signed audit packet for payout review. + +All examples are synthetic and no external services, credentials, or personal data are required. + +## Run + +```bash +npm run check +npm test +npm run demo +``` + +The demo reads `sample-data.json` and prints a deterministic settlement readiness packet. + +## Demo Video + +`docs/demo.mp4` is a short H.264 walkthrough artifact generated from `docs/demo.svg`. diff --git a/bounty-payout-eligibility-gate/demo.js b/bounty-payout-eligibility-gate/demo.js new file mode 100644 index 0000000..a61bc53 --- /dev/null +++ b/bounty-payout-eligibility-gate/demo.js @@ -0,0 +1,25 @@ +const sample = require("./sample-data.json"); +const { buildPayoutReadinessPacket, summarizeForSponsor } = require("./src/eligibilityGate"); + +const packet = buildPayoutReadinessPacket(sample); +const sponsorSummary = summarizeForSponsor(packet); + +console.log("Bounty payout eligibility gate demo"); +console.log("------------------------------------"); +console.log(`Challenge: ${packet.challengeTitle}`); +console.log(`Team: ${packet.teamName}`); +console.log(`Bounty: $${packet.bountyAmountUsd}`); +console.log(`Status: ${packet.status}`); +console.log(`Settlement recommendation: ${sponsorSummary.settlementRecommendation}`); +console.log(`IP release: ${packet.ipRelease}`); +console.log(`Audit digest: ${packet.auditDigest}`); +console.log(""); +console.log("Payout plan:"); +for (const entry of packet.payoutPlan) { + console.log(`- ${entry.displayName}: ${entry.percent}% / $${entry.amountUsd} / ${entry.routingStatus}`); +} +console.log(""); +console.log("Remediation actions:"); +for (const item of packet.remediationActions) { + console.log(`- [${item.severity}] ${item.owner}: ${item.message}`); +} diff --git a/bounty-payout-eligibility-gate/docs/demo.mp4 b/bounty-payout-eligibility-gate/docs/demo.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..22a5b4350f9cd36dd5f59f10a66e9c36643540fb GIT binary patch literal 71904 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 ?dduv0$(izbGVM~}~?P%#vl?f3km}jEHSFfFu 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 k``xjce(RB0m#HPVB_HUAJx8C-T(jq literal 0 HcmV?d00001 diff --git a/bounty-payout-eligibility-gate/docs/demo.svg b/bounty-payout-eligibility-gate/docs/demo.svg new file mode 100644 index 0000000..ce7182b --- /dev/null +++ b/bounty-payout-eligibility-gate/docs/demo.svg @@ -0,0 +1,46 @@ + + Bounty payout eligibility gate demo + Diagram showing challenge reward, payout eligibility checks, remediation actions, and signed audit packet. + + + Bounty Payout Eligibility Gate + Scientific Bounty System payout readiness before settlement release + + + + Reward Decision + $1,000 bounty funded + Team split: 70 / 30 + + + + + Eligibility Checks + Identity attestation + Supported payout country + Tax and institution routing + Watchlist and IP release guards + + + + + Status: Blocked + Missing payout method + Missing tax form + + + + + + + + Signed Audit Packet + Sponsor receives remediation actions, payout plan, IP release status, and deterministic SHA-256 audit digest. + + + + + + + + diff --git a/bounty-payout-eligibility-gate/docs/requirement-map.md b/bounty-payout-eligibility-gate/docs/requirement-map.md new file mode 100644 index 0000000..8c3844a --- /dev/null +++ b/bounty-payout-eligibility-gate/docs/requirement-map.md @@ -0,0 +1,20 @@ +# Requirement Map + +This module maps to issue #18, Scientific Bounty System. + +| Issue capability | Implementation | +| --- | --- | +| Reward distribution | Builds contributor-level payout plan from award splits and bounty amount. | +| Payout routing | Checks payout method evidence, country support, tax form status, and institution routing approval. | +| Escrowed prize funds | Blocks settlement if sponsor funds are not confirmed. | +| Team and institution payouts | Supports contributor splits plus institution approval holds. | +| IP management options | Keeps IP release blocked until payout eligibility and funding are ready. | +| Platform-mediated arbitration | Emits signed audit packets and sponsor-facing remediation actions for payout review. | +| Secure solver participation | Flags identity attestation and watchlist review blockers before funds move. | + +## Acceptance Evidence + +- `npm run check` +- `npm test` +- `npm run demo` +- `docs/demo.mp4` diff --git a/bounty-payout-eligibility-gate/package.json b/bounty-payout-eligibility-gate/package.json new file mode 100644 index 0000000..5a08a94 --- /dev/null +++ b/bounty-payout-eligibility-gate/package.json @@ -0,0 +1,13 @@ +{ + "name": "bounty-payout-eligibility-gate", + "version": "1.0.0", + "description": "Payout eligibility and compliance readiness gate for scientific bounty teams.", + "type": "commonjs", + "private": true, + "scripts": { + "check": "node --check src/eligibilityGate.js && node --check test.js && node --check demo.js", + "test": "node test.js", + "demo": "node demo.js" + }, + "license": "MIT" +} diff --git a/bounty-payout-eligibility-gate/sample-data.json b/bounty-payout-eligibility-gate/sample-data.json new file mode 100644 index 0000000..9eb6de7 --- /dev/null +++ b/bounty-payout-eligibility-gate/sample-data.json @@ -0,0 +1,55 @@ +{ + "challenge": { + "id": "CH-2026-BIOMARKER-042", + "title": "Single-cell biomarker discovery challenge", + "bountyAmountUsd": 1000, + "settlementFunded": true, + "ipPolicy": "solver-retains-until-paid", + "sponsor": "Northstar Bioinformatics Lab" + }, + "team": { + "id": "TEAM-ALPHA", + "name": "Open Reproducibility Alpha", + "awardSplits": [ + { + "contributorId": "solver-1", + "percent": 70 + }, + { + "contributorId": "solver-2", + "percent": 30 + } + ], + "contributors": [ + { + "id": "solver-1", + "displayName": "Dr. A. Rivera", + "country": "US", + "identityAttested": true, + "payoutMethodVerified": true, + "taxFormStatus": "valid", + "institutionRouting": { + "required": false, + "approved": false + }, + "watchlistStatus": "clear", + "ipAssignmentConsent": true + }, + { + "id": "solver-2", + "displayName": "M. Chen", + "country": "CA", + "identityAttested": true, + "payoutMethodVerified": false, + "taxFormStatus": "missing", + "institutionRouting": { + "required": true, + "approved": false, + "institution": "Example University" + }, + "watchlistStatus": "clear", + "ipAssignmentConsent": true + } + ] + } +} diff --git a/bounty-payout-eligibility-gate/src/eligibilityGate.js b/bounty-payout-eligibility-gate/src/eligibilityGate.js new file mode 100644 index 0000000..daa6c9c --- /dev/null +++ b/bounty-payout-eligibility-gate/src/eligibilityGate.js @@ -0,0 +1,315 @@ +const crypto = require("crypto"); + +const DEFAULT_SUPPORTED_COUNTRIES = new Set([ + "AT", + "AU", + "BE", + "BR", + "CA", + "CH", + "DE", + "DK", + "ES", + "FI", + "FR", + "GB", + "IE", + "IT", + "JP", + "NL", + "NO", + "NZ", + "PT", + "SE", + "SG", + "US" +]); + +const BLOCKED_WATCHLIST_STATUSES = new Set(["match", "blocked", "review-required"]); + +function normalizeCountry(country) { + return String(country || "").trim().toUpperCase(); +} + +function stableJson(value) { + if (Array.isArray(value)) { + return `[${value.map(stableJson).join(",")}]`; + } + + if (value && typeof value === "object") { + return `{${Object.keys(value) + .sort() + .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`) + .join(",")}}`; + } + + return JSON.stringify(value); +} + +function auditDigest(value) { + return crypto.createHash("sha256").update(stableJson(value)).digest("hex"); +} + +function action(code, severity, message, owner, dueInDays) { + return { + code, + severity, + owner, + dueInDays, + message + }; +} + +function evaluateContributor(contributor, supportedCountries = DEFAULT_SUPPORTED_COUNTRIES) { + const country = normalizeCountry(contributor.country); + const actions = []; + + if (!contributor.identityAttested) { + actions.push( + action( + "identity_attestation_required", + "blocker", + "Collect contributor identity attestation before payout review.", + contributor.id, + 2 + ) + ); + } + + if (!supportedCountries.has(country)) { + actions.push( + action( + "unsupported_payout_country", + "blocker", + `Country ${country || "UNKNOWN"} is not currently enabled for direct payout routing.`, + contributor.id, + 1 + ) + ); + } + + if (!contributor.payoutMethodVerified) { + actions.push( + action( + "payout_method_required", + "blocker", + "Verify payout method before settlement can be released.", + contributor.id, + 3 + ) + ); + } + + if (contributor.taxFormStatus !== "valid") { + actions.push( + action( + "tax_form_required", + "blocker", + "Collect a valid tax form or platform-approved tax attestation.", + contributor.id, + 5 + ) + ); + } + + if (contributor.institutionRouting?.required && !contributor.institutionRouting.approved) { + actions.push( + action( + "institution_routing_approval_required", + "hold", + `Confirm payout routing with ${contributor.institutionRouting.institution || "the contributor institution"}.`, + contributor.id, + 5 + ) + ); + } + + if (BLOCKED_WATCHLIST_STATUSES.has(String(contributor.watchlistStatus || "").toLowerCase())) { + actions.push( + action( + "watchlist_review_required", + "blocker", + "Hold settlement until compliance review clears the contributor.", + contributor.id, + 1 + ) + ); + } + + if (!contributor.ipAssignmentConsent) { + actions.push( + action( + "ip_release_consent_required", + "hold", + "Confirm IP handoff consent before releasing sponsor license rights.", + contributor.id, + 4 + ) + ); + } + + const blockers = actions.filter((item) => item.severity === "blocker"); + const holds = actions.filter((item) => item.severity === "hold"); + const status = blockers.length > 0 ? "blocked" : holds.length > 0 ? "hold" : "ready"; + + return { + contributorId: contributor.id, + displayName: contributor.displayName, + country, + status, + blockerCount: blockers.length, + holdCount: holds.length, + actions + }; +} + +function validateAwardSplits(team) { + const contributorIds = new Set(team.contributors.map((contributor) => contributor.id)); + const splitTotal = team.awardSplits.reduce((sum, split) => sum + Number(split.percent || 0), 0); + const unknownSplits = team.awardSplits.filter((split) => !contributorIds.has(split.contributorId)); + const missingSplits = team.contributors.filter( + (contributor) => !team.awardSplits.some((split) => split.contributorId === contributor.id) + ); + const actions = []; + + if (Math.round(splitTotal * 100) / 100 !== 100) { + actions.push( + action( + "award_split_total_invalid", + "blocker", + `Award splits must total 100 percent; current total is ${splitTotal}.`, + team.id, + 1 + ) + ); + } + + for (const split of unknownSplits) { + actions.push( + action( + "award_split_unknown_contributor", + "blocker", + `Award split references unknown contributor ${split.contributorId}.`, + team.id, + 1 + ) + ); + } + + for (const contributor of missingSplits) { + actions.push( + action( + "award_split_missing_contributor", + "hold", + `Contributor ${contributor.id} has no payout split.`, + team.id, + 2 + ) + ); + } + + return { + splitTotal, + actions + }; +} + +function buildPayoutReadinessPacket(input, options = {}) { + const supportedCountries = options.supportedCountries + ? new Set([...options.supportedCountries].map(normalizeCountry)) + : DEFAULT_SUPPORTED_COUNTRIES; + const challenge = input.challenge; + const team = input.team; + const contributorResults = team.contributors.map((contributor) => + evaluateContributor(contributor, supportedCountries) + ); + const splitCheck = validateAwardSplits(team); + const contributorActions = contributorResults.flatMap((result) => result.actions); + const allActions = [...splitCheck.actions, ...contributorActions]; + const blockerCount = allActions.filter((item) => item.severity === "blocker").length; + const holdCount = allActions.filter((item) => item.severity === "hold").length; + const challengeActions = []; + + if (!challenge.settlementFunded) { + challengeActions.push( + action( + "settlement_not_funded", + "blocker", + "Sponsor funds must be confirmed before payout release.", + challenge.id, + 1 + ) + ); + } + + const finalActions = [...challengeActions, ...allActions]; + const finalBlockers = finalActions.filter((item) => item.severity === "blocker").length; + const finalHolds = finalActions.filter((item) => item.severity === "hold").length; + const status = finalBlockers > 0 ? "blocked" : finalHolds > 0 ? "hold" : "ready"; + const ipRelease = status === "ready" && challenge.settlementFunded ? "release-after-payout" : "blocked-until-ready"; + const payoutPlan = team.awardSplits.map((split) => { + const contributor = team.contributors.find((item) => item.id === split.contributorId); + return { + contributorId: split.contributorId, + displayName: contributor?.displayName || split.contributorId, + percent: split.percent, + amountUsd: Math.round(challenge.bountyAmountUsd * (Number(split.percent) / 100) * 100) / 100, + routingStatus: + contributorResults.find((result) => result.contributorId === split.contributorId)?.status || "unknown" + }; + }); + const unsignedPacket = { + challengeId: challenge.id, + challengeTitle: challenge.title, + sponsor: challenge.sponsor, + teamId: team.id, + teamName: team.name, + bountyAmountUsd: challenge.bountyAmountUsd, + settlementFunded: challenge.settlementFunded, + status, + blockerCount: finalBlockers, + holdCount: finalHolds, + ipRelease, + contributorResults, + payoutPlan, + remediationActions: finalActions.sort((left, right) => { + const severityRank = { blocker: 0, hold: 1, info: 2 }; + return severityRank[left.severity] - severityRank[right.severity] || left.dueInDays - right.dueInDays; + }) + }; + + return { + ...unsignedPacket, + auditDigest: auditDigest(unsignedPacket) + }; +} + +function summarizeForSponsor(packet) { + return { + status: packet.status, + settlementRecommendation: + packet.status === "ready" + ? "release_payout" + : packet.status === "hold" + ? "hold_for_routing_confirmation" + : "block_until_remediated", + nextActions: packet.remediationActions.map((item) => ({ + code: item.code, + owner: item.owner, + dueInDays: item.dueInDays, + message: item.message + })), + auditDigest: packet.auditDigest + }; +} + +module.exports = { + DEFAULT_SUPPORTED_COUNTRIES, + auditDigest, + buildPayoutReadinessPacket, + evaluateContributor, + normalizeCountry, + stableJson, + summarizeForSponsor, + validateAwardSplits +}; diff --git a/bounty-payout-eligibility-gate/test.js b/bounty-payout-eligibility-gate/test.js new file mode 100644 index 0000000..b1ed918 --- /dev/null +++ b/bounty-payout-eligibility-gate/test.js @@ -0,0 +1,92 @@ +const assert = require("assert"); +const sample = require("./sample-data.json"); +const { + auditDigest, + buildPayoutReadinessPacket, + evaluateContributor, + normalizeCountry, + stableJson, + summarizeForSponsor, + validateAwardSplits +} = require("./src/eligibilityGate"); + +function clone(value) { + return JSON.parse(JSON.stringify(value)); +} + +function testContributorReadiness() { + const ready = evaluateContributor(sample.team.contributors[0]); + assert.equal(ready.status, "ready"); + assert.equal(ready.actions.length, 0); + + const blocked = evaluateContributor({ + id: "solver-x", + displayName: "Solver X", + country: "zz", + identityAttested: false, + payoutMethodVerified: false, + taxFormStatus: "missing", + institutionRouting: { required: true, approved: false }, + watchlistStatus: "review-required", + ipAssignmentConsent: false + }); + + assert.equal(blocked.status, "blocked"); + assert(blocked.actions.some((item) => item.code === "unsupported_payout_country")); + assert(blocked.actions.some((item) => item.code === "watchlist_review_required")); + assert(blocked.actions.some((item) => item.code === "ip_release_consent_required")); +} + +function testAwardSplitValidation() { + const splitCheck = validateAwardSplits(sample.team); + assert.equal(splitCheck.splitTotal, 100); + assert.equal(splitCheck.actions.length, 0); + + const broken = clone(sample.team); + broken.awardSplits[0].percent = 60; + const brokenCheck = validateAwardSplits(broken); + assert(brokenCheck.actions.some((item) => item.code === "award_split_total_invalid")); +} + +function testPacketBlocksUntilPayoutEvidenceIsReady() { + const packet = buildPayoutReadinessPacket(sample); + assert.equal(packet.status, "blocked"); + assert.equal(packet.ipRelease, "blocked-until-ready"); + assert(packet.auditDigest.length === 64); + assert(packet.payoutPlan.some((entry) => entry.contributorId === "solver-2" && entry.amountUsd === 300)); + assert(packet.remediationActions[0].severity === "blocker"); + + const sponsorSummary = summarizeForSponsor(packet); + assert.equal(sponsorSummary.settlementRecommendation, "block_until_remediated"); + assert(sponsorSummary.nextActions.some((item) => item.code === "payout_method_required")); +} + +function testReadyPacketReleasesOnlyWhenFunded() { + const ready = clone(sample); + ready.team.contributors[1].payoutMethodVerified = true; + ready.team.contributors[1].taxFormStatus = "valid"; + ready.team.contributors[1].institutionRouting.approved = true; + const readyPacket = buildPayoutReadinessPacket(ready); + + assert.equal(readyPacket.status, "ready"); + assert.equal(readyPacket.ipRelease, "release-after-payout"); + + ready.challenge.settlementFunded = false; + const unfundedPacket = buildPayoutReadinessPacket(ready); + assert.equal(unfundedPacket.status, "blocked"); + assert(unfundedPacket.remediationActions.some((item) => item.code === "settlement_not_funded")); +} + +function testStableDigest() { + assert.equal(normalizeCountry(" us "), "US"); + assert.equal(stableJson({ b: 2, a: 1 }), stableJson({ a: 1, b: 2 })); + assert.equal(auditDigest({ b: 2, a: 1 }), auditDigest({ a: 1, b: 2 })); +} + +testContributorReadiness(); +testAwardSplitValidation(); +testPacketBlocksUntilPayoutEvidenceIsReady(); +testReadyPacketReleasesOnlyWhenFunded(); +testStableDigest(); + +console.log("bounty-payout-eligibility-gate tests passed");