Учебный гайд: Прикладная часть 1. Восстановление спецификаций из legacy

Урок 3 из 5 в модуле «Прикладная часть 1. Восстановление спецификаций из legacy»
Вы просматриваете урок без входа. Войдите, чтобы сохранять прогресс и проходить тесты.

Тема: Прикладная часть 1. Восстановление спецификаций из legacy

Уровень сложности: Средний

Расчётное время изучения: 6-8 часов (теория + практика)

Предварительные требования: Знакомство с первым томом курса, часть 13 (восстановление конституции существующего проекта)

Базовое понимание Kubernetes, Grafana, PagerDuty

Опыт работы с markdown и JSON

Понимание структуры Git-репозитория

Знакомство с форматом Given/When/Then для пользовательских историй

Цели обучения: Различать требования (SDD-контракт) и фоновый контекст (memory bank), применяя жёсткое разделение при инвентаризации артефактов

Создавать genealogy.md с минимум двумя evidence_ref, уровнем уверенности и открытым вопросом для одного production-требования

Преобразовывать восстановленные утверждения в формат Given/When/Then и определять соответствующие поля JSON Schema

Использовать Qwen Code в режиме извлечения (не генерации) для получения claims с обязательными источниками и контрпримерами

Оценивать готовность требования к утверждению через проверку защищённости порогов и SLA ссылками на источники

Обзор: Эта глава посвящена восстановлению инженерно пригодных спецификаций из хаоса legacy-артефактов: неструктурированных логов, Slack-тредов, скриншотов дашбордов и пост-мортемов без формального SDD. После оттока команды SRE в проекте автоматического управления инцидентами остаются фрагменты, из которых нужно извлечь проверяемые требования, а не набор правдоподобных догадок. Учебный фокус узкий: один claim, два источника, один открытый вопрос. Полный production-трек (нормализаторы, исторический replay, файловый арбитраж) отложен до части 8. Главный результат — заполненный genealogy.md, отделяющий утверждённое требование от гипотезы и фонового контекста.

Ключевые концепции: Genealogy.md: Реестр происхождения требования, связывающий утверждение с источниками (logs, Slack, метрики, пост-мортемы), уровнем уверенности (uncertainty) и открытыми вопросами. В отличие от git log, который показывает кто и когда изменил файл, genealogy.md показывает откуда взялось само требование и насколько в нём уверены. Обязательные поля: claim, evidence_ref (минимум два), status (approved/needs_clarity/rejected), uncertainty, open_questions.

Memory bank: Отдельный слой инфраструктурного контекста: всё, что помогает интерпретировать факты, но само контрактом не является. Топология кластера, список команд, исторические договорённости, ограничения API, привычные каналы связи, операционная лексика. Смешение memory bank с требованиями опасно: в SDD появляются ложные правила вроде «canary всегда неэскалируемый», которые на самом деле — только контекст тестового namespace.

Evidence ref: Пометка-доказательство — ссылка на конкретное место в исходном артефакте. Формат: source:path#location. Примеры: grafana:NR-2026-05-17-01, postmortem:node-not-ready-2026-05, slack/thread_11#msg_7. Без evidence_ref утверждение остаётся мнением автора, а не проверяемым требованием.

Claim (утверждение-кандидат): Восстановленное правило, ещё не утверждённое в контракт. Хороший claim содержит: конкретный порог (>=3 NodeNotReady), окно (за 10 минут), условие (для одного node), корреляцию (с ростом 5xx), evidence_ref, контрпример (counterexample), недостающий контекст (missing_context), уровень уверенности (confidence).

Given/when/then: Формат поведенческого описания требования. Given — исходное состояние системы. When — событие-триггер. Then — ожидаемый результат с конкретными числами, статусами и SLA. Пример: Given кластер в активной смене и >=3 NodeNotReady за 10м; When событие коррелировано с развёртыванием; Then создаётся P1, первичная реакция за 8 минут, эскалация в NOC через 15 минут, закрытие после 2 последовательных OK в течение 10 минут.

