docs: проект переведён на канон документов версии 4
- каталог задач: PLAN.md → ROADMAP.md с каноническими секциями, все 44 записи получили тип, заголовки приведены к форме своего типа - расхождения, найденные судьями канона: исключения инварианта «источник неприкосновенен», инвариант про один активный infohash, UTC в logging.md, поведение из architecture.md заменено ссылками на спеки - триггеры профиля ревью переписаны под умолчание standard
This commit is contained in:
@@ -22,7 +22,9 @@ Driven Development** через OpenSpec — см. раздел ниже.
|
||||
Go 1.26, один статический бинарь (`CGO_ENABLED=0`). Module path —
|
||||
`git.vakhrushev.me/av/jellybit`. SQLite через `modernc.org/sqlite` + `sqlx`,
|
||||
миграции `goose`, HTTP — `chi` + `html/template` + htmx, конфиг —
|
||||
`pelletier/go-toml/v2`, логи — `log/slog` (структурированный JSON).
|
||||
`pelletier/go-toml/v2`, разбор `.torrent` и инфохэшей — `anacrolix/torrent`,
|
||||
пред-парс имени раздачи — `middelink/go-parse-torrent-name`, логи — `log/slog`
|
||||
(структурированный JSON).
|
||||
|
||||
## Инварианты
|
||||
|
||||
@@ -32,6 +34,15 @@ Go 1.26, один статический бинарь (`CGO_ENABLED=0`). Module
|
||||
- **Источник неприкосновенен** — под `paths.downloads` допустимы только чтение
|
||||
и `link(2)`; никаких `unlink`, `rename`, записи. Нарушение уничтожает
|
||||
невосстановимые данные пользователя. **Необратимо. `critical`.**
|
||||
Исключения два, и оба — не наши операции с файловой системой, а вызов
|
||||
`torrents/delete` qBittorrent с `deleteFiles=true`: (1) `Delete` из
|
||||
`done`/`orphaned`/`target_missing` по явному подтверждению человека — гард
|
||||
последней копии там выключен сознательно
|
||||
([state-reconciliation](openspec/specs/state-reconciliation/spec.md));
|
||||
(2) уборка воркером **собственного** торрента, добавленного этим же `add`
|
||||
секундами ранее, когда задачу отменили в окне после `add`
|
||||
([download-tracking](openspec/specs/download-tracking/spec.md)). Всё
|
||||
остальное под `paths.downloads` — по-прежнему `critical`.
|
||||
- **Последняя копия не снимается** — `Undo` отклоняется целиком, если у цели не
|
||||
осталось других жёстких ссылок (`nlink <= 1`) или исходного файла уже нет.
|
||||
Частичный откат тоже стёр бы часть данных. **Необратимо. `critical`.**
|
||||
@@ -47,14 +58,24 @@ Go 1.26, один статический бинарь (`CGO_ENABLED=0`). Module
|
||||
qBittorrent, ключи LLM и метабаз, токен Telegram, API-ключ Jellyfin.
|
||||
Утёкший в лог секрет отзывается вручную. **`major`.**
|
||||
- **Авто-раскладка только при подтверждённом матче в метабазе** — самооценка
|
||||
LLM гейтом не является
|
||||
([ADR](docs/adr/ADR-2026-06-13-auto-link-requires-db-match.md)). Обратимо
|
||||
LLM **единственным** гейтом не является и матч не заменяет: порог
|
||||
`[recognition].auto_confidence_threshold` стоит поверх матча дополнительным
|
||||
условием
|
||||
([ADR](docs/adr/ADR-2026-06-13-auto-link-requires-db-match.md),
|
||||
[recognition](openspec/specs/recognition/spec.md)). Обратимо
|
||||
через `Undo`. **`major`.**
|
||||
- **Не более одной активной загрузки на infohash** — проверка отсутствия другой
|
||||
активной загрузки и вставка идут одной write-транзакцией (`_txlock=immediate`,
|
||||
guarded-методы `store`); обход даёт две задачи, претендующие на одну раздачу и
|
||||
один целевой путь. Обратимо (лишняя закрывается), но состояние расходится.
|
||||
**`major`.** Поведение — [ingest](openspec/specs/ingest/spec.md).
|
||||
- **Переходы состояний — только через `worker` под per-download блокировкой**,
|
||||
и только легальные по декларативному графу. Обход даёт гонку двух
|
||||
транспортов. **`major`.**
|
||||
- **Время — только `store.Now()` (UTC), идентификаторы — только `ident`**;
|
||||
`ident.Parse` на каждой входной границе. Механизировано линтером. **`minor`.**
|
||||
`ident.Parse` на каждой входной границе. Время механизировано линтером
|
||||
(`forbidigo` на `time.Now`); правило про `ident` линтером не проверяется —
|
||||
держится на ревью. **`minor`.**
|
||||
|
||||
## Команды
|
||||
|
||||
@@ -117,9 +138,10 @@ Go 1.26, один статический бинарь (`CGO_ENABLED=0`). Module
|
||||
(`git merge-base HEAD master`), в неё вливает батч, от неё ветвятся задачи.
|
||||
- **Необратимое** (спрашивается у человека всегда): всё, что пишет в
|
||||
`paths.downloads` или удаляет оттуда; удаление раздачи из qBittorrent вместе
|
||||
с файлами (`Delete`); снятие последней копии данных; правка уже применённой
|
||||
миграции; `git push --force`; удаление или перезапись файла в библиотеке
|
||||
Jellyfin, которого мы не создавали.
|
||||
с файлами (`Delete`) — кроме уборки собственного, только что добавленного
|
||||
торрента при отмене (см. исключения инварианта выше); снятие последней копии
|
||||
данных; правка уже применённой миграции; `git push --force`; удаление или
|
||||
перезапись файла в библиотеке Jellyfin, которого мы не создавали.
|
||||
- **Общий станок** — покрасневший `task gate` на `master` врывается в
|
||||
замороженный спринт: пока он красный, ни одна задача не считается сделанной.
|
||||
- **Ориентир по размеру спринта:** 5–8 задач. Ориентир, а не закон.
|
||||
|
||||
Reference in New Issue
Block a user