Files
healthlog/openspec/changes/archive/2026-08-02-trenirovki-i-zapisi/tasks.md
T
av d79189be18 docs: документация переведена на канон av-dev-pm
- беклог и план переехали в docs/tasks (38 задач, 11 целей), слаги
  переименованы с транслита на английские, 85 ссылок поправлены
- conventions.md разобран в docs/conventions/, local-research.md — в
  docs/research/, review-journal.md — в docs/review.md с разделом настройки
  конвейера; заведены security.md, adr/ и .pm.json
- шаг docs.py check добавлен в task gate; поведение в architecture.md помечено
  девятью маркерами долга, database.md получил настройки с числовым значением
2026-08-03 17:14:53 +03:00

11 KiB
Raw Blame History

1. Фикстуры на реальных пакетах

  • 1.1 Расширить tmp/research/fixtures.py: вычистка UUID (id), меток RFC 3339, route[].timestamp и словарных значений stateOfMind (kind, valenceClassification, labels, associations) при сохранении формы литерала, структуры и порядка ключей
  • 1.2 Собрать internal/hae/testdata/workout_route.json — уличная тренировка с маршрутом (проверяет дословность маршрута и внутренних рядов)
  • 1.3 Собрать internal/hae/testdata/workout_indoor.json — тренировка без маршрута, с полями, которых нет у уличной (temperature, humidity, intensity)
  • 1.4 Собрать internal/hae/testdata/state_of_mind.json — состояние разума (RFC 3339, отсутствие source)
  • 1.5 Дописать в handmade_edge.json случаи, которых поток не даёт: сущность без id, с пустым и со слишком длинным id, с неразбираемой меткой, с неразбираемым end, с нечисловой длительностью, два элемента с одним id в одном теле
  • 1.6 Обновить internal/hae/testdata/README.md: новые файлы и что именно вычищено

2. Разбор (internal/hae)

  • 2.1 Множество покрытых секций: metrics, workouts, stateOfMind — одно объявление на разбор и на перечисление непокрытых
  • 2.2 Типы Workout и Record в Result; счётчики SkippedNoID, SkippedNoTime для сущностей
  • 2.3 parseEntityTime: формат HAE, затем RFC 3339; офсет из разобранной зоны. Парсер точек остаётся строгим — причина записана в спеке
  • 2.4 Разбор workouts: заголовок (id, name, start, end, duration), содержимое — исходные байты элемента; end нечитаем → равен началу; длительность отсутствует → не заполнена (не ноль)
  • 2.5 Разбор stateOfMind в записи рода stateOfMind (имя секции дословно)
  • 2.6 Parse отдаёт сущности и при отсутствии секции metrics; при ошибке (обрыв тела, невыводимый слой) не отдаёт ни точек, ни сущностей
  • 2.7 Повтор ключа покрытой секции даёт объединение; повтор члена data накапливает результаты, а не присваивает последний (существующий дефект decodeEnvelope)
  • 2.8 Предел длины id: сущность сверх него пропускается тем же счётчиком
  • 2.9 Тесты на фикстурах: маршрут дословно, пульс тренировки не стал метрикой, оба формата времени, пропуски со счётчиками
  • 2.10 Тест: доставка из одних тренировок и из одного stateOfMind непокрытых ключей не даёт; из одного ecg — даёт

3. Схема (internal/store/migrations)

  • 3.1 Миграция 00007_workout_record.sql: таблицы workout и record (провенанс delivery_id + delivery_received_at, content_hash, nullable duration_sec), индексы по времени, перевод partial-доставок с ключами workouts и stateOfMind в pending
  • 3.2 Проверить, что перевод в pending отбирает строки точно (по элементу JSON-массива, а не по подстроке тела)
  • 3.3 Обновить docs/database.md: обе таблицы, смысл колонок, ключ род + id, провенанс, NULL у длительности, офсет 0 у stateOfMind

