Skip to main content
Status: Draft Type: Standards Track Category: Core Created: 2026-04-09

1. Abstract

This CIP specifies Cowboy’s on-chain governance system and the mechanism by which system actors (0x010x0B) and governance-tunable parameters are upgraded. Governance is implemented as the 0x09 Governance system actor and supports:
  • Bicameral voting from day one: a proposal must pass both a staked-CBY chamber (economic weight) and a validator chamber (one-validator-one-vote operational weight).
  • Tiered proposals (Tier 0–4) with thresholds, quorums, and timelocks scaled to blast radius.
  • On-chain temperature checks as non-binding signal votes before formal submission.
  • A permanent Security Council 7-of-9 multisig that can cancel queued proposals, trigger a fast-track path during emergencies, and circuit-break a system actor. Circuit-break is the Council’s one unilateral protocol power and is strictly time-limited: a pause auto-reverts after 7 days unless the community ratifies an extension via a Tier 3 proposal, and extensions are capped (§7.7). The Security Council is not the Foundation.
  • Built-in system actor upgrades via content-addressed PVM bytecode activation, with a rollback slot and optional migration functions.
  • A separate Labs Multisig controlling only the governance portal frontend — never the protocol.
Whitepaper §11 provides a summary of the governance model; this CIP is the full specification.

2. Motivation

Cowboy ships with many explicitly governance-tunable parameters (CIP-1, CIP-3, CIP-5, CIP-9, CIP-10, whitepaper §13). Without a specified governance mechanism, every parameter change would require either a hard fork or a centralized admin key — neither is acceptable for a live L1. The governance system must satisfy three design constraints:
  1. Separation of Foundation and protocol authority. The Foundation is a legal entity that holds the treasury and runs ops. It should have zero protocol powers and act only as a recipient of governance-authorized disbursements. This separation is important for the regulatory posture and prevents capture.
  2. No arbitrary sunset. Token governance has well-documented failures (voter apathy, plutocracy, bribery markets). A permanent emergency authority is a feature, not training wheels. Removal of that authority should itself be a governance decision, not a calendar event.
  3. Operational voice for validators. Token-weighted voting alone ignores the judgment of validators who actually run infrastructure. A parameter change that token holders approve but validators deem unsafe should not pass.
This CIP addresses all three: the Foundation has no protocol powers; bicameral voting (staked CBY + validator majority) is live from day one; and the Security Council is a permanent but removable-by-Tier-4 emergency brake.

3. Entities

Three distinct entities, intentionally separated:

3.1 The Foundation

A legal entity (e.g., “Cowboy Foundation”) that holds a treasury address on-chain and runs off-chain operations (legal, accounting, payroll). The Foundation has no protocol authority. It cannot propose, vote, execute, or cancel. It receives funds only when a treasury disbursement proposal passes governance. Foundation employees MAY serve as Security Council members in their individual capacity, but the Foundation SHOULD hold at most one (1) Security Council seat. Exceeding this is grounds for a Tier 4 rotation proposal.

3.2 The Security Council

A 7-of-9 multisig of named individuals serving fixed terms. The Council’s only powers are:
  1. Cancel a queued proposal during its timelock period (Tier 0–3 only; cannot cancel Tier 4).
  2. Trigger fast-track execution on a Tier 3 (system actor upgrade) proposal in an emergency — skipping the temperature check, compressing voting to 24 hours, compressing the timelock to 6 hours, and raising thresholds to compensate (see §7.6 for full parameters).
  3. Circuit-break specific system actors by toggling a paused flag (requires retroactive ratification within 7 days or the pause auto-reverts).
The Council cannot:
  • Submit proposals (anyone with the proposal deposit can)
  • Vote in either chamber
  • Change governance parameters directly
  • Upgrade actors directly
  • Spend treasury funds
  • Modify its own membership (only Tier 4 meta-governance can)
Council membership: 9 named individuals selected for diverse expertise (core protocol developers, independent security researchers, validator operators, ecosystem builders, community-elected seats). At most 1 seat may be Foundation-affiliated. Signers use hardware wallets; each key is held individually, never shared. Annual rotation of at least 2 seats is encouraged, enforced via Tier 4 proposal.

3.3 The Labs Multisig

