Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions .claude/skills/cut-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,24 @@ If any is "no," propose waiting rather than pushing ahead.

From [release.md](../../../docs/standards/release.md):

| Change type | Bump |
|---|---|
| Breaking (removed flag, renamed YAML field, changed exit code) | MAJOR |
| New feature (new trainer, new CLI subcommand, new config field) | MINOR |
| Bug fixes, docs, internal refactor | PATCH |
| Change type | `__version__` bump | `__api_version__` bump |
|---|---|---|
| Breaking (removed flag, renamed YAML field, changed exit code) | MAJOR | — (see below) |
| New feature (new trainer, new CLI subcommand, new config field) | MINOR | — (see below) |
| Bug fixes, docs, internal refactor | PATCH | none |
| Stable library symbol added to `forgelm.__all__` (e.g. new `verify_*` function) | MINOR | MINOR |
| Stable library symbol removed or signature changed | MAJOR | MAJOR |

Current version in [`pyproject.toml`](../../../pyproject.toml) line 7. Single source of truth.
`__version__` (single source of truth: [`pyproject.toml`](../../../pyproject.toml) line 7) tracks the *CLI / YAML / behavioural* contract. `__api_version__` (single source of truth: [`forgelm/_version.py`](../../../forgelm/_version.py)) tracks the *Python library* contract — operators who pin against it for feature detection rely on this signal. The two version numbers are decoupled by design: a release that adds a new training paradigm bumps `__version__` MINOR while leaving `__api_version__` untouched (no new public symbol), and a release that adds a new lazy-import target bumps both.

Library consumers should compare `__api_version__` via `packaging.version.Version` rather than string `>=`, because lexicographic comparison breaks for two-digit minor / patch components (e.g. `"1.10.0" < "1.2.0"` as strings):

```python
from packaging.version import Version
import forgelm

assert Version(forgelm.__api_version__) >= Version("1.0.0")
```

## Pre-release checklist

Expand Down Expand Up @@ -89,6 +100,16 @@ version = "0.4.0" # was "0.3.1rc1" or "0.4.0rc1"

If pre-release → release: drop `rcN` suffix. If new rc: `0.4.0rc1` → `0.4.0rc2`.

### 3.5. Bump `__api_version__` if applicable

**Question to answer:** did this release add, remove, or change the signature of a *stable-tier* library symbol (anything in `forgelm.__all__`)?

- [ ] **No** → leave [`forgelm/_version.py`](../../../forgelm/_version.py) `__api_version__` untouched. Most releases sit here (CLI features, YAML knobs, internal refactors).
- [ ] **Yes, added** → bump `__api_version__` MINOR. Library consumers can then pin `assert Version(forgelm.__api_version__) >= Version("X.Y.0")` (using `packaging.version.Version` — see top-of-skill block) for feature detection.
- [ ] **Yes, removed or signature changed** → bump `__api_version__` MAJOR. The next 0.x release MUST telegraph the break in CHANGELOG's "Breaking" section.

The canonical bump rule lives at the top of [`forgelm/_version.py`](../../../forgelm/_version.py); the matching policy paragraph is in [`docs/standards/release.md`](../../../docs/standards/release.md). `__version__` and `__api_version__` are intentionally decoupled — see the table at the top of this skill.

### 4. Docs alignment

- [ ] If a new CLI flag was added: [`docs/reference/usage.md`](../../../docs/reference/usage.md) + `-tr.md` reflect it
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ jobs:
# outbound HTTP call must go through forgelm/_http.py (safe_post /
# safe_get). This grep guard fails CI if any new module reaches
# for requests / urllib / httpx directly.
# Phase 16: every Pydantic field in forgelm/config.py must carry a
# description= argument so the autogenerated configuration reference
# stays in lockstep with the schema. Strict mode exits 1 on any
# undocumented field — a new contributor adding a field forgets the
# description here, not silently drifting from the operator-facing docs.
- name: Pydantic description= guard
run: python tools/check_field_descriptions.py --strict forgelm/config.py

- name: HTTP discipline guard
run: |
set +e
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ docs/analysis/code_reviews/*
!docs/analysis/code_reviews/closure-plan-202604300906.md
!docs/analysis/code_reviews/master-review-opus-202604300906.md
!docs/analysis/code_reviews/split-design-data_audit-cli-202604300906.md
!docs/analysis/code_reviews/wave2b-final-merge-review-prompt.md

# Generated by tools/build_usermanuals.py — produced from
# docs/usermanuals/<lang>/**/*.md during the CI deploy. Not committed;
Expand Down
Loading