# Отвечать 304 на повторный запрос точек - **Секция:** Ядро - **Зачем:** Агент опрашивает по расписанию, а каждый повтор стоит полного чтения: на каталоге это 693 мс и +153 МиБ - **Теги:** goal:read-api, sprint:2026-08-04, kind:feature Повторный опрос точек с той же меткой стоит `304` вместо полного чтения, и метка не может ответить на другой набор данных. Машинерия готова и берётся, а не пишется заново: `store.VersionedRead` держит правило «версией, снятой после чтения, не подписывать», `internal/httpapi/conditional.go` разбирает `If-None-Match` и отдаёт `304`. Новое здесь ровно одно — **область действия метки**. У каталога ответ есть функция версии витрины; у точек он ещё и функция параметров запроса, поэтому `etag(scope, version)` требует их канонизированной формы. Ошибиться тут значит ответить `304` на другой набор данных — молча и без следов. Цена, которую это снимает, измерена на каталоге: 693 мс и +153 МиБ живой кучи на враждебном запросе. Агент опрашивает по расписанию, и без условного запроса каждый его повтор стоит полного чтения. Двигает строку «Завершения» цели: «Повторный запрос тех же точек стоит `304`, а не полного чтения». ## Затрагивает Маршрут `GET /api/v1/metrics/{name}` — заголовки `ETag` и `If-None-Match`, код ответа `304`. Область действия метки: набор параметров запроса (метрика, окно, слой) и версия витрины, из которых метка считается, и их каноническая форма. Схемы и формата на диске не трогает. ## Критерии приёмки - повторный запрос с `If-None-Match` при неизменной витрине даёт `304` — оракул: тест - запрос, отличающийся любым параметром по очереди (метрика, окно, слой), при той же версии витрины даёт `200` и другое тело — оракул: тест, перебирающий параметры по одному - параметры, различающиеся только формой записи (порядок, регистр, эквивалентная запись времени), дают одну и ту же метку — оракул: тест на канонизации ## Рамки Схема не трогается, данные только читаются. Берётся после точек за период. Связано: `docs/architecture.md` → «Условный запрос».