A separate multisig (e.g., 3-of-5) controlled by Cowboy Labs. Its only authority is upgrades to the governance portal frontend (static assets in CBFS) and the portal gateway actor under CIP-14. It has no protocol authority — a compromised Labs Multisig can only serve a bad UI, not change governance rules. Users retain the ability to vote via CLI or third-party portals pointed at the same 0x09 state. The Labs Multisig signer set MUST NOT overlap with the Security Council signer set by more than one person, to prevent correlated compromise.

4. The 0x09 Governance System Actor

4.1 Storage layout

params:              map<ParamKey, ParamValue>           // live values read by other system actors
param_history:       map<ParamKey, Vec<ParamChange>>     // audit trail
config_version:      u64                                 // bumped on every params mutation

proposals:           map<ProposalId, Proposal>
proposals_by_status: map<Status, Vec<ProposalId>>        // TempCheck|Voting|Queued|Executed|ExecutionFailed|Rejected|Cancelled

temp_check_votes:    map<ProposalId, map<Address, Signal>>
stake_votes:         map<ProposalId, map<Address, Vote>>
validator_votes:     map<ProposalId, map<ValidatorId, Vote>>

actor_versions:      map<Address, VersionRecord>         // active code per system actor
rollback_slot:       map<Address, VersionRecord>         // previous version (grace window)
pending_upgrades:    map<Address, PendingUpgrade>        // queued but not yet activated

security_council:    SignerSet                           // 7-of-9
labs_multisig:       Address                             // reference only, no authority here
paused_actors:       map<Address, PauseRecord>           // circuit-breaker state
council_cancellations: Vec<CancellationRecord>           // rolling log for griefing-cap review (§7.8)

4.2 Config consumer pattern

Other system actors MUST read governance-tunable parameters from 0x09.params rather than maintaining local copies. Two acceptable patterns:
  • Direct read on every access (simple, one extra cross-actor message per call).
  • Cached read, invalidated on the ConfigVersionBumped(old, new) event emitted by 0x09 whenever config_version increments.
The DualBasefee actor (0x06) is the canonical example: T_c, T_b, alpha, and delta live in 0x09.params, not in 0x06’s own state.

4.3 Upgradeability of 0x09 itself

The Governance actor is upgradeable only via a Tier 4 MetaGovernance { op: UpgradeGovernance { ... } } proposal (see §7.3). This path has no fast-track, no Security Council cancellation authority, and no Circuit-breaker pause (which is forbidden on 0x09, §7.7). There is no out-of-band escape hatch.

5. Proposals

5.1 Tiers

TierNameScope
0Parameter tuningScalar updates to any governance-tunable parameter (see genesis defaults and CIP-1/3/5/9/10)
1Registry & whitelistPython stdlib whitelist additions, approved runner images, model flags/bans, TEE attestation roots, relay operator allowlist
2Treasury & disbursementGrants, liquidity incentives, audit payments, Foundation operating budgets, burns
3System actor upgradeHot-swap PVM bytecode for any 0x010x0B actor, with optional migration (§7)
4Constitutional / metaUpgrade 0x09 itself, modify Security Council membership, change tier parameters, pause an actor permanently, or extend a Tier 3 pause past the consecutive-renewal cap (default 3 extensions ≈ 90 days; see §7.7)

5.2 Tiered parameters

All values are initial defaults. Every number in this table is itself governance-tunable via Tier 4.
TierProposal depositTemp checkVoting windowStake quorumStake approvalValidator majorityTimelockFast-track
01,000 CBY3 days5 days5% of active stake> 50%> 50% of active validators3 daysNo
15,000 CBY3 days5 days10%> 50%> 50%5 daysNo
25,000 CBY5 days7 days15%> 55%> 50%7 daysNo
325,000 CBY7 days7 days15%> 60%> 50%7 daysYes — see §7.6
4100,000 CBY14 days14 days20%> 66%> 66%14 daysNo
Deposit is refunded if the proposal reaches the voting stage (temperature check passed and deposit holder did not withdraw). Deposit is burned if the temperature check fails or if the proposal is withdrawn after entering the voting stage.

5.3 Proposal body

