@@ -33,7 +33,7 @@ Recommended setup:
33333 . From the repository root, run ` task setup ` .
3434
3535` task setup ` installs Astral's official standalone ` uv ` if you don't have it, installs a managed
36- Python 3.11 environment, syncs the pinned dependencies, and installs the pre-commit hooks.
36+ Python 3.11 environment, syncs the pinned dependencies, and installs the pre-commit hooks.
3737
3838If you already have ` uv ` installed and prefer to run the steps directly, the equivalent setup is:
3939
@@ -108,7 +108,29 @@ Before opening a pull request, make sure that:
108108- linting, formatting, and type checks pass locally
109109- the PR description explains the user-facing impact and any notable tradeoffs
110110
111- Small pull requests are much easier to review and merge than large mixed changes.
111+ Small pull requests are much easier to review and merge than large, mixed changes.
112+
113+ ## Use of AI tools
114+
115+ Researchers rely on VoteKit and its results, so contributors have a heightened responsibility for
116+ the correctness and clarity of every change.
117+
118+ - Core implementation and business logic in ` src/votekit/ ` must be written by humans. AI tools may
119+ provide inline assistance (e.g., an editor copilot) and may be used to navigate and deepen
120+ understanding of the codebase and domain material (e.g., with chat agents). Contributors should
121+ not delegate the generation or rewriting of core implementation code to agentic coding tools.
122+ For example, Codex GUI/CLI, Claude GUI/CLI, Cursor v3+, and similar tools should not be asked to
123+ generate or substantially rewrite that code.
124+ - Tests may be developed jointly by humans and AI. AI is particularly useful for adversarial
125+ testing, such as searching for user inputs that break an implementation, but the person
126+ responsible for the pull request must review every AI-generated or AI-assisted test and confirm
127+ that it meaningfully tests the intended behavior.
128+ - Docstrings may be developed jointly by humans and AI. The person responsible for the pull
129+ request must read, edit, and review every AI-assisted docstring for accuracy, thoroughness, and
130+ compliance with the documentation and formatting guidelines below.
131+
132+ The person responsible for a pull request remains accountable for all of its contents, regardless
133+ of which tools assisted in preparing it.
112134
113135## Code style guidelines
114136
@@ -119,7 +141,7 @@ the current conventions below and avoid style-only churn in unrelated files.
119141 and linting.
120142- Use absolute imports in all implementation files. Relative imports are only used in ` __init__.py `
121143 files for re-exporting. For example, prefer `from votekit.elections.election_state import
122- ElectionState` over ` from ..election_state import ElectionState`.
144+ ElectionState` over ` from ..election_state import ElectionState`.
123145- Keep lines at roughly 100 characters to match the configured formatter and linter settings.
124146- Add type annotations for function parameters and return values. Run ` uv run ty check src tests `
125147 on changes that add or reshape APIs.
@@ -179,7 +201,7 @@ Tests are required for behavior changes.
179201 ` tests/elections/... ` .
180202- Cover both successful behavior and expected failures.
181203- When raising exceptions, prefer tests that check the error message with `pytest.raises(...,
182- match=...)`.
204+ match=...)`.
183205- Include edge cases that are natural for the change: empty inputs, invalid candidate data,
184206 malformed rankings, tie handling, or zero-weight behavior.
185207- Mark long-running tests with ` @pytest.mark.slow ` .
@@ -202,11 +224,11 @@ export the class from the subfolder's `__init__.py` and from `src/votekit/electi
202224
203225### Choosing a base class
204226
205- | Ballot type | Base class | Profile type |
206- | ---------------------- | ------------------------------------------------------- | ---------------- |
207- | Ranked ballots | ` RankingElection ` | ` RankProfile ` |
208- | Score/rating ballots | ` GeneralRating ` (or ` Election[ScoreProfile] ` directly)| ` ScoreProfile ` |
209- | Approval ballots | ` GeneralRating ` (with ` per_candidate_limit=1 ` ) | ` ScoreProfile ` |
227+ | Ballot type | Base class | Profile type |
228+ | -------------------- | ------------------------------------------------------ | -------------- |
229+ | Ranked ballots | ` RankingElection ` | ` RankProfile ` |
230+ | Score/rating ballots | ` GeneralRating ` (or ` Election[ScoreProfile] ` directly) | ` ScoreProfile ` |
231+ | Approval ballots | ` GeneralRating ` (with ` per_candidate_limit=1 ` ) | ` ScoreProfile ` |
210232
211233` RankingElection ` and ` GeneralRating ` both ultimately inherit from ` Election[P] ` , the root
212234abstract base class in ` src/votekit/models.py ` .
@@ -297,5 +319,5 @@ abide by the expectations in [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
297319
298320## Questions
299321
300- If anything in the contribution process is unclear, please feel free to reach out to
301- ` code@mggg.org ` with questions. Thanks!
322+ If anything in the contribution process is unclear, please feel free to reach out to
323+ ` code@mggg.org ` with questions. Thanks!
0 commit comments