Repository navigation
ENG-640: pay allowlisted referrals while the referral program is paused - #518
Merged
islandbitcoin merged 6 commits intoOct 11, 2026
Merged
Conversation
GET /api/resource/Referral Payout Allowlist with fields account_id and enabled, filtered to enabled rows, no page cap. A non-array response or a request error returns ReferralPayoutAllowlistQueryError. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WxkKbrg2Xohf3mQj7BLrs6
…G-640) 60s cache of allowlisted account ids (successes and failures). Unreadable, non-array, disabled or malformed rows mean nobody is allowlisted. Rows are keyed by the 24-hex flash account id, so no Mongo lookups. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WxkKbrg2Xohf3mQj7BLrs6
…ENG-640) With referralReward.enabled=false, an empty allowlist still returns before any Mongo query. Otherwise a referral proceeds when the invitee or the inviter is allowlisted, and both parties are paid per the tier. The ERPNext Referral Settings switch still gates every payout. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WxkKbrg2Xohf3mQj7BLrs6
…(ENG-640) --account/--username narrow to one invitee and --inviter to one inviter, inside the Mongo query. The result reports whether the filtered party is allowlisted, and an empty filtered backlog warns. Usage text: fund the rewards wallet first, dry-run with --username, then execute. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WxkKbrg2Xohf3mQj7BLrs6
Review fix: the operator usage text now states the wallet must be funded before the Referral Payout Allowlist row is added, and that an underfunded payout is recorded as "partial" or "failed" (award-referral-reward.ts writes "failed" when neither party was paid). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G4SaLJF5SWq6sjBEaWJFow
`make audit` (yarn audit --level critical) fails on main since the two Handlebars advisories published with 4.7.10 (JS injection via AST type confusion; via own-property-check bypass). handlebars is a transitive dep of grpc_tools_node_protoc_ts and spectaql only; the existing `**/handlebars` resolution pinned 4.7.9. Bump it to 4.7.10. No runtime code path uses handlebars. Verified: `yarn audit --level critical` exit 14 (no critical) after the bump, 30 before. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G4SaLJF5SWq6sjBEaWJFow (cherry picked from commit df358ae)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Referral rewards are paused in prod (helm
referralReward.enabled: false) since the 2026-08-31 farming wave. There is no way to pay a trusted account (an ambassador, a known referrer) without turning the whole program back on.Change
ErpNext.getReferralPayoutAllowlist():GET /api/resource/Referral%20Payout%20Allowlistwithfields=["account_id","enabled"],filters=[["enabled","=",1]],limit_page_length: 0. Errors returnReferralPayoutAllowlistQueryError.src/app/invite/referral-payout-allowlist.ts: a 60s cache (successes and failures) of allowlisted account ids. It is fail-closed: an unreadable, non-array, disabled or malformed row means nobody is allowlisted. Rows are keyed by the 24-hex flash account id (frappe resolves the operator's input at save time), so the reader never touches Mongo.awardReferralRewardOnKycApproval: whileconfig.enabledis false:config.enabled=truebehaves exactly as before (the allowlist is not consulted).--account <id>/--username <name>(mutually exclusive) narrow it to one invitee, and--inviter <id>narrows it to one inviter. Both filters run inside the Mongo query. When filtered, the result reportsallowlisted/inviterAllowlisted, and an empty filtered backlog warns. A malformed id or an unknown username exits 1.No GraphQL, schema, config or mobile change.
Globals.referralRewardEnabledstill readsconfig.enabled, so the invite card stays hidden.Operator runbook (order matters)
partialorfailedand needs manual reconciliation.node lib/scripts/retry-deferred-referral-rewards.js --configPath ... --username <name> --dry-run. Check thatbacklogCount> 0 andallowlisted=true.--dry-run.How it was tested
yarn test:unit: 279 suites, 3578 passed, 3 skipped (pre-existing), 0 failed.referral-payout-allowlist.spec.ts(30 tests): validation, case normalisation, fail-closed on ERP error, non-array, throw and missing method, TTL memoisation, cached failures, removal after 60s.award-referral-reward.spec.ts: full gate matrix. It covers config on/off × ERP switch on/off × invitee listed / inviter listed / neither × allowlist empty vs non-empty, plus already-rewarded, non-referred, missing inviterId, and tier counter cases. The existing zero-Mongo assertion is kept and strengthened for paused + empty.retry-deferred-rewards.spec.ts: account / inviter / combined query filters, allowlisted reporting, empty-backlog warn, scoped replay.retry-deferred-referral-rewards.spec.ts: flag parsing,--account/--usernameconflict, username resolution, unknown username, malformed ids.ErpNext.spec.ts: URL, params, rows, non-array, no data, request error recorded in span.yarn tsc-check,yarn tsc-check-noimplicitany,yarn eslint-check(on tracked files),prettier --checkwith the lockfile binary (3.6.2),typos --config typos.toml, andyarn check:sdl(no schema diff) all pass.Follow-ups
account_id+enabled, read permission for the flash service account) must be live on each env before this deploys.award-referral-reward.tsand drop--inviter.🤖 Generated with Claude Code
https://claude.ai/code/session_01WxkKbrg2Xohf3mQj7BLrs6