Proposals reference a content-addressed body stored in CBFS:
Proposal {
  id:                 bytes32        // hash of (submitter, nonce, tier, body_ref)
  tier:               Tier
  submitter:          Address
  deposit:            u256
  title:              string
  body_ref:           CbfsRef        // rationale, spec text, links to forum discussion
  payload:            Payload        // machine-readable change set (§5.4)
  status:             Status
  submitted_at:             Block
  temp_check_snapshot_block: Block          // stake weights for temp check denominator; fixed at submission
  temp_check_ends:           Block
  voting_snapshot_block:     Option<Block>  // stake weights for formal voting; fixed when temp check passes
  voting_starts:             Option<Block>
  voting_ends:               Option<Block>  // may be extended per §6.5
  voting_extensions_used:    u8             // bounded by max_voting_extensions (§6.5)
  executable_at:             Option<Block>  // set on entering Queued
}

5.4 Payload types

enum Payload {
    ParamUpdate { changes: Vec<(ParamKey, ParamValue)> },
    RegistryUpdate { add: Vec<RegistryEntry>, remove: Vec<RegistryEntry> },
    TreasuryDisbursement { recipient: Address, amount: u256, memo: string },
    SystemActorUpgrade { target: Address, new_code_hash: bytes32, code_ref: CbfsRef, migration: Option<MigrationSpec>, activation_delay_blocks: u64, rollback_window_blocks: u64, spec_ref: CbfsRef },
    MetaGovernance { op: MetaOp },
    Circuit { target: Address, action: PauseAction },
}
§7.1 is the authoritative schema for the SystemActorUpgrade variant (including field types, default values, and validation rules). The summary row above omits internal field structure for readability. Payloads are executed deterministically by 0x09 when the timelock expires. Execution is idempotent and failures are logged without consuming the proposal; a failed execution may be retried within a grace window of execution_retry_blocks (Tier 0 param, default 1 day). If retries are exhausted, the proposal transitions to ExecutionFailed and its deposit is refunded — the proposal passed governance but could not be applied, which is a bug in the payload, not a spam signal.

6. Voting

6.1 Bicameral rule

A proposal passes if and only if all of:
stake_quorum_met     : total_stake_voted >= stake_quorum_pct * active_stake_at_snapshot
stake_approval_met   : yes_stake / (yes_stake + no_stake) > stake_approval_pct
validator_majority   : yes_validator_votes / active_validators_at_snapshot > validator_majority_pct
not_cancelled        : security_council did not cancel during timelock
abstain contributes to quorum but not to approval ratio. A proposal that passes the stake chamber but fails the validator chamber is rejected — validators have an effective veto on operational parameters.

6.2 Stake chamber

Weight source: CBY staked to validators (self-stake and delegated stake both count). Unstaked CBY held in wallets has zero weight. This deliberately forces participation through the staking system. Snapshot: Stake weights for formal voting are frozen at voting_snapshot_block, taken when the temperature check concludes successfully and the proposal enters the voting stage. (The temperature check uses a separate earlier snapshot, temp_check_snapshot_block, fixed at submission — see §6.4.) Late stakers cannot vote on the proposal; earlier unstakers who are still in the 7-day unbonding queue at the snapshot still count for the full weight they had when they initiated unbonding (prevents griefing by flash-exiting mid-proposal). Delegation: Delegators to validators MAY override their validator’s vote per proposal. Absent an override, the delegated weight votes with the validator. Override messages are cheap (System lane). Vote types: Yes | No | Abstain. For multi-choice proposals (Tier 0 parameter-setting with a menu), the ballot is an index into the options list; the first option exceeding the approval threshold wins. Vote mutability: Votes may be changed until the last epoch of the voting window, at which point they are sealed.

6.3 Validator chamber

Weight source: Exactly one vote per active validator, independent of stake. A validator running 1% of total stake has the same chamber weight as a validator running 10%. Snapshot: Active validator set at the proposal’s voting_snapshot_block (taken when temp check passes). Jailed or exited validators at that block do not count. Delegation: Not applicable — validators vote themselves, not their delegators (who already vote in the stake chamber). Vote types: Same as stake chamber.

6.4 Temperature checks