Json schema контракт: Машинно-читаемое представление требования с обязательными полями, допустимыми значениями (enum), числовыми границами (minimum/maximum). Двойная запись (Given/When/Then + JSON Schema) устраняет разрыв между «понятно человеку» и «проверяемо машиной». Проверяемые поля: rule_id, severity (enum P0-P3), sla_minutes, conditions (event_code, count, window_minutes, namespace_rule).

Нормализация временной шкалы: Приведение источников к общему времени (UTC), удаление дублей, выделение кодов событий, связывание записей единым идентификатором инцидента. Каркас: ts → source → event_code → actor → affected_scope → evidence_ref. Без нормализации восстановление превращается в спор о воспоминаниях, а не в реконструкцию поведения системы.

Файловый арбитраж (полный трек): Процесс проверки спорных требований тремя ролями: Верификатор (непротиворечивость чисел и статусов), Имплементор (реализуемость в текущем пайплайне), Safety (границы безопасного действия, право veto при critical_risk). Координатор ведёт журнал, не голосуя. Детально в части 8. Для учебного минимума — справочно.

Qwen code как извлекатель: Модель работает не как автор бизнес-логики, а как посредник для извлечения claims из нормализованных данных. Хороший промпт запрашивает: повторяющиеся правила, подтверждающие источники, контрпримеры, уровень уверенности. Запрещены утверждения без ссылки на доказательство. Режим: безголовый Plan Mode (--approval-mode plan).

Uncertainty (уровень уверенности): low — утверждение подтверждено независимыми источниками, прошло реплей или арбитраж. medium — есть противоречия, недостающий контекст, один источник. high — предположение на основе косвенных данных. Спорные факты не маскируются под approved: ставится needs_clarity с планом проверки.

Практические упражнения: Название: Создание genealogy.md для node_not_ready

Проблема: Используя учебную выписку из материалов курса, создайте файл genealogy.md с одной записью для инцидента node_not_ready. Дано: grafana-лог с тремя событиями NodeNotReady за 10 минут, запись PagerDuty об эскалации P1, пост-мортем с отказом от auto-resolve до двух стабильных окон, и открытый вопрос про canary namespace. Задача: оформить claim, добавить два evidence_ref, указать uncertainty и open_questions, отделить memory bank.

Решение: 1. Скопируйте шаблон book2/examples/templates/genealogy.md в рабочий каталог. 2. Запишите claim: 'При >=3 NodeNotReady за 10m для одного node создаётся P1, закрытие требует 2 последовательных OK в течение 10m'. 3. Добавьте evidence_ref: ['grafana:NR-2026-05-17-01', 'postmortem:node-not-ready-2026-05']. 4. Укажите uncertainty: medium (из-за открытого вопроса про canary). 5. Добавьте open_questions: ['canary namespace исключает P1 или только снижает уверенность?']. 6. В memory bank отправьте: cluster=prod-k8s, node=worker-07, owner=platform_oncall (контекст, не контракт). 7. Поставьте status: needs_clarity. 8. Проверьте: утверждение нельзя прочитать как 'мнение автора' — порог защищён ссылкой на grafana, условие закрытия — на пост-мортем.

Сложность: beginner

Название: Перевод claim в Given/When/Then и JSON Schema

Проблема: Возьмите утверждение из предыдущего упражнения и оформите его в двойной записи: поведенческая история (Given/When/Then) и минимальная JSON Schema. Определите, какие три поля схемы проверяют порог, severity и условие закрытия. Исключение для canary оформите как отдельное условие namespace_rule.

Решение: Given/When/Then: Given кластер в активной смене и за 10 минут фиксируется >=3 NodeNotReady для одного узла; When событие не в canary namespace или в canary с коррелированным ростом 5xx; Then создаётся инцидент severity=P1, первичная реакция за 8 минут, эскалация в NOC через 15 минут, закрытие после 2 последовательных OK в течение 10 минут. JSON Schema: { '$id': 'urn:spec:node-not-ready:v1', 'type': 'object', 'required': ['rule_id','severity','sla_minutes','conditions'], 'properties': { 'rule_id': {'type':'string'}, 'severity': {'type':'string','enum':['P0','P1','P2','P3']}, 'sla_minutes': {'type':'integer','minimum':1,'maximum':120}, 'conditions': {'type':'object','required':['event_code','count','window_minutes','namespace_rule'], 'properties': {'count':{'type':'integer','minimum':3}, 'window_minutes':{'type':'integer','minimum':1}, 'namespace_rule':{'type':'string','enum':['standard','canary']}}}}} Три проверяемых поля: count (порог >=3), severity (enum P1), conditions с window_minutes и namespace_rule (условие закрытия через последовательные OK — в полном треке через auto_resolve_window с регулярным выражением).

