Consequence
ProtocolThe Reserve

Session
Protocol.

How royalties are calculated, how the ledger branches between compose-time equity and sale-time settlement, and how every USDC leg stays auditable from Kafka through Solana.

Governance

00 · Charter

One protocol. Two clocks.

Consequence runs two intertwined timelines: the compose clock (signals → algorithmic equity → Solana PDA updates) and the commerce clock (marketplace purchase → split calculation → Circle payouts). Session Protocol is the contract between them — what gets recorded, who may read it, and how capital always defers to the latest verified ownership vector.

Compose

Signals & equity

MIDI, arrangement, AI acceptance, session time — normalized to 10,000 basis points.

Ledger

Branch authority

Mongo projections for speed; Solana PDAs for settlement truth; ClickHouse for analytics.

Settle

USDC legs

Platform fee, net pool, parallel creator transfers — confirmed <2s on Solana.

01 · Royalty calculation

From gross sale to creator legs

Every marketplace purchase emits a single gross figure in USDC. The settlement service applies a platform fee, reads ownership from the composition PDA on Solana, and allocates the net pool proportionally. No renegotiation at checkout — the chain snapshot wins.

net = gross × (1 − platform_fee)
leg_i = net × (ownership_bp_i / 10_000)

Live split model

$15.00 USDC gross

Platform

−$1.50

10% fee

Net pool

$13.50

Creator A · 60%

$8.10

Creator B · 30%

$4.05

Creator C · 10%

$1.35

Splits read from on-chain ownership at settlement time — not cached listing metadata. Platform fee accrues to treasury twin before net legs execute on Circle → Solana.

02 · Ledger branch

Ledger Branch — where truth lives

The ledger is not one database — it is a branch. Hot twins in Mongo answer product surfaces in milliseconds. Solana holds the ownership vector settlement must cite. ClickHouse mirrors events for Monte Carlo and audit. Reconciliation jobs detect drift; settlement never proceeds on stale equity.

  • Composition PDA — stores normalized basis points per creator; updated after each equity recomputation.
  • Equity snapshots — Mongo timeline of every revision with signal evidence and rule overrides.
  • Settlement records — gross, fee, legs, Circle + Solana refs — immutable once confirmed.
  • Event bus — Kafka partitions by composition; purchase events enriched and on bus in <100ms.

03 · Algorithmic equity

The equity formula

Contribution signals are normalized per channel, weighted, and summed. Log scaling prevents spam; pre-agreed floors and caps apply when creators negotiate fixed splits. Output is always 10,000 basis points — the only vector settlement trusts.

S_total(i) = Σ_c w_c · norm_c(i)
equity_bp(i) = round(10_000 · S_total(i) / Σ_j S_total(j))
Channels c: participation (0.25) · midi (0.30) · arrangement (0.20) · ai (0.15) · structural (0.10)
computeAlgorithmicEquity
export interface CreatorSignals {  creatorId: string;  participationSeconds: number;  midiNotesCreated: number;  arrangementImprovements: number;  aiSuggestionsGenerated: number;  aiSuggestionsAccepted: number;  structuralChanges: number;} export const SIGNAL_WEIGHTS = {  participation: 0.25,  midi: 0.3,  arrangement: 0.2,  ai: 0.15,  structural: 0.1,} as const; function log1pScaled(n: number): number {  return Math.log1p(Math.max(0, n));} function normalizedParticipation(signals: CreatorSignals[], i: number): number {  const total = signals.reduce((s, c) => s + c.participationSeconds, 0);  if (total === 0) return signals.length ? 1 / signals.length : 0;  return signals[i].participationSeconds / total;} function normalizedMidi(signals: CreatorSignals[], i: number): number {  const raw = signals.map((c) => log1pScaled(c.midiNotesCreated));  const sum = raw.reduce((a, b) => a + b, 0);  if (sum === 0) return signals.length ? 1 / signals.length : 0;  return raw[i] / sum;} function blendAiCredit(signals: CreatorSignals[], i: number): number {  const gen = log1pScaled(signals[i].aiSuggestionsGenerated);  const acc = log1pScaled(signals[i].aiSuggestionsAccepted);  const score = 0.3 * gen + 0.7 * acc;  const scores = signals.map(    (c) => 0.3 * log1pScaled(c.aiSuggestionsGenerated) + 0.7 * log1pScaled(c.aiSuggestionsAccepted)  );  const sum = scores.reduce((a, b) => a + b, 0);  return sum === 0 ? (signals.length ? 1 / signals.length : 0) : scores[i] / sum;} function normArrangement(signals: CreatorSignals[], i: number): number {  const raw = signals.map((c) => log1pScaled(c.arrangementImprovements));  const sum = raw.reduce((a, b) => a + b, 0);  if (sum === 0) return signals.length ? 1 / signals.length : 0;  return raw[i] / sum;} function normStructural(signals: CreatorSignals[], i: number): number {  const raw = signals.map((c) => log1pScaled(c.structuralChanges));  const sum = raw.reduce((a, b) => a + b, 0);  if (sum === 0) return signals.length ? 1 / signals.length : 0;  return raw[i] / sum;} export function computeAlgorithmicEquity(signals: CreatorSignals[]): Map<string, number> {  if (signals.length === 0) return new Map();   const weighted = signals.map((_, i) => {    const p = normalizedParticipation(signals, i) * SIGNAL_WEIGHTS.participation;    const m = normalizedMidi(signals, i) * SIGNAL_WEIGHTS.midi;    const ar = normArrangement(signals, i) * SIGNAL_WEIGHTS.arrangement;    const ai = blendAiCredit(signals, i) * SIGNAL_WEIGHTS.ai;    const st = normStructural(signals, i) * SIGNAL_WEIGHTS.structural;    return p + m + ar + ai + st;  });   const total = weighted.reduce((a, b) => a + b, 0);  const out = new Map<string, number>();  if (total === 0) {    const even = Math.floor(10_000 / signals.length);    signals.forEach((c, idx) =>      out.set(c.creatorId, even + (idx === 0 ? 10_000 - even * signals.length : 0))    );    return out;  }   let allocated = 0;  signals.forEach((c, i) => {    const bp = Math.round((weighted[i]! / total) * 10_000);    allocated += bp;    out.set(c.creatorId, bp);  });  const drift = 10_000 - allocated;  if (drift !== 0 && signals[0]) {    const id = signals[0].creatorId;    out.set(id, (out.get(id) ?? 0) + drift);  }  return out;}

