# Story 10.16: Python 3.10+ Minimum Enforcement

**Status:** Complete
**Priority:** Medium
**Depends on:** None

---

## Context / Background

The project declares `requires-python = ">=3.10"` in `pyproject.toml:32`, but the linting and type-checking tools still target Python 3.8:

- `pyproject.toml:274` - ruff `target-version = "py38"`
- `pyproject.toml:364` - black `target-version = ['py38']`

This inconsistency means:
1. Linters allow Python 3.8 syntax patterns that could be simplified with 3.10+ features
2. No runtime guard prevents developers from accidentally using Python < 3.10 locally
3. Modern Python features like `match` statements, union types (`X | Y`), and `ParamSpec` are flagged unnecessarily

---

## Scope (In / Out)

### In Scope

- Update ruff `target-version` to `py310`
- Update black `target-version` to `['py310']`
- Update mypy `python_version` to `3.10`
- Add pre-commit hook to validate Python >= 3.10
- Verify all CI workflows use Python 3.10+

### Out of Scope

- Expanding CI test matrix (nightly already tests 3.10, 3.11, 3.12)
- Refactoring existing code to use 3.10+ syntax (future story)
- Dropping 3.10 support to require 3.11+ (separate decision)

---

## Acceptance Criteria

### AC1: Tool Target Versions Updated

**Description:** All linting/formatting tools target Python 3.10 as minimum.

**Validation:**
```bash
grep -E "target-version.*py3" pyproject.toml
# Should show py310, not py38
```

### AC2: Pre-commit Python Version Guard

**Description:** Pre-commit fails fast if running on Python < 3.10.

**Validation:**
```bash
# Simulated test (actual Python check)
python -c "import sys; assert sys.version_info >= (3, 10), 'Python 3.10+ required'"
```

### AC3: No CI Workflows Use Python < 3.10

**Description:** All GitHub Actions workflows specify Python 3.10 or higher.

**Validation:**
```bash
grep -rn "python-version" .github/workflows/ | grep -v "3.1[0-9]"
# Should return empty (no versions below 3.10)
```

### AC4: Mypy Python Version Aligned

**Description:** Mypy targets Python 3.10 for type checking.

**Validation:**
```toml
# pyproject.toml
[tool.mypy]
python_version = "3.10"
```

---

## Implementation Notes

### File Changes

```
pyproject.toml (MODIFIED - update target-version settings)
.pre-commit-config.yaml (MODIFIED - add python version check hook)
```

### Key Changes

**pyproject.toml:**
```toml
[tool.ruff]
target-version = "py310"  # was py38

[tool.black]
target-version = ['py310']  # was py38

[tool.mypy]
python_version = "3.10"  # was 3.11 - align with minimum
```

**Pre-commit hook:**
```yaml
- repo: local
  hooks:
    - id: check-python-version
      name: Check Python >= 3.10
      entry: python -c "import sys; exit(0 if sys.version_info >= (3, 10) else 1)"
      language: system
      pass_filenames: false
      always_run: true
      stages: [pre-commit]
```

---

## Tasks

### Phase 1: Configuration Updates

- [ ] Update ruff target-version to py310
- [ ] Update black target-version to py310
- [ ] Update mypy python_version to 3.10

### Phase 2: Pre-commit Guard

- [ ] Add python version check hook to .pre-commit-config.yaml
- [ ] Test hook locally with Python 3.10+

### Phase 3: Verification

- [ ] Verify all CI workflows use Python 3.10+
- [ ] Run full pre-commit suite
- [ ] Update CHANGELOG

---

## Tests

### Manual Tests

- Run `pre-commit run --all-files` to verify no regressions
- Run `hatch run lint:lint` to verify ruff works with new target
- Run `hatch run typecheck:typecheck` to verify mypy works

### CI Verification

- All existing CI checks should pass
- No new lint errors from target-version change

---

## Definition of Done

### Code Complete

- [ ] All target-version settings updated to py310
- [ ] Pre-commit hook added and tested
- [ ] No new lint/type errors introduced

### Quality Assurance

- [ ] `ruff check` passes
- [ ] `mypy` passes
- [ ] Pre-commit runs successfully
- [ ] CI pipeline passes

### Documentation

- [ ] CHANGELOG updated

---

## Risks / Rollback

### Risks

1. **Risk:** New lint errors from stricter Python 3.10 checks
   - **Mitigation:** Run `ruff check` before committing; fix any issues

2. **Risk:** Pre-commit hook too aggressive
   - **Mitigation:** Hook only runs on pre-commit stage, not blocking CI

### Rollback Plan

If issues occur:
1. Revert target-version changes in pyproject.toml
2. Remove python version check hook from .pre-commit-config.yaml

---

## Code Review

**Date:** 2026-01-18
**Reviewer:** Claude
**Verdict:** OK to PR

### Summary

Configuration-only changes aligning tool target versions with `requires-python = ">=3.10"`, plus pre-commit guard hook.

### AC Verification

| Criterion | Evidence |
|-----------|----------|
| AC1: Tool target versions | `pyproject.toml:274` ruff `py310`, `:370` black `['py310']` |
| AC2: Pre-commit guard | `.pre-commit-config.yaml:61-67` version check hook |
| AC3: CI workflows 3.10+ | All workflows verified via grep |
| AC4: Mypy python_version | `pyproject.toml:304` `python_version = "3.10"` |

### Quality Gates

- [x] ruff check passed
- [x] ruff format passed
- [x] mypy passed
- [x] No dead code (vulture)
- [x] No Pydantic v1 syntax

---

## Change Log

| Date | Change | Author |
|------|--------|--------|
| 2026-01-18 | Initial draft | Claude |
| 2026-01-18 | Code review passed | Claude |