Сложность: intermediate

Название: Разделение требований и memory bank в реальном фрагменте

Проблема: Дан фрагмент из Slack-треда и пост-мортема: 'Дежурный Вася в 3 ночи заметил, что worker-07 в prod-k8s снова NotReady, написал в канал #sre-alerts, через 15 минут позвал Настю из NOC, они решили не закрывать автоматически, потому что в прошлый раз auto-resolve привёл к повторному инциденту. Оказалось, что в 2:47 был плановый деплой в canary. Старый сервис назывался node-health-check, теперь это k8s-node-monitor'. Разделите на требования (SDD) и memory bank. Объясните, почему каждый элемент относится к своему слою.

Решение: SDD-требования: '>=3 NodeNotReady за 10м → P1' (восстанавливается из повторяющейся картины), 'закрытие требует 2 последовательных OK в течение 10м' (пост-мортем: auto-resolve отклонён), 'эскалация в NOC через 15 минут' (временная цепочка событий). Memory bank: 'дежурный Вася' (кто дежурил — контекст, не контракт), 'канал #sre-alerts' (привычный канал связи), 'worker-07 в prod-k8s' (конкретная топология, меняется), 'старое имя node-health-check' (историческая лексика), 'плановый деплой в canary в 2:47' (контекст для интерпретации, но само по себе не правило — unless оформлено как условие namespace_rule). Обоснование: имена людей и узлов меняются, каналы связи — операционная привычка, а пороги и SLA — проверяемое поведение системы.

Сложность: intermediate

Название: Оценка готовности claim к утверждению

Проблема: Дано три claims для high_memory_usage. A: 'При memory_percent >= 90% за 10m для appointments-api создаётся P1' — два evidence_ref (grafana, пост-мортем), но запрет auto-resolve без двух стабильных окон не подтверждён. B: 'При memory_percent >= 85% за 5m создаётся P0' — один evidence_ref (Slack), нет пост-мортема, противоречит соседнему кластеру. C: 'При memory_percent >= 90% за 10m создаётся P1, auto-resolve запрещён без двух стабильных окон 5m каждое' — три evidence_ref, прошёл реплей на исторических данных, но владелец сервиса уволился. Определите status и uncertainty для каждого, обоснуйте.

Решение: A: status needs_clarity, uncertainty medium. Порог и severity защищены двумя источниками, но условие закрытия — открытый вопрос. Нельзя переводить в approved частично подтверждённое требование. План: запросить владельца сервиса или найти дополнительный пост-мортем. B: status rejected (или остаётся гипотезой), uncertainty high. Один источник, противоречие с соседним кластером, порог 85% не защищён — похоже на догадку из чата. Нельзя принимать без перепроверки. C: status approved или needs_clarity в зависимости от процедуры. Технически три источника и реплей дают low uncertainty, но отсутствие владельца сервиса — риск для будущего пересмотра. Решение: оставить approved с примечанием 'последнее подтверждение от уволившегося владельца, требуется re-validation при смене архитектуры' или перевести в needs_clarity до назначения нового владельца. Урок: даже сильное доказательство требует живого механизма пересмотра.

Сложность: advanced

Кейсы: Название: Восстановление SLA эскалации после ухода команды SRE в AgentClinic-production

Сценарий: Учебная модель AgentClinic-production развёрнута в Kubernetes. После оттока команды SRE остались фрагменты: 47 страниц неструктурированных логов, 11 релевантных Slack-сообщений, скриншоты дашбордов Grafana, пост-мортемы без формального SDD. Триаж-контур получает вебхуки от Grafana и PagerDuty. Нужно восстановить одно требование: когда NodeNotReady становится P1 и когда его нельзя закрывать автоматически.

