# Userland Module Specification — v0.1 Status: Normative for kernel v0.1.x Companion files: `spec/module.schema.json` (machine-checkable schema), `kernel/constitution.md` (the kernel this spec serves) --- ## 1. Purpose and position in the stack The kernel (`kernel/constitution.md`) defines only meta-rules: how rules change, who votes, what quorum means, the right to fork, and the invariants no configuration may override. Everything else — what a group actually decides about, how its money moves, who keeps the minutes — lives in **userland**. A **userland module** is a single configuration document that instantiates the kernel for a concrete group. The same kernel text, parameterized differently, governs a household of six or a DAO of five thousand. The module does not restate the kernel; it fills the kernel's declared parameter slots (kernel Appendix A) and nothing else. The design rule throughout: **optimism in the defaults, paranoia in the bounds.** Every parameter has a kernel-imposed floor or ceiling chosen so that no legal configuration permits the canonical capture moves found in the comparative research (`docs/research/comparative/03-synthesis.md`): bare-majority commons drain, emergency-power entrenchment, quorum starvation, expulsion-as-purge, and exit suppression. ### 1.1 Supremacy and conflict resolution 1. The kernel text is supreme. If a module configuration, however validated, is found to conflict with the kernel text, the kernel governs and the conflicting parameter reverts to its kernel default. 2. This spec restates the Appendix A bounds for convenience. If this spec and the kernel's Appendix A ever diverge, **the kernel's Appendix A is authoritative** and this spec must be corrected by ordinary documentation amendment. 3. The schema (`module.schema.json`) is the machine projection of this spec. A config is **conformant** only if it (a) validates against the schema, (b) satisfies every cross-parameter constraint in §6, and (c) carries the attestations in §7. --- ## 2. Module lifecycle ### 2.1 Instantiation (genesis) A group adopts the kernel by executing the following procedure. The procedure is itself part of conformance; a module without a recorded genesis is not a module, it is a draft. 1. **Draft.** Founders produce a candidate `*.config.json`. 2. **Validate.** The candidate must pass schema validation and all cross-constraints (§6). A failing draft may not be put to a vote — validation is the CI gate, not a courtesy. 3. **Founding review window.** The validated draft is published to all prospective members for at least the config's own `timing.review_hours` (founders are bound by the rules they propose, even before adoption). 4. **Founding ratification.** Prospective members vote, one person one vote. Adoption requires at least the config's own `thresholds.amendment` of votes cast and at least `quorum.amendment` participation of the founding roster. The config must clear its own bar. 5. **Genesis record.** The adopted config, the roster of founding members, the vote tally, and a hash of the kernel version adopted are written as the first entry of the module's ledger. This entry is immutable. ### 2.2 Module versioning (semver for governance) Modules carry their own semantic version in `module.version`, independent of the kernel version they target. | Bump | Definition | Process required | |---|---|---| | **MAJOR** | Any change that removes or narrows a member right, raises any threshold or quorum, lengthens any term, extends emergency scope or duration, tightens expulsion or fork conditions, or changes `membership.admission` | Amendment vote at `thresholds.amendment` / `quorum.amendment`, with review window of **2 × `timing.review_hours`** | | **MINOR** | Any other substantive change: new offices, new commons tiers (within bounds), lowered thresholds, shortened terms, expanded rights | Amendment vote at `thresholds.amendment` / `quorum.amendment`, standard review window | | **PATCH** | Typographical or clarifying changes with no behavioral effect, certified as such by the dispute mechanism | Ordinary vote at `thresholds.ordinary` | Rationale: asymmetric friction. Making future change *harder* is the signature of entrenchment (synthesis finding F-3, "ratchet capture"), so it always pays the major-version price. Making change easier or rights broader is cheap by design. ### 2.3 Kernel upgrades A module declares the kernel range it targets in `kernel.version_constraint` (e.g. `^0.1`). When the kernel ships a new MAJOR version, modules do not upgrade automatically; adopting a new kernel major is itself a module MAJOR change. A module stranded on an unsupported kernel retains full fork rights — kernel maintainers can never force-upgrade userland. This is the constitutional analogue of "no forced migrations." ### 2.4 Dissolution A module dissolves when membership falls below two, or by a vote meeting the expulsion bar (`membership.expulsion.threshold` and quorum), the strictest bar in the config. On dissolution, commons assets divide per `forks.collective.asset_division` applied to the whole membership, and the ledger is archived read-only. --- ## 3. File format A module config is a single UTF-8 JSON document validating against `spec/module.schema.json` (JSON Schema draft 2020-12). All fractions are decimals in `(0, 1]` interpreted against the stated denominator: - **Thresholds** are fractions of **votes cast** (abstentions excluded from the denominator). - **Quorums** are fractions of **eligible members** who must cast a ballot (including explicit abstention) for the vote to bind. - **Treasury fractions** are fractions of the commons balance **at proposal time**. A "yes" prevails when `yes / (yes + no) >= threshold` is **strictly exceeded** for thresholds written above 0.5, and ties always fail. (This is why the schema sets `exclusiveMinimum: 0.5` on thresholds: a literal 0.5 would let a tie pass, which inverts the burden of proof onto the status quo's defenders.) --- ## 4. Parameter reference Every parameter below maps to a kernel Appendix A slot. Bounds shown are the kernel bounds mirrored in the schema. **Attack surface** notes record why the bound exists — each cites the failure mode it forecloses. ### 4.1 `module` — identity | Field | Type / bounds | Notes | |---|---|---| | `name` | string, 1–80 chars | Public identifier | | `version` | semver string | See §2.2 | | `description` | string, 1–500 chars | Plain-language statement of scope | | `scope` | enum: `household`, `community`, `online_community`, `cooperative`, `dao`, `organization`, `federation`, `other` | Informational; drives which example defaults and which benchmark scenario packs apply | | `population_estimate` | integer ≥ 1 | Used by validators to warn (not fail) on configurations pathological at the given scale, e.g. fractional quorums that round to zero people | ### 4.2 `membership` | Field | Type / bounds | Attack surface | |---|---|---| | `admission.method` | enum: `open`, `invitation`, `sponsor`, `vote`, `birthright`, `criteria` | **Sybil flooding** (open admission + low quorum lets an attacker mint voters). Mitigated not by banning `open` but by `probation_days` and quorum floors. v0.1 limitation: one channel per module; multi-channel admission is a v0.2 item. | | `admission.vote_threshold` | fraction, (0.5, 1.0]; required iff method = `vote` | | | `admission.sponsors_required` | integer 1–5; required iff method = `sponsor` | Sponsor chains are auditable in the ledger; >5 becomes a gatekeeping cartel (synthesis F-7, "guild closure") | | `admission.criteria_uri` | string; required iff method = `criteria` | Criteria must be published; secret admission criteria are a kernel invariant violation (legibility) | | `probation_days` | integer 0–365 | Probationary members hold every right **except** voting and fork asset claims. Ceiling at 365: longer probation is a second-class-membership caste (F-9). | | `eligibility_age` | integer 0–21, optional | Only meaningful for households/communities with minors. Members below the age are full members with voice, advocate representation in disputes, and protection of all invariants — they lack only the ballot. Ceiling at 21 mirrors the widest age gate found in the national corpus. | | `expulsion.threshold` | fraction 0.6–1.0; **must be ≥ `thresholds.amendment`** (XC-03) | **Purge attack**: a faction that can expel cheaper than it can amend will expel its way to an amendment majority. Expulsion must always be the most expensive ordinary act in the system. | | `expulsion.quorum` | fraction 0.05–1.0; **must be ≥ `quorum.amendment`** (XC-04) | Same logic applied to participation: no midnight expulsions. | | `expulsion.review_hours` | integer 72–720 | Floor of 72h: due-process invariant requires the subject time to answer. | | `expulsion.subject_excluded` | const `true` | The subject does not vote on their own expulsion; their membership *is* counted in the quorum denominator (they cannot be quorum-starved out either). | | `expulsion.appeal` | const `true` | Kernel due-process invariant. One appeal to the dispute mechanism is non-negotiable. | ### 4.3 `suffrage` | Field | Type / bounds | Attack surface | |---|---|---| | `one_person_one_vote` | const `true` | Kernel invariant. Capital-weighted, reputation-weighted, or tenure-weighted ballots are not expressible in this format, deliberately. | | `ballot.method` | enum: `simple`, `approval`, `ranked_choice`, `score` | Method choice is genuinely free; all four preserve equal weight at issuance. | | `ballot.privacy` | enum: `secret`, `member_visible`, `public` | **Vote buying** prefers `public`; **coercion within small groups** also prefers `public`, but households legitimately choose it for legibility. The kernel does not mandate secrecy; the test suite stresses each choice differently. | | `delegation.enabled` | boolean | Liquid democracy is permitted but caged (below). | | `delegation.max_chain_depth` | integer 1–3; required iff enabled | **Delegation cartels** (F-12): unbounded chains reconstruct capital-weighted voting through accumulation. Depth ≤ 3 keeps every delegated vote within two hops of a human decision. | | `delegation.revocable_instantly` | const `true` | A delegation that cannot be revoked at any moment before ballot close is a sold vote. | | `delegation.expiry_days` | integer 1–365; required iff enabled | Standing delegations must be actively renewed; permanent proxies are dormant capture. | Delegation does **not** violate one-person-one-vote: weight is equal at issuance, and what is delegated is the *exercise*, revocably. The schema encodes the cage; the test suite (next milestone) attacks the cage. ### 4.4 `quorum` | Field | Bounds | Attack surface | |---|---|---| | `ordinary` | fraction 0.05–1.0 | Floor of 0.05: below this, a handful of insomniacs govern (F-2, "quorum capture"). Ceiling of 1.0 permitted but the validator warns above 0.9: **quorum starvation** — a minority blocks everything by staying home — is the dual attack. | | `amendment` | fraction 0.15–1.0; **must be ≥ `ordinary`** (XC-02) | Rule changes must never be easier to attend than ordinary business. | ### 4.5 `thresholds` | Field | Bounds | Attack surface | |---|---|---| | `ordinary` | fraction, exclusiveMin 0.5, max 0.9 | Above 0.9 is a unanimity trap: the status quo becomes unamendable in practice (F-3 inverse, "Polish liberum veto"). | | `amendment` | fraction, exclusiveMin 0.5, max 1.0; **must be ≥ `ordinary`** (XC-01) | The 51%-drain canonical test binds here jointly with commons tiers (XC-10). | Kernel-level amendments (changes to `kernel/constitution.md` itself) are **not** configurable here; the kernel fixes its own thresholds. This section governs only the module's own rules. ### 4.6 `timing` | Field | Bounds | Attack surface | |---|---|---| | `review_hours` | integer 24–2160 | Floor of 24h kills the **midnight amendment** (F-5: rule changes passed before opponents knew they existed). Ceiling of 90 days prevents review-as-veto. | | `voting_window_hours` | integer 24–720 | Floor of 24h: every timezone and shift pattern gets a real chance to vote. | | `resubmission_cooldown_days` | integer 0–180 | **Proposal spam / attrition**: re-running a failed proposal weekly until the opposition tires (F-8). A defeated proposal in substantially similar form waits out the cooldown. | | `results_publication_hours` | integer 1–72 | Results must land in the ledger promptly; delayed certification is itself a stress scenario in the Incumbent Benchmark. | ### 4.7 `emergency` The single most-exploited surface in the comparative corpus (F-1: of the national constitutions analyzed, emergency provisions were the entry point in a majority of the democratic-backsliding cases). The kernel therefore caves this in hard. | Field | Bounds | Attack surface | |---|---|---| | `enabled` | boolean | A module may simply have no emergency powers. Absence is a valid design. | | `provisional_hold_hours` | integer 1–24; required iff enabled | Any single member or empowered office may declare a **provisional hold** (freeze of commons disbursement and pending votes). It dies within 24h unless confirmed. Speed without entrenchment. | | `confirm_threshold` | fraction, exclusiveMin 0.5; required iff enabled | Confirming the hold into a state of emergency takes a real majority of votes cast. | | `max_duration_hours` | integer 1–720; required iff enabled | Hard 30-day ceiling per declaration. | | `max_renewals` | integer 0–2; required iff enabled | Combined with XC-06: total continuous emergency ≤ 720 hours, ever, under any config. | | `renewal_threshold` | fraction, exclusiveMin 0.5; **≥ `confirm_threshold`** (XC-05) | Escalating cost of staying in emergency. The Roman dictatorship expired; the Weimar Article 48 did not. We side with Rome. | | `auto_sunset` | const `true` | Emergencies end by clock, never by vote-to-end. Inaction restores normalcy. | | `invariants_suspendable` | const `false` | No emergency suspends suffrage, fork rights, due process, or the ledger. This is the line. | ### 4.8 `offices` An array (possibly empty) of role definitions. The kernel position: offices are conveniences, not powers — anything an office can do, the membership can do directly or undo. | Field | Bounds | Attack surface | |---|---|---| | `name` | string 1–60 | | | `selection` | enum: `election`, `sortition`, `rotation`, `appointment` | `appointment` requires an appointing office or a vote, recorded in the ledger; self-perpetuating appointment chains are caught by the recall bound below. | | `term_days` | integer 1–730 | Hard 2-year ceiling (F-4, "tenure entrenchment"). | | `max_consecutive_terms` | integer 1–3 | After the limit, one full term out before re-eligibility. | | `recall_threshold` | fraction, exclusiveMin 0.5, max 0.9; **≤ `thresholds.amendment`** (XC-07) | **Court-capture analogue**: if removing an officer costs more than amending the constitution, officers become a super-constitutional class. Recall must never be the hardest act. | | `powers` | array of enum: `convene`, `moderate`, `mediate`, `execute_spending`, `emergency_hold`, `maintain_records`, `represent_externally` | Closed enumeration. Powers not listed here do not exist; "inherent powers" doctrines are how incumbents grew (F-6). `execute_spending` means *executing* already-authorized tiers, never authorizing. | ### 4.9 `commons` | Field | Bounds | Attack surface | |---|---|---| | `exists` | boolean | Modules without shared assets skip the rest. | | `unit` | string; required iff exists | Denomination, descriptive. | | `spend_tiers` | array 1–5 of `{max_fraction, threshold, quorum}`; required iff exists | Per-proposal authorization ladder. `max_fraction` ∈ (0,1], `threshold` ∈ (0.5,1], `quorum` ∈ [0.05,1]. Tiers must ascend in `max_fraction` strictly (XC-08), with non-decreasing `threshold` and `quorum` (XC-09). **A spend exceeding the top tier's `max_fraction` is simply unauthorized** — there is no implicit catch-all. | | — | **XC-10**: any tier with `max_fraction > 0.25` must have `threshold ≥ thresholds.amendment` | This is the schema-level encoding of the project's headline test: *a 51% faction cannot drain the commons under any conformant wording.* Big money moves at constitutional cost. | | — | **XC-11**: every tier `quorum ≥ quorum.ordinary` | No spending vote may be quieter than ordinary business. | | `drain_cap.window_days` | integer 28–365; required iff exists | Rolling window. | | `drain_cap.max_fraction` | fraction 0.05–0.5; required iff exists | Cumulative outflow ceiling per window, measured against the balance at window start. **XC-12**: no single tier may exceed the drain cap. Even a unanimous module cannot empty itself in one season — the cap protects future members and the worst-off present ones, who depend on the commons longest. | | `impact_statement_required` | const `true`; iff exists | Every spend above the lowest tier must include a written statement of impact on the worst-off member. This is the empathy metric's hook into the document itself: it is graded by the test suite, not merely filed. | ### 4.10 `forks` The kernel's load-bearing right. Exit is the ultimate check; everything here bounds how *assets* follow exit, never whether exit happens. | Field | Bounds | Attack surface | |---|---|---| | `individual_exit` | const `true` | Unconditional, immediate, never penalized. Not configurable. | | `collective.min_faction_fraction` | fraction 0.01–0.10 | A faction this large may fork *with an asset claim*. Ceiling at 0.10: requiring a larger faction makes funded exit impossible and converts fork rights to parchment (F-10, "Hotel California governance"). | | `collective.notice_days` | integer 7–90 | Window for negotiation and ledger reconciliation. | | `collective.asset_division` | enum: `pro_rata`, `contribution_adjusted`, `custodial_negotiated` | `pro_rata`: per departing member, equal shares. `contribution_adjusted`: weighted by ledger-recorded contributions within the lookback — permitted for *assets* only; never echoes into votes. `custodial_negotiated`: division by the dispute mechanism, suitable where assets are indivisible (a house). | | `collective.contribution_lookback_days` | integer 30–1095; required iff `contribution_adjusted` | Unbounded lookback re-creates founder aristocracy. | | `data_portability` | const `true` | Departing members and forks receive the full ledger history and their own records. A fork without the history is a fork without the lessons. | ### 4.11 `disputes` | Field | Bounds | Attack surface | |---|---|---| | `method` | enum: `mediation`, `juror_panel`, `steward_ruling`, `external_arbiter` | | | `juror_count` | enum {3,5,7,9,11,13,15}; required iff `juror_panel` | Odd, bounded; even panels deadlock into the status quo. | | `juror_selection` | const `sortition`; iff `juror_panel` | Elected judges are a second legislature (F-11, "court capture"). Sortition from the full membership, with recusal, is the only conformant panel selection. | | `appeal_available` | const `true` | One appeal, always. Appeals from `steward_ruling` go to a sortition panel even in modules that chose `steward_ruling` as the first instance. | | `recusal_required` | const `true` | Parties to a dispute never adjudicate it. | ### 4.12 `records` | Field | Bounds | Notes | |---|---|---| | `ledger_visibility` | enum: `public`, `member_visible` | Kernel floor is `member_visible`: a member can never be denied the ledger. Households may legitimately keep it private to members; DAOs spending pooled funds should be `public` (the dogfooding instance is). | | `decisions_archived` | const `true` | Every vote, tally, and adopted text persists. | | `amendment_history_immutable` | const `true` | History is append-only. You may repeal; you may not erase. | --- ## 5. What userland may NOT touch For clarity, the invariant locks — expressed as `const` in the schema so that a non-conformant value is a *syntax* error, not a judgment call: 1. `suffrage.one_person_one_vote: true` 2. `suffrage.delegation.revocable_instantly: true` (when delegation enabled) 3. `membership.expulsion.subject_excluded: true`, `membership.expulsion.appeal: true` 4. `emergency.auto_sunset: true`, `emergency.invariants_suspendable: false` 5. `forks.individual_exit: true`, `forks.data_portability: true` 6. `disputes.appeal_available: true`, `disputes.recusal_required: true`, sortition for juror panels 7. `commons.impact_statement_required: true` (when a commons exists) 8. `records.decisions_archived: true`, `records.amendment_history_immutable: true` These correspond one-to-one with the kernel invariants derived in `docs/research/04-moral-convergence.md`: equal standing, due process, exit, non-erasure of the record, regard for the worst-off, and the impossibility of suspending any of the above. --- ## 6. Cross-parameter constraints (normative) Schema validation alone cannot express relations *between* fields (JSON Schema has no numeric cross-field comparison). These constraints are therefore listed in the schema under the extension keyword `x-cross-constraints` and MUST be evaluated by any conformant validator. A config failing any one is non-conformant exactly as if it had failed the schema. | ID | Rule | Forecloses | |---|---|---| | XC-01 | `thresholds.amendment >= thresholds.ordinary` | Rule changes cheaper than ordinary business | | XC-02 | `quorum.amendment >= quorum.ordinary` | Quiet-room amendments | | XC-03 | `membership.expulsion.threshold >= thresholds.amendment` | Purge-to-majority | | XC-04 | `membership.expulsion.quorum >= quorum.amendment` | Midnight expulsions | | XC-05 | `!emergency.enabled or emergency.renewal_threshold >= emergency.confirm_threshold` | Cheap emergency renewal | | XC-06 | `!emergency.enabled or emergency.max_duration_hours * (1 + emergency.max_renewals) <= 720` | Rolling permanent emergency | | XC-07 | `forall(offices, o => o.recall_threshold <= thresholds.amendment)` | Super-constitutional officers | | XC-08 | `!commons.exists or strictly_ascending(commons.spend_tiers[*].max_fraction)` | Degenerate/overlapping tiers | | XC-09 | `!commons.exists or nondecreasing(commons.spend_tiers[*].threshold) and nondecreasing(commons.spend_tiers[*].quorum)` | Big spends easier than small ones | | XC-10 | `!commons.exists or forall(commons.spend_tiers, t => t.max_fraction <= 0.25 or t.threshold >= thresholds.amendment)` | **51% commons drain** | | XC-11 | `!commons.exists or forall(commons.spend_tiers, t => t.quorum >= quorum.ordinary)` | Quiet-room spending | | XC-12 | `!commons.exists or max(commons.spend_tiers[*].max_fraction) <= commons.drain_cap.max_fraction` | Single-shot drain around the rolling cap | ### 6.1 Expression grammar Constraint expressions use the following minimal language, defined here so any implementation (the test-suite milestone ships the reference evaluator) is unambiguous: ``` expr := disj disj := conj ( "or" conj )* conj := unary ( "and" unary )* unary := "!" unary | comparison comparison:= operand ( ("==" | "!=" | ">=" | "<=" | ">" | "<") operand )? | "forall(" path "," ident "=>" expr ")" | "(" expr ")" operand := path | number | boolean | arith | helper arith := operand ( ("+" | "-" | "*" | "/") operand )* helper := "strictly_ascending(" projection ")" | "nondecreasing(" projection ")" | "max(" projection ")" path := ident ( "." ident )* ; dotted access into the config projection:= path "[*]." ident ; field projected over an array ``` Semantics: missing optional paths short-circuit any constraint guarded by the corresponding `enabled`/`exists` boolean (the `!x.enabled or ...` pattern is the required idiom). `forall` over an empty array is `true`. --- ## 7. Attestations Every config closes with explicit, non-defaultable acknowledgments: - `attestations.invariants_accepted: true` — the adopting group affirms it has read the kernel invariants and understands they bind regardless of any future config value. - `attestations.kernel_supremacy_accepted: true` — the group affirms §1.1: kernel beats config on conflict. These are `const true` in the schema. Their purpose is not legal theater; it is that the genesis ledger entry contains, in the adopters' own ratified document, the answer to the future bad-faith argument "we never agreed to that." --- ## 8. Nesting and federation (informative, v0.1 scope note) A module may name a parent in a future `parent_module` field (reserved, not yet in schema). The intended semantics, frozen here so v0.2 cannot quietly invert them: **children may tighten their own bounds, never loosen the parent's; parents gain no new powers over children by federation; fork rights of the child against the parent are identical to member fork rights within a module.** Federation mechanics are explicitly out of scope for v0.1 and will be specified alongside the test suite, where the attack surface (parent capture of child treasuries, child sybil-voting in parent decisions) can be exercised rather than merely imagined. ## 9. Validation pipeline (informative) A conformant validator: 1. Parses the JSON; rejects on syntax error. 2. Validates against `module.schema.json` with a JSON Schema **draft 2020-12** validator. 3. Evaluates all twelve `x-cross-constraints` per §6.1, reporting each failure by ID. 4. Emits scale warnings (non-fatal): any quorum or faction fraction that rounds to `< 1` person at `population_estimate`; `quorum.* > 0.9` at `population_estimate > 50`; `ballot.privacy = "public"` at `scope = "dao"`. The reference implementation ships with the constitutional test suite (next milestone). Until then, steps 1–2 run under any off-the-shelf 2020-12 validator, and step 3 is a dozen one-line checks any reviewer can do by hand against the table above.