feat(voting): add bounded closing, advisory results and explicit governance policy disclosures #45

Open
opened 2026-10-14 03:11:35 +00:00 by PlasticDigits · 0 comments
Owner

Scope and source

Priority: P1. Gap coverage: GAP-027, GAP-028, GAP-045. Derived from GAP_1791945837.md, reviewed code commit f8dbe93df953a78b17cb3304b717dcf84c4cd517. Current e476a68da09645c2308cbf47b90211fcaffcb7af adds only the report, so implementation findings remain applicable. Report evidence is local reproduction/source inspection unless explicitly proposed; no production exploit or current live-readiness claim.

Coverage and sequencing: gap backlog tracker. Workstream 10. Dependencies: 05, 08, 09.

Current codebase

Schema permits draft/open only and votes never expire. Tallies exist in API/DB but dApp list/detail do not show them. Running tallies and any address-specific ballot are public unauthenticated reads. No quorum/pass denominator, roll-renewal lifecycle or delegation/edit policy exists; current ballots are immutable one vote per address.

Why this implementation is needed

Users need a defined participation window and durable results without mistaking advisory token-weighted polling for executable governance or secret ballots.

Relevant files

Record finite duration/close authority and withdrawal/rejection semantics before implementing schema/API/UI changes; bind duration/end intent to signed revision/approval and derive actual close consistently from actual opening. Enforce the deadline in the voting transaction even if a worker is late; materialize idempotent closed state/archive. Show raw weighted For/Against/Abstain, voter counts, dates, per-chain context and frozen eligible denominator only if turnout is displayed. Keep public ballot visibility and immutable voting as documented defaults. Record GAP-045 decisions: no invented quorum/pass label, roll TTL/pruning, delegation, vote editing or veto/execution powers. Any future policy change requires separately versioned rules frozen with the proposal. Add opener/reviewer/reason/history/outcome attribution using audit receipts; do not require optional policy features to release raw results.

Constraints and guardrails

Preserve standalone offchain advisory voting, no new smart contracts or archive-node dependency, BSC as a core electorate, raw 18-decimal integer balances and separate Terra/BSC address identities. Keep Legal fail-closed transactional UI and the proven DEX Terra/Bridge EVM connectors; no browser BSC balance RPC, seed/key prompt or embedded admin/model credential. API must retain a restricted role separate from the ledger writer. Freeze at actual opening, never at draft creation or a client-supplied height. Agents own design, implementation, review and evidence under repository guidance; do not shift approvals/tests to the human or invent PASS evidence.

Acceptance criteria

Votes at/after deadline are rejected atomically and valid earlier votes retain immutable weight. Closed results survive reload/restart and reconcile with DB tallies; running/closed views clearly remain advisory. Zero votes, abstention and chain-specific weights render accurately without floating-point loss or false passed/secret claims. Withdrawal/rejection rights/reasons and defaults are documented.

Test plan: supported paths, failure paths and concurrency

Before/at/after close; vote/close race, delayed worker, duplicate close, restart and timezone display. Empty/single/mixed-chain tallies, abstain, large raw integers, late registration and unchanged frozen power after sale. Authorized/unauthorized withdrawal/rejection in each allowed state. Anonymous/public ballot reads and per-address queries follow the stated visibility rule. Migration of indefinite legacy polls requires explicit disclosed policy, not silent retroactive closure.

Test plan: attack, hack and abuse vectors

Forged/client-backdated times, expired vote replay, close authority escalation, tally/turnout manipulation, nonexistent denominator, private-ballot claims and withdrawal intended to erase cast ballots. Attempt cross-chain identity summing and snapshot rewrite; verify immutable evidence and no automatic fund execution.

Verification and completion criteria

Attach signed lifecycle policy and close-boundary concurrency tests, tally reconciliation fixtures and browser results for both chains. Update governance/API/user docs and verify legacy migration plus real deployed behavior separately; future quorum/privacy/delegation opportunities stay explicitly deferred unless separately specified.

Record commit and pinned toolchain, commands/results and sanitized artifacts. Relevant Rust changes require cargo test --workspace --lib plus isolated Postgres integration (explicit guarded LEDGER_TEST_DATABASE_URL); frontend changes require npm test and production build plus relevant browser cases. Run secret scanning for new fixtures/config. Exercise fresh/upgrade migrations when schema/grants change; report skipped/live-only checks explicitly.

