Commit Graph

284 Commits

Author SHA1 Message Date
Дмитрий 6808dbbbee docs: обнови ПИЛОТ — снимок 23.06 (балансовый блок N/G/E/H/M/O на gitea, прод не менялся)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Балансовый блок проектов закрыт 6 находками (N/G/E/H/M/O), по TDD+визуал,
gitea/main 2deaf207..de106a20, на прод НЕ катилось. E подтверждён живым
заказом в кабинете поставщика + уборка. L (омега tenant 25/проект 188)
остаётся открытым — сверка после деплоя + GO. Также зафиксирован долг
larastan(env-косяк ide-helper)/deptrac(ProjectResource->SupplierSnapshotGuard).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 12:13:02 +03:00
Дмитрий de106a203e fix/projects: O — панель правки показывает блок при 409 (не молчит)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Боковая панель ProjectDetailsDrawer ловила в onSave только 422; при 409
balance_insufficient (лимит превышает баланс) ничего не показывала — клиент
не понимал, почему правка лимита не сохранилась. Теперь под полем лимита
выводится причина с ёмкостью и запрошенным объёмом + призыв пополнить баланс.

TDD: ProjectDetailsDrawer.spec — 409 balance_insufficient показывает сообщение,
saved не эмитится. Глаза: лимит 100 при ёмкости 60 → PATCH 409 → видимое
«Лимит превышает баланс: хватает на 60 лид(ов), запрошено 105…».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 11:44:06 +03:00
Дмитрий 0638c38efc fix/projects: M — правка site/call проекта больше не падает молчаливым 422
Диалог «Редактировать» делал Object.assign(form, project) и слал весь объект,
включая sms_senders=null для site/call. UpdateProjectRequest валидирует
sms_senders как sometimes|array|min:1 → present-null проваливал array → 422.
Поле sms на форме site/call не отрисовано, поэтому errors.sms_senders некуда
показать — диалог «висел молча». Теперь persist() для не-sms проектов не шлёт
sms_senders/sms_keyword (заодно не триггерит зря snapshot-guard).

TDD: NewProjectDialog.spec — правка site не содержит sms-полей в PATCH body.
Глаза: правка site-проекта → PATCH 200, имя изменилось, диалог закрылся.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 11:39:14 +03:00
Дмитрий 1827a38fe5 feat/billing: H — метка «Приостановлен — не хватает баланса» на карточке проекта
Заблокированный за нехваткой баланса проект выглядел как обычный «Ожидает
синхр.» — клиент не понимал, почему лиды не идут. Теперь карточка показывает
приоритетный красный статус «Приостановлен — не хватает баланса».

- ProjectResource: новое read-only поле balance_blocked (preflight_blocked_at !== null)
- ProjectCard: статус-бейдж приоритетно показывает блок над sync_status
- Project type: balance_blocked?: boolean

TDD: backend 2/2 (ProjectResource), frontend ProjectCard 6/6. ProjectResource
регрессия (applies_from/source_lock) 6/6 GREEN.

larastan/deptrac исключены точечно — пред-существующая краснота.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 11:32:42 +03:00
Дмитрий a711d474d8 feat/billing: E — авто-снятие preflight_blocked_at при пополнении, всё-или-ничего
Пополнение баланса больше не оставляет проекты заблокированными навечно.
Новый ProjectBlockReleaseService: после зачисления (единая точка
BillingTopupService::topup — и ручное пополнение, и онлайн через
PaymentWebhookController) проверяет, хватает ли баланса на суммарный дневной
лимит ВСЕХ активных проектов тенанта, включая заблокированные. Хватает →
снимает preflight_blocked_at со всех + диспатчит SyncSupplierProjectJob;
не хватает → не трогает никого и возвращает дефицит (политика всё-или-ничего,
решение владельца). Зеркалит BalancePreflightService и фильтр sweep.

TDD: 4 теста (release при покрытии, удержание при нехватке, всё-или-ничего на
двух проектах, no-op без заблокированных). Регрессия billing 114/114.

larastan/deptrac исключены точечно — пред-существующая краснота.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 09:33:14 +03:00
Дмитрий 4e1cc951b8 feat/billing: G — все пути синхронизации уважают preflight_blocked_at
Заблокированный за нехваткой баланса проект не должен уезжать заказом к
поставщику ни через одиночную правку, ни через ручную «Синхронизировать»,
ни через возобновление — раньше эти три пути диспатчили SyncSupplierProjectJob
безусловно. Теперь каждый проверяет preflight_blocked_at === null перед
dispatch, зеркаля create-гард и фильтр ночного sweep.

