A Smart Poll opens, takes stakes, closes, and the option holding the most credits becomes its recorded answer. There is no oracle and no way out. Two rules stand in for the oracle: a stake ceiling that falls with time, and one bet per person. This is the math of that layer as it runs today, and the three changes drafted for it — written down so that serious people can tell us where it is wrong.
A Smart Poll is not a prediction market. Nothing outside the poll decides it. That is the design, and the rest of this page hangs on that sentence.
The money is meant to buy the verdict. If 50,000 Credits ✦ sit on yes and 40,000 on no, yes is the recorded answer, and everyone who backed yes splits the pot the no side put in. That is the design, not a defect in it. There is no oracle at the end of a Smart Poll, so the pot is the only thing that can decide it.
What keeps that honest is not an outside judge. It is two rules that shape when and how much conviction can land: a stake ceiling that falls as the poll ages, so early belief counts for more than late sniping, and a limit of one bet per person, so a verdict is a crowd rather than a wallet. And nothing comes out before the clock does — there is no withdraw, no sell, no cancel.
So a Smart Poll is a conviction-weighted consensus instrument. It does not claim to find truth; it claims to find what people with skin in the game believe. The servers rule — rank the options by credits, most credits first, head count only to break an exact tie — is the intended rule, not a bug.
Some of our earlier writing says the opposite, that money “can never buy the verdict”, and the current outertalk.com copy is among it. That wording is stale, and this page is part of replacing it. What a polls answer is never allowed to do is a separate matter, spelled out under the wall (R10).
One poll · from open to settled · nothing comes out before the clock does
Opens, takes stakes under a ceiling that falls with time, closes, pays out to whichever side carried more. No withdrawals. It is a consensus instrument and it settles against its own pool.
No bets, no settlement, no clock. Back a concept, hold, and — if the drafted exit is adopted — sell when you change your mind. The sell rule is drafted, not decided; the earlier rule was lock-only, no trading curve. Its rules live at the concept-token page. Money there may light a concept and nothing more.
Each rule says whether it is decided, still open, built, or drafted and waiting. Where the code and the rule disagree today, the rule says so, with the number.
A Smart Poll has options, a max_bet — the most one account may ever hold in it — and a duration_minutes. Stakes go in while it is open. When it closes, the option holding the most credits is the recorded answer. Head count is used only to break an exact tie in credits. There is no oracle: nothing outside the poll is consulted, and nothing outside it can overrule the pot.
What that answer is: one row in pool_settlements, read by the payout path and shown on the category page as the settled outcome. What it is not: truth, a name on the map, a position, or brightness. See R10.
Once a stake is in, it stays until the poll closes. There is no withdraw, no sell, no cancel. Someone who filled the ceiling early is never refunded and never forced out; they simply cannot add. That is the intent: early conviction counts, late sniping does not. The only paths that return a stake are the refund paths of R8 and R9, and those return everyone's, together.
place_bet never reads max_bet itself. It asks one function, stake_ceiling(post_id), how much one account may hold in this poll right now, and refuses the stake if the account's existing holding plus the new amount would exceed it. The holding is counted across every option of the poll, so tapping Bet ten times cannot beat the cap. The balance row is locked before the check, which closed a race where one account could pass the ceiling by staking from two sessions at once (fix 20260910000100).
stake_ceiling is least(decay, concentration): the time curve of R4 and the concentration cap of R6, whichever is smaller. A vote-only post carries max_bet = 0, and the same function returns 0 for it, so a vote-only poll accepts no stake by the same rule and not by a separate one.
Rule 3 · the chain that decides a ceiling · verified from production, 28 September 2026
place_bet locks the balance row, asks stake_ceiling, and compares. The curve is bet_ceiling, which today reads two global flags. The concentration branch exists and does nothing on polls, because the seed floor is NULL on all 73 of them. The dashed box is the draft that would make the curve a property of the poll rather than of a flag; it is on disk and not applied.Let f be the fraction of the poll's life that has elapsed: 0 at open, 1 at close, clamped. The ceiling is floor(max_bet × weight(f)). Two weights exist, and they are the same parabola — what differs is when it starts. Immediate: 1 − f², full at the open and falling away faster the longer the poll runs. Delayed: 1 while f ≤ 0.25, then 1 − ((f − 0.25) / 0.75)² — that same curve, held flat for a quarter and then compressed into the three quarters that remain.
Corrected 30 September 2026 (decision 95). Until today this page and the code described the immediate curve as (1 − f)². That is a parabola too, but the opposite one: its vertex sits at the close, so it surrenders most of the ceiling in the poll's first moments and then runs nearly flat along the bottom — moving from three quarters elapsed to the close would cost an account almost nothing. A ceiling exists to make waiting expensive, so the penalty has to grow as the close approaches, and that curve is 1 − f². The delayed curve always had the right shape, as does the quarterly grade allowance (grade_ceiling_weight), which is flat for half a quarter and then falls on the same parabola; the immediate curve was the only one in the codebase shaped the other way. The flag-driven quadratic branch still computes the old shape in live code — it is switched off in production and has never run a poll — and the drafted per-poll migration now carries the corrected one.
Today the curve is picked by two global flags. In production quadraticDecay = false and quadraticDecayDelayed = true, so every poll runs the delayed curve. The code's own defaults are the opposite (quadratic: true), which is one reason R5 exists — and why the superseded shape still matters even though it is off: if the app_settings row went missing, both server and client would fall back to it. quadraticDecay is tested first, so if both were on the immediate curve would win; the SQL twin repeats that order on purpose, because if the two disagreed the screen would show one number and the server would enforce another.
Pinned values at max_bet 10,000, halfway through: immediate 7,500, delayed 8,888, none 10,000. One fifth of the way through: delayed 10,000 (still flat), immediate 9,600. Three quarters through, where the two sit furthest apart in credits: delayed 5,555, immediate 4,375.
The superseded curve carried a load-bearing quirk, and the correction retires it. The server wrote floor(max_bet * (1 − f) * (1 − f)) left to right and the client wrote the same, because folding it to max_bet * weight changed the last bit of a double on some fractions and floor() turned that into a whole credit — the screen offered 8,649 and the server refused it. Three comments say that happens on “42 of 101” sampled fractions; a re-run measured 9 of 101, and the test pins three (0.07, 0.14, 0.27). 1 − f² builds a weight and multiplies once, exactly like the delayed branch, so there is a single multiplication and no order to get wrong. The warning stays true of the live flag-driven function, which still holds the old form; the count in its comments is overstated (decision 63).
Rule 4 · one parabola, two starting points · computed from the formulas at max_bet 10,000
(f − ¼) / ¾ for f and the two are the same function. That is what makes the mode a choice about when decay begins rather than about what shape it has. Every point is floor(max_bet × weight), pinned by the draft migration's self-test at a fifth, a half and three quarters.Decided 28 September 2026: “i can see the immediate quadratic curve be useful as well as the delayed one, that needs to be an option in smart poll creation, but the default should be delayed.”
The draft (DRAFT_20260929000300, on disk, not applied) adds posts.decay_mode — immediate, delayed or none, default delayed — chosen when the poll is created and immutable once the first stake lands (a trigger refuses the change), so the rule cannot move under people who already staked. The 73 existing smart polls take the default, which is the curve they have run under since 10 September 2026, so nothing they do changes. A new pure function, bet_ceiling_for_mode(created_at, duration, max_bet, mode), computes the curve with no flag read; stake_ceiling keeps its identity and calls it, falling back to the flag-driven bet_ceiling only if the mode is somehow NULL, so the global flags become a fallback and stop being the rule. The migration's self-test pins 7,500 / 8,888 / 10,000 at f = 0.5, 9,600 / 10,000 at f = 0.2, 4,375 / 5,555 at f = 0.75, and that vote-only and closed polls still return 0. It also carries the corrected immediate curve and the renamed mode value, so applying it is what makes 1 − f² real; the client half — every screen that reads the flags, plus the two client copies of the superseded shape — is unbuilt (Q2).
Decay is about time (late sniping). Concentration is about distribution (one account owning a pool). concentration_ceiling(seed_floor, pool, share_cap) = max(seed_floor, floor(share_cap × pool)), where the pool is counted before the new stake — deliberately conservative, since a holder's true share afterwards is strictly smaller. stake_ceiling takes the smaller of this and the decay ceiling; a NULL seed floor means no cap at all.
On Smart Polls it does nothing today: stake_seed_floor is NULL on all 73. That was chosen on purpose when it shipped, because 14 of the 15 positions open on 10 September 2026 would have been locked out of their own polls by a retroactive cap. Why it exists at all, measured that day: the average pool was 215 credits against a ceiling of 10,000, the largest account held 64% of its own pool, and polls averaged 1.6 stakers — a flat ceiling had never bound anything, and lowering it would not have either. The cap binds today only on governance grades (share cap 0.10; seed floors 100 federal, 50 state, 25 local), which are a different instrument with their own page.
The rule, in his words: “we need to fix the 1 bet per user to enforce it, but there needs to be variable honestly, so users can maybe bet twice, once in the first half of the poll and once in the second half of the poll, but that needs to be able to change on a per poll basis.”
Today it is not enforced. The unique index on pool_bets is (post_id, user_id, option_idx) — one row per option — and place_bet tops a row up without limit (ON CONFLICT … amount + excluded.amount). So an account may sit on every option of one poll. Measured 28 September 2026: 21 user-poll pairs hold more than one bet, and all 21 are on both sides of the same poll. Under the payout rule of R1 a hedged account is in the winning and the losing pot at once.
The draft (DRAFT_20260929000200, on disk, not applied): posts.bet_windows, 1 to 4, default 1, set at publish and immutable once the first bet lands. 1 means one bet for the life of the poll; 2 means one per half. place_bet computes window_no = least(bet_windows, floor(f × bet_windows) + 1) and refuses a second bet in the same window with a message naming when the next window opens. A bet in a later window may be on a different option — that is the point: the second bet is how you change your mind, and the curve of R4 has already made it worth less. The unique key becomes (post_id, user_id, window_no), partial on rows dated after the migration, so the 21 historical hedges stay exactly as they are. Both sides in one window becomes impossible by construction. A poll with no duration has one window whatever bet_windows says. At 14 users this changes nothing visible except that hedging stops.
Rule 7 · bet_windows · one bet per person per window · draft 000200, not applied
A cron job (job 19, every five minutes, active) runs auto_settle_expired_polls: every smart poll past created_at + duration_minutes with no settlement row and no freeze, oldest first, 200 per run. It ranks the options by credits, then by bettors, and takes rank 1. An exact tie refunds everyone; otherwise it distributes. A frozen poll (under review for suspected cheating or system error) is never settled automatically — the whole point of freezing is that the money stops moving until a human decides. The kill switch is the flag autoSettleSmartPolls, which defaults to true when the key is missing. The manual path, settle_poll, has been used 0 times in 34 settlements; the fallback became the whole mechanism.
The fee. 3% of the stakes, in four parts (migration 20260605000000): 1.0% treasury, 1.0% notes, 0.5% locked, and 0.5% to the Investigator who authored the poll. When the author is Yon, revoked, or not an Investigator, that slice folds back into treasury, which then takes 1.5%. The total on bettors stays 3% in every case. On the refund path the fee is 0 and every bettor is credited the full stake.
Rule 8 · what the pot pays · fee split from migration 20260605000000
11 of the 19 distributions to date had every stake on one option. Nothing was decided, there was no losing pot to split, and a ~3% fee was booked against unanimity. The draft (DRAFT_20260929000100, on disk, not applied) adds one guard to auto_settle_expired_polls: if fewer than two options carry stake, refund instead of distribute. The refund path already credits each bettor the full stake and writes fee_amount = 0, so no new money code is needed. Applied to history it would have returned the fee on 11 of 19. The function's signature stays byte-identical, because the cron resolves it by name at first execution and an arity change would apply green and then throw where nobody is told.
The first version of this draft also added a three-bettor quorum. It was removed. By its own arithmetic it would have refunded 33 of 34 historical settlements, and with 10 lifetime bettors that is an off switch with a comment on it, not a floor. Neither comparable uses one: a market with one trade still resolves when the answer comes from outside, and tote pools subsidise thin markets rather than void them. The draft's own header says the cheaper, reversible move is the flag — autoSettleSmartPolls = false until a resolution source exists — and to reach for the migration only if auto-settle is staying on (Q5). One wart, cosmetic: the refund path marks the settlement is_tied = true with winning_option = 0, and an uncontested pool is unanimous, not tied (Q3). The money is right.
Two things a poll's money may never touch. First, brightness on the map is never money. A settled poll counts as activity, which glows and fades over about a day; how much was staked in it moves nothing. Second, a poll's outcome is shown with the people% and the money% side by side, never collapsed — a whale can move money%, but cannot erase the people% beside it (docs/mission-roadmap-milestones.md, under “The WALL”).
The second is decided and not collected. Measured for the plan on 28 September 2026: 73 smart-market posts carry 3 free votes from 2 distinct voters; the smart-poll card (PollCard.tsx, 1,171 lines) never reads poll_votes — its option shares are pool shares. What the app calls people% on a consensus poll is a distinct-bettor count, which is money in disguise. There is no personhood-capped vote channel. Until there is, a Smart Poll card shows money, and this page says so rather than pretend otherwise.
One bet per person is one bet per account, and every account is minted with 10,000 free credits. So every limit on this page is a speed bump, not a wall, until proof of personhood exists in design. Irrelevant on play money; decisive the day money is real.
See the ledger below. The curve, the ceiling, the cron and the fee split are live. The three drafts — uncontested refund, bet windows, per-poll decay mode — are on disk and not applied. The client half of R5 is unbuilt. One bet per person is not enforced.
Integer credits only. Every ceiling is floored. The SQL is the authority and the client is its twin; a test pins them to each other.
Worked example, live: “Should New York expand congestion pricing in Manhattan?” was created 9 July 2026 at 03:59 with a duration of 525,600 minutes (one year) and a max_bet of 10,000. On 28 September 2026 it was 0.2237 of the way through — inside the flat quarter — so bet_ceiling and stake_ceiling both returned 10,000, and the chart in the app drew its dashed line flat at 10,000 at “now”. Expected ticks: 7 November (33%) → 9,876; 9 March (67%) → 6,913; close → 0. Its pool: option 0 held 1,000 ✦ from 3 bettors, option 1 held 650 ✦ from 2 — the 1,650 ✦ on the card.
Measured against production on 26 and 28 September 2026, each row dated. Nothing on this page should be read as shipped unless it is in this table.
Every settlement to date · 34 of them · measured 28 September 2026
| Thing | State | Detail |
|---|---|---|
| Smart Polls | 73 · live | 114 posts in production, 73 of them Smart Polls (counted 26 September 2026). 3 of the 73 carry any resolution_criteria text. |
| Stakes ever placed | 81 · 10 bettors | 81 rows in pool_bets from 10 distinct bettors (26 September 2026). |
| Settlements | 34 · 0 by a human | 15 refunded on an exact credit tie; 19 distributed; 11 of the 19 uncontested; 8 contested; 7 of the 8 with fewer than 3 distinct bettors; in 5 of the 8 money broke an exact human tie; 10 verdicts decided by a single bettor; largest 1-vs-1 1,000 ✦ against 5 ✦; 1 contested pool ever had a crowd of three (28 September 2026). |
| Settle path | cron · live | Job 19, every five minutes, active. Flag autoSettleSmartPolls true, and true when the key is missing. The manual settle_poll has been used 0 times. |
| Decay curve | built · delayed | Production is unaffected by decision 95: it runs the delayed curve, whose shape did not change. quadraticDecay = false, quadraticDecayDelayed = true in production. Cumulative across options since 20260910000100. Client twin src/utils/betCeiling.ts; the in-app chart (DecayChartModal.tsx) verified identical to the server on shape, flag order, max_bet source, time bounds and copy — rounding aside, the dashed line is continuous where the server floors (28 September 2026). |
| A live poll | ceiling 10,000 | “Should New York expand congestion pricing in Manhattan?” — created 9 July 2026 03:59, 525,600 minutes, max_bet 10,000, elapsed 0.2237 → bet_ceiling 10,000, stake_ceiling 10,000. Pool 1,000 ✦ / 3 bettors against 650 ✦ / 2 = 1,650 ✦. Expected: 7 Nov (33%) → 9,876; 9 Mar (67%) → 6,913; close → 0. |
| Concentration cap | built · inert | stake_seed_floor NULL on 73 of 73 polls. Binds only on governance grades (share cap 0.10; seed floors 100 / 50 / 25). |
| One bet per person | not enforced | Unique per (post, user, option). 21 user-poll pairs hold more than one bet, all 21 on both sides of one poll (28 September 2026). |
| people% | never collected | 3 free votes from 2 voters across 73 smart-market posts. PollCard.tsx (1,171 lines) never reads poll_votes; its shares are pool shares. |
| Fees booked | 22 ✦ · 0 paid | The notes fund accrued 22 credits over 34 settlements and paid out 0. The Investigator fund paid out 0. Credits ever transferred to anyone for producing information: 0. No function credits a note author. |
| Draft 000100 | on disk · not applied | Uncontested → refund. Quorum dropped. Would have returned the fee on 11 of 19. Signature unchanged. |
| Draft 000200 | on disk · not applied | posts.bet_windows 1–4; pool_bets.window_no; partial unique (post_id, user_id, window_no); no accumulate; old per-option index kept as a plain lookup. |
| Draft 000300 | on disk · not applied | posts.decay_mode; bet_ceiling_for_mode; the corrected 1 − f² immediate curve and the renamed mode value; self-test pins 7,500 / 8,888 / 10,000, 9,600 / 10,000 and 4,375 / 5,555. Client half unbuilt (Q2). |
| On chain | nothing | Smart Polls run in Postgres. The 7 contracts on the Base Sepolia testnet include a poll factory and a poll pool; no mainnet deploy exists, and the wallet path is switched off in the app (0 of 36 users). |
Numbered so you can refer to one. Tell us which way, and why.
bet_windows. The draft defaults every poll to 1 — one bet for its whole life. His own example was 2, one per half. Which default for new polls, and does the picker live where max_bet is set today?post.decay_mode instead (swept 28 September 2026): usePool.ts 122–123, the number the Bet sheet offers; DecayChartModal.tsx 267–269, the curve the chart draws; BetModal.tsx 284, the “(decay)” label; bubbles.ts 93, the explainer; AdminFeatureFlags.tsx 112–113 and 231–232, where the two toggles become the default for new polls rather than the rule for open ones; featureFlags.ts 62–63 and 194–195, the type and the code defaults. Plus a selector at creation in the same places that set max_bet (the admin draft queue, the draft, Investigator and local-issue composers, and the two service-role publishers), a decay_mode column on poll_drafts, and the three SQL publish paths. The arithmetic already takes a mode, so mostly only its source moves — with one exception since decision 95: betCeiling.ts's quadratic branch and DecayChartModal.tsx's third copy (calcDecayWeight, mode standard) still compute the superseded (1 − f)² and must become 1 − f² in the same commit. betCeiling.test.ts pins the old numbers and will fail until it is updated; that failure is the reminder. Unbuilt.is_tied = true, winning_option = 0. A settlement_reason column — tied, uncontested, frozen — would make the ledger say which (decision 62). Low priority; the money is right.autoSettleSmartPolls = false until a resolution source exists, and to apply the migration only if auto-settle stays on. Which?north-star.md, mission-roadmap-milestones.md lines 63–72, and the live outertalk.com copy all say money can never buy the verdict. The design says it does. Decide before the site gets traffic (decision 55); this page is the first replacement, and the other two still need to change.This is not open source. It is open to suggestions, from people who take it seriously. If a rule is gameable, contradictory, or illegal, we would rather hear it now than after it is built.