Задача: 1. Разрозненные источники без единого формата: логи метрик, эскалации в PagerDuty, неформальные пост-мортемы. 2. Риск смешения операционного контекста (имена дежурных, топология кластера, старые имена сервисов) с бизнес-правилами. 3. Неявное правило про canary namespace: исключает ли он P1 или только снижает уверенность? 4. Отсутствие формального SDD — альтернатива 'набор правдоподобных догадок' неприемлема. 5. Необходимость проверяемости: восстановленная спецификация должна стать исполняемым артефактом.

Решение: 1. Применён жёсткий фильтр 'требование vs memory bank' уже на этапе инвентаризации. Имена дежурных, каналы Slack, топология worker-07 — отправлены в memory bank. 2. Создана нормализованная временная цепочка: 1248 событий NodeNotReady → группировка по 10-минутным окнам → 63 алерта → выделение 8 ранее закрытых инцидентов. 3. Выявлено совпадение резкого роста NodeNotReady с развёртыванием, и две ветки поведения: стандартный P1 и canary-путь с ослабленными порогами. 4. Сформирован claim с двумя evidence_ref: grafana:NR-2026-05-17-01 и postmortem:node-not-ready-2026-05. 5. Открытый вопрос про canary зафиксирован, не замаскирован под утверждённое правило. 6. Двойная запись: Given/When/Then + JSON Schema с полями severity, sla_minutes, conditions. 7. Для учебного минимума — genealogy.md без полного арбитража; для production-трека предусмотрен переход к файловому арбитражу в части 8.

Результат: Восстановлено проверяемое требование: '>=3 NodeNotReady за 10 минут для одного node создаёт P1, первичная реакция 8 минут, эскалация в NOC через 15 минут, закрытие после 2 последовательных OK в течение 10 минут'. Условие для canary namespace выделено как отдельное правило namespace_rule, а не примечание. genealogy.md позволяет аудировать происхождение каждого пункта. Спецификация готова к валидации в CI и реплею на исторических данных.

Извлечённые уроки: Доказательство важнее уверенной формулировки: красивое правило без evidence_ref — всё ещё гипотеза

Разделение требований и memory bank должно происходить на этапе инвентаризации, а не в конце — иначе ложные правила проникают в контракт

Исключения (canary, плановый деплой) — не шум, а указатели на скрытые условия спецификации; удалять их нельзя

Открытые вопросы должны быть явно помечены, не замаскированы под approved — это защита от принятия необоснованных решений

Двойная запись Given/When/Then + JSON Schema устраняет разрыв между человекочитаемым описанием и машинной проверяемостью

Даже сильное доказательство требует живого механизма пересмотра при смене команды или архитектуры

Связанные концепции: genealogy.md

memory bank

evidence_ref

Given/When/Then

JSON Schema контракт

нормализация временной шкалы

uncertainty

Название: Ошибка смешения memory bank и требований в проекте миграции мониторинга

Сценарий: Команда платформы мигрировала с самописного мониторинга на Prometheus+Grafana. При восстановлении спецификаций алертинга инженеры включили в SDD фразу: 'Алерты severity=P1 отправляются в канал #critical-alerts, упоминающего oncall из команды platform'.

Задача: Через 6 месяцев команда platform переименовалась в platform-infra, канал сменил название, а ротация дежурных перешла в PagerDuty. SDD пришлось переписывать, хотя бизнес-логика (когда создаётся P1) не изменилась. Проблема: операционный контекст был закодирован как контрактное требование.

Решение: Ретроспективный анализ показал, что правильное разделение: требование — 'При >=3 NodeNotReady за 10м создаётся P1, эскалация происходит через 15 минут согласно SLA'. Memory bank — 'канал #critical-alerts, команда platform, текущий oncall Вася'. Переписанный SDD с genealogy.md отделяет устойчивое поведение от изменяемого контекста. JSON Schema содержит severity и sla_minutes, но не channel_name или team_name.

Результат: Новая структура пережила три реорганизации коммуникаций без изменения контракта. Обновление memory bank — операция минуты, не требующая арбитража. Урок подтвердил: фильтр 'контракт vs контекст' критичен для долгоживущих спецификаций.

