# План: Линтер (Ruff + ESLint) для агентской разработки

## Мотивация

Привести тулинг проекта в соответствие с GRACE-Poly протоколом:

- **Pylint** — мёртвый груз (плагин `pylint_ai_checker.checker` не существует, никто не использует)
- **Ruff** — уже де-факто стандарт (все агенты ссылаются на `ruff check`), но нет конфига
- **ESLint** — есть `.eslintignore`, но нет ни конфига, ни зависимостей, ни npm-скрипта
- **semantics-contracts** `@REJECTED`: linter НЕ должен проверять GRACE-Poly контракты — это агентский протокол

---

### 1. Создать `backend/ruff.toml`

```toml
target-version = "py313"
line-length = 300  # перенос из .pylintrc (символов в строке, не LOC)

[lint]
select = [
  "F",     # pyflakes — неиспользуемые импорты/переменные (антислэш)
  "E", "W", # pycodestyle — PEP8
  "I",     # isort — порядок импортов
  "N",     # pep8-naming — snake_case
  "UP",    # pyupgrade — современный Python 3.13
  "B",     # flake8-bugbear — баги
  "SIM",   # flake8-simplify — упрощение
  "C4",    # flake8-comprehensions
  "C90",   # mccabe — cyclomatic complexity (INV_7 из semantics-core)
  "ARG",   # flake8-unused-arguments — мёртвые аргументы
  "T20",   # flake8-print — запрет print (должен быть log())
  "RUF",   # ruff-specific
]
ignore = [
  "E501",   # line-length — своё через глобальный параметр
  "D",      # pydocstyle — контракты заменяют docstring (per .pylintrc)
  "ANN",    # аннотации — слишком педантично
]

[lint.mccabe]
max-complexity = 10  # INV_7 из semantics-core

[lint.per-file-ignores]
"tests/*" = ["T20"]  # в тестах print разрешён
```

### 2. Удалить `.pylintrc` из корня проекта

- Плагин `pylint_ai_checker.checker` не существует
- Ruff покрывает всё (и быстрее, и с автофиксом)
- Ни один агент/скилл не ссылается на pylint

### 3. Добавить ruff в `backend/requirements.txt`

```
ruff>=0.11.0
```

### 4. Создать `frontend/eslint.config.js` (flat config)

```js
import svelte from "eslint-plugin-svelte";
import js from "@eslint/js";
import globals from "globals";

export default [
  js.configs.recommended,
  ...svelte.configs["flat/recommended"],
  {
    languageOptions: {
      globals: { ...globals.browser, ...globals.node },
    },
    rules: {
      "no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
      "no-console": ["warn", { allow: ["warn", "error"] }],
    },
  },
  {
    ignores: [
      "node_modules/", "dist/", "build/",
      ".svelte-kit/", ".vite/", "coverage/",
    ],
  },
];
```

### 5. Обновить `frontend/package.json`

**devDependencies** (добавить):
```json
"eslint": "^9.0.0",
"@eslint/js": "^9.0.0",
"eslint-plugin-svelte": "^3.0.0",
"globals": "^16.0.0"
```

**scripts** (добавить):
```json
"lint": "eslint .",
"lint:fix": "eslint . --fix"
```

`.eslintignore` уже существует — его содержимое корректно.

### 6. Обновить агентские инструкции

| Файл | Изменение |
|---|---|
| `.opencode/agents/python-coder.md` | `ruff check src/ tests/` → `ruff check .` |
| `.opencode/agents/qa-tester.md` | `ruff check src/ tests/` → `ruff check .` |
| `.opencode/agents/fullstack-coder.md` | `ruff check src/ tests/` → `ruff check .` |
| `.opencode/agents/speckit.md` | Добавить `npm run lint` в verification |
| `.opencode/skills/semantics-python/SKILL.md` | `ruff check src/ tests/` → `ruff check .` |
| `.opencode/skills/semantics-contracts/SKILL.md` | `ruff check .` |
| `.opencode/command/speckit.*.md` | `ruff check backend/src/ backend/tests/` → `ruff check .` |

### 7. Верификация

```bash
# Python
cd backend && source .venv/bin/activate
pip install -r requirements.txt    # установка ruff
python -m ruff check .

# Frontend
cd frontend && npm install          # установка eslint + плагинов
npm run lint
```

---

## Что НЕ проверяет linter (сознательно)

- GRACE-Poly анкоры (`@BRIEF`, `@RELATION`, `@PRE`/`@POST`, `#region`) — rejected контрактами
- Наличие/отсутствие контрактных тегов C1-C5 — агентский протокол
- Длину модуля (< 400 LOC) и контракта (< 150 LOC) — сложно автоматизировать в linter, мониторится через code review
