# Contributing

## Development setup

```bash
make install   # create .venv and install all dev + doc dependencies
make check     # lint + typecheck + test (full CI gate)
```

## Workflow

This project follows strict TDD. Before writing any implementation code:

1. Pick a task from `bd ready`
2. Write a failing test in `tests/` that captures the acceptance criteria
3. Run `make test` — confirm it fails for the right reason
4. Write the minimum implementation to make it pass
5. Run `make check` before closing the task

Never write implementation code without a corresponding failing test driving it.

## Validation against lme4

Numerical parity with R's `lme4::lmer()` is enforced by the test suite on every CI run.
Three scenarios are tested, each with a pre-computed oracle file generated from R:

| Scenario | Test file | Groups | Obs |
|---|---|---|---|
| Single random intercept | `test_parity_single_re.py` | 1 (vs statsmodels) | 200 |
| Two crossed intercepts | `test_parity_two_re.py` | 2 (firm × dept) | 2 000 |
| Three crossed intercepts | `test_parity_three_re.py` | 3 (firm × dept × region) | 3 000 |

The oracle fixtures (`tests/fixtures/*.json`) are generated by R scripts that run
`lme4::lmer()` and serialise the results. The Python tests load these and assert the
following tolerances:

| Quantity | Tolerance | How measured |
|---|---|---|
| Fixed effects | abs diff < 1e-4 | per coefficient |
| Variance components | rel diff < 5% | per grouping factor + residual |
| BLUPs (conditional modes) | Pearson *r* > 0.99 | per grouping factor |
| Conditional residuals | Pearson *r* > 0.999 | across all observations |

When adding a new feature that touches estimation, extend the relevant parity test or
add a new fixture to keep these tolerances enforced.

## Releasing a new version

Releases are fully automated once a version tag is pushed.

**Steps:**

1. Bump `version` in `pyproject.toml`
2. Commit the bump:
   ```bash
   git commit -am "chore: bump to vX.Y.Z"
   git push
   ```
3. Tag and push:
   ```bash
   git tag vX.Y.Z
   git push origin vX.Y.Z
   ```

The [`publish` workflow](https://github.com/heliopais/interlace/actions/workflows/publish.yml)
triggers automatically on `v*` tags and:

- Runs the full CI gate (lint + typecheck + tests)
- Publishes the wheel and sdist to [PyPI](https://pypi.org/project/interlace-lme/)
  (silently skips if the version already exists)
- Creates a [GitHub Release](https://github.com/heliopais/interlace/releases)
  with auto-generated release notes

> **Note:** Do not push a tag without first bumping the version in `pyproject.toml` —
> PyPI will reject a duplicate version and the workflow will skip the publish step.