Before a proposal enters the formal voting stage it MUST pass a temperature check: a non-binding on-chain signal vote with a low participation bar. Duration per tier is given in §5.2. Purpose. Gauge sentiment early, kill proposals with no demonstrated support before they consume a voting window, and surface controversial splits so proposers can refine before formal submission. Anti-spam is primarily enforced by the tier deposit (§5.2); the temperature check is an additional filter so that proposals with a non-zero deposit but zero demonstrated interest do not waste validator attention. Snapshot. The temperature check has its own earlier stake snapshot, temp_check_snapshot_block, fixed at the block the proposal is submitted. This is distinct from the formal-voting snapshot (§6.2), which is only taken if the temperature check passes. Using a distinct pre-voting snapshot resolves the denominator: the participation percentage is measured against stake active at submission, not against a snapshot that does not yet exist. Pass conditions. A proposal passes the temperature check if all of:
participation_met    : total_signal_stake >= temp_check_min_participation_pct * active_stake_at_temp_check_snapshot
approval_met         : yes_signal / (yes_signal + no_signal) >= temp_check_approval_pct
Initial defaults (Tier 0 params, governance-tunable):
  • temp_check_min_participation_pct = 1% of active stake
  • temp_check_approval_pct = 33%
Abstain contributes to participation only. If either condition fails at the end of the temp check window, the proposal is rejected and the deposit is burned. Temperature check tallies are displayed on the portal alongside the formal vote tally.

6.5 Tallying, finalization, and participation-triggered extension

Running tallies are computed by a tick handler invoked each block while any proposal is in Voting. At the scheduled voting_ends block, 0x09 performs a participation check before freezing the tally. Participation check. Let:
  • validator_participation = (validators_voted / active_validators_at_snapshot)
  • stake_participation = (total_stake_voted / active_stake_at_voting_snapshot)
The proposal may finalize if both of:
  • validator_participation >= voting_min_validator_participation_pct
  • stake_participation >= voting_min_stake_participation_pct
Extension. If either participation measure is below its floor, 0x09 extends voting_ends by voting_extension_blocks and emits VotingWindowExtended { proposal_id, new_voting_ends, stake_participation, validator_participation }. The snapshot blocks do not change — stake and validator weights remain as captured at the original voting start, so the extension cannot be exploited to change who is eligible to vote. Extensions are capped at max_voting_extensions. After the cap is reached, 0x09 finalizes the tally at the extended voting_ends regardless of participation — the proposal either passes (if quorum and approval thresholds were met by whoever participated) or is rejected. This prevents an indefinite-extension attack where a participant simply stays offline to stall finalization. Parameters (Tier 0, governance-tunable):
  • voting_min_validator_participation_pct = 60%
  • voting_min_stake_participation_pct = 60% of the tier’s stake quorum (i.e., at Tier 3 with a 15% quorum requirement, extension triggers when observed stake participation is below 9%)
  • voting_extension_blocks = 1 day
  • max_voting_extensions = 3
Rationale. The window exists to give honest participants time to observe and respond. If the chain or the validator set is under pressure during the scheduled window such that participation is meaningfully below the expected floor, the extension bounds the damage a timing attack can do. Capping extensions at 3 ensures governance still terminates — an attacker who keeps participation below the floor pays at most 3 extra days before the tally proceeds against them. Finalization. At the final voting_ends (original or extended), the tally is frozen and the proposal transitions to either Queued or Rejected. Queued proposals set executable_at = now + timelock.

7. System Actor Upgrades

System actor upgrades are handled natively by 0x09 Governance — there is no separate SystemActorUpgrader actor. Keeping the upgrader inside Governance avoids adding another trust boundary and another upgrade target.

7.1 Proposal shape (Tier 3)

SystemActorUpgrade {
  target:                  Address        // e.g. 0x02 JobDispatcher; MUST NOT be 0x09 (see §7.3)
  new_code_hash:           bytes32        // keccak256 of new PVM bytecode
  code_ref:                CbfsRef        // CBFS volume holding the blob
  migration:               Option<MigrationSpec> {
    fn_name:               string
    args:                  bytes
    expected_state_hash_after: bytes32    // post-migration invariant (§7.4)
  }
  activation_delay_blocks: u64            // blocks to wait after timelock expires (min 0)
  rollback_window_blocks:  u64            // blocks after activation during which rollback is available (min = 7 days)
  spec_ref:                CbfsRef        // human-readable upgrade notes
}
Timing is specified as offsets, not absolute blocks. Absolute block numbers are computed at queue time, when executable_at is known:
  • activation_block = executable_at + activation_delay_blocks
  • rollback_deadline = activation_block + rollback_window_blocks