<!-- voting-gap-1791945837:10 --> ## Scope and source **Priority:** P1. **Gap coverage:** GAP-027, GAP-028, GAP-045. Derived from [GAP_1791945837.md](https://git.cl8y.com/code/voting/src/branch/main/gaps/GAP_1791945837.md), reviewed code commit `f8dbe93df953a78b17cb3304b717dcf84c4cd517`. Current `e476a68da09645c2308cbf47b90211fcaffcb7af` adds only the report, so implementation findings remain applicable. Report evidence is local reproduction/source inspection unless explicitly proposed; no production exploit or current live-readiness claim. Coverage and sequencing: [gap backlog tracker](https://git.cl8y.com/code/voting/issues/35). Workstream **10**. Dependencies: [05](https://git.cl8y.com/code/voting/issues/40), [08](https://git.cl8y.com/code/voting/issues/43), [09](https://git.cl8y.com/code/voting/issues/44). ## Current codebase Schema permits draft/open only and votes never expire. Tallies exist in API/DB but dApp list/detail do not show them. Running tallies and any address-specific ballot are public unauthenticated reads. No quorum/pass denominator, roll-renewal lifecycle or delegation/edit policy exists; current ballots are immutable one vote per address. ## Why this implementation is needed Users need a defined participation window and durable results without mistaking advisory token-weighted polling for executable governance or secret ballots. ## Relevant files - [`ledger/migrations/20260830000002_draft_lifecycle.sql`](https://git.cl8y.com/code/voting/src/branch/main/ledger/migrations/20260830000002_draft_lifecycle.sql) - [`operator-voting/src/api.rs`](https://git.cl8y.com/code/voting/src/branch/main/operator-voting/src/api.rs) - [`operator-voting/src/db.rs`](https://git.cl8y.com/code/voting/src/branch/main/operator-voting/src/db.rs) - [`operator-voting/src/payload.rs`](https://git.cl8y.com/code/voting/src/branch/main/operator-voting/src/payload.rs) - [`frontend/src/pages/VoteListPage.tsx`](https://git.cl8y.com/code/voting/src/branch/main/frontend/src/pages/VoteListPage.tsx) - [`frontend/src/pages/VoteDetailPage.tsx`](https://git.cl8y.com/code/voting/src/branch/main/frontend/src/pages/VoteDetailPage.tsx) - [`frontend/src/services/operatorVoting.ts`](https://git.cl8y.com/code/voting/src/branch/main/frontend/src/services/operatorVoting.ts) - [`docs/GOVERNANCE_RESEARCH.md`](https://git.cl8y.com/code/voting/src/branch/main/docs/GOVERNANCE_RESEARCH.md) - [`docs/OPERATOR_VOTING.md`](https://git.cl8y.com/code/voting/src/branch/main/docs/OPERATOR_VOTING.md) - [`docs/FRONTEND.md`](https://git.cl8y.com/code/voting/src/branch/main/docs/FRONTEND.md) ## Recommended solution Record finite duration/close authority and withdrawal/rejection semantics before implementing schema/API/UI changes; bind duration/end intent to signed revision/approval and derive actual close consistently from actual opening. Enforce the deadline in the voting transaction even if a worker is late; materialize idempotent closed state/archive. Show raw weighted For/Against/Abstain, voter counts, dates, per-chain context and frozen eligible denominator only if turnout is displayed. Keep public ballot visibility and immutable voting as documented defaults. Record GAP-045 decisions: no invented quorum/pass label, roll TTL/pruning, delegation, vote editing or veto/execution powers. Any future policy change requires separately versioned rules frozen with the proposal. Add opener/reviewer/reason/history/outcome attribution using audit receipts; do not require optional policy features to release raw results. ## Constraints and guardrails Preserve standalone offchain advisory voting, no new smart contracts or archive-node dependency, BSC as a core electorate, raw 18-decimal integer balances and separate Terra/BSC address identities. Keep Legal fail-closed transactional UI and the proven DEX Terra/Bridge EVM connectors; no browser BSC balance RPC, seed/key prompt or embedded admin/model credential. API must retain a restricted role separate from the ledger writer. Freeze at actual opening, never at draft creation or a client-supplied height. Agents own design, implementation, review and evidence under repository guidance; do not shift approvals/tests to the human or invent PASS evidence. ## Acceptance criteria Votes at/after deadline are rejected atomically and valid earlier votes retain immutable weight. Closed results survive reload/restart and reconcile with DB tallies; running/closed views clearly remain advisory. Zero votes, abstention and chain-specific weights render accurately without floating-point loss or false passed/secret claims. Withdrawal/rejection rights/reasons and defaults are documented. ## Test plan: supported paths, failure paths and concurrency Before/at/after close; vote/close race, delayed worker, duplicate close, restart and timezone display. Empty/single/mixed-chain tallies, abstain, large raw integers, late registration and unchanged frozen power after sale. Authorized/unauthorized withdrawal/rejection in each allowed state. Anonymous/public ballot reads and per-address queries follow the stated visibility rule. Migration of indefinite legacy polls requires explicit disclosed policy, not silent retroactive closure. ## Test plan: attack, hack and abuse vectors Forged/client-backdated times, expired vote replay, close authority escalation, tally/turnout manipulation, nonexistent denominator, private-ballot claims and withdrawal intended to erase cast ballots. Attempt cross-chain identity summing and snapshot rewrite; verify immutable evidence and no automatic fund execution. ## Verification and completion criteria Attach signed lifecycle policy and close-boundary concurrency tests, tally reconciliation fixtures and browser results for both chains. Update governance/API/user docs and verify legacy migration plus real deployed behavior separately; future quorum/privacy/delegation opportunities stay explicitly deferred unless separately specified. Record commit and pinned toolchain, commands/results and sanitized artifacts. Relevant Rust changes require `cargo test --workspace --lib` plus isolated Postgres integration (explicit guarded LEDGER_TEST_DATABASE_URL); frontend changes require `npm test` and production build plus relevant browser cases. Run secret scanning for new fixtures/config. Exercise fresh/upgrade migrations when schema/grants change; report skipped/live-only checks explicitly.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
code/voting#45
No description provided.