# Дизайн: чистый помощник `formatBytes` — человекочитаемый размер

**Дата:** 2026-06-14

## Цель

Дать переиспользуемую чистую функцию, превращающую число байт в короткую человекочитаемую строку (`1536` → `1.5 KB`). Нужна в логах и отчётах размеров файлов/дампов, где сейчас размеры печатаются сырыми байтами и плохо читаются.

## Контракт {#D1}

`formatBytes(n, { precision = 1 } = {}) → string`. Вход — неотрицательное число байт. Выход — строка вида `"<число> <единица>"`, единицы по основанию 1024: `B`, `KB`, `MB`, `GB`, `TB`. Дробная часть округляется до `precision` знаков; для единицы `B` дробная часть не печатается (целые байты). Функция детерминирована, без побочных эффектов и без обращения к I/O.

## Алгоритм {#D2}

1. Привести вход к числу; невалидный/отрицательный/`NaN` — см. крайние случаи (D3).
2. Выбрать наибольшую единицу `u`, при которой `n / 1024^i < 1024` (или последняя — `TB`).
3. Значение = `n / 1024^i`; для `i === 0` (`B`) вернуть целое; иначе округлить до `precision` и убрать хвостовые нули.
4. Склеить `"<значение> <единица>"`.

## Крайние случаи {#D3}

- `0` → `"0 B"`.
- Отрицательное число / `NaN` / не-число → `"0 B"` (деградация к безопасному, без исключения).
- Очень большие значения (> 1024 TB) остаются в `TB` (последняя единица не переполняется в новую).
- `precision = 0` → без дробной части во всех единицах.

## Конвенция {#D4}

ES-модуль `tools/format-bytes.mjs`, единственный именованный экспорт `formatBytes`. Без зависимостей. Покрытие — vitest tools-config. Имя файла и экспорта совпадают по смыслу; чистая функция тестируется в изоляции.

## Критерий готовности {#D5}

- Юнит-тесты: базовые переходы единиц (`B`/`KB`/`MB`/`GB`/`TB`), округление по `precision`, целые байты для `B`, безопасная деградация невалидного входа в `"0 B"`.
- Полная регрессия tools-only зелёная: `npx vitest run --root app --config vitest.config.tools.mjs`.

```verified-context-json
[
  {"id": "vc-pricing", "kind": "EXTRACTED", "ref": "tools/cost-pricing.mjs", "anchor": "export const PRICING = Object.freeze("}
]
```
