---
phase: 09-config-and-auto-fix
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - pyproject.toml
autonomous: true
requirements:
  - CONF-01
  - CONF-02
  - CONF-03
  - CONF-04

must_haves:
  truths:
    - "pyproject.toml has extend-exclude suppressing .windsurf and .planning from ruff scope"
    - "pyproject.toml has per-file-ignores suppressing E501 for src/corpus_analyzer/llm/*.py"
    - "pyproject.toml has per-file-ignores suppressing B006 for src/corpus_analyzer/cli.py"
    - "pyproject.toml has [[tool.mypy.overrides]] block with ignore_missing_imports = true for frontmatter module"
    - "Running ruff check src/ shows no violations in .windsurf/ paths"
  artifacts:
    - path: "pyproject.toml"
      provides: "All four config stanzas for CONF-01 through CONF-04"
      contains: "extend-exclude"
  key_links:
    - from: "pyproject.toml [tool.ruff]"
      to: ".windsurf exclusion"
      via: "extend-exclude = [\".windsurf\", \".planning\", \"test_debug.py\"]"
      pattern: "extend-exclude"
    - from: "pyproject.toml [tool.ruff.lint.per-file-ignores]"
      to: "llm/ E501 suppression"
      via: "\"src/corpus_analyzer/llm/*.py\" = [\"E501\"]"
      pattern: "per-file-ignores"
    - from: "pyproject.toml [[tool.mypy.overrides]]"
      to: "frontmatter stub suppression"
      via: "module = [\"frontmatter\"], ignore_missing_imports = true"
      pattern: "tool.mypy.overrides"
---

<objective>
Add four surgical configuration stanzas to pyproject.toml so that ruff and mypy are correctly scoped before any auto-fix runs.

Purpose: Config must land before auto-fix so that ruff does not touch .windsurf/ files; all suppressions are centralised in pyproject.toml with no inline noqa noise.
Output: Updated pyproject.toml with extend-exclude, per-file-ignores (llm/ E501 + cli.py B006), and mypy frontmatter override. Committed as Commit 1.
</objective>

<execution_context>
@/home/ollie/.claude/get-shit-done/workflows/execute-plan.md
@/home/ollie/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/09-config-and-auto-fix/09-RESEARCH.md
</context>

<tasks>

<task type="auto">
  <name>Task 1: Add ruff and mypy config stanzas to pyproject.toml</name>
  <files>pyproject.toml</files>
  <action>
Edit `pyproject.toml` to add the following four changes:

1. **Extend the existing `[tool.ruff]` section** — add `extend-exclude` key:
   ```toml
   [tool.ruff]
   line-length = 100
   target-version = "py312"
   src = ["src", "tests"]
   extend-exclude = [".windsurf", ".planning", "test_debug.py"]
   ```
   Use `extend-exclude` (NOT `exclude`) — `exclude` replaces ruff's entire default exclusion list and would lose `.venv`, `.git` etc.

2. **Add a new `[tool.ruff.lint.per-file-ignores]` section** after `[tool.ruff.lint]`:
   ```toml
   [tool.ruff.lint.per-file-ignores]
   "src/corpus_analyzer/llm/*.py" = ["E501"]
   "src/corpus_analyzer/cli.py" = ["B006"]
   ```
   Use the full relative path from project root (NOT short forms like `"llm/*.py"`) — ruff resolves globs relative to where `pyproject.toml` lives.

3. **Add `[[tool.mypy.overrides]]` block** at the end of the file:
   ```toml
   [[tool.mypy.overrides]]
   module = ["frontmatter"]
   ignore_missing_imports = true
   ```
   Use double-bracket `[[tool.mypy.overrides]]` — this is TOML array-of-tables syntax. Single-bracket would be wrong. The module name must be `"frontmatter"` (the import name), NOT `"python-frontmatter"` (the PyPI package name).

After editing, verify the TOML is valid by running:
```bash
python3 -c "import tomllib; tomllib.load(open('pyproject.toml','rb')); print('TOML valid')"
```

