Skip to content

feat: governance committee quorum persistence#2007

Open
wolf31o2 wants to merge 1 commit intomainfrom
feat/committee-quorum-persistence
Open

feat: governance committee quorum persistence#2007
wolf31o2 wants to merge 1 commit intomainfrom
feat/committee-quorum-persistence

Conversation

@wolf31o2
Copy link
Copy Markdown
Member

@wolf31o2 wolf31o2 commented Apr 22, 2026

Closes #1967

Summary by CodeRabbit

  • New Features

    • Added ability to clear the enacted committee quorum; cleared state is treated as "no quorum enacted" so the system falls back to genesis thresholds until a new quorum is set.
    • No-confidence enactments now clear the enacted committee quorum as part of enactment.
  • Tests

    • Added tests covering clearing behavior, persistence of enacted quorums, rollback recovery, and fallback-to-genesis scenarios.

Summary by cubic

Persist committee quorum updates and add a clear state. No-confidence clears the quorum; ratification falls back to Conway genesis until a new quorum is set.

  • New Features
    • Added ClearCommitteeQuorum(slot, txn) to MetadataStore with mysql, postgres, and sqlite implementations, exposed via database; GetCommitteeQuorum returns nil when cleared.
    • UpdateCommittee persists positive quorum; NoConfidence calls ClearCommitteeQuorum; ratification prefers the DB quorum over genesis and falls back to genesis after a clear. Upserts by added_slot keep mutations idempotent and limited to one per slot.

Written for commit cb2409f. Summary will update on new commits.

@wolf31o2 wolf31o2 requested a review from a team as a code owner April 22, 2026 15:59
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

📝 Walkthrough

Walkthrough

Adds persistence and clearing for enacted committee quorum. A new ClearCommitteeQuorum method is implemented on Database and on MySQL/Postgres/SQLite metadata stores; it upserts a zero-valued quorum row at a slot as a cleared marker. GetCommitteeQuorum now returns (nil, nil) when the latest record is a cleared marker or non-positive. Enactment logic was changed to call ClearCommitteeQuorum for NoConfidence actions. Tests were added to cover persisting an enacted quorum, clearing it via NoConfidence, rollback behavior, and ratify logic preferring DB quorum and falling back to genesis after a clear.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: governance committee quorum persistence' clearly and concisely summarizes the primary change: adding persistence to committee quorum data in governance.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from issue #1967: committee-quorum state store with rollback support, enactment via applyUpdateCommittee, ratification preferring DB quorum with genesis fallback, and comprehensive unit tests.
Out of Scope Changes check ✅ Passed All changes directly support the primary objective: adding committee quorum persistence, clearing on NoConfidence, and ratification fallback behavior. No unrelated modifications detected.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/committee-quorum-persistence

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
database/plugin/metadata/mysql/committee_member.go (1)

90-150: ⚠️ Potential issue | 🟡 Minor

Both SetCommitteeQuorum and ClearCommitteeQuorum upsert on the same unique key—document the at-most-one-mutation-per-slot assumption.

The added_slot column does have a UNIQUE constraint (verified in model definition), so the upsert works correctly and duplicates will not pile up. However, both methods share the same conflict key, so if UpdateCommittee and NoConfidence enact at the same slot, the second call silently overwrites the first's marker. While current Conway rules prevent this (only one ratified proposal per conflicting class per epoch), a one-line comment noting "at most one committee-quorum mutation per slot" would guard against future atomic-enactment changes.

The Sign() <= 0 nil-guard is correctly safe via short-circuit evaluation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@database/plugin/metadata/mysql/committee_member.go` around lines 90 - 150,
Both ClearCommitteeQuorum and SetCommitteeQuorum perform an upsert on the same
unique key (added_slot) so the second mutation at the same slot will overwrite
the first; add a one-line comment near the upsert logic in ClearCommitteeQuorum
and SetCommitteeQuorum (or above the methods) stating the assumption "at most
one committee-quorum mutation per slot (unique on added_slot)" to document why
this behavior is acceptable and to warn future maintainers (reference functions
ClearCommitteeQuorum, SetCommitteeQuorum and the added_slot unique key).
🧹 Nitpick comments (2)
ledger/governance/enact_test.go (1)

201-240: Test relies on implicit zero-deposit short-circuit in refundProposalDeposit.

The comment notes the zero-deposit path short-circuits the reward-account refund, but the test also doesn't configure a reward-address lookup or network state. If refundProposalDeposit ever grows a non-zero-deposit code path that runs unconditionally (e.g. metric/log on return address decode), this test will start failing for unrelated reasons. Consider explicitly setting proposal.Deposit = 0 to make the intent visible even if the field already defaults to zero.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ledger/governance/enact_test.go` around lines 201 - 240, The test relies on
an implicit zero deposit when calling EnactProposal which makes the zero-deposit
short-circuit in refundProposalDeposit fragile; explicitly set proposal.Deposit
= 0 in TestEnactProposal_NoConfidence_ClearsCommitteeQuorum to document intent
and prevent future failures if refundProposalDeposit adds non-short-circuit
logic (update the models.GovernanceProposal instance before calling
EnactProposal to set Deposit to 0, and keep the test’s existing assertions
around EnactProposal and db.GetCommitteeQuorum).
database/plugin/metadata/sqlite/committee_member_test.go (1)