This avoids the chicken-and-egg problem of validating absolute times at submission, when executable_at has not yet been determined.

7.2 Validation at submission

Before accepting the proposal, 0x09 verifies:
  1. target is a system actor in the range 0x010x0B and is not 0x09 (governance self-upgrade goes through Tier 4, §7.3).
  2. code_ref resolves to bytecode whose hash matches new_code_hash.
  3. Bytecode passes the PVM determinism whitelist (no forbidden imports, no non-deterministic ops).
  4. Bytecode size is within max_system_actor_bytecode_size (Tier 0 param, default 512 KiB).
  5. rollback_window_blocks >= blocks_per_day * 7 (minimum 7-day rollback window).
There is deliberately no precondition on the current state of target at submission time. The actor is almost certainly still in service during temp check, voting, and timelock, so any state-at-submission assertion would typically be stale by activation. Migration safety is checked at activation time (§7.4), not submission. Failing any check rejects the proposal before the temperature check stage; the deposit is returned.

7.3 Upgrading 0x09 itself

0x09 is explicitly excluded from SystemActorUpgrade.target. Self-upgrade goes through a dedicated MetaGovernance { op: UpgradeGovernance { ... } } payload, which uses the same bytecode/migration fields but is Tier 4 (not Tier 3), has no fast-track path, and has no Security Council cancellation authority. This prevents a compromised or misguided fast-track from replacing the rules that define fast-track.

7.4 Execution

There are two execution paths, selected by whether the proposal’s migration field is set. Validators in both paths pre-fetch new bytecode from CBFS during the timelock period so activation is zero-downtime. A validator that cannot fetch before activation_block fails to execute messages to target until it catches up — identical to any other “missing code” lag.

7.4.a Code-pointer-only upgrade (no migration)

When migration is None, there is no state transformation and no quiesce. At activation_block, 0x09 performs a single atomic transition in one system transaction:
  1. Copy the current VersionRecord for target to rollback_slot[target].
  2. Write the new VersionRecord to actor_versions[target].
  3. Emit SystemActorUpgraded(target, old_version, new_version).
The next message delivered to target in any subsequent block invokes the new bytecode. No messages are dropped or delayed, no queue is drained, and target remains available across the transition. This path is appropriate for pure code refactors, bug fixes, and additions that do not rewrite persistent state.

7.4.b Migration-accompanied upgrade

When migration is Some(spec), the migration needs a consistent state snapshot, so target is briefly quiesced. The flow at activation_block:
  1. 0x09 places target in quiesce state: new inbound messages to target are held in a queue; in-flight messages already dispatched in the current block drain against the old code.
  2. Once the drain completes (typically the next block), 0x09 performs these steps in one atomic system transaction: a. Copy the current VersionRecord for target to rollback_slot[target]. b. Write the new VersionRecord to actor_versions[target]. c. Invoke target.migration.fn_name(migration.args) under the new code. This call runs in the system lane with unlimited gas and is logged as MigrationExecuted. d. Compute the post-migration state hash of target and compare to migration.expected_state_hash_after (if supplied).
  3. Atomic rollback on failure. If step (c) reverts, or if step (d) disagrees with the expected hash, 0x09 reverts steps (a)–(c) in the same atomic transaction. After rollback, target is back on its prior (known-working) code and state. 0x09 then automatically releases target from quiesce and emits MigrationFailed { target, reason, reverted_to_version }. Queued messages resume dispatch against the old code. No human action is required to restore service — the actor is already back in the state it was in immediately before activation. Operators MAY prepare a corrected migration proposal at their own pace.
  4. On success, 0x09 emits SystemActorUpgraded(target, old_version, new_version) and releases target from quiesce. Queued messages resume dispatch against the new code.