Then run a dry-run ruff check to confirm suppressions take effect:
```bash
uv run ruff check src/ tests/ --output-format=json 2>/dev/null | python3 -c "
import json, sys
data = json.load(sys.stdin)
from collections import Counter
by_rule = Counter(d['code'] for d in data)
print('Remaining violations after config:')
for k,v in by_rule.most_common():
    print(f'  {k}: {v}')
print(f'Total: {sum(by_rule.values())}')
"
```

Confirm that:
- No violations appear from `.windsurf/` paths
- `B006` count is 0 (suppressed by per-file-ignores for cli.py)
- E501 count in llm/ files is 0 (suppressed by per-file-ignores)

Then commit **only `pyproject.toml`** as Commit 1:
```bash
git add pyproject.toml
git commit -m "chore(config): add ruff per-file-ignores, extend-exclude, and mypy frontmatter override

- extend-exclude: .windsurf, .planning, test_debug.py
- per-file-ignores: E501 for llm/*.py, B006 for cli.py (Typer list trap)
- [[tool.mypy.overrides]]: ignore_missing_imports for frontmatter module

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
```
  </action>
  <verify>
    <automated>python3 -c "import tomllib; data=tomllib.load(open('/home/ollie/Development/Tools/vibe_coding/corpus-analyzer/pyproject.toml','rb')); ruff=data['tool']['ruff']; assert 'extend-exclude' in ruff, 'extend-exclude missing'; pfi=data['tool']['ruff']['lint']['per-file-ignores']; assert 'src/corpus_analyzer/llm/*.py' in pfi, 'llm E501 suppression missing'; assert 'src/corpus_analyzer/cli.py' in pfi, 'cli B006 suppression missing'; overrides=data['tool']['mypy']['overrides']; assert any('frontmatter' in str(o.get('module','')) for o in overrides), 'frontmatter override missing'; print('All config checks PASSED')"</automated>
    <manual>Run `uv run ruff check src/ tests/` and confirm no violations from .windsurf/ paths appear. Confirm B006 count is 0. Confirm E501 in llm/ is 0.</manual>
  </verify>
  <done>pyproject.toml has all four config additions (extend-exclude, per-file-ignores for llm/ E501 and cli.py B006, [[tool.mypy.overrides]] for frontmatter). TOML parses cleanly. Ruff dry-run shows no .windsurf/ violations, zero B006, zero E501 in llm/ files. Committed as Commit 1.</done>
</task>

</tasks>

<verification>
```bash
# Verify config is in place
python3 -c "
import tomllib
data = tomllib.load(open('/home/ollie/Development/Tools/vibe_coding/corpus-analyzer/pyproject.toml','rb'))
ruff = data['tool']['ruff']
print('extend-exclude:', ruff.get('extend-exclude'))
pfi = ruff['lint']['per-file-ignores']
print('per-file-ignores:', pfi)
overrides = data['tool']['mypy']['overrides']
print('mypy overrides:', overrides)
"

# Confirm ruff sees no .windsurf violations
uv run ruff check src/ tests/ --output-format=json 2>/dev/null | python3 -c "
import json, sys
data = json.load(sys.stdin)
windsurf_hits = [d for d in data if '.windsurf' in d['filename']]
print('windsurf violations:', len(windsurf_hits))
b006_hits = [d for d in data if d['code'] == 'B006']
print('B006 violations:', len(b006_hits))
"
```
</verification>

<success_criteria>
- `pyproject.toml` has `extend-exclude = [".windsurf", ".planning", "test_debug.py"]` in `[tool.ruff]`
- `pyproject.toml` has `[tool.ruff.lint.per-file-ignores]` with E501 for `src/corpus_analyzer/llm/*.py` and B006 for `src/corpus_analyzer/cli.py`
- `pyproject.toml` has `[[tool.mypy.overrides]]` with `module = ["frontmatter"]` and `ignore_missing_imports = true`
- TOML parses without error
- `ruff check src/ tests/` shows zero violations from `.windsurf/` paths
- Committed as Commit 1 (config-only commit)
</success_criteria>

<output>
After completion, create `.planning/phases/09-config-and-auto-fix/09-01-SUMMARY.md`
</output>
