Skip to content

Feature request: "simple majority of cast votes" pass mode (more +1 than -1, excluding abstentions and non-voters) #707

Description

@hendrikebbers

Add a pass mode where a vote passes when there are more binding votes in favor (+1) than against (-1), and where abstentions (eyes) and maintainers who did not vote are not counted at all.

Today the pass decision is a percentage of all allowed voters and never looks at the against count. Our governance requires the opposite: a plurality of the votes actually cast, ignoring everyone who abstained or stayed silent. We currently cannot express this with pass_threshold.

Current behavior

From src/results.rs, the result is computed as:

in_favor_percentage = in_favor / allowed_voters.len() * 100
passed = in_favor_percentage >= pass_threshold

This means:

  1. The denominator is always the full set of allowed_voters. Abstentions (eyes) and non-voters stay in the denominator and drag the percentage down — there is no way to exclude them.
  2. The against count is tracked (against_percentage) but never used in the passed decision. There is no "more in favor than against" comparison.
    So a vote with 2 in favor, 0 against, 10 abstentions in a 12-maintainer team yields 2 / 12 = 16.7 %, which fails at any pass_threshold >= 17. Lowering pass_threshold doesn't help either, because a low threshold would also pass a vote with more -1 than +1 (e.g. 2 in favor, 10 against), since against is ignored.

Use case

The Hiero project (LF Decentralized Trust) uses GitVote for all asynchronous maintainer votes. Our governance defines the passing rule as follows (see roles/roles-and-groups.md, "Voting" section):

A vote passes when more maintainers have voted in favor (+1 / thumbs up in GitVote) than against (-1 / thumbs down in GitVote). Maintainers who abstain or do not vote are not counted. For example, 2 votes in favor and 0 against with 10 abstentions is a passing vote.

Abstaining is an explicit, first-class outcome in our process: maintainers are required to participate in a nomination but may effectively abstain by only posting a comment. Non-participation is a separate governance concern (inactivity), not a "no" vote. So neither abstentions nor non-voters may count toward or against the result.

We suspect this "plurality of participants" model is common in maintainer/promotion votes and would be useful beyond our project.

Proposed solution

Introduce an alternative pass mode, selectable per profile. For example:

profiles:
  default:
    duration: 5m
    # Instead of pass_threshold, allow a mode that compares cast votes:
    pass_mode: simple_majority   # passes when in_favor > against; abstain & not_voted ignored
    allowed_voters:
      teams:
        - project-maintainers

Behavior of simple_majority:

  • passed = in_favor > against (binding votes only).
  • Abstentions and non-voters are excluded from the decision entirely.
  • Optionally require at least one +1 (i.e. an empty vote with 0 in favor and 0 against does not pass).
    Naming is of course up to you (pass_mode, or a quorum/majority sub-section). The key point is a mode that (a) compares in_favor against against, and (b) uses cast votes rather than the full allowed_voters set as the basis.

Alternatives considered

  • Low pass_threshold: rejected — it ignores against and would pass votes with more -1 than +1.
  • Threshold as a % of all maintainers: changes the semantics (a fixed quorum of the whole team), and depends on team size; it does not match "more for than against, ignore abstentions".
  • Custom GitHub Action counting reactions: works, but we'd rather keep using GitVote as the single, consistent voting tool across all Hiero projects.

Additional context

This would also make the existing "close on passing" / early-close logic more expressive for us, since our governance already allows closing a vote early once the outcome can no longer change (enough +1 that remaining votes can't flip it, or enough -1 that +1 > -1 is impossible).

Happy to help implement, test or review a PR for this issue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions