# Firmware Stability

> Прошивка → продукт: зависания, фризы, лаги, потери данных, утечки, гонки, деградация за сутки; наблюдаемость, soak/endurance, фаззинг, приёмка. «Плату наизнанку», «не воспроизводится», «готова ли к релизу». Чтение кода на дефекты → `code-audit-core`.

- Skill: `vibeengineering-llc/firmware-stability` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add vibeengineering-llc/firmware-stability`
- Raw SKILL.md: https://api.skillmd.com/api/skills/vibeengineering-llc/firmware-stability/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: VibeEngineering-LLC (https://skillmd.com/u/vibeengineering-llc)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/vibeengineering-llc/firmware-stability

---


# firmware-stability — от «код работает» до «продукт готов»

> Подскилл `code-audit-core`. Аудит отвечает на вопрос «что не так в тексте программы»;
> этот скилл — на вопрос «что не так в работающей системе и чего ей не хватает до выпуска».
> Написан для любой встроенной платформы; платформенное вынесено в `references/`.

## Главный закон: сначала наблюдаемость, потом нагрузка

**Прогон, который не оставляет следов, — потраченное время, а не эксперимент.** Типовая
история: устройство встало на три часа, само ожило, в логах ничего. Событие произошло —
разбирать нечего, и всё повторится. Поэтому порядок жёсткий: **сначала сделать отказ
наблюдаемым, и только потом нагружать.** До запуска ответить письменно на три вопроса:

1. Если задача зависнет — что останется в доказательство? (сторожевой таймер: он
   перезагружает или только пишет предупреждение? — см. `references/esp-idf-diagnostics.md`)
2. Если система перезагрузится — сохранится ли посмертный дамп, и есть ли куда его класть?
3. Если деградация будет плавной — какие счётчики её покажут, и пишутся ли они уже сейчас?

Нет ответа хотя бы на один — прогон откладывается, чинится наблюдаемость. Это не
бюрократия: без неё редкий отказ придётся ловить заново, а он редкий.

## Разметка достоверности — обязательна во всех документах скилла

| Метка | Значение |
|---|---|
| **[Ф]** | факт, проверен в исходнике или выводом команды — с `файл:строка` либо командой |
| **[В]** | внешний факт с источником и уровнем ✅/📗 по методике `sci-search` |
| **[Г]** | гипотеза, выведенная из [Ф]+[В], но не подтверждённая замером |
| **[П]** | предлагаемая проверка, ещё не выполненная |

Смешивать запрещено. «Наверное, из-за флеша» — это [Г], и обязано быть помечено как [Г],
пока нет замера. Непомеченная гипотеза в отчёте читается как факт и отравляет решения.

## Лестница фаз

Порядок обусловлен ценой ошибки и ценой самого шага: дешёвое и воспроизводимое — раньше.

| Фаза | Что | Почему здесь |
|---|---|---|
| **0. Инвентаризация** | что за система: задачи, приоритеты, ядра, память, хранилище, интерфейсы, чего в ней НЕТ | без карты дальше гадание; «чего нет» отсекает целые ветки поиска |
| **1. Статика** | аудит кода по линзам `code-audit-core`, упор на параллелизм и ресурсы | найденный за столом дефект дешевле пойманного сутками прогона |
| **2. Хост-тесты** | модели узлов на обычном ПК, фаззинг парсеров | воспроизводимость за секунды вместо часов на железе |
| **3. Наблюдаемость** | сторожевые таймеры, посмертные дампы, счётчики, отдельная диагностическая сборка | главный закон выше |
| **4. Базовые метрики** | стеки, куча, загрузка ядер, таймеры — в покое и под типовой нагрузкой | нужна точка отсчёта, иначе «стало хуже» не с чем сравнить |
| **5. Нагрузка и время** | длительный прогон, все подсистемы одновременно | отказы этого класса появляются только на масштабе времени |
| **6. Хаос** | отключения, разрывы, снятие питания, мусор на входе | проверяется восстановление, а не работа |
| **7. Целостность** | сквозная сверка данных независимыми путями | последний рубеж: система жива, но данные врут |
| **8. Приёмка** | критерии готовности, `references/release-checklist.md` | решение о выпуске — по числам, не по ощущению |

Пропускать фазы можно, но осознанно и с записью причины. Чаще всего пропуск фазы 3
оборачивается возвратом к ней после первого же необъяснённого прогона.

## Классы отказов и где их искать

| Класс | Как выглядит снаружи | Где искать в первую очередь |
|---|---|---|
| Зависание задачи | «замерло», часть функций жива | сторожевой таймер, приоритеты, блокирующие вызовы под локом |
| Фриз всей системы | замирает всё, включая связь | долгие операции с запретом прерываний или отключением кэша |
| Плавная деградация | «через сутки тормозит» | фрагментация кучи, рост структур, износ и заполнение хранилища |
| Утечка ресурса | падает через N часов | дескрипторы, буферы, сокеты, задачи, не освобождённые на путях ошибок |
| Гонка | «иногда», не воспроизводится | общее состояние между обработчиком и фоновой задачей |
| Потеря данных | пробелы в записи | буфер перезаписан раньше, чем потребитель забрал; проверить, кто кого догоняет |
| Тихий отказ | функция молча не работает | проглоченные коды возврата, лог об успехе до проверки результата |
| Отказ под нагрузкой | ошибки только при совмещении | конкуренция за единственный ресурс, таймауты меньше физического времени операции |

## Приём: бюджет времени против таймаута

Класс дефектов, который статический аудит не ловит, а замер ловит сразу: **в коде стоит
таймаут, физически меньший, чем время операции, которую он ждёт.**

Метод, три шага:

1. **[Ф]** Выписать из кода все таймауты и окна ожидания — с `файл:строка`.
2. **[В]** Найти в документации и паспортах компонентов физическое время операций, которых
   эти таймауты ждут: стирание и запись памяти, обмен по шине, установление соединения.
3. Сопоставить **арифметикой, а не на глаз**: объём разделить на гранулярность, умножить на
   время операции, взять типовое и предельное значения. Расхождение на порядок — находка.

Считать скриптом и печатать промежуточные величины. Ошибка в устном счёте здесь стоит
неверного вывода: проверено на себе — условие в однострочнике дало одинаковый множитель
для двух разных гранулярностей, числа разошлись втрое и были пойманы только пересчётом.

Типовые источники «физики» — `references/flash-storage.md`.

## Приём: что система делает МОЛЧА

Отдельно проверяется не поведение, а его отсутствие:

- Возвращаемые значения, которые никто не смотрит: удаление, запись, освобождение.
- Лог об успехе, стоящий **до** проверки результата или без неё вовсе.
- Флаг «сделано», сбрасываемый раньше, чем действие подтверждено, — повтора не будет
  никогда, временный сбой превращается в постоянное состояние.
- Ветки ошибок без освобождения захваченного ресурса — каждая утечка одноразова, но
  повторяется при каждой ошибке.
- Счётчики потерь, которые считаются, но никуда не выводятся.

Это самый урожайный проход по чужой прошивке и самый неприятный по последствиям:
такие дефекты не падают, а тихо портят данные.

## Кто исполняет проверки и откуда берётся стерильность

Работа идёт на самой нижней ступени, которая её тянет: обход исходников, счёт и арифметика
бюджета — **скрипт**; разбор логов прогона, классификация и суммаризация — **локальная
модель** (суточный лог в контекст не заходит вовсе); суждение «дефект или намеренно» —
**субагент**; вердикт и решение о выпуске — **не делегируется**.

**Стерильность — свойство контекста, а не модели.** Проверяющий проход не должен видеть ни
работы, ни выводов проверяемого: названный ответ подтверждают, а не проверяют. В бриф идут
задача, метод и критерий приёмки — и никогда ожидаемые числа. Числа проверяются пересчётом
**от первичных величин**, а не сверкой с уже напечатанным: сверка ловит опечатку, но
подтверждает ошибку в самом расчёте. Состояние — чтением результата командой, а не памятью о
том, что команда вызывалась.

**Необратимое и критичное — два прохода**, не видящих друг друга. При расхождении побеждает
предъявивший `файл:строка`, вывод команды или число замера, а не более уверенный.

**Дробить проверку на короткие шаги.** Единственный длинный фоновый проход не переживает
перезапуск инструмента и теряет результат целиком; скриптовые проверки живучее прочих и идут
первыми. Тело правила, таблицы ступеней и разбор — `references/execution-and-sterility.md`.

## Границы и дисциплина

**Необратимое — только оператор.** Снятие питания на живой записи, стирание разделов,
перепрошивка без пути отката, любые деструктивные команды прибору — предлагаются, но не
выполняются. Отдельно: если пути отката нет физически (нет резервной копии прошивки,
корпус неразборный) — это стоп, а не «аккуратно попробуем».

**Диагностическая сборка ≠ релизная.** Всё, что включено ради наблюдаемости, помечается и
в выпуск не уезжает. Обратное тоже верно: измерять надо ту сборку, которую выпускают, иначе
меряется не тот объект.

**Чужая зона (§ 12).** Прошивку чужого контура не правим: находки, доказательства
`файл:строка`, промпт владельцу. Рецензия чужого аудита — профильная работа
(actor ≠ verifier), делается по исходному коду, а не по пересказу.

**Замер «до» обязателен.** Сначала телеметрия как есть, потом изменения. Иначе «починили»
неотличимо от «не воспроизвелось» — а это разные вещи с разной ценой.

## Справочники

| Файл | Содержимое |
|---|---|
| `references/esp-idf-diagnostics.md` | штатные средства ESP-IDF и FreeRTOS: сторожевые таймеры, дампы, трассировка, метрики кучи и стеков — с источниками |
| `references/flash-storage.md` | тайминги NOR-флеш, поведение файловых систем при обрыве питания и при заполнении, следствия для таймаутов |
| `references/test-methods.md` | методология: длительные испытания, фаззинг, внесение отказов, испытания с оборудованием в контуре — с источниками |
| `references/release-checklist.md` | критерии готовности продукта, чек-лист приёмки, форма отчёта |
| `references/execution-and-sterility.md` | кто исполняет проверки, лестница ступеней, стерильность проходов, живучесть |
| `references/testplan-atomspectra-waterfall.md` | ПРИМЕР полного прогона лестницы 0-8 на реальном проекте (прошивка ESP32 + ПК-приёмник, 2026-08-20) — шаблон структуры плана, переносимые уроки процесса |
| `scripts/aswf/verify_aswf.py` | независимая проверка целостности `.aswf`-файлов (CRC32 построчно) — извлечён из прогона выше, переиспользуемый инструмент |
| `scripts/doc-inventory/docs_inventory.py` | Ollama-инвентаризация md-документации (функции/интерфейсы/форматы/ограничения из README и т.п.) — не проектно-специфичен, годен для любой прошивки с доками |

## Тест-план: диагностика незнакомой прошивки

1. Инвентаризация (фаза 0) — карта задач, память, хранилище; отдельно записать, **чего в
   системе нет**: это сокращает работу сильнее, чем любая находка.
2. Прочитать её собственные разборы прошлых отказов, если есть, — чтобы не переоткрывать
   уже починенное, а проверять полноту фиксов.
3. Статика по линзам `code-audit-core`, приоритет — «размер × риск».
4. Приём «бюджет против таймаута» и приём «что делает молча» — оба дают находки до железа.
5. Наблюдаемость (фаза 3) — до первого длительного прогона, без исключений.
6. Базовые метрики, затем нагрузка, хаос, целостность.
7. Приёмка по `references/release-checklist.md`; невыполненные пункты — в отчёт как есть,
   без округления в свою пользу.

## Анти-паттерны

| Избегать | Почему |
|---|---|
| Суточный прогон без наблюдаемости | отказ произойдёт и не оставит следов; время потрачено |
| «Наверное, из-за X» без метки [Г] | гипотеза читается как факт и определяет решения |
| Устный счёт бюджета времени | множители путаются; считать скриптом с промежуточными числами |
| Диагностическая сборка в релиз | меняет тайминги; выпускается не то, что измеряли |
| Мерить одну подсистему в изоляции | отказы этого класса живут на стыках, а не внутри узлов |
| Чинить найденное до конца измерений | пропадает база сравнения; сначала зафиксировать «до» |
| «Не воспроизводится» как вывод | это не вывод, а состояние: значит, не хватает наблюдаемости |
| Считать зелёный прогон доказательством | отсутствие отказа за сутки не равно его отсутствию; писать длительность и условия |

## Связанные скиллы

- `code-audit-core` — мастер-скилл: линзы, шкала P0–P3, форма отчёта.
- `sci-search` — внешние факты и уровни ✅/📗 для меток [В].
- `~/.claude/references/systematic-debugging.md` (#DBG-1) — один воспроизводимый баг, а не поиск
  неизвестных: сначала причина, потом правка; три неудачных фикса — вопрос к архитектуре.
- `product-dev-cycle` — тест до кода, мутационная приёмка, цикл ветки, приём критики.
- `six-corner-audit` — гейт перед мержем и публикацией.
- `incident-log` — фиксация случившегося отказа и уроков из него.
- `md-doc` — вёрстка отчёта и плана для оператора.