267-308: Good coverage for the clear + rollback semantics.

Both tests exercise the key invariants (clear hides prior quorum; rollback past the clear restores it). Consider adding one more case that calls ClearCommitteeQuorum when no prior quorum exists (start-of-chain) to lock in the "never enacted + cleared marker ⇒ still nil" contract, but this is a nice-to-have.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@database/plugin/metadata/sqlite/committee_member_test.go` around lines 267 -
308, Add a test that verifies ClearCommitteeQuorum when no prior quorum exists
preserves a nil result: create a new test (e.g.,
TestClearCommitteeQuorumWhenNoPrior) that uses setupTestStore, calls
store.ClearCommitteeQuorum with some slot and nil tx (without any prior
SetCommitteeQuorum), then asserts store.GetCommitteeQuorum(nil) returns nil, and
finally verifies a subsequent SetCommitteeQuorum (e.g., at a later slot) still
returns the newly set quorum; reference the existing helpers and methods
SetCommitteeQuorum, ClearCommitteeQuorum, and GetCommitteeQuorum to implement
this case.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@database/plugin/metadata/mysql/committee_member.go`:
- Around line 90-150: Both ClearCommitteeQuorum and SetCommitteeQuorum perform
an upsert on the same unique key (added_slot) so the second mutation at the same
slot will overwrite the first; add a one-line comment near the upsert logic in
ClearCommitteeQuorum and SetCommitteeQuorum (or above the methods) stating the
assumption "at most one committee-quorum mutation per slot (unique on
added_slot)" to document why this behavior is acceptable and to warn future
maintainers (reference functions ClearCommitteeQuorum, SetCommitteeQuorum and
the added_slot unique key).

---

Nitpick comments:
In `@database/plugin/metadata/sqlite/committee_member_test.go`:
- Around line 267-308: Add a test that verifies ClearCommitteeQuorum when no
prior quorum exists preserves a nil result: create a new test (e.g.,
TestClearCommitteeQuorumWhenNoPrior) that uses setupTestStore, calls
store.ClearCommitteeQuorum with some slot and nil tx (without any prior
SetCommitteeQuorum), then asserts store.GetCommitteeQuorum(nil) returns nil, and
finally verifies a subsequent SetCommitteeQuorum (e.g., at a later slot) still
returns the newly set quorum; reference the existing helpers and methods
SetCommitteeQuorum, ClearCommitteeQuorum, and GetCommitteeQuorum to implement
this case.

In `@ledger/governance/enact_test.go`:
- Around line 201-240: The test relies on an implicit zero deposit when calling
EnactProposal which makes the zero-deposit short-circuit in
refundProposalDeposit fragile; explicitly set proposal.Deposit = 0 in
TestEnactProposal_NoConfidence_ClearsCommitteeQuorum to document intent and
prevent future failures if refundProposalDeposit adds non-short-circuit logic
(update the models.GovernanceProposal instance before calling EnactProposal to
set Deposit to 0, and keep the test’s existing assertions around EnactProposal
and db.GetCommitteeQuorum).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 37baf4fe-4157-4941-83e4-e80f99aae0f3

📥 Commits

Reviewing files that changed from the base of the PR and between 493af26 and cd7140a.

📒 Files selected for processing (9)
  • database/committee.go
  • database/plugin/metadata/mysql/committee_member.go
  • database/plugin/metadata/postgres/committee_member.go
  • database/plugin/metadata/sqlite/committee_member.go
  • database/plugin/metadata/sqlite/committee_member_test.go
  • database/plugin/metadata/store.go
  • ledger/governance/enact.go
  • ledger/governance/enact_test.go
  • ledger/governance/ratify_test.go

Comment thread database/plugin/metadata/postgres/committee_member.go
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 9 files

Signed-off-by: Chris Gianelloni <wolf31o2@blinklabs.io>
@wolf31o2 wolf31o2 force-pushed the feat/committee-quorum-persistence branch from cd7140a to cb2409f Compare April 22, 2026 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

governance: persist committee quorum threshold from UpdateCommittee

1 participant