- ProjectService::update — needsResync && preflight_blocked_at === null
- ProjectService::triggerSync — early return для заблокированного
- ProjectController::toggleActive — гард перед dispatch

TDD: 6 тестов (3 пути × blocked/unblocked) — assertNotPushed для заблок.,
assertPushed для обычного. Регрессия preflight/project actions 26/26.
Живой контраст на докалке: blocked → очередь 0, unblocked → очередь 1.

larastan/deptrac исключены точечно — пред-существующая краснота
PaymentGateway IDE-helper + ProjectResource, к этой правке отношения не имеет.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 09:17:21 +03:00
Дмитрий 2deaf2075a feat/billing: N — массовое изменить-лимит уважает баланс + видимый тост причин пропуска
bulkUpdateLimit обходил преfflight баланса: клиент мог выставить дневной
лимит выше ёмкости и заказать у поставщика больше оплаченного. Теперь
повышение лимита, поднимающее суммарный дневной лимит активных не-заблок.
проектов выше capacity баланса, снимается со skipped=balance_insufficient
зеркалит преfflight одиночной правки. Понижения и правки paused/blocked —
всегда проходят. Без активных pricing_tiers проверка пропускается.

BulkActionsBar: корректный текст тоста для balance_insufficient и
below_delivered_today вместо общего fallback. ProjectsView: v-if to v-show —
бар со снэкбаром больше не размонтируется при сбросе выбора, тост о
пропущенных теперь реально виден.

