Skip to content

Commit cdb97ef

Browse files
committed
add AI contribution guidelines
1 parent 6b25863 commit cdb97ef

1 file changed

Lines changed: 33 additions & 11 deletions

File tree

CONTRIBUTING.md

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Recommended setup:
3333
3. 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

3838
If 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
212234
abstract 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

Comments
 (0)