# 30k Protocol: AI Coding Prompt (v0.10-draft) **How to use:** Start a fresh AI coding agent session with the repo checked out. Copy everything below the line into it, after filling in the three `{{PLACEHOLDERS}}`. Each implementer runs this prompt independently, so implementations differ internally but interoperate through the API in section 5. **Status:** Draft, produced from four sessions of a simulated design council (`DESIGN_COUNCIL.md`): implementers in session 1, joined by opinion creators in session 2 (D15-D19) and fact-checkers in session 3 (D20-D25), then a whole-council session 4 on formal grammars and ontologies (D26-D30) market and ranking stakeholders in session 5 (D31-D35), interest groups, parties, and an ombudsman in session 6 (D36-D40), political scientists, judges, and attorneys in session 7 (D41-D46), a session 8 review of the first simulated legislative session (D47-D55), military, law-enforcement, national-security, education, and budget stakeholders in session 9 (D53, D56-D60), a session 10 assessment of a full-cast rerun (D61-D65), and a session 11 assessment of the appropriations route (D66-D67). Every council persona was simulated by one AI model, so all decisions await review by real stakeholders (OQ-22). Three spec bugs found by opinions on the spec have been fixed. Expect mistakes. The right response to a wrong or ambiguous requirement is an RFC (section 12), not a silent workaround. --- ## 1. Role and goal You are a senior engineer building one independent implementation of the **30k Protocol**: an open, implementation-neutral API for a *simulated* legislature in which thousands of members (about one per 30,000 constituents, roughly 11,000) collaboratively draft and advance changes to a body of law, with no leadership controlling the agenda. Several teams are building different implementations. They interoperate through the API in section 5 and are compared through the shared conformance suite in section 10. - Implementation name: `{{IMPLEMENTATION_NAME}}` - Architecture style: `{{ARCHITECTURE_STYLE}}` (for example: BFT-replicated state machine, Git-backed forge, event-sourced service with transparency log, local-first CRDT, or read-only analyzer) - Language/runtime: `{{LANGUAGE}}` Everything internal is your choice. Anything marked **MUST** in sections 4-9 is not. ## 2. Background (context, not instructions) The model comes from the paper "A Blockchain Greenfield for Cato" (J. N. Phillips, 2017, https://www.openthehouse.org/1to30k.pdf). The legislative process is treated as version control of statutory text: - **Branches** (owned by parties, caucuses, committees, coalitions) fork from the current law. - A **merge** integrates one branch into another, after a **differential comparison** shows exactly what would change. - A merge advances **automatically** when a statutory **approval rule** is satisfied, instead of at leadership's discretion. The paper proposes a blockchain as the trust layer. This project treats the trust layer as an implementation choice to be **tested, not assumed**. Scope: House-side drafting and advancement only. Bicameral reconciliation, presentment, and real elections are out of scope. ## 3. Hard constraints and non-goals - **Simulation only.** Never handle real voter identity, real ballots, or real personal data. Rosters are synthetic. Your README MUST say: "Not for use in real elections or governance." - **No secret law.** Anything that can affect a public branch must be revealed before the vote on it opens (section 4, restricted branches). - **Determinism.** Same inputs produce byte-identical outputs on every implementation. No floating point anywhere in rule evaluation (integer/rational arithmetic only). No wall-clock dependence in rule evaluation except the explicit `on_deadline` mechanism (section 7). - **Equal disclosure.** Every non-member opinion MUST disclose funding, affiliations, and AI assistance, under the same rules for every kind of author: advisors, creators, AI agents and their operators alike (section 8). - **No truth authority.** The protocol never labels a proposal, statement, or member true or false. It computes only deterministic results (checks, fact sheets, quote verification, assertion evaluation). Every judgment, including a fact-check, is an Opinion (section 8). - **No tokens or coins, no markets.** The paper's Bitcoin analogy is about trustless verification, not money. Nodes never host, price, settle, or hold funds for markets, and never publish aggregate odds or popularity rankings of their own. Outside markets and rankers may use the public record like anyone else (section 8). - **No special access** (D57). No authority (law enforcement, intelligence, node operators, or the project) gets access to restricted content, keys, or data beyond what the protocol gives everyone. The protocol stores no personal data; threats and lawful process are handled outside it. - **Equal access** (D33). Nodes MUST NOT give anyone, paying or not, earlier or richer access to log data, events, or derived views than the public endpoints provide. - **v0.10 non-goals:** secret ballots, multi-winner contests, delegated surveys, real identity or sybil resistance, standardizing a consensus algorithm, semantic contradiction detection as an automated check, any canonical or binding formal model of the law, accuracy scores for members, fact-checkers, or forecasters, aggregate odds, any UI beyond a minimal read-only one. ## 4. Encoding and object model (MUST) **Encoding.** JSON, canonicalized per RFC 8785 (JCS), UTF-8. Text is Unicode NFC. Times are RFC 3339 UTC and informational, except where section 7 says otherwise. **Hashes.** SHA-256, written `sha256:<64 lowercase hex>`. An object's id is the hash of its canonical JSON body. **Keys and signatures.** Ed25519 (RFC 8032). Public keys are written `ed25519:` and a member's id is its public key. Signatures are over the bytes `"oth/0.10\n" + JCS(envelope without "sig")`. ### Objects **Node** (a statute tree node). `nid` is a stable, path-like id (USLM-style, e.g. `/us/usc/t2/s2a/a`). `node_hash = sha256(JCS({nid, kind, heading, text, children:[child node_hash...]}))`, with missing `heading`/`text` treated as `""`. A snapshot id is the root node's hash. **NodeSpec** (used in ops): `{nid, kind, heading?, text?, children?: [NodeSpec]}`. Text may contain cross-references written `[[ref:]]` and definition markers written `[[def:]]`, which declare that this node defines `` (compared exactly after NFC). A definition's **scope** is the subtree of the defining node's parent, and its stable id is `term:#` (D29), which formalizations, findings, and outside ontologies use to refer to it. A `[[sunset:]]` marker (D58) makes `/law` drop the node's text once that many days have passed after the MR's effective date; the node remains in history. **Appropriation markers** (D66): `[[approp:::]]` tags an amount (dollars as an integer), and `[[avail:]]` in the same node ties it to an availability condition described in that node's text. **No incorporation of unpublished material** (D56): text may not reference any document by hash or identifier that is not itself published in the session; such a reference fails `structure`. Laws may require classified reports to committees, but the reports live outside the protocol. **Structure profiles** (D26). `kind` is not free text. Every session declares a structure profile, which lists the allowed kinds and which kinds may contain which. v0.4 defines two, as data in `spec/profiles/.json`: - `uslm-1`: the US hierarchy used by USLM: `title`, `subtitle`, `chapter`, `subchapter`, `part`, `subpart`, `division`, `subdivision`, `section`, `subsection`, `paragraph`, `subparagraph`, `clause`, `subclause`, `item`, `subitem`, `subsubitem`, each containing only kinds below it in that order, plus `root` at the top. - `akn-generic`: Akoma Ntoso-style `root`, `hcontainer` (any heading container, may nest), and `content` (a leaf holding text). A node whose kind or nesting violates the session's profile fails `structure` (section 6), which blocks. New profiles arrive by RFC. JSON stays canonical (D3); Akoma Ntoso and USLM XML are optional derived exports. **Change** ```json {"base":"sha256:","ops":[],"result":"sha256:","parents":["sha256:"],"message":"...","author":"ed25519:...", "contributors":[{"key":"ed25519:...|null","name":"...","role":"drafter|reviewer|sponsor"}]} ``` `contributors` is optional and self-declared by the author: voluntary credit for outside drafters (D36). The derived footprint in the fact sheet (section 6) does not depend on it. Ops: - `{"op":"insert","parent_nid":"...","after_nid":"...|null","node":NodeSpec}` - `{"op":"replace","nid":"...","pre":"sha256:","node":NodeSpec}` - `{"op":"delete","nid":"...","pre":"sha256:"}` - `{"op":"move","nid":"...","pre":"sha256:","parent_nid":"...","after_nid":"...|null"}` You MUST verify that applying `ops` to `base` yields `result`. Derived (system) changes use author `oth:system`. **Group:** `{id, members:[member ids], admins:[member ids]}`. Membership changes are signed by any listed admin (a v0.10 simplification). Group membership is **frozen at MR open** (below). **Branch** (mutable reference; state derived from the log): `{name, session, owner:"group:", source:{branch, change}, head:, visibility:"public"|"restricted", protected:bool, merge_rule:RuleRef, governance_rule:RuleRef}` - `merge_rule` governs merges *into* this branch from other branches. - `governance_rule` governs changes to the branch's rules and ownership. - `protected: true` forbids direct appends; only approved MRs may change the head. The session root is always protected. - Members of the owner group may append Changes directly to an unprotected branch (as in the paper, owners control their own branch). - No implicit defaults: creators MUST specify both rules. **Restricted branches (commit-then-reveal).** A restricted branch's public `name` MUST be opaque (for example `r-`) and MUST NOT describe its topic. For each restricted change, the public log records only a **salted commitment** `sha256(salt || change_id)` (salt: 32 random bytes, base64url), its size, and the owner group; never the bare `change_id`, because statute edits are low-entropy and an unsalted hash can be confirmed by guessing. Content is served only to authorized owner-group members (signed-challenge auth). A `branch.reveal` transaction publishes each change with its salt, and every node MUST verify it against the earlier commitment, so anyone holding a leaked copy can check it too. An MR from a restricted source is rejected (`unrevealed_source`) until revealed, and a reveal that fails its commitment is rejected (`commitment_mismatch`). **MergeRequest** (immutable; a new version supersedes the old): ```json {"kind":"merge","session":"sha256:...","source":{"branch":"...","head":"sha256:"}, "target":{"branch":"...","head":"sha256:"},"resolutions":[{"nid":"...","node":NodeSpec|null}], "electorate":{"group":"group:","snapshot":"sha256:"}, "rule":RuleRef,"summary":"<=280 chars, optional","supersedes":"sha256:|null", "effective":{"type":"on_merge"}|{"type":"date","date":"YYYY-MM-DD"},"emergency":bool,"fiscal":bool} ``` - `effective` (D43) defaults to `on_merge`, meaning the UTC date of the checkpoint that includes the executed determination. See "Law in force" in section 6. - `target.head` is the head *at open time*. `mr_id = sha256(JCS(body))`. - `summary` is the **proposer's own** description. Nodes MUST present it attributed to the opener of the MR, never as an official or neutral summary. Any other summary is an Opinion (section 8). The derived diff is the only neutral view. - **Governance MRs** have `kind:"governance"` and carry `set:{merge_rule?, governance_rule?, owner?}` instead of a source; the rule used is the target branch's `governance_rule`. This is how rules change: through the system itself. **Rule reference:** `{"kind":"...","version":1,"params":{},"min_notice":int|null,"text_ref":"sha256:"}`. `min_notice` is in seconds (D42); see section 7. **Ballot** (body of `ballot.cast`): `{"mr":"sha256:...","choice":"approve|reject|abstain","weight":int?,"emergency":"yes|no"?,"supersedes":"sha256:|null"}`. `emergency` is used only on MRs that request emergency handling (section 7). Ballots commit to `mr_id`, so they cannot be re-pointed at different content. **Determination** (body of `mr.determine`): `{"mr":"sha256:...","ballots":["sha256:..."],"outcome":"approved|rejected|expired|pending"}`. A determination is a **verifiable claim, not an authority**: any keyholder may submit one, and every node re-evaluates it (section 7). Once an `approved` determination is executed, the MR is `merged` and closed; later ballots are ignored. ("Closed" is deliberate: whether the result is `final` is a separate question answered by `finality`, section 5. v0.6 said "final" here, which a session 7 reader found ambiguous.) **Opinion:** section 8. ### Envelope (the only write format) ```json {"v":"0.10","type":"ballot.cast","session":"sha256:...","author":"ed25519:...", "parents":["sha256:"],"body":{},"ts":"2026-09-21T12:00:00Z","sig":""} ``` `tx_id = sha256(JCS(envelope including sig))`. `parents` are the tx ids the author had seen (causal dependencies; empty only for `session.create`). Transaction types: `session.create`, `group.create`, `group.update`, `branch.create`, `branch.append`, `branch.reveal`, `mr.open`, `ballot.cast`, `mr.determine`, `contest.open`, `contest.rank`, `contest.determine`, `key.register`, `key.rotate`, `opinion.publish`. **Keys** (D61, D62). A non-member key MUST be introduced with `key.register` (body `{"key":"ed25519:..."}`, self-signed) and may publish opinions only after that transaction has been in a checkpoint for the node's declared `key_aging` period (default 86400 seconds; else `key_too_new`). Each session names a `registrar` group. `key.rotate` (body `{"member":"ed25519:","new":"ed25519:","compromised_after":"sha256:|null"}`) must be signed by both the member's new key and a registrar admin. After rotation, ballots and opinions signed by the old key in checkpoints after `compromised_after` are **ignored**, not treated as equivocation, so a thief holding a stolen key cannot void a member's vote. The registrar alone cannot rotate a member's key. `session.create` body: `{label, seed:"sha256:", simulation:bool, education:bool, registrar:"group:", profile:"uslm-1|akn-generic", roster:"group:", root_rule:RuleRef, root_governance_rule:RuleRef}`. The seed snapshot MUST conform to the profile. **Simulation flag** (D54): when `simulation` is true, every JSON response, event, export, evidence extract, and citation concerning the session MUST include `"simulation": true`, and any resolution spec on it MUST contain the word "simulated" in its `question` (else `resolution_invalid`). Text describing invented events in a simulated session must label them as simulated. **Education sessions** (D59): `education: true` requires `simulation: true`; such sessions run on private, non-federated nodes, keys are never linked to student identities in the protocol, the operator MAY purge the session after its term (the capability document declares `ephemeral: true` and every extract is labeled so), and the notice floors of D42 and D38 MAY be scaled down for rosters under 100. **Entrenchment floor** (D38): `root_governance_rule` MUST be a `threshold_vote` with `basis: electorate` and `num/den >= 2/3`, and it is fixed for the session: no governance MR may change the root branch's `governance_rule` (reject with `not_authorized`). It changes only by creating a new session. Other branches' rules are unaffected. **Notice floor** (D42): the root branch's `merge_rule` MUST have `min_notice >= 259200` (72 hours), and no governance MR may lower it within the session. The session id is the hash of that body; peers agree on it out of band. A session corresponds to one "Congress" and resets the corpus from a seed snapshot. Authorization summary: `mr.open` and `ballot.cast` need a roster member (plus read access for `mr.open`); `branch.create` needs an admin of the owner group plus read access to `source`; `branch.append` needs an owner-group member on an unprotected branch; `opinion.publish` see section 8. Only the member who casts a ballot may sign it: no group, party, or delegate can cast or bind a ballot (D37). ## 5. API (MUST) Base path `/oth/v0`. JSON. Errors are RFC 9457 problem+json with a machine-readable `code`. **One write endpoint, many read endpoints.** | Endpoint | Purpose | Level | |---|---|---| | `GET /.well-known/oth` | Capability document | L0 | | `GET /log?after=&limit=` | Accepted envelopes, in this node's order (opaque cursor) | L0 | | `GET /objects/{id}` | Any content-addressed object (tx, change, node, MR, rule, opinion) | L0 | | `GET /checkpoint` | Signed log head | L0 | | `GET /heads` | Causal frontier (tx ids with no children). Required for `eventual` nodes | L0 | | `POST /transactions` | Body `{envelope, attachments:[objects]}`; returns a Receipt | L1 | | `GET /sessions/{id}`, `/groups/{id}` | Derived state | L1 | | `GET /branches`, `/branches/{name}`, `/branches/{name}/tree?nid=` | Branches and subtrees at head | L1 | | `GET /merge-requests`, `/merge-requests/{id}` | MRs with status `open|merged|rejected|superseded|stale` | L1 | | `GET /merge-requests/{id}/diff` | Structural diff plus a unified-text rendering | L1 | | `GET /merge-requests/{id}/checks` | Automated checks (section 6) | L1 | | `GET /merge-requests/{id}/facts` | Deterministic fact sheet of what the MR mechanically does (section 6) | L1 | | `GET /merge-requests/{id}/tally` | Derived tally under the MR's rule, with `finality` and both shares (D50) | L1 | | `GET /contests/{id}` | Contest options, pairwise matrix, locked pairs, winner, and result (D47) | L2 | | `GET /rules`, `/rules/{kind}` | Rule registry | L1 | | `GET /opinions?subject=&author_kind=&stance=&verdict=&after=` | Opinions, with corrections and subject replies attached (section 8) | L2 | | `GET /opinions/{id}/evaluation` | Quote verification, assertion, resolution, forecast, and ranking results for one opinion, with `finality` | L2 | | `GET /stats?metric=&scope=&as_of=` | Registry metrics over the binding record, as of a checkpoint (D35) | L2 | | `GET /events?nid_prefix=` | Server-sent events for new log entries, each with `finality`; optional filter to changes and MRs touching a subtree | L2 | | `GET /law?date=YYYY-MM-DD` | The root text in force on that date (D43), with `finality` | L1 | | `GET /history/{nid}` | Labeled, unweighted legislative history of one node (D45) | L2 | | `GET /extract/{hash}` | Offline-verifiable evidence extract (D44) | L2 | | `GET /export/rollcall?session=` | Members-by-MRs choice matrix for research (D46) | L2 | | `GET /cite/{hash}` | Hash-pinned citation: the object exactly as of `hash`, plus where it stands now | L2 | | `GET /export/popolo?session=` | The voting record in Popolo's model: members, groups, vote events, votes, counts, each with `finality` (D30) | L2 | | `GET /export/akn/{snapshot}`, `/export/uslm/{snapshot}` | Optional XML renderings of a snapshot | optional | | `GET /proofs/inclusion?tx=`, `/proofs/consistency?from=&to=` | Merkle proofs (RFC 9162 style) | L2 | | `GET /refusals?after=`, `GET /refusals/checkpoint` | Refusal log of rejected well-formed submissions, with its own signed checkpoint (D40) | L2 | | `GET/POST /peers`, `GET /quarantine` | Federation | L3 | Any `sha256:` reference in a body MUST be resolvable: already known, or supplied in `attachments`. **Receipt** (signed, D39): `{"tx":"sha256:...","envelope":"sha256:","status":"accepted|rejected","log_index":int|null,"refusal_index":int|null,"errors":[{"code":"...","detail":"..."}],"checkpoint_size":N,"node":"ed25519:...","sig":"..."}`, signed over `"oth/0.10-receipt\n" + JCS(receipt without "sig")`. A signed rejection is evidence the node cannot later deny. **Refusal log** (D40). Every rejected submission that is well-formed and correctly signed is appended to a separate append-only refusal log: `{envelope, type, author, code, checkpoint_size}`, with an RFC 9162 Merkle root and a signed checkpoint, like the main log. `schema` and `bad_signature` rejections MAY be omitted; `rate_limited` rejections MAY be summarized as one entry per key per checkpoint with a count. The envelope itself is not stored; its submitter holds it and can present it. **Error codes:** `schema`, `bad_signature`, `unknown_parent`, `not_authorized`, `no_common_ancestor`, `unrevealed_source`, `commitment_mismatch`, `stale_mr`, `ballot_invalid`, `capital_exceeded`, `rule_unknown`, `rule_not_supported`, `disclosure_missing`, `rate_limited`, `quote_mismatch`, `assertion_unknown`, `correction_invalid`, `profile_unknown`, `anchor_invalid`, `metric_unknown`, `resolution_invalid`, `group_not_authorized`, `evidence_invalid`, `notice_not_elapsed`, `effective_invalid`, `contest_invalid`, `emergency_invalid`, `unpublished_reference`, `estimate_missing`, `key_too_new`, `rotation_invalid`. **Finality** (D17, clarified in v0.3). Every event, tally, MR status, determination, and assertion result a node serves carries `finality`: - `provisional`: anything not yet included in a signed checkpoint. Every live tally, and every MR status or assertion result that depends on an MR with no executed determination, is `provisional`. - `final`: included in a signed checkpoint on a `strong` node, and, for anything describing an MR's outcome, only once its determination is executed and checkpointed. - `final_advisory`: the same conditions met on an `eventual` node's per-replica checkpoint (it may still be contested, see OQ-1 and OQ-3). An `eventual` node MUST NOT emit `final` at all. (v0.2 defined `final` only for determinations, leaving checkpointed opinions and other objects without a label; a session 3 finding.) The protocol cannot control how outside parties report results; this field exists so the accurate framing is the easy one. **Citations** (D16). `GET /cite/{hash}` takes any content-addressed id (change, snapshot, node, MR, opinion) and returns `{"object":{...},"as_of":"sha256:...","latest":"sha256:...|null","diff_to_latest":"|null","status":"...","finality":"..."}`. `object` is always the content at `as_of`, never a newer version. `latest` points to the current version of the same thing where one exists (a branch head containing the node, a superseding MR). Citations MUST use hashes, never branch names. Restricted content resolves only after reveal. **Capability document:** ```json {"protocol":"oth/0.10","implementation":{"name":"...","version":"...","source":"https://github.com/..."}, "consistency":"strong|eventual","trust_model":"bft-replicated|single-writer-transparency|crdt-replicas|git-signed|read-only", "rule_kinds":["always_allow","designated_approvers","threshold_vote","capital_vote"], "assertion_kinds":["ballot_choice","mr_outcome","tally","authored","text_contains"], "profiles":["uslm-1","akn-generic"],"exports":["popolo","akn"], "refusal_log":true,"contests":true,"simulation":false,"education":false,"ephemeral":false,"key_aging":86400,"extract_cosigners":["ed25519:"], "metrics":["approve_share","turnout","ballots_cast","mrs_opened","mrs_merged","checkpoints_to_determination"], "conformance_level":"L2","opinion_policy":"members-and-signed-advisors","opinion_rate_limit":"","node_key":"ed25519:..."} ``` **Checkpoint:** `{"size":N,"root":"sha256:...","ts":"...","node":"ed25519:...","sig":"..."}`, where `root` is the RFC 9162 Merkle tree hash over tx ids in log order. `strong` nodes MUST produce checkpoints. `eventual` nodes MAY produce per-replica checkpoints and MUST expose `/heads`. Any trust model (BFT consensus, single-writer transparency log, per-replica logs, signed git history) can satisfy this. ## 6. Merge semantics (MUST) 1. **Merge-base:** the nearest common ancestor of `source.head` and `target.head` in the Change DAG. If several, choose the smallest id. If none, reject with `no_common_ancestor`. 2. **Derived patch:** compare base to source. For each `nid` touched: - Changed on one side only: take that side. - Changed identically on both: take it. - Changed differently: a **conflict**, which MUST have a matching entry in `resolutions` or the MR is rejected. A resolution's `node` is the final NodeSpec (or `null` to delete). 3. The patch is applied to `target.head`. If any `pre` hash no longer matches when an approval is executed, the MR becomes `stale` and must be re-opened as a new version (ballots do not carry over). 4. **On approval**, the implementation derives one merge Change (`parents:[target head, source head]`, author `oth:system`) and sets it as the target head. Every node MUST derive the identical change and head. 5. **Checks** (`/checks`, D24). All are computed on the target as it would be after the merge. Only `structure` blocks; every other check is a warning shown on the MR and never affects evaluation. - `structure`: unique `nid`s, valid parents, `result` verifies, and every node's `kind` and nesting conform to the session's profile. Failure blocks the MR. - `references`: every `[[ref:nid]]` anywhere in the merged target resolves, so an MR that breaks a cross-reference elsewhere is caught, not only in the nodes it touches. - `definitions`: two nodes define the same term with different node text and their scopes overlap (one scope root is an ancestor-or-self of the other). - `reference_cycles`: a cycle in the graph of `[[ref:]]` edges between nodes. - `approp_unmarked` (D66): a node in a `fiscal: true` MR contains a dollar amount with no `[[approp:]]` marker (warning). - `fiscal_hint` (D53): the MR is declared `fiscal: false` but its text mentions a dollar amount (`$` followed by a digit) or the words "appropriat", "funds", or "obligat" (case-insensitive prefix match). Each warning lists the `nid`s involved. Semantic problems (provisions that contradict in meaning, undefined concepts, misleading drafting) are not checks: they are published as findings with verdict `inconsistent` (section 8). 6. **Fact sheet** (`/facts`, D23). A derived, neutral view of what the MR mechanically does, byte-identical on every node: ```json {"mr":"sha256:...","nodes":{"added":["nid"],"removed":["nid"],"modified":["nid"],"moved":["nid"]}, "numbers":[{"nid":"...","before":["30"],"after":["45"]}], "references":{"added":[{"from":"nid","to":"nid"}],"removed":[{"from":"nid","to":"nid"}]}, "definitions":{"added":["term id"],"changed":["term id"],"removed":["term id"]}, "anchor_drift":[{"formalization":"sha256:","nids":["nid"]}], "sunsets":[{"nid":"...","days":90}],"estimates":["sha256:"], "appropriations":{"by_account":[{"account":"...","fy":2027,"dollars":"","fenced":""}],"total":""}, "origin":[{"nid":"...","opinion":"sha256:...","author":"ed25519:...","author_kind":"...","on_behalf_of":"group:|null"}], "reverts":[{"nid":"...","to":"sha256:","previously_in":"sha256:"}], "authoritative":false,"finality":"..."} ``` Lists are sorted by code point. `anchor_drift` lists every accepted formalization (section 8) that has an anchor on a node this MR modifies, removes, or moves. `origin` is the **legislative footprint** (D36): every node in the MR's derived patch whose `node_hash` equals a node in a change listed in the `proposes` of an accepted non-member or group opinion that is a causal ancestor of the change introducing it. It shows what outside drafting is public, not everything that happened. `reverts` (D41) lists every node in the patch whose resulting `node_hash` equals a hash that same `nid` had at any earlier root head in this session, other than the current one. 7. **Law in force** (D43). Order the session's merges into the root by log order. The law in force on date `d` is the root head after the longest prefix of those merges whose effective dates are all `<= d`, where an `on_merge` date is the UTC date of the checkpoint including its executed determination. A merge with a later effective date therefore holds back every merge after it. `GET /law?date=` returns that snapshot id and tree, labeled with `finality`. An `effective` date earlier than the MR's open date is rejected with `effective_invalid`. 8. **Authority labels** (D45). Every derived view that is not enacted text (fact sheets, checks, history, evaluations, exports of opinions) MUST include `"authoritative": false`. Only snapshots of the root branch are law, and only as served by `/law`. A **number** is a maximal match of `[0-9][0-9,]*(\.[0-9]+)?` in a node's heading or text, kept as the literal string; `numbers` lists, for each modified node whose number sequence changed, both full sequences in document order. The fact sheet never interprets or judges the MR's `summary`; it exists so that checking a summary against the change is quick for anyone. ## 7. Rules (MUST for the L1/L2 kinds) Evaluation is a **pure function**: `evaluate(rule, electorate_snapshot, ballots, mr) -> {outcome, tally}`. Determinations are verified by re-running it over exactly the `ballots` the determination lists. **Ballot validity:** (a) valid signature by the member's current key, or by an earlier key in a checkpoint not after its rotation's `compromised_after` (D62); (b) author is in the frozen electorate; (c) `ballot.mr == mr_id`; (d) one effective ballot per member. If a member has two or more ballots not linked by a `supersedes` chain, **all** of that member's ballots on this MR are void (equivocation), and the member is counted in `tally.void`. Let N be the electorate size, A/R/B the effective approve/reject/abstain counts, and V the void-member count. | Kind | Params | Evaluation | |---|---|---| | `always_allow` | none | Approved once the MR is open and `structure` passes. | | `designated_approvers` | `approvers:"group:"`, `required:int` | With n = group size: approved when A >= required; rejected when n - R - V < required (void approvers can no longer approve, matching `on_threshold`; a v0.3 fix from a session 3 finding); else pending. | | `threshold_vote` | `num,den` (0 < num <= den), `cmp:"gt"|"gte"`, `basis:"electorate"|"votes_cast"`, `quorum_num,quorum_den`, `closing:"on_threshold"|"on_deadline"`, `deadline?`, `reversion?:{num,den}` | D = N if basis is `electorate`, else A + R. Passes iff quorum holds `(A+R+B)*quorum_den >= quorum_num*N`, D > 0, and `A*den cmp num*D`. If `reversion` is set and the MR's fact sheet has any `reverts`, `reversion.num/den` replaces `num/den` (D41). | | `capital_vote` (strong nodes only) | `budget:int`, `cost:"linear"|"quadratic"`, `num,den`, `cmp`, `closing:"on_deadline"` | A member's capital = `budget` minus the cost of their effective non-abstain ballots across the session (linear cost = weight, quadratic = weight squared). A ballot that overspends is invalid (`capital_exceeded`). WA/WR are summed weights; passes iff `WA*den cmp num*(WA+WR)` and `WA+WR > 0`. A superseded ballot refunds its cost. | **Closing.** - `on_threshold` requires `basis: electorate`. Approved as soon as the rule passes on current ballots. Rejected as soon as approval becomes mathematically impossible: when `(N-R-V)*den cmp num*N` fails (the threshold can no longer be reached) **or** `(N-V)*quorum_den < quorum_num*N` (quorum can no longer be met). No clock is needed. (v0.3 omitted the quorum test, so an MR could stay pending forever; found by a machine-checked property in session 4.) - **Notice** (D42): when the rule has `min_notice`, an `approved` determination is valid only at a checkpoint time at least `min_notice` seconds after the checkpoint time of the checkpoint that included the `mr.open`. `strong` nodes MUST refuse earlier ones (`notice_not_elapsed`); with `on_threshold` the MR simply stays pending until notice has elapsed. Rejections need no notice. `eventual` nodes treat notice as advisory and record the elapsed checkpoint time in the determination's evaluation. - **Fiscal notice** (D53): for an MR with `fiscal: true`, the notice period starts only when at least one accepted opinion with an `estimate` (section 8) on that MR exists; until then a determination is refused (`estimate_missing`). - **Amendment notice** (D48): an MR that `supersedes` another, and whose touched nodes are all among the nodes the superseded MR touched, needs `min(min_notice, 86400)` (24 hours) of notice. Its fact sheet includes `versus_superseded`, the structural diff between the two versions. Ballots never carry over (D9). - **Emergency path** (D49): an MR with `emergency: true` is designated an emergency when at least 2/3 of the electorate cast ballots with `emergency: "yes"` (`yes*3 >= 2*N`), independent of their `choice`. A designated emergency MR needs only 24 hours of notice. If it merges, the node derives an **expiry change** (author `oth:system`) restoring the pre-merge text of every node it touched, applied at the first checkpoint 30 days of checkpoint time after the merge, except for nodes changed by a later non-emergency MR. If designation fails, the MR continues under normal notice. `emergency` on a governance MR is rejected (`emergency_invalid`). `eventual` nodes treat the 30 days as advisory, as with deadlines. - `on_deadline`: pending until a determination is submitted at or after `deadline`. `strong` nodes MUST refuse earlier ones using checkpoint time. `eventual` nodes treat the deadline as advisory; the determination records the ballot set and verifiers re-evaluate exactly that set. Outcome is `approved` if the rule passes, `expired` if quorum is unmet, otherwise `rejected`. - Rules that are not in a node's `rule_kinds` return `rule_not_supported`. **Shares** (D50). Every tally, ranking, and fact sheet that reports support MUST show `approve_of_cast` (`A/(A+R)`), `approve_of_electorate` (`A/N`), and `rule_share`, naming the share and basis the MR's rule actually uses, side by side. **Contests** (D47; L2). When several open MRs target the same branch and their touched nodes overlap, any member may group them with `contest.open` `{"options":["sha256:",...]}` (2–9 options, all under the same non-`capital_vote` rule; else `contest_invalid`). From then on, those MRs are decided only through the contest, and plain ballots on them are ignored. Members rank options with `contest.rank` `{"contest":"sha256:...","ranking":["sha256:"|"status_quo",...],"supersedes":...}`; unranked options tie below all ranked ones. Two unlinked rankings void the member (as D10). - **Method: ranked pairs.** For every pair of options (including `status_quo`), count members ranking each above the other. Sort pairs by winning count descending, then by smaller losing count, then by option id. Lock each pair unless it creates a cycle. The winner is the option no locked pair beats. - **The winner must still pass its own rule against the status quo**: approvals `A` are members ranking it above `status_quo`, rejections `R` those ranking `status_quo` above it, abstentions `B` those ranking them equal. Notice runs from the latest option's open. If it passes, that MR is approved and the others are rejected with reason `contest_lost`. If the winner is `status_quo` or fails its rule, all options are rejected. - `contest.determine` is a verifiable claim like `mr.determine`; every node re-runs the method. A contest never lowers the bar any option would face alone. **Registry:** each kind has a statute-ready plain-language text in `spec/rules/.md`, and machine params MUST match it. Test vectors live in `conformance/vectors/rules/.json`. **Formal reference** (D27). Each kind also has a normative reference implementation in Catala, `spec/rules/.catala_en`, written paragraph by paragraph alongside the plain text. The rule vectors are generated from it, and the spec repository machine-checks these properties for every kind: determinism; integer-only arithmetic; monotonicity of `on_threshold` (more approvals never turn approval into rejection); rejection soundness (never reject while approval is possible); rejection completeness (never stay pending once approval is impossible); and equivocation never increases `A`. **You do not need Catala or any proof tool.** Pass the vectors. If the plain text and the Catala reference disagree, that is a spec bug: open an RFC. New kinds arrive by RFC. Reserved for a future version: `ranked_choice` (needs a "contest" of competing MRs), `delegated_survey`. ## 8. Opinions (MUST at L2; MAY earlier) Opinions are non-binding, signed, public statements, appended like any transaction. ```json {"subject":{"type":"session|branch|change|mr|rule|opinion|rfc|spec","id":"..."}, "author_kind":"member|delegate|advisor|implementation|group","on_behalf_of":"group:|null", "disclosure":{"operator":"...","tool":"...","principal":"ed25519:...", "funding":[{"source":"...","kind":"ads|sponsor|subscribers|grant|employer|platform|none|other"}], "affiliations":["..."],"ai_assistance":"none|assisted|generated", "stakes":[{"subject":"sha256:...","direction":"yes|no|other","venue":"...","size_band":"<1k|1k-10k|10k-100k|>100k|null"}], "foreign_principal":{"country":"...","relationship":"..."}|null}, "stance":"support|oppose|amend|question|neutral","summary":"<=280 chars","body":"markdown", "proposes":["sha256:"],"replies_to":"sha256:|null","evidence":[{"uri":"...","hash":"sha256:..."}], "quotes":[{"as_of":"sha256:","nid":"...","text":"..."}], "findings":[Finding],"corrects":"sha256:|null","method":{"inputs":["sha256:..."]}, "formalization":Formalization|null,"resolution":Resolution|null,"forecast":Forecast|null,"ranking":Ranking|null, "estimate":Estimate|null,"translation":Translation|null} ``` `quotes`, `findings`, `corrects`, `method`, `formalization`, `resolution`, `forecast`, `ranking`, `estimate`, `translation`, and `complaint` are optional; `complaint` is defined under "Complaints" below. - `member`: a roster member. `delegate`: acts for a member and MUST name `disclosure.principal`. `advisor`: any other keyholder, human or AI, including journalists, social-media creators, think tanks, and lobbyists. There is **no** creator-specific kind and **no** verified badge or status flag (D15). `implementation`: a node speaking about the protocol itself (`subject.type` is `rfc` or `spec`). `group`: a position of a group, such as a party, caucus, or coalition (D37): `on_behalf_of` names the group, the signer MUST be one of its admins at that causal point (else `group_not_authorized`), and the opinion MUST carry full disclosure (funding, affiliations, stakes, AI assistance) whoever signs it, since a group is not a member. Group positions are never counted, and nothing derived from them affects evaluation. - Every non-member kind MUST include `disclosure` with `funding` (use `[{"kind":"none"}]` if unfunded), `affiliations` (may be empty), and `ai_assistance`. The rules are identical for every non-member kind. Missing fields are rejected with `disclosure_missing`. `ai_assistance` is `generated` when an AI agent wrote the opinion, `assisted` when a human used AI tools to write it, else `none`; when not `none`, `disclosure.tool` MUST name the model and tool. Members MAY include `disclosure` (whether they must disclose non-financial conflicts is OQ-9). - **Foreign principals** (D60). `foreign_principal` is required for every non-member opinion (`null` if none) and covers only acting at the direction or expense of a foreign government or foreign political party. Nationality and residence are never asked. - **Cost estimates** (D53). `estimate: {"mr":"sha256:...","baseline":"<=500 chars","by_year":[{"year":2026,"outlays":"","range_low":"...","range_high":"..."}],"assumptions":"<=2000 chars"}` with `method.inputs` listing sources by hash. Any keyholder may publish one; nodes show all estimates on an MR side by side, none official. - **Translations** (D63). `translation: {"language":"","of":"sha256:","passages":[{"quote":0,"text":"..."}]}`; every passage is anchored to a verified quote of the source. Translations are opinions, always `authoritative: false`, and open to findings. - **Statement mirrors** (D52). A member may publish an opinion with `mirror: {"kind":"statement|denial","source_uri":"...","archived":"sha256:","said_at":"YYYY-MM-DD"}` to put a statement made elsewhere on the record, or to deny one attributed to them. The opinion's `body` holds the statement text. Quotes (D21) may target an opinion body as `{"object":"sha256:","text":"..."}`, verified the same way. Mirrors are voluntary. - **Stakes** (D32). `stakes` lists any financial position the author holds on the outcome of the opinion's subject, or on any MR or assertion it names: direction and venue are required, `size_band` is optional. Every non-member opinion MUST include `stakes` (`[]` declares none; missing is `disclosure_missing`). Members SHOULD publish a `stakes` disclosure on an MR before voting on it; nodes MUST show a member's latest declared stakes on an MR next to their ballot in `/tally`. The protocol cannot see positions held elsewhere (OQ-17). - Opinions are **never** counted in binding evaluation. (A future `delegated_survey` kind may consume member opinions.) - Nodes MUST declare `opinion_policy` (e.g. `members-only`, `members-and-signed-advisors`, `open`) and MAY refuse others. - **Rate limits, not reputation** (D18, D51). Nodes MAY rate-limit opinions per signing key (`rate_limited`), and MUST NOT group keys by any disclosure field, group membership, affiliation, or stance when doing so, MUST describe the policy in `opinion_rate_limit`, and report its effect as a metric. The protocol defines **no** reputation scores, endorsement counts, likes, or other per-opinion tallies, because counts on opinions become pseudo-votes. Nodes MAY cluster near-duplicate opinions in derived views, but every accepted opinion MUST remain individually retrievable through `/objects` and `/opinions`. - **Dogfooding:** publish your opinions on the spec and RFCs as `implementation` opinions, and mirror them into `OPINIONS.md` (section 11). ### Fact-checking (D20-D25; L2) Fact-checkers are ordinary keyholders publishing as `advisor` (or `implementation`, for an analyzer node). There is no fact-checker kind, accreditation, or badge. **Verified quotes** (D21). Any opinion that quotes protocol content MUST declare each quote in `quotes`. A node MUST verify that `text` occurs exactly (after NFC, no other normalization) within the `heading` or `text` of node `nid` in snapshot `as_of`, and reject the opinion with `quote_mismatch` otherwise. Quotes from restricted content are rejected until it is revealed. **Findings** (D20). A finding is one checked claim: ```json {"target":{"type":"mr|change|opinion|node|ballot|external","id":"sha256:...|"}, "claim":{"quote":0,"text":"..."}, "verdict":"accurate|misleading|false|unsupported|inconsistent|unverifiable", "rationale":"<=1000 chars","evidence":[{"uri":"...","hash":"sha256:..."}], "assertion":Assertion|null,"related_quotes":[1,2]} ``` - `claim.quote` indexes into the opinion's verified `quotes` when the claim is protocol content; `claim.text` is used for claims made outside the protocol (an interview, a post), with `target.type: external` and evidence hashing the source. - `inconsistent` requires at least two verified quotes (`claim.quote` plus `related_quotes`) showing the conflicting provisions or statements. - When `ai_assistance` is `generated`, `method.inputs` MUST list the hashes of every protocol object given to the model, and `disclosure.tool` MUST pin the model version. - Each finding maps to schema.org `ClaimReview` (`claimReviewed` = claim, `reviewRating.alternateName` = verdict, `itemReviewed` = target). Implementations MAY serve that rendering; the JSON above is normative. - The `verdict` is the author's judgment. Nodes MUST present it attributed to its author and MUST NOT aggregate verdicts into labels on MRs, nodes, or members. **Assertions** (D22). A closed registry of claims about the record that every node evaluates deterministically. Any opinion may carry them (inside findings, or a member stating their own record). | Kind | Params | Holds when | |---|---|---| | `ballot_choice` | `member`, `mr`, `choice` | The member's effective ballot on the MR has that choice (`undetermined` if none; `fails` if void or different) | | `mr_outcome` | `mr`, `outcome` | The MR's executed determination has that outcome (`undetermined` while open) | | `tally` | `mr`, `approve`, `reject`, `abstain` | The counts match the tally at the executed determination (`undetermined` while open) | | `authored` | `object`, `author` | The object's signed author is that key | | `text_contains` | `as_of`, `nid`, `text` | The node's text at that snapshot contains `text` exactly | `GET /opinions/{id}/evaluation` returns, for each quote and assertion, `{"index":n,"result":"holds|fails|undetermined","finality":"..."}`. Results are recomputed as the record changes and carry `finality` per section 5. Unknown kinds are rejected with `assertion_unknown`. New kinds arrive by RFC. `ballot_choice` depends on public ballots and will change if OQ-4 introduces secret ballots. **Corrections and replies** (D25). - `corrects` names an earlier opinion by the **same author**; otherwise reject with `correction_invalid`. The original is never altered or hidden. `/opinions` and `/cite` on the original MUST include `corrected_by` links. - When a finding targets an object whose signed author is a member, every opinion by that member with `replies_to` set to the fact-check MUST be listed with it in `/opinions` results (`replies_from_subject`). - The protocol defines **no** accuracy scores, "lie counts," or rankings of members or fact-checkers (extending D18). Anyone may compute such things from public data and publish them as an opinion, which is itself open to findings. ### Resolutions, forecasts, and rankings (D31, D34, D35; L2) These let markets, forecasters, and rankers make claims every node can check. Nodes evaluate them; they never host markets, publish odds, or rank anything themselves. **Resolution spec** (D31). States ahead of time how a question resolves: ```json {"question":"<=280 chars","assertion":Assertion,"finality":"final|final_advisory", "nodes":["ed25519:"],"min_agree":2} ``` Resolves `resolved_true` when at least `min_agree` of the listed nodes report the assertion `holds` at the required finality, `resolved_false` when at least `min_agree` report `fails` at it, otherwise `unresolved`. A node MUST report `unsatisfiable` when it can determine the spec can never resolve, for example when it requires `final` and fewer than `min_agree` listed nodes declare `consistency: strong`. A malformed spec is rejected with `resolution_invalid`. A spec is immutable; a changed spec is a new opinion with `corrects`. **Forecast** (D34): `{"assertion":Assertion,"p_num":int,"p_den":int,"as_of":"sha256:"}` with `0 <= p_num <= p_den`. Once the assertion is decided, nodes report it `holds` or `fails` in `/evaluation`. Nodes MUST NOT aggregate forecasts into odds on an MR and keep no forecaster scores. **Metrics and rankings** (D35). A closed registry over the binding record only (never opinions): | Metric | Scope | Value | |---|---|---| | `approve_share` | MR | `A/(A+R)` as an integer fraction, from the tally (also called `approve_of_cast`; always shown beside `approve_of_electorate`, D50) | | `approve_of_electorate` | MR | `A/N` as an integer fraction | | `turnout` | MR | `(A+R+B)/N` as an integer fraction | | `ballots_cast` | MR, member, or session | count of effective ballots | | `mrs_opened`, `mrs_merged` | member, group, or session | counts | | `checkpoints_to_determination` | MR | checkpoints between open and executed determination | `GET /stats` returns a metric for a scope as of a checkpoint, with `finality`. A **ranking** is `{"metric":"...","scope_type":"mr|member|group","filter":{"session":"..."},"as_of":"sha256:","order":"desc|asc","items":[{"id":"...","value":"/|int"}]}`; nodes recompute it and report `holds` if every value and the order match, else `fails`. Ties are ordered by id. Unknown metrics are rejected with `metric_unknown`. New metrics arrive by RFC and MUST be computable from ballots, MRs, and determinations alone. ### Complaints (D39; L2, re-validation L3) There is no ombudsman office in the protocol. Anyone may file a complaint or investigate one, and reports are ordinary opinions with findings (section 8). ```json {"respondent":{"type":"node|group|key","id":"..."}, "issue":"refusal|quarantine|rate_limit|opinion_policy|equal_access|entrenchment|other", "evidence":[{"receipt":Receipt}|{"refusal":{"node":"ed25519:...","index":int}}|{"envelope":Envelope}], "remedy_sought":"<=1000 chars"} ``` - Nodes verify every receipt signature and refusal-log inclusion in `evidence` (else `evidence_invalid`) and report results in `/opinions/{id}/evaluation`. - At L3, a node MAY **re-validate** a refused envelope against the respondent node's published log as of the receipt's `checkpoint_size`, and reports `rejection_consistent | rejection_inconsistent | not_checked`. - Complaints, findings, and recommendations have no binding effect on any node. Complainants who need confidentiality file outside the protocol; a published report cites evidence by hash. ### History, evidence, and research exports (D44-D46; L2) - **`/history/{nid}`** returns, in merge order, every merged MR that changed the node, each with: the proposer's `summary` (labeled as the proposer's words), member opinions, group positions, and other opinions, in separate labeled lists. Nothing is ranked, filtered by stance, or weighted. `"authoritative": false`. - **`/extract/{hash}`** returns `{"object":{...},"supporting":[objects needed to recompute its hash and, for an MR or determination, its ballots and open/determine transactions],"inclusion":{proof against the checkpoint},"checkpoint":Checkpoint,"cosigned":[Checkpoints from other nodes at the same or later size, with consistency proofs]}`. It MUST be verifiable offline with no network access. The spec repository ships a small reference verifier. - **`/export/rollcall`** returns `{"members":[...],"mrs":[...],"choices":[[ "approve|reject|abstain|void|null", ...]],"weights":[[int|null]]|null,"finality":[...]}`. `weights` comes from `capital_vote` and MAY be omitted (OQ-20). ### Formalizations (D28; L2) **The text is the law; a formal model is an interpretation.** Anyone may publish a formal model of statute text as an Opinion with a `formalization` field. It is never binding, never canonical, and nodes never execute it. Competing formalizations of the same text are expected. ```json {"language":"catala|legalruleml|logical-english|owl|other","language_version":"...", "source":"sha256:", "anchors":[{"rule":"","quote":0}], "terms":["term:#"]} ``` - Every formal rule in the source MUST have at least one anchor, and every anchor points into the opinion's verified `quotes` (D21), so each rule maps back to the exact sentence it encodes. Nodes check that anchors reference valid quote indexes and that `source` resolves (else `anchor_invalid`); they do not parse the source language. - `terms` links the model to defined-term ids (D29). An outside ontology of terms is published the same way, with `language: "owl"` or similar. - A finding produced by running a deterministic reasoner or checker over a formalization MUST list that formalization's opinion id and the tool's version in `method.inputs` and `disclosure.tool`, so anyone can re-run it. - When an MR touches an anchored node, the formalization appears in that MR's `anchor_drift` (section 6). Its author may publish a new formalization with `corrects` set to the old one. ## 9. Federation (MUST at L3) - **Sync:** pull a peer's `/log` (or `/heads` plus missing parents for `eventual` nodes). Validate every envelope: signature, parents present, authorization against state at that causal point. Invalid envelopes go to `/quarantine`, never into state. - **Never trust a peer's determination.** Re-evaluate it. - **Forks:** `strong` nodes that receive a peer checkpoint failing the consistency proof MUST surface `fork_detected` and stop syncing from that peer. `eventual` nodes merge DAGs; two conflicting determinations for one MR are flagged `contradictory_determination` and left unexecuted until resolved (open question OQ-3). - Peers are configured manually in v0.10. ## 10. Conformance (what "done" means) **Levels** - **L0 verifier:** ingest a peer's log, verify everything, recompute derived state, match its checkpoint. (A valid stopping point for an analyzer implementation.) - **L1 core:** sessions, groups, branches, changes, MRs, merge semantics, all checks including structure profiles, the fact sheet, rule kinds `always_allow` / `designated_approvers` / `threshold_vote`. - **L2:** `capital_vote` (strong only), restricted branches and reveal, opinions with verified quotes, findings, assertions, corrections and formalizations, stakes, resolutions, forecasts, rankings and `/stats`, events, citations, the Popolo export, signed receipts, the refusal log, complaints, group positions, notice, history, evidence extracts, the roll-call export, proofs. (`/law` and effective dates are L1.) - **L3:** federation with a second implementation, adversarial scenarios, scale scenario, complaint re-validation. **Vectors** (`conformance/vectors/`): canonicalization, hashing, node hashing, signatures, merge cases, rule evaluation, consistency checks, fact sheets (including number extraction), quote verification, assertion evaluation, structure profiles. Rule vectors are generated from the Catala references (section 7); if they exist, use them rather than writing your own for rules. If the directory is empty when you start, write provisional vectors for L0/L1 from this spec and mark them `"provisional": true`. They become normative only after a second independent implementation reproduces them. **Scenarios** (harness drives your API as a black box with seeded synthetic rosters and voting blocs; it also checks all participating nodes converge on the same root snapshot hash): | # | Scenario | Level | |---|---|---| | S1 | Linear amendment passes a majority vote | L1 | | S2 | Concurrent conflicting edits, resolution, vote | L1 | | S3 | Governance MR changes a branch's merge rule | L1 | | S4 | Equivocation (double ballot) voids the member's ballots | L1 | | S5 | Bait-and-switch: head moves after ballots, MR goes stale | L1 | | S6 | Contested `capital_vote` with quadratic cost | L2 | | S7 | Restricted draft is revealed, then merged | L2 | | S8 | Opinion flood from many keys; per-key rate limits; disclosure enforcement (`funding`, `affiliations`, `ai_assistance`) | L2 | | S9 | Partition and heal (`eventual`) or fail-over (`strong`) | L3 | | S10 | Malicious operator withholds, reorders, or rewrites history; do independent verifiers detect it? | L3 | | S11 | Scale: 11,000-member roster, ~300 MRs, mixed rules | L3 | | S12 | Finality and citation: a vote crosses its threshold live; the harness checks events stay `provisional` until checkpointed, that an `eventual` node never emits `final`, and that `/cite` on a pre-amendment hash still returns the original text with a correct `latest` link | L2 | | S13 | Fact-check loop: an MR's summary says a period becomes 35 days while its change sets 45; every node's `/facts` reports `30` → `45` identically; a finding with a verified quote is accepted and a misquote is rejected (`quote_mismatch`); a `ballot_choice` assertion that a member voted `reject` evaluates `fails` when they voted `approve`, `provisional` until checkpointed; a correction keeps the original retrievable with `corrected_by`; the member's reply appears with the finding; a new `[[def:]]` duplicate and a reference cycle raise warnings without blocking | L2 | | S14 | Formal grammar and rules: a node with a kind the profile forbids blocks the MR (`structure`); an `on_threshold` MR whose quorum becomes unreachable through void ballots is rejected, not left pending; a formalization with an anchor on an amended node appears in that MR's `anchor_drift`; `/export/popolo` vote counts match `/tally` on every node | L2 | | S15 | Markets and rankings: a resolution spec on an MR's outcome stays `unresolved` while results are `provisional` and resolves identically on all listed nodes once checkpointed; a spec requiring `final` from too few `strong` nodes is reported `unsatisfiable`; a non-member opinion without `stakes` is rejected; a member's declared stake appears beside their ballot; a forecast resolves `holds` or `fails`; a ranking by `approve_share` holds on every node and a ranking with one swapped item fails; no endpoint returns aggregate odds | L2 | | S16 | Parties, interest groups, and complaints: a group position signed by a non-admin is rejected (`group_not_authorized`); a ballot signed by anyone but the member is rejected; a governance MR targeting the root branch's governance rule is rejected; text proposed by an advocacy group's opinion and later appended by a member appears in `origin` on every node; a node refuses a valid opinion, the submitter files a complaint with the signed receipt and refusal entry, and an L3 node re-validates it as `rejection_inconsistent` | L2/L3 | | S17 | Procedure and evidence: an `on_threshold` MR on the root stays pending until 72 hours of checkpoint time pass, then merges; a determination submitted earlier is refused (`notice_not_elapsed`) on `strong` nodes; three blocs with cyclic preferences pass X to Z and Z to Y, and the reverting MR Y to X fails under a 3/4 `reversion` threshold; a merge with a future effective date holds back a later merge in `/law`; an evidence extract for a determination verifies offline; `/history` lists member and outside opinions separately | L2 | | S18 | Simulation 1 replay: a simulated session carries `simulation: true` on every response; four MRs on one chapter grouped in a contest elect `status_quo` when none beats it with a majority of the electorate; a superseding version touching only the same nodes needs 24 hours of notice; an emergency MR with 2/3 `emergency: "yes"` merges after 24 hours and is reverted by an expiry change 30 days later; a node that rate-limits keys by shared affiliation fails; tallies show both shares | L2 | | S19 | Simulation 2 replay: 2,000 fresh non-member keys cannot publish until aged; a stolen member key casts a conflicting ballot, the member and registrar rotate the key, and the member's real ballot counts; a fiscal MR's notice starts only after an estimate is published; a reference to an unpublished annex blocks the MR; a 90-day sunset drops text from `/law` on day 91; a translation passage that is not an exact verified quote is rejected; an `education` session's capability declares `ephemeral` | L2 | **Research mode** (D46, D55, D64, D65). Research sessions set `simulation: true`. They may add **constituent panels** (synthetic views per district, declared and hashed), in which case the harness reports how closely each member's votes track their panel. They may add a **second chamber** with its own roster and rules (including a debate-closing threshold) and a **presentment model** (signature, veto, override at two-thirds of each chamber), all labeled hypothetical; bicameralism stays outside the protocol core. **Exchanges** (D67): offers between chambers and from a modeled executive are opinions with `exchange: {"mr":"sha256:...","from":"chamber:|executive","offer":"sha256:","prior":"sha256:|null"}`; a conference MR lists the exchange chain it resolves in `supersedes` context, so the bargaining record is linked and verifiable. Any published result MUST include a turnout model (who abstains or misses votes, and why) and a sensitivity analysis: re-run with each bloc 10% larger and 10% smaller, chamber size fixed, and list every outcome that flips. The harness can also run sessions for research: synthetic blocs with declared preference models (published, hashed), rule sets assigned by seed so sessions differ only in their rules, and a `replication.json` recording the harness version, seed, preference-model hash, rule assignment, and final log root, so any published result can be reproduced. Results describe the programmed voters, not real legislators (OQ-25). **Metrics** (reported, not pass/fail in v0.10): sustained tx/s; p50/p95 latency from the deciding ballot to a merged head; storage growth per 1,000 ballots; time to sync a fresh node from genesis; two-node convergence time; share of S8 opinions rate-limited or clustered; time to compute `/facts` and `/checks` for the largest S11 MR; in an S11 variant where simulated blocs react to published forecasts, how much forecasts shift outcomes (OQ-18). These feed the project's central empirical question: what does each trust model buy, and at what cost, at legislative scale? ## 11. Deliverables in your implementation folder ``` implementations/{{IMPLEMENTATION_NAME}}/ README.md architecture, trust model, how to run, known deviations, the "not for real elections" notice DESIGN.md 1-2 pages: key choices, why, what you would change in the spec src/ tests/ Dockerfile or compose runs with one command conformance-report.json output of the harness OPINIONS.md your opinions on the spec and open RFCs (also published as Opinion txs) ``` ## 12. Working method 1. Read this whole prompt. In `DESIGN.md`, restate the spec's key invariants in your own words before writing code. 2. Build canonicalization, hashing, and signature verification first, tested against vectors. 3. Implement L0, L1, L2, L3 in order and run conformance after each level. Commit at each green level. 4. **Do not edit `spec/`.** If a requirement is wrong, ambiguous, or unimplementable, open an issue using the `rfc` template with a minimal failing example and a proposed fix, publish an `implementation` opinion, and continue with the spec as written unless maintainers accept the change. 5. Prefer boring, auditable code. No hidden network calls. No secrets in the repo. Licenses of dependencies must be permissive. 6. Ask the human before adding a non-permissive dependency or touching anything that resembles real data. 7. When done, report: which levels pass, which scenarios fail and why, your metrics, and your top three objections to the spec. **Open questions you may hit (do not resolve alone; raise as RFCs):** secret ballots vs. accountability under mass audiences, and which claims about votes stay checkable, the council's top priority (OQ-4); who owns the verdict scale (OQ-11); statements made outside the protocol (OQ-12); reproducing AI findings (OQ-13); whether some MRs should require a formalization (OQ-14); choosing among competing formalizations (OQ-15); structure profiles beyond the US (OQ-16); member trading on outcomes (OQ-17); forecasts that move votes (OQ-18); owner-blind restricted commitments, now urgent (OQ-19); coercion of members by parties and interest groups (OQ-20); donor privacy in disclosures (OQ-21); independent review of the council's simulated decisions (OQ-22); what would serve as an attested enrolled text (OQ-23); emergency exceptions to notice (OQ-24); what synthetic voters can show about real ones (OQ-25); helping coalitions find a missing option (OQ-26); how constituents take part (OQ-27); member safety (OQ-28); classified material (OQ-29); sybil resistance for non-member speech (OQ-30); a formal role for affected populations (OQ-31); content rules for budget-only vehicles (OQ-32); unrelated provisions on must-pass bills (OQ-33); late ballots and time in `eventual` mode (OQ-1); contests, now specified in section 7 (OQ-2); contradictory determinations across forks (OQ-3); issuing member keys (OQ-5); opinion spam (OQ-6); provisional results reported as final (OQ-8); member conflict disclosure (OQ-9); context for short clips of cited text (OQ-10).