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 and governance-tunable parameters are upgraded. The system-actor space is the deployed registrynode/runner/src/system_actors.rs (see the WP §9.1 canonical allocation table): 0x01–0x11 are code-deployed (including 0x0E ROUTE_REGISTRY, 0x0F GATEWAY_REGISTRY, 0x10 RECEIPT_REGISTRY, 0x11 VALIDATOR_SET), 0x12 is reserved (PaymentGate, spec-allocated), and 0x13 CONTAINER_REGISTRY / 0x14 INTENT_SETTLEMENT / 0x1D EVENT_SUBSCRIPTION (virtual) / 0x1E TRADING_POST are also deployed. Not every deployed address is upgradeable/pausable — the governance-actionable set is the explicit allowlist in §7.2. 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.
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:- 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.
- 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.
- 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.
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 by charter: it does not propose, vote, execute, or cancel. This is a governance/legal constraint on the Foundation entity, not an on-chain address denylist — the protocol does not special-case the Foundation’s treasury address; enforcement is the charter plus the general staking/tier requirements every proposer faces. 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:- Cancel a queued proposal during its timelock period (Tier 0–3 only; cannot cancel Tier 4).
- 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).
- Circuit-break specific system actors by toggling a
pausedflag (requires retroactive ratification within 7 days or the pause auto-reverts).
- 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)
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-11. 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 same0x09 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
4.2 Config consumer pattern
Other system actors MUST read governance-tunable parameters from0x09.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 by0x09wheneverconfig_versionincrements.
SetGovParam do live under 0x09 (prefix system:gov:param:). However, the deployed structured BasefeeConfig (T_c, T_b, alpha, delta, and the other EIP-1559 fields) is stored at the DualBasefee actor 0x06 under BASEFEE_CONFIG_KEY = "system:basefee_config" (node/execution/src/basefee.rs, loaded via BasefeeConfig::load_from_storage()), not at 0x09.params. Treat this section’s “read from 0x09.params” as the intended consumer pattern for scalar params; structured per-actor configs currently live at their owning actor and are mutated by governance-enacted instructions (e.g. UpdateBasefeeConfig).
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
5.2 Tiered parameters
All values are initial defaults. Every number in this table is itself governance-tunable via Tier 4.
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.
⚠️ On-chain status (2026-07) — deployed timing is demo-scale, and errors are generic. The day-scale durations in this table and in §7.7 are the intended values; the current genesis defaults are compressed to demo-scale block counts (node/types/src/constants.rs,runner/src/types.rs): e.g.TEMP_CHECK_BLOCKS = 100,MIN_VOTING_BLOCKS = 5, per-tiertimelock_blocks= 5/5/7/7/14,PAUSE_DURATION_BLOCKS = 7,PAUSE_EXTEND_BLOCKS = 30,MIN_ROLLBACK_WINDOW_BLOCKS = 7,CANCELLATION_REVIEW_WINDOW_BLOCKS = 90— all governance-tunable. Separately, the on-chain code defines no governance-specific error taxonomy: every governance rejection surfaces as a genericExecutionError→ structured codeUnauthorized (1211),InvalidData (1213), orActorPaused (1219)(node/execution/src/structured_error_map.rs). A proposal/council/tier/quorum-specific error set would need to be added if desired.
5.3 Proposal body
Proposals reference a content-addressed body stored in CBFS:5.4 Payload types
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
⚠️ On-chain status (2026-07) — the deployed tally is simplified and fail-closed. The stake-weight snapshot integration is not yet wired (COW-1028):voting_snapshot_total/validator_snapshot_totalare defined on the proposal but currently written as0. Consequences in current code (runner/src/types.rs::resolve_at/participation_below_floor): (a) with a zero denominator a proposal resolvesDefeated— governance is effectively inert until the snapshot writer lands; (b) the stake tally is an unweighted distinct-address count (1 vote per address), not the token/stake-weighted model described in §6.2; (c) the per-tierstake_quorum_pctthresholds exist inTierParamsbut are not enforceable while the denominator is 0. The weighted/snapshotted model below is the intended design; treat it as pending COW-1028.
6.1 Bicameral rule
A proposal passes if and only if all of: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 atvoting_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’svoting_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:
temp_check_min_participation_pct= 1% of active staketemp_check_approval_pct= 33%
6.5 Tallying, finalization, and participation-triggered extension
Running tallies are computed by a tick handler invoked each block while any proposal is inVoting. 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)
validator_participation >= voting_min_validator_participation_pctstake_participation >= voting_min_stake_participation_pct
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 daymax_voting_extensions= 3
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 by0x09 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)
executable_at is known:
activation_block = executable_at + activation_delay_blocksrollback_deadline = activation_block + rollback_window_blocks
executable_at has not yet been determined.
⚠️ On-chain status (2026-07). The deployedSubmitUpgradeSystemActorProposalpayload carries only{ target, new_code_hash: [u8;32] (keccak256 of bytecode), activation_delay_blocks, rollback_window_blocks }(plus the generic proposal fieldsdescription_hash,voting_blocks,tier). There is nocode_ref, nomigrationspec, and nospec_refin the on-chain struct (cowboy-protocol-codecSubmitUpgradeSystemActorProposal; stored fields inrunner/src/types.rs; enacted recordActorVersionRecord { version, code_hash, activated_at_block, rollback_deadline_block }). Code is referenced solely by its 32-byte hash; the CBFScode_ref/spec_refand themigrationmachinery below (§7.4.b) are part of the intended design but are not yet on-chain — enactment (gov_enact.rs::apply_upgrade_system_actor) only writes thecode_hash/rollback pointer, and the bytecode fetch + dispatcher code-swap are explicitly external/future.
7.2 Validation at submission
Before accepting the proposal,0x09 verifies:
targetis a pausable/upgradeable system actor. The code enforces an explicit allowlist (is_pausable_actor,node/types/src/pause.rs), not a contiguous range:{0x04, 0x05, 0x06, 0x07, 0x08, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x13, 0x14, 0x1D, 0x1E}. Excluded (and why): the job trio0x01–0x03(coupled into block construction),0x09GOVERNANCE (self-lock),0x0ASTORAGE_MANAGER and0x0BRELAY_REGISTRY (epoch-boundary unconditional writes → brick risk),0x11VALIDATOR_SET (consensus liveness), and reserved0x12. (0x06and0x13are pausable because their write paths were isolated so a pause no longer halts block production.)targetMUST NOT be0x09(self-upgrade goes through Tier 4, §7.3).code_refresolves to bytecode whose hash matchesnew_code_hash.- Bytecode passes the PVM determinism whitelist (no forbidden imports, no non-deterministic ops).
- Bytecode size is within
max_system_actor_bytecode_size(Tier 0 param, default 512 KiB). rollback_window_blocks >= blocks_per_day * 7(minimum 7-day rollback window).
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’smigration 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)
Whenmigration is None, there is no state transformation and no quiesce. At activation_block, 0x09 performs a single atomic transition in one system transaction:
- Copy the current
VersionRecordfortargettorollback_slot[target]. - Write the new
VersionRecordtoactor_versions[target]. - Emit
SystemActorUpgraded(target, old_version, new_version).
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
Whenmigration is Some(spec), the migration needs a consistent state snapshot, so target is briefly quiesced. The flow at activation_block:
0x09placestargetin quiesce state: new inbound messages totargetare held in a queue; in-flight messages already dispatched in the current block drain against the old code.- Once the drain completes (typically the next block),
0x09performs these steps in one atomic system transaction: a. Copy the currentVersionRecordfortargettorollback_slot[target]. b. Write the newVersionRecordtoactor_versions[target]. c. Invoketarget.migration.fn_name(migration.args)under the new code, logged asMigrationExecuted. ⚠️ Normative (security): this migration call MUST run under a bounded gas/cycle cap (a governance-tunablemax_migration_cycles), not “unlimited gas” — an uncapped migration that infinite-loops would halt block production. A migration that exceeds the cap is treated as a step-(c) failure and triggers the atomic rollback in step 3. (This entire migration path is not yet implemented on-chain — see the §7.1 on-chain-status note; when built, the cap is mandatory.) d. Compute the post-migration state hash oftargetand compare tomigration.expected_state_hash_after(if supplied). - Atomic rollback on failure. If step (c) reverts, or if step (d) disagrees with the expected hash,
0x09reverts steps (a)–(c) in the same atomic transaction. After rollback,targetis back on its prior (known-working) code and state.0x09then automatically releasestargetfrom quiesce and emitsMigrationFailed { 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. - On success,
0x09emitsSystemActorUpgraded(target, old_version, new_version)and releasestargetfrom quiesce. Queued messages resume dispatch against the new code.
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
Untilrollback_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:
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 signedCircuit { target, action: Pause } message to 0x09. Effects:
- All messages to
targetrevert withActorPaused. paused_actors[target]records the pausing signers, the pause block, and anexpires_atblock (initiallypause_block + 7 days).0x09automatically 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
- Payload:
-
paused_actors[target]tracks anextension_count: u32alongsideexpires_at.extension_countstarts at 0 when the pause is first invoked. -
A passing Tier 3
RatifyExtendproposal extendsexpires_atbypause_extend_blocks(Tier 0 param, default 30 days) and incrementsextension_countby 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 4MetaGovernance { 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_countto 0 if the Tier 4 vote also transitions the actor back to Tier 3 renewal (via a suppliednew_expires_at); otherwise the permanent flag takes over andextension_countis no longer consulted. -
An unpause at any time requires a Tier 3
Circuit { target, action: Unpause }proposal. On successful unpause,extension_countis reset to 0 andpaused_actors[target]is cleared. -
If the initial ratification proposal fails, or if
expires_atis reached with no active extension proposal, the pause auto-reverts and the Council signers are flagged in the portal for community review.
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 signedCircuit { 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):
cancellation_review_window_blocks (Tier 0 param, default 90 days) and cancellation_review_threshold (Tier 0 param, default 3) be governance-tunable.
- On every Council cancellation,
0x09appends a record tocouncil_cancellationsand emitsCancellationExecuted { proposal_id, signers, block }. 0x09then counts entries incouncil_cancellationswhosecancelled_atfalls within(now − cancellation_review_window_blocks, now]. Call this countrecent_count.- If
recent_count >= cancellation_review_threshold,0x09automatically creates a Tier 4MetaGovernance { op: ReviewCouncil }proposal with:- Payload body referencing the
recent_countcancellations and theirproposal_ids - Submitter:
0x09(system-generated) - Deposit: 0 (waived for auto-generated accountability proposals)
- Standard Tier 4 voting parameters (§5.2)
- Payload body referencing the
- The auto-generated proposal can pass with
ReviewOutcome::Affirm(Council behavior judged appropriate; no action),ReviewOutcome::Warn(event logged, no removal), orReviewOutcome::Rotate(replaces a named subset of Council signers; requires the replacement signer list in the payload). - 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.
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 via0x09 and require a validator-coordinated hard fork:
- Block format, transaction format, signature schemes.
- Simplex BFT consensus rules.
- The
0x09upgrade mechanism itself (Tier 4 can change0x09bytecode, but the execution layer must still recognize0x09as the authority — changing that is a fork). - Genesis allocations.
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-11 DNS-addressable gateway actor, also owned by the Labs Multisig.
- Reads from the
0x09actor 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
0x09state; 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
paramstable 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:- Use the Cowboy CLI to submit votes and read proposal state.
- Run a local portal from the CBFS volume at any historical hash.
- Point a third-party portal at the same
0x09contract.
0x09 authority.
9. Open Questions
- 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.
- Multi-choice ballot semantics. First option above approval threshold, or highest-ranked option that clears a minimum? Default is the former.
- Minimum Security Council rotation cadence. Is 2 seats per year enough? Should it be proportional to Council size?
- 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.
- Delegation override cost. Delegators who override their validator’s vote pay a small fee (System lane). What fee? Default: basefee only, no premium.
- Liveness-critical pause targets beyond
0x09. §7.7 forbids pausing0x09but permits pausing other system actors. In practice some pauses are economically disruptive (e.g.,0x02halts the runner marketplace,0x06would 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. - 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?
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 into0x09? 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-11 — DNS-addressable gateway actor used by the portal frontend

