DRAFT Governance ZIP (working draft) for Comment

DRAFT Governance ZIP v2 for Comment

Field Description
zip ZIP:-XXXX (to be assigned by sponsoring Pillar)
title Pillar-Governed Embedded Governance Contract (Spork- and Admin-Scoped)
author 0x3639
status Draft
type Hard Fork
acceptance Community review; forks proceed at their heights regardless of adoption (§11).
activation Two hard-fork heights (TBD), scheduled per §11; the companion Multisig ZIP activates at its own height — either order, or the same height (§2).
created 2026-05-31
updated 2026-07-28
requires Multisig Embedded Contract ZIP (go-zenon#72) — for AdminMigrationForkHeight only (§2).
license GNU General Public License v3.0
link TBD — upstream PR to zenon-network/go-zenon
branch codex/governance-ratchet (81c2474), pending updates below
original sumoshi21, go-zenon PR #47
changelog Separate post: Governance ZIP — Changelog & Implementation Notes

Abstract

This ZIP adds GovernanceContract, letting Pillars propose, vote on, and execute exactly two classes of action: (1) creating and activating Sporks — a deliberate standard track or a supermajority emergency track; and (2) setting networkAdmin, a single address holding all operational admin authority. Proposals require a Pillar’s registered owner address and a refundable 100 ZNN deposit: returned on approval or expiry, donated to Accelerator-Z on rejection.

networkAdmin replaces every existing operational admin identity. At AdminMigrationForkHeight, Bridge and Liquidity drop their per-contract Administrator state and guardians, Plasma’s SetVariables stops honoring the GovernanceAddress placeholder key, and all three authorize admin methods against networkAdmin, read from governance storage. The intended admin is the community Multisig of the companion ZIP — which this ZIP does not modify; governance stores its address as an opaque value.

At GovernanceForkHeight, the legacy spork-signer and CommunitySporkAddress paths are removed: GovernanceContract becomes the sole spork authority (background).

Motivation

Sporks are consensus changes warranting deliberate Pillar votes; bridge halts, keygens, token pairs, liquidity parameters, and plasma tuning need responses in hours — and testnet experience (the PR #47 lineage) showed Pillars will not vote on routine operations. The split:

  • Governance (this ZIP): spork creation/activation, plus one escape hatch — setting networkAdmin — so Pillars retain authority over who holds operational control, and nothing else.
  • Operations (networkAdmin): all admin methods on Bridge, Liquidity, Plasma, and future contracts authorize against one address that can act in hours and holds no embedded-contract funds. The intended holder is the community Multisig, whose address derives from its creation event and is stable across signer rotation.

The urgency is concrete: the legacy spork signer’s whereabouts are unknown — the network has no reachable spork-activation authority. Hence hard-fork activation (§11), removal of the defunct paths (§6), and the Type-1E emergency track (§4).

A second motivation surfaced in review: dynamic plasma (ZIP-3) gates plasma.SetVariables on types.GovernanceAddress — a placeholder user address with a TODO to repoint it at the governance contract. Completing the TODO would permanently strand the setter (PlasmaContract is on no action allowlist); leaving it lets one keyholder change live consensus parameters. This ZIP resolves both: the placeholder is retired and plasma becomes networkAdmin-set (§6.3).

Specification

1. New Embedded Contract

z1qxemdeddedxg0vernancexxxxxxxxxxxklyh23   // GovernanceContract

Added to types.EmbeddedContracts; callable only from GovernanceForkHeight. The types.GovernanceAddress placeholder is not repointed by this ZIP; it is retired at AdminMigrationForkHeight (§6.3).

2. Activation by Hard Fork

Constants:    GovernanceForkHeight, AdminMigrationForkHeight (both TBD, set per §11)
Reference:    MultisigForkHeight (companion ZIP; independent, MAY equal GovernanceForkHeight)
Enforcement:  IsGovernanceForkEnforced() / IsAdminMigrationForkEnforced() at each height
Prerequisites: runtime none (forks proceed regardless of adoption); scheduling per
               §11.3, plus for AdminMigrationForkHeight both prior heights and §11.5

Spork-based activation is unavailable (it would require the unreachable legacy signer); implementations MUST NOT condition enforcement on any on-chain spork object.

Both contracts activate by hard fork, at independent heights, in either order. The dependency graph is acyclic: the Multisig depends on nothing, governance depends on nothing (an address is opaque to it), and only the migration adds a read-only edge. Consequences:

  • Merge order of the two implementations is unconstrained.
  • The two heights MAY be scheduled in either order — or as the same height, preferred when one release carries both: one coordination event, no window where one contract exists without the other. The coupling is a convenience, never a dependency.
  • AdminMigrationForkHeight MUST NOT be scheduled until both heights pass and the §11.5 gate is satisfied.
  • Between the two heights networkAdmin is inert — nothing reads it — yet a Type-2 vote there is legal and persists, so the initial value can be corrected before it takes effect.
  • Legacy Bridge/Liquidity administrators and the plasma GovernanceAddress gate remain authoritative until AdminMigrationForkHeight.

3. Contract ABI

function ProposeAction(
    string  name,
    string  description,
    string  url,
    address destination,
    string  data,
    bool    emergency     // valid only when destination == SporkContract (§4)
)

function ExecuteAction(hash id)

function VoteByName(hash id, string name, uint8 vote)
function VoteByProdAddress(hash id, uint8 vote)

// Type-2 payload codec ONLY — NOT dispatchable; no callable setter (§6.2)
function SetNetworkAdministrator(address administrator)

variable action(owner, name, description, url, destination, data,
    creationTimestamp, type, round, currentVoteId, roundStartTimestamp,
    activePillarSnapshot,  // active-Pillar count fixed at round start
    approvalTimestamp,     // drives Type-2 ratchet delay (§5)
    status, executed, deposit)

variable networkAdministrator(address administrator)

vote = 0 is Yes, vote = 1 is No.

4. Action Types, Rounds, and Thresholds

Type derives from destination plus the emergency flag; SporkContract and GovernanceContract are the only destinations (ErrForbiddenDestination); emergency is valid only with SporkContract (ErrInvalidEmergencyFlag).

Type Destination Allowed methods Execution Track
1 SporkContract CreateSpork, ActivateSpork Emits contract-send Standard; ratcheted rounds
1E SporkContract CreateSpork, ActivateSpork Emits contract-send Emergency; one 7-day round, Yes from >66% of all active Pillars
2 GovernanceContract SetNetworkAdministrator Direct storage write (§5) Admin repointing; ratcheted rounds

Type-1E counts abstentions and non-votes against approval, so it is strictly harder than Type-1 at any realistic turnout — the flag buys speed only when support is overwhelming. Type-2 repoints networkAdmin: governance stops pointing at an admin rather than reaching into it. The decoded selector is validated at propose time; a Type-2 payload decoding to the zero address is rejected (ErrInvalidNetworkAdministrator); any other well-formed address is accepted — the vote is the filter, informed by §8 inlining.

An undecided initial round enters a bounded ratchet — each round lowers participation but raises the directional (Yes+No, excluding abstentions) bar:

Type Round Active-Pillar threshold Directional threshold Period
1 0 >66% >50% 45 days
1 1 >55% >55% 21 days
1 2 >45% >60% 21 days
1 3 >40% floor >66% 21 days
2 0 >50% >50% 30 days
2 1 >40% >60% 14 days
2 2 >33% floor >66% 14 days

activePillars is the round-start activePillarSnapshot — registry churn cannot move a live round’s thresholds. A round approves when:

(yes + no) * 100 > activePillars * activePillarThreshold
yes * 100 > (yes + no) * directionalThreshold

and rejects when participation holds and no * 100 > (yes + no) * directionalThreshold.

Type-1E approves the moment yes*100 > activePillars*66 and rejects the moment no*100 >= activePillars*34 (approval impossible). A lapsed 7-day window expires as NoDecision; re-propose as Type-1.

Abstentions count toward VoteBreakdown.Total but toward neither threshold. The last vote before round close counts; votes do not carry across rounds (fresh tally and vote id; old votes stay queryable).

5. Proposal Lifecycle

Propose. ProposeAction MUST come from the registered owner address of an active Pillar (ErrNotPillarOwner), carrying exactly ProposalDeposit (100 ZNN); at most 2 open actions per owner (ErrTooManyOpenActions). Validation: Name 1–30 bytes; Description 1–240 bytes; Url non-empty matching ^([Hh][Tt][Tt][Pp][Ss]?://)?[a-zA-Z0-9]{2,60}\.[a-zA-Z]{1,6}([-a-zA-Z0-9()@:%_+.~#?&/=]{0,100})$; Data valid base64; destination/method on the §4 allowlist; emergency false unless spork-bound; Type-2 address non-zero. Url SHOULD point to the action’s public deliberation — the thread specifying the change, and for Type-2 the post publishing (creatorPubKey, nonce) and signer identities — and is informational only, never consensus-verified (the binding Type-2 verification is §8’s policy inlining). The contract assigns Id = sendBlock.Hash, records round-0 state and ActivePillarSnapshot, escrows the deposit, and opens a VotableHash on the existing pillar-voting machinery.

Vote. One standing vote per Pillar per round via VoteByName/VoteByProdAddress, against CurrentVoteId (differs from Id after round 0).

Finalize / Execute. Any address MAY call ExecuteAction(id) (execution is uncensorable):

  1. Nonexistent id → ErrDataNonExistent; terminal actions return silently.
  2. Thresholds use the round’s recorded snapshot, never the live count; abstentions excluded.
  3. Type-1 cannot finalize before its period elapses; Type-1E and Type-2 finalize the moment thresholds cross.
  4. On approval: Status = Approved, ApprovalTimestamp set, deposit refunded. Type-1/1E emit the contract-send immediately. Type-2 emits nothing: ExecuteAction writes networkAdmin directly — immediately in round 0; for ratchet rounds, only at/after ApprovalTimestamp + Type2ExecutionDelay (72h), the pending repoint visible meanwhile.
  5. On rejection: Status = Rejected, deposit donated to Accelerator-Z, no send.
  6. Round elapsed undecided: next round opens (fresh CurrentVoteId and snapshot); final round undecided → NoDecision, deposit refunded.

Type-2 has no external destination — the write happens in whichever ExecuteAction performs it, so there is no approved-but-destination-rejected state. Ratchet rounds separate approval and effect by 72h by design, never by a fallible send.

6. Authorization Changes to Existing Contracts

6.1 Spork contract — at GovernanceForkHeight

CreateSpork/ActivateSpork become callable only by GovernanceContract; the legacy spork-signer and CommunitySporkAddress paths are removed.

Future implemented sporks (normative). Activation through governance takes two Type-1 actions with a mandatory binary release between them: (1) CreateSpork — the send-block hash is the real SporkId; (2) a point release replaces the shipped placeholder with that ID, operators upgrade; (3) ActivateSpork; enforcement after SporkMinHeightDelay. Skipping step 2 is fatal: an active spork absent from ImplementedSporksMap terminates the node.

6.2 Governance storage

variable networkAdministrator(address administrator)

This variable holds the single admin role referred to as networkAdmin throughout this ZIP and its companion — one role, one storage location; the longer form is only the code identifier (matching the existing …Administrator naming convention). Unset reads fall back to constants.InitialNetworkAdministrator (§9), mirroring the InitialBridgeAdministrator pattern. SetNetworkAdministrator exists only as the Type-2 payload codec — absent from the dispatch table; the sole write path is vote execution. Deliberately not the Bridge ChangeAdministrator pattern, under which a captured admin could hand authority onward voteless.

GetNetworkAdministrator() types.Address is added to AccountVmContext, reading governance storage via the momentum store pinned for the executing block — deterministic, and already idiomatic for cross-contract reads.

6.3 Bridge, Liquidity, and Plasma — at AdminMigrationForkHeight

Every admin-gated check becomes sendBlock.Address != context.GetNetworkAdministrator()ErrPermissionDenied. Complete privileged-method disposition (normative — this enumeration is the migration’s work item):

Contract Method Today At AdminMigrationForkHeight
Bridge SetNetwork, RemoveNetwork, SetNetworkMetadata, SetTokenPair, RemoveTokenPair, Unhalt, SetOrchestratorInfo, SetBridgeMetadata, RevokeUnwrapRequest admin networkAdmin (SoftDelay challenges retained)
Bridge Halt admin or valid TSS signature networkAdmin or TSS (dual path unchanged)
Bridge ChangeTssECDSAPubKey admin + SoftDelay, or TSS path networkAdmin + same challenge, or TSS path
Bridge SetAllowKeygen admin + guardian predicate networkAdmin (guardian predicate removed)
Bridge Emergency admin + guardians; zeroes admin, clears TSS keys, halts redefined: networkAdmin-gated; clears TSS keys and halts; no admin zeroing or guardian predicate
Liquidity Fund, BurnZnn *types.SporkAddress — the unreachable legacy signer; stranded today networkAdmin
Liquidity SetTokenTuple admin + guardians + SoftDelay networkAdmin + SoftDelay
Liquidity SetIsHalted, UnlockLiquidityStakeEntries, SetAdditionalReward admin (+ SoftDelay where present) networkAdmin, challenges retained
Liquidity Emergency admin + guardians; zeroes admin, halts removed — post-migration it would equal SetIsHalted(true)
both ChangeAdministrator, NominateGuardians, ProposeAdministrator admin / guardians removed
  • Fund/BurnZnn are a rescue: gated on the lost spork signer, they are unreachable today and forever without re-gating.
  • Guardian predicate: CheckSecurityInitialized’s guardian-count requirement is removed post-height; surviving callers proceed on the delay fields alone — otherwise guardian removal would brick them with ErrSecurityNotInitialized.
  • Delays: SoftDelay survives; AdministratorDelay is deprecated (all consumers removed). Removed constants: InitialBridgeAdministrator, MinGuardians.
  • Storage schema (consensus-critical): the removed fields live inside persisted composite ABI variables, so the persisted codecs are unchanged — “removal” applies to authorization, dispatch, and RPC, never the encoding. Deprecated fields MUST be ignored post-height and SHOULD be zeroed on first write; conformance asserts no authorization path reads them, not key absence.

Plasma. SetVariables moves from the GovernanceAddress gate to the same networkAdmin check — in ReceiveBlock, since send-side validation has no state access (the Bridge does likewise). An unauthorized send is accepted and rejected at receive, matching Bridge semantics; the in-code parameter bounds are unchanged. GovernanceAddress survives only for pre-height replay — retiring today’s placeholder-key backdoor over live consensus parameters.

The boundary. Governance sets networkAdmin and nothing else. It cannot set plasma variables directly (its only send destination is SporkContract) or indirectly (plasma authorizes the sender, a role governance never holds). Parameters belong to the admin; governance’s sole lever is deciding who the admin is.

RPC compatibility. Bridge/Liquidity RPC responses keep their administrator field, populated from GetNetworkAdministrator() — no shape break for wallets, explorers, or the orchestrator.

6.4 Multisig contract — no changes

The companion Multisig contract is unmodified and has no governance-caller path — none could be added without redesign: ChangePolicy operates only on its own sender, the verifier rejects blocks without valid threshold signatures (a contract-send has none), and Locked is monotonic. Governance never reaches into the multisig; it only points at it. Minimums: (1) no networkAdmin method holds direct custody of embedded-contract funds; (2) fund-equivalent methods (ChangeTssECDSAPubKey) retain their timelocks; (3) initial-signer criteria MUST be objective, published, free of delegation-status exclusions; the initial admin address is published and verified per §11.5.

7. Plasma and Fees

ProposeAction: EmbeddedWDoubleWithdraw; ExecuteAction: EmbeddedSimple; votes inherit pillar-voting pricing. The deposit is a constant, not a fee: refunded on Approved/NoDecision, donated to AZ on Rejected.

8. RPC

Namespace embedded.governance: GetActionById, GetAllActions, GetPillarVotes, and GetNetworkAdministrator() -> { administrator, multisig } — the current admin with the address’s MultisigRecordInfo (threshold, signers, locked, pending, pendingHeight) inlined, or null if not a multisig.

Action adds computed fields (Expired, Round, Status, CurrentVoteId, thresholds, VotingPeriod, ExecutableAt, Votes) and — Type-2 only, a security requirementProposedAdministrator inlining the proposed address’s MultisigRecordInfo: what voters are delegating to sits in the action view itself, defending the bait-and-switch and locked-target traps.

IsGovernanceForkEnforced(), IsAdminMigrationForkEnforced(), and GetNetworkAdministrator() are added to AccountVmContext.

9. Constants Introduced

Type1Action / Type2Action / Type1EAction        = uint8(1) / uint8(2) / uint8(3)
ActionStatusVoting/Approved/Rejected/NoDecision = uint8(0..3)
Type1ActionActivePillarThresholds = []uint32{66, 55, 45, 40}
Type1ActionDirectionalThresholds  = []uint32{50, 55, 60, 66}
Type1ActionVotingPeriods          = []int64{45, 21, 21, 21} // * PhaseTimeUnit
Type2ActionActivePillarThresholds = []uint32{50, 40, 33}
Type2ActionDirectionalThresholds  = []uint32{50, 60, 66}
Type2ActionVotingPeriods          = []int64{30, 14, 14}     // * PhaseTimeUnit
Type1EPillarYesThreshold          = uint32(66)  // absolute, vs all active Pillars
Type1EVotingPeriod                = int64(7 * PhaseTimeUnit)
Type2ExecutionDelay               = int64(72 * 60 * 60)     // ratchet rounds only
MaxOpenActionsPerPillar           = uint8(2)
GovernanceForkHeight / AdminMigrationForkHeight = uint64(TBD)
InitialNetworkAdministrator = "z1...TBD" // community Multisig, per §11.5
ProposalDeposit = 100 * g.Zexp; GovernanceActionDataMaxLength = MaxDataLength

New errors: ErrUnkownActionType, ErrInvalidActionRound, ErrForbiddenDestination, ErrForbiddenMethod, ErrNotPillarOwner, ErrInvalidEmergencyFlag, ErrTooManyOpenActions, ErrInvalidNetworkAdministrator. MultisigForkHeight is defined by the companion ZIP; the heights MAY coincide (§2).

10. Fork Classification

A Hard Fork at each height: non-upgraded nodes stop following the canonical (upgraded) chain. No adoption threshold exists at either height.

11. Activation

1. Both ZIPs finalize independently; heights are scheduled via the process below, in either order or as one shared height (preferred, §2).

2. Implementations merge; a release ships with readiness signaling enabled but no height set.

3. Readiness criterion. When ≥66% of active Pillars have signaled over a sustained window (suggested: 7 consecutive days), a point release sets the height at least 60 days of momentums ahead.

3a. How a Pillar signals (normative). The upgraded node signals automatically: once per epoch while producing for Pillar P, it broadcasts a zero-amount block from P’s registered producer address whose Data carries a protocol marker plus the feature id (governance-fork / multisig-fork; one block MAY carry both) — an ordinary transaction valid under pre-fork rules. (The momentum Version field cannot serve: the verifier pins it exactly pre-fork.) Signals are attributable via the Pillar registry, automatic, and measurable by anyone; a dashboard SHOULD track the trailing share.

3b. If the threshold is not reached. The criterion is scheduling guidance — not an adoption veto, which would recreate paralysis-by-absence. If signaling stalls after a sustained campaign (suggested: 90 days), the height MAY be scheduled anyway with longer lead (≥90 days of momentums) and unambiguous notice. The fork proceeds regardless (item 4).

3c. The chain never evaluates the threshold (normative). Signal blocks are measurement, not consensus input: no rule reads them; no on-chain condition triggers a height. The chain is: signals → human judgment → point release with a compiled height constant → nodes enforce it. A hard fork cannot be chain-triggered (old binaries lack the new rules); BIP9-style self-activation is rejected as an adoption veto encoded in consensus.

4. Each fork proceeds at its height regardless of adoption. Legacy nodes halt and re-sync on the new znnd.

5. Community Multisig publication gate — AdminMigrationForkHeight only. InitialNetworkAdministrator compiles into that release, so the community Multisig MUST first exist on-chain and be publicly verified: the address; the (creatorPubKey, nonce) pair for offline recomputation; threshold and signer list mapped to nominated identities; locked == false, pending == null at a stated height via getPolicy.

Rationale

Why sporks plus a single admin pointer? Sporks warrant deliberate votes; operations need hour-level response Pillars won’t reliably provide. Governance keeps one operational lever — who is admin — the sole operational question that is a legitimacy question.

Why does set-admin live in governance, not the Multisig contract? Two independent recovery paths: compromised-but-operable signers rotate themselves via ChangePolicy (no vote, hours); a captured, Locked, or abandoned multisig is escaped by one Type-2 vote. A rotation-based design has only the first path, is unimplementable (a contract-send cannot carry threshold signatures; Locked is permanent), and leaves a locked admin recoverable only by hard fork. Repointing ignores the incumbent’s state, is more verifiable, and keeps the graph acyclic.

Why is a multisig a drop-in admin? Its address derives from the creation event, not the policy — rotation never changes it; the pointer is set once.

Why admin-set plasma parameters? Allowlisting PlasmaContract would add a second operational surface inside governance, and tuning needs operational tempo, not 30-day votes. The admin turns the dials within in-code bounds; Pillars control who holds the dials — bounds-limited, recoverable by repoint-then-restore, strictly better than today’s placeholder keyholder or a frozen parameter set.

Why reject only the zero address for Type-2? An IsMultisigAddress check is false assurance — one person with two keypairs mints a passing 2-of-2 — and it forecloses a future embedded-timelock admin. The vote is the filter, informed by §8 inlining.

Why no callable setter? A ChangeAdministrator-style method is invoked by the current admin — a captured admin could hand authority onward without a vote.

Why Pillar-only proposing? The owner address binds proposals to registered stake; anyone else lobbies a Pillar. Deposit plus cap make spam cost capital.

Why hard fork, no adoption threshold, full legacy removal? The inability to activate sporks is the problem; an adoption gate hands a veto to inaction; a retained legacy path is an unrotatable weakest key.

Why an emergency track? The sole spork path must not be only slow. Type-1E’s absolute >66% means silence blocks it, and being strictly harder than Type-1, the flag enables no threshold-shopping.

Why a fixed 100 ZNN deposit, refunded on NoDecision? Skin in the game, not a fee: a convincing proposal costs nothing; rejected deposits fund AZ. No setter — spam is structurally bounded and a lever is a censorship vector; changing the amount takes a Type-1 upgrade. NoDecision refunds because a proposer cannot compel turnout.

Why these thresholds? Sporks start at 66% with a deliberation window; repointing at 50% with immediate round-0 execution, because replacement may be an emergency. Final-round floors: asymptotically >21.8% assent for Type-2 (>33% × >66%), >26.4% for Type-1 (>40% × >66%); ratchet repoints hold 72h so quiet capture is contestable.

Other choices. Rejected: a combined contract; an operational action class; security councils; proposer-specified types; unbounded decay; vote carryover; per-contract admin variables; seeding admin from the live Bridge administrator; failure-case fallback branches.

Backward Compatibility

Before each height, behaviour is byte-identical to today; from it, non-upgraded nodes halt and must upgrade and re-sync. Enforcement comes solely from the release binary; signaling informs scheduling only. Chain-split risk is accepted and mitigated per §11.

Unchanged: address state, token issuance, block formats, and the AZ, Pillar, Sentinel, Stake, HTLC, and Token contracts. The Spork contract changes per §6.1; Bridge/Liquidity/Plasma change per §6.3 (removed methods become unresolvable; storage codecs unchanged, deprecated fields ignored). The Multisig contract is unchanged.

Orchestrator (off-chain). It gates “administrator mode” on the admin equalling its own producer address — impossible for a multisig, so the mode goes permanently inactive post-migration; admin-initiated halt becomes a manual M-of-N action while the TSS halt path stays automatic. Document for operators; retire the code path.

Reference Implementation

Original: go-zenon PR #47 by sumoshi21. Branch: codex/governance-ratchet (81c2474). Required pre-merge updates (each with tests): The 15-item pre-merge update checklist (fork-height activation, Type-2 direct-write semantics, migration disposition tests, readiness signaling, and RPC inlining, each with tests) is maintained in the companion post: Governance ZIP — Changelog & Implementation Notes.

Security Considerations

  • Narrow attack surface. Governance touches no Bridge/Liquidity/Plasma/Token/Multisig state. A captured vote at worst creates a spork (still needing matching binaries) or repoints networkAdmin — visible from propose time.
  • Sole spork authority. A contract defect could stall upgrades; mitigated by battle-tested voting machinery, tests, and hard fork as last resort.
  • Emergency-track abuse. The absolute threshold cannot pass quietly; the 7-day window and early-reject give the No side a veto.
  • Malicious admin repointing. A >50% round-0 coalition could install a hostile admin: it holds no funds and no un-timelocked fund-equivalents; the repoint is visible; the same path repoints back; the floor and 72h delay bound low-turnout capture.
  • Bait-and-switch / locked target. A clean Active policy can hide a Pending rotation maturing post-vote; a Locked multisig can never rotate again — why §8 inlining of pending/locked is mandatory. A locked admin stays escapable by repoint.
  • Admin control of plasma parameters. Bounds-limited, recoverable by repoint-then-restore, strictly narrower than today’s placeholder-keyholder exposure.
  • Emergency admin replacement. One of the intended new signers submits CreateMultisig (the creator must be among the initial signers; creation is immediate), publishes (creatorPubKey, nonce), and a Type-2 proposal repoints — round-0 executes instantly; ratchet rounds wait 72h. During the window: plasma is bounds-clamped; a malicious Halt is reversed post-repoint; ChangeTssECDSAPubKey sits behind its time challenge — a race, not a guarantee (it completes no earlier than SoftDelay, min. ~24h, after its visible start; the protocol guarantees no vote latency). Monitoring MUST surface challenge starts — a hostile challenge triggers the emergency vote. If epoch-level Pillar responsiveness cannot be assumed, raise the TSS-change delay floor first.
  • Hard-fork coordination risk. No adoption threshold means chain-split risk — deliberate; heights are scheduled only per §11 with long lead and public tracking.
  • Proposer gating. Owner-only proposing concentrates agenda-setting in accountable identities; in-flight actions survive registry churn; the cap bounds spam.
  • Deposit as censorship lever — eliminated. A constant with no setter; changing it takes a Pillar-approved upgrade.
  • Registry churn / late-round capture. Round-start snapshots freeze thresholds; floors, rising bars, fresh vote ids, the 72h delay, and terminal NoDecision bound capture.
  • Replay / idle execution / storage. Id = sendBlock.Hash binds actions to the chain; stalled execution cannot block governance; expired actions are not pruned (a follow-up ZIP MAY).
  • Non-atomic target execution — Type-1/1E only. Approved is set before the destination processes the send; a rejection leaves the action terminal. Type-2 is exempt: its write is internal and atomic with whichever ExecuteAction performs it.
  • Migration completeness. A missed admin-gated method is an invisible authority hole — hence §6.3’s enumeration and item-14 tests.

Changelog

Maintained in the companion post — Governance ZIP — Changelog & Implementation Notes (v2.2 current).

Copyright

This ZIP is licensed under the GNU General Public License v3.0.