/** * rGov module — Modular governance decision circuits (GovMods). * * Do-ocratic circuit components for multiplayer collaboration around * shared goals. Wire together governance primitives on a shared canvas: * signoff gates, resource thresholds, tunable knobs, project aggregators, * and amendable circuits. */ import { Hono } from "hono"; import { renderShell } from "../../server/shell"; import { getModuleInfoList } from "../../shared/module"; import type { RSpaceModule } from "../../shared/module"; import { renderLanding } from "./landing"; import { addShapes, getDocumentData } from "../../server/community-store"; const routes = new Hono(); // ── Module page (within a space) ── routes.get("/", (c) => { const space = c.req.param("space") || "demo"; return c.html(renderShell({ title: `${space} — rGov | rSpace`, moduleId: "rgov", spaceSlug: space, modules: getModuleInfoList(), theme: "dark", body: `

⚖️ rGov — GovMods

Do-ocratic circuit components for multiplayer collaboration

Build governance decision circuits by wiring GovMods together on the canvas:

Open Canvas →
`, })); }); // ── API: list gov shapes in a space ── routes.get("/api/shapes", (c) => { return c.json({ info: "Gov shapes are stored in the space's Automerge document. Query the canvas shapes map for types listed below.", types: [ "folk-gov-binary", "folk-gov-threshold", "folk-gov-knob", "folk-gov-project", "folk-gov-amendment", "folk-gov-quadratic", "folk-gov-conviction", "folk-gov-multisig", "folk-gov-sankey", ], }); }); // ── Seed template: example governance circuits ── function seedTemplateGov(space: string) { const docData = getDocumentData(space); const govTypes = [ "folk-gov-binary", "folk-gov-threshold", "folk-gov-knob", "folk-gov-project", "folk-gov-amendment", "folk-gov-quadratic", "folk-gov-conviction", "folk-gov-multisig", "folk-gov-sankey", ]; if (docData?.shapes) { const existing = Object.values(docData.shapes as Record) .filter((s: any) => !s.forgotten && govTypes.includes(s.type)); if (existing.length > 0) return; } const now = Date.now(); // ── Circuit 1: "Build a Climbing Wall" ── // Labor threshold + Capital threshold + Proprietor signoff → Project aggregator const laborId = `gov-labor-${now}`; const capitalId = `gov-capital-${now}`; const signoffId = `gov-signoff-${now}`; const projectId = `gov-project-${now}`; // ── Circuit 2: "Community Event Approval" ── // Budget knob → Attendance threshold, plus Venue signoff → Event project const knobId = `gov-knob-${now}`; const attendId = `gov-attend-${now}`; const venueId = `gov-venue-${now}`; const eventId = `gov-event-${now}`; const baseY = 2600; const shapes: Record[] = [ // ── Circuit 1 shapes ── { id: laborId, type: "folk-gov-threshold", x: 50, y: baseY, width: 240, height: 160, rotation: 0, title: "Labor Contributed", target: 50, unit: "hours", contributions: [ { who: "Alice", amount: 12, timestamp: now - 86400000 }, { who: "Bob", amount: 8, timestamp: now - 43200000 }, ], }, { id: capitalId, type: "folk-gov-threshold", x: 50, y: baseY + 200, width: 240, height: 160, rotation: 0, title: "Capital Raised", target: 3000, unit: "$", contributions: [ { who: "Community Fund", amount: 1500, timestamp: now - 172800000 }, { who: "Sponsor A", amount: 500, timestamp: now - 86400000 }, ], }, { id: signoffId, type: "folk-gov-binary", x: 50, y: baseY + 440, width: 240, height: 120, rotation: 0, title: "Proprietor Approval", assignee: "Dana (proprietor)", satisfied: false, signedBy: "", timestamp: 0, }, { id: projectId, type: "folk-gov-project", x: 400, y: baseY + 140, width: 300, height: 240, rotation: 0, title: "Build a Climbing Wall", description: "Community climbing wall project — requires labor, capital, and proprietor signoff.", status: "active", }, // Arrows wiring Circuit 1 { id: `gov-arrow-labor-${now}`, type: "folk-arrow", x: 0, y: 0, width: 0, height: 0, rotation: 0, sourceId: laborId, targetId: projectId, color: "#0891b2", }, { id: `gov-arrow-capital-${now}`, type: "folk-arrow", x: 0, y: 0, width: 0, height: 0, rotation: 0, sourceId: capitalId, targetId: projectId, color: "#0891b2", }, { id: `gov-arrow-signoff-${now}`, type: "folk-arrow", x: 0, y: 0, width: 0, height: 0, rotation: 0, sourceId: signoffId, targetId: projectId, color: "#7c3aed", }, // ── Circuit 2 shapes ── { id: knobId, type: "folk-gov-knob", x: 800, y: baseY, width: 200, height: 170, rotation: 0, title: "Event Budget", min: 100, max: 5000, step: 100, value: 1500, unit: "$", cooldown: 0, }, { id: attendId, type: "folk-gov-threshold", x: 800, y: baseY + 210, width: 240, height: 160, rotation: 0, title: "RSVPs Collected", target: 20, unit: "people", contributions: [ { who: "Mailing list", amount: 14, timestamp: now - 86400000 }, ], }, { id: venueId, type: "folk-gov-binary", x: 800, y: baseY + 410, width: 240, height: 120, rotation: 0, title: "Venue Confirmed", assignee: "Events Team", satisfied: true, signedBy: "Carlos", timestamp: now - 43200000, }, { id: eventId, type: "folk-gov-project", x: 1140, y: baseY + 140, width: 300, height: 240, rotation: 0, title: "Community Potluck", description: "Monthly community potluck — needs budget, RSVPs, and venue confirmation.", status: "active", }, // Arrows wiring Circuit 2 { id: `gov-arrow-knob-${now}`, type: "folk-arrow", x: 0, y: 0, width: 0, height: 0, rotation: 0, sourceId: knobId, targetId: eventId, color: "#b45309", }, { id: `gov-arrow-attend-${now}`, type: "folk-arrow", x: 0, y: 0, width: 0, height: 0, rotation: 0, sourceId: attendId, targetId: eventId, color: "#0891b2", }, { id: `gov-arrow-venue-${now}`, type: "folk-arrow", x: 0, y: 0, width: 0, height: 0, rotation: 0, sourceId: venueId, targetId: eventId, color: "#7c3aed", }, ]; // ── Circuit 3: "Delegated Budget Approval" ── // Quadratic transform → Conviction gate, plus 3-of-5 Multisig → Project, plus Sankey visualizer const quadId = `gov-quad-${now}`; const convId = `gov-conv-${now}`; const msigId = `gov-msig-${now}`; const budgetProjId = `gov-budgetproj-${now}`; const sankeyId = `gov-sankey-${now}`; const c3BaseY = baseY + 700; shapes.push( // Quadratic weight transform { id: quadId, type: "folk-gov-quadratic", x: 1600, y: c3BaseY, width: 240, height: 160, rotation: 0, title: "Vote Weight Dampener", mode: "sqrt", entries: [ { who: "Whale", raw: 100, effective: 10 }, { who: "Alice", raw: 4, effective: 2 }, { who: "Bob", raw: 1, effective: 1 }, ], }, // Conviction accumulator { id: convId, type: "folk-gov-conviction", x: 1600, y: c3BaseY + 200, width: 240, height: 200, rotation: 0, title: "Community Support", convictionMode: "gate", threshold: 5, stakes: [ { userId: "u1", userName: "Alice", optionId: "gate", weight: 2, since: now - 7200000 }, { userId: "u2", userName: "Bob", optionId: "gate", weight: 1, since: now - 3600000 }, ], }, // Multisig 3-of-5 { id: msigId, type: "folk-gov-multisig", x: 1600, y: c3BaseY + 440, width: 260, height: 220, rotation: 0, title: "Council Approval", requiredM: 3, signers: [ { name: "Alice", signed: true, timestamp: now - 86400000 }, { name: "Bob", signed: true, timestamp: now - 43200000 }, { name: "Carol", signed: false, timestamp: 0 }, { name: "Dave", signed: false, timestamp: 0 }, { name: "Eve", signed: false, timestamp: 0 }, ], }, // Project aggregator { id: budgetProjId, type: "folk-gov-project", x: 1960, y: c3BaseY + 180, width: 300, height: 240, rotation: 0, title: "Delegated Budget Approval", description: "Budget approval with quadratic dampening, time-weighted conviction, and council multisig.", status: "active", }, // Sankey visualizer { id: sankeyId, type: "folk-gov-sankey", x: 2320, y: c3BaseY + 100, width: 380, height: 300, rotation: 0, title: "Governance Flow", }, // Arrows wiring Circuit 3 { id: `gov-arrow-quad-${now}`, type: "folk-arrow", x: 0, y: 0, width: 0, height: 0, rotation: 0, sourceId: quadId, targetId: budgetProjId, color: "#14b8a6", }, { id: `gov-arrow-conv-${now}`, type: "folk-arrow", x: 0, y: 0, width: 0, height: 0, rotation: 0, sourceId: convId, targetId: budgetProjId, color: "#d97706", }, { id: `gov-arrow-msig-${now}`, type: "folk-arrow", x: 0, y: 0, width: 0, height: 0, rotation: 0, sourceId: msigId, targetId: budgetProjId, color: "#6366f1", }, ); addShapes(space, shapes); console.log(`[rGov] Template seeded for "${space}": 3 circuits (13 shapes + 9 arrows)`); } // ── Module export ── export const govModule: RSpaceModule = { id: "rgov", name: "rGov", icon: "⚖️", description: "Modular governance decision circuits (GovMods)", routes, scoping: { defaultScope: "space", userConfigurable: false }, landingPage: renderLanding, seedTemplate: seedTemplateGov, canvasShapes: [ "folk-gov-binary", "folk-gov-threshold", "folk-gov-knob", "folk-gov-project", "folk-gov-amendment", "folk-gov-quadratic", "folk-gov-conviction", "folk-gov-multisig", "folk-gov-sankey", ], canvasToolIds: [ "create_binary_gate", "create_threshold", "create_gov_knob", "create_gov_project", "create_amendment", "create_quadratic_transform", "create_conviction_gate", "create_multisig_gate", "create_sankey_visualizer", ], onboardingActions: [ { label: "Build a Circuit", icon: "⚖️", description: "Create a governance decision circuit on the canvas", type: 'create', href: '/rgov' }, ], };