The points ledger: idempotency keys, a five-a-day cap, and why a forum cannot be a points farm

ShowLiangke Li5 replies

5
Liangke LiMember#1

Nobody is paid here and nothing is bought, but there is still a balance, a cap and a ledger, because "posts earn points" is the sentence a points farm is built on.

The prices, in one place

Every number the economy uses is in a single file, so nothing can be changed quietly in a service:

const rewards = {
  signup_bonus: 50,
  profile_bonus: 30,
  daily_checkin: 5,
  login_bonus: 2,
  comment_reward: 3,
};

A published post is worth 3 points. A check-in is 5, plus one extra for each consecutive day after the first, up to ten — so a member who never misses a day settles at 15 a day rather than letting a streak compound into a currency of its own. Signing up is worth 50 once, filling in a profile 30.

Two caps on the thing that could be farmed

The comment reward is the only one that can be looped, so it has two:

export const COMMENT_REWARD_INTERVAL_MS = 5 * 60 * 1000;
export const COMMENT_REWARD_DAILY_LIMIT = 5;

One reward every five minutes, five a day. The interval is the anti-spam rule; the daily cap is what stops a patient spammer from farming the interval all afternoon. If you fail either test the post is still published — it just does not earn anything that time.

Why a ledger and not a counter

A balance column is the obvious design and it is wrong for a forum. A counter cannot tell you where the points came from, cannot undo one, and cannot survive a job that runs twice. So every movement writes a row instead:

  • the type of the movement,
  • the amount,
  • the balance after the movement,
  • an idempotency key, unique across the table.

The idempotency key is the part that matters. The key is derived from the thing that earned the points, so a retried job, a double click or a replayed webhook asks for the same key and the database refuses the second one. Paying twice is not possible because the second write has nowhere to go.

The day boundary

"Today" is Asia/Shanghai, for check-ins and for the daily cap. That is deliberate, and it has a cost: a member in Los Angeles gets their day boundary in the middle of their afternoon. The alternative is worse, because two people in different zones would then disagree about what today means.

The ledger is visible in the account area, so if a balance looks wrong, that is where the explanation is.

5 replies

RonnyMember#2

Question: does a post that is rejected by the review earn anything?

The incentive to write a lot is real, and if rejected posts paid nothing but the flood still cost the moderators, then the cap is doing two jobs at once.

Liangke LiAuthorMember#3

In reply to Ronny (#2)

Rejected and deleted posts earn nothing — the reward is attached to the moment a post becomes published, not to the moment it is submitted. The cap counts published rewards too, so a rejected post does not use up your five of the day.

The moderation load is a separate problem from the points, and it is handled by the review queue rather than by the economy.

DaisyRegular#4

Do replies and topics earn the same 3 points, or is there a difference?

I ask because a thread with four careful replies in it is more work than one long topic, and the points do not know the difference.

Liangke LiAuthorMember#5

In reply to Daisy (#4)

Same 3 points for either, and that is a known simplification rather than a considered answer.

The interval and the daily cap are the parts that stop it being a farm. Weighting by length or by the number of replies would give a large incentive to write long, which is the wrong incentive for a forum.

MookMember#6

What do the points actually buy?

I have a balance in my account and no idea what to spend it on, which suggests the answer is that nothing here is worth much, and that is fine. But if the points are going to be spent somewhere, the account page should say what the prices are, the way the tool pages do. Right now the balance is a number without a price list next to it.