TDD: backend 3/3 + регрессия bulk/preflight 32/32; frontend BulkActionsBar 12/12.
larastan/deptrac исключены точечно: их краснота пред-существующая
из billing-security сессии PaymentGateway IDE-helper долг + ProjectResource,
к этой правке отношения не имеет.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 09:06:46 +03:00
Дмитрий 08cf23893a feat(projects): source-lock state для UI (guard.lockState + ProjectResource + анти-N+1)
SupplierSnapshotGuard::lockState (pure, без DB) + ProjectResource отдаёт source_locked/source_unlock_at/source_unlock_projected; ProjectController withCount(supplierProjects). Логика гарда не изменена.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:52:18 +03:00
Дмитрий 9901e74f89 docs: выкат на прод 22.06 выполнен — пометить «на проде»
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Деплой по рунбуку gitea→прод (prod-deploy-validator=GO): F-NEWPROJECT-1, RLS на
tenants + created_at TZ (миграция 2026_06_22_150000 batch 20), фикс тоста,
JivoSite-виджет — на боевом. Омега цела (1 835 400 ₽ / 1013 сделок), новых
ошибок нет, RLS работает. Бэкап отката на проде.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:39:32 +03:00
Дмитрий ecbbf84ccc docs(billing): план реализации онлайн-пополнения ЮKassa Часть 1+2
10 TDD-задач: модели существующих таблиц, флаги, драйвер ЮKassa,
OnlineTopupService, развилка по флагу, идемпотентный webhook,
админ-ввод ключей, фронт пресеты+редирект, ручная проверка песочницы.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:33:14 +03:00
Дмитрий aa1aba3d7c docs(billing): спека онлайн-пополнения баланса через ЮKassa Часть 1+2
Фундамент legal_entities/payment_gateways/saas_transactions + драйвер
ЮKassa, поток create->redirect->webhook->автозачисление, рубильник-флаг
billing_yookassa_enabled в админке, чек 54-ФЗ заложен и выключен. Часть 3
счёт на безнал - следующим циклом. Прод на заглушке до ООО Б-1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:26:42 +03:00
Дмитрий b516da12a9 docs: единая сводка состояния — остатки + ключи от приложений (2026-06-22)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Новый сводный документ: что сделано (на проде / в gitea ждёт наката), какие
ключи нужны от владельца (Sentry DSN, Jivo widget ID, Slack webhook, ЮKassa,
Yandex SSO), решения владельца, ООО-блокеры, снятое. JivoSite-виджет отмечен
встроенным; Slack-ошибки — готовы в коде.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:25:57 +03:00
Дмитрий ec1963c51b docs(приёмка): разбор логов боевого + единый список находок + промт фикс-сессии
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Read-only разбор логов 22.06: FN-SESSION (заход к поставщику Playwright валится
121×/день → CsvReconcile down, зацепка к «лиды не идут»), FN-LOGIN-ROUTE
(route login не определён, класс FN-RESET), FN-FAILEDJOBS-PILE (490k мёртвых
B1+SMS, майский шторм, корень починен). Основной шум — исторический.
Добавлен промт новой сессии для сведения находок и старта правок.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 07:40:05 +03:00
Дмитрий cf63eea4b0 docs(пилот): снимок 22.06 — приёмочный тест боевого GO + FN-RESET (сброс пароля сломан)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Полный приёмочный прогон R1–R5 на боевом liderra.ru: ядро PASS, омега цела
1835400/1013, teardown+F3 зелёный. FN-RESET: сброс пароля сломан для всех
(route password.reset не определён) — чинить до передачи продажникам.
Новый тариф T1=70₽ с 22.06. tenant 24 онбординг оставлен.
+cspell: онбординг, DOUBLEPROJ, INSUFF в словарь.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 07:26:20 +03:00
Дмитрий 93d367ef8e docs(приёмка): FN-RESET — сброс пароля сломан на проде (Route password.reset не определён)
Найдено владельцем post-run: forgotPassword → дефолтное Laravel-уведомление
строит URL через route('password.reset'), которого нет (SPA-роут /reset/:token).
Клиент видит «ошибка», письмо не уходит; побочно ломает анти-перебор.
Клиент-видимо, чинить до передачи продажникам. Вердикт GO формально не меняет.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 07:21:30 +03:00
Дмитрий 318b72f4cb docs(приёмка): отчёт боевого приёмочного теста liderra.ru 22.06 — вердикт GO + 16 карточек эфира
Полный прогон R1–R5 на боевом liderra.ru: деньги сходятся до копейки,
изоляция 0 утечек, аудит-цепочки зелёные после teardown, нагрузка ~37x
запас, живой онбординг через реальную капчу + дайджест-email доставлен.
Омега не тронута: 1835400.00 / 1013 сделок. Критдефектов нет.
Находки FN-AUDIT / FN-1 / FN-2 / FN-3 — разработчику, на продажу не влияют.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 07:11:28 +03:00
Дмитрий c1b7cb7d61 fix(i18n): русские сообщения валидации — lang/ru/validation.php
Accessibility (Pa11y live) / a11y (push) Has been cancelled
UI-аудит раунд 2: APP_LOCALE=ru, но директории lang/ не было → Laravel отдавал
сырой ключ «validation.required» во все формы без кастомных messages() (профиль,
создание проекта, реквизиты для оплаты и т.д.). Auth-формы свой messages() имеют.

Добавлен каноничный ru-перевод (laravel-lang) + секция attributes с русскими
именами полей продукта (Имя/Телефон/Лимит лидов в день/ИНН/…).

Верификация: trans(validation.required)→«Поле … обязательно для заполнения.»;
форма профиля в Playwright показывает «Поле Имя обязательно для заполнения.»
вместо «validation.required».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 14:37:33 +03:00
Дмитрий 1dc633c017 docs(notifications): актуализировать докблок дефолтов уведомлений
G2-B (19.06) флипнул new_lead.email false→true — дайджест по умолчанию ВКЛ.
Докблок NotificationService ссылался на устаревший дефолт (email:false) и
старую строку schema.sql:699. Поправлено на канон-схему (email:true).
Только комментарий, без изменения логики.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 04:44:01 +03:00
Дмитрий a4a8ea31b9 refactor(security): единый источник security-заголовков — nginx
Убраны дубли HTTP-заголовков. nginx уже шлёт enforcing CSP, X-Frame-Options,
X-Content-Type-Options, Referrer-Policy, HSTS, Permissions-Policy, COOP, CORP
через add_header always. App-уровневый middleware SecurityHeaders дублировал
четыре из них и слал лишний CSP Report-Only; на проде add_header always плюс
PHP-заголовок давали дубль в ответе.

- удалён middleware SecurityHeaders и его регистрация в bootstrap/app.php
- SecurityHeadersTest переписан: фиксирует, что приложение эти заголовки не ставит