Migration-accompanied upgrades are designed for infrequent, planned state-shape changes. Proposers whose target cannot tolerate quiesce (long-running timers, latency-critical dispatch) SHOULD structure the change as a sequence of code-pointer-only upgrades (§7.4.a) that internally handle schema coexistence — or, in the rare case where true quiesce is required, schedule the activation during a known low-traffic window and accept the brief unavailability. Quiesce is distinct from Circuit-breaker pause (§7.7). Quiesce is a migration-atomicity mechanism internal to 0x09’s upgrade flow, strictly bounded in duration (a single block of drain plus one atomic transaction), and always self-released — either by a successful migration or by the atomic rollback on failure. It is not a governance lever. The Council’s pause authority operates on the separate paused_actors state and has its own lifecycle (§7.7).

7.5 Rollback slot

Until rollback_deadline, a Tier 3 fast-track proposal (§7.6) MAY revert target to the version in rollback_slot without re-validating the old bytecode (it was previously live). Rollback uses the same quiesce/atomic mechanism as forward migration. After the deadline, a rollback requires a full Tier 3 upgrade proposal pointing at the old code_hash.

7.6 Fast-track (Tier 3 only)

The Security Council MAY trigger fast-track on a submitted Tier 3 proposal by signing a 7-of-9 endorsement. Fast-track compresses all three phases — not just the timelock — and modestly raises the stake-approval threshold:
PhaseNormal Tier 3Fast-track
Temperature check7 daysSkipped (Council endorsement substitutes)
Voting window7 days24 hours
Timelock7 days6 hours
Stake quorum15%15%
Stake approval> 60%> 66%
Validator majority> 50%> 50%
Total fast-track path: ~30 hours from Council endorsement to activation, vs. ~21 days normally. The approval bump (60% → 66%) is the only numerical protective bar; the real protection is the Council endorsement + the bicameral requirement. Fast-track is an emergency path, not an end-run around review — it must still pass both chambers, just on a compressed clock. Fast-track is designed for known-bad-actor-code scenarios where a patched version exists and the community broadly agrees it should ship now. For scenarios where the patch does not yet exist or consensus is unclear, the Council’s Circuit-breaker (§7.7) is the appropriate tool — it stops the bleeding while a normal Tier 3 proposal is prepared.

7.7 Circuit-breaker (Security Council only)

The Security Council MAY pause a system actor via a 7-of-9 signed Circuit { target, action: Pause } message to 0x09. Effects:
  • All messages to target revert with ActorPaused.
  • paused_actors[target] records the pausing signers, the pause block, and an expires_at block (initially pause_block + 7 days).
  • 0x09 automatically creates a Tier 3 ratification proposal on behalf of the pause:
    • Payload: Circuit { target, action: RatifyExtend }
    • Submitter: 0x09 (system-generated)
    • Deposit: 0 (waived for auto-generated ratifications)
    • Skips the temperature check and enters Voting immediately
    • Voting window: standard Tier 3 (7 days), or fast-track (24 hours) if the Council also endorses the ratification
Pause durations are bounded, and Tier 3 extensions are capped. Ratification does not produce an indefinite pause; it extends the pause by a bounded renewable period, and the number of consecutive Tier 3 extensions is capped so that continued freeze past the cap forces a constitutional decision at Tier 4:
  • paused_actors[target] tracks an extension_count: u32 alongside expires_at. extension_count starts at 0 when the pause is first invoked.
  • A passing Tier 3 RatifyExtend proposal extends expires_at by pause_extend_blocks (Tier 0 param, default 30 days) and increments extension_count by 1.
  • If extension_count >= pause_tier3_extension_cap (Tier 0 param, default 3, i.e. ~90 days of cumulative Tier 3 extensions past the initial 7-day pause), further extensions MUST be Tier 4 MetaGovernance { op: PauseExtendPermanent { target, duration_blocks } } proposals. A Tier 3 extension attempted past the cap is rejected at the payload validation step, even if temperature check and voting thresholds are met.
  • A Tier 4 MetaGovernance { op: PausePermanent { target } } proposal freezes the actor with no renewal schedule (this is the permanent freeze referenced in §5.1’s scope table).
  • A Tier 4 extension or permanent pause resets extension_count to 0 if the Tier 4 vote also transitions the actor back to Tier 3 renewal (via a supplied new_expires_at); otherwise the permanent flag takes over and extension_count is no longer consulted.
  • An unpause at any time requires a Tier 3 Circuit { target, action: Unpause } proposal. On successful unpause, extension_count is reset to 0 and paused_actors[target] is cleared.
  • If the initial ratification proposal fails, or if expires_at is reached with no active extension proposal, the pause auto-reverts and the Council signers are flagged in the portal for community review.
