The board says the one condition out loud

The card read "when someone new opens PolHunter" and listed everyone a hunter
had brought as hunting or earning, including members who joined InstantAdPay
before the mission existed and can never pay a bounty. So the board promised an
earning the payout code would refuse.

It now says what actually qualifies: someone who has never had an InstantAdPay
account. People who were already members are listed as exactly that, the match
window is not claimed for them, and the counts show how many of the brought are
genuinely new.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-23 11:41:54 -05:00
parent d04474fd7b
commit 2503b1e1a2
4 changed files with 254 additions and 240 deletions
+11 -2
View File
@@ -162,17 +162,25 @@ function state(member) {
const me = hunter(id) || { memberId: id };
const rows = refRows().filter(p => Number(p.memberId) === id);
const today = ctDay();
// the same floor onFind pays by, so the card can never promise an earning it will not make
const floor = Date.parse(String(c.refNewAfter || ''));
const gateOk = Number.isFinite(floor) && floor > 0;
const mine = broughtBy(id).map(x => {
const theirFinds = store.read('payouts', []).filter(p => Number(p.memberId) === Number(x.memberId) && !p.ref && !p.prize && p.status !== 'failed');
const paid = bountyPaidFor(x.memberId);
const isNew = !!(gateOk && x.joinedAt && Number(x.joinedAt) >= floor);
return {
name: x.username || ('#' + x.memberId),
// when they actually joined InstantAdPay, not when this directory first noticed them:
// the backfill stamped firstSeen at seeding time and made everyone look brought-in today
joinedAt: x.joinedAt || x.firstSeen || null,
finds: theirFinds.length,
state: paid ? 'earning' : theirFinds.length ? 'hunting' : 'signed up, no find yet',
stillNew: x.joinedAt ? (Date.now() - Number(x.joinedAt)) / 86400000 <= Number(c.refMatchDays) : false,
// an account that predates the mission was already a member: say so plainly rather than
// show them as 'hunting' next to a bounty that will never arrive
isNew,
state: !isNew ? 'already a member before the mission, earns nothing'
: paid ? 'earning' : theirFinds.length ? 'hunting' : 'signed up, no find yet',
stillNew: isNew && (Date.now() - Number(x.joinedAt)) / 86400000 <= Number(c.refMatchDays),
};
});
return {
@@ -182,6 +190,7 @@ function state(member) {
matchPct: Number(c.refMatchPct),
matchDays: Number(c.refMatchDays),
brought: mine.length,
broughtNew: mine.filter(x => x.isNew).length, // the only ones that can ever pay
broughtToday: mine.filter(x => x.joinedAt && ctDay(x.joinedAt) === today).length,
earnedPol: round4(rows.reduce((n, p) => n + p.pol, 0)),
earnedTodayPol: round4(rows.filter(p => p.day === today).reduce((n, p) => n + p.pol, 0)),
+2 -2
View File
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Your board · PolHunter</title>
<meta name="robots" content="noindex">
<link rel="stylesheet" href="/style.css?v=16">
<link rel="stylesheet" href="/style.css?v=17">
</head>
<body>
<div class="wrap">
@@ -47,6 +47,6 @@
<footer class="foot">Rewards are for completed missions, not income. The daily pool is limited; when it is spent, claims close until midnight Central. Cryptocurrency involves risk of loss.</footer>
</div>
<div class="modal" id="shareModal" hidden><div class="modal-card"><button class="modal-x" id="shareClose" type="button" aria-label="Close">×</button><div id="shareBody"></div></div></div>
<script src="/app.js?v=16"></script>
<script src="/app.js?v=17"></script>
</body>
</html>
+3 -2
View File
@@ -57,13 +57,14 @@
return '<div class="card ref-card">'
+ '<span class="tag gold">Best paid</span>'
+ '<h3>🤝 Bring a hunter</h3>'
+ '<p>Send your link. When someone new opens PolHunter and finds their first code, you get <b>' + rf.bountyPol + ' POL</b>. '
+ '<p>Send your link. When someone who has <b>never had an InstantAdPay account</b> joins on it, opens PolHunter and finds their first code, you get <b>' + rf.bountyPol + ' POL</b>. '
+ 'After that you earn <b>' + rf.matchPct + '%</b> on top of everything they find for their first ' + rf.matchDays + ' days. '
+ 'It comes out of our pool, never theirs.</p>'
+ '<p class="ref-note">This pays for new people only. Someone who was already a member before this mission started earns nothing, however much they hunt.</p>'
+ (rf.firstBonusPol ? '<p class="ref-bonus">\u{1F947} <b>' + rf.firstBonusPol + ' POL bonus, still unclaimed.</b> It goes to the first hunter who brings someone all the way through. Nobody has yet.</p>' : '')
+ '<div class="codebox"><input id="refLink" readonly value="' + esc(link) + '"><button class="btn pol" id="refCopy">Copy</button></div>'
+ '<p style="margin-top:10px"><span class="range">' + today + ' brought today</span> '
+ '<span style="color:var(--dim);font-size:12px">· ' + total + ' all time · ' + rf.earnedPol + ' POL earned</span></p>'
+ '<span style="color:var(--dim);font-size:12px">· ' + total + ' all time, ' + (rf.broughtNew || 0) + ' of them new · ' + rf.earnedPol + ' POL earned</span></p>'
+ (people ? '<div class="ref-list">' + people + '</div>' : '<p style="color:var(--dim);font-size:12px;margin-top:10px">Nobody yet. One message is all it takes.</p>')
+ '<div class="ref-watch"><button class="btn ghost sm" type="button" id="refPlay">▶ Watch: how it works (46s)</button></div>'
+ '</div>';
+4
View File
@@ -137,3 +137,7 @@ textarea{width:100%;padding:12px 14px;border-radius:12px;border:1px solid var(--
.ref-watch{margin-top:14px}
.ref-video{width:100%;max-width:560px;border-radius:14px;display:block;background:#000}
.ref-bonus{margin-top:10px;padding:9px 12px;border:1px solid rgba(243,190,67,.38);border-radius:12px;background:rgba(243,190,67,.07);font-size:13.5px;color:var(--ink)}
/* the one condition that decides whether a referral ever pays, said plainly on the card itself
rather than discovered when the bounty does not arrive (Marty, 2026-09-23) */
.ref-note{margin-top:8px;font-size:12.5px;line-height:1.45;color:var(--dim)}