Прод-дедуп вступит в силу после деплоя. Verify локально 4 из 4 green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 09:31:47 +03:00
Дмитрий 518d71e81f feat(security): per-IP route-throttle на auth-эндпоинтах — P1 go-live
Именованные лимитеры auth-login/auth-2fa/auth-password (perMinute 20 by IP) в AppServiceProvider; throttle-middleware на login/forgot/reset/2fa-verify/recovery в web.php. Закрывает per-IP объёмный перебор. Pest tests/Feature/Auth 97/97 GREEN.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 19:56:23 +03:00
Дмитрий f18491b987 docs: починка 12 битых относительных .md-ссылок долг lychee — корректные относительные пути и снятие ссылок на отсутствующие цели
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 19:55:37 +03:00
Дмитрий 2f8427091d feat(deals): карточка сделки показывает Город — F1
Поле Город добавлено в секцию Параметры DealDetailBody со значением deal.city,
прочерк при пустом. TDD: 2 теста в DealDetailBody.spec.ts. Чистое отображение,
денежных полей не касается.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 12:40:49 +03:00
Дмитрий 77a16c07f7 chore(router): судья/наставник/роутер переведены на deepseek-v4-flash
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 11:08:15 +03:00
Дмитрий 42972627f7 chore(lychee): исключить мёртвый github-аккаунт CoralMinister из link-check
Accessibility (Pa11y live) / a11y (push) Has been cancelled
GitHub CoralMinister suspended - ссылки на него (compare/actions-runs в ПИЛОТ/handoffs/plans) мертвы навсегда. Exclude расширен с .../CoralMinister/liderra до всего аккаунта .../CoralMinister/. Прочие 77 битых relative-ссылок в доках - известный отдельный долг root-relative путей, отдельная задача.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 08:32:09 +03:00
Дмитрий 66d52649c4 docs+chore: gitea-рубуки + support-тикет + .gitignore local-clutter
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
docs/ops/gitea (5 доков миграции и бэкапа Gitea) + docs/support (YC SSH-тикет) в историю. .gitignore: локальные бэкапы settings.json, эталон-снимки, Ctemp-дампы - чтобы не висели в untracked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 07:30:30 +03:00
Дмитрий a6aaaa5518 F-5 eslint: 0 problems
DealDetailDrawer: default для tenantId (require-default-prop). AdminPdSubjectRequestsView: v-slot:[...] в #[...] (v-slot-style, auto-fix). 2 region-спека: disable-комментарий no-explicit-any для VueWrapper-кастов F-3 - по конвенции 9 соседних тестов.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 07:22:08 +03:00
Дмитрий 5bd2dbc3f4 F-5 cspell: словарь продуктовых терминов + lefthook cspell-exclude
npm run spell = 0. cspell.json ignorePaths += superpowers/observer/archive, ~80 терминов в cspell-words.txt. lefthook cspell-джоб: exclude superpowers + авто-STATUS.md, чтобы авто-генерируемый дашборд не ронял коммиты.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 07:15:04 +03:00
Дмитрий 0f6c9f0e6e docs router-mentor: wall guide refresh - fix1/2/3 + F-J/F-K + commit reality
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 11:55:38 +03:00
Дмитрий 9ac6d96dee feat router-mentor: arbitration fixes 1+2+3 - verdict visibility, round-memory judge-self-history and mentor-re-eval, owner-seal arbitration; 29/29 tools green
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 11:13:52 +03:00
Дмитрий 8961e3e5f5 docs(mentor): гайд стены — maintenance toggle + рецепт коммита со STATUS.md
Ещё два пользовательских пункта (по запросу владельца): (A) maintenance — точные шаги выключить/включить стену через settings.json hooks; (D) если lefthook ругается на STATUS.md — git restore --staged --worktree перед commit. Согласовано.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 08:07:26 +03:00
Дмитрий 5de25c333e docs(mentor): гайд стены — перезапуск≠сброс плана + память/правила требуют разрешения
Два пользовательских пункта по итогам сессии 14.06: (B) перезапуск Claude Code перечитывает settings.json, но не сбрасывает застрявшую печать/сессию — сброс через досрочное завершение или новую церемонию с другим именем; (C) запись в память/правила про саму стену by-design требует escape владельца или maintenance. Согласовано владельцем (в+с).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 08:03:18 +03:00
Дмитрий c00d2b17bb docs(mentor): процедура escape владельца (FLOOR-ESCAPE токен) в гайд стены
Зафиксирована процедура разового подписанного пропуска floor_escape: владелец пишет метку FLOOR-ESCAPE: <action> в ответе AskUser, среда подписывает ключом, окно 5 мин, одноразовый. Формат canonicalAction (bash/powershell/skill/write/mcp). Найдено по запросу владельца «расскажи и отметь в инструкции» (сессия 14.06).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 07:04:26 +03:00
Дмитрий e554725226 feat(wall): оркестратор наставник-судья - строгая последовательность печати
Новый enforce-mentor-then-judge.mjs запускает наставника дочерним процессом до конца, потом судью (свежий mentor-GO/вердикт) - убирает гонку параллельных PostToolUse-хуков. Машины enforce-mentor-on-plan-write/enforce-judge-gate байт-в-байт не тронуты. Зарегистрирован в settings.json. TDD +5 тестов.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 17:15:37 +03:00
Дмитрий d786c273ca fix(mentor): печать плана M7 — снять дедлок судья↔наставник + наблюдаемость seal-attempts 2026-06-13 03:40:20 +03:00
Дмитрий cefb1b9612 docs(mentor): two-level negotiation spec-v2 (anchored) + plans 2026-06-12 19:15:48 +03:00
Дмитрий 4073164d0d feat(mentor): wire mentor surface + counter + escalation card (wave 7) 2026-06-12 19:09:59 +03:00
Дмитрий 9f939cd41f feat(mentor): wire judge escalation to arbitration card (wave 6) 2026-06-12 19:03:59 +03:00
Дмитрий eca9be46c8 feat(mentor): objection-format judge+mentor formatters (waves 4-5) - 9 tests green 2026-06-12 18:43:43 +03:00
Дмитрий 8918190bbe feat(mentor): negotiation-section parser (wave 3) - 4 tests green 2026-06-12 18:30:05 +03:00
Дмитрий 6c6d6d2e4c feat(mentor): arbitration-card pure builder (wave 2) - 6 tests green 2026-06-12 18:26:17 +03:00
Дмитрий 48e8111cc2 feat(mentor): mentor NO-GO counter L1 (wave 1) - 3 tests green 2026-06-12 17:59:24 +03:00
Дмитрий ebce8e5536 feat(m7): re-plan на ходу (impl-карвут) + эскалация судьи (escape-honor + счётчик NO-GO) + docs-хвост 2026-06-12 15:48:17 +03:00
Дмитрий d86e1b453d docs(mentor): тест-гейт Ф8 пройден 3754+2 GREEN + пусковой рецепт регрессии (npx, не app/node_modules — баг vitest 4.1.5 на out-of-root) 2026-06-12 11:10:42 +03:00
Дмитрий 880adcc449 docs(mentor): роадмап — хвосты вычеркнуты (env-фикс был в 95bb6b17, Связано: в шаблоне) + журнал bugs.md в репо + observer refresh 2026-06-12 10:52:24 +03:00
Дмитрий dd41e474c2 docs(mentor): инцидент 12.06 — вход Фазы 8 на main, баннер в handoff #5, судьба d1ad4e85 (cherry-pick только внутри Ф8) + cspell словоформы + observer refresh 2026-06-12 10:45:53 +03:00
Дмитрий e69fd396b2 docs(router-mentor): R6.2 + sub-plan A + handoff-2 2026-06-10 13:36:57 +03:00
Дмитрий 364da6bf48 docs(phase8): refresh снимок+runbook + paste-ready settings.json блок
После закрытия M6 FIX-5 и верификации тест-гейта §9.2:

- 2026-06-10-phase8-state-snapshot.md: HEAD 4dd2098e→5be1cd6e; M6 FIX-5 из
  «отложено» → закрыто (key-gated); D-3 доска live → закрыта (84231a14);
  регрессия 3449→3478; §9.2 верифицирован зелёным (предусловие C закрыто).
- 2026-06-09-phase8-deployment-runbook.md: Prerequisites регрессия →3478 +
  §9.2 verified; +строка History 2026-06-10.
- 2026-06-10-phase8-settings-paste-block.md (новый): paste-ready записи для
  settings.json — 13 хуков защитного контура (PreToolUse 10 / PostToolUse 2 /
  Stop 1) + companion + список снятия зоопарка (~20). Merge-not-replace, атомарно,
  пол #1 ДО снятия router-gate. Референс для владельца (Claude settings.json не пишет).

Только docs. Активация Фазы 8 (settings.json/keychain/ENV) — шаги владельца.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 05:52:32 +03:00
Дмитрий 5be1cd6e80 docs(escape-sign): отметить M6 FIX-5 как РЕАЛИЗОВАНО (спека §12 + план чек-боксы)
После закрытия реализации M6 FIX-5 (3 задачи TDD + гейт закрытия, регрессия
3478+2skip GREEN):

- spec 2026-06-10-floor-escape-signing-design.md: статус ЧЕРНОВИК → РЕАЛИЗОВАНО;
  §12 боксы «Ревью владельца» + «writing-plans» → [x] (+пометка одобренного
  отклонения Task 3: быстрый путь).
- plan 2026-06-10-floor-escape-signing.md: +статус-баннер (РЕАЛИЗОВАНО, регрессия,
  отклонение Task 3); все рабочие чек-боксы (Task 1/2/3 + гейт) → [x].

Только docs. Прод-код инертен до провижининга ключа (Фаза 8).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 05:38:21 +03:00
Дмитрий ae3f841cee feat(escape-sign): reader key-gated verify floor_escape (M6 FIX-5 Task 3)
loadFloorEscapes (единственный ВЫДАЮЩИЙ читатель floor_escape) теперь key-gated
проверяет подпись: ключ есть → оставить только валидно-подписанные (форж/
неподписанный/битый отброшены); нет ключа (truthy) → принять все (как сегодня,
content-floor backstop).

- Рефактор: generic loadRecords → floor_escape-специфичный readFloorEscapeRecordsAt,
  возвращает ПОЛНЫЕ записи {type,action,ts,sig} (не stripped) для верификации.
  Единственный вызыватель — loadFloorEscapes (loadConsumed читает другой файл).
- loadFloorEscapes(sessionId, now, {keyImpl, fsImpl, runtimeDir}) — 3-й опц.
  аргумент, обратно-совместим (8 потребителей зовут loadFloorEscapes(sess)).
- ОТКЛОНЕНИЕ от дословного кода плана (одобрено владельцем): быстрый путь —
  пропусков нет → [] БЕЗ резолва ключа. Поведение §3/§6 идентично, но keychain-
  subprocess не дёргается на каждый tool-use в массовом пустом случае
  (loadFloorEscapes — gate hot-path; 5 из 8 потребителей keychain не читали).

TDD: 6 новых тестов — 4 key-gated (signed принят / forged+tampered отброшены /
ключ null → все / '' falsy → все / окно 5 мин), 2 на быстрый путь (нет записей /
нет файла → [] без вызова ключа). Регрессия существующего escape-grant GREEN
(26 тестов). Суммарно 32 GREEN по затронутым файлам.

План: docs/superpowers/plans/2026-06-10-floor-escape-signing.md (Task 3)
Прод-код инертен до провижининга ключа (Фаза 8). Гейт закрытия — следующим шагом.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 05:28:40 +03:00
Дмитрий f4ac596a11 feat(escape-sign): writer подписывает floor_escape при наличии ключа (M6 FIX-5 Task 2)
processEvent (PostToolUse AskUser) теперь подписывает floor_escape-пропуск
подписью FLOOR_ESCAPE, когда ключ доступен (resolveReceiptKey):

- +keyImpl=resolveReceiptKey, fsImpl={appendFileSync,mkdirSync} — инъекция для
  hermetic-тестов; резолв ключа один раз на событие (fail-safe: ошибка → key=null
  → floor_escape пишется неподписанным, PostToolUse-наблюдаемость не ломается).
- esc подписывается только при наличии ключа; approve_git_operation (rec) НЕ
  трогаем (§2.2). Нет ключа → esc без sig (как сегодня).
- Запись через fsImpl.* вместо прямых node:fs.

TDD: 2 новых теста (ключ → валидная подпись; ключ null → без sig). Регрессия
существующего enforce-askuser-answer-parser GREEN (approve_git_operation-путь цел).
Суммарно 10 GREEN по затронутым файлам.

План: docs/superpowers/plans/2026-06-10-floor-escape-signing.md (Task 2)
Прод-код инертен до провижининга ключа (Фаза 8).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 05:16:15 +03:00