diff --git a/PMOVES-ToKenism-Multi b/PMOVES-ToKenism-Multi index 0b978a1975..d17ea07b59 160000 --- a/PMOVES-ToKenism-Multi +++ b/PMOVES-ToKenism-Multi @@ -1 +1 @@ -Subproject commit 0b978a1975ef4abac9cb75bc5f4202bd2dac8ac0 +Subproject commit d17ea07b59c30051a6258d0bde4c9d82dabe0907 diff --git a/docs/superpowers/plans/2026-07-17-equalweight-governor.md b/docs/superpowers/plans/2026-07-17-equalweight-governor.md index 53817982d7..1fd1ff5820 100644 --- a/docs/superpowers/plans/2026-07-17-equalweight-governor.md +++ b/docs/superpowers/plans/2026-07-17-equalweight-governor.md @@ -8,6 +8,12 @@ **Tech Stack:** TypeScript, Jest (ts-jest). Submodule `PMOVES-ToKenism-Multi`, tests run from `integrations/`. +> **Implementation reconciliation (2026-07-18):** The authoritative runtime is the ToKenism +> implementation merged in submodule PR #64 (`d17ea07b`). Review hardening added bounded configuration, exact +> distinct committees, proposal-scoped roll snapshots, duplicate/deadline guards, immutable finalized +> tallies, and Ed25519 attestation validation. The snippets below are updated for those lifecycle +> invariants, including a post-close gate for secret tally ingestion; the focused governor suite now contains 43 tests. + ## Global Constraints - Spec: `docs/superpowers/specs/2026-07-17-equalweight-governor-design.md`. @@ -16,7 +22,9 @@ - Config defaults: `votingBasis 'member'`, `quorumPercentage 0.5`, `passThreshold 0.5`, `committeeSize 3`, `committeeThreshold 2`. - Voting weight: `member`→1, `unit`→`member.units ?? 1`, `share`→`member.shares ?? 1`. - Quorum is roll-percentage: `voterCount / eligibleCount >= quorumPercentage` — never stake-weighted. -- `committeeThreshold >= 2` by default so no single party can finalize. +- `quorumPercentage` and `passThreshold` are finite values in `[0,1]`; `committeeSize` is an integer `>= 2`; and `committeeThreshold` is an integer in `[2, committeeSize]`. +- A proposal snapshots the eligible roll at creation; later `setRoll` calls affect future proposals only. +- Proposal IDs are unique, deadlines are enforced when configured, and finalized tallies are persisted and immutable. - Set git identity in the submodule before committing: `git config user.name/user.email` mirrored from the parent repo (the submodule has no identity configured). ## Setup (do once, before Task 1) @@ -42,7 +50,7 @@ git config user.name "$(git -C .. config user.name)"; git config user.email "$(g - Test: `PMOVES-ToKenism-Multi/integrations/contracts/__tests__/equalweight-governor-model.test.ts` **Interfaces:** -- Produces: `EqualWeightGovernorModel` with `setRoll(members: EligibleMember[]): void`, `createProposal(id: string, title: string, closesAtWeek?: number): void`, `castVote(proposalId: string, voter: string, support: boolean): void`, `tally(proposalId: string): TallyResult`. Types `VotingBasis`, `EligibleMember`, `EqualWeightGovernorConfig`, `TallyResult` (fields per spec; `finalized:false` here). +- Produces: `EqualWeightGovernorModel` with `setRoll(members: EligibleMember[]): void`, `createProposal(id: string, title: string, closesAtWeek?: number): void`, `castVote(proposalId: string, voter: string, support: boolean, currentWeek?: number): void`, `tally(proposalId: string): TallyResult`. Types `VotingBasis`, `EligibleMember`, `EqualWeightGovernorConfig`, `TallyResult`. - [ ] **Step 1: Write the failing test** @@ -111,7 +119,9 @@ interface Proposal { id: string; title: string; closesAtWeek?: number; + roll: Map; votes: Map; // voter -> support + finalizedTally?: TallyResult; } export class EqualWeightGovernorModel { @@ -128,14 +138,34 @@ export class EqualWeightGovernorModel { committeeThreshold: 2, ...config, }; + if (!Number.isFinite(this.config.quorumPercentage) || this.config.quorumPercentage < 0 || this.config.quorumPercentage > 1) { + throw new Error('quorumPercentage must be between 0 and 1'); + } + if (!Number.isFinite(this.config.passThreshold) || this.config.passThreshold < 0 || this.config.passThreshold > 1) { + throw new Error('passThreshold must be between 0 and 1'); + } + if (!Number.isSafeInteger(this.config.committeeSize) || this.config.committeeSize < 2) { + throw new Error('committeeSize must be an integer >= 2'); + } + if (!Number.isSafeInteger(this.config.committeeThreshold) || this.config.committeeThreshold < 2 || this.config.committeeThreshold > this.config.committeeSize) { + throw new Error('committeeThreshold must be an integer between 2 and committeeSize'); + } } setRoll(members: EligibleMember[]): void { - this.roll = new Map(members.map((m) => [m.id, m])); + if (new Set(members.map((m) => m.id)).size !== members.length) { + throw new Error('eligible roll contains duplicate member ids'); + } + this.roll = new Map(members.map((m) => [m.id, { ...m }])); } createProposal(id: string, title: string, closesAtWeek?: number): void { - this.proposals.set(id, { id, title, closesAtWeek, votes: new Map() }); + if (this.proposals.has(id)) throw new Error(`Proposal ${id} already exists`); + if (closesAtWeek !== undefined && (!Number.isSafeInteger(closesAtWeek) || closesAtWeek < 0)) { + throw new Error('closesAtWeek must be a non-negative safe integer'); + } + const roll = new Map(Array.from(this.roll, ([memberId, member]) => [memberId, { ...member }])); + this.proposals.set(id, { id, title, closesAtWeek, roll, votes: new Map() }); } private weightOf(member: EligibleMember): number { @@ -150,9 +180,18 @@ export class EqualWeightGovernorModel { } } - castVote(proposalId: string, voter: string, support: boolean): void { + castVote(proposalId: string, voter: string, support: boolean, currentWeek?: number): void { const proposal = this.proposals.get(proposalId); if (!proposal) throw new Error(`Proposal ${proposalId} not found`); + if (proposal.finalizedTally) throw new Error(`Proposal ${proposalId} is finalized`); + if (proposal.closesAtWeek !== undefined) { + if (currentWeek === undefined || !Number.isSafeInteger(currentWeek) || currentWeek < 0) { + throw new Error(`A non-negative currentWeek is required for proposal ${proposalId}`); + } + if (currentWeek > proposal.closesAtWeek) throw new Error(`Proposal ${proposalId} is closed`); + } + if (!proposal.roll.has(voter)) throw new Error(`${voter} is not on the eligible roll`); + if (proposal.votes.has(voter)) throw new Error(`${voter} has already voted on ${proposalId}`); proposal.votes.set(voter, support); } @@ -163,14 +202,14 @@ export class EqualWeightGovernorModel { let votesFor = 0; let votesAgainst = 0; for (const [voter, support] of proposal.votes) { - const member = this.roll.get(voter); + const member = proposal.roll.get(voter); if (!member) continue; const w = this.weightOf(member); if (support) votesFor += w; else votesAgainst += w; } - const eligibleCount = this.roll.size; + const eligibleCount = proposal.roll.size; const voterCount = proposal.votes.size; const turnout = eligibleCount > 0 ? voterCount / eligibleCount : 0; @@ -241,10 +280,17 @@ Expected: FAIL — the two new tests do not throw. - [ ] **Step 3: Write minimal implementation** (replace `castVote` body) ```ts - castVote(proposalId: string, voter: string, support: boolean): void { + castVote(proposalId: string, voter: string, support: boolean, currentWeek?: number): void { const proposal = this.proposals.get(proposalId); if (!proposal) throw new Error(`Proposal ${proposalId} not found`); - if (!this.roll.has(voter)) { + if (proposal.finalizedTally) throw new Error(`Proposal ${proposalId} is finalized`); + if (proposal.closesAtWeek !== undefined) { + if (currentWeek === undefined || !Number.isSafeInteger(currentWeek) || currentWeek < 0) { + throw new Error(`A non-negative currentWeek is required for proposal ${proposalId}`); + } + if (currentWeek > proposal.closesAtWeek) throw new Error(`Proposal ${proposalId} is closed`); + } + if (!proposal.roll.has(voter)) { throw new Error(`${voter} is not on the eligible roll`); } if (proposal.votes.has(voter)) { @@ -372,7 +418,7 @@ Expected: FAIL — `quorumMet`/`passed` are still hard-coded `false` from Task 1 - [ ] **Step 3: Write minimal implementation** (replace the `return` block in `tally`) ```ts - const eligibleCount = this.roll.size; + const eligibleCount = proposal.roll.size; const voterCount = proposal.votes.size; const turnout = eligibleCount > 0 ? voterCount / eligibleCount : 0; const quorumMet = turnout >= this.config.quorumPercentage; @@ -416,7 +462,7 @@ git commit -m "feat(gov): roll-percentage quorum + majority pass logic" **Interfaces:** - Consumes: `tally` (Task 1/4), `EqualWeightGovernorConfig.committeeThreshold`. -- Produces: `setCommittee(memberIds: string[]): void`; `finalize(proposalId: string, approvers: string[]): TallyResult` (returns `{...tally, finalized:true, attestation}`); `TallySigner` interface `sign(tally, approvers, committee, threshold): TallyAttestation`; `MockThresholdSigner` (default injected); `TallyAttestation { algo, approvers, signature }`. +- Produces: `setCommittee(memberIds: string[]): void`; `finalize(proposalId: string, approvers: string[]): TallyResult` (persists and returns a defensive copy of the immutable finalized result); `TallySigner` interface `sign(tally, approvers, committee, threshold): TallyAttestation`; `MockThresholdSigner` (default injected); `TallyAttestation { algo, approvers, signature }`. - [ ] **Step 1: Write the failing test** @@ -552,11 +598,34 @@ Add a committee field + inject the signer in the class (constructor gains a seco this.signer = signer; } + private cloneTally(t: TallyResult): TallyResult { + return { + ...t, + ...(t.ballotRef ? { ballotRef: { ...t.ballotRef } } : {}), + ...(t.attestation ? { + attestation: { + ...t.attestation, + approvers: [...t.attestation.approvers], + ...(t.attestation.signatures ? { signatures: { ...t.attestation.signatures } } : {}), + }, + } : {}), + }; + } + setCommittee(memberIds: string[]): void { + if (memberIds.length !== this.config.committeeSize) { + throw new Error(`committee must contain exactly ${this.config.committeeSize} members`); + } + if (new Set(memberIds).size !== memberIds.length) { + throw new Error('committee contains duplicate member ids'); + } this.committee = new Set(memberIds); } finalize(proposalId: string, approvers: string[]): TallyResult { + const proposal = this.proposals.get(proposalId); + if (!proposal) throw new Error(`Proposal ${proposalId} not found`); + if (proposal.finalizedTally) return this.cloneTally(proposal.finalizedTally); const result = this.tally(proposalId); const attestation = this.signer.sign( result, @@ -564,14 +633,20 @@ Add a committee field + inject the signer in the class (constructor gains a seco Array.from(this.committee), this.config.committeeThreshold ); - return { ...result, finalized: true, attestation }; + proposal.finalizedTally = this.cloneTally({ ...result, finalized: true, attestation }); + return this.cloneTally(proposal.finalizedTally); } ``` +`cloneTally` defensively copies `ballotRef`, `attestation.approvers`, and +`attestation.signatures`; `tally()` returns that stored snapshot after finalization, while +`castVote()` and secret-tally ingestion reject later proposal mutations. A later `setRoll()` remains +valid for future proposals because each existing proposal owns an immutable roll snapshot. + - [ ] **Step 4: Run test to verify it passes** Run: `cd PMOVES-ToKenism-Multi/integrations && npx jest contracts/__tests__/equalweight-governor-model.test.ts` -Expected: PASS (10 tests). +Expected: PASS (43 focused governor tests after review hardening). - [ ] **Step 5: Run the full submodule suite (no regression)** @@ -590,19 +665,23 @@ git commit -m "feat(gov): k-of-n committee finalize gate + TallySigner (no singl ## After the plan (open the PR) +Start from the parent repository's required `.github/pull_request_template.md`, then populate it with the linked +parent issue/PR, affected ToKenism contracts, actual focused/full-suite/typecheck/lint evidence, +deployment impact, and rollback instructions. Do not use the former abbreviated inline body. + ```bash cd PMOVES-ToKenism-Multi git push -u origin feat/equalweight-governor gh pr create --base PMOVES.AI-Edition-Hardened --head feat/equalweight-governor \ --title "feat(gov): EqualWeightGovernor — equal-weight tally + roll-% quorum + M-of-N finalize" \ - --body "Stage 1 of the #5 governance replacement (spec: docs/superpowers/specs/2026-07-17-equalweight-governor-design.md). Drop-in equal-weight (member/unit/share) governor with roll-% quorum and a modeled k-of-n committee finalize gate (crypto stubbed behind TallySigner). CoopGovernor left intact as the sweep contrast. Independent review + TDD-green expected." + --body-file /path/to/completed-pull-request-template.md ``` Then: independent code-review (like #53–#59), fold fixes back, admin-merge. ## Self-Review -**Spec coverage:** Components (Task 1/5) ✓; API/data flow (Tasks 1,2,4,5) ✓; voting basis member/unit/share (Task 1 `weightOf` + Task 3 contrast) ✓; roll-% quorum (Task 4) ✓; passed logic (Task 4) ✓; M-of-N gate + TallySigner + MockThresholdSigner (Task 5) ✓; all 6 spec tests mapped (Task1 tally, Task2 non-roll+double, Task3 basis contrast, Task4 quorum, Task5 M-of-N + non-committee) ✓; CoopGovernor untouched (Global Constraints) ✓. `unit` basis is implemented (Task 1) though only `member`/`share` are directly asserted — acceptable (the switch covers it; a unit test can be added later if desired). +**Spec coverage:** Components (Task 1/5) ✓; API/data flow (Tasks 1,2,4,5) ✓; voting basis member/unit/share ✓; roll-% quorum ✓; bounded configuration and exact committee ✓; proposal roll snapshot, duplicate ID, deadline, secret-tally close window, and immutable finalization lifecycle ✓; M-of-N gate + TallySigner + MockThresholdSigner ✓; 43 focused governor tests pass after review hardening; CoopGovernor remains untouched as the non-binding contrast ✓. **Placeholder scan:** none — every code step has complete code; every run step has an exact command + expected result. diff --git a/docs/superpowers/plans/2026-07-17-member-registry.md b/docs/superpowers/plans/2026-07-17-member-registry.md index 19728b99a2..ed0ed51adc 100644 --- a/docs/superpowers/plans/2026-07-17-member-registry.md +++ b/docs/superpowers/plans/2026-07-17-member-registry.md @@ -12,7 +12,8 @@ - Spec: `docs/superpowers/specs/2026-07-17-member-registry-design.md`. - All new code in `PMOVES-ToKenism-Multi/integrations/contracts/`; do NOT modify `equalweight-governor-model.ts` (import from it only) or any other existing file. -- Config defaults: `committeeSize 3`, `committeeThreshold 2`. Constructor MUST validate `1 <= committeeThreshold <= committeeSize` (throw otherwise). +- Config defaults: `committeeSize 3`, `committeeThreshold 2`. Constructor MUST validate integer `committeeSize >= 2` and `2 <= committeeThreshold <= committeeSize` (throw otherwise). +- `setCommittee` MUST install exactly `committeeSize` distinct IDs; smaller, larger, or duplicate-ID committees throw. - M-of-N gate: dedupe approvers; every approver must be on the committee; `distinct approvers >= committeeThreshold`; else throw. - `roll()` returns ONLY active members. `isEligible(id)` is true iff an active membership exists. - Import `EligibleMember` from `./equalweight-governor-model`; do not redefine it. @@ -113,8 +114,11 @@ export class MemberRegistryModel { constructor(config: Partial = {}) { this.config = { committeeSize: 3, committeeThreshold: 2, ...config }; - if (this.config.committeeThreshold < 1) { - throw new Error('committeeThreshold must be >= 1'); + if (!Number.isSafeInteger(this.config.committeeSize) || this.config.committeeSize < 2) { + throw new Error('committeeSize must be an integer >= 2'); + } + if (!Number.isSafeInteger(this.config.committeeThreshold) || this.config.committeeThreshold < 2) { + throw new Error('committeeThreshold must be an integer >= 2'); } if (this.config.committeeThreshold > this.config.committeeSize) { throw new Error('committeeThreshold must be <= committeeSize'); @@ -122,6 +126,12 @@ export class MemberRegistryModel { } setCommittee(ids: string[]): void { + if (ids.length !== this.config.committeeSize) { + throw new Error(`committee must contain exactly ${this.config.committeeSize} members`); + } + if (new Set(ids).size !== ids.length) { + throw new Error('committee contains duplicate member ids'); + } this.committee = new Set(ids); } @@ -236,7 +246,7 @@ Expected: FAIL — `r.revoke is not a function` / `r.roll is not a function`. - [ ] **Step 4: Run test to verify it passes** Run: `cd PMOVES-ToKenism-Multi/integrations && npx jest contracts/__tests__/member-registry-model.test.ts` -Expected: PASS (7 tests). +Expected: PASS (10 tests: the original eight plan cases plus smaller/larger and duplicate committee-cardinality regressions). - [ ] **Step 5: Commit** @@ -317,7 +327,7 @@ Then: independent code-review, fold fixes back, admin-merge. ## Self-Review -**Spec coverage:** enrol M-of-N (Task 1) ✓; revoke M-of-N (Task 2) ✓; isEligible (Task 1) ✓; roll() active-only (Task 2) ✓; config validation (Task 1) ✓; duplicate/non-committee approver (Task 1) ✓; roll→governor integration (Task 3) ✓; decoupled from tokens (no token import anywhere — Global Constraints) ✓; all 7 spec tests mapped (T1: enrol+dup+non-committee+config, T2: revoke+non-member+roll, T3: integration) ✓; no existing model modified ✓. +**Spec coverage:** enrol M-of-N (Task 1) ✓; revoke M-of-N (Task 2) ✓; isEligible (Task 1) ✓; roll() active-only (Task 2) ✓; config validation (Task 1) ✓; exact distinct committee cardinality (Task 1) ✓; duplicate/non-committee approver (Task 1) ✓; roll→governor integration (Task 3) ✓; decoupled from tokens (no token import anywhere — Global Constraints) ✓; all 10 runtime tests mapped, including the Task-3 integration case and the two cardinality regressions added during review ✓; no existing model modified ✓. **Placeholder scan:** none — every code step is complete; every run step has command + expected result. diff --git a/docs/superpowers/specs/2026-07-07-fordham-hill-room-design.md b/docs/superpowers/specs/2026-07-07-fordham-hill-room-design.md index a786b3a680..e21c61bc9c 100644 --- a/docs/superpowers/specs/2026-07-07-fordham-hill-room-design.md +++ b/docs/superpowers/specs/2026-07-07-fordham-hill-room-design.md @@ -2,8 +2,8 @@ _Spec date: 2026-07-07 · Status: DRAFT · Room id: `fordham.room.community` · Stage: `rehearsal`_ -> One shared box delivers cheaper+more-private internet **and** the tamper-evident ledger/ballot box -> for co-op self-governance. This spec turns that four-lane pilot into one **room-on-a-stage** so P7 can +> One shared box can deliver cheaper+more-private internet and host a separately governed election +> rehearsal; it is not yet a ballot box. This spec turns that four-lane pilot into one **room-on-a-stage** so P7 can > launch it, Archon can mint its agents, and residents get a single audience-facing surface instead of > four disconnected docs. Every dollar/vote/governance claim in this room is > **DRAFT — REQUIRES LEGAL REVIEW** (pmoves/docs/pilots/fordham-hill/README.md:3). @@ -13,8 +13,8 @@ _Spec date: 2026-07-07 · Status: DRAFT · Room id: `fordham.room.community` · This room inherits the pilot's three-tier framing verbatim — no claim may cross a tier boundary in the UI: - **PROVEN (measured this session):** the 3 KVM exit nodes run and were measured (845/683/448 Mbps down, - ~1,976 aggregate; $10/mo/node); HMAC `sign_cgp` vote-receipt primitive exists and is tested - (pmoves/docs/pilots/fordham-hill/README.md:10). + ~1,976 aggregate; $10/mo/node). HMAC `sign_cgp` is tested for agent trails only and cannot underwrite + a contested ballot (pmoves/docs/pilots/fordham-hill/README.md:10). - **MODELED (projected arithmetic, not adopted):** homes-per-node (~84/node, ~197 fleet), the ~$10 pooled due, ~$25/mo ($300/yr, 71%) per-home saving, Dirichlet contribution attribution (pmoves/docs/pilots/fordham-hill/README.md:12). @@ -78,7 +78,7 @@ Mirrors the shape of the validated `4090-field.room.control.json` seed |---|---|---|---| | `voice-console` | `chat` | left | FlOO$ spoken interaction (the accessibility front door) | | `pilot-overview` | `custom` | center | the four-lane dashboard, each tile tier-badged | -| `ledger-graph` | `graph` | right | contribution/roll trail (who contributed == who may vote) | +| `ledger-graph` | `graph` | right | contribution trail only; not a legal voter roll | **Apps** (each declares `route` + `action_namespace` + `capabilities`, room.manifest.v1.schema.json:125): @@ -88,7 +88,7 @@ Mirrors the shape of the validated `4090-field.room.control.json` seed | `mesh-ab` | `dashboard` | `/dashboard/fordham/capacity` | `capacity` | `active` | A/B measured vs. raw uplink (mesh-egress-ab skill) | | `coop-ledger` | `dashboard` | `/dashboard/fordham/wealth` | `wealth` | `planned` | Firefly III co-op ledger view (life-team `wealth` agent, agent-teams.yaml:166) | | `voter-roll` | `notebook` | `/dashboard/fordham/roll` | `governance` | `planned` | eligible-voter roll + enrollment; `planned` because roll = 1 of N today (users.yaml:9) | -| `ballot-box` | `dashboard` | `/dashboard/fordham/governance` | `governance` | `planned` | HMAC vote receipts; `planned` — MUST NOT go `active` until legal + one-member-one-vote basis resolved | +| `ballot-box` | `dashboard` | `/dashboard/fordham/governance` | `governance` | `planned` | Disabled rehearsal; no ballot event contract/service; MUST NOT go `active` without the full legal, resident, evidence, and accessibility gates | App `status` values are schema-supported (`active|planned|deprecated`, room.manifest.v1.schema.json:153) — governance surfaces ship as `planned` so the room can **declare** @@ -168,14 +168,12 @@ How each of the four lanes (one system, four angles) appears as a concrete room | **Capacity** | PROVEN | `mesh-ab` · `capacity` (`/dashboard/fordham/capacity`) | fordham-onboarding (mesh side) | `mesh-egress-ab`, `fleet:enroll` | README:10 (measured 845/683/448 Mbps; honest caveat 305/70 vs 520/101) | | **Wealth** | MODELED | `coop-ledger` · `wealth` (`/dashboard/fordham/wealth`) | fordham-transaction | `pmoves-chit-sign` + Firefly (`wealth`) | README:12,36 ($35→~$10, ~$25/mo saved = surplus) | | **Tokenism** | MODELED + FLAGGED | `pilot-dashboard` contribution tile · `fordham` | fordham-transaction | Dirichlet/CHIT attribution (attribution-preview only) | README:12 (12-wk decay; flags: localEconomicActivities inert, Dirichlet not wired to distribution) | -| **Governance** | SCAFFOLDED | `voter-roll` + `ballot-box` · `governance` (both `status: planned`) | fordham-onboarding (roll) / fordham-voice (accessible read-out) | `fleet:enroll`, `pmoves-chit-sign` (`vote.signed.v1` HMAC receipts) | README:14,39 (roll 1 of N; governor plutocratic — DO NOT SHIP as-is) | +| **Governance** | SCAFFOLDED | `voter-roll` + `ballot-box` · `governance` (both `status: planned`) | fordham-onboarding (roll) / fordham-voice (accessible read-out) | `fleet:enroll`; committee-tally model (no active ballot subject) | README:14,39 (roll 1 of N; no binding election service) | **The convergence in the room:** the dollars the capacity tile frees are the dollars the wealth tile books -as surplus; the contribution the tokenism tile attributes is what earns roll standing; the governance -surfaces are how the co-op votes on that surplus — all on **one mesh + one signing key** -(pmoves/docs/pilots/fordham-hill/README.md:39). The room makes that literal: the same -`pmoves-chit-sign` HMAC primitive that receipts a dues trail (wealth) receipts a vote -(`vote.signed.v1`, governance) — no blockchain, no wallets. +as surplus, while tokenism records contribution. Governance may share the mesh transport, but eligibility +is independently attested and the tally uses distinct non-operator committee keys. Agent-trail HMAC, +Mode-B attribution identity, and Mode-A ballot identity must never be one key or roster. --- @@ -224,8 +222,8 @@ surface it governs (pmoves/docs/pilots/fordham-hill/README.md:58-69): - **Voting basis & quorum legality** (one-member vs unit vs share; roll-percentage quorum) must be counsel-confirmed against the certificate/bylaws/NY law before any binding vote → gates governance namespace (:62). -- **E-voting / remote-quorum validity** — whether HMAC-receipted (`vote.signed.v1`) mesh ballots satisfy NY - cooperative-meeting/notice/quorum requirements → hard gate on `ballot-box` (:63). +- **E-voting / remote-quorum validity** — whether a future receipt-free, committee-audited mesh ballot + satisfies NY cooperative-meeting/notice/quorum requirements → hard gate on `ballot-box` (:63). - **Board/management transition process** — legal mechanics stay counsel-led; the platform provides auditable records only and must not be represented as conferring legal authority (:64). - **Fraud-investigation boundary** — tooling outputs are transparency/audit artifacts only; no accusations; diff --git a/docs/superpowers/specs/2026-07-17-equalweight-governor-design.md b/docs/superpowers/specs/2026-07-17-equalweight-governor-design.md index b1c4109acc..899010a66c 100644 --- a/docs/superpowers/specs/2026-07-17-equalweight-governor-design.md +++ b/docs/superpowers/specs/2026-07-17-equalweight-governor-design.md @@ -1,10 +1,10 @@ # EqualWeightGovernor — Design Spec (governance replacement, stage 1) **Date:** 2026-07-17 -**Status:** DRAFT — approved for implementation (stage 1 of the #5 governance-replacement arc) +**Status:** IMPLEMENTED AND TESTED — merged in ToKenism PR #64 (`d17ea07b`); activation remains counsel- and operations-gated **Scope:** the tractable, sim/bridge first increment ONLY. Stages 2–5 (real threshold crypto, voter-card credentials, secret-ballot integration, paper parity) are later, heavier, counsel-gated lanes and are out of scope here. **Where:** submodule `PMOVES-ToKenism-Multi/integrations/contracts/` (alongside the other economic/governance models). -**Boundaries:** honors `pmoves/docs/pilots/fordham-hill/08-voter-identity-key-custody.md` and `pmoves/docs/CATACLYSM_CROSSLINKS.md` (open decision #5). DRAFT — counsel-gated before anything binding/member-facing. +**Boundaries:** honors `pmoves/docs/pilots/fordham-hill/08-voter-identity-key-custody.md` and `pmoves/docs/CATACLYSM_CROSSLINKS.md` (open decision #5). Implementation does not authorize binding or member-facing activation; those uses remain counsel-gated. ## Problem @@ -72,19 +72,21 @@ interface TallySigner { ### API / data flow ``` -setRoll(members: EligibleMember[]) // the eligible membership (decoupled from tokens) -setCommittee(memberIds: string[]) // the election committee (distinct from the roll) -createProposal(id, title, closesAtWeek?) // binary for/against -castVote(proposalId, voter, support: boolean) +setRoll(members: EligibleMember[]) // affects future proposals; duplicates throw +setCommittee(memberIds: string[]) // exactly committeeSize distinct committee ids +createProposal(id, title, closesAtWeek?) // snapshots roll; duplicate id/deadline errors throw +castVote(proposalId, voter, support: boolean, currentWeek?) - rejects a voter not on the roll - one vote per member (last-write-wins is out of scope; a second vote throws) -tally(proposalId): TallyResult // pure read of roll + votes; finalized:false + - requires/validates currentWeek when closesAtWeek exists; rejects late/finalized votes +tally(proposalId): TallyResult // pure read; returns frozen snapshot after finalize finalize(proposalId, approvers: string[]): TallyResult - the ONLY place a result becomes official - delegates the k-of-n check + attestation to the injected TallySigner + - persists an immutable finalized snapshot; later proposal mutations throw ``` -`castVote` and `tally` are pure reads over the roll and recorded votes. `finalize` is the sole path to an official, attested result. +`castVote` mutates recorded proposal state; only `tally` is a pure read. `finalize` is the sole path to an official, attested result and freezes the returned tally. ## Voting basis + quorum semantics diff --git a/docs/superpowers/specs/2026-07-17-member-registry-design.md b/docs/superpowers/specs/2026-07-17-member-registry-design.md index fd056b6442..978386557f 100644 --- a/docs/superpowers/specs/2026-07-17-member-registry-design.md +++ b/docs/superpowers/specs/2026-07-17-member-registry-design.md @@ -1,10 +1,10 @@ # MemberRegistry — Design Spec (governance replacement, stage 3) **Date:** 2026-07-17 -**Status:** DRAFT — approved for implementation (stage 3 of the #5 governance-replacement arc) +**Status:** IMPLEMENTED AND TESTED — merged in ToKenism PR #64 (`d17ea07b`); activation remains counsel- and operations-gated **Scope:** the committee-controlled eligibility layer ONLY. Real voter-card crypto, secret-ballot integration, and paper parity are later counsel-gated stages, out of scope here. **Where:** submodule `PMOVES-ToKenism-Multi/integrations/contracts/`. -**Builds on:** stage 1 `EqualWeightGovernorModel` (this stage produces the roll it consumes). Honors `pmoves/docs/pilots/fordham-hill/08-voter-identity-key-custody.md` and `CATACLYSM_CROSSLINKS.md` (#5). DRAFT — counsel-gated before anything binding. +**Builds on:** stage 1 `EqualWeightGovernorModel` (this stage produces the roll it consumes). Honors `pmoves/docs/pilots/fordham-hill/08-voter-identity-key-custody.md` and `CATACLYSM_CROSSLINKS.md` (#5). The model is implemented; any binding use remains counsel-gated. ## Problem @@ -15,7 +15,7 @@ This stage adds `MemberRegistryModel`: a committee-controlled roll where **enrol ## Decisions (from brainstorming, approved) 1. **Enrollment (and revocation) require k-of-n committee approval** — the anti-chokepoint design, reusing stage 1's M-of-N gate pattern. Not a single registrar. -2. **Own committee + threshold** config (mirrors the governor's); constructor validates `1 <= committeeThreshold <= committeeSize` (the forge-hole lesson from stage 1's review). +2. **Own committee + threshold** config (mirrors the governor's); constructor validates integer `committeeSize >= 2` and `2 <= committeeThreshold <= committeeSize` (the forge-hole lesson from stage 1's review). 3. **Reuse `EligibleMember`** from `equalweight-governor-model.ts` so `roll()` output drops straight into `EqualWeightGovernor.setRoll()` (DRY; loose coupling — the caller wires `registry.roll()` → `governor.setRoll()`, no hard dependency between them at runtime). 4. **Decoupled from tokens** — membership is residency/committee-issued, never derived from holdings/contribution. @@ -31,7 +31,7 @@ import { EligibleMember } from './equalweight-governor-model'; interface MemberRegistryConfig { committeeSize: number; // n (default 3) - committeeThreshold: number; // k (default 2; 1 <= k <= n; k >= 2 => no single party can enrol/revoke) + committeeThreshold: number; // k (default 2; 2 <= k <= n) } interface MembershipCredential { @@ -45,7 +45,7 @@ interface MembershipCredential { ### API ``` -setCommittee(memberIds: string[]): void // the enrollment committee (distinct from the voter roll) +setCommittee(memberIds: string[]): void // exactly committeeSize distinct ids; else throws enrol(member: EligibleMember, approvers: string[]): MembershipCredential - M-of-N gate: approvers deduped, all in committee, count >= committeeThreshold; else throw - records the member as 'active'; returns the credential @@ -57,7 +57,7 @@ roll(): EligibleMember[] // active members only → fee ## The M-of-N gate (anti-chokepoint property) -Both `enrol` and `revoke` require ≥ `committeeThreshold` **distinct** committee approvers. With `committeeThreshold >= 2` (default), **no single party — including the operator — can add, remove, or forge a member.** The gate logic mirrors stage 1's `MockThresholdSigner`: dedupe approvers (a member approving twice counts once), reject any approver not on the committee, reject below-threshold. Constructor validates `1 <= committeeThreshold <= committeeSize` so a `committeeThreshold: 0` cannot bypass the gate. +Both `enrol` and `revoke` require ≥ `committeeThreshold` **distinct** committee approvers. With `committeeThreshold >= 2`, **no single party — including the operator — can add, remove, or forge a member.** The gate logic mirrors stage 1's `MockThresholdSigner`: dedupe approvers (a member approving twice counts once), reject any approver not on the committee, reject below-threshold. Constructor validation rejects non-integer/undersized configurations, and `setCommittee` requires exactly `committeeSize` distinct IDs so configured *n* equals the installed committee. ## Testing (TDD, red-first) @@ -68,6 +68,9 @@ Both `enrol` and `revoke` require ≥ `committeeThreshold` **distinct** committe 5. **revoke of a non-member** — `revoke('0xNOBODY', ['0xC1','0xC2'])` throws. 6. **roll() feeds the governor** — enrol A + B (with committee approval), `roll()` returns `[{id:'A'},{id:'B'}]` (order-insensitive), and passing it to `new EqualWeightGovernorModel().setRoll(registry.roll())` lets A and B vote (integration proof). 7. **config validation** — `new MemberRegistryModel({ committeeThreshold: 0 })` throws; `{ committeeThreshold: 4, committeeSize: 3 }` throws. +8. **integration count** — the Task-3 roll→governor case is counted in the expected suite total. +9. **committee cardinality** — committees smaller or larger than configured `committeeSize` throw. +10. **duplicate committee ID** — a committee with repeated member IDs throws even when its array length equals `committeeSize`. No changes to existing models; `EqualWeightGovernorModel` is imported (for `EligibleMember`) but not modified. diff --git a/docs/superpowers/specs/2026-07-18-tally-signer-ed25519-design.md b/docs/superpowers/specs/2026-07-18-tally-signer-ed25519-design.md index bfe956a8f6..56a5ac6cb8 100644 --- a/docs/superpowers/specs/2026-07-18-tally-signer-ed25519-design.md +++ b/docs/superpowers/specs/2026-07-18-tally-signer-ed25519-design.md @@ -1,10 +1,10 @@ # Ed25519 Multisig TallySigner — Design Spec (governance replacement, stage 2) **Date:** 2026-07-18 -**Status:** DRAFT — approved for implementation (stage 2 of the #5 governance-replacement arc) +**Status:** IMPLEMENTED AND TESTED — merged in ToKenism PR #64 (`d17ea07b`); activation remains counsel- and operations-gated **Scope:** the real committee tally-signature ONLY — a third-party-verifiable Ed25519 k-of-n multisignature replacing the stubbed `MockThresholdSigner`, behind the same `TallySigner` interface. Key custody, CGP/bus emission, secret-ballot integration, and paper parity are later stages, out of scope here. **Where:** submodule `PMOVES-ToKenism-Multi/integrations/contracts/`. -**Builds on:** stage 1 `EqualWeightGovernorModel` (it calls `this.signer.sign(...)` through `TallySigner`) and stage 3 `MemberRegistryModel` (loose-coupled; see below). Honors `pmoves/docs/pilots/fordham-hill/08-voter-identity-key-custody.md` (§5b: "an election committee threshold-signs the tally … no single party incl. operator can forge — replaces single-operator HMAC") and `CATACLYSM_CROSSLINKS.md` (#5). DRAFT — counsel-gated before anything binding. +**Builds on:** stage 1 `EqualWeightGovernorModel` (it calls `this.signer.sign(...)` through `TallySigner`) and stage 3 `MemberRegistryModel` (loose-coupled; see below). Honors `pmoves/docs/pilots/fordham-hill/08-voter-identity-key-custody.md` (§5b: "an election committee threshold-signs the tally … no single party incl. operator can forge — replaces single-operator HMAC") and `CATACLYSM_CROSSLINKS.md` (#5). The model is implemented; any binding use remains counsel-gated. ## Problem @@ -54,15 +54,21 @@ export function tallyPreimage(tally: TallyResult): Buffer; // Encoding: for each field in fixed order, append `:,` // Order: DOMAIN("pmoves.tally.v1"), proposalId, votesFor, votesAgainst, // eligibleCount, voterCount, quorumMet("1"/"0"), passed("1"/"0") +// Before serialization, votesFor, votesAgainst, eligibleCount, and voterCount +// MUST each be non-negative safe integers and voterCount <= eligibleCount. +// Fractional, NaN, infinite, negative, or unsafe values throw. Weighted voting +// must use a documented scaled-integer representation before signing. // Numbers -> decimal string; booleans -> "1"/"0". ``` ### The M-of-N gate (extracted, shared) ```ts -// Throws on: a non-committee approver, or fewer than `threshold` DISTINCT -// approvers. Returns the deduplicated approver list. This is the anti-forgery -// gate — one definition, used by the real signer and MockThresholdSigner. +// Throws unless threshold is a safe integer >= 2 and the committee contains +// at least threshold distinct IDs; also throws on duplicate committee IDs, a +// non-committee approver, or fewer than `threshold` DISTINCT approvers. Returns +// the deduplicated approver list. This is the anti-forgery gate — one definition, +// used by the real signer and MockThresholdSigner. export function assertCommitteeThreshold( approvers: string[], committee: string[], @@ -70,7 +76,7 @@ export function assertCommitteeThreshold( ): string[]; ``` -`equalweight-governor-model.ts`'s `MockThresholdSigner.sign` is refactored to call `assertCommitteeThreshold` instead of its inline checks (behavior identical; ~3 lines). +`equalweight-governor-model.ts`'s `MockThresholdSigner.sign` is refactored to call `assertCommitteeThreshold` instead of its inline checks, so both signers inherit the minimum 2-of-N, distinct-committee, membership, and deduplicated-approver contract. ### Keyring + sim helper @@ -125,11 +131,13 @@ export function verifyTallyAttestation( publicKeyring: Record, // committeeMemberId -> publicKey (hex) threshold: number ): VerifyResult; -// Steps: recompute tallyPreimage(tally); for each (id -> sig) in -// attestation.signatures: require id in publicKeyring AND crypto.verify passes; -// count DISTINCT verified committee signers; valid iff count >= threshold and -// every listed signature verified. Any unknown id, bad sig, or short count => -// valid:false with a reason. +// Steps: require attestation.algo === 'ed25519-multisig'; require threshold >= 2; +// validate and recompute tallyPreimage(tally); require distinct approvers whose +// set exactly equals the signature-map IDs; for each (id -> sig), require id in +// publicKeyring AND crypto.verify passes; count DISTINCT public-key material; +// valid iff that count >= threshold and every listed signature verified. Any +// malformed tally, metadata mismatch, unknown id, duplicate key, bad sig, or +// short count => valid:false with a reason. ``` ### Attestation shape — minimal widening @@ -159,6 +167,12 @@ Test file: `integrations/contracts/__tests__/tally-signer-ed25519.test.ts` (Jest 8. **Preimage determinism / float-independence** — `tallyPreimage` is bytewise stable across calls; two `TallyResult`s with identical integers/booleans but different `turnout` floats produce identical preimages. 9. **Gate parity** — after the refactor, `MockThresholdSigner` still throws on below-threshold / non-committee / duplicate (guards the extracted helper didn't change stage-1 behavior). 10. **Integration** — `new EqualWeightGovernorModel({}, new Ed25519MultisigSigner(keyring))`, cast votes, `finalize(proposalId, approvers)` → returned `attestation` passes `verifyTallyAttestation` with the matching public keyring. +11. **Canonical numeric rejection** — signing rejects fractional, `NaN`, infinite, negative, and unsafe count fields; verification returns `valid:false` for the same malformed tallies. +12. **Minimum threshold** — both real and mock signers reject threshold `0` or `1`; verification also rejects thresholds below two. +13. **Algorithm binding** — changing `attestation.algo` causes verification to fail even when the signatures are otherwise valid. +14. **Signer-metadata binding** — duplicate, missing, added, or substituted `attestation.approvers` fail unless the distinct approver set exactly equals the signature-map IDs. + +The implemented focused suite expands these cases to 34 tests, including malformed encodings, duplicate public-key material, defensive failure reasons, and ballot-reference binding. ## Out of scope (later arc stages / follow-ons) @@ -172,6 +186,6 @@ Test file: `integrations/contracts/__tests__/tally-signer-ed25519.test.ts` (Jest ## Success criteria - `tally-signer-ed25519.ts` compiles; all TDD tests pass; full submodule suite stays green. -- `Ed25519MultisigSigner.sign` provably rejects a single-party / below-threshold / duplicate / non-committee action (tests 2–4). -- `verifyTallyAttestation` provably rejects tampering, outsider forgery, and wrong-tally presentation (tests 5–7) using **public keys only** — the third-party informing surface. +- `Ed25519MultisigSigner.sign` rejects a single-party / below-threshold / duplicate / non-committee action and malformed numeric tally (tests 2–4, 11–12). +- `verifyTallyAttestation` rejects tampering, outsider forgery, wrong-tally presentation, malformed numeric tally, algorithm relabeling, and approver/signature metadata mismatch (tests 5–7, 11–14) using **public keys only** — the third-party informing surface. - The real signer drops into `EqualWeightGovernorModel` unchanged at the call site (test 10); the only stage-1 edits are the optional `signatures` field and the gate-helper refactor, with behavior preserved (test 9). diff --git a/pmoves/docs/CATACLYSM_CROSSLINKS.md b/pmoves/docs/CATACLYSM_CROSSLINKS.md index 1ca3698ace..a6f332fb53 100644 --- a/pmoves/docs/CATACLYSM_CROSSLINKS.md +++ b/pmoves/docs/CATACLYSM_CROSSLINKS.md @@ -76,14 +76,20 @@ So the built tokens are the design the board-facing docs say they replaced. Nota ## Governance -**Built:** single-chamber **CoopGovernor** — quadratic vote cost `rawVotes²` charged against **GroVault voting power = √(staked GRO) × lock-multiplier**. Execution gated on flat `proposalThreshold` + `forVotes>againstVotes` + period-ended. One chairperson admin. This is **stake-weighted / plutocratic**. +**Built:** single-chamber **CoopGovernor** — quadratic vote cost `rawVotes²` charged against **GroVault voting power = √(staked GRO) × lock-multiplier**. Execution gated on flat `proposalThreshold` + `forVotes>againstVotes` + period-ended. One chairperson admin. This is **stake-weighted / plutocratic** and remains non-binding simulation contrast. -**Required (Fordham + refresh direction), NOT built:** -- **Equal-weight** one-member/one-unit/per-share voting — stake/token weight MUST NEVER translate into vote weight. -- **Quorum as a percentage of the eligible member roll** — not a flat count, not a percentage of staked voting power. -- **Committee M-of-N threshold-signing** of the tally (FROST/Ed25519, non-operator committee) replacing single-operator **symmetric HMAC** (operator-forgeable — disqualifying for a contested recall). +**Implemented in the ToKenism rehearsal model (merged submodule PR #64, `d17ea07b`):** configurable +equal-weight member/unit/share tally; quorum as a percentage of a proposal-snapshotted eligibility roll; +duplicate/deadline/finalization guards; exact distinct committee cardinality; Ed25519 multi-signature +attestation with a minimum 2-of-N threshold; canonical safe-integer preimages; and exact +approver/signature identity binding. This is executable model/test evidence, **not** a deployed election +service or legal activation. + +**Still required before any Fordham activation:** - **Eligibility credential** (`voter-card.v1`), committee-issued, human-witnessed, **decoupled from Archon minting and the token structure**. - **Mode A (secret/adversarial)** vs **Mode B (attributable)** separation with a hard **key-unlinkability invariant**; residents authenticate eligibility only and never sign their choice; **paper ballot is a first-class equal path**. +- An immutable complete ballot log, deterministic committee recomputation, voter inclusion proofs, and a reviewed receipt-freeness mechanism. +- A deployed service/event contract, non-operator key ceremony, resident/accessibility review, counsel approval, and signed activation evidence. `vote.signed.v1` remains a disabled non-contractual scaffold. **Documented alternative (unbuilt):** bicameral two-house dual-consent (Token House `$CAT` + Citizen House `$WORK`). ⚠️ The "~500→~750 token" collusion simulation and the Constitution quorum numbers (20/25/60%) are **FABRICATED/unsourced** (Fordham `07` §3.1) and must not be cited as binding. @@ -105,8 +111,9 @@ So the built tokens are the design the board-facing docs say they replaced. Nota |---|---|---|---| | `$CAT / $WORK / $CRED` trinity | Authoritative (newest DAO docs) | Zero code | **Specced-not-built (high)** | | Soul-bound reputation | Required | GRO freely transferable; no SBT | **Specced-not-built / contradiction (high)** | -| Equal-weight vote + roll quorum | Required | Stake-weighted, flat threshold | **Specced-not-built / contradiction (high)** | -| Committee threshold-signing | Required | Single-operator HMAC | **Specced-not-built (high)** | +| Equal-weight vote + roll quorum | Required | Tested ToKenism model in PR #64; no deployed election service | **Model implemented / activation blocked** | +| Committee threshold-signing | Required | Tested Ed25519 multisig model in PR #64; no key ceremony or service | **Model implemented / activation blocked** | +| Eligibility, ballot-set proofs, paper parity, receipt-freeness | Required | No complete runtime path | **Specced-not-built (high)** | | Bicameral two-house passage | Required | Single-chamber | **Specced-not-built** | | ERC-1155 machine-time, OEE multiplier, <15% cap | Required (Fordham) | None | **Specced-not-built** | | Sector variants, Fame Coin | Documented | None | **Specced-not-built** | @@ -124,11 +131,11 @@ So the built tokens are the design the board-facing docs say they replaced. Nota ## Contradictions to resolve 1. **Token suite** (resolve first): documented `$CAT/$WORK/$CRED` vs built `FoodUSD+GroToken`. No mapping doc. Pick one canonical roster. -2. **Governance basis** (disqualifying for pilot): stake-weighted CoopGovernor vs required equal-weight one-member-one-vote. +2. **Governance basis:** stake-weighted CoopGovernor remains, while the equal-weight replacement exists only as a separate rehearsal model; no binding service is activated. 3. **Soulbound:** GRO freely transferable vs required non-transferable reputation. 4. **Distribution:** Gaussian random live vs required Dirichlet-by-attribution. 5. **Fabricated evidence:** collusion simulation + quorum numbers are unsourced yet appear as MUST boundaries. -6. **Signing primitive:** one HMAC underwriting both trails and ballots is operator-forgeable — self-contradiction inside the built package. +6. **Signing primitive:** HMAC is retained for operator-controlled trails only; the Ed25519 committee model replaces it for tally attestation, but the production key ceremony and service are unbuilt. 7. **Receipt/coercion:** verifiable individual receipt framed as protection vs shown to be a coercion tool. 8. **Maturity claim:** "L5 production DAO" vs "unaudited Research Track / nothing built." 9. **Built-vs-built:** `.sol` flat threshold vs TS model's (capital-weighted) quorum floor. @@ -169,7 +176,7 @@ D12 (every contributor non-zero) holds under all settings. The distribution itse 2. **LoyaltyPoints + RewardsPool** — keep / deprecate / spec? *(still open — a dedicated increment: needs staking activity in scenarios + GRO-minting plumbing to show effect; RewardsPool re-couples reward to stake, so the sweep will show it raising concentration.)* 3. ~~**The one wire**~~ ✅ **DONE (PR #55)** — `processWeek` distributes GRO by kept-commitment Dirichlet attribution; Gaussian retired from the sim flow. 4. ~~**GroToken soulbound**~~ 🎛️ **PARAMETERIZED (PR #56)** — `soulbound` knob on GroToken (default off = transferable). Toggle to make earned GRO non-transferable ($WORK direction). Left OPEN as a variable. -5. **Governance replacement** — build equal-weight Ballot + deterministic Tally + committee threshold-signing, or keep CoopGovernor strictly non-binding sim? *(still open — larger build.)* +5. **Governance replacement** — the bounded rehearsal model is implemented: the equal-weight deterministic tally and hardened Ed25519 committee-attestation model merged in ToKenism PR #64 (`d17ea07b`); CoopGovernor stays non-binding contrast. A complete ballot log/inclusion-proof path, paper parity, deployed service, committee ceremony, resident review, and counsel-gated binding activation remain open. 6. ~~**Concentration cap**~~ 🎛️ **PARAMETERIZED (PR #58)** — `maxConcentration` knob (water-filling; bounds topShare, lowers Gini, raises the floor, D12 held). Supply-cap (invented 1,000,000) ratify/remove still open. 7. ~~**FoodUSD transferability**~~ 🎛️ **PARAMETERIZED (PR #59)** — `vendorLocked` + `approvedVendors` knob (default free-transfer). Toggle to narrow toward the spend-limited `$CRED` model; internal escrow/refund exempt. 8. **Commitment remediation** — define the broken-commitment dispute-cure economy. diff --git a/pmoves/docs/architecture/TOKEN_STRUCTURE_REFRESH.md b/pmoves/docs/architecture/TOKEN_STRUCTURE_REFRESH.md index 9c4ff2ac12..9080bd37f7 100644 --- a/pmoves/docs/architecture/TOKEN_STRUCTURE_REFRESH.md +++ b/pmoves/docs/architecture/TOKEN_STRUCTURE_REFRESH.md @@ -102,23 +102,23 @@ connected to anything that matters.** The plutocratic mechanism is connected. Th ## 5. Why B leads to A (the important half) -The economic engine (Mode B — consensual, attributable formation) is *prior to* and *more important -than* the ballot (Mode A). A group that has already **formed by agreed commitment and accrued real, -attributed contribution** is, by construction, a roster of real participants with demonstrated standing. -That roster **is** the eligible roll a quorum or union vote needs — "real quorum formed by real voters -who reside," "real lemonade based on real demand." So building B correctly (this refresh) is what makes -A legitimate and defensible: the eligibility of Mode A is a *read* of the commitments recorded in -Mode B — while still honoring the invariant that the two modes' **keys stay unlinkable** and a contested -secret ballot never runs in Mode B (see `08:§8`). +The economic engine (Mode B — consensual, attributable formation) comes before the ballot (Mode A) +as a way to demonstrate activity and standing. Its commitment and attribution records **do not prove +residency, membership, or legal voting eligibility** and therefore are not the Mode-A eligible roll. +Mode A requires an independently governed, committee-attested eligibility credential and roll. Mode-B +records may inform a human eligibility review only through a privacy-preserving bridge that preserves +the modes' **unlinkable keys**; they must never automatically admit or exclude a voter, and a contested +secret ballot must never run in Mode B (see `08:§8`). ## 6. Real vs aspirational (honesty) -Built today: the Dirichlet primitive; the tokenism sim service (:8103); FoodUSD + GroupPurchase escrow; -Firefly calibration/export modules. **Not wired / aspirational:** Dirichlet→distribution (Gaussian -today); soul-bound credit (doc-only, no SBT code); `shape.trace/profile.*` subjects (referenced, not in -the catalog); live Firefly settlement execution; `RewardsPool`/`LoyaltyPoints` contracts (named, not -built). The refresh is mostly **connecting and constraining what exists**, plus the new commitment -primitive — not a green-field token launch. +Built today: the Dirichlet primitive; the tokenism simulator on host `:8103` (`GET /healthz`), which +publishes `tokenism.simulation.result.v1`; the cataloged `shape.trace.recorded.v1` and +`shape.profile.updated.v1` contracts; FoodUSD + GroupPurchase escrow; and Firefly calibration/export +modules. **Not wired / aspirational:** Dirichlet→distribution in every production path; soul-bound +credit (doc-only, no SBT code); live Firefly settlement execution; and production activation of the +governance rehearsal. The canonical mappings live in `.claude/context/nats-subjects.md`, +`.claude/context/services-catalog.md`, and `pmoves/contracts/topics.json`. ## 7. Open decisions + legal diff --git a/pmoves/docs/pilots/fordham-hill/04-governance-bylaws-scaffold.md b/pmoves/docs/pilots/fordham-hill/04-governance-bylaws-scaffold.md index 67729e5c58..a033f029c7 100644 --- a/pmoves/docs/pilots/fordham-hill/04-governance-bylaws-scaffold.md +++ b/pmoves/docs/pilots/fordham-hill/04-governance-bylaws-scaffold.md @@ -4,11 +4,18 @@ > **DRAFT — REQUIRES LEGAL REVIEW.** This document is an engineering + process scaffold, not legal advice and not an adopted instrument. Every clause touching bylaws, board transition, quorum, notice, or voting validity is marked and MUST be reviewed by New York cooperative-corporation counsel and adopted through the co-op's own statutory amendment procedure before it has any binding effect. Nothing here certifies an election result. +> **SECURITY RECONCILIATION:** The original HMAC ballot-receipt and shared-roster design below was +> rejected by decision records `07` and `08`. HMAC remains agent-trail integrity only; +> `vote.signed.v1` is disabled/non-contractual; contribution records are not legal eligibility; and +> no election path is active. The corrected target uses an independently attested roll, a complete +> immutable ballot set with inclusion evidence, committee Ed25519 tally attestation, paper parity, +> and a separately reviewed receipt-freeness mechanism. + --- ## 0. Boundary statement (read first) -The fraud/mismanagement investigation into the outgoing board and management company is **human-led** — driven by **PMOVES-mike** and the **Missing Link** node. This platform and everything below it provide **transparency and auditable records only**: tamper-evident vote receipts, a deterministic quorum tally, and an append-only audit log. The software **makes no accusations, reaches no findings, and adjudicates nothing**. Investigators may *use* the auditable records as evidence; the records do not *produce* conclusions. This boundary is a design constraint, not a disclaimer — the signing/tally components are built to attest "who voted, when, on what," and deliberately stop there. +The fraud/mismanagement investigation into the outgoing board and management company is **human-led** — driven by **PMOVES-mike** and the **Missing Link** node. This platform provides **transparency and rehearsal models only**. The software **makes no accusations, reaches no findings, adjudicates nothing, and currently produces no binding ballot evidence**. Any future audit record must preserve ballot secrecy and be accepted only after legal, resident, and election-committee review. --- @@ -50,34 +57,34 @@ Resident (phone/laptop, no wallet, no gas) [Tally Service] (NEW — deterministic, "tool can tool") • counts one accepted signed ballot per eligible unit • applies the BYLAW quorum % against the eligible roll size - • emits a signed audit report (sign_cgp over the tally) + • emits a committee-attested audit report after independent recomputation │ ▼ -[Audit Log] append-only, publicly verifiable receipts (transparency-only) +[Audit Log] append-only ballot-set commitment + inclusion proofs (unbuilt) ``` Grounding for each reused piece: -- **Signing:** `sign_cgp()` in `chit_security.py:72` is the single source of truth for HMAC signing; `sign_trail.py:33` is the existing CLI caller. A resident ballot is just a different CGP payload signed by the same primitive → a **tamper-evident vote receipt** with no wallet, gas, or blockchain. -- **Transport:** `sign_trail.py` already stages publishes to `chit.signed.v1` on the mesh bus (skill `.claude/skills/pmoves-chit-sign/SKILL.md`). A `vote.signed.v1` subject is the direct analog. -- **Identity:** issue each eligible resident a **signing identity card** in the same shape as `signing_identity_cards.yaml` (today keyed by agent). One card per voting unit = the cryptographic basis for one-unit-one-vote. -- **Roll:** `users.yaml:humans` becomes the eligible-voter roll the quorum % is computed against (`users.yaml:19-26` already reserves the template rows). +- **Signing:** `sign_cgp()` HMAC is valid for operator-controlled agent trails only. The rehearsal tally model uses distinct Ed25519 committee signatures, while a production non-operator key ceremony remains unbuilt. +- **Transport:** `vote.signed.v1` is a disabled, non-contractual room label with no schema, publisher, or service owner. It is not a direct analog of `chit.signed.v1` until an interface and activation review land. +- **Identity:** agent signing cards cannot establish resident voting eligibility. A future `voter-card.v1` must be election-scoped, committee-issued, human-witnessed, and unlinkable from contribution/token identity. +- **Roll:** `users.yaml:humans` is a one-entry template, not a legal voter roll. An independently governed committee process must establish residency and membership before quorum math is meaningful. ### 1.3 Proposal lifecycle (transparent, auditable) 1. **Draft** — proposal authored, classified (see amendment clause 2.5), notice window set per bylaw. 2. **Notice / comment** — published to all residents over the mesh; open comment period (the constitution's amendment model already uses a 2-week comment window, `Cataclysm_DAO_Constitution_v0.1.md:49`). -3. **Open vote** — ballots signed to `vote.signed.v1`; each resident receives their own receipt hash. +3. **Open vote** — future ballot intake writes to an immutable ballot set; no voter signs their choice and no active `vote.signed.v1` publisher exists. 4. **Close** — voting window ends; no further ballots accepted. 5. **Tally** — deterministic count, quorum-% check against roll, majority/supermajority per class. -6. **Publish audit report** — signed tally + list of receipt hashes (not identities in the public view) so any resident can verify their vote was counted and the total is reproducible. +6. **Publish audit report** — after independent deterministic recomputation, publish the committee-attested tally, ballot-set commitment, and privacy-preserving inclusion proof. Receipt-freeness still requires a separate reviewed mechanism. 7. **Archive** — immutable record retained for the co-op's books and for investigators. ### 1.4 What must be BUILT (gaps — none of this ships today) - **Ballot service + Tally service** — grep of `pmoves/services` for `quorum|ballot|castVote|proposal` returns nothing; the only vote engine is the on-chain governor. These are net-new (small, deterministic, mesh-native). -- **Equal-weight voting** — no one-member/one-unit path exists in code; the SBT/`$WORK` "Citizen House" weighting described in the constitution has **no implementation** (only `GroToken/GroVault/FoodUSD/GroupPurchase` exist). -- **Percentage-of-roll quorum** — must replace the flat `proposalThreshold` count with `count(accepted ballots) / count(eligible units) >= bylaw_quorum_pct`. -- **`vote.signed.v1` schema + per-resident card issuance + tally/audit generator** — the sign primitive today emits `agent.graphiti.signed.v1`, not ballots. +- **Equal-weight voting model** — implemented/tested in the ToKenism rehearsal; no election service or binding activation exists. The SBT/`$WORK` "Citizen House" remains unbuilt. +- **Percentage-of-roll quorum model** — implemented against a proposal-snapshotted roll; the legal roll source and production service remain unbuilt. +- **Ballot contract + evidence path** — define any future subject/schema/service together with committee-issued eligibility, immutable ballot-set commitment, inclusion proofs, receipt-freeness, paper merge, and tally/audit generation. `vote.signed.v1` is not currently contractual. - **Proxy / absentee / meeting-quorum tracking** — standard for a co-op annual meeting and a board transition; absent everywhere in the repo. Required before a real election. - **Populated roll + Committee on Elders as a governance actor** — see Part 2.2. @@ -127,4 +134,4 @@ Grounding for each reused piece: 4. **Build ballot + deterministic tally services** — mesh-native, wallet-free, publishing signed audit reports. 5. **Counsel review + statutory adoption** — notice, quorum, supermajority per the co-op's real procedure. Only after this does anything bind. -Throughout: the platform attests and tallies; **it never investigates or concludes.** That remains with PMOVES-mike + Missing Link. \ No newline at end of file +Throughout: the platform attests and tallies; **it never investigates or concludes.** That remains with PMOVES-mike + Missing Link. diff --git a/pmoves/docs/pilots/fordham-hill/05-room-agents-mint-specs.md b/pmoves/docs/pilots/fordham-hill/05-room-agents-mint-specs.md index cfd8ed6195..84a7eaeeec 100644 --- a/pmoves/docs/pilots/fordham-hill/05-room-agents-mint-specs.md +++ b/pmoves/docs/pilots/fordham-hill/05-room-agents-mint-specs.md @@ -101,8 +101,8 @@ metadata: tags: [fordham-hill, onboarding, mesh, voter-roll, community-pilot] spec: role: >- - Enroll residents onto the community mesh and record them on the eligible-voter roll — - the single roster YAML that is both the contribution ledger and the ballot roll (README.md:40). + Enroll residents onto the community mesh and stage committee-reviewed eligibility evidence. + Contribution records and the roster YAML do not by themselves establish the legal ballot roll. team_ref: fordham-community node_affinity: [kvm4-1, kvm4-2, kvm2] model: @@ -111,7 +111,7 @@ spec: fallback: ollama capabilities: - mesh_enrollment_token # fleet:enroll — CHIT-signed device enrollment token - - voter_roll_append # write resident row into roster users.yaml (the roll) + - voter_roll_candidate # stage evidence for committee review; never self-authorize eligibility - consent_capture # record explicit PII/enrollment consent before any write - committee_on_elders_enroll # enroll Committee rows (commented templates today, README.md:14) - roll_reconcile # diff enrolled vs roster; report the 1-of-N gap honestly diff --git a/pmoves/docs/pilots/fordham-hill/08-voter-identity-key-custody.md b/pmoves/docs/pilots/fordham-hill/08-voter-identity-key-custody.md index cf404dfa13..6eff034b4f 100644 --- a/pmoves/docs/pilots/fordham-hill/08-voter-identity-key-custody.md +++ b/pmoves/docs/pilots/fordham-hill/08-voter-identity-key-custody.md @@ -41,7 +41,7 @@ decides who can vote, and the forgeable step is enrollment, not signing. The cor |-----------|-------------------------|-----------------------------------| | The operator / whoever runs the state authority | Add, drop, or alter ballots; manufacture a tally | No single party can sign a valid tally alone → **committee threshold key**, not one operator secret | | The operator, at *enrollment* | Bind a key it controls to a resident; deny/duplicate eligibility | Enrollment authority sits with a **non-operator committee**, human-witnessed, on an append-only committee-signed log | -| A coercer (someone with power over a resident) | Compel a resident to prove how they voted | Receipt proves *that* a vote counted, never *how* → **residents never sign their choice**; verifiability comes from the nonce commitment | +| A coercer (someone with power over a resident) | Compel a resident to prove how they voted | **Residents never sign their choice**; a nonce commitment can support inclusion checking, but receipt-freeness additionally requires revoting, a time-limited verification window, or an equivalent reviewed mechanism | | An outside attacker / a shared or lost device | Steal a credential and vote as someone | Eligibility credential is election-scoped and unlinked to the cast ballot; a lost device is not a lost franchise (paper equal path) | The auditors this must convince are external and non-trusting: the Attorney General, a bank, and a @@ -67,7 +67,7 @@ Everything else follows from this one line: | Option | Where the private key lives | Strength | Cost / caveat | |--------|-----------------------------|----------|---------------| | **A. `localStorage` Ed25519** (ClawZ as-is) | Browser JS storage, plaintext | Weak — XSS-exfiltratable, single-device, lost on cache clear | Zero new work; **rejected as primary** | -| **B. WebAuthn / passkey** (platform authenticator) | Device secure enclave / TPM, **non-exportable** | Strongest — XSS-proof, phishing-resistant, syncs across the resident's own devices | No npm dep needed; verification is over `authData ‖ SHA-256(clientDataJSON)`; default alg P-256 (Ed25519 only on some authenticators); needs enrollment | +| **B. WebAuthn / passkey** (platform authenticator) | Device secure enclave / TPM, normally **non-exportable** | Strong resistance to key export and phishing; does **not** make the relying-party page or authenticated session XSS-proof; device sync depends on the platform/provider | No npm dep needed; verification is over `authData ‖ SHA-256(clientDataJSON)`; default alg P-256 (Ed25519 only on some authenticators); needs enrollment | | **C. Wrapped Ed25519** (`@noble/ed25519` + WebCrypto non-extractable / passphrase-encrypted) | Browser, but encrypted at rest | Medium — resists casual theft, gives raw Ed25519 over our netstring preimage | We own custody + recovery; passphrase UX for elderly residents is real friction | | **D. Printed recovery card** (public-key fingerprint + recovery secret / QR) | Paper, resident-held | Complements A/B/C — survives device loss, fits in-person enrollment | Physical issuance + secure printing; not a signing method on its own | @@ -80,8 +80,10 @@ wrong variable. The private key's *storage location* matters far less than three 1. **Signing your choice defeats the secret ballot.** A voter signature over the choice is a transferable, publicly-verifiable proof of *how* someone voted — exactly the coercion receipt the `pm-ballot` scheme spends three mitigations removing (strip `voterId`/`choice`, omit `ts`, - seal + hash-order the log). A coercer says "unlock your key and sign `yes` in front of me." The - nonce commitment is coercion-resistant *because no voter key signs the choice*. + seal + hash-order the log). A coercer says "unlock your key and sign `yes` in front of me." Omitting + the voter signature removes that direct proof, but a nonce commitment provides individual inclusion + evidence rather than receipt-freeness. A reviewed revoting rule, time-limited verification window, + or equivalent mechanism is still required before calling the system coercion-resistant. 2. **Enrollment, not signing, is the integrity surface — and the operator controls it.** A client-side key stops the operator forging a *signature*, but does nothing to stop whoever writes the eligibility registry from binding a key *it* generated to a resident's name (then it can forge @@ -97,7 +99,8 @@ wrong variable. The private key's *storage location* matters far less than three **Residents authenticate *eligibility*; they do not sign their *choice*. The ballot content / tally is signed by an *election-committee threshold key* (M-of-N, asymmetric) so no single party — -operator included — can forge, without manufacturing a coercion receipt. A paper ballot is a +operator included — can forge. This does not itself establish receipt-freeness; that remains a separate +protocol and procedural gate. A paper ballot is a first-class equal path, not a fallback. `voter-card.v1` is an *eligibility credential* (public), committee-issued and human-witnessed, deliberately **decoupled from Archon minting and from the token structure**.** @@ -110,9 +113,10 @@ Why each piece: not touch the plutocratic on-chain governor (`CoopGovernor.sol:72`, stake-weighted — unusable for one-member-one-vote per `README:§Open decisions`). 2. **Eligibility is separated from ballot content** — a credential proves a resident *may* vote at - booth-entry; it is never linked to the cast ballot. **Individual verifiability is already provided - by the nonce commitment — no voter signature is required for a resident to confirm their vote - counted.** + booth-entry; it is never linked to the cast ballot. A nonce commitment supports individual + verifiability only when the voter also receives a trustworthy inclusion proof against a published, + append-only ballot-set commitment. Neither the inclusion-proof service nor a trusted bulletin-board + procedure is implemented today, and no voter signature is added as a substitute. 3. **Enrollment is committee-controlled, human-witnessed, non-operator** — a neutral scrutineer body the contesting side trusts writes the registry, with an append-only, committee-signed eligibility log. Client-side keygen alone cannot prove the enroller is the named resident; a witness must. @@ -128,6 +132,11 @@ Why each piece: **Mode B**, and there it is **raw Ed25519 over the netstring preimage**, never WebAuthn (dead on the co-op LAN with no secure context; drags device-linkable credential-ID + signature-counter into the receipt). +7. **The committee verifies the ballot set before signing** — committee members must recompute the + tally deterministically from the complete immutable ballot log, reconcile paper ballots, and verify + the published ballot-set commitment/inclusion evidence. They must reject an operator-supplied tally + or ballot set that cannot be independently reproduced; threshold signatures authenticate an audited + result, not an unchecked operator assertion. What survives from rev 1: the load-bearing principle (§3 — no private key server-side) still holds; a `voter-card.v1` still holds *public material only* and stays separate from `signing-card.v1`; and the @@ -144,9 +153,10 @@ anchor for both enrollment and tally signing. authenticates eligibility ──▶ witnesses enrollment, writes registry ──────▶ voter-card.v1 registry (Supabase) (credential proves MAY append-only eligibility log vote; not linked to choice) (committee-signed) - casts vote → nonce-commitment threshold-signs the tally / ballot log ─────▶ signed-receipt log (JuiceFS/S3) - receipt (already verifiable, (no single party can forge; verifiers vote.signed.v1 (NATS, scaffolded) - no signature needed) check the committee public key) Tally service (spec, unbuilt — 04) + casts vote → nonce-commitment recomputes full ballot set, then signs ─────▶ append-only audit log (JuiceFS/S3) + (inclusion proof unbuilt; (no single party can forge; verifiers vote.signed.v1 (disabled, + no voter signature) check the committee public key) non-contractual scaffold) + Tally model exists; service unbuilt PAPER BALLOT (equal path) ─────────────────────────────────────────────────▶ counted into the same tally ``` @@ -156,6 +166,10 @@ store, mid-cutover per `JUICEFS_OBJECT_STORE_MIGRATION.md`) holds the **audit lo **public eligibility registry** — neither holds a private key, and the **tally-signing key is the committee's, split M-of-N**, never a single operator secret. +`vote.signed.v1` is cataloged only as a Fordham rehearsal label and is gated `enabled:false`. It has no +event schema in `pmoves/contracts`, no active publisher, and no service/health-check owner; it is not a +contractual NATS interface until those artifacts and the activation review land together. + ## 7. Do NOT mint the voter card through Archon (reversed from rev 1) Rev 1 proposed minting the voter card through Archon's agent pipeline (`archon.mint.agent.v1` → QA gate @@ -193,14 +207,14 @@ central danger. | Does a member sign their choice? | **No** — a signature would be a coercion receipt | **Yes** — members *want* attributable proof they participated | | Attribution / token linkage | **Decoupled** — no link to contribution/wealth identity | **On** — this is the point: shape attribution → credit → wealth | | Signing authority for the outcome | Committee **threshold** key (no single party forges) | The group co-signs its own formation | -| Secrecy | Secret ballot, coercion-resistant | Public / attributable by design | +| Secrecy | Secret-ballot target; receipt-freeness mechanism still counsel/protocol-gated | Public / attributable by design | **Mode B is grounded in primitives that already exist:** *shape attribution* credits contributions via **Dirichlet-weighted CGP packets** (`.claude/context/geometry-nats-subjects.md`), fed by -`shape.trace.recorded.v1` → `shape.profile.updated.v1`, with SBT (soul-bound token) minting for the -credit. So "sign to form the group, run the stand, get credit even for a one-off pop-up" maps directly -onto: co-sign formation → each member's contribution is shape-attributed (Dirichlet CGP) → exports to -`pmoves-wealth` (Firefly). This is the desirable coupling — it is the product. +`shape.trace.recorded.v1` → `shape.profile.updated.v1`. Those subjects and the simulator are cataloged; +SBT (soul-bound token) minting and live Firefly settlement remain unbuilt/activation-gated. Thus the +current executable claim is attribution simulation and export, not resident credit issuance or settled +wealth. That Mode-B coupling remains a product direction, not evidence of Mode-A legal eligibility. **The invariant (this is the load-bearing rule):** @@ -227,9 +241,11 @@ corner. 3. **Only then**, and as a v0.3 lane: define the **committee threshold-signing** scheme for the tally, the **eligibility credential** (public, election-scoped, committee-issued, human-witnessed — *not* Archon-minted), the **paper-parity** merge, and the recovery/enrollment operations. -4. The A2UI `pm-ballot` receipt (`#2153`) already gives residents individual verifiability via the - nonce commitment — **no voter signature is added to a secret ballot.** A raw-Ed25519 voter signature - is considered *only* if an explicitly attributable (non-secret) voting mode is ever specced. +4. The A2UI `pm-ballot` receipt (`#2153`) is a gated rehearsal. Its nonce commitment can support + individual verifiability only after a trustworthy append-only ballot-set commitment and inclusion + proof are implemented and reviewed; it does not by itself provide receipt-freeness. **No voter + signature is added to a secret ballot.** A raw-Ed25519 voter signature is considered only if an + explicitly attributable (non-secret) voting mode is ever specced. ## 10. Open operator decisions (new) diff --git a/pmoves/docs/pilots/fordham-hill/README.md b/pmoves/docs/pilots/fordham-hill/README.md index 4aa102c062..55d1c2f3ad 100644 --- a/pmoves/docs/pilots/fordham-hill/README.md +++ b/pmoves/docs/pilots/fordham-hill/README.md @@ -1,19 +1,19 @@ # Fordham Hill Pilot — Convergence Package -> Pool the money you already spend on separate premium internet into a few community-run exit nodes, and the same shared box that makes the connection cheaper and more private also becomes the tamper-evident ledger and ballot box that lets Fordham Hill govern itself — DRAFT, REQUIRES LEGAL REVIEW. +> Pool the money you already spend on separate premium internet into a few community-run exit nodes; the same mesh can host a separately governed election rehearsal, but it is not yet a ballot box or a binding election system — DRAFT, REQUIRES LEGAL REVIEW. ## Executive summary -One shared piece of infrastructure delivers two things Fordham Hill needs at once: a cheaper, more resilient, more private internet arrangement, and the auditable rails for residents to hold public quorum and vote during the board/management transition. The four lanes are not four projects — they are one system seen from four angles. +One shared piece of infrastructure can support a cheaper, more resilient, more private internet arrangement and host auditable governance tooling. The election trust model is deliberately separate from the infrastructure operator, and no current artifact authorizes a public quorum or binding vote during the board/management transition. -WHAT IS PROVEN (measured this session): The fleet already exists and works. Three community KVM exit nodes measured 845/347, 683/704, and 448/372 Mbps of real uplink (kvm2 is the small 4C/8GB node per TOPOLOGY.md:22), ~1,976 Mbps aggregate down. Each node costs $10/mo to run (TOPOLOGY.md:20). Each household pays ~$35/mo ($420/yr) SEPARATELY today for a premium internet upcharge. The tamper-evident signing primitive that would receipt a vote already exists and is tested for agent trails (HMAC sign_cgp in sign_trail.py + chit_security.py). Honest measured caveat: on an already-fast Fios line, routing through the tunnel LOWERS peak speed (305/70 through-exit vs 520/101 direct) — pooling does NOT win on raw peak on good lines; it wins on cost, on degraded/expensive links (Starlink), on a stable datacenter IP, on privacy, on resilience, and on adding agents and self-governance. +WHAT IS PROVEN (measured this session): The fleet already exists and works. Three community KVM exit nodes measured 845/347, 683/704, and 448/372 Mbps of real uplink (kvm2 is the small 4C/8GB node per TOPOLOGY.md:22), ~1,976 Mbps aggregate down. Each node costs $10/mo to run (TOPOLOGY.md:20). Each household pays ~$35/mo ($420/yr) SEPARATELY today for a premium internet upcharge. HMAC `sign_cgp` is tested for agent-trail integrity only; it is operator-forgeable and is not admissible as ballot or tally evidence. Honest measured caveat: on an already-fast Fios line, routing through the tunnel LOWERS peak speed (305/70 through-exit vs 520/101 direct) — pooling does NOT win on raw peak on good lines; it wins on cost, on degraded/expensive links (Starlink), on a stable datacenter IP, on privacy, and on resilience. WHAT IS MODELED (projected arithmetic, not yet real): Applying the repo's own 10 Mbps/home budget (FLEET_CAPACITY_ANALYSIS.md:124) to measured throughput, one node conservatively serves ~84 homes and the 3-node fleet ~197 — several times a single Fordham Hill building, before any ISP-style oversubscription. Redirecting the $35 premium into a ~$10/mo pooled due (illustrative, not adopted) models a per-home saving of ~$25/mo ($300/yr, 71%) and a community surplus that grows with every home and every node. Note the repo already frames exit-node service as a $5/user/mo product (FLEET_CAPACITY_ANALYSIS.md:129) — so there are three different dollar anchors in play ($5 product price, $10 illustrative due, $35 current premium) that the operator must reconcile into ONE adopted rate. The tokenism lane shows contribution can be fairly attributed with a real Dirichlet/CHIT formula (12-week decay half-life, dirichlet-weights.ts:58) so that residents who host a node or share uplink earn recognized weight without passive households ever dropping to zero. WHAT IS SCAFFOLDED (designed, needs humans before any binding use): The governance layer is architecture, not a shipped election system. The eligible-voter roll today lists one person (users.yaml:9) with resident/Committee-on-Elders rows still commented templates. The on-chain governor is plutocratic quadratic-stake voting (CoopGovernor.sol:72) with a flat numeric quorum (CoopGovernor.sol:96) — it CANNOT express one-member-one-vote or a quorum as a percentage of the eligible roll, so it must NOT ship as-is for a board election. Two tokenism honesty flags: the sim ignores localEconomicActivities (schema-valid but inert) and the Dirichlet model is not wired into token distribution. Every bylaw clause is DRAFT pending NY cooperative-corporation counsel. -THE CONVERGENCE: The dollars the capacity lane saves are the dollars the wealth lane books as community surplus; the contribution the tokenism lane attributes is what earns a resident standing; and the governance lane is how the co-op votes — using the same mesh and the same signing key — on how that surplus and standing are spent. Cheaper internet funds the commons; self-governance decides the commons; both run on one lattice. The fraud investigation stays human-led (PMOVES-mike + Missing Link); the platform provides transparency and auditable records only, never accusations. +THE CONVERGENCE: The dollars the capacity lane saves are the dollars the wealth lane books as community surplus, while the tokenism lane records contribution. Governance may use the same transport mesh, but ballot eligibility is independently attested and the tally uses a distinct non-operator committee trust path — never the agent-trail HMAC key. Cheaper internet may fund the commons; only a legally valid, human-governed process can decide the commons. The fraud investigation stays human-led (PMOVES-mike + Missing Link); the platform provides transparency and auditable records only, never accusations. ## Package @@ -24,8 +24,8 @@ THE CONVERGENCE: The dollars the capacity lane saves are the dollars the wealth 4. 4. Capacity (MODELED) — homes-per-node at the repo's own 10 Mbps budget: ~84/node, ~197 fleet conservative, up to ~338/~790 at ISP-typical oversubscription. Several times one building's worth of homes. 5. 5. Wealth (MODELED) — illustrative Firefly III co-op ledger: $35 premium in, ~$10 pooled due, ~$25/mo ($300/yr, 71%) per-home saving, community surplus that scales with N. Every line maps to a real Firefly account type. All figures illustrative. 6. 6. Tokenism (MODELED + FLAGGED) — runnable A/B co-op-vs-status-quo scenario; real Dirichlet/CHIT attribution splits a contribution pool fairly (12-week decay, passive homes never zero). Two honesty flags named: localEconomicActivities inert, Dirichlet not yet wired to token distribution. -7. 7. Governance (SCAFFOLDED — DRAFT/LEGAL) — resident public-quorum + e-voting architecture on real PMOVES primitives (HMAC vote receipts, mesh/NATS transport, roster YAML as the roll). Gaps stated plainly: roll has 1 of N, on-chain governor is plutocratic & flat-quorum (do not ship for board election), bylaw clauses all DRAFT. -8. 8. Convergence — the single diagram: saved dollars -> booked surplus -> attributed contribution -> governed vote, all on one mesh + one signing key. Cheaper internet funds the commons; self-governance decides it. +7. 7. Governance (SCAFFOLDED — DRAFT/LEGAL) — equal-weight tally and committee-signing models exist in the ToKenism rehearsal, while `vote.signed.v1` remains disabled and non-contractual (no event schema, publisher, or service owner). The roster YAML is not a legal eligibility roll; no binding election path is active. +8. 8. Convergence — the single diagram: saved dollars -> booked surplus -> attributed contribution -> separately governed vote. The lanes may share transport, but Mode-A eligibility keys and committee tally keys stay unlinkable from Mode-B attribution and agent-trail HMAC. 9. 9. Open Operator Decisions — the numbers and choices only the Committee/board can set (adopted rate, real home count, one-member-one-vote basis, quorum %). 10. 10. Legal Review Register — every DRAFT/binding item routed to NY co-op counsel before any quorum or vote relies on it. 11. 11. Appendix — verified source citations (path:line) and the proven/modeled/scaffolded ledger. @@ -41,8 +41,8 @@ THE CONVERGENCE: The dollars the capacity lane saves are the dollars the wealth - The saving and the surplus are the same dollars. The ~$25/mo per home the capacity lane frees up (by replacing the $35 premium with a ~$10 pooled cost) is exactly what the wealth lane books as community surplus — one flow of money, two lanes describing it. This is the entire pooling thesis in one sentence: the money doesn't leave the building. - Three different dollar anchors are in play and must be reconciled to ONE adopted rate. The repo prices exit-node service at $5/user/mo (FLEET_CAPACITY_ANALYSIS.md:129), the wealth lane models a $10/mo due, and the field datum for what homes pay now is $35/mo. These are not contradictions but they are not yet one number — the co-op must adopt a single rate and every downstream statement should key to it. - The network effect is literal, not marketing: aggregate capacity (~1,976 Mbps today) grows with every node, AND every added host raises the Dirichlet attribution numerator and the modeled surplus for the WHOLE co-op. The same act — plugging in another node — strengthens the mesh, the books, and a resident's earned governance standing simultaneously. -- One signing key underwrites both trust surfaces. The HMAC sign_cgp primitive (sign_trail.py:33 + chit_security.py:72) that makes agent trails tamper-evident is the same primitive proposed to receipt a resident vote (vote.signed.v1). The co-op does not need a blockchain or wallets to have auditable ballots — it reuses a real, tested, wallet-free mechanism. -- Contribution attribution and vote eligibility are the same roster. The roster YAML that is the eligible-voter roll is also where hosting/uplink/coverage contribution is recorded — so 'who may vote' and 'who contributed' are two reads of one source of truth, which is exactly what a co-op transition needs to be defensible. +- The former one-key proposal is rejected. HMAC `sign_cgp` remains valid for operator-controlled agent trails, but it cannot underwrite a contested ballot. A non-operator committee must verify the complete ballot set and threshold-sign the deterministic tally with asymmetric keys. +- Contribution attribution is not vote eligibility. Mode-B hosting/uplink records may support a human review, but only an independently governed, committee-attested Mode-A roll can establish residency and membership without coupling ballot identity to wealth/contribution identity. - The honest speed caveat is a governance asset, not a weakness. Admitting that tunneling lowers peak on a good Fios line (305/70 vs 520/101) is the kind of measured, non-inflated claim that builds Committee-on-Elders trust — the pitch is resilience/cost/privacy/self-rule, and being straight about where pooling does NOT win is what makes the rest credible. - Capacity headroom de-risks governance adoption. Because one node conservatively models ~84 homes and the fleet ~197, the platform can carry an entire building's worth of residents for quorum/voting traffic (tiny bandwidth) with capacity to spare — the governance use case is nearly free on infrastructure already justified by the internet-cost case. @@ -65,10 +65,10 @@ THE CONVERGENCE: The dollars the capacity lane saves are the dollars the wealth - ALL dollar/rate claims are DRAFT — REQUIRES LEGAL/ACCOUNTING REVIEW: the $35/mo premium counterfactual, the ~$10 pooled due, per-home savings, community surplus, and every Firefly statement figure must be reviewed before any quorum or voting materials rely on them. - BYLAWS AMENDMENT CLAUSES: every clause enshrining the Committee on Elders and resident e-voting is DRAFT and requires NY cooperative-corporation statute review by counsel before adoption or filing. - VOTING BASIS & QUORUM LEGALITY: whether one-member-one-vote / unit-vote / share-vote and a roll-percentage quorum comply with the co-op's certificate of incorporation, existing bylaws, and NY Business/Cooperative Corporation Law — counsel must confirm before any binding vote. -- E-VOTING / REMOTE-QUORUM VALIDITY: whether electronically cast, HMAC-receipted ballots (vote.signed.v1) and remote/mesh participation satisfy NY requirements for valid cooperative meetings, notice, and quorum — must be validated before a real board election or bylaw vote. +- E-VOTING / REMOTE-QUORUM VALIDITY: whether a future electronically cast, receipt-free, committee-audited ballot and remote/mesh participation satisfy NY requirements for valid cooperative meetings, notice, and quorum — must be validated before a real board election or bylaw vote. The disabled `vote.signed.v1` rehearsal subject is not evidence of such a system. - BOARD/MANAGEMENT TRANSITION PROCESS: the legal mechanics of replacing the existing board and management company (notice, elections, fiduciary duties, records handover) must be counsel-led; the platform provides auditable records only and must not be represented as conferring legal authority. - FRAUD-INVESTIGATION BOUNDARY: legal confirmation that PMOVES tooling outputs are transparency/audit artifacts only and make no accusations — the investigation stays human-led (PMOVES-mike + Missing Link); avoid any tooling framing that could imply defamation or unauthorized legal conclusions. - TELECOM / ISP TERMS & LIABILITY: whether pooling and reselling/sharing internet via community exit nodes conflicts with residents' ISP terms of service, and the co-op's liability for traffic egressing shared datacenter IPs — counsel + possibly the ISP contracts must be reviewed. - COOPERATIVE ENTITY FOR THE MESH: whether the mesh co-op is a program of the existing housing co-op, a separate entity, or a vendor relationship — affects who books the surplus, tax treatment, and member dues authority; requires legal/accounting structuring. - DATA / PRIVACY & MEMBER RECORDS: the eligible-voter roll and contribution ledger contain resident PII; retention, consent, and privacy handling of the roster and vote receipts need review under applicable NY privacy obligations. -- SECURITIES / TOKEN CHARACTERIZATION: confirm that any GroToken/contribution-attribution mechanism (Dirichlet-weighted pool, on-chain governor) does NOT constitute a security or create securities-law exposure if surfaced to residents — counsel must review before any token concept is presented as member-facing. \ No newline at end of file +- SECURITIES / TOKEN CHARACTERIZATION: confirm that any GroToken/contribution-attribution mechanism (Dirichlet-weighted pool, on-chain governor) does NOT constitute a security or create securities-law exposure if surfaced to residents — counsel must review before any token concept is presented as member-facing.