Skip to content

Build1 publisher2 min readPublished

Two ranking formulas let a paid bid outlive the votes meant to unseat it

Kingpin showed the same listings on two surfaces with two scoring functions, so votes moved a listing only inside the swipe feed. Merging them raised a fair question about whether bid decay duplicated downvotes.

The Engineer · Build desk

Illustration accompanying Two ranking formulas let a paid bid outlive the votes meant to unseat it

What happened

  • Kingpin ranked the same listings with two different formulas, one per surface, so the crowd could dethrone a paid listing inside the swipeable /feed while money held a permanent position on /board.
  • The board is the pre-pivot leaderboard built in Phases 0 to 8, the feed arrived with the pivot in Phases 9 to 15, and the older surface was never retired.
  • The fix routes both surfaces through one ranking function. That puts votes in charge of the board that people actually land on and share.
  • Automatic bid decay survived the review, fully implemented behind FLAG_DECAY and defaulting off, to be switched on once vote volume makes the crowd the dominant force.
  • Founders were barred from all voting, including votes for their own listings, because a narrower ban on voting for rivals invites the question about self-votes.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • decision The escalating refuel price only means something if positions erode, so a fairness cleanup on the ranking side was also a decision about how the platform earns.
  • constraint With the gate false, nothing erodes on either surface, so the refuel price has nothing to charge for until someone deliberately flips the flag.
  • exposure Founders hold a direct financial interest in every rival's rank, so an open vote on a board where votes move paid position would have made the cheapest listing a way to attack the leader.
  • cost An automatic traffic threshold would have charged founders for the switch, wiping value off every paid position the instant it crossed, with no notice to anyone who had bid.

Downvotes and decay have the same effect and different triggers. Both push a listing down the ladder, and that shared effect is what makes two mechanisms look like one [22]. One needs a person who dislikes the thing; the other needs a date.

A downvote answers "is this bad?", and it requires a human to actively dislike the listing [7]. The post frames decay's question as "why are you still #1 in September?" and says it requires nobody [8]. Between those two triggers sits indifference. A merely dull listing collects roughly zero net votes forever, and nobody downvotes a product for being old [9]. Delete decay and the best available strategy is to pay once, annoy no one, and keep the top spot [10].

That was already the strategy the board allowed, which is why the write-up calls the product's central claim silently false on its most-visited surface [3]. Nobody designed that state; it is an old decision nobody re-opened [5]. The feed came with the pivot and the old surface was never retired [4], so the two formulas coexisted across the seven phases numbered 9 through 15 [23].

There was a second cost to deleting decay, and it sat outside the code under discussion. Removing it would have retired the escalating refuel price along with it, leaving working, tested code permanently unreachable [12].

What shipped instead is one gate in `lib/scoring.mjs`: `export const decayEnabled = (flags = {}) => flags?.decay === true;`. Both `effectiveCents` and `bidBaseCents` read it, so no surface can disagree with another about what a listing is worth [16].

Someone flips that flag by hand. I would copy that. A traffic threshold that tripped on its own would erode every paid position the instant it crossed, with no warning to any founder; a flag a person flips means the moment is chosen, it can be announced, and it can be reversed [17].

Whether decay belongs on is a question about the board's population. With about two listings and effectively no voters, decay was the only force acting on the board, it moved one direction, and the only way to recover position was to pay again [13]. The post says that outcome is "the platform billing people for standing still" and that it "punishes founders for the platform's lack of traffic, which isn't their fault" [14].

The vote handler treats one rejection differently from all the others. Every other rejection there fails quietly, because a clear error tells a bot exactly which control it tripped. The founder-vote rejection is loud, since it is a published policy, not a detection [20].

What to watch

  • Whether FLAG_DECAY gets flipped on, and whether founders are told before it happens.
  • Whether anything other than effectiveCents and bidBaseCents starts reading bid values outside the single gate in lib/scoring.mjs.
  • Whether the escalating refuel price collects anything at all while the decay gate stays false.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories