# Ответ точек несёт измеренный род и его применимость к отданному ряду - **Дата:** 2026-08-04 - **Источник:** openspec/changes/archive/2026-08-04-tochki-metriki-za-period/design.md ## Решение Конверт ответа маршрута точек несёт `aggregation` **объектом** `{style, applicable, last_hour}`, а не строкой с применённой свёрткой: - `style` — измеренный род метрики, тот же словарь и то же имя, что у каталога; - `applicable` — применим ли объявленный род к **отданному ряду**; - `last_hour` — ярлык самого свежего часа окна измерения. `docs/architecture.md` до этого изменения обещал `"aggregation": "sum"` — строку. Решение её **пересматривает**: строка называет применённое и молчит об основании. Отвергнуто и названо поимённо: поле `applied` с именем применённой свёртки (выводится из `style` и `bucket` тем же инвариантом; как строка неверно описывает свёртку мгновенной метрики, у которой по архитектуре «среднее с `min`/`max` рядом»); полное основание каталога (`hours`, `compared`, `agreeing`, `conflicting`, `first_hour`) в конверте точек — второй экземпляр факта, обязанный сходиться с первым. ## Почему **Род есть свойство метрики, а слой — свойство ряда, и их сочетание бывает опасным.** Конверт `{"layer": "raw", "style": "cumulative"}` законен и штатен: правило выбора слоя при равном охвате предпочитает самый мелкий. Инвариант «нижний слой HAE не суммируется никогда» система соблюдает, ничего не складывая, — но потребитель об инварианте не знает, а сумма по нижнему слою завышает втрое (находка 34 разведки). Разрыв построен проходом `review-rubric` на предложении, до кода: > Конверт `{"layer": "raw", "aggregation": {"style": "cumulative"}}` законен, > штатен — и он прямо приглашает главного потребителя (агента с ограниченным > контекстом) сложить ряд самому. Система при этом свёртки не делает, инвариант > формально цел; результат у потребителя завышен, а решение по нему уже принято. `applicable: false` — та самая оговорка, которая едет вместе с данными. **`last_hour` — единственный след замершего окна.** Род считается по 48 самым свежим **общим** часам, а не по последним 48 часам календаря: выключенная минутная автоматизация HAE останавливает пополнение общих часов, окно замирает и продолжает объявлять род. **Литература расколота, и обе стороны названы.** Род **вместе с данными**: Google Cloud Monitoring объявляет `metricKind` и `valueType` в каждом объекте `TimeSeries` ответа, а не только в дескрипторе метрики; CloudWatch `GetMetricData` кладёт `StatusCode` (`Complete` / `PartialData`) рядом с рядом — оговорка едет с данными, а не оставляется клиенту на вывод; Home Assistant `statistics_during_period` держит `start` и `end` в ответе **всегда**, независимо от запрошенных `types`. Род **отдельно от данных**: Prometheus отдаёт `{resultType, result}` без единого слова о типе, а тип живёт в `/api/v1/metadata`; Graphite render не объявляет ничего. Второе отвергнуто по измеримой причине: клиент обязан сделать второй запрос, а до тех пор не отличает «род известен» от «род не измерен», — и согласованности между двумя ответами всё равно нет, потому что род есть функция **окна**, а окно едет с часами. Принцип HealthKit `HKStatistics` («род не тот — свёртки нет») взят, механизм неприменим: у нас стиль источником не объявлен. ## Последствия - `+` Потребитель видит не только число, но и на каком основании его можно сворачивать, без второго запроса и без знания инвариантов проекта. - `+` Форма объявлена **до** того, как её скопируют свёртка по сетке, порог неполного ведра, тренировки, записи и MCP. После копирования это была бы не развилка, а археология. - `−` Поле `applicable` избыточно по построению: клиент, знающий правило «нижний слой HAE не суммируется», вывел бы его из `style` и `layer`. Взято сознательно — правило принадлежит нам, и молчаливо перекладывать его на потребителя дороже, чем поле. - `−` Чтобы разобрать, **почему** род `unknown`, придётся спросить каталог: полное основание живёт там в одном экземпляре. - `−` Род в конверте точек и род в каталоге считаются в разные моменты и у клиента, сравнивающего два ответа, могут разойтись. Это свойство измерения, а не дефект; ровно поэтому `last_hour` едет вместе с родом. ## Открыто, решает владелец **Машинно-различимый код причины отказа.** Тело отказа несёт только человекочитаемую строку, и агент не отличит «зона не указана» от «слой незнаком» иначе, чем разбором русского текста. Правило общее для всех маршрутов и меняет `errorWire`, то есть и контракт приёма, — сюда не взято.