04 · Settlement rail

Circle → Solana execution

After splits are computed, Circle Payouts stages parallel USDC legs. The program verifies signatures against the PDA, writes settlement snapshots, and twins refresh lifetime revenue and available balances — auditable end-to-end.

executeSettlementWithEquity
import type { Connection, PublicKey } from "@solana/web3.js"; export interface SettlementQuote {  saleGrossUsdc: bigint;  platformFeeBps: number;} /** * Settlement always hydrates authoritative ownership from the Solana PDA — * never from a Mongo cache — before computing per-creator payouts. */export async function executeSettlementWithEquity(params: {  rpc: Connection;  compositionPda: PublicKey;  quote: SettlementQuote;  /** Platform treasury receives fee leg */  platformTreasury: PublicKey;  creatorWallets: Map<string, PublicKey>;}): Promise<{  netToCreator: Map<string, bigint>;  platformFee: bigint;  equitySnapshotSig: string;}> {  const acct = await params.rpc.getAccountInfo(params.compositionPda, "confirmed");  if (!acct?.data) throw new Error("missing composition account");   const { ownership, lastSnapshotSig } = decodeCompositionState(acct.data);  const totalBps = ownership.reduce((s, o) => s + o.basisPoints, 0);  if (totalBps !== 10_000) throw new Error("invalid equity sum");   const gross = params.quote.saleGrossUsdc;  const fee =    (gross * BigInt(params.quote.platformFeeBps)) /    10_000n;  const net = gross - fee;   const netToCreator = new Map<string, bigint>();  for (const row of ownership) {    const wallet = params.creatorWallets.get(row.creatorId);    if (!wallet) continue;    const share = (net * BigInt(row.basisPoints)) / 10_000n;    netToCreator.set(row.creatorId, share);    await transferUsdc(params.rpc, params.platformTreasury, wallet, share);  }   await recordSettlementOnChain({    composition: params.compositionPda,    gross,    fee,    netSplits: netToCreator,    equitySnapshotSig: lastSnapshotSig,  });   return { netToCreator, platformFee: fee, equitySnapshotSig: lastSnapshotSig };} function decodeCompositionState(_data: Buffer): {  ownership: { creatorId: string; basisPoints: number }[];  lastSnapshotSig: string;} {  throw new Error("decode Borsh layout for your program version");} async function transferUsdc(  _rpc: Connection,  _from: PublicKey,  _to: PublicKey,  _amount: bigint): Promise<void> {  // SPL transfer_checked} async function recordSettlementOnChain(_args: unknown): Promise<void> {  // record_settlement instruction}

05 · Full trace

Velvet Clip · $15 USDC

From first bar to final leg — the same narrative the royalty carousel steps through, at architectural scale.