This document gives more-or-less complete docs on how the first EC ran this election.
- Create a new repository for the election
- Create an
ec-<YEAR>
team for the EC and give it admin access to the repository - Ensure the existence of an election GitHub App, reusable for every election.
To create it initially:
- Have an org owner create a new App
- Title: Nix Elections
- URL: https://nixos.org
- Disable Webhooks
- Permissions:
- Repository Permissions > Pull Requests: Read and write
- Repository Permissions > Issues: Read and write
- Repository Permissions > Contents: Read and write
- Organization Permissions > Members: Read and write
- Ensure the App is installed on the org
- Give the App access to the current election repository
- Set the App ID as a new repository variable named
APP_ID
- Generate a private key for the App and set it as a new repository secret named
PRIVATE_KEY
- Have an org owner create a new App
- Set up
[email protected]
as an alias for the EC members addresses. Could also beelection<YEAR>@nixos.org
going forward. - Send the mail server, SMTP user and password to the EC members, potentially regenerating the password to revoke access to previous EC members
- Make sure that you have a good enough email setup for sending many emails
- Ensure that a public Matrix room for the elections is set up
- Make sure the EC has moderator permissions for the room
-
Set the SMTP password as a new repository secret with key
SMTP_PASSWORD
-
Create a private room for the EC members to decide over things (Matrix or otherwise)
-
In the repositories Moderation options, limit interactions to repository collaborators for the maximum possible duration (should be 6 months)
- Note that anybody in the organisation can interact with the repository regardless, but CI will ask non-voters to abstain from doing so
-
Set up branch protection for the repo
-
Set up a GitHub team for the voters:
- Create a team for the voters:
- Name: Voters
- Description: Voters for the Steering Committee election"
- Team visibility: Visible
- Team notifications: Enabled
- Remove yourself as team maintainer, the automation will maintain the team
- Add the voter team as a repository collaborator with the read role
- This doesn't grant any extra access, because users in the organisation will be able to interact with the repository anyways However it does provide context to users when they get the team invite, letting them see which repository this team is related to.
- Set the team's slug (should be
voters-<YEAR>
) as a new repository variable namedVOTER_TEAM
- Create a team for the voters:
-
Ensure that a "nomination", "question" and "enough endorsements" label exists for the repository
-
Initialise the repo from the previous election.
Important: Before pushing, empty
voters.json
to prevent automation from inviting all those users already- Remove or empty
scripts/invited.txt
andscripts/endorsersAsked.txt
- Remove
removed-voters-due-to-bounced-emails.json
- Remove
opavote_ballots.blt
andcivs_ballots.csv
- Empty
candidates
- Ensure the repo reflects the current version of the Nix Governance Constitution
- Check that the voting platform is still functional and find an alternative otherwise
- Grep for
TODO
in the repo and address it as necessary - Update the year
- Update the EC contact info
- Decide on the timeline and update it in the
README
and other places
- Remove or empty
-
Pick a cut-off date and set it as
endEpoch
inconfig.nix
. Set thestartEpoch
to 4 years before theendEpoch
.Then prebuild the GitHub data and push it to a cache:
nix-build -A data.prebuiltDerivations | cachix push nca
This takes a lot of resources!
-
Make a test run of everything and improve things as necessary.
Note that if you test in a private repo, you should enable private repo forking and maybe set the base organisation access to None, because the GitHub App invites users to the organisation, which gives them access to all private repos by default.
-
Create a retro document to write things down that could be improved for the future.
-
Make sure every EC member can send and receive emails from
[email protected]
. If ImprovMX is still the Mail service used, follow this tutorial.Make sure to set the identity to "Nix Election Committee" or so
-
Enable notifications for the public Matrix room
-
Subscribe to all activity on the election repository
The ec/default.nix
file contains code to automate announcements, able to take care of:
- Sending hundreds of personalised emails to voters.
- Ensuring proper formatting on GitHub and Discourse (where single newlines cause line breaks).
- Ease linking to repository files.
- Customise announcements based on the platform.
In general the workflow is always:
-
Announce on Discourse with (
$NAME
is the name of the announcement, use auto-complete):nix-build ec -A $NAME.discourse
Then post the contents of
result
to Discourse, potentially as a reply to a previous announcement. -
For more important announcements, post it to the website, linking to Discourse, with:
nix-build ec -A $NAME.website --argstr discourseLink $DISCOURSE_LINK
Then make a PR against the website announcements, ensuring that CI passes and ping somebody from the marketing team to merge it.
-
Send emails to voters (needs
SMTP_PASSWORD
set):nix-build ec -A $NAME.email --argstr discourseLink $DISCOURSE_LINK ./result
If 10 emails fail to send, it stops, but it can be resumed with
./result --resume
You can view failed sends in
jobs.log
, but you might also get delayed (up to ~1 day) mail delivery failure responses.Reach out to people whose email bounced by pinging them on GitHub and optionally removing their email from the
voters.json
file. -
Announce it on GitHub:
nix-build ec -A $NAME.github --argstr discourseLink $DISCOURSE_LINK
Then post
./result
as a PR (or a reply to an existing PR) to the election repo, requesting a review from the voters GitHub team (which will ask you to explicitly confirm to send a notification to so many users).Lock the PR to only collaborators (with write access), so that only the EC can send further notifications using it.
Then, remove the teams review request again, so that it doesn't stick around in users "to review" column without being able to review it (since it's locked)
-
Update the blocked users list: Have an org admin get the GitHub ids using
gh api /orgs/NixOS/blocks --jq '.[].id'
Then Insert them into
config.nix
.Don't update this once the voters are generated.
-
Generate
voters.json
usingnix-build -A generateVoters ./result
-
Announce it,
$NAME
iskickoff
-
Push the generated
voters.json
to start triggering team additions -
Directly contact the users in
usersWithoutEmailAndGitHub.txt
Process EC requests as documented in process.md
and keep the timeline in mind throughout and send reminders throughout as described below.
The weekend before the nomination deadline, do the announcement with $NAME
as reminder1
.
- Open an issue like this
- Send emails to unconfirmed candidates using the various attributes under
unconfirmed
:
nix-build ec -A unconfirmed.needsToAccept
./result $GITHUB_HANDLE $NOMINATION_PR
nix-build ec -A unconfirmed.needsToSubmitFormAndNeedsMoreEndorsements
./result $GITHUB_HANDLE $NOMINATION_PR
nix-build ec -A unconfirmed.needsToSubmitForm
./result $GITHUB_HANDLE $NOMINATION_PR
nix-build ec -A unconfirmed.needsMoreEndorsements
./result $GITHUB_HANDLE $NOMINATION_PR
- Optionally PM the nominees via other means (e.g. Matrix) in case the above means fail.
-
Close all PRs of candidates that didn't meet the criteria with a comment mentioning the unmet criteria.
-
Decide with the EC on which (if any) candidates have a conflict of interest and update the source for
reminder2
with the result. -
Copy all candidate forms for confirmed candidates from the internal EC repo into this repo.
-
Delete the internal EC repo.
-
Send a reminder for the Q&A, updating voter emails and requesting exceptions, by doing an announcement with
$NAME
asreminder2
.
- Push Q&A to candidate forms using this script.
- Start an OpaVote election with:
- Description:
In this election we choose 7 people for the first Nix Steering Committee. See the announcement for more information. You must cast your vote by 2024-11-03 23:59:59 Sun in Anywhere on Earth time, meaning as long as it is still the given day anywhere on the planet (i.e. at the end of that day in UTC-12). After the poll is closed, votes will not be accepted for any reason. Please inform yourself about the candidates by looking at their candidate info documents, which include: - Basic contact info - A conflict of interest disclosure - A statement on their motivation to be on the Steering Committee - All Q&A questions answered by the candidate, followed by ones not answered If you have a question, please contact the Election Committee. TODO: Token timeout
- Enable automatic reminders (note that you can update the reminder text over time).
- If you intend to use OpaVote to tally the results, pick an appropriate method and number of winners, otherwise pick any method and the same number of winners as candidates.
- Add all the voters by building
nix-build -A voters
and uploadingresult/emails.txt
.
- Description:
- Send the announcement with
$NAME
as (voteStart
,corruption
,restart
) - Turn off the Auto-merge update email PR workflow, because EC members will need to manually add emails to OpaVote when merging a PR from now on.
Send a final voting reminder like this to voters using GitHub and Discourse.
- Close the OpaVote poll and download the ballots, storing them under
opavote_ballots.blt
. - Run
nix-build -A verifyBallotMatch
to generateresult/civs_ballots.txt
- Create a new CIVS poll, making sure to check:
- Make this a test poll: read all votes from a file.
- Enable detailed ballot reporting"
- Enforce proportional representation (rank of their favorite choice)
- Close the CIVS poll to get the result
- Download the CIVS ballots from
https://civs1.civs.us/cgi-bin/download_ballots.pl?id=$POLL_ID
, store it in the repo ascivs_ballots.csv
- Update the verification docs here.
- Post the announcement with
$NAME
asresult
. - Do final cleanups of this repository and archive it.
The 2024 election didn't have any CoIs among candidates, but if future elections do, here's some notes:
- Next to the candidate names, indicate other people they conflict with. When looking at election results, this allows voters to easily spot when two conflicting people would be elected and know that one of them will be disqualified.
- The description of the election should point out that the result of the election might not be correct depending on the conflicts.
- Remove the candidate with the least votes from the CIVS ballots and create a new test poll with the changed ballots
- Note that OpaVote also charges for recounts of ballots