Exclusions. Circuit.target MUST NOT be 0x09. Pausing the Governance actor would deadlock governance itself (including the ratification proposal required to validate the pause). The ability to pause other liveness-critical actors is permitted but is a recognized weapon — a pause of 0x02 JobDispatcher, for example, halts the runner marketplace — and is why ratification is mandatory, bounded, and renewable only at Tier 3 (for ongoing incident response) or Tier 4 (for constitutional freezes). Pause is the Council’s only unilateral protocol power and it is strictly time-limited without community ratification.

7.8 Cancellation authority and griefing cap

The Security Council MAY cancel a queued Tier 0–3 proposal during its timelock by submitting a 7-of-9 signed Circuit { target: proposal_id, action: Cancel } message to 0x09. Cancellation is immediate: the proposal transitions to Cancelled, its deposit is refunded, and execution never occurs. Cancellation itself is never rate-limited — the Council’s ability to stop a queued proposal in a real emergency is preserved. But sustained use of the cancellation power triggers automatic community review: Storage (added to §4.1):
council_cancellations: Vec<{ proposal_id: bytes32, cancelled_at: Block, signers: SignerSet }>
Mechanism. Let cancellation_review_window_blocks (Tier 0 param, default 90 days) and cancellation_review_threshold (Tier 0 param, default 3) be governance-tunable.
  1. On every Council cancellation, 0x09 appends a record to council_cancellations and emits CancellationExecuted { proposal_id, signers, block }.
  2. 0x09 then counts entries in council_cancellations whose cancelled_at falls within (now − cancellation_review_window_blocks, now]. Call this count recent_count.
  3. If recent_count >= cancellation_review_threshold, 0x09 automatically creates a Tier 4 MetaGovernance { op: ReviewCouncil } proposal with:
    • Payload body referencing the recent_count cancellations and their proposal_ids
    • Submitter: 0x09 (system-generated)
    • Deposit: 0 (waived for auto-generated accountability proposals)
    • Standard Tier 4 voting parameters (§5.2)
  4. The auto-generated proposal can pass with ReviewOutcome::Affirm (Council behavior judged appropriate; no action), ReviewOutcome::Warn (event logged, no removal), or ReviewOutcome::Rotate (replaces a named subset of Council signers; requires the replacement signer list in the payload).
  5. While an auto-generated review proposal for the current Council is active, subsequent cancellations do not stack new review proposals — the existing review is extended to cover additional cancellations that occur during its lifecycle.
Why not rate-limit cancellations directly. A rate limit prevents the Council from responding to coordinated attacks (e.g., an attacker spamming Tier 3 upgrade proposals to exhaust cancellation budget). The escalation design preserves unlimited cancellation power for real emergencies while ensuring any pattern that looks like griefing triggers a community check, not a hardcoded veto. Cancellations vs Tier 4. The Council cannot cancel Tier 4 proposals (§3.2). An attempted Circuit { target: tier4_proposal_id, action: Cancel } message is rejected at payload validation. This means the auto-generated ReviewCouncil proposal itself is not cancellable by the Council being reviewed.

7.9 Non-upgradeable elements

Certain protocol rules are not upgradeable via 0x09 and require a validator-coordinated hard fork:
  • Block format, transaction format, signature schemes.
  • Simplex BFT consensus rules.
  • The 0x09 upgrade mechanism itself (Tier 4 can change 0x09 bytecode, but the execution layer must still recognize 0x09 as the authority — changing that is a fork).
  • Genesis allocations.
These are listed so that proposers do not try to route them through CIP-12.

8. Portal and Discoverability

8.1 On-chain portal

The governance portal is a web application served directly from Cowboy:
  • Static assets (HTML, JS, CSS) live in a public CBFS volume owned by the Labs Multisig.
  • Served by a CIP-14 DNS-addressable gateway actor, also owned by the Labs Multisig.
  • Reads from the 0x09 actor for all state; writes vote transactions on behalf of the connected wallet.
  • Runs anywhere: the portal is a thin explorer + wallet bridge. Third parties can run their own portal pointed at the same 0x09 state; this is encouraged.

8.2 What the portal shows

  • Active, queued, executed, and rejected proposals
  • Proposal body rendered from CBFS body_ref
  • Running stake-chamber tally, validator-chamber tally, and temperature-check tally, updated each block
  • Voter list (address + stake + choice) for transparency
  • Security Council membership and current signers on pending cancellations
  • Live params table with history
  • System actor version table with links to bytecode in CBFS

8.3 Portal upgrade path

Portal upgrades (UI, gateway actor bytecode) are signed by the Labs Multisig and do not go through governance. If the Labs Multisig is compromised, users can still:
  1. Use the Cowboy CLI to submit votes and read proposal state.
  2. Run a local portal from the CBFS volume at any historical hash.
  3. Point a third-party portal at the same 0x09 contract.
The protocol itself is unaffected because the Labs Multisig has no 0x09 authority.

9. Open Questions

  1. Validator chamber weight ties. With one-vote-per-validator, ties in the validator chamber are possible. Current rule: ties fail the validator majority check. Should a tie fall through to a Security Council tie-break? Probably not — failing closed is safer.
  2. Multi-choice ballot semantics. First option above approval threshold, or highest-ranked option that clears a minimum? Default is the former.
  3. Minimum Security Council rotation cadence. Is 2 seats per year enough? Should it be proportional to Council size?
  4. Portal censorship. If the Labs Multisig delists a proposal from the default portal UI, is there a protocol-level mitigation or is “run your own portal” sufficient? Default: the latter.
  5. Delegation override cost. Delegators who override their validator’s vote pay a small fee (System lane). What fee? Default: basefee only, no premium.
  6. Liveness-critical pause targets beyond 0x09. §7.7 forbids pausing 0x09 but permits pausing other system actors. In practice some pauses are economically disruptive (e.g., 0x02 halts the runner marketplace, 0x06 would halt fee computation). Should additional actors be on a “pause-with-extra-approval” list requiring, say, stake-chamber signal as well as Council signatures? Current default: no, the 7-day auto-revert and mandatory ratification are sufficient protection.
  7. Migration quiesce duration caps. §7.4 drains the message queue before migration. An actor with a very large queue could take many blocks to drain. Should there be a max-drain-blocks limit that aborts the migration if exceeded?
These are all parameters or policies that can be resolved in implementation without changing the core design.

10. Rationale

Why bicameral? Requiring both a stake chamber and a validator chamber means a proposal must be both economically and operationally defensible. Neither token holders nor validators alone can push through changes without the other’s consent. Why a permanent Security Council? The Council can be removed by the community via Tier 4, so it is not irrevocable. But it defaults to present because an emergency brake operated by named, accountable individuals is strictly safer than having no fast-response mechanism at all. The community opts in to removing its own safety net when ready — not on an arbitrary calendar date. Why separate the Foundation from protocol authority? The Foundation is a legal entity with employees, bank accounts, and regulatory obligations. Granting it protocol powers creates capture risk and a regulatory target. The Security Council is a group of named individuals chosen for expertise and independence, none of whom hold the role by virtue of employment. Why build upgrades into 0x09? A separate SystemActorUpgrader actor would itself need an upgrade path, adding a trust boundary without reducing any. Keeping upgrades in 0x09 means the upgrade mechanism is protected by the same meta-governance rules as everything else. Why staked-only vote weight? Unstaked CBY has no skin in the game and is cheap to accumulate (exchange floats, lost wallets). Staked CBY is committed to network security and earns/loses rewards based on network health. Requiring stake aligns voting power with long-term interest.

11. References

  • Whitepaper §11 — summary of the governance model
  • node/runner/src/system_actors.rs — canonical system actor addresses
  • CIP-1, CIP-3, CIP-5, CIP-9, CIP-10 — sources of governance-tunable parameters
  • CIP-14 — DNS-addressable gateway actor used by the portal frontend