Files
govoplan-voting/docs/VOTING_DOMAIN.md
T

81 lines
3.8 KiB
Markdown

# Voting domain, assurance, and operations
## Ownership boundary
Voting owns the protocol and authoritative state of a governed ballot:
- immutable ballot definitions after opening
- frozen electorate entries, weights, and provenance
- eligibility enforcement, vote replacement, and receipts
- deterministic tally, quorum, threshold, closure, and certification
- challenge, annulment, command replay, and lifecycle evidence
- provider-neutral handoff for confidential, secret, or externally certified
voting
Committee owns the body, meeting, agenda, deliberation, and minute context. It
stores a Voting ballot reference and a verified aggregate result for meeting
records. Poll owns informal preference, response, and availability collection.
Decisions owns the resulting formal institutional outcome. Encryption and
Identity Trust own cryptographic key and device primitives rather than the
voting ceremony.
## Assurance profiles
The native `recorded` profile stores each current vote with its elector,
selection, weight, generation, and receipt hash. Superseded votes remain
available for authorized reconstruction. It is auditable but **not secret**.
The `confidential`, `secret`, and `external_certified` profiles require a
provider exposed as `voting.provider.<provider-id>`. Voting refuses to open the
ballot when that provider is unavailable. The provider keeps raw ballots and
credentials inside its own assurance boundary and returns aggregate counts,
weighted counts, a result hash, and evidence. GovOPlaN does not claim that a
provider or deployment satisfies legal or certification requirements merely
because the adapter contract is implemented.
## Lifecycle and concurrency
Ballots move through `draft -> open -> closed -> certified`. A closed or
certified result can be challenged. An administrator can annul an invalid
ballot from any non-annulled lifecycle state. Opening freezes SHA-256 hashes of
the definition and electorate. Each state change creates a new immutable
revision and lifecycle event. Mutating commands require an expected revision
and an idempotency key; a key replay returns the first outcome and a key reused
with another payload is rejected.
Recorded voters can replace a vote only when the frozen definition allows it.
The previous generation is retained and excluded from the active tally.
Lifecycle events contain the receipt hash and generation, not the selection.
## Operations and recovery
Back up these tables as one consistency unit:
- `voting_ballot_revisions`
- `voting_cast_records`
- `voting_lifecycle_events`
- `voting_command_replays`
A restore is valid only when current revisions are unique per tenant and
ballot, cast generations are unique per elector, every active cast references
the current frozen definition hash, result hashes can be recomputed, and event
sequences are contiguous. Provider-backed restores also require the external
provider evidence and ballot reference to remain resolvable. Do not reopen a
restored external ballot merely to compensate for missing provider state.
Before destructive retirement, stop new casts, retain a verified database
snapshot, export result/certification evidence under the applicable retention
policy, and reconcile any Committee or Decision references. Horizontal nodes
must use the shared database; no authoritative Voting state is stored on a
node-local filesystem.
## Security checks
- tenant predicates apply to every ballot, cast, event, and replay lookup
- the authenticated account must match the frozen elector subject
- native casting fails closed for non-recorded assurance profiles
- raw selections are never returned by list, detail, result, or history APIs
- provider result keys must exactly match frozen options
- external results require evidence and cannot exceed the frozen electorate
- certification and annulment use separate permissions