Research: estate tally game theory, power indices and simulations (Fork Desk 39, estate-internal-tally)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-29 22:07:10 +01:00
commit 3f241c0fe4
15 changed files with 1188 additions and 0 deletions

View file

@ -0,0 +1,174 @@
# Eyes: estate internal tally, game-theory probes (2026-10-29)
Fork: Fork Desk question 39, `eureka-body:question:estate-internal-tally` (InForce; options proportional | winner-take-all; Self's recommended: proportional). Context ruling `eureka-body:ruling:governance-estate-blocks`. Session self-2026-10-29-eureka. Facts and measured results only, no recommendation.
Operator additions folded in (her words relayed by the Self): within-bloc vote-power curves ("Patrons vote power scales with donation total, but it's logarithmic... Member vote should scale with contribution... via a lower exponent"); present case ("I'm the only active member"); renormalization ruling ("normalize it by who actually voted").
## Code, outputs, model
Dir `C:\Users\Meta\AppData\Local\Temp\claude\F--Projects-CultLib\c4b0441b-f176-4f06-b58b-75efa6163f29\scratchpad\estate-sims\` (numpy 2.5.4, Python 3.13, `python -I <script>`; each `X.py` writes `X.out.md`, full tables there):
`power.py` exact Banzhaf/Shapley and two-tier individual power; `mc.py` Monte Carlo outcomes; `weights.py` within-bloc curves; `growth.py` present case and growth path; `strat.py` misreport/abstention and logrolling; `noshow.py` no-show and quorum under renormalization; `lone.py` lone-estate bounds (her absent).
- Pass rule as in Bifrost `MotionGovernanceService`: For/(For+Against) >= q, abstain excluded. Every tally renormalizes over estates with at least one For/Against ballot (the ruling); a WTA tie casts nothing, so a tied estate also drops out. Ties at exactly q pass (>=).
- Sizes unless stated: Minds 8, Members 15, Users 30 voting (roll 300, 10% turnout), Patrons 4. Weight seeds M/Me/U/P: equal 25/25/25/25; minds-heavy 40/30/20/10; members-heavy 20/45/20/15.
- "A priori" = Banzhaf coin-flip voters. "Motion model" (mc, weights W3): merit m~N(0,1), bloc taste e~N(0,1), bloc support p_b=logistic(1.7(0.6m+0.8e)); Minds intra-class correlation (ICC) via a shared beta-binomial propensity. ICC 0.44 is Kish-calibrated to Kohli 2026 (9 LLM judges ~ 2 effective votes, cited in the Bifrost prior-art note).
- Assumptions, not data: Member contribution = operator holds share S (0.5/0.8/0.95) of the total, the rest a Pareto(1.16) quantile ladder; Patron donations [10, 50, 200, 5000].
- Bug caught and fixed mid-run: the first mc.py drew per-voter propensities, which gives no correlation; results below are from the fixed shared-propensity version.
## 1. Unitary blocs: a priori power (power.out.md)
| weights | q | Banzhaf M/Me/U/P | Shapley M/Me/U/P | veto blocs |
|---|---|---|---|---|
| equal | .15/.5/.66 | .25 each | .25 each | none |
| minds-heavy | .15 | .33/.33/.33/0 (Patrons dummy) | same | none |
| minds-heavy | .5 | .42/.25/.25/.08 | .42/.25/.25/.08 | none |
| minds-heavy | .66 | .50/.30/.10/.10 | .58/.25/.08/.08 | Minds |
| members-heavy | .5 | .17/.50/.17/.17 | same | none |
| members-heavy | .66 | .20/.40/.20/.20 | .17/.50/.17/.17 | Members |
- Power is not weight: 40/30/20/10 at q=.5 gives Members and Users equal power; 10% Patrons are a dummy at q=.15.
- Meta-vote on weights (the ruling votes on block sizes): a reallocation of weight is a divide-the-dollar game. A simple game's core is nonempty iff it has a veto player (standard; e.g. Osborne & Rubinstein 1994 ch. 13) [M]. With no veto bloc (most rows) every weight vector can be beaten by a winning coalition that moves weight to itself. Where a veto bloc exists (minds-heavy .66, members-heavy .66), that bloc must be in any reweighting coalition. At equal weights and q > .75 every bloc is a veto player.
## 2. Individual power inside blocs, a priori (power.out.md)
P(one voter flips the motion); sizes 8/15/30/4.
| weights | q | rule | Mind | Member | User | Patron | max/min |
|---|---|---|---|---|---|---|---|
| equal | .5 | WTA | .118 | .096 | .064 | .158 | 2.5 |
| equal | .5 | prop | .143 | .077 | .038 | .296 | 7.7 |
| equal | .66 | WTA | .118 | .096 | .064 | .158 | 2.5 |
| equal | .66 | prop | .026 | .015 | .007 | .047 | 6.5 |
| minds-heavy | .5 | WTA | .169 | .108 | .051 | .061 | 3.3 |
| minds-heavy | .5 | prop | .234 | .091 | .030 | .115 | 7.8 |
| members-heavy | .5 | WTA | .037 | .189 | .016 | .058 | 11.5 |
| members-heavy | .5 | prop | .125 | .151 | .033 | .189 | 5.8 |
- Under prop each voter's marginal weight is w_b/n_b, so individual power scales ~1/n. Under WTA it scales ~1/sqrt(n) (Penrose). WTA compresses individual inequality, except where the council game makes a bloc near-dummy (members-heavy WTA: Users .016).
- At q=.66 with coin-flip voters, prop individual power collapses (a bloc share rarely sits near the threshold). WTA is unchanged at equal weights (3 of 4 blocs either way).
- Penrose sqrt shares for 8/15/30/4: 19.9/27.3/38.6/14.1. Using Minds n_eff 1.96 instead of 8: 11.0/30.4/43.0/15.7. Under sqrt weights the WTA individual powers are .093/.084/.096/.122, roughly equal (4 blocs is too few for exactness). Headcount weights make prop exactly equal (.106 each) but make WTA Minds and Patrons dummies (0) and Users a dictator.
## 3. Monte Carlo, motion model (mc.out.md; Minds ICC .44)
| weights | q | P(pass) prop | P(pass) WTA | P(outcomes differ) |
|---|---|---|---|---|
| equal | .15 / .5 / .66 | .934/.501/.265 | .838/.594/.404 | .098/.119/.148 |
| minds-heavy | .15 / .5 / .66 | .913/.500/.299 | .796/.537/.357 | .122/.118/.091 |
| members-heavy | .15 / .5 / .66 | .932/.500/.270 | .838/.500/.342 | .101/.111/.113 |
- The two rules disagree on 9-15% of motions in every configuration. Prop is the weighted popular share, so each disagreement is a WTA referendum paradox (Nurmi 1998) [M]. WTA flattens the effective threshold: passes less at .15 and more at .66, because a bloc that clears its internal majority casts 100%.
- Single-voter pivot (equal, q=.5), prop vs WTA: Mind .050/.021, Member .026/.023, User .013/.012, Patron .100/.076.
- Minds correlation (equal, q=.5):
| Minds ICC | n_eff of 8 | mean abs(Minds share - .5) | Mind pivot prop | Mind pivot WTA | P(Minds 4-4 tie) | P(rules differ) |
|---|---|---|---|---|---|---|
| 0 | 8.0 | .280 | .051 | .040 | .107 | .115 |
| .44 | 1.96 | .379 | .050 | .020 | .054 | .119 |
| .8 | 1.21 | .458 | .049 | .006 | .017 | .124 |
| 1 | 1.0 | .500 | .047 | 0 | 0 | .126 |
Correlation pushes the Minds split toward 0/8 or 8/0, so prop and WTA deliver nearly the same Minds cast. Under WTA one Persona's flip almost never matters at ICC >= .44; under prop each Persona keeps a 1/8 slice regardless.
- Users turnout (equal, q=.5): at turnout 1/3/10/30%, P(the WTA cast misstates the population majority) = .18/.12/.08/.04 and the mean prop share error = .19/.11/.06/.03. P(motion differs from the full-turnout result) is prop .077/.044/.024/.014 vs WTA .062/.040/.024/.014. The rules are about equal here.
- Faction capture (Users population support .3, 9 random voters + k coordinated): P(WTA Users cast For) for k=0/3/6/9 = .10/.27/.80/.96; prop share .30/.48/.58/.65. Under WTA a 6-voter faction takes the whole Users weight 80% of the time; under prop it moves the share by .28.
## 4. Within-bloc power curves (weights.out.md)
Kish n_eff = (sum w)^2 / sum w^2. "Top" = the operator (Members) or the largest donor (Patrons). Internal Banzhaf = P(top's flip changes the bloc's WTA cast).
| bloc | curve | S | n_eff | top share | top internal Banzhaf |
|---|---|---|---|---|---|
| Members 15 | one-each | - | 15.0 | .067 | .21 |
| Members 15 | k=1 / 2 / 3 / 5 | .5 | 3.6 / 10.1 / 12.9 / 14.3 | .50 / .22 / .15 / .11 | 1.0 / .67 / .48 / .33 |
| Members 15 | k=1 / 2 / 3 / 5 | .8 | 1.6 / 6.1 / 10.4 / 13.5 | .80 / .36 / .23 / .14 | 1.0 / .96 / .70 / .47 |
| Patrons 4 | one-each / k=1 / log(1+d) | - | 4.0 / 1.1 / 3.3 | .25 / .95 / .42 | .75 / 1.0 / .75 |
| Patrons 4 | k=3 / 5 / 10 | - | 2.4 / 3.2 / 3.8 | .59 / .45 / .35 | 1.0 / .75 / .75 |
(The k=1, S=.5 row is an exact 50% tie with the rest, scored pivotal because tie-to-win counts as a change. Internal Banzhaf .75 for 4 one-each Patrons has the same cause.) On this donation ladder log(1+d) flattens like d^(1/5); d^(1/3) still leaves the top Patron dictating the bloc under WTA.
Operator's whole-tally pivot (a priori, Patrons log(1+d); W2):
| seed | q | S | one-each | k=1 | k=2 | k=3 | k=5 | (Mind / User, k=3) |
|---|---|---|---|---|---|---|---|---|
| equal | .5 | .5 prop/WTA | .069/.089 | .50/.42 | .23/.29 | .16/.20 | .12/.14 | .13/.11, .035/.059 |
| equal | .5 | .8 prop/WTA | - | .75/.42 | .38/.40 | .24/.30 | .15/.20 | |
| equal | .66 | .8 prop/WTA | - | .25/.42 | .09/.41 | .06/.30 | .04/.20 | |
| members-heavy | .5 | .8 prop/WTA | .15/.18 | 1.0/.84 | .75/.81 | .50/.59 | .32/.40 | |
- Under WTA her power is capped by the Members bloc's council power: about .42 at equal weights and .84 at members-heavy, reached once she dictates the bloc. Under prop it is uncapped at q=.5 (members-heavy k=1 S=.8: .999, which makes her near-dictator of the whole tally). At q=.66 prop shrinks every individual's power and WTA does not.
- Exponent sensitivity, motion model (W3; equal, q=.5, S=.5, baseline Members k=3 and Patrons log): P(outcome changes vs baseline) for Members one-each/k=1/k=2/k=5 is prop .014/.051/.010/.007, WTA .014/.061/.012/.008. For the Patron curve one-each/k=1/k=3/k=5/k=10 it is prop .027/.080/.026/.006/.013, WTA .032/.033/.033/0/0. Outcomes move by 1-8%. Her pivot moves more: .025 (one-each) to .21 (k=1) prop, and .022 to .30 WTA.
## 5. Present case and growth (growth.out.md, noshow.out.md; renormalized)
Present case: Members = her alone, Minds 8, Users and Patrons empty, so only two estates are live and their weights renormalize. P(pass | she votes For / Against / stays home), Minds coin-flip (N2):
| seed (M,Me) | q | prop | WTA |
|---|---|---|---|
| 25,25 | .5 | 1.00 / .004 / .64 | 1.00 / .36 / .36 |
| 25,25 | .66 | .86 / 0 / .15 | .64 / 0 / .36 |
| 40,30 | .5 | .996 / .035 / .64 | .64 / .36 / .36 |
| 20,45 | any | 1.00 / 0 / home .64 (.5), .15 (.66) | 1.00 / 0 / .36 |
- Equal seed, q=.5: under prop she decides the motion 99.6% of the time (Minds share must hit 8/0 to beat her Against). Under WTA her Against is overridden whenever the Minds majority is For (25 vs 25 ties and passes at >=). Minds-heavy WTA: a unanimous Minds bloc decides alone (her pivot 0.000 with correlated Minds). Members-heavy: she is dictator under both rules.
- With 3 Users + 1 Patron present (G1), equal q=.5: her pivot is .50 prop / .41 WTA.
When her single vote stops deciding the Members bloc under WTA (share <= .5; G2):
| curve | S=.5 | S=.8 | S=.95 |
|---|---|---|---|
| one-each | n=2 (tie), n>=3 | n=2 (tie), n>=3 | n=2 (tie), n>=3 |
| k=5 | n>=2 (tie at 2) | n=3 | n=5 |
| k=3 | n>=2 | n=5 (n=3 at .501) | n=10 |
| k=2 | n>=2 | n=10 | n=50 |
| k=1 | always tied at .5 | never | never |
Growth path, her whole-tally pivot (equal seed, q=.5, Users 10, Patrons 2): alone .72 prop / .43 WTA. n=5, S=.8: k=1 .60/.43, k=3 .31/.38, k=5 .24/.22, one-each .15/.16. n=20, S=.8: k=3 .16/.29, k=5 .10/.18, one-each .04/.08. Members-heavy seed, n=20, S=.8, k=3: .38/.59.
## 5b. Lone estate bounds, she absent (lone.out.md)
Operator ruling relayed: "But they totally should be able to make decisions without me if I'm not there to vote". Under renormalization the Minds estate is then the whole tally.
- Quorum floors a lone, fully turned-out Minds estate meets:
- Headcount floor: 8/9 = .889 of eligible individuals.
- Estate-weight floor (Minds weight over live-eligible estate weight): .500 equal, .571 minds-heavy, .308 members-heavy.
- Any floor above these values requires her turnout. The at-least-two-estates floor (section 6 N1) requires her by construction while Users and Patrons are empty, so it is kept only as a later-membership comparison.
- Category thresholds (Bifrost `MotionCategoryPolicy`), lone Minds, all 8 voting. Columns: Personas needed under prop, then P(pass) in the motion model at Minds ICC 0 / .44 / 1:
- Bugs .15: 2 needed; .78/.65/.50
- Cosmetics .30: 3 needed; .66/.59/.50
- Balance .40: 4 needed; .55/.53/.50
- Features and NewContent .50: 4 needed; .55/.53/.50
- FundamentalDesign .66: 6 needed; .34/.42/.50
- Under WTA a lone estate casts 100% For or 100% Against, so the ratio is 1 or 0 and every category passes on a 5-of-8 majority: .45/.47/.50. Category thresholds are inert for a lone estate under WTA and binding under prop.
- At ICC 1 (one effective Mind) both rules give .50 at every threshold: the threshold stops discriminating when the estate votes as one.
- Delay-plus-cancel window: P(she is back before effect), absence ~ Exponential(mean A); this measures the chance a cancel opportunity exists, not that it is used.
| delay D | A=1 day | A=3 days | A=7 days | A=14 days |
|---|---|---|---|---|
| 1 day | .63 | .28 | .13 | .07 |
| 3 days | .95 | .63 | .35 | .19 |
| 7 days | 1.00 | .90 | .63 | .39 |
| 14 days | 1.00 | .99 | .86 | .63 |
Prior-art delays (Bifrost prior-art note, section 5 and section 1):
- Compound Timelock: 2 days.
- OpenZeppelin Timelock: exists so users can "exit the system if they disagree" before a decision executes; a canceller role; a guardian may cancel at any stage.
- Olympus Bravo: veto guardian until execution.
- Apache: votes run at least 72 h.
- Rust FCP: 10 days, and a raised concern blocks.
- Beanstalk had no delay; its governance attack drained ~$76M.
## 6. Strategic probes
S1 (strat.py, exhaustive; sizes 3/3/2/2, sincere profiles, no quorum): 0 profitable misreports or abstentions under either rule at any q or seed. The For/(For+Against) ratio is monotone and participation-safe without a quorum. With a cast-weight quorum (>= 50% of estate weight), WTA produced 144-288 profitable abstentions per 10240 cases: an abstention creates an internal tie, the estate drops out, and quorum fails. Prop produced 0.
N1 (noshow.py, renormalized, quorum floors). Columns: individual profitable deviations / hers / profitable estate stay-home. Present case 8/1/0/0, 512 profiles:
- No quorum: 0 / 0 / 0 in every seed, q and rule.
- Headcount quorum (>= half of eligible): 0 individual deviations. Estate stay-home is profitable in 56-93 profiles, because with only 9 eligible the Minds estate staying home breaks quorum.
- "At least two estates": WTA equal q=.5 gives 93 / 93 / 186; prop gives 1 / 1 / 94. Her staying home kills any motion she opposes, because with Users and Patrons empty she is the second estate. Minds-heavy q=.5: prop 9 / 9 / 101, WTA 93 / 93 / 93. At q=.66 most of these drop to 0 (prop equal still 56 estate cases).
- Mixed 3/1/2/1 with everyone voting: 0 under every floor. The no-show leverage comes from empty estates, not from the rule itself.
S2 logrolling (6-motion agendas, 1500 each, greedy mutually profitable pairwise trades; welfare = sum of bloc utilities). Unitary blocs can deliver their whole weight; proportional blocs' leadership moves the share by delta:
| seed | bloc type | P(>=1 trade) | mean trades | mean welfare change | P(welfare falls) | P(a non-trader loses) | P(a trader ends worse) |
|---|---|---|---|---|---|---|---|
| equal | unitary | .615 | 1.04 | +.168 | .245 | .397 | .234 |
| equal | prop delta .5 | .430 | .66 | -.396 | .338 | .305 | .127 |
| equal | prop delta .2 | .127 | .17 | -.027 | .071 | .093 | .017 |
| minds-heavy | unitary | .615 | .90 | +.016 | .302 | .484 | .184 |
| minds-heavy | prop delta .5 | .324 | .44 | -.306 | .230 | .261 | .076 |
- Unitary blocs find trades on most agendas. Trades raise mean welfare (equal seed) but impose losses on a non-trading bloc in 40-48% of agendas and leave a trader worse than sincere in 18-23%, which is Riker & Brams's paradox of vote trading at bloc scale. Partial-delivery blocs trade far less. The negative mean welfare at delta .5 is a model result (proportional shares near .5 flip low-stakes motions) that I have not cross-checked.
## 7. Literature (one or two lines each; [V] = verified by search this pass, [M] = from memory, not fetched)
- Putnam 1988, "Diplomacy and Domestic Politics: The Logic of Two-Level Games", Int. Org. 42(3):427-460 [M]. A deal must lie in each side's domestic win-set; a smaller win-set gives bargaining advantage (the Schelling conjecture), with the risk of involuntary defection. Mapping: a bloc parliament that ratifies the bloc position is a level-II ratifier. A prop bloc has no ratified position to bargain from.
- Schelling 1956 "An Essay on Bargaining", AER 46(3); Strategy of Conflict 1960 [M]. Binding oneself (burning bridges) is power. A unitary bloc whose position is fixed by an internal vote is a visible commitment device; prop splitting commits nothing beyond the count.
- Tests of the conjecture [V]. Mo 1995 APSR 89(4):914-924: a negotiator may gain by giving an agent veto, but only when the agent's preferences are extreme enough and depending on what the other side knows. Iida 1993 JCR and 1996 Public Choice: incomplete information about domestic preferences drives ratification failure; two-sided constraints give relatively equitable outcomes. Tarar 2001 JCR 45(3):320-340: with both sides constrained and incomplete information, the opposite of the conjecture can occur. All four estates having parliaments is the two-sided case.
- Diermeier & Feddersen 1998 APSR 92(3) [M]: the vote-of-confidence procedure makes coalitions cohesive, and cohesion raises a coalition's value in legislative bargaining. This is the party-discipline analogue: a disciplined unit outbargains an undisciplined one. Krehbiel 1993 "Where's the Party?" and Cox & McCubbins 1993 dispute how much discipline is real.
- Riker & Brams 1973 "The Paradox of Vote Trading", APSR 67(4) [M]: individually rational trades can leave all parties worse off. S2 measures it.
- Snyder, Ting & Ansolabehere 2005 "Legislative Bargaining under Weighted Voting", AER 95(4) [M]: in Baron-Ferejohn bargaining, expected payoffs track minimal-integer-representation weights rather than Banzhaf/Shapley. This applies to the weight meta-vote as distributive bargaining among unitary blocs.
- Penrose 1946 JRSS 109; Banzhaf 1965 Rutgers L. Rev. 19 [M]. Two-tier WTA equalizes individual power with sqrt(n) weights. Banzhaf 1968 "One Man, 3.312 Votes" showed large US states' unit rule over-empowers their voters [M].
- Jagiellonian compromise [V]: Słomczyński & Życzkowski; sqrt-of-population weights with quota ~62% (61.5% for EU-27) (arXiv cond-mat/0405396, 0712.2699). Poland tabled it in 2007; the Council adopted the double majority instead.
- Gelman, Katz & Bafumi 2004, BJPS 34(4):657-674 [V]: the coin-flip model overstates decisiveness in large units; empirically, proportional weights are "basically fair" and sqrt is not. Kirsch 2007 (Homo Oeconomicus) [M]: with correlated voters the optimal two-tier weights move from sqrt(n) toward n. The Minds correlation table above is a local instance: a high-ICC bloc of 8 has n_eff ~ 2.
- Coleman 1971 [M]: separates the power to initiate action from the power to prevent it. The thresholds .15 vs .66 shift power between these two, which is visible in the q rows of section 2.
- Electoral college unit rule [M]. Pathologies: campaigning and policy concentrate in swing states (Strömberg 2008 AER 98(3)); referendum paradox (Nurmi 1998 SCW 15). Faithless electors are bound by state law (Chiafalo v. Washington, 2020); in a bloc parliament the analogue is a Persona breaking the bloc mandate.
- Estates-General 1789 [M]: vote by order (each estate one unitary vote) vs by head; the Third Estate refused the unitary-order rule and declared itself the National Assembly on 17 June 1789. Precedent: a unitary-estate rule is contested when one estate's size outgrows its weight.
- Lijphart 1969 World Politics 21(2); Democracy in Plural Societies 1977 [M]. Consociationalism has four pillars: grand coalition, segmental autonomy, proportionality and mutual veto. Segmental autonomy fits each estate running its own internal process; mutual veto corresponds to the q > .75 equal-weight case in section 1.
- Hirschman 1970 [M]: exit, voice, loyalty. In section 5 no-show acts as exit-as-leverage when an estate is the quorum's second member.
## 8. Candidate articulations of the hunch: what the evidence shows
- Credible commitment / paradox of weakness. Supported in theory by Putnam, Schelling, Mo and Diermeier-Feddersen; qualified by Mo (needs an extreme agent) and reversed under two-sided incomplete information (Tarar). In sim, only unitary blocs can deliver whole-weight trades (S2: 61.5% of agendas vs 12.7% at delta .2).
- Power games in the open. Supported in structure: unitary blocs have 2^4 = 16 coalitions and the trades are pairwise and nameable. Under prop, influence travels through individual cross-bloc switching (prop pivots are per-individual, section 2). Contradicted in part by S2: open bloc trades still harm a non-trading bloc in 40-48% of agendas (Riker-Brams).
- Internal deliberation absorbs correlated noise. For Minds at ICC >= .44, prop and WTA already cast nearly the same weight (section 3), so the internal rule matters little there; a parliament would decide which Persona's argument wins, not the tally. For Users at low turnout, both rules carry the same sampling error (.08 at 10%), and WTA is more capturable by a small faction (k=6: 80%).
- Legibility of who owes whom. Unitary trades are pairwise records; under prop the "debt" is spread over individuals. No source measured this directly. Not found.
- Individual equality cuts the other way. WTA two-tier is Penrose-equalizable with sqrt weights; prop needs headcount weights. Gelman et al. and Kirsch argue that correlation pulls the fair weights back toward proportional.
- Operator dominance. Under WTA her ceiling is the Members bloc's council power (.42 equal, .84 members-heavy). Under prop at q=.5 her influence has no such ceiling. Her internal dictatorship of Members ends at the n shown in the section 5 table.
- Renormalization with no quorum: participation-safe in every exhaustive probe. Adding any quorum floor while estates are empty hands the sole Member, or the Minds estate, a stay-home veto. The two-estates floor conflicts with the "decide without me" ruling today. The bounds that remain on a lone Minds estate are a headcount floor <= .889, category thresholds (binding only under prop, and void at ICC 1), and a delay window whose cancel opportunity depends on her absence length (section 5b).

View file

@ -0,0 +1,110 @@
## G1. Present case: Members = her alone, Minds 8 (fair coins; 'unan' = Minds fully correlated)
Cells: P(her vote flips the motion) / P(outcome matches her vote), prop then WTA.
| seed | q | Users, Patrons | Minds | prop pivot / match | WTA pivot / match |
|---|---|---|---|---|---|
| equal | 0.15 | 0U, 0P | indep | 0.145 / 0.570 | 0.636 / 0.817 |
| equal | 0.15 | 0U, 0P | unan | 0.501 / 0.752 | 0.501 / 0.752 |
| equal | 0.15 | 3U, 1P | indep | 0.066 / 0.530 | 0.159 / 0.578 |
| equal | 0.15 | 3U, 1P | unan | 0.126 / 0.564 | 0.126 / 0.564 |
| equal | 0.5 | 0U, 0P | indep | 0.996 / 0.998 | 0.636 / 0.817 |
| equal | 0.5 | 0U, 0P | unan | 0.501 / 0.752 | 0.501 / 0.752 |
| equal | 0.5 | 3U, 1P | indep | 0.500 / 0.750 | 0.410 / 0.705 |
| equal | 0.5 | 3U, 1P | unan | 0.467 / 0.733 | 0.374 / 0.687 |
| equal | 0.66 | 0U, 0P | indep | 0.855 / 0.928 | 0.635 / 0.818 |
| equal | 0.66 | 0U, 0P | unan | 0.499 / 0.749 | 0.499 / 0.749 |
| equal | 0.66 | 3U, 1P | indep | 0.420 / 0.712 | 0.407 / 0.705 |
| equal | 0.66 | 3U, 1P | unan | 0.375 / 0.687 | 0.375 / 0.687 |
| minds-heavy | 0.15 | 0U, 0P | indep | 0.145 / 0.570 | 0.636 / 0.817 |
| minds-heavy | 0.15 | 0U, 0P | unan | 0.501 / 0.752 | 0.501 / 0.752 |
| minds-heavy | 0.15 | 3U, 1P | indep | 0.017 / 0.506 | 0.251 / 0.624 |
| minds-heavy | 0.15 | 3U, 1P | unan | 0.251 / 0.627 | 0.251 / 0.628 |
| minds-heavy | 0.5 | 0U, 0P | indep | 0.961 / 0.980 | 0.271 / 0.636 |
| minds-heavy | 0.5 | 0U, 0P | unan | 0.000 / 0.501 | 0.000 / 0.501 |
| minds-heavy | 0.5 | 3U, 1P | indep | 0.857 / 0.929 | 0.477 / 0.739 |
| minds-heavy | 0.5 | 3U, 1P | unan | 0.280 / 0.640 | 0.374 / 0.688 |
| minds-heavy | 0.66 | 0U, 0P | indep | 0.635 / 0.818 | 0.635 / 0.818 |
| minds-heavy | 0.66 | 0U, 0P | unan | 0.499 / 0.749 | 0.499 / 0.749 |
| minds-heavy | 0.66 | 3U, 1P | indep | 0.484 / 0.744 | 0.475 / 0.739 |
| minds-heavy | 0.66 | 3U, 1P | unan | 0.467 / 0.733 | 0.375 / 0.687 |
| members-heavy | 0.15 | 0U, 0P | indep | 0.365 / 0.681 | 0.636 / 0.817 |
| members-heavy | 0.15 | 0U, 0P | unan | 0.501 / 0.752 | 0.501 / 0.752 |
| members-heavy | 0.15 | 3U, 1P | indep | 0.122 / 0.558 | 0.159 / 0.578 |
| members-heavy | 0.15 | 3U, 1P | unan | 0.220 / 0.611 | 0.126 / 0.564 |
| members-heavy | 0.5 | 0U, 0P | indep | 1.000 / 1.000 | 1.000 / 1.000 |
| members-heavy | 0.5 | 0U, 0P | unan | 1.000 / 1.000 | 1.000 / 1.000 |
| members-heavy | 0.5 | 3U, 1P | indep | 0.988 / 0.994 | 0.818 / 0.908 |
| members-heavy | 0.5 | 3U, 1P | unan | 0.936 / 0.968 | 0.750 / 0.875 |
| members-heavy | 0.66 | 0U, 0P | indep | 1.000 / 1.000 | 1.000 / 1.000 |
| members-heavy | 0.66 | 0U, 0P | unan | 1.000 / 1.000 | 1.000 / 1.000 |
| members-heavy | 0.66 | 3U, 1P | indep | 0.700 / 0.851 | 0.567 / 0.785 |
| members-heavy | 0.66 | 3U, 1P | unan | 0.687 / 0.843 | 0.500 / 0.749 |
## G2. Her weight share inside Members; WTA-internal she alone decides the bloc iff share > 0.5
| n Members | S | one-each | k=1 | k=2 | k=3 | k=5 |
|---|---|---|---|---|---|---|
| 1 | 1.0 | 1.00* | 1.00* | 1.00* | 1.00* | 1.00* |
| 2 | 0.5 | 0.50 | 0.50 | 0.50 | 0.50 | 0.50 |
| 2 | 0.8 | 0.50 | 0.80* | 0.67* | 0.61* | 0.57* |
| 2 | 0.95 | 0.50 | 0.95* | 0.81* | 0.73* | 0.64* |
| 3 | 0.5 | 0.33 | 0.50 | 0.42 | 0.39 | 0.37 |
| 3 | 0.8 | 0.33 | 0.80* | 0.59* | 0.50* | 0.43 |
| 3 | 0.95 | 0.33 | 0.95* | 0.76* | 0.63* | 0.51* |
| 5 | 0.5 | 0.20 | 0.50 | 0.34 | 0.29 | 0.25 |
| 5 | 0.8 | 0.20 | 0.80* | 0.51* | 0.39 | 0.31 |
| 5 | 0.95 | 0.20 | 0.95* | 0.69* | 0.52* | 0.38 |
| 10 | 0.5 | 0.10 | 0.50* | 0.26 | 0.19 | 0.15 |
| 10 | 0.8 | 0.10 | 0.80* | 0.41 | 0.28 | 0.19 |
| 10 | 0.95 | 0.10 | 0.95* | 0.60* | 0.39 | 0.24 |
| 20 | 0.5 | 0.05 | 0.50 | 0.20 | 0.13 | 0.09 |
| 20 | 0.8 | 0.05 | 0.80* | 0.33 | 0.19 | 0.12 |
| 20 | 0.95 | 0.05 | 0.95* | 0.52* | 0.29 | 0.15 |
| 50 | 0.5 | 0.02 | 0.50* | 0.14 | 0.08 | 0.05 |
| 50 | 0.8 | 0.02 | 0.80* | 0.24 | 0.12 | 0.06 |
| 50 | 0.95 | 0.02 | 0.95* | 0.41 | 0.18 | 0.08 |
(* = she alone decides the Members bloc under WTA/unitary internal majority)
## G3. Growth path: her pivot over the whole tally (fair coins, Minds indep, Users 10, Patrons [50,500] log), q=0.5
| seed | n Members | S | curve | prop pivot | WTA pivot |
|---|---|---|---|---|---|
| equal | 1 | 1.0 | alone | 0.723 | 0.429 |
| equal | 5 | 0.5 | one-each | 0.152 | 0.161 |
| equal | 5 | 0.5 | k=1 | 0.387 | 0.413 |
| equal | 5 | 0.5 | k=2 | 0.259 | 0.269 |
| equal | 5 | 0.5 | k=3 | 0.225 | 0.215 |
| equal | 5 | 0.5 | k=5 | 0.195 | 0.161 |
| equal | 5 | 0.8 | one-each | 0.152 | 0.161 |
| equal | 5 | 0.8 | k=1 | 0.601 | 0.434 |
| equal | 5 | 0.8 | k=2 | 0.392 | 0.434 |
| equal | 5 | 0.8 | k=3 | 0.305 | 0.380 |
| equal | 5 | 0.8 | k=5 | 0.237 | 0.215 |
| equal | 20 | 0.5 | one-each | 0.040 | 0.076 |
| equal | 20 | 0.5 | k=1 | 0.396 | 0.430 |
| equal | 20 | 0.5 | k=2 | 0.161 | 0.290 |
| equal | 20 | 0.5 | k=3 | 0.106 | 0.201 |
| equal | 20 | 0.5 | k=5 | 0.074 | 0.144 |
| equal | 20 | 0.8 | one-each | 0.040 | 0.076 |
| equal | 20 | 0.8 | k=1 | 0.606 | 0.430 |
| equal | 20 | 0.8 | k=2 | 0.267 | 0.411 |
| equal | 20 | 0.8 | k=3 | 0.156 | 0.293 |
| equal | 20 | 0.8 | k=5 | 0.095 | 0.179 |
| members-heavy | 1 | 1.0 | alone | 1.000 | 0.862 |
| members-heavy | 5 | 0.5 | one-each | 0.296 | 0.323 |
| members-heavy | 5 | 0.5 | k=1 | 0.752 | 0.823 |
| members-heavy | 5 | 0.5 | k=2 | 0.519 | 0.538 |
| members-heavy | 5 | 0.5 | k=3 | 0.441 | 0.429 |
| members-heavy | 5 | 0.5 | k=5 | 0.380 | 0.323 |
| members-heavy | 5 | 0.8 | one-each | 0.296 | 0.323 |
| members-heavy | 5 | 0.8 | k=1 | 0.987 | 0.862 |
| members-heavy | 5 | 0.8 | k=2 | 0.779 | 0.862 |
| members-heavy | 5 | 0.8 | k=3 | 0.613 | 0.755 |
| members-heavy | 5 | 0.8 | k=5 | 0.475 | 0.429 |
| members-heavy | 20 | 0.5 | one-each | 0.099 | 0.152 |
| members-heavy | 20 | 0.5 | k=1 | 0.832 | 0.861 |
| members-heavy | 20 | 0.5 | k=2 | 0.388 | 0.580 |
| members-heavy | 20 | 0.5 | k=3 | 0.259 | 0.403 |
| members-heavy | 20 | 0.5 | k=5 | 0.179 | 0.288 |
| members-heavy | 20 | 0.8 | one-each | 0.099 | 0.152 |
| members-heavy | 20 | 0.8 | k=1 | 0.991 | 0.861 |
| members-heavy | 20 | 0.8 | k=2 | 0.627 | 0.824 |
| members-heavy | 20 | 0.8 | k=3 | 0.380 | 0.586 |
| members-heavy | 20 | 0.8 | k=5 | 0.231 | 0.359 |

View file

@ -0,0 +1,73 @@
"""Present case and growth path (operator 2026-10-29: "until we get more people in, I'm the only active member").
Operator = Member 0. S = her share of total Member contribution; the other n-1 follow the Pareto(1.16) ladder.
Empty blocs cast nothing and drop out of the denominator (abstentions excluded). Run: python -I growth.py
"""
import numpy as np
SEEDS = {"equal": [25, 25, 25, 25], "minds-heavy": [40, 30, 20, 10], "members-heavy": [20, 45, 20, 15]}
CURVES = {"one-each": None, "k=1": 1, "k=2": 2, "k=3": 3, "k=5": 5}
def mweights(n, S, k):
if n == 1: return np.ones(1)
tail = np.array([i ** (-1 / 1.16) for i in range(1, n)]); tail = tail / tail.sum() * (1 - S)
c = np.concatenate([[S], tail]); return np.ones(n) if k is None else c ** (1 / k)
def tally(Wb, F, Tot, q, rule):
Wb = np.array(Wb, float); live = Tot > 0
if rule == "prop":
sh = np.divide(F, Tot, out=np.zeros_like(F), where=live); f = (sh * Wb).sum(1); den = (live * Wb).sum(1)
else:
st = np.where(live, np.sign(2 * F - Tot), 0); f = (st == 1) @ Wb; den = f + (st == -1) @ Wb
return (den > 0) & (f >= q * den - 1e-9)
def her_power(wM, Wb, q, users=0, patrons=(), minds_corr=False, T=200_000, seed=5):
r = np.random.default_rng(seed)
ws = [np.ones(8), wM, np.ones(users), np.log1p(np.array(patrons, float))]
F = np.zeros((T, 4)); Tot = np.zeros((T, 4)); her = None
for b, w in enumerate(ws):
if len(w) == 0: continue
if b == 0 and minds_corr: v = np.repeat(r.random((T, 1)) < .5, 8, 1)
else: v = r.random((T, len(w))) < .5
if b == 1: her = v[:, 0]
F[:, b] = v @ w; Tot[:, b] = w.sum()
res = {}
for rule in ("prop", "wta"):
G = F.copy(); G[:, 1] += np.where(her, -wM[0], wM[0])
o = tally(Wb, F, Tot, q, rule); o2 = tally(Wb, G, Tot, q, rule)
res[rule] = (np.mean(o != o2), np.mean(o == her))
return res
if __name__ == "__main__":
print("## G1. Present case: Members = her alone, Minds 8 (fair coins; 'unan' = Minds fully correlated)")
print("Cells: P(her vote flips the motion) / P(outcome matches her vote), prop then WTA.")
print("| seed | q | Users, Patrons | Minds | prop pivot / match | WTA pivot / match |")
print("|---|---|---|---|---|---|")
for name, Wb in SEEDS.items():
for q in (0.15, 0.5, 0.66):
for users, pat in ((0, ()), (3, (100,))):
for mc in (False, True):
r = her_power(np.ones(1), Wb, q, users, pat, mc, T=100_000)
print(f"| {name} | {q} | {users}U, {len(pat)}P | {'unan' if mc else 'indep'} | {r['prop'][0]:.3f} / {r['prop'][1]:.3f} | {r['wta'][0]:.3f} / {r['wta'][1]:.3f} |")
print("\n## G2. Her weight share inside Members; WTA-internal she alone decides the bloc iff share > 0.5")
print("| n Members | S | one-each | k=1 | k=2 | k=3 | k=5 |")
print("|---|---|---|---|---|---|---|")
for n in (1, 2, 3, 5, 10, 20, 50):
for S in (0.5, 0.8, 0.95):
if n == 1 and S != 0.95: continue
cells = []
for kn, k in CURVES.items():
w = mweights(n, S if n > 1 else 1, k); sh = w[0] / w.sum()
cells.append(f"{sh:.2f}{'*' if sh > 0.5 else ''}")
print(f"| {n} | {S if n > 1 else 1.0} | " + " | ".join(cells) + " |")
print("(* = she alone decides the Members bloc under WTA/unitary internal majority)")
print("\n## G3. Growth path: her pivot over the whole tally (fair coins, Minds indep, Users 10, Patrons [50,500] log), q=0.5")
print("| seed | n Members | S | curve | prop pivot | WTA pivot |")
print("|---|---|---|---|---|---|")
for name in ("equal", "members-heavy"):
Wb = SEEDS[name]
for n in (1, 5, 20):
for S in ((1.0,) if n == 1 else (0.5, 0.8)):
for kn, k in (CURVES.items() if n > 1 else [("alone", None)]):
r = her_power(mweights(n, S, k), Wb, .5, users=10, patrons=(50, 500), T=100_000)
print(f"| {name} | {n} | {S} | {kn} | {r['prop'][0]:.3f} | {r['wta'][0]:.3f} |")

View file

@ -0,0 +1,28 @@
## L1. Quorum floors a lone Minds turnout (8 of 8) meets, she absent
| floor type | Minds-alone value | equal | minds-heavy | members-heavy |
|---|---|---|---|---|
| headcount fraction of eligible (8 Minds + her) | 8/9 = 0.889 | same | same | same |
| estate-weight fraction of live-eligible estates | w_M/(w_M+w_Me) | 0.500 | 0.571 | 0.308 |
A floor above these values requires her turnout; at or below, Minds alone can decide.
## L2. Lone Minds: Personas For needed and P(pass), motion model, by category
| category | q | Personas needed prop | Personas needed WTA | P(pass) prop ICC 0 / .44 / 1 | P(pass) WTA ICC 0 / .44 / 1 |
|---|---|---|---|---|---|
| Bugs | 0.15 | 2 | 5 (any q) | 0.775 / 0.647 / 0.500 | 0.446 / 0.474 / 0.500 |
| Cosmetics | 0.3 | 3 | 5 (any q) | 0.662 / 0.585 / 0.500 | 0.446 / 0.474 / 0.500 |
| Balance | 0.4 | 4 | 5 (any q) | 0.554 / 0.528 / 0.500 | 0.446 / 0.474 / 0.500 |
| Features | 0.5 | 4 | 5 (any q) | 0.554 / 0.528 / 0.500 | 0.446 / 0.474 / 0.500 |
| NewContent | 0.5 | 4 | 5 (any q) | 0.554 / 0.528 / 0.500 | 0.446 / 0.474 / 0.500 |
| FundamentalDesign | 0.66 | 6 | 5 (any q) | 0.337 / 0.418 / 0.500 | 0.446 / 0.474 / 0.500 |
Under WTA a lone estate casts 100% For or 100% Against, so For/(For+Against) is 1 or 0 and category thresholds are inert.
## L3. Delay-plus-cancel window: P(she is back before the decision takes effect), absence ~ Exponential(mean A)
| delay D | A=1 day | A=3 days | A=7 days | A=14 days |
|---|---|---|---|---|
| 1 d | 0.63 | 0.28 | 0.13 | 0.07 |
| 2 d | 0.86 | 0.49 | 0.25 | 0.13 |
| 3 d | 0.95 | 0.63 | 0.35 | 0.19 |
| 7 d | 1.00 | 0.90 | 0.63 | 0.39 |
| 10 d | 1.00 | 0.96 | 0.76 | 0.51 |
| 14 d | 1.00 | 0.99 | 0.86 | 0.63 |
Memoryless assumption; real absences are not exponential. P = chance a cancel opportunity exists, not that it is used.

View file

@ -0,0 +1,41 @@
"""Lone estate bounds (operator 2026-10-29: "they totally should be able to make decisions without me if I'm not there to vote").
Present case with her absent: Minds (8) are the only live estate; renormalization makes Minds the whole tally.
L1 quorum floors that a lone Minds turnout meets; L2 category thresholds vs Personas needed and pass rates;
L3 delay-plus-cancel window: P(she returns before effect) for exponential absence. Run: python -I lone.py
"""
import math
import numpy as np
CATS = {"Bugs": .15, "Cosmetics": .30, "Balance": .40, "Features": .50, "NewContent": .50, "FundamentalDesign": .66}
print("## L1. Quorum floors a lone Minds turnout (8 of 8) meets, she absent")
print("| floor type | Minds-alone value | equal | minds-heavy | members-heavy |")
print("|---|---|---|---|---|")
print("| headcount fraction of eligible (8 Minds + her) | 8/9 = 0.889 | same | same | same |")
for lab in ("estate-weight fraction of live-eligible estates",):
vals = [wm_ / (wm_ + wme_) for wm_, wme_ in ((25, 25), (40, 30), (20, 45))]
print(f"| {lab} | w_M/(w_M+w_Me) | {vals[0]:.3f} | {vals[1]:.3f} | {vals[2]:.3f} |")
print("A floor above these values requires her turnout; at or below, Minds alone can decide.")
print("\n## L2. Lone Minds: Personas For needed and P(pass), motion model, by category")
r = np.random.default_rng(11); T = 400_000
m = r.standard_normal(T); p = 1 / (1 + np.exp(-1.7 * (0.6 * m + 0.8 * r.standard_normal(T))))
def minds_for(icc):
if icc >= 1: return np.where(r.random(T) < p, 8, 0)
if icc <= 0: return r.binomial(8, p)
a = p * (1 - icc) / icc; b = (1 - p) * (1 - icc) / icc; return r.binomial(8, r.beta(a, b))
print("| category | q | Personas needed prop | Personas needed WTA | P(pass) prop ICC 0 / .44 / 1 | P(pass) WTA ICC 0 / .44 / 1 |")
print("|---|---|---|---|---|---|")
draws = {icc: minds_for(icc) for icc in (0, .44, 1)}
for c, q in CATS.items():
need = math.ceil(q * 8 - 1e-9)
pp = [np.mean(draws[i] / 8 >= q - 1e-9) for i in (0, .44, 1)]
pw = [np.mean(draws[i] >= 5) for i in (0, .44, 1)]
print(f"| {c} | {q} | {need} | 5 (any q) | " + " / ".join(f"{x:.3f}" for x in pp) + " | " + " / ".join(f"{x:.3f}" for x in pw) + " |")
print("Under WTA a lone estate casts 100% For or 100% Against, so For/(For+Against) is 1 or 0 and category thresholds are inert.")
print("\n## L3. Delay-plus-cancel window: P(she is back before the decision takes effect), absence ~ Exponential(mean A)")
print("| delay D | A=1 day | A=3 days | A=7 days | A=14 days |")
print("|---|---|---|---|---|")
for D in (1, 2, 3, 7, 10, 14):
print(f"| {D} d | " + " | ".join(f"{1 - math.exp(-D / A):.2f}" for A in (1, 3, 7, 14)) + " |")
print("Memoryless assumption; real absences are not exponential. P = chance a cancel opportunity exists, not that it is used.")

View file

@ -0,0 +1,38 @@
## A. P(outcome differs, prop vs WTA) and single-voter pivot rates (Minds ICC .44, humans 0, Users turnout 10% = 30 voters)
| weights | q | P(pass) prop | P(pass) WTA | P(differ) | pivot prop M/Me/U/P | pivot WTA M/Me/U/P |
|---|---|---|---|---|---|---|
| equal | 0.15 | 0.934 | 0.838 | 0.098 | 0.0202/0.0118/0.0062/0.0424 | 0.0139/0.0135/0.0063/0.0406 |
| equal | 0.5 | 0.501 | 0.594 | 0.119 | 0.0501/0.0262/0.0133/0.1004 | 0.0207/0.0227/0.0115/0.0756 |
| equal | 0.66 | 0.265 | 0.404 | 0.148 | 0.0422/0.0228/0.0112/0.0870 | 0.0199/0.0219/0.0110/0.0762 |
| minds-heavy | 0.15 | 0.913 | 0.796 | 0.122 | 0.0432/0.0180/0.0058/0.0236 | 0.0193/0.0188/0.0088/0.0037 |
| minds-heavy | 0.5 | 0.500 | 0.537 | 0.118 | 0.0718/0.0258/0.0084/0.0330 | 0.0305/0.0233/0.0112/0.0276 |
| minds-heavy | 0.66 | 0.299 | 0.357 | 0.091 | 0.0651/0.0256/0.0079/0.0323 | 0.0379/0.0206/0.0040/0.0248 |
| members-heavy | 0.15 | 0.932 | 0.838 | 0.101 | 0.0184/0.0219/0.0050/0.0279 | 0.0139/0.0135/0.0063/0.0406 |
| members-heavy | 0.5 | 0.500 | 0.500 | 0.111 | 0.0376/0.0463/0.0099/0.0566 | 0.0096/0.0466/0.0050/0.0480 |
| members-heavy | 0.66 | 0.270 | 0.342 | 0.113 | 0.0343/0.0409/0.0088/0.0512 | 0.0125/0.0356/0.0068/0.0494 |
## B. Minds within-bloc correlation (equal weights, q=0.5)
| Minds ICC | Kish n_eff of 8 | P(differ) | Minds |share-0.5| mean | Minds pivot prop | Minds pivot WTA | P(Minds tie) |
|---|---|---|---|---|---|---|
| 0.0 | 8.00 | 0.115 | 0.280 | 0.0506 | 0.0403 | 0.107 |
| 0.2 | 3.33 | 0.118 | 0.324 | 0.0513 | 0.0304 | 0.086 |
| 0.44 | 1.96 | 0.119 | 0.379 | 0.0495 | 0.0199 | 0.054 |
| 0.8 | 1.21 | 0.124 | 0.458 | 0.0487 | 0.0064 | 0.017 |
| 1.0 | 1.00 | 0.126 | 0.500 | 0.0474 | 0.0000 | 0.000 |
## C. Users turnout (equal weights, q=0.5, Users roll 300)
| turnout | Users voters | P(Users WTA cast != population majority) | mean |prop share - p_U| | P(motion != full-turnout result) prop | same, WTA |
|---|---|---|---|---|---|
| 0.01 | 3 | 0.181 | 0.186 | 0.077 | 0.062 |
| 0.03 | 9 | 0.117 | 0.106 | 0.044 | 0.040 |
| 0.1 | 30 | 0.084 | 0.058 | 0.024 | 0.024 |
| 0.3 | 90 | 0.044 | 0.033 | 0.014 | 0.014 |
## D. Coordinated Users faction of k voters, Users population support p_U=0.3, turnout 3% (9 random voters + k)
| k | P(Users bloc cast For) WTA | mean Users For share prop |
|---|---|---|
| 0 | 0.098 | 0.300 |
| 3 | 0.270 | 0.475 |
| 6 | 0.803 | 0.580 |
| 9 | 0.961 | 0.650 |
| 12 | 1.000 | 0.700 |

View file

@ -0,0 +1,82 @@
"""Monte Carlo: proportional vs winner-take-all estate tallies under a motion model.
Motion model: common merit m~N(0,1), bloc taste e_b~N(0,1), bloc mean support p_b=logistic(1.7*(0.6m+0.8e_b)).
Within-bloc correlation: individual propensities ~ Beta with mean p_b and ICC r_b (beta-binomial).
Users: roll 300, a random sample of round(300*turnout) votes. Run: python -I mc.py
"""
import numpy as np
rng = np.random.default_rng(20261029)
BLOCS = ["Minds", "Members", "Users", "Patrons"]
WEIGHTS = {"equal": [25, 25, 25, 25], "minds-heavy": [40, 30, 20, 10], "members-heavy": [20, 45, 20, 15]}
T = 200_000
def draw(minds_r=0.44, human_r=0.0, turnout=0.1, T=T):
sizes = [8, 15, max(1, round(300 * turnout)), 4]
rs = [minds_r, human_r, human_r, human_r]
m = rng.standard_normal(T)
p = 1 / (1 + np.exp(-1.7 * (0.6 * m[:, None] + 0.8 * rng.standard_normal((T, 4)))))
F = np.zeros((T, 4), int); first = np.zeros((T, 4), int)
for b, (n, r) in enumerate(zip(sizes, rs)):
if r <= 0: probs = np.repeat(p[:, b:b + 1], n, 1)
elif r >= 1: probs = np.repeat((rng.random((T, 1)) < p[:, b:b + 1]).astype(float), n, 1)
else:
a = p[:, b] * (1 - r) / r; c = (1 - p[:, b]) * (1 - r) / r
probs = np.repeat(rng.beta(a, c)[:, None], n, 1) # one shared propensity per bloc-motion = beta-binomial ICC r
v = rng.random((T, n)) < probs
F[:, b] = v.sum(1); first[:, b] = v[:, 0]
return np.array(sizes), p, F, first
def out_prop(ws, sizes, F, q):
s = (F / sizes) @ np.array(ws, float); return s >= q * sum(ws) - 1e-9
def out_wta(ws, sizes, F, q):
ws = np.array(ws, float); st = np.sign(2 * F - sizes) # +1 For, -1 Against, 0 tie casts nothing
f = (st == 1) @ ws; a = (st == -1) @ ws
return (f + a > 0) & (f >= q * (f + a) - 1e-9)
def flip(F, first, b):
G = F.copy(); G[:, b] += np.where(first[:, b] == 1, -1, 1); return G
def fmt(v): return " | ".join(f"{x:.3f}" for x in v)
if __name__ == "__main__":
print("## A. P(outcome differs, prop vs WTA) and single-voter pivot rates (Minds ICC .44, humans 0, Users turnout 10% = 30 voters)")
sizes, p, F, first = draw()
print("| weights | q | P(pass) prop | P(pass) WTA | P(differ) | pivot prop M/Me/U/P | pivot WTA M/Me/U/P |")
print("|---|---|---|---|---|---|---|")
for name, ws in WEIGHTS.items():
for q in (0.15, 0.5, 0.66):
op, ow = out_prop(ws, sizes, F, q), out_wta(ws, sizes, F, q)
pp = [np.mean(op != out_prop(ws, sizes, flip(F, first, b), q)) for b in range(4)]
pw = [np.mean(ow != out_wta(ws, sizes, flip(F, first, b), q)) for b in range(4)]
print(f"| {name} | {q} | {op.mean():.3f} | {ow.mean():.3f} | {np.mean(op != ow):.3f} | "
+ "/".join(f"{x:.4f}" for x in pp) + " | " + "/".join(f"{x:.4f}" for x in pw) + " |")
print("\n## B. Minds within-bloc correlation (equal weights, q=0.5)")
print("| Minds ICC | Kish n_eff of 8 | P(differ) | Minds |share-0.5| mean | Minds pivot prop | Minds pivot WTA | P(Minds tie) |")
print("|---|---|---|---|---|---|---|")
for r in (0.0, 0.2, 0.44, 0.8, 1.0):
sizes, p, F, first = draw(minds_r=r, T=100_000); ws = WEIGHTS["equal"]
op, ow = out_prop(ws, sizes, F, .5), out_wta(ws, sizes, F, .5)
pp = np.mean(op != out_prop(ws, sizes, flip(F, first, 0), .5)); pw = np.mean(ow != out_wta(ws, sizes, flip(F, first, 0), .5))
print(f"| {r} | {8 / (1 + 7 * r):.2f} | {np.mean(op != ow):.3f} | {np.mean(abs(F[:, 0] / 8 - .5)):.3f} | {pp:.4f} | {pw:.4f} | {np.mean(2 * F[:, 0] == 8):.3f} |")
print("\n## C. Users turnout (equal weights, q=0.5, Users roll 300)")
print("| turnout | Users voters | P(Users WTA cast != population majority) | mean |prop share - p_U| | P(motion != full-turnout result) prop | same, WTA |")
print("|---|---|---|---|---|---|")
for t in (0.01, 0.03, 0.1, 0.3):
sizes, p, F, first = draw(turnout=t, T=100_000); ws = WEIGHTS["equal"]
st = np.sign(2 * F[:, 2] - sizes[2]); pop = np.sign(p[:, 2] - .5)
Ffull = F.astype(float).copy(); Ffull[:, 2] = p[:, 2] * sizes[2]
sfull = sizes.copy()
opf = out_prop(ws, sfull, Ffull, .5)
stf = np.sign(2 * F - sizes).astype(float); stf[:, 2] = pop
wsA = np.array(ws, float); owf = ((stf == 1) @ wsA) >= .5 * (((stf == 1) | (stf == -1)) @ wsA)
print(f"| {t} | {sizes[2]} | {np.mean(st != pop):.3f} | {np.mean(abs(F[:, 2] / sizes[2] - p[:, 2])):.3f} | "
f"{np.mean(out_prop(ws, sizes, F, .5) != opf):.3f} | {np.mean(out_wta(ws, sizes, F, .5) != owf):.3f} |")
print("\n## D. Coordinated Users faction of k voters, Users population support p_U=0.3, turnout 3% (9 random voters + k)")
print("| k | P(Users bloc cast For) WTA | mean Users For share prop |")
print("|---|---|---|")
for k in (0, 3, 6, 9, 12):
rnd = rng.random((100_000, 9)) < 0.3; f = rnd.sum(1) + k; n = 9 + k
print(f"| {k} | {np.mean(2 * f > n):.3f} | {np.mean(f / n):.3f} |")

View file

@ -0,0 +1,117 @@
## N1. Profitable deviations (count of profile x actor cases where deviating gets the actor's sincere preference)
Present case sizes Minds 8 / Members 1 (her) / Users 0 / Patrons 0; mixed case 3/1/2/1.
| sizes | weights | q | rule | quorum | profiles | indiv profitable dev | of which hers | estate stay-home profitable |
|---|---|---|---|---|---|---|---|---|
| 8/1/0/0 | (25, 25, 25, 25) | 0.5 | prop | none | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (25, 25, 25, 25) | 0.5 | prop | head | 512 | 0 | 0 | 93 |
| 8/1/0/0 | (25, 25, 25, 25) | 0.5 | prop | two | 512 | 1 | 1 | 94 |
| 8/1/0/0 | (25, 25, 25, 25) | 0.5 | wta | none | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (25, 25, 25, 25) | 0.5 | wta | head | 512 | 0 | 0 | 93 |
| 8/1/0/0 | (25, 25, 25, 25) | 0.5 | wta | two | 512 | 93 | 93 | 186 |
| 8/1/0/0 | (25, 25, 25, 25) | 0.66 | prop | none | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (25, 25, 25, 25) | 0.66 | prop | head | 512 | 0 | 0 | 56 |
| 8/1/0/0 | (25, 25, 25, 25) | 0.66 | prop | two | 512 | 0 | 0 | 56 |
| 8/1/0/0 | (25, 25, 25, 25) | 0.66 | wta | none | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (25, 25, 25, 25) | 0.66 | wta | head | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (25, 25, 25, 25) | 0.66 | wta | two | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (40, 30, 20, 10) | 0.5 | prop | none | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (40, 30, 20, 10) | 0.5 | prop | head | 512 | 0 | 0 | 92 |
| 8/1/0/0 | (40, 30, 20, 10) | 0.5 | prop | two | 512 | 9 | 9 | 101 |
| 8/1/0/0 | (40, 30, 20, 10) | 0.5 | wta | none | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (40, 30, 20, 10) | 0.5 | wta | head | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (40, 30, 20, 10) | 0.5 | wta | two | 512 | 93 | 93 | 93 |
| 8/1/0/0 | (40, 30, 20, 10) | 0.66 | prop | none | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (40, 30, 20, 10) | 0.66 | prop | head | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (40, 30, 20, 10) | 0.66 | prop | two | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (40, 30, 20, 10) | 0.66 | wta | none | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (40, 30, 20, 10) | 0.66 | wta | head | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (40, 30, 20, 10) | 0.66 | wta | two | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (20, 45, 20, 15) | 0.5 | prop | none | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (20, 45, 20, 15) | 0.5 | prop | head | 512 | 0 | 0 | 93 |
| 8/1/0/0 | (20, 45, 20, 15) | 0.5 | prop | two | 512 | 0 | 0 | 93 |
| 8/1/0/0 | (20, 45, 20, 15) | 0.5 | wta | none | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (20, 45, 20, 15) | 0.5 | wta | head | 512 | 0 | 0 | 93 |
| 8/1/0/0 | (20, 45, 20, 15) | 0.5 | wta | two | 512 | 0 | 0 | 93 |
| 8/1/0/0 | (20, 45, 20, 15) | 0.66 | prop | none | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (20, 45, 20, 15) | 0.66 | prop | head | 512 | 0 | 0 | 93 |
| 8/1/0/0 | (20, 45, 20, 15) | 0.66 | prop | two | 512 | 0 | 0 | 93 |
| 8/1/0/0 | (20, 45, 20, 15) | 0.66 | wta | none | 512 | 0 | 0 | 0 |
| 8/1/0/0 | (20, 45, 20, 15) | 0.66 | wta | head | 512 | 0 | 0 | 93 |
| 8/1/0/0 | (20, 45, 20, 15) | 0.66 | wta | two | 512 | 0 | 0 | 93 |
| 3/1/2/1 | (25, 25, 25, 25) | 0.5 | prop | none | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (25, 25, 25, 25) | 0.5 | prop | head | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (25, 25, 25, 25) | 0.5 | prop | two | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (25, 25, 25, 25) | 0.5 | wta | none | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (25, 25, 25, 25) | 0.5 | wta | head | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (25, 25, 25, 25) | 0.5 | wta | two | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (25, 25, 25, 25) | 0.66 | prop | none | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (25, 25, 25, 25) | 0.66 | prop | head | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (25, 25, 25, 25) | 0.66 | prop | two | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (25, 25, 25, 25) | 0.66 | wta | none | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (25, 25, 25, 25) | 0.66 | wta | head | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (25, 25, 25, 25) | 0.66 | wta | two | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (40, 30, 20, 10) | 0.5 | prop | none | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (40, 30, 20, 10) | 0.5 | prop | head | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (40, 30, 20, 10) | 0.5 | prop | two | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (40, 30, 20, 10) | 0.5 | wta | none | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (40, 30, 20, 10) | 0.5 | wta | head | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (40, 30, 20, 10) | 0.5 | wta | two | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (40, 30, 20, 10) | 0.66 | prop | none | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (40, 30, 20, 10) | 0.66 | prop | head | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (40, 30, 20, 10) | 0.66 | prop | two | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (40, 30, 20, 10) | 0.66 | wta | none | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (40, 30, 20, 10) | 0.66 | wta | head | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (40, 30, 20, 10) | 0.66 | wta | two | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (20, 45, 20, 15) | 0.5 | prop | none | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (20, 45, 20, 15) | 0.5 | prop | head | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (20, 45, 20, 15) | 0.5 | prop | two | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (20, 45, 20, 15) | 0.5 | wta | none | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (20, 45, 20, 15) | 0.5 | wta | head | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (20, 45, 20, 15) | 0.5 | wta | two | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (20, 45, 20, 15) | 0.66 | prop | none | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (20, 45, 20, 15) | 0.66 | prop | head | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (20, 45, 20, 15) | 0.66 | prop | two | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (20, 45, 20, 15) | 0.66 | wta | none | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (20, 45, 20, 15) | 0.66 | wta | head | 128 | 0 | 0 | 0 |
| 3/1/2/1 | (20, 45, 20, 15) | 0.66 | wta | two | 128 | 0 | 0 | 0 |
## N2. Present case outcome map (Minds 8 independent fair coins, her vote fixed), renormalized
P(pass | she votes For) / P(pass | she votes Against) / P(pass | she stays home)
| weights | q | rule | quorum | For | Against | home |
|---|---|---|---|---|---|---|
| (25, 25) | 0.15 | prop | none | 1.000 | 0.855 | 0.965 |
| (25, 25) | 0.15 | prop | two | 1.000 | 0.855 | 0.000 |
| (25, 25) | 0.15 | wta | none | 1.000 | 0.363 | 0.363 |
| (25, 25) | 0.15 | wta | two | 1.000 | 0.363 | 0.000 |
| (25, 25) | 0.5 | prop | none | 1.000 | 0.004 | 0.637 |
| (25, 25) | 0.5 | prop | two | 1.000 | 0.004 | 0.000 |
| (25, 25) | 0.5 | wta | none | 1.000 | 0.363 | 0.363 |
| (25, 25) | 0.5 | wta | two | 1.000 | 0.363 | 0.000 |
| (25, 25) | 0.66 | prop | none | 0.855 | 0.000 | 0.145 |
| (25, 25) | 0.66 | prop | two | 0.855 | 0.000 | 0.000 |
| (25, 25) | 0.66 | wta | none | 0.637 | 0.000 | 0.363 |
| (25, 25) | 0.66 | wta | two | 0.637 | 0.000 | 0.000 |
| (40, 30) | 0.15 | prop | none | 1.000 | 0.855 | 0.965 |
| (40, 30) | 0.15 | prop | two | 1.000 | 0.855 | 0.000 |
| (40, 30) | 0.15 | wta | none | 1.000 | 0.363 | 0.363 |
| (40, 30) | 0.15 | wta | two | 1.000 | 0.363 | 0.000 |
| (40, 30) | 0.5 | prop | none | 0.996 | 0.035 | 0.637 |
| (40, 30) | 0.5 | prop | two | 0.996 | 0.035 | 0.000 |
| (40, 30) | 0.5 | wta | none | 0.637 | 0.363 | 0.363 |
| (40, 30) | 0.5 | wta | two | 0.637 | 0.363 | 0.000 |
| (40, 30) | 0.66 | prop | none | 0.637 | 0.000 | 0.145 |
| (40, 30) | 0.66 | prop | two | 0.637 | 0.000 | 0.000 |
| (40, 30) | 0.66 | wta | none | 0.637 | 0.000 | 0.363 |
| (40, 30) | 0.66 | wta | two | 0.637 | 0.000 | 0.000 |
| (20, 45) | 0.15 | prop | none | 1.000 | 0.637 | 0.965 |
| (20, 45) | 0.15 | prop | two | 1.000 | 0.637 | 0.000 |
| (20, 45) | 0.15 | wta | none | 1.000 | 0.363 | 0.363 |
| (20, 45) | 0.15 | wta | two | 1.000 | 0.363 | 0.000 |
| (20, 45) | 0.5 | prop | none | 1.000 | 0.000 | 0.637 |
| (20, 45) | 0.5 | prop | two | 1.000 | 0.000 | 0.000 |
| (20, 45) | 0.5 | wta | none | 1.000 | 0.000 | 0.363 |
| (20, 45) | 0.5 | wta | two | 1.000 | 0.000 | 0.000 |
| (20, 45) | 0.66 | prop | none | 1.000 | 0.000 | 0.145 |
| (20, 45) | 0.66 | prop | two | 1.000 | 0.000 | 0.000 |
| (20, 45) | 0.66 | wta | none | 1.000 | 0.000 | 0.363 |
| (20, 45) | 0.66 | wta | two | 1.000 | 0.000 | 0.000 |

View file

@ -0,0 +1,70 @@
"""No-show incentives under the renormalization ruling (operator 2026-10-29: "normalize it by who actually voted").
Estate weights renormalize over estates where at least one For/Against ballot was cast; WTA tie casts nothing.
A motion failing its quorum fails (status quo). Exhaustive over sincere For/Against profiles.
Deviations: one voter switches or abstains; or a whole estate stays home (estate as unitary actor).
Quorum floors: none | head = cast ballots >= half of eligible individuals | two = at least two estates voting.
Run: python -I noshow.py
"""
import itertools
def tally(ws, sizes, ballots, q, rule, quorum):
F = [0] * 4; A = [0] * 4; idx = 0
for b, n in enumerate(sizes):
for v in ballots[idx:idx + n]:
F[b] += v == 1; A[b] += v == -1
idx += n
live = [b for b in range(4) if F[b] + A[b] > 0]
if quorum == "head" and sum(F) + sum(A) < sum(sizes) / 2: return False
if quorum == "two" and len(live) < 2: return False
f = a = 0.0
for b in live:
if rule == "prop": f += ws[b] * F[b] / (F[b] + A[b]); a += ws[b] * A[b] / (F[b] + A[b])
elif F[b] > A[b]: f += ws[b]
elif A[b] > F[b]: a += ws[b]
return f + a > 0 and f >= q * (f + a) - 1e-9
def probe(ws, sizes, q, rule, quorum):
N = sum(sizes); starts = [sum(sizes[:b]) for b in range(4)]
ind = est = her = 0; prof = 0
for bal in itertools.product((1, -1), repeat=N):
prof += 1; o = tally(ws, sizes, bal, q, rule, quorum)
for i, v in enumerate(bal):
want = v == 1
if o != want and any(tally(ws, sizes, bal[:i] + (d,) + bal[i + 1:], q, rule, quorum) == want for d in (-v, 0)):
ind += 1
if sizes[1] == 1 and i == starts[1]: her += 1
for b in range(4):
if sizes[b] == 0: continue
seg = bal[starts[b]:starts[b] + sizes[b]]; pos = sum(seg) > 0 if 2 * sum(x == 1 for x in seg) != len(seg) else None
if pos is None or o == pos: continue
home = bal[:starts[b]] + (0,) * sizes[b] + bal[starts[b] + sizes[b]:]
est += tally(ws, sizes, home, q, rule, quorum) == pos
return prof, ind, her, est
if __name__ == "__main__":
print("## N1. Profitable deviations (count of profile x actor cases where deviating gets the actor's sincere preference)")
print("Present case sizes Minds 8 / Members 1 (her) / Users 0 / Patrons 0; mixed case 3/1/2/1.")
print("| sizes | weights | q | rule | quorum | profiles | indiv profitable dev | of which hers | estate stay-home profitable |")
print("|---|---|---|---|---|---|---|---|---|")
for sizes in ((8, 1, 0, 0), (3, 1, 2, 1)):
for ws in ((25, 25, 25, 25), (40, 30, 20, 10), (20, 45, 20, 15)):
for q in (0.5, 0.66):
for rule in ("prop", "wta"):
for quorum in ("none", "head", "two"):
p, i, h, e = probe(ws, sizes, q, rule, quorum)
print(f"| {'/'.join(map(str, sizes))} | {ws} | {q} | {rule} | {quorum} | {p} | {i} | {h} | {e} |")
print("\n## N2. Present case outcome map (Minds 8 independent fair coins, her vote fixed), renormalized")
print("P(pass | she votes For) / P(pass | she votes Against) / P(pass | she stays home)")
print("| weights | q | rule | quorum | For | Against | home |")
print("|---|---|---|---|---|---|---|")
from math import comb
for ws in ((25, 25, 25, 25), (40, 30, 20, 10), (20, 45, 20, 15)):
for q in (0.15, 0.5, 0.66):
for rule in ("prop", "wta"):
for quorum in ("none", "two"):
row = []
for hv in (1, -1, 0):
pp = sum(comb(8, k) / 256 * tally(ws, (8, 1, 0, 0), (1,) * k + (-1,) * (8 - k) + (hv,), q, rule, quorum) for k in range(9))
row.append(f"{pp:.3f}")
print(f"| {ws[:2]} | {q} | {rule} | {quorum} | " + " | ".join(row) + " |")

View file

@ -0,0 +1,41 @@
## Unitary blocs: normalized Banzhaf / Shapley-Shubik, veto blocs
| weights | q | Banzhaf M/Me/U/P | Shapley M/Me/U/P | veto blocs |
|---|---|---|---|---|
| equal [25, 25, 25, 25] | 0.15 | 0.25/0.25/0.25/0.25 | 0.25/0.25/0.25/0.25 | none |
| equal [25, 25, 25, 25] | 0.5 | 0.25/0.25/0.25/0.25 | 0.25/0.25/0.25/0.25 | none |
| equal [25, 25, 25, 25] | 0.66 | 0.25/0.25/0.25/0.25 | 0.25/0.25/0.25/0.25 | none |
| minds-heavy [40, 30, 20, 10] | 0.15 | 0.33/0.33/0.33/0.00 | 0.33/0.33/0.33/0.00 | none |
| minds-heavy [40, 30, 20, 10] | 0.5 | 0.42/0.25/0.25/0.08 | 0.42/0.25/0.25/0.08 | none |
| minds-heavy [40, 30, 20, 10] | 0.66 | 0.50/0.30/0.10/0.10 | 0.58/0.25/0.08/0.08 | Minds |
| members-heavy [20, 45, 20, 15] | 0.15 | 0.25/0.25/0.25/0.25 | 0.25/0.25/0.25/0.25 | none |
| members-heavy [20, 45, 20, 15] | 0.5 | 0.17/0.50/0.17/0.17 | 0.17/0.50/0.17/0.17 | none |
| members-heavy [20, 45, 20, 15] | 0.66 | 0.20/0.40/0.20/0.20 | 0.17/0.50/0.17/0.17 | Members |
## Individual power (P one voter flips the motion), sizes {'Minds': 8, 'Members': 15, 'Users': 30, 'Patrons': 4}
| weights | q | rule | Minds | Members | Users | Patrons | max/min |
|---|---|---|---|---|---|---|---|
| equal | 0.15 | WTA | 0.0538 | 0.0525 | 0.0316 | 0.0683 | 2.2 |
| equal | 0.15 | prop | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 2.7 |
| equal | 0.5 | WTA | 0.1184 | 0.0961 | 0.0640 | 0.1584 | 2.5 |
| equal | 0.5 | prop | 0.1426 | 0.0770 | 0.0384 | 0.2956 | 7.7 |
| equal | 0.66 | WTA | 0.1184 | 0.0961 | 0.0640 | 0.1584 | 2.5 |
| equal | 0.66 | prop | 0.0262 | 0.0145 | 0.0073 | 0.0474 | 6.5 |
| minds-heavy | 0.15 | WTA | 0.0782 | 0.0661 | 0.0398 | 0.0293 | 2.7 |
| minds-heavy | 0.15 | prop | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 3.9 |
| minds-heavy | 0.5 | WTA | 0.1686 | 0.1080 | 0.0505 | 0.0609 | 3.3 |
| minds-heavy | 0.5 | prop | 0.2343 | 0.0909 | 0.0302 | 0.1146 | 7.8 |
| minds-heavy | 0.66 | WTA | 0.1769 | 0.0942 | 0.0316 | 0.0511 | 5.6 |
| minds-heavy | 0.66 | prop | 0.0407 | 0.0172 | 0.0058 | 0.0215 | 7.0 |
| members-heavy | 0.15 | WTA | 0.0538 | 0.0525 | 0.0316 | 0.0683 | 2.2 |
| members-heavy | 0.15 | prop | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 3.7 |
| members-heavy | 0.5 | WTA | 0.0366 | 0.1891 | 0.0164 | 0.0583 | 11.5 |
| members-heavy | 0.5 | prop | 0.1246 | 0.1509 | 0.0327 | 0.1888 | 5.8 |
| members-heavy | 0.66 | WTA | 0.0647 | 0.1455 | 0.0324 | 0.0900 | 4.5 |
| members-heavy | 0.66 | prop | 0.0167 | 0.0200 | 0.0045 | 0.0243 | 5.4 |
## Penrose square-root weights (WTA individual-power equalizer, independent voters)
sqrt(n) shares: [19.9, 27.3, 38.6, 14.1]
with Minds n_eff=8/(1+7*0.44)=1.96: [11.0, 30.4, 43.0, 15.7]
headcount shares (prop equalizer): [14.0, 26.3, 52.6, 7.0]
sqrt weights q=0.5: WTA indiv [0.0928, 0.0835, 0.096, 0.1218] prop indiv [0.1414, 0.1027, 0.0722, 0.2034]
headcount weights q=0.5: WTA indiv [0.0, 0.0303, 0.1445, 0.0] prop indiv [0.1061, 0.1061, 0.1061, 0.1061]

View file

@ -0,0 +1,110 @@
"""A priori power of estate blocs and of individuals inside them.
Pass rule (Bifrost MotionGovernanceService): For / (For + Against) >= q, abstain excluded.
Blocs: Minds, Members, Users, Patrons. Run: python -I power.py
"""
import itertools, math
from math import comb
BLOCS = ["Minds", "Members", "Users", "Patrons"]
WEIGHTS = {"equal": [25, 25, 25, 25], "minds-heavy": [40, 30, 20, 10], "members-heavy": [20, 45, 20, 15]}
QS = [0.15, 0.5, 0.66]
SIZES = [8, 15, 30, 4] # voting individuals (Users = active turnout, not roll)
def wins(ws, S, q):
return sum(ws[i] for i in S) >= q * sum(ws) - 1e-12
def banzhaf(ws, q):
n = len(ws); sw = [0] * n
for i in range(n):
others = [j for j in range(n) if j != i]
for r in range(len(others) + 1):
for S in itertools.combinations(others, r):
if not wins(ws, S, q) and wins(ws, S + (i,), q):
sw[i] += 1
t = sum(sw); return [s / t for s in sw], sw
def shapley(ws, q):
n = len(ws); piv = [0] * n
for perm in itertools.permutations(range(n)):
acc = 0
for i in perm:
acc += ws[i]
if acc >= q * sum(ws) - 1e-12:
piv[i] += 1; break
t = sum(piv); return [p / t for p in piv]
def veto(ws, q):
W = sum(ws); return [BLOCS[i] for i in range(len(ws)) if W - ws[i] < q * W - 1e-12]
def binom(n): # P(k For among n coin-flip voters)
return [comb(n, k) / 2 ** n for k in range(n + 1)]
def wta_state(k, n): # +1 For, -1 Against, 0 tie casts nothing
return 1 if 2 * k > n else (-1 if 2 * k < n else 0)
def outcome_wta(ws, states, q):
f = sum(w for w, s in zip(ws, states) if s == 1); a = sum(w for w, s in zip(ws, states) if s == -1)
return f + a > 0 and f / (f + a) >= q - 1e-12
def bloc_state_dist(n):
d = {1: 0.0, -1: 0.0, 0: 0.0}
for k, p in enumerate(binom(n)): d[wta_state(k, n)] += p
return d
def indiv_power_wta(ws, q, sizes, b):
"""P(one voter in bloc b changes the motion outcome), others independent fair coins."""
others = [j for j in range(len(ws)) if j != b]
dists = [bloc_state_dist(sizes[j]) for j in others]
tot = 0.0
for k, pk in enumerate(binom(sizes[b] - 1)):
sF, sA = wta_state(k + 1, sizes[b]), wta_state(k, sizes[b])
if sF == sA: continue
for combo in itertools.product([1, -1, 0], repeat=len(others)):
p = pk
for d, s in zip(dists, combo): p *= d[s]
if p == 0: continue
st = [0] * len(ws)
for j, s in zip(others, combo): st[j] = s
stF = st[:]; stF[b] = sF; stA = st[:]; stA[b] = sA
if outcome_wta(ws, stF, q) != outcome_wta(ws, stA, q): tot += p
return tot
def indiv_power_prop(ws, q, sizes, b):
others = [j for j in range(len(ws)) if j != b]
W = sum(ws); tot = 0.0
dists = [binom(sizes[j]) for j in others]
for ks in itertools.product(*[range(sizes[j] + 1) for j in others]):
p = 1.0; base = 0.0
for j, k, d in zip(others, ks, dists): p *= d[k]; base += ws[j] * k / sizes[j]
for k, pk in enumerate(binom(sizes[b] - 1)):
vF = base + ws[b] * (k + 1) / sizes[b]; vA = base + ws[b] * k / sizes[b]
if (vF >= q * W - 1e-12) != (vA >= q * W - 1e-12): tot += p * pk
return tot
if __name__ == "__main__":
print("## Unitary blocs: normalized Banzhaf / Shapley-Shubik, veto blocs")
print("| weights | q | Banzhaf M/Me/U/P | Shapley M/Me/U/P | veto blocs |")
print("|---|---|---|---|---|")
for name, ws in WEIGHTS.items():
for q in QS:
bz, _ = banzhaf(ws, q); ss = shapley(ws, q)
f = lambda v: "/".join(f"{x:.2f}" for x in v)
print(f"| {name} {ws} | {q} | {f(bz)} | {f(ss)} | {', '.join(veto(ws, q)) or 'none'} |")
print("\n## Individual power (P one voter flips the motion), sizes", dict(zip(BLOCS, SIZES)))
print("| weights | q | rule | Minds | Members | Users | Patrons | max/min |")
print("|---|---|---|---|---|---|---|---|")
for name, ws in WEIGHTS.items():
for q in QS:
for rule, fn in (("WTA", indiv_power_wta), ("prop", indiv_power_prop)):
v = [fn(ws, q, SIZES, b) for b in range(4)]
r = max(v) / min(v) if min(v) > 0 else float("inf")
print(f"| {name} | {q} | {rule} | " + " | ".join(f"{x:.4f}" for x in v) + f" | {r:.1f} |")
print("\n## Penrose square-root weights (WTA individual-power equalizer, independent voters)")
sq = [math.sqrt(n) for n in SIZES]; print("sqrt(n) shares:", [round(100 * s / sum(sq), 1) for s in sq])
neff = [8 / (1 + 7 * 0.44)] + SIZES[1:]
sq2 = [math.sqrt(n) for n in neff]; print("with Minds n_eff=8/(1+7*0.44)=%.2f:" % neff[0], [round(100 * s / sum(sq2), 1) for s in sq2])
pr = [100 * n / sum(SIZES) for n in SIZES]; print("headcount shares (prop equalizer):", [round(x, 1) for x in pr])
for ws, lab in ((sq, "sqrt"), (SIZES, "headcount")):
for q in (0.5,):
v = [indiv_power_wta(ws, q, SIZES, b) for b in range(4)]; u = [indiv_power_prop(ws, q, SIZES, b) for b in range(4)]
print(f"{lab} weights q={q}: WTA indiv", [round(x, 4) for x in v], " prop indiv", [round(x, 4) for x in u])

View file

@ -0,0 +1,43 @@
## S1. Profitable misreport/abstention on a single binary motion (sizes 3/3/2/2, exhaustive)
| weights | q | quorum | rule | profiles x voters | profitable deviations | of which abstention |
|---|---|---|---|---|---|---|
| [25, 25, 25, 25] | 0.15 | 0.0 | prop | 10240 | 0 | 0 |
| [25, 25, 25, 25] | 0.15 | 0.0 | wta | 10240 | 0 | 0 |
| [25, 25, 25, 25] | 0.15 | 0.5 | prop | 10240 | 0 | 0 |
| [25, 25, 25, 25] | 0.15 | 0.5 | wta | 10240 | 192 | 192 |
| [25, 25, 25, 25] | 0.5 | 0.0 | prop | 10240 | 0 | 0 |
| [25, 25, 25, 25] | 0.5 | 0.0 | wta | 10240 | 0 | 0 |
| [25, 25, 25, 25] | 0.5 | 0.5 | prop | 10240 | 0 | 0 |
| [25, 25, 25, 25] | 0.5 | 0.5 | wta | 10240 | 192 | 192 |
| [25, 25, 25, 25] | 0.66 | 0.0 | prop | 10240 | 0 | 0 |
| [25, 25, 25, 25] | 0.66 | 0.0 | wta | 10240 | 0 | 0 |
| [25, 25, 25, 25] | 0.66 | 0.5 | prop | 10240 | 0 | 0 |
| [25, 25, 25, 25] | 0.66 | 0.5 | wta | 10240 | 0 | 0 |
| [40, 30, 20, 10] | 0.15 | 0.0 | prop | 10240 | 0 | 0 |
| [40, 30, 20, 10] | 0.15 | 0.0 | wta | 10240 | 0 | 0 |
| [40, 30, 20, 10] | 0.15 | 0.5 | prop | 10240 | 0 | 0 |
| [40, 30, 20, 10] | 0.15 | 0.5 | wta | 10240 | 288 | 288 |
| [40, 30, 20, 10] | 0.5 | 0.0 | prop | 10240 | 0 | 0 |
| [40, 30, 20, 10] | 0.5 | 0.0 | wta | 10240 | 0 | 0 |
| [40, 30, 20, 10] | 0.5 | 0.5 | prop | 10240 | 0 | 0 |
| [40, 30, 20, 10] | 0.5 | 0.5 | wta | 10240 | 144 | 144 |
| [40, 30, 20, 10] | 0.66 | 0.0 | prop | 10240 | 0 | 0 |
| [40, 30, 20, 10] | 0.66 | 0.0 | wta | 10240 | 0 | 0 |
| [40, 30, 20, 10] | 0.66 | 0.5 | prop | 10240 | 0 | 0 |
| [40, 30, 20, 10] | 0.66 | 0.5 | wta | 10240 | 0 | 0 |
## S2. Logrolling (greedy best mutually profitable pairwise trade, repeated, max 6 trades)
### weights [25, 25, 25, 25], q=0.5, 6 motions, 1500 agendas; bloc utility u[b,m]~N(0,1) per motion passed
| bloc type | delta | P(>=1 trade) | mean trades | mean welfare change (sum u) | P(welfare falls) | P(a non-trader loses) | P(a trader ends worse than sincere) |
|---|---|---|---|---|---|---|---|
| unitary | 1.0 | 0.615 | 1.04 | +0.168 | 0.245 | 0.397 | 0.234 |
| proportional | 0.5 | 0.430 | 0.66 | -0.396 | 0.338 | 0.305 | 0.127 |
| proportional | 0.2 | 0.127 | 0.17 | -0.027 | 0.071 | 0.093 | 0.017 |
### weights [40, 30, 20, 10], q=0.5, 6 motions, 1500 agendas; bloc utility u[b,m]~N(0,1) per motion passed
| bloc type | delta | P(>=1 trade) | mean trades | mean welfare change (sum u) | P(welfare falls) | P(a non-trader loses) | P(a trader ends worse than sincere) |
|---|---|---|---|---|---|---|---|
| unitary | 1.0 | 0.615 | 0.90 | +0.016 | 0.302 | 0.484 | 0.184 |
| proportional | 0.5 | 0.324 | 0.44 | -0.306 | 0.230 | 0.261 | 0.076 |
| proportional | 0.2 | 0.110 | 0.13 | -0.075 | 0.070 | 0.099 | 0.013 |

View file

@ -0,0 +1,86 @@
"""Strategic probes. Run: python -I strat.py
S1 exhaustive: can any voter gain by misreporting or abstaining on one binary motion? (with and without a quorum)
S2 logrolling among 4 blocs over a 6-motion agenda: unitary blocs (whole weight deliverable) vs
proportional blocs whose leadership can move only a fraction delta of the bloc's share.
"""
import itertools
import numpy as np
def tally(ws, blocs, ballots, q, rule, quorum=0.0):
"""ballots: tuple of +1 For, -1 Against, 0 abstain, one per voter; blocs: bloc index per voter."""
F = [0] * len(ws); A = [0] * len(ws)
for b, v in zip(blocs, ballots):
if v == 1: F[b] += 1
elif v == -1: A[b] += 1
f = a = 0.0
for b, w in enumerate(ws):
if F[b] + A[b] == 0: continue
if rule == "prop": f += w * F[b] / (F[b] + A[b]); a += w * A[b] / (F[b] + A[b])
elif F[b] > A[b]: f += w
elif A[b] > F[b]: a += w
if f + a < quorum * sum(ws) - 1e-9 or f + a == 0: return False
return f >= q * (f + a) - 1e-9
def s1():
blocs = [0, 0, 0, 1, 1, 1, 2, 2, 3, 3]
print("| weights | q | quorum | rule | profiles x voters | profitable deviations | of which abstention |")
print("|---|---|---|---|---|---|---|")
for ws in ([25, 25, 25, 25], [40, 30, 20, 10]):
for q in (0.15, 0.5, 0.66):
for quorum in (0.0, 0.5):
for rule in ("prop", "wta"):
cache = {}
def out(bal):
if bal not in cache: cache[bal] = tally(ws, blocs, bal, q, rule, quorum)
return cache[bal]
gain = gab = n = 0
for bal in itertools.product((1, -1), repeat=10): # sincere profiles, no sincere abstainers
o = out(bal)
for i, v in enumerate(bal):
n += 1; want = v == 1
if o == want: continue
for d in (-v, 0):
b2 = bal[:i] + (d,) + bal[i + 1:]
if out(b2) == want: gain += 1; gab += d == 0; break
print(f"| {ws} | {q} | {quorum} | {rule} | {n} | {gain} | {gab} |")
def s2(ws=(25, 25, 25, 25), q=0.5, M=6, T=1_500, seed=3):
rng = np.random.default_rng(seed); W = np.array(ws, float)
print(f"\n### weights {list(ws)}, q={q}, {M} motions, {T} agendas; bloc utility u[b,m]~N(0,1) per motion passed")
print("| bloc type | delta | P(>=1 trade) | mean trades | mean welfare change (sum u) | P(welfare falls) | P(a non-trader loses) | P(a trader ends worse than sincere) |")
print("|---|---|---|---|---|---|---|---|")
for kind, delta in (("unitary", 1.0), ("proportional", 0.5), ("proportional", 0.2)):
stats = np.zeros(6)
for t in range(T):
u = rng.standard_normal((4, M))
share0 = 1 / (1 + np.exp(-2 * u)) if kind == "proportional" else (u > 0).astype(float)
dev = np.zeros((4, M)) # signed share shift each bloc has committed to
def outcome(dv):
s = np.clip(share0 + dv, 0, 1); return (W @ s) >= q * W.sum() - 1e-9
def util(o): return u @ o
o_s = outcome(dev); U_s = util(o_s); cur = U_s.copy(); trades = 0; traders = set()
while True:
best = None
for A, B in itertools.permutations(range(4), 2):
if A > B: continue
for x in range(M):
if dev[A, x] != 0: continue
for y in range(M):
if y == x or dev[B, y] != 0: continue
d2 = dev.copy(); d2[A, x] = -np.sign(u[A, x]) * delta; d2[B, y] = -np.sign(u[B, y]) * delta
Un = util(outcome(d2)); g = Un - cur
if g[A] > 1e-9 and g[B] > 1e-9 and (best is None or g[A] + g[B] > best[0]):
best = (g[A] + g[B], d2, Un, A, B)
if best is None or trades >= 6: break
_, dev, cur, A, B = best; trades += 1; traders |= {A, B}
dW = cur.sum() - U_s.sum(); non = [b for b in range(4) if b not in traders]
stats += [trades > 0, trades, dW, dW < -1e-9, any(cur[b] < U_s[b] - 1e-9 for b in non),
any(cur[b] < U_s[b] - 1e-9 for b in traders)]
s = stats / T
print(f"| {kind} | {delta} | {s[0]:.3f} | {s[1]:.2f} | {s[2]:+.3f} | {s[3]:.3f} | {s[4]:.3f} | {s[5]:.3f} |")
if __name__ == "__main__":
print("## S1. Profitable misreport/abstention on a single binary motion (sizes 3/3/2/2, exhaustive)")
s1()
print("\n## S2. Logrolling (greedy best mutually profitable pairwise trade, repeated, max 6 trades)")
s2(); s2(ws=(40, 30, 20, 10))

View file

@ -0,0 +1,76 @@
## W1. Effective voters (Kish = inverse Herfindahl) and top share
| bloc | curve | operator S | Kish n_eff | top voter share | internal Banzhaf of top (WTA bloc) |
|---|---|---|---|---|---|
| Members (15) | one-each | 0.5 | 15.00 | 0.067 | 0.209 |
| Members (15) | k=1 | 0.5 | 3.55 | 0.500 | 1.000 |
| Members (15) | k=2 | 0.5 | 10.13 | 0.222 | 0.672 |
| Members (15) | k=3 | 0.5 | 12.85 | 0.154 | 0.481 |
| Members (15) | k=5 | 0.5 | 14.30 | 0.112 | 0.333 |
| Members (15) | one-each | 0.8 | 15.00 | 0.067 | 0.209 |
| Members (15) | k=1 | 0.8 | 1.55 | 0.800 | 1.000 |
| Members (15) | k=2 | 0.8 | 6.05 | 0.364 | 0.958 |
| Members (15) | k=3 | 0.8 | 10.44 | 0.225 | 0.700 |
| Members (15) | k=5 | 0.8 | 13.54 | 0.143 | 0.470 |
| Patrons (4) | one-each | - | 4.00 | 0.250 | 0.750 |
| Patrons (4) | k=1 | - | 1.10 | 0.951 | 1.000 |
| Patrons (4) | log(1+d) | - | 3.33 | 0.423 | 0.750 |
| Patrons (4) | k=3 | - | 2.40 | 0.594 | 1.000 |
| Patrons (4) | k=5 | - | 3.22 | 0.452 | 0.750 |
| Patrons (4) | k=10 | - | 3.78 | 0.346 | 0.750 |
## W2. Operator's power over the whole tally (two-tier Banzhaf, all voters fair coins, 200k draws)
Comparators: a one-each Member; a Mind (8); a User (30); top Patron under log(1+d).
| bloc weights | q | Members curve | S | op pivot prop | op pivot WTA | one-each Member prop/WTA | Mind prop/WTA | User prop/WTA |
|---|---|---|---|---|---|---|---|---|
| equal | 0.5 | one-each (baseline) | - | 0.0688 | 0.0887 | - | 0.1335/0.1066 | 0.0341/0.0588 |
| equal | 0.5 | k=1 | 0.5 | 0.5037 | 0.4220 | - | 0.1117/0.1067 | 0.0294/0.0591 |
| equal | 0.5 | k=2 | 0.5 | 0.2321 | 0.2855 | - | 0.1286/0.1064 | 0.0338/0.0588 |
| equal | 0.5 | k=3 | 0.5 | 0.1611 | 0.2046 | - | 0.1301/0.1066 | 0.0348/0.0586 |
| equal | 0.5 | k=5 | 0.5 | 0.1175 | 0.1412 | - | 0.1312/0.1065 | 0.0345/0.0588 |
| equal | 0.5 | k=1 | 0.8 | 0.7458 | 0.4220 | - | 0.0791/0.1067 | 0.0217/0.0591 |
| equal | 0.5 | k=2 | 0.8 | 0.3764 | 0.4044 | - | 0.1214/0.1067 | 0.0323/0.0591 |
| equal | 0.5 | k=3 | 0.8 | 0.2353 | 0.2966 | - | 0.1288/0.1064 | 0.0343/0.0588 |
| equal | 0.5 | k=5 | 0.8 | 0.1492 | 0.1998 | - | 0.1309/0.1065 | 0.0349/0.0587 |
| equal | 0.66 | one-each (baseline) | - | 0.0167 | 0.0885 | - | 0.0305/0.1084 | 0.0083/0.0595 |
| equal | 0.66 | k=1 | 0.5 | 0.1367 | 0.4227 | - | 0.0425/0.1083 | 0.0118/0.0591 |
| equal | 0.66 | k=2 | 0.5 | 0.0563 | 0.2849 | - | 0.0325/0.1087 | 0.0089/0.0590 |
| equal | 0.66 | k=3 | 0.5 | 0.0391 | 0.2041 | - | 0.0315/0.1089 | 0.0086/0.0596 |
| equal | 0.66 | k=5 | 0.5 | 0.0281 | 0.1402 | - | 0.0310/0.1087 | 0.0081/0.0598 |
| equal | 0.66 | k=1 | 0.8 | 0.2524 | 0.4227 | - | 0.0573/0.1083 | 0.0150/0.0591 |
| equal | 0.66 | k=2 | 0.8 | 0.0940 | 0.4051 | - | 0.0368/0.1083 | 0.0101/0.0592 |
| equal | 0.66 | k=3 | 0.8 | 0.0566 | 0.2959 | - | 0.0324/0.1088 | 0.0090/0.0591 |
| equal | 0.66 | k=5 | 0.8 | 0.0358 | 0.1994 | - | 0.0313/0.1088 | 0.0083/0.0597 |
| members-heavy | 0.5 | one-each (baseline) | - | 0.1462 | 0.1769 | - | 0.1208/0.0588 | 0.0317/0.0256 |
| members-heavy | 0.5 | k=1 | 0.5 | 0.8932 | 0.8447 | - | 0.0399/0.0585 | 0.0108/0.0257 |
| members-heavy | 0.5 | k=2 | 0.5 | 0.4826 | 0.5700 | - | 0.1052/0.0585 | 0.0276/0.0256 |
| members-heavy | 0.5 | k=3 | 0.5 | 0.3413 | 0.4083 | - | 0.1153/0.0587 | 0.0314/0.0257 |
| members-heavy | 0.5 | k=5 | 0.5 | 0.2489 | 0.2814 | - | 0.1196/0.0586 | 0.0312/0.0257 |
| members-heavy | 0.5 | k=1 | 0.8 | 0.9990 | 0.8447 | - | 0.0009/0.0584 | 0.0003/0.0256 |
| members-heavy | 0.5 | k=2 | 0.8 | 0.7504 | 0.8096 | - | 0.0734/0.0583 | 0.0198/0.0257 |
| members-heavy | 0.5 | k=3 | 0.8 | 0.4956 | 0.5928 | - | 0.1058/0.0584 | 0.0284/0.0257 |
| members-heavy | 0.5 | k=5 | 0.8 | 0.3181 | 0.3986 | - | 0.1178/0.0586 | 0.0312/0.0256 |
| members-heavy | 0.66 | one-each (baseline) | - | 0.0218 | 0.1263 | - | 0.0176/0.0688 | 0.0047/0.0366 |
| members-heavy | 0.66 | k=1 | 0.5 | 0.2538 | 0.6046 | - | 0.0570/0.0688 | 0.0151/0.0364 |
| members-heavy | 0.66 | k=2 | 0.5 | 0.0727 | 0.4074 | - | 0.0248/0.0691 | 0.0066/0.0365 |
| members-heavy | 0.66 | k=3 | 0.5 | 0.0487 | 0.2919 | - | 0.0198/0.0692 | 0.0056/0.0365 |
| members-heavy | 0.66 | k=5 | 0.5 | 0.0347 | 0.2011 | - | 0.0181/0.0688 | 0.0052/0.0366 |
| members-heavy | 0.66 | k=1 | 0.8 | 0.6287 | 0.6046 | - | 0.0785/0.0688 | 0.0205/0.0364 |
| members-heavy | 0.66 | k=2 | 0.8 | 0.1359 | 0.5793 | - | 0.0392/0.0688 | 0.0104/0.0364 |
| members-heavy | 0.66 | k=3 | 0.8 | 0.0708 | 0.4232 | - | 0.0243/0.0691 | 0.0065/0.0365 |
| members-heavy | 0.66 | k=5 | 0.8 | 0.0439 | 0.2851 | - | 0.0190/0.0692 | 0.0055/0.0366 |
## W3. Exponent sensitivity under the motion model (Minds ICC .44, equal bloc weights, q=0.5, S=0.5)
P(motion outcome differs) between Members curve k and k=3 baseline, Patron curve log(1+d); and Patron curve vs log(1+d) with Members k=3.
| varied | curve | P(differ) prop | P(differ) WTA | operator pivot prop | operator pivot WTA |
|---|---|---|---|---|---|
| Members | one-each | 0.014 | 0.014 | 0.0254 | 0.0217 |
| Members | k=1 | 0.051 | 0.061 | 0.2080 | 0.2962 |
| Members | k=2 | 0.010 | 0.012 | 0.0889 | 0.0856 |
| Members | k=3 | 0.000 | 0.000 | 0.0609 | 0.0545 |
| Members | k=5 | 0.007 | 0.008 | 0.0436 | 0.0361 |
| Patrons | one-each | 0.027 | 0.032 | - | - |
| Patrons | k=1 | 0.080 | 0.033 | - | - |
| Patrons | log(1+d) | 0.000 | 0.000 | - | - |
| Patrons | k=3 | 0.026 | 0.033 | - | - |
| Patrons | k=5 | 0.006 | 0.000 | - | - |
| Patrons | k=10 | 0.013 | 0.000 | - | - |

View file

@ -0,0 +1,99 @@
"""Within-bloc vote-power curves (operator addition 2026-10-29).
Members: w = contribution^(1/k). Patrons: w = log(1+d) or d^(1/k). Minds, Users: one each.
Assumptions (stated, not data): 15 Members; operator (member 0) holds share S of all contribution
(S=0.5 or 0.8); the other 14 follow a Pareto(alpha=1.16, "80/20") quantile ladder c_i = i^(-1/1.16).
4 Patrons with donations [10, 50, 200, 5000]. Run: python -I weights.py
"""
import itertools, math
import numpy as np
rng = np.random.default_rng(29)
def members(S):
tail = np.array([i ** (-1 / 1.16) for i in range(1, 15)]); tail /= tail.sum()
return np.concatenate([[S / (1 - S)], tail]) # operator / tail-sum = S/(1-S)
PATRON_D = np.array([10, 50, 200, 5000.0])
CURVES_M = {"one-each": lambda c: np.ones_like(c), "k=1": lambda c: c, "k=2": np.sqrt,
"k=3": lambda c: c ** (1 / 3), "k=5": lambda c: c ** 0.2}
CURVES_P = {"one-each": lambda d: np.ones_like(d), "k=1": lambda d: d, "log(1+d)": np.log1p,
"k=3": lambda d: d ** (1 / 3), "k=5": lambda d: d ** 0.2, "k=10": lambda d: d ** 0.1}
def kish(w): return w.sum() ** 2 / (w ** 2).sum()
def internal_banzhaf(w, i=0):
"""P(voter i decides the weighted bloc majority), others fair coins; tie casts nothing (counts as change)."""
others = np.delete(w, i); n = len(others); tot = 0
for bits in itertools.product([0, 1], repeat=n):
f = np.dot(bits, others); a = others.sum() - f
sF = np.sign(f + w[i] - a); sA = np.sign(f - a - w[i])
tot += sF != sA
return tot / 2 ** n
def tally(Wb, F, Tot, q, rule):
"""F, Tot: (T,4) weighted For and cast weight per bloc."""
Wb = np.array(Wb, float)
if rule == "prop":
return (F / Tot) @ Wb >= q * Wb.sum() - 1e-9
st = np.sign(2 * F - Tot); f = (st == 1) @ Wb; a = (st == -1) @ Wb
return (f + a > 0) & (f >= q * (f + a) - 1e-9)
def sim(wM, wP, Wb=(25, 25, 25, 25), q=0.5, T=200_000, model="coin", minds_r=0.44, seed=1):
r = np.random.default_rng(seed)
if model == "coin": p = np.full((T, 4), .5)
else:
m = r.standard_normal(T); p = 1 / (1 + np.exp(-1.7 * (0.6 * m[:, None] + 0.8 * r.standard_normal((T, 4)))))
ws = [np.ones(8), wM, np.ones(30), wP]; F = np.zeros((T, 4)); Tot = np.zeros((T, 4)); V = []
for b, w in enumerate(ws):
pb = p[:, b:b + 1]
if b == 0 and model != "coin" and minds_r > 0:
a = p[:, 0] * (1 - minds_r) / minds_r; c = (1 - p[:, 0]) * (1 - minds_r) / minds_r
pb = r.beta(a, c)[:, None]
v = r.random((T, len(w))) < pb; V.append(v)
F[:, b] = v @ w; Tot[:, b] = w.sum()
return ws, V, F, Tot
def pivot(ws, V, F, Tot, b, i, Wb, q, rule):
G = F.copy(); G[:, b] += np.where(V[b][:, i], -ws[b][i], ws[b][i])
return np.mean(tally(Wb, F, Tot, q, rule) != tally(Wb, G, Tot, q, rule))
if __name__ == "__main__":
print("## W1. Effective voters (Kish = inverse Herfindahl) and top share")
print("| bloc | curve | operator S | Kish n_eff | top voter share | internal Banzhaf of top (WTA bloc) |")
print("|---|---|---|---|---|---|")
for S in (0.5, 0.8):
for name, fn in CURVES_M.items():
w = fn(members(S)); print(f"| Members (15) | {name} | {S} | {kish(w):.2f} | {w[0] / w.sum():.3f} | {internal_banzhaf(w):.3f} |")
for name, fn in CURVES_P.items():
w = fn(PATRON_D); print(f"| Patrons (4) | {name} | - | {kish(w):.2f} | {w.max() / w.sum():.3f} | {internal_banzhaf(w, int(np.argmax(w))):.3f} |")
print("\n## W2. Operator's power over the whole tally (two-tier Banzhaf, all voters fair coins, 200k draws)")
print("Comparators: a one-each Member; a Mind (8); a User (30); top Patron under log(1+d).")
print("| bloc weights | q | Members curve | S | op pivot prop | op pivot WTA | one-each Member prop/WTA | Mind prop/WTA | User prop/WTA |")
print("|---|---|---|---|---|---|---|---|---|")
wP = np.log1p(PATRON_D)
for Wb, lab in (((25, 25, 25, 25), "equal"), ((20, 45, 20, 15), "members-heavy")):
for q in (0.5, 0.66):
for S in (0.5, 0.8):
for name in ("one-each", "k=1", "k=2", "k=3", "k=5"):
if name == "one-each" and S == 0.8: continue
wM = CURVES_M[name](members(S)); ws, V, F, Tot = sim(wM, wP, Wb, q)
pr = [pivot(ws, V, F, Tot, b, i, Wb, q, "prop") for b, i in ((1, 0), (0, 0), (2, 0))]
pw = [pivot(ws, V, F, Tot, b, i, Wb, q, "wta") for b, i in ((1, 0), (0, 0), (2, 0))]
base = "" if name != "one-each" else " (baseline)"
print(f"| {lab} | {q} | {name}{base} | {S if name != 'one-each' else '-'} | {pr[0]:.4f} | {pw[0]:.4f} | - | {pr[1]:.4f}/{pw[1]:.4f} | {pr[2]:.4f}/{pw[2]:.4f} |")
print("\n## W3. Exponent sensitivity under the motion model (Minds ICC .44, equal bloc weights, q=0.5, S=0.5)")
print("P(motion outcome differs) between Members curve k and k=3 baseline, Patron curve log(1+d); and Patron curve vs log(1+d) with Members k=3.")
print("| varied | curve | P(differ) prop | P(differ) WTA | operator pivot prop | operator pivot WTA |")
print("|---|---|---|---|---|---|")
Wb = (25, 25, 25, 25); q = .5
def outcomes(wM, wP):
ws, V, F, Tot = sim(wM, wP, Wb, q, T=200_000, model="motion", seed=7)
return ws, V, F, Tot, tally(Wb, F, Tot, q, "prop"), tally(Wb, F, Tot, q, "wta")
*_, bp, bw = outcomes(CURVES_M["k=3"](members(.5)), wP)
for name in ("one-each", "k=1", "k=2", "k=3", "k=5"):
ws, V, F, Tot, op, ow = outcomes(CURVES_M[name](members(.5)), wP)
print(f"| Members | {name} | {np.mean(op != bp):.3f} | {np.mean(ow != bw):.3f} | {pivot(ws, V, F, Tot, 1, 0, Wb, q, 'prop'):.4f} | {pivot(ws, V, F, Tot, 1, 0, Wb, q, 'wta'):.4f} |")
for name in ("one-each", "k=1", "log(1+d)", "k=3", "k=5", "k=10"):
ws, V, F, Tot, op, ow = outcomes(CURVES_M["k=3"](members(.5)), CURVES_P[name](PATRON_D))
print(f"| Patrons | {name} | {np.mean(op != bp):.3f} | {np.mean(ow != bw):.3f} | - | - |")