Разбор совета — 2026-08-13¶
Пятеро независимых рецензентов читали репозиторий вслепую, затем прошли перекрёстный допрос с обязательной контрфактической проверкой. Здесь — что нашли, что с этим делаем и на чём остановились.
Это не протокол ради протокола: разбор изменил формулировку цели проекта (ADR-0019) и вскрыл четыре подтверждённых дефекта контрактов.
Главный вывод¶
Проект не надо останавливать. Его посылка была сформулирована неверно — не ложна, а нереализуема как записано, — и это чинится дёшево.
Трое рецензентов независимо потребовали «сначала проверить гипотезу, потом строить». Контрфактический проход сломал их же вывод: проверка требует таймстампов подходов, то есть самого логгера. «Остановиться и проверить» превращается в «построй 60% системы, потом решай» — то есть не в стоп, а в переупорядочивание.
Что не так с исходной формулировкой¶
Цель звучала как «какой был пульс во время конкретного подхода». Два независимых физических возражения:
- Пик не там. Пульс после тяжёлого подхода достигает максимума в первые 5–20
секунд отдыха. Запрос «максимум внутри
[T1, T2]» промахивается мимо пика по построению. - Выборка смещена, а не разрежена. Fitbit Air пишет точку раз в ~5 секунд и отбрасывает точки при низком качестве оптического сигнала, а качество падает ровно при хвате штанги. На подход в 40 секунд приходится 0–8 точек, и уцелевшие смещены к спокойным моментам.
Отдельно: даже при идеальном датчике пульс за подход может полностью предсказываться упражнением, весом, повторами и предыдущим отдыхом. Тогда число точное — и бесполезное. Поэтому критерий проверки гипотезы — остаточная дисперсия, а не совпадение с эталонным датчиком: нагрудный ремень проверяет датчик, а не полезность величины.
Подтверждённые дефекты (проверены по коду, не со слов)¶
| Дефект | Где | Проверка |
|---|---|---|
MAX_BACKDATE рубит бэкфилл на пути синк-воркера |
core-service/internal/server/validate.go:39 |
правило обосновано для часов телефона (ADR-0013), применено на границе воркера |
Ack обещает частичный приём, обработчик — «всё или ничего», без идентичности записи |
common.proto:27 vs server.go:58 |
выборочный ретрай невозможен в принципе |
rir = 0 («до отказа») неотличим от «не записано» |
workout.proto:36-38 |
proto3 без optional |
UNIQUE (source, external_id) не работает при NULL |
migrations/0001_init.sql:12,17 |
Postgres считает NULL различными |
Плюс организационный: Спринт 1 недостижим как написан — S1-06 требует кнопку
web_app, TLS для неё даёт S4-01 через три спринта; фолбэк описан в
SERVICES.md §2, но ни в одной задаче не зафиксирован.
Что осталось неразрешённым¶
- ~~Топология.~~ Закрыто владельцем 2026-08-13. Микросервисы — осознанный
выбор архитектуры, а не побочный эффект; все они живут в одной VM
pet. Претензия совета была основана на прочтении проекта как одиночного инструмента. Отдельно снята и главная её часть: форк wger больше не несёт вечного ребейза, потому что upstream не отслеживается (ADR-0020), а сам wger используется как полноценный интерфейс из Mini App, а не только как хранилище. - Какое решение меняет этот датасет в понедельник — нигде не записано.
- Реальное разрешение Google Health v4 под нагрузкой — никто не измерял, включая совет.
- Смещение часов телефона относительно часов — нигде не измеряется, а 5 секунд съедают весь бюджет сигнала.
Статус работ¶
| # | Что | Статус |
|---|---|---|
| 1 | Переписать посылку: эпизод усилия вместо подхода | ✅ сделано — PROJECT.md, DATA_MODEL.md, ADR-0019, задача S3-04 (issue #22) |
| 2 | Провенанс в health.proto и схеме до первого ингеста |
📋 issue #29 |
| 3 | Починить 4 дефекта контрактов до персистентности | 📋 issue #30 |
| 4 | Развязать Спринт 1 от TLS | 📋 issue #31 |
| 5 | Отчёт о покрытии и остаточной дисперсии | 📋 issue #32 |
| 6 | user_id в схему до персистентности (ADR-0021) |
📋 issue #33 |
Позже (2026-08-13): бот стал единственной точкой входа (ADR-0023), из-за чего
публичный HTTPS оказался предусловием, а не финальным штрихом (ADR-0025) — issue #31
закрывается этим решением. Порядок этапов пересобран в ROADMAP.md, новые задачи —
34 (туннель), #35 (регистрация), #36 (OAuth через бота), #37 (мультипользовательский¶
синк). Актуальное состояние целиком — COUNCIL-BRIEF.md.
Следующей сессии¶
Пункт 1 закрыт. Дальше по порядку — issue #29, он самый срочный: провенанс
точек единственный из всего списка невозможно добавить задним числом. Как
только пойдёт первый ингест пульса без confidence/recording_method/интервалов,
собранные данные нельзя будет оценить на достоверность.
Затем #33 вместе с #30 — обе правят натуральные ключи в одной миграции, делать их порознь значит мигрировать схему дважды. Затем #31 (до старта Спринта 1) и #32 (после первых реальных сессий).
Вопрос про топологию закрыт владельцем (см. выше): микросервисы остаются, wger — хард-форк. Из открытого осталось только то, что требует данных: разрешение датчика на реальной тренировке и смещение часов телефона относительно часов.
Что уточнилось после разбора (ADR-0020…0022): хард-форк wger снимает ребейз и разрешает удалить nutrition; мультипользовательность закладывается в схему сразу, до реализации персистентности; брокер сообщений не заводится.