4. Хранение (internal/store, internal/canon)

  • 4.1 canon: сравнение множеств содержательных ключей без условия о совпадении значений (поверх существующего relateKeys) плюс сравнение длин верхнеуровневых массивов
  • 4.2 Incoming{Points, Workouts, Records} и Merge вместо MergePoints: одна транзакция на доставку
  • 4.3 Правило замены версии: хеш-детектор без чтения блоба, условие «не теряет содержания», тай-брейк по позиции журнала (received_at, id), внутридоставочный тай-брейк по канонической форме, счётчик и координаты для WARN
  • 4.4 Чтение и запись тренировки и записи; содержимое — сжатый блоб; хеш приехавшей считается один раз на доставку, до входа в транзакцию
  • 4.5 Fingerprint покрывает тренировки и записи, читает одной read-only транзакцией, строки разделов различаются константным признаком
  • 4.6 Тесты: замещение маршрутом; досчёт при том же наборе полей; обеднённая версия с изменившимися значениями не затирает; усечённый маршрут не затирает; несравнимые наборы; повтор не пишет; две версии в одном теле; перестановка трёх версий в двух порядках подачи (конвенция docs/conventions.md)
  • 4.7 Тест: отпечаток расходится при расхождении одной тренировки

5. Свёртка и пересборка (internal/fold, internal/replay, cmd)

  • 5.1 Stats несёт счётчики сущностей; свёртка зовёт Merge один раз; счётчики доезжают до лога без ручного копирования (или это покрыто тестом)
  • 5.2 Единственный логирующий чекпоинт: атрибуты сущностей, ветка WARN для удержанной обеднённой версии — координатами, без содержимого
  • 5.3 Отчёт reindex: «до и после» по тренировкам и записям, «покрыта новая секция» в перечне ожидаемых классов расхождения
  • 5.4 Тест: содержимое сущности в лог не попадает

6. Сходимость и проверка на живом архиве

  • 6.1 task gate — зелёный
  • 6.2 task verify:archive — прогон всего ./data/raw, повтор даёт то же состояние; он же оракул того, что живой приём и пересборка применяют к сущностям один порядок
  • 6.3 Проверка на копии рабочей базы в отдельном каталоге данных: миграция накатывается, partial-доставки пересворачиваются, тренировки и записи появляются

7. Документация и беклог

  • 7.1 docs/architecture.md — раздел «Тренировки и прочие секции»: правило замены версии с обоснованием, отвергнутые варианты, предел import; плюс блок схемы БД (record(kind, id), сжатый блоб, content_hash, провенанс)
  • 7.2 docs/conventions.md — строка про ключ record устарела, поправить
  • 7.3 docs/local-research.md — находка о поведении тренировки при переприсылке (числа замера) и пересчёт находки 50 на 118 доставок
  • 7.4 Беклог: задача про идентичность тренировок при импорте родного экспорта (в export.xml id нет — dogsheep считает hash_id); raw-archive-retention — предусловие про stateOfMind снова открыто; отметить в read-api-points, что отдача тренировок и записей входит в неё; уточнить unseen-sections-check — модель заложена, остались пять секций
  • 7.5 Удалить docs/tasks/items/trenirovki-i-zapisi.md и строку индекса

8. Приёмочные критерии (рубрика ревью)

  • 8.1 Тренировка с маршрутом переживает круг «разбор → хранение → чтение» побайтово
  • 8.2 Повторная свёртка того же журнала не меняет отпечатка витрины
  • 8.3 Ни один путь не пишет содержимое сущности в лог выше DEBUG
  • 8.4 Доставка из одних тренировок получает parsed, а не partial
  • 8.5 Доставка с непокрытой секцией по-прежнему partial, и её тело ретеншену трогать нельзя
  • 8.6 Исход правила замены не зависит от порядка свёртки в пунктах 2–4 правила; зависимость в пункте 5 наблюдаема счётчиком
  • 8.7 У каждого класса пропуска при разборе сущности — свой счётчик, и пропуск одного элемента не уносит соседей