From 893d63d929526c888791a169e7b82a2d8324b2e3 Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Mon, 3 Aug 2026 17:31:12 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BA=D0=B0=D0=BD=D0=BE=D0=BD:=20=C2=AB=D0=BF?= =?UTF-8?q?=D0=BE=D1=87=D0=B5=D0=BC=D1=83=C2=BB=20=D0=B1=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D1=88=D0=B5=20=D0=BD=D0=B5=20=D0=BE=D1=82=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20=D0=B2=20architect?= =?UTF-8?q?ure.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Три документа — CLAUDE.md, паспорт и openspec/config.yaml — велели писать причину отвергнутого решения в architecture.md. По канону дом «почему» это design.md изменения и промоут в docs/adr/, а architecture.md переезд как раз опустошает: обоснования шли ровно туда, откуда их вычищают. Раздел «Процесс» в CLAUDE.md пересказывал шаги пайплайна дословно — тот же второй дом, что уже вычищен из config.yaml. Осталось три вещи, которые действительно проектные: автономность, prior art, «поток не останавливается». config.yaml пересказывал паспорт и инвариант безопасности — стали ссылками. docs/review.md ссылался на healthlog-review-rubric и healthlog-task-pipeline, удалённые вместе с проектными копиями. Первое — указание на будущее, поэтому исправлено на проходы rubric и ops; второе оставлено историей с пометкой. README.md называл architecture.md домом «принятых решений» и не упоминал database.md и adr/ вовсе. Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 64 ++++++++++++++++++-------------------------- README.md | 6 ++++- docs/passport.md | 3 ++- docs/review.md | 6 +++-- openspec/config.yaml | 37 ++++++++++++------------- 5 files changed, 54 insertions(+), 62 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 5c2cef4..c117840 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -145,28 +145,26 @@ Module path — `git.vakhrushev.me/av/healthlog`. - **Что такое «сделана»:** пайплайн `av-dev-pipeline:task-pipeline` пройден целиком **и** критерии приёмки задачи проверены поимённо. -## Процесс +## Как здесь принято работать -Задачи — в [docs/tasks/BACKLOG.md](docs/tasks/BACKLOG.md) (один файл на запись, -индексы производны), цели — в [docs/tasks/PLAN.md](docs/tasks/PLAN.md). Ведёт их -скилл `av-dev-pm:tasks`, спринт и ритуал между спринтами — `av-dev-pm:session`. +Задачи и спринт ведёт `av-dev-pm`, работу над задачей — `av-dev-pipeline`. +Порядок шагов, состав проходов ревью и правила ведения задач здесь **не +пересказываются**: их дом — сами скиллы, а проектная настройка конвейера — +[docs/review.md](docs/review.md). Пересказ разъедется на первой же правке +скилла, и разойдётся молча. -Работа над задачей идёт скиллом `av-dev-pipeline:task-pipeline`: задача → -`opsx:explore` → `opsx:propose` → ревью спек (профиль `design`) → `opsx:apply` → -ревью кода → `opsx:archive` → закрытие задачи → коммит. Ревью — скилл -`av-dev-pipeline:review-pipeline`, проходы — агенты `av-dev-pipeline:review-*`, -проектная настройка конвейера — [docs/review.md](docs/review.md). +Проектного здесь три вещи: -**Действуем автономно.** Умолчание — делать, а не спрашивать. Вопрос, который -решать не мне, **выносится в раздел «Вопросы»** файла задачи и помечается тегом -`question`; задача с открытым вопросом в спринт не берётся, а сама работа -переформулируется на остаток и доводится до коммита. Спрашиваем немедленно -только про **необратимое** — список выше. +**Действуем автономно.** Умолчание — делать, а не спрашивать. Немедленно +спрашиваем только про **необратимое** — список выше. Остальное, что решать не +мне, уходит вопросом в файл задачи, а работа переформулируется на остаток и +доводится до коммита. -**Развилка или вопрос — сперва prior art.** Проект не уникален: прежде чем -проектировать своё, смотрим, как это решено в референсах -[паспорта](docs/passport.md) и в интернете. Готовое решение либо берётся, либо -отвергается с названной причиной — и причина идёт в `architecture.md`. +**Развилка или вопрос — сперва prior art.** Проект не уникален; правило и +референсы — [docs/passport.md](docs/passport.md), раздел «Мы не делаем +уникального». Отвергли готовое решение — причина идёт в `design.md` изменения, +а оттуда промоутом в [docs/adr/](docs/adr/README.md). В `architecture.md` +обоснования больше не пишем: он переопределён как обзор. **Поток не останавливается.** Телефон шлёт непрерывно и молча. Сломанный приём, оставленный работать, теряет данные необратимо: доставка, не попавшая в @@ -174,27 +172,17 @@ Module path — `git.vakhrushev.me/av/healthlog`. ## Конвенции -Механизируемое проверяет `task lint` (`.golangci.yml`): форма логов -(`sloglint`), `fmt.Print*` / `os.Getenv` / `time.Now` мимо единых точек -(`forbidigo`), сравнение ошибок (`errorlint`), сторонние пакеты ошибок -(`depguard`). Пересказывать эти правила не нужно — линтер скажет точнее. +Механизируемое проверяет `task lint` по `.golangci.yml`, прозой остаётся то, +что правилом не выражается — [docs/conventions/](docs/conventions/README.md). +Перечень правил и перечень записей есть в обоих файлах; здесь они не +дублируются. -Прозой остаётся то, что правилом не выражается: -[docs/conventions/README.md](docs/conventions/README.md) — уровень лога по адресату, -единственный логирующий чекпоинт на доменной границе, трансляция ошибки на -внешней границе, самодокументируемый `config.example.toml`, время в БД в UTC -RFC 3339, ULID через `ident`. - -Отдельно: **тесты на разбор формата HAE держим на реальных пакетах** в -`testdata`. Документация формата тонкая и местами расходится с тем, что -приложение реально шлёт, — источником истины служат живые данные. - -Что показал реальный поток — [docs/research/apple-health.md](docs/research/apple-health.md). -Читать **до** работы над разбором: там же лежат находки, которых нет в -документации HAE (поле `source` существует; порядок ключей в JSON нестабилен, -поэтому хеш содержимого считается по канонической форме с рекурсивной -сортировкой; мелкая группировка даёт интерполяцию, а не измерения). Файл -пополняется по мере накопления доставок. +Отдельно, потому что это решает, каким тестам верить: **тесты на разбор формата +HAE держим на реальных пакетах** в `testdata`. Документация формата тонкая и +местами расходится с тем, что приложение реально шлёт, — источником истины +служат живые данные, [docs/research/apple-health.md](docs/research/apple-health.md). +Читать **до** работы над разбором: скорее всего вопрос о формате уже закрыт +измерением. ## Язык diff --git a/README.md b/README.md index 7e0ad5a..4fdfa1b 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,11 @@ curl -i -H 'If-None-Match: W/"…"' localhost:8080/api/v1/metrics # 304 - [docs/passport.md](docs/passport.md) — цель проекта, типовые сценарии работы, референсы: чужие проекты, у которых смотрим решения, прежде чем придумывать своё -- [docs/architecture.md](docs/architecture.md) — устройство, схема данных, API, принятые решения +- [docs/architecture.md](docs/architecture.md) — устройство: принципы, + компоненты, внешние границы, эксплуатация, деплой +- [docs/database.md](docs/database.md) — схема хранилища и настройки с + числовым значением +- [docs/adr/](docs/adr/README.md) — почему решено именно так - [docs/conventions/](docs/conventions/README.md) — как пишем код - [docs/security.md](docs/security.md) — периметр и модель угроз - [docs/review.md](docs/review.md) — настройка конвейера ревью и журнал дефектов diff --git a/docs/passport.md b/docs/passport.md index e499ec6..8433e6e 100644 --- a/docs/passport.md +++ b/docs/passport.md @@ -120,7 +120,8 @@ HAE), а сырой архив получает право быть подчищ > **Развилка или вопрос — сперва prior art.** Прежде чем проектировать своё, > посмотреть, как это сделано в проектах ниже и в интернете. Готовое решение > либо берётся, либо отвергается **с названной причиной** — и тогда причина -> идёт в [architecture.md](architecture.md), а не теряется. +> идёт в `design.md` изменения, а оттуда промоутом в [adr/](adr/README.md), +> а не теряется. Формулировка «у всех так, а у нас иначе, потому что…» — это готовое обоснование решения. Формулировка «я придумал вот так» — ещё нет. diff --git a/docs/review.md b/docs/review.md index 262f1e0..5967385 100644 --- a/docs/review.md +++ b/docs/review.md @@ -191,7 +191,7 @@ «`import + replay` даёт то же состояние» ни один из них не проверял на конкретном правиле: он записан в архитектуре как свойство системы, а не как критерий для каждого узла, читающего состояние. -- **Что меняем:** в рубрику `healthlog-review-rubric` и в проход `ops` — вопрос +- **Что меняем:** в проходы `rubric` и `ops` — вопрос «читает ли узел состояние, которое сам же меняет, и остаётся ли он функцией от префикса журнала». Дешевле правила: любой запрос к `delivery` из свёртки обязан иметь границу по `received_at` разбираемой доставки. Тест сходимости @@ -227,7 +227,9 @@ ## 2026-08-02 — чекпоинт кода прошёл без трёх проходов, и ровно они нашли всё [проскочил] - **Где:** конвейер, а не код: коммит `f8200f7` («тренировки и записи с - собственным `id`»), шаг 7 скилла `healthlog-task-pipeline`, профиль `deep`. + собственным `id`»), шаг 7 пайплайна задачи (тогда — проектная копия + `healthlog-task-pipeline`, ныне `av-dev-pipeline:task-pipeline`), профиль + `deep`. - **Симптом:** изменение было закоммичено и заархивировано как прошедшее ревью. Дозапуск трёх пропущенных проходов на **уже закоммиченном** коде дал девять причин, семь из которых пошли в работу с прогнанными оракулами: скелет из diff --git a/openspec/config.yaml b/openspec/config.yaml index bd8d124..448a461 100644 --- a/openspec/config.yaml +++ b/openspec/config.yaml @@ -27,27 +27,24 @@ context: | скилл av-dev-pipeline:review-pipeline, проектная настройка — docs/review.md. Конвенции кода (соблюдать при apply): - - Механизируемое проверяет `task gate` (линтер, сборка, тесты, race, - покрытие изменённых строк, миграции, образцы конфига, секреты и данные о - здоровье в индексе). Состав шагов и правил здесь не пересказываем — он - растёт, а гейт скажет точнее и всегда актуальнее. - - Прозой остаётся то, что правилом не выражается: docs/conventions/README.md. - Читаем в источнике, а не отсюда — конвенции дописываются по ходу задач. - - Безопасность: данные о здоровье чувствительнее токенов. Ни тела запросов, - ни значения точек не попадают в логи выше DEBUG; ничего из ./data не - попадает под контроль версий — это проверяет гейт. + - Механизируемое проверяет `task gate`, прозой остаётся + docs/conventions/README.md. Ни состав шагов гейта, ни перечень конвенций + здесь не пересказываем: и то и другое растёт по ходу задач, а источник + скажет точнее и всегда актуальнее. - Что это за проект: - - ЧИТАЙ ПЕРЕД ПРЕДЛОЖЕНИЕМ: docs/passport.md — цель и её граница (чем проект - НЕ является), типовые сценарии работы, референсы. - - Вкратце: healthlog — хранилище данных Apple Health, а не аналитика: - принять, дедуплицировать, сохранить, отдать. Состояние пересобирается из - журнала доставок, поэтому свёртка обязана быть детерминированной. - - Развилка или блокер — сперва prior art. Проект не уникален: готовые решения - смотрим в референсах паспорта, отвергаем — с названной причиной, и причина - идёт в architecture.md. - - Инварианты целиком — в CLAUDE.md, архитектура — в docs/architecture.md, - периметр и модель угроз — в docs/security.md, схема — в docs/database.md. + Что это за проект — читай перед предложением, а не отсюда: + - docs/passport.md — цель, её граница (чем проект НЕ является), потребители, + типовые сценарии, референсы; + - CLAUDE.md — инварианты с severity и семантика гейта; + - docs/architecture.md — устройство; docs/database.md — схема; + docs/security.md — периметр и модель угроз; docs/adr/ — почему решено так. + Пересказа этих документов здесь нет намеренно: второй дом факта расходится с + первым молча, и заметно это становится в предложении, которое уже написано. + + Развилка или блокер — сперва prior art. Проект не уникален: готовые решения + смотрим в референсах паспорта, отвергаем — с названной причиной, и причина + идёт в design.md этого же изменения (оттуда её промоутит в docs/adr/ скилл + av-dev-pm:docs). Разведка уже проведена, догадки о формате не нужны: - docs/research/apple-health.md — находки на живом потоке, во многом расходящиеся с