Contributing#
This page tells you how to set up cleverly, which checks your change has to pass, and where each
working rule is written down. Read pull requests before you open one. That page
gives the commit style, the pull request body, and what each CI job checks.
What to expect#
One person maintains cleverly, so a review can take several days. Open an issue before you start
a large change. An early conversation is cheaper than a rejected branch.
cleverly is alpha software. The public API can change between 0.1.N releases. A result that one
release saves loads in another release with a VersionMismatchWarning, and the load does not
migrate it. Do not add compatibility code for an earlier release. The “Compatibility” section of
CLAUDE.md states the rule.
The roadmap is the single planning contract. It orders open work by beta
milestone. It keeps work that needs new fundamental theory in a separate future grid. Read its
eligibility rule before you propose a new method. cleverly
accepts established methods and natural extensions of established theory.
The eligibility rule names three acceptance routes: an established method, an acceptable implementation comparison, and a natural extension. A missing comparator never blocks a method, as theory and comparators states. A comparator run that has not finished does not block a method either. The method merges when its Python studies pass, and a later change registers the comparator results.
Set up your environment#
git clone https://github.com/esbraun/cleverly-tmle.git
cd cleverly-tmle
uv venv
uv pip install -e ".[dev,docs]"
The dev extra pins Ruff and mypy to exact versions, and uv.lock resolves them. CI and nox
install the same extra. Do not restate a tool version anywhere else.
The docs extra adds Sphinx. Install it so you can run the documentation build directly, which is
faster than the isolated nox session.
If an editable install points at another worktree, the test suite refuses to run and names both paths. Reinstall the current checkout to fix that.
Pick a branch name#
Branch from main. Use a lowercase prefix and a hyphenated topic.
prefix |
use it for |
example |
|---|---|---|
|
a change to the library or to the tests |
|
|
a change to documentation only |
|
|
a new registered validation study |
|
The remote holds main alone. Delete your branch after it merges.
Run the checks#
command |
what it gates |
|---|---|
|
the lint rules in |
|
formatting, including every Python fence in a Markdown file |
|
types in |
|
the fast suite, which is the default handoff gate |
|
a report on the reader-facing prose. It changes nothing and fails nothing |
|
the documentation build, with every Sphinx warning as an error |
|
distribution metadata, contents, and clean installs |
nox with no argument runs the lint, typecheck, docs, and tests sessions. Those sessions
mirror the CI jobs, so a green nox run predicts a green pull request.
Do not run a study regeneration beside the fast suite. Each process expects the machine’s cores. Fast tests and validation studies explains the design behind the commands.
Read releases before you change src/cleverly/_version.py or create a tag.
Choose the checks your change needs#
your change |
run |
|---|---|
documentation, or a docstring |
|
library code, or a test |
|
a regenerated evidence artifact |
the row above. The fast suite recomputes each study’s verdicts from the artifacts you commit |
a notebook artifact |
|
The fast suite is the handoff gate for every row. It recomputes registered-study verdicts from committed artifacts, so the statistical evidence is checked in minutes rather than hours.
The notebook command executes every cell and replaces the stored outputs. The TWINS notebook needs network access, because it downloads a pinned dataset. The tutorial notebooks run offline. The command then writes a stamp with two halves, and only one half can fail the fast suite. Example notebooks gives the cell outline, the rules, and the procedure for a tutorial notebook.
stamp half |
covers |
the fast suite |
|---|---|---|
gated |
the notebook’s own code cells and stored outputs, its schema, and the repair command |
asserts it equal |
recorded |
the shipped package source, the dependency lock, and the generator |
asserts it present and well formed |
recorded |
the commit, the version, and the generator’s file list |
asserts the file list matches this checkout |
Edit a code cell and the gated half fails until you run the command again. Rename a notebook and
the recorded command fails for the same reason. Edit library code and no notebook gate fails. The
recorded half fingerprints the run’s repository context. It does not reconstruct a dirty tree or
constrain the tree you work in. tests/notebooks.py gives the reason for the split.
A hash comparison cannot see a library change that moved a published number while every cell kept
its bytes. Run python scripts/execute_notebook.py <path> --check to find one. The command
re-executes the notebook and reports each cell whose printed text moved. It writes nothing.
Regenerate every registered study that evaluates a result-determining implementation change. Read fast tests and validation studies to select the affected rows.
Write documentation#
The root README.md and reader-facing documents under docs/ align with Issue 9 of
ASD-STE100 Simplified Technical English. CLAUDE.md states the rules and their limits in full.
Use one idea per sentence, the active voice, the present tense, and a named actor.
Use a table wherever the content is parallel.
docs/README.md is the source map. It states which document holds which record. It also states the
examples contract: a new method entry needs a new tutorial, and the two link to each other in both
directions.
Follow these steps when you change a document.
Rewrite the text your change touches. Do not sweep unrelated pages.
Run
python -m tests.proseand read every finding it reports. Use--path <file>for a report on one file.Fix each sentence where the change improves its meaning or clarity.
After edits, run
python -m tests.prose --updateto refresh the whole ledger. Do not combine--updatewith--path.For each retained finding, record
accepted: <reason>in the last column oftests/prose-report.md. Keep an existing reason if it still applies.
The fast tier rejects findings without an accepted reason and stale ledger rows. Refresh the ledger even when you fix every finding. A mechanical edit that breaks a sentence defeats the report’s purpose. Keep the sentence whole and record why you accept the finding.
Write docstrings#
Docstrings are numpydoc, and sphinx.ext.napoleon is not installed. Write name : type always,
and give one entry for each parameter. The documentation job builds with -W, so a malformed
docstring breaks the published site.
An example runs in the fast tier. Pass explicit learners to every fit, because the default learner
library costs 30 to 120 seconds per fit. CLAUDE.md gives the complete docstring rules.
Add a method, or a validation study#
Read method benchmarking strategy first. Its governing rule is that a row is not written. It is earned by registering a study.
step |
where |
|---|---|
confirm the method is eligible |
eligibility in the roadmap, and theory and comparators |
register the study, with margins declared before the run |
|
name every key the study reports |
|
generate the published tables |
|
Pair each positive claim with a control that fails. A double-robustness claim needs a both-wrong nuisance control. A type-I error claim needs a nonzero-effect power control.
Quote no measured number by hand. The generator writes each table between its generated sentinels, and a fast test checks the result against the committed artifacts.
Add an optional dependency#
Put a new extra inside the dev extra, or give it a CI job that installs it and runs its tests. An
extra that no session installs makes its tests skip, and a skipped correctness check reads exactly
like a passing one.
AI-assisted contributions#
AI-assisted work is welcome, and this project uses it. You own the correctness of what you submit, and you answer each review finding yourself.
Add a
Co-Authored-By:trailer when a tool wrote part of the change. That is the convention here.Check every citation against the source, and every measured number against the artifact that produced it.
A generated statistical claim clears the same evidence gate as any other claim.
Add a nonzero witness or a deliberate-mutation control wherever a sign, mask, guard, or counterfactual block can vanish at the truth. An exact-law check is blind to a term that disappears at the truth.
CLAUDE.md holds the working agreements a coding agent needs, and AGENTS.md points at it.
Report a bug#
The project has no issue templates yet. Include these items in the issue.
item |
why it is needed |
|---|---|
the |
alpha releases can differ from later Git snapshots |
your Python version |
the supported versions are 3.11, 3.12, and 3.13 |
your dataframe backend |
some code paths differ between pandas and polars |
the learners you passed |
estimator behaviour depends on the learner, not on |
a runnable script, with compact data |
a reproducer that runs in seconds gets a faster answer |
the full traceback |
the message alone rarely names the failing module |
License#
cleverly is under the MIT License. Your contribution to the project is licensed under the
same terms.
One directory differs. tests/canonical/ is under the GNU General Public License v3.0,
because its R runners call reference packages in the same process. A contribution to that
directory is licensed under the GPL. No published distribution carries it.