How Ownership Stake Works

8 min read

This document explains exactly how ownership stake works on Our One. Every claim includes the actual source code. Anyone can verify these claims against the public repository.

Stake is defined in src/modules/stake/stake.service.ts. The entire file is 108 lines — we show the important parts here.


The Problem Stake Solves

A community-owned platform has to answer one question that a privately-owned platform never does: when the community needs to make a decision, whose voice should carry the most weight?

One member, one vote sounds fair. But it creates two problems. The first is Sybil attack — one person with a hundred accounts has a hundred votes. The second is deeper: a three-year member has more invested in this platform's future than someone who joined yesterday. Treating them identically is not equality. It erases the reality of commitment.

At the same time, a system that rewards activity creates incentives to perform activity. Points, badges, leaderboards — these turn a community into a game. LinkedIn endorsements are gamed. Stack Overflow reputation is gamed. Any visible score attached to behavior will be gamed.

Stake resolves this with radical simplicity.


One Input

Your stake is how many years you have been a paying member. Nothing else.

Here is the complete function that computes it:

// stake.service.ts, lines 35–56
export async function getMembershipYears(userId: string): Promise<number> {
  const db = getReadDb();
  const profile = await db.query.userProfiles.findFirst({
    where: eq(userProfiles.userId, userId),
    columns: { joinedAt: true, paidThroughDate: true, pausedDays: true },
  });
  if (!profile?.joinedAt) return 0;
 
  // No paidThroughDate means never paid — 0 stake
  if (!profile.paidThroughDate) return 0;
 
  // Active days = min(today, paidThroughDate) - joinedAt - pausedDays
  const endDate = Math.min(Date.now(), profile.paidThroughDate.getTime());
  const rawDays = Math.floor(
    (endDate - profile.joinedAt.getTime()) / (1000 * 60 * 60 * 24),
  );
  const pausedDays = profile.pausedDays ?? 0;
  const activeDays = Math.max(0, rawDays - pausedDays);
 
  // 1 stake immediately on payment + 1 per completed year
  return Math.floor(activeDays / 365) + 1;
}

Even if you cannot read TypeScript, you can see what is NOT in this function: no postCount, no voteCount, no profileCompleteness, no endorsementScore. The only inputs are three fields from your profile: joinedAt, paidThroughDate, and pausedDays.


Total Stake Equals Membership Years

There is no bonus. No multiplier. No extra weight for any activity. The computeStake function makes this explicit:

// stake.service.ts, lines 60–66
export async function computeStake(userId: string): Promise<{
  membershipYears: number;
  totalStake: number;
}> {
  const membershipYears = await getMembershipYears(userId);
  return { membershipYears, totalStake: membershipYears };
}

totalStake equals membershipYears. That is the entire function. No bonus added. No adjustment. The value returned is used directly as your governance voting weight.


The Formula

Three fields. One computation. No hidden state.

activeDays = min(today, paidThroughDate) − joinedAt − pausedDays
membershipYears = floor(activeDays / 365) + 1
totalStake = membershipYears

A new member who just paid gets 1 stake immediately. After one full year, they have 2. After three years, 4. A member who posts ten articles a day and a member who reads quietly accumulate the same stake. This is intentional.


Subscription Lifecycle

What happens when you stop paying, and when you come back:

Active member. paidThroughDate is in the future. Stake grows normally.

Lapsed member. paidThroughDate has passed. Stake is frozen — the calculation caps at paidThroughDate, not today. You can see this in the code:

// stake.service.ts, line 47
const endDate = Math.min(Date.now(), profile.paidThroughDate.getTime());

Math.min — if your subscription expired three months ago, the calculation stops at the date it expired. Your stake does not grow while you're away. But it is not erased either.

Returned member. When you resume payment, the gap between your old paidThroughDate and your return date is added to pausedDays. Your stake resumes but the gap is subtracted:

// stake.service.ts, lines 51–52
const pausedDays = profile.pausedDays ?? 0;
const activeDays = Math.max(0, rawDays - pausedDays);

Two years active, then a six-month gap, then one year active = three years of active membership = 4 stake. The gap is subtracted, not ignored.


What Stake Is Used For

Stake has exactly one function: governance voting weight.

// governance.service.ts, lines 147–149
const { totalStake } = await computeStake(userId);
const stakeWeight = totalStake;

When you vote on a proposal, your vote is weighted by your stake. A founding member who has been here for years has more say than someone who joined last week. Not as a prize. As a reflection of commitment.

Stake does NOT influence:

  • What content you see in your Brief
  • How your posts are ranked or surfaced
  • Who discovers you in search
  • How many messages you can send
  • Any feature of the platform other than governance

What Does NOT Earn Stake

This is the most important section. These are verifiable facts about the event handler that processes platform activity:

// handlers.ts — event processing
// post_created:      NO stake awarded
// reply_created:     NO stake awarded
// signal_added:      NO stake awarded
// endorsement_given: NO stake awarded
// message_sent:      NO stake awarded
// proposal_created:  NO stake awarded — stake is membership years only
// governance_vote:   NO stake awarded — stake is membership years only

Publishing does not earn stake. Receiving reactions does not earn stake. Endorsing someone does not earn stake. Being endorsed does not earn stake. Messaging does not earn stake. Voting on proposals does not earn stake. Completing your profile does not earn stake.

Post because it is worth posting, not because a system is watching. Vote because the outcome matters, not because a number goes up.


Stake Is Not Displayed

Your stake balance is not a number next to your name. It is not shown to other members. It is not a leaderboard position. It is not a status signal.

The only thing other members see is your member-since date. "Member since 2026" is information. "4 stake points" is a leaderboard entry. We show the first. Never the second.


Why Platform Stake Is Simple

Our One AI will have its own constitution and its own stake system — because the contribution that matters there is different. Contributing professional expertise, providing computing resources, funding model development — these are materially different from being a platform member. They require their own governance layer.

Platform stake is infrastructure. One cent a day. One stake per year. If a proposed feature requires a second input, it is probably gamification in disguise.


How to Verify

Every claim in this document can be verified:

  1. Read the source code. The file is src/modules/stake/stake.service.ts in the public repository. It is 108 lines. You can read the entire file in two minutes.

  2. Run the tests. src/__tests__/modules/stake.test.ts contains 23 tests covering the formula, edge cases, subscription lifecycle, and explicit verification that nothing else earns stake.

  3. Check the event handlers. src/modules/events/handlers.ts processes all platform events. Search for "recordStakeEvent" — you will find zero results.

  4. Run the negative checks. npm run transparency:negative-checks greps the entire codebase for engagement scoring patterns.

This document will be updated whenever the stake logic changes.