Извлечённые уроки: Имена команд, каналов, людей — memory bank, независимо от того, насколько 'очевидно' они кажутся при написании

Если при чтении SDD возникает вопрос 'а что если команда переименуется?' — это сигнал смешения слоёв

JSON Schema как аудит-инструмент: если поле не имеет enum или числовых границ, оно возможно принадлежит memory bank

Связанные концепции: memory bank

фильтр контракт vs контекст

JSON Schema контракт

genealogy.md

Советы по изучению: Начинайте с минимального учебного сценария: один claim, два источника, один открытый вопрос. Не пытайтесь сразу покрыть все 47 страниц логов — это полный production-трек

Практикуйтесь на учебной выписке из 4 строк, прежде чем применять к реальным материалам. Структура важнее объёма

Для визуального стиля: рисуйте на бумаге две колонки — левая 'требование (проверяемо)', правая 'memory bank (контекст)'. Перебирайте каждый фрагмент исходного артефакта, решая в какую колонку он попадает

Для аудиального стиля: озвучивайте claims вслух с вопросом 'а что должно измениться в системе?' Если ответ — 'ничего, это просто информация' — это memory bank

Для кинестетического стиля: физически перемещайте карточки с фрагментами между двумя стопками 'SDD' и 'memory bank', обсуждая каждое перемещение

Проверяйте каждый claim тестом 'могу ли я написать автоматический тест на это?' Если нет — возможно, это не требование, или требование недостаточно конкретно

Используйте genealogy.md как 'чеклист подозрительности': если запись не имеет двух evidence_ref — это автоматически гипотеза, независимо от того, насколько автор уверен

Практикуйтесь с Qwen Code на учебных данных в Plan Mode, но всегда валидируйте выходной JSON отдельным парсером — модель генерирует отчёт сессии, не строгий claims.json

Создавайте 'контрпримеры' как обязательное поле: хорошее упражнение — найти в исходных данных случай, который противоречит вашему claim, и объяснить почему (исключение? ошибка данных? неверная гипотеза?)

Делайте ревью genealogy.md через 24 часа с 'чужими глазами': можете ли вы, не вспоминая контекст, понять почему порог именно 3, а не 2 или 4?

Дополнительные ресурсы: Шаблон genealogy.md: book2/examples/templates/genealogy.md — стартовый шаблон для провенанса

Учебный проект первого тома: AgentClinic на TypeScript, Hono, серверном JSX, SQLite, Vitest — опора для понимания memory bank из tech-stack.md и QWEN.md

Github spec kit: https://github.com/github/spec-kit — рамка 'спецификация как исполняемый артефакт'

Часть 13 первого тома: Восстановление конституции существующего проекта — предварительная опора

Часть 8 второго тома: part-08-multiagent-tribunal.md — файловый арбитраж, детали ролей Verifier/Implementor/Safety

Примеры трибунала: examples/tribunal/ — запускаемый учебный аналог

Приложение a: appendix-a-bridges-to-book.md — связи с первым томом

Репозиторий учебника: book2/examples/ — runnable-скрипты на Python stdlib

Резюме: Восстановление спецификаций из legacy — это инженерный приём превращения хаоса артефактов (логи, чаты, пост-мортемы) в проверяемый контракт. Ключевые принципы: жёсткое разделение требований и memory bank, нормализация временной шкалы, извлечение (не генерация) claims через Qwen Code с обязательными evidence_ref, двойная запись Given/When/Then + JSON Schema, явная маркировка uncertainty и open_questions. Учебный минимум — один заполненный genealogy.md с защищённым утверждением, двумя источниками и открытым вопросом. Полный production-трек добавляет нормализаторы, исторический replay и файловый арбитраж (часть 8). Главный результат: спецификация становится цепочкой доказательств, которую можно валидировать, оспаривать, переигрывать на исторических данных и аудировать спустя месяцы.

Мои заметки
0 / 10000

Заметки сохраняются в этом браузере. На другом устройстве они не появятся.

Меню курса

Курс

Production SDD для Qwen Code CLI. Часть 2
Прогресс 0 / 100