# Contributing to `mgf-common`

Thanks for your interest in `mgf-common`. This document tells you
how to get a working dev setup, what we expect from a PR, and
where to discuss design decisions.

## TL;DR

- Read the [`docs/standards/`](docs/standards/) folder; that's the
  bar.
- Run `uv sync --extra dev --extra observability`.
- `uv run pytest`, `uv run mypy src`, `uv run ruff check src tests`,
  `uv run lint-imports` — all four green before opening a PR.
- For non-trivial design changes, file an entry in
  [`FEEDBACK.md`](FEEDBACK.md) first; the discussion happens there.
- Vulnerabilities go to the private channel in [`SECURITY.md`](SECURITY.md),
  not to the public issue tracker.

---

## Project posture

`mgf-common` is the **cornerstone library** for the MGF project
family. Every change you make ripples outward:

1. The library implementation in `src/mgf/common/` — every consumer
   sees this.
2. The cross-project engineering standards in
   [`docs/standards/`](docs/standards/) — every consumer's bar.
3. The reference consumer ([VManager](https://codeberg.org/magogi-admin/VManager))
   imports both.

That's the right time for high standards. We aim for:

- **`mypy --strict` clean** on every PR.
- **Coverage ≥ 80%** on the package; **≥ 90%** on changed lines.
- **Docs grounded in code that runs.** A standards doc that drifts
  from `mgf.common` is the worst failure mode for the cornerstone
  posture.
- **Pre-1.0 churn welcome — post-1.0 churn forbidden.** See
  [`FEEDBACK.md`](FEEDBACK.md) for the API-stability discussion.

If your change touches the public API, read
[`docs/standards/API_DESIGN.md`](docs/standards/API_DESIGN.md)
first — it spells out the deprecation cycle, the SemVer discipline,
and the `PUBLIC_API.md` contract.

---

## Setting up your dev environment

```bash
git clone ssh://git@codeberg.org/magogi-admin/mgf_common.git
cd mgf_common

# uv is the recommended Python package manager:
#   https://docs.astral.sh/uv/
uv venv
uv sync --extra dev --extra observability
```

Verify:

```bash
uv run pytest -q
uv run mypy src
uv run ruff check src tests
uv run lint-imports
```

All four MUST pass before you start changing code; if they don't,
your environment is wrong before any PR is on the table.

### Tooling versions

The package targets **Python 3.11+** and runs against 3.11, 3.12,
and 3.13 in the CI matrix. Develop on whichever version matches
your local default, but ensure your changes don't accidentally use
3.13-only syntax in a path that runs under 3.11.

---

## What to read before your first PR

Required:

1. [`docs/standards/README.md`](docs/standards/README.md) — the
   master index to the engineering standards.
2. The Rules box at the top of every topic doc your change
   touches.
3. [`docs/claude/CLAUDE.md`](docs/claude/CLAUDE.md) — the dense lookup with
   gotchas, invariants, and phase-by-phase critical facts.
4. [`FEEDBACK.md`](FEEDBACK.md) — the early-consumer feedback
   pipeline; your change MUST NOT contradict an Accepted decision
   recorded there.

Recommended:

- [`docs/standards/COMMON_COMPONENTS.md`](docs/standards/COMMON_COMPONENTS.md)
  §"Maintaining compliance over time" — the compliance-rhythm
  pattern that future contributors will use to audit your code.
- [`docs/internal/EXTRACTION_HISTORY.md`](docs/internal/EXTRACTION_HISTORY.md) —
  the extraction history; explains *why* the package looks the
  way it does.

---

## The PR process

### 1. Open an issue or feedback entry first (for non-trivial work)

Trivial: typo fix, doc clarification, single-function bug fix
with test. Open the PR.

Non-trivial: new public API, new dependency, refactor that touches
≥3 modules, change to a `docs/standards/` MUST. Open an issue (or
add to [`FEEDBACK.md`](FEEDBACK.md) as a 🟢 Suggestion or 💭
Aspirational entry) and let discussion happen first. The PR you
open *after* the discussion is much more likely to merge.

### 2. Branch + work

- Branch from `master`. Branch names: `<topic>-<short-description>`
  (e.g., `security-add-pip-audit-step`, `docs-fix-cf07-link`).
- Commits follow [Conventional Commits](https://www.conventionalcommits.org/):
  `feat:`, `fix:`, `docs:`, `test:`, `refactor:`, `chore:`,
  `security:`. Subject ≤ 70 chars; body explains *why* (the *what*
  is in the diff).
- Atomic commits: one logical change per commit. A 200-line PR
  with 1 commit is harder to review than the same 200 lines split
  into 5 commits with clear stories.

### 3. The four green gates

Before pushing:

```bash
uv run pytest --tb=short -q --cov --cov-fail-under=80
uv run mypy src
uv run ruff check src tests
uv run lint-imports
```

If any of these fails, **don't push** — fix the issue first. CI
runs the same set; pushing red is wasted CI cycles for everyone.

### 4. PR description

The PR description MUST cover:

- **What** — one sentence summary.
- **Why** — the motivation (link to the issue / FEEDBACK entry).
- **How** — the design choice if non-obvious; link to the relevant
  standards doc section if your change implements / closes a MUST
  / SHOULD.
- **Test plan** — the specific assertions that prove the change
  works. "I ran the suite" is insufficient; "I added X test that
  asserts Y" is the bar.
- **Standards compliance** — if your change adopts or closes a gap
  against a `docs/standards/` rule, cite the rule ID
  (e.g., "closes SC-10 by adding `pip-audit` to CI").
- **Breaking changes** — if any, the [`CHANGELOG.md`](CHANGELOG.md)
  `[Unreleased]` `### Changed: BREAKING` block MUST include the
  four-part migration recipe per AP-12.

### 5. Review

Reviews focus on:

- **Standards compliance.** Every claim maps to a MUST/SHOULD in
  the standards.
- **Test coverage.** New code has tests; changed code's tests
  exercise the change.
- **Doc sync.** If you changed a public API, the relevant standards
  doc, [`docs/claude/CLAUDE.md`](docs/claude/CLAUDE.md), and the README's
  Public API listing MUST be updated in the same PR.
- **`CHANGELOG.md`.** Every user-visible change has an entry in
  `[Unreleased]`.

Disagreements about design get worked out in PR threads. If a
thread can't converge, escalate to a `FEEDBACK.md` entry — that
forces a decision with rationale, recorded permanently.

### 6. Merge

Maintainer-merge only. The maintainer rebases-and-merges (no merge
commits unless the PR is unusually large). Squash is OK for tiny
trivial PRs (1-line typo fix, etc.).

After merge:

- The `[Unreleased]` block in `CHANGELOG.md` accumulates entries
  until a release.
- Releases follow the manual workflow in
  [`docs/claude/CLAUDE.md`](docs/claude/CLAUDE.md) §"Build and release".

---

## Specific contribution paths

### Adding to the engineering standards

Every change to [`docs/standards/`](docs/standards/) is a public
contract change. The bar:

- Read the existing voice (dense, code-grounded, AS-IS callouts,
  cross-references). Match it.
- Bump the topic doc's version per the policy in
  [`docs/standards/README.md`](docs/standards/README.md)
  §Versioning: MAJOR for new MUST, MINOR for SHOULD/template, PATCH
  for wording.
- Update the master `docs/standards/README.md` MUSTs index if you
  added a new MUST.
- Add the rule to the relevant topic doc's mechanical-enforcement
  matrix (or write a justification for review-only).

### Adding a new component to `mgf.common`

The high bar — `mgf.common` is intentionally small. Before writing
code, file a [`FEEDBACK.md`](FEEDBACK.md) entry as a 🟢 Suggestion
or 💭 Aspirational and let discussion converge. The "lift candidate"
list at the bottom of [`docs/internal/EXTRACTION_HISTORY.md`](docs/internal/EXTRACTION_HISTORY.md) §12 catalogues
everything we've considered.

If accepted, the path is:

1. Add to `src/mgf/common/<sub>/`.
2. Add the public name(s) to the package's `__all__`.
3. Add to [`README.md`](README.md) public-API listing.
4. Add to `docs/standards/COMMON_COMPONENTS.md` catalogue with
   status, conformance level, lift instructions.
5. Add to [`PUBLIC_API.md`](PUBLIC_API.md) with stability tier
   `experimental` (per AP-11).
6. Tests under `tests/unit/<sub>/` mirroring the source.
7. CHANGELOG entry under `[Unreleased]` `### Added`.

### Reporting a security vulnerability

**Do not open a public issue.** Follow the private channel in
[`SECURITY.md`](SECURITY.md). The team will acknowledge within 3
business days, fix within the policy window, and disclose with
your credit (unless declined).

### Contributing to a consumer (e.g., VManager)

The consumer projects have their own contribution guides. The
shape is the same: standards-grounded, test-covered,
docs-in-sync. The standards live here; the implementation lives
in the consumer.

---

## Communication

| Channel | What it's for |
|---|---|
| **Codeberg issues** | Bug reports, feature requests, public discussion |
| **Codeberg PRs** | Code + doc changes |
| **Codeberg private security advisories** | Vulnerability reports (per [`SECURITY.md`](SECURITY.md)) |
| **[`FEEDBACK.md`](FEEDBACK.md) entries** | Pre-1.0 design discussion that needs to be recorded permanently — opinionated feedback from real consumers |

We do **not** use chat (Discord / Slack / IRC) for design
discussion — chat is ephemeral and excludes future contributors.
PRs and issues are the record.

---

## License

By contributing, you agree that your contributions are licensed
under the project's [MIT License](LICENSE).

---

## Acknowledging the cornerstone posture

This file you're reading and the standards you're being asked to
follow are not bureaucracy. They are the discipline that lets the
MGF family of projects share infrastructure without inventing it
N times in N inconsistent shapes. Every PR you land that respects
the discipline makes the next PR — and the next consumer — easier.

Welcome aboard.
