WEB board

всеканоны и докиворкеры↗ iOS↗ Легаси
WEB-405 · Задача · — · web

[WEB370-G] Active/passive lease и запрет двух активных копий

Закрыт P1 · важно ведёт: — эпик: WEB-395
Суть
Источник: WEB370PLAN2. Зависимости: WEB370-B,D,F. Оценка: 1 день. Обязательный gate перед любым platform-facing действием.

--- 30.08 ~15:25Z (Фабл): ПРИЁМКА GO (ACCWEB370G): active/passive lease принят — гонка на захват, истечение/renewal, fencing без SSH к Pi, clock skew, «протухший lease пишет → отвергнут» проверены. Ступень G ЗАКРЫТА. Отчёт: A1 ACCWEB370G-REPORT.md.
Чем закрывается (приёмка)
Только один host имеет platform egress; A1 identities fail closed без marker/lease; Pi reboot остаётся fenced/masked; duplicate Signal/TG/provider-route activation блокируется.
Доказательства
[2026-08-27 08:40Z] web405g в очереди A1: lease-механизм (arbiter M1), гейт в unit-ы WEB404F, fencing-скрипт Pi (dry-run, применение координатором), негатив на две активные копии.
[2026-08-27 09:50Z] WEB405G DONE: lease-механизм + гейт в unit-ы (verify заново), fencing Pi как dry-run на A1 (прод не тронут), негатив на две активные копии. -> review. Миграция A-G ВСЯ в review.
[2026-08-27 20:29:19Z tickacc5] ВЕРДИКТ: не доказано
Что проверил: открыл WEB405G-REPORT.md и ACCTOGGLE3-REPORT.md; выполнил web405g-lease/tests/run-local-tests.sh; прочитал m1/m1-lease-authority.sh и lease-holder-check.sh; провёл независимые временные F1/F2 негативные тесты без production state.
Что увидел: штатный mock harness PASS, но F1=FAIL — revoke принял proof с mismatched migration_id; F2=FAIL — старый lease того же epoch принят при floor из-за epoch >= floor. На A1 marker/lease отсутствуют; production migration в report NO-GO.
Отрицательный тест: mismatched migration proof was accepted by revoke; older same-epoch lease was accepted at floor. Это нарушает fence/migration и stale-epoch запреты.
Чего не хватает: проверка migration_id в revoke, запрет epoch <= accepted floor, повторный adversarial+positive harness и production fence/lease receipts. Production не изменялся.

---
## 2026-08-29 04:15Z — взят в работу (ночная цель owner-а: миграция-эпик)
Волна WEB405 заряжена (A1 queue/364), база l66 eb577cd1. Требования круга: (1) инвентарь существующих механизмов lease/singleton/lock в телефонии, воркерах, cron — таблица «механизм → есть? → атомарен? → переживает рестарт?»; (2) устройство аренды: одна активная копия, TTL, продление, АТОМАРНЫЙ захват на уровне БД; пассивная копия обязана ОТКАЗЫВАТЬ, а не тихо простаивать; (3) три вопроса границы процесса (рестарт / две одновременные попытки → ровно один победитель / истечение TTL у мёртвой копии); (4) наблюдаемость смены владельца и отказов; (5) тесты: гонка, TTL, «зомби» (жив, но не продлевает), рестарт победителя. Прод/Pi/Oracle НЕ трогать.
Почему важно: без аренды переключение Pi→Oracle может дать ДВЕ активные копии — двойные списания и двойные звонки. Связано: WEB-370 (переезд), WEB-409 (тумблер, идёт круг 9 по sidecar-обходу), WEB-413 (cutover+наблюдение).

---
## 2026-08-29 06:05Z — ACC405: NO-GO. Аренда держит вход, но не останавливает начатую работу
Принято приёмкой (реальный PostgreSQL, не моки): атомарность — 25/25 гонок дали ровно одного победителя и одну строку (PK scope + INSERT ON CONFLICT ... RETURNING); TTL/рестарт — при TTL 500 мс захват через 200 мс отклонён, после 600 мс разрешён, старый токен на продление отвергнут, рестарт владельца ротирует токен и поднимает generation; пассивная копия — active=false, reason=active_holder, cron 503 с holder/reason, телефония retryable 503; часы — всё считается в БД через CURRENT_TIMESTAMP, время процесса не участвует.
БЛОКЕР: аренда ограничивает только ВХОД. Adversarial-прогон: pi c TTL 500 мс, cron run() занят 1.4 с без heartbeat, oracle забрал аренду (generation=2), guard записал renewal_lost — но handleCronRequest вернул HTTP 200 с workCompletedAfterLeaseWindow=true. То есть зомби доделывает побочные эффекты после потери аренды → двойные списания/звонки при переключении остаются возможны.
Круг WEB405B заряжен (queue/370): проверка владения ПЕРЕД каждым побочным эффектом, единая обёртка «выполнить под арендой» для cron/телефонии/фоновых, ответ при потере аренды не 200 (503 lease_lost + маячок), воспроизведение сценария приёмки в тестах.

---
## 2026-08-29 08:35Z — ACC405B: NO-GO. Fence не на всех telephony entrypoints
Принято (реальный PostgreSQL, отдельная proof-база, прод не затрагивался): основной cron-сценарий исправлен — зомби останавливается ДО следующего эффекта и получает 503.
БЛОКЕР: execution fence подключён не ко всем активным entrypoints телефонии, названы конкретные — signal-call/v1/outbound/dispatch-failed/route.ts (voiceSession.findUnique/update :105/:138 и maybeEnqueueOutboundCallSummary :166 без обёртки) и signal-call/v1/sessions/[sessionId]/google-bootstrap/route.ts (DB read и proxy/direct bootstrap fetch :61, :139-160). Пассивная копия может начать запись/provider/lifecycle работу без аренды.
Круг WEB405C (queue/389): оба маршрута под обёртку + САМОСТОЯТЕЛЬНЫЙ обход ВСЕХ telephony/messenger entrypoints с таблицей «через fence? какие побочные эффекты» + тест-страж на новые entrypoints вне fence.

---
## 2026-08-29 12:10Z — ACC405D: NO-GO. Пассивная копия успевает ПРИНЯТЬ ЗВОНОК
Принято (реальные PostgreSQL takeover-пробы): три блокера прошлого круга + найденный автором cli-bridge-mac-daemon.ts подключены к общему DB-fence web370-runtime; после перехвата старое исполнение не доходит до следующего эффекта, пассивная копия не входит в callback даже при свободном локальном lock.
БЛОКЕР: infra/signal-adapter/signal-call-poller.js (systemd web403-signal-call-poller-pi.service) делает provider-side acceptCall — создаёт Signal-туннель — на строках 715-719, и только потом зовёт fenced app-POST /api/signal-call/v1/sessions/start (:750). Ни withActivePassiveLease, ни ACTIVE_PASSIVE_LEASE_SCOPE, ни assertActivePassiveLeaseFence в файле нет. Пассивная копия успевает принять входящий звонок и породить эффект у провайдера ДО того, как маршрут вернёт 503 → при переключении Pi→Oracle возможен двойной приём звонка.
Круг WEB405E (queue/411): проверка аренды ДО первого провайдерского действия, та же общая обёртка (не третья реализация), самостоятельный обход ВСЕХ systemd-юнитов и поллеров с таблицей «первое побочное действие → под fence?».

---
## 2026-08-29 13:05Z — круг 5 сдан, приёмка заряжена
WEB405E: поллер звонков (infra/signal-adapter/signal-call-poller.js, юнит web403-signal-call-poller-pi.service) должен спрашивать аренду ДО provider-side acceptCall. Приёмка ACC405E (queue/414) требует: смоделировать входящий звонок на пассивной копии (туннель не создаётся), убедиться в отсутствии ложных отказов на активной, САМОСТОЯТЕЛЬНО обойти все systemd-юниты/поллеры/демоны с таблицей «первое побочное действие → под fence?», проверить, что используется общий контур web370-runtime, а не третья реализация.
Это последний известный блокер линии аренды — она же элемент эпика миграции (переключатель Pi→Oracle).

---
## 2026-08-29 13:35Z — ACC405E: NO-GO. Поведение принято, но юнит не даёт БД → активная копия отказывает СЕБЕ
ПРИНЯТО по поведению: аренда проверяется ДО IPC/Signal-соединения и ДО первого provider-side acceptCall; пассивная копия звонок не принимает и туннель не создаёт; активная принимает; второго незакрытого Signal-входа приёмка не нашла.
БЛОКЕР: infra/signal-adapter/systemd/web403-signal-call-poller-pi.service:11-31 не задаёт DATABASE_URL и не подключает EnvironmentFile. В обычном systemd-окружении PrismaClient (src/lib/prisma.ts:36-44) падает с PrismaClientInitializationError, поллер пишет «REFUSED active-passive lease» и выходит с кодом 75 ДО Signal-сокета. На реальной машине это означало бы: активная копия отказывает сама себе, звонки не принимаются вообще.
⚠️ Отдельный дефект наблюдаемости: database_error превращается в «lease refused» — разные причины под одной надписью; оператор не поймёт, что сломано окружение.
Круг WEB405F (queue/416): дать юниту окружение как у note-clone-3010/source-indexing, развести коды и маячки database_error vs lease refused, пройти ВСЕ юниты и plists таблицей «получает ли DATABASE_URL/секреты».

---
## 2026-08-29 14:05Z — круг 6 сдан, приёмка заряжена
WEB405F: юнит поллера получает окружение (как note-clone-3010/source-indexing), причины разведены — ошибка окружения не маскируется под отказ аренды. Приёмка ACC405F (queue/419) требует: построчная сверка трёх юнитов, ФАКТИЧЕСКИЙ запуск с пустым DATABASE_URL и показ вывода (отдельный код/маячок, не «lease refused»), самостоятельный обход ВСЕХ юнитов и plists таблицей «откуда берёт секреты», сохранность кругов 1-5.
Это последний известный блокер линии аренды — элемента переключателя Pi→Oracle.

---
## 2026-08-29 14:20Z — ✅ ACC405F: GO. Линия аренды ЗАКРЫТА (шесть кругов)
Принят коммит круга 6: web403-signal-call-poller-pi.service получает DB/app-окружение ДО запуска поллера, есть отдельный boot-fail при отсутствии DATABASE_URL, ошибка БД больше НЕ классифицируется как отказ active/passive lease. Второго аналогичного юнита/plist без источника окружения приёмка не нашла. Не регрессировали: active/passive, порядок проверки ДО acceptCall, остановка зомби, четыре Signal bridge-входа.
Путь линии: (1) атомарный захват аренды 25/25 гонок; (2) прерывание уже начатой работы (зомби возвращал HTTP 200); (3) fence на Next-маршрутах; (4) fence на внешних процессах и мостах; (5) поллер спрашивает аренду ДО provider-side acceptCall; (6) окружение юнита + разведение причин отказа.
Значение: это элемент эпика миграции — переключатель Pi→Oracle. Код готов; сам cutover — по гейту owner-а.

---
## 2026-08-29 09:40Z — ЭВОЛЮЦИЯ ЛИНИИ АРЕНДЫ, шесть кругов (для нулевого агента)
Зачем: без аренды переключение Pi→Oracle может дать ДВЕ активные копии — двойные списания и двойные звонки.
1. WEB405 (e4dd622c) → ACC405 NO-GO: захват атомарен (25/25 гонок — один победитель), TTL/рестарт, отказ пассивной копии, время из БД (CURRENT_TIMESTAMP) — принято; НО потеря аренды не прерывала уже начатую работу: зомби доделывал побочные эффекты и возвращал HTTP 200 при renewal_lost.
2. WEB405B (9f0012f3) → ACC405B NO-GO: cron-зомби прерывается и получает 503, но fence не на всех telephony entrypoints (signal-call/v1/outbound/dispatch-failed:105/138/166, sessions/[id]/google-bootstrap:61/139-160).
3. WEB405C (ce306ccc) → ACC405C NO-GO: Next-маршруты закрыты, но вне Next остались me2-compiled-server.cjs (:3020, проксируется nginx), me-bridge-mac-daemon.ts (launchd), me-bridge-pipe-watcher.ts. Отмечено: локальный lock MeBridgeSession НЕ заменяет fence (нет scope/TTL/holder, не прерывает после перехвата).
4. WEB405D (6038e8dd) → ACC405D NO-GO: четыре bridge-входа закрыты и проверены реальными takeover-пробами, но infra/signal-adapter/signal-call-poller.js (юнит web403-signal-call-poller-pi.service) делал provider-side acceptCall на :715-719 ДО fenced app-POST :750 — пассивная копия успевала ПРИНЯТЬ ЗВОНОК.
5. WEB405E (c69fbd66) → ACC405E NO-GO: поведение принято, но systemd-юнит не давал DATABASE_URL → PrismaClient падал, поллер писал «REFUSED active-passive lease» и выходил с кодом 75 — активная копия отказывала САМА СЕБЕ, а причина маскировалась под отказ аренды.
6. WEB405F (547ee42c) → ⭐ACC405F GO: окружение юнита как у note-clone-3010/source-indexing, database_error отделён от lease refused, второго такого юнита приёмка не нашла.
Отчёты: WEB405*-REPORT.md и ACC405*-REPORT.md на A1. Едет в l68. Сам cutover — по гейту owner-а.

[29.08 ⚠️ ЭТА РАБОТА УРОНИЛА ПРОД — читать перед посадкой похожего]
Механизм аренды поехал на прод в линии l68 (18af977a) и через 40 минут закрыл ВСЕ платные пути (503).
Цепочка: resolveActivePassiveLeaseConfig (src/lib/activePassiveLease.ts:107) ставит required=true по умолчанию при NODE_ENV=production; ownerId читается из ACTIVE_PASSIVE_COPY_ID (:109, normalizeOwnerId :143). В drop-in прода переменной не было -> deny(config,'missing_copy_id') (:492) -> периодическая сверка расхода /api/cron/spend-reconcile отвечала {"ok":false,"error":"active_passive_lease_denied","skipped":"passive-copy","reason":"missing_copy_id","scope":"web370-runtime","holderId":null} -> мертвец reconcile_deadman -> paidReady=false -> 503 на платном.
Последняя успешная сверка 2026-08-29T07:29:49Z = ровно момент переключения на l68.
ПОЧИНКА координатора: Environment=ACTIVE_PASSIVE_COPY_ID=pi в standalone-artifact.conf (бэкап .pre-copyid-20260829T081500Z), daemon-reload + restart, принудительный прогон сверки ok:true, paidReady=True failures=[]. Проверено в живом процессе: /proc/<pid>/environ содержит ACTIVE_PASSIVE_COPY_ID=pi.
Соглашение имён копий pi/oracle — из src/lib/cron/__tests__/auth.test.ts:353,360. Для тумблера Pi<->Oracle (WEB-370/409/412/413) это ключевая переменная: на Oracle она должна быть oracle, и обе копии одновременно активными быть не должны.
ЧЕГО НЕ ХВАТАЛО В РАБОТЕ: механизм обязателен по умолчанию в проде, но не принёс с собой ни требования к runbook посадки, ни проверки «переменная задана». Заряжена волна LANDENV (очередь 439): страж новых обязательных серверных переменных при посадке + ожидание полного периода таймеров перед объявлением посадки зелёной.

[29.08 ⚠️ ВТОРАЯ НАХОДКА ПО ЭТОЙ РАБОТЕ — дефект самой аренды, вскрыт приёмкой ACC88ZERO]
Два ПРОЦЕССА с одинаковым ACTIVE_PASSIVE_COPY_ID не фехтуются между собой. defaultGuard (src/lib/activePassiveLease.ts:821) — отдельный singleton в каждом Node-процессе; SQL acquire (:191) разрешает обновить живую строку, если ownerId совпадает. Probe приёмки двумя ActivePassiveLeaseGuard с COPY_ID=pi и одним store: A ensure active=true gen=1; B ensure active=true gen=2; side effects: B gen=2, A gen=3; финальная строка ownerId=pi token=token-a gen=3 — ОБА execute() дошли до побочного эффекта.
Следствие: процесс, первым получивший новый token/generation, может быть вытеснен вторым, а второй снова захватывает ту же живую аренду как «тот же owner». Требование «два слота одного релиза — не две активные копии» нарушено. Тесты WEB-405 для РАЗНЫХ owner и structural route-fence проходят — именно два процесса одного COPY_ID не покрыты.
Значение для тумблера Pi<->Oracle (WEB-370/409/412/413): пока это не починено, гарантия «одна активная копия» держится только на том, что у Pi и Oracle РАЗНЫЕ copy id. Совпадение id (копипаста конфига при миграции) даст две активные копии молча.
Заряжен круг WEB88B (очередь 442) с требованием сделать handoff slot-aware, не сломав принятые тесты WEB-405.

[29.08] Дефект «два процесса с одинаковым copy id не фехтуются» ЗАКРЫТ работой WEB-88 круг 2 (коммит cf8ebf43, приёмка ACC88B GO): handoff сделан slot-aware, probe показывает side effects count=1 при двух active=true с разными slot. Для миграции Pi->Oracle это снимает риск «копипаста конфига даёт две активные копии», но требование РАЗНЫХ значений ACTIVE_PASSIVE_COPY_ID (pi / oracle) остаётся в силе как первая линия защиты.


[BOARDTRIAGE] Приёмщик: migration/release coordinator. ACC405F GO и WEB-88 slot-aware handoff приняты; перед переводом в done подтвердить в cutover runbook разные copy id pi/oracle.
Лента
2026-09-02T17:48:59.441Z · Fable
[A1 17:58 Фабл] Кит аренды 1280-web413leasekit сдан (ветка web413leasekit-1280, ops/web370/lease-kit/; отчёт A1 /home/ubuntu/waves/WEB413LEASEKIT-REPORT.md): вердикт NO-GO до решений §8. Главное: (1) на A1 установлен WEB405G flat-чекер (marker 8 строк, lease 10 строк, ttl 15 с, без run_nonce), а канон WEB409K/K7–K13 использует другой wire-формат (JSON receipts, generations) — смешивать нельзя; (2) authority по контракту = M1 (ноутбук): сон/ребут → боты fail-closed SAFE_OFF — не production; перенос на A2 или смена TTL требуют нового круга WEB-405; (3) семь owner-gates: bootstrap из пустого authority (none→a1 после fence Pi), глобальный scope vs bot-only, fence-контроллер с квитанцией, transport identity (pinned SSH, forced-command receiver — в ките есть), доступность M1, T0-блокеры кода (1279 закрыла), durability flat authority. Решение координатора (дефолтный GO owner-а 16:17): M1-как-authority НЕ принимается; authority → always-on A2 новым кругом дизайна + независимой приёмки — волна 1291-web405a2authority (A1): ADR, bootstrap none→a1, bot-lane fence с квитанцией, pinned SSH A2→A1, flock+журнал, локальная репетиция, процедура; TTL 15 не меняется. Боты остаются на Pi до посадки. Owner-у сообщено 17:58 (возражений ждём, иначе идём).
2026-09-02T17:51:50.588Z · Fable
[A1 18:08 Фабл] Owner 02.09 17:50 (voice): «арбитр переезжает на A2 как по уму; убираем зависимости от малинки на максималках; зависимости от ноутбуков тоже убирать; единственная допустимая — FaceTime (M1), когда снова поднимем». Принцип закреплён: authority WEB-405 = A2 (волна 1291-web405a2authority), M1 остаётся только для iMessage/FaceTime-лейна (WEB-411 M1-only).
2026-09-02T18:30:33.191Z · Fable
[A1 18:40 Фабл] Волна 1291-web405a2authority сдана: коммит 5ed3704e96, «READY FOR INDEPENDENT WEB-405 ACCEPTANCE; production не применялся» (ветка web405a2authority-1291; отчёт A1 /home/ubuntu/waves/WEB405A2AUTHORITY-REPORT.md; ADR ops/web370/authority-a2/DESIGN.md; локальная репетиция: lease ALLOW holder=a1 epoch=1 mode=ongoing, static unit poll-ит ongoing каждую секунду через BindsTo/PartOf). Дальше: независимая приёмка 1311-accweb405a2authority (A1: fault/concurrency harness как K11–K13 — wire-совместимость с установленным чекером, bootstrap none→a1 с квитанцией fence, kill -9/flock/power-loss, renewal/revoke/ребуты, pinned SSH, scope) + волна 1300-authoritypack (состояние authority в зашифрованный пакет на Storage Box + restore-authority — требование owner-а 18:08). Бандл: A1 /home/ubuntu/mirrors/lines/web405a2authority-1291.bundle; A2 ref web405a2authority-1291/head.
2026-09-02T19:22:08.710Z · Fable
[A1 19:55 Фабл] Приёмка 1311-accweb405a2authority = NO-GO (A1 /home/ubuntu/waves/ACCWEB405A2AUTHORITY-REPORT.md): независимый fault/concurrency harness подтвердил wire-совместимость с чекером, bootstrap+fence receipt, durability/flock, регресс; два пункта против production GO: (1) code-level — если bootstrap записал durable state и lease, но упал на публикации marker, повторный bootstrap запрещён и команды восстановления нет; (2) production-gates не закрыты (Pi apply с readback, независимый external fence, OOB A1 host-key fingerprint, фактический forced-command/sudoers, поведение при ребутах A2/A1, доказательство «app и телефония только на A1»). → волна 1326-web405a2authority2 (A1): транзакционная/восстанавливаемая публикация (journal PREPARED→COMMITTED→PUBLISHED, republish/resume, шимы kill-точек) + PRODUCTION-GATES.md с gates-check.sh и readback для координатора. Затем приёмка → установка на A2/A1 с прохождением gates → T1–T3 (после ротации токенов owner-ом).
2026-09-02T19:35:47.599Z · Fable
[A1 20:25 Фабл] Волна 1300-authoritypack сдана: коммит a2815b7967 (ветка authoritypack-1300 поверх 1291): состояние authority A2 (ключ, журнал/epoch, конфиг, SSH-pin) в зашифрованный пакет на Storage Box + restore-authority с тест-шимом + RESTORE.md. Отчёт: A1 /home/ubuntu/waves/AUTHORITYPACK-REPORT.md. Приниматься будет вместе с 1326-web405a2authority2 одной приёмкой (общая зона ops/web370/authority-a2).
2026-09-02T20:03:03.417Z · Fable
[A1 20:08 Фабл] Волна 1326-web405a2authority2 сдана: коммит 9f2be230e0 (круг после NO-GO 1311: восстановление после частичной публикации + производственные гейты кодом). Отчёт: A1 /home/ubuntu/waves/WEB405A2AUTHORITY2-REPORT.md. Приёмка обеих линий (1326 + 1300-authoritypack a2815b79) одной проверкой = волна 1333-accweb405authority3 (A1, sol, в очереди). При GO: install на A2 → dry publish → A1-чекер WEB405G → переключение lease с M1 на A2 → T1–T3 ботов после ротации токенов owner-ом.
2026-09-02T20:26:21.831Z · Fable
[A1 20:35 Фабл] Приёмка 1333-accweb405authority3: authoritypack (1300, a2815b79) = GO; authority2 (1326, 9f2be230) = NO-GO. A2-1: authority выдаёт flat lease/marker (format_version=1), а репозиторный K7 checker (ops/web370-k7/lease-holder-check.mjs) ждёт JSON — два контракта, DESIGN.md исключает K7. A2-2: gate-checker проверяет наличие строк grep-ом и принимает противоречивое evidence (7 случаев ALLOW: дубль активной записи в Pi-receipt, FENCED рядом с UNFENCED, адрес A1 только в комментарии, лишний authorized_key…). A2-3: shellcheck не чист. Третья находка одного класса по контракту → РЕШЕНИЕ: канон = flat-контракт живого A1-чекера (WEB405G); K7 JSON — либо проекция из того же источника при наличии потребителя, либо deprecated явно. Круг 3 = волна 1341-web405a2authority3 (A1, Luna xhigh, от 9f2be230): таблица потребителей, одна модель данных/две сериализации, fail-closed парсинг с единственностью, adversarial-матрица как тесты. Authoritypack принят — установка на A2 после GO authority3 (пакет и authority ставятся вместе).
2026-09-02T21:25:19.989Z · Fable
[A1 21:47 Фабл] Волна 1354-web405a2authority3 (перезапуск 1341 после капа) сдана: коммит d47a7c4809 (таблица потребителей, канон flat + K7 как проекция/deprecated, fail-closed структурный парсинг, adversarial-матрица как тесты, shellcheck). Отчёт: A1 /home/ubuntu/waves/WEB405A2AUTHORITY3-REPORT.md. Дальше: приёмка 1371-accweb405authority4 (A1, Sol high, в очереди) → при GO install на A2 + authoritypack → dry publish → A1-чекер → переключение lease.
2026-09-02T22:23:50.602Z · Fable
[A1 23:55 Фабл] Приёмка 1371-accweb405authority4: A2-1 (контракт flat + таблица потребителей), A2-2 (fail-closed структурный парсинг, adversarial 7/7 DENY), A2-3 (shellcheck) — PASS; блокер: authoritypack (a2815b79) и authority3 (d47a7c48) — sibling-коммиты от базы 5ed3704e, деревья несовместимы. Слияние = волна 1394-web405authoritymerge (A1, Luna high): pack поверх authority3, тесты обеих линий, restore-репетиция на шиме → одна приёмка → install на A2.
2026-09-02T23:21:00.552Z · Fable
[A1 03:15 Фабл] Волна 1394-web405authoritymerge сдана: коммит a166665946 (authoritypack поверх authority3, тесты обеих линий, restore-репетиция пакета на шиме). Отчёт: A1 /home/ubuntu/waves/WEB405AUTHORITYMERGE-REPORT.md. Приёмка 1411-accweb405authority5 (A1, Sol high, в очереди) → при GO: install на A2 → dry publish → A1-чекер → переключение lease с M1 на A2.
2026-09-03T00:15:55.324Z · Fable
[A1 07:15 Фабл] Приёмка 1411-accweb405authority5 = GO (Sol): слитая линия authority-a2 + authoritypack (a166665946) — контракт flat (канон живого A1-чекера), fail-closed структурный парсинг, adversarial 7/7 DENY, pack восстанавливается с продолжением epoch. Дальше по рецепту приёмки: install на A2 → dry publish → A1 WEB405G checker → переключение lease с M1 на A2 (арбитр уезжает с ноутбука на A2 — принцип owner-а «никаких зависимостей от ноутбуков»).
2026-09-03T00:17:32.683Z · Fable
[A1 07:30 Фабл] §1 PROCEDURE выполнен на A2: kit в /usr/local/libexec/web370/authority-a2 (11 файлов), ключи lease-signing + fence-coordinator (ed25519) в /etc/web370-authority/keys, authority.env (A1 internal 10.0.0.131 / public 129.213.25.105, hook hetzbk-authority-pack), units установлены, таймер renew disabled/inactive; hetzbk-authority-pack и hetzbk-restore-authority добавлены в /usr/local/libexec (полный install.sh hetzbk НЕ запускался, чтобы не откатить круг 4/6 тёплой копии). status: journal_seq=0, publication_phase=NONE. Следующие шаги §2–§5 (публичный материал на A1, Pi fence, bootstrap, переключение) — с owner-ом на связи.
2026-09-03T00:22:23.123Z · Fable
[A1 08:00 Фабл] §2 выполнен на A1 (install-renewed-lease.sh, /etc/web370/arbiter/m1-lease-ed25519.pub, sudoers web370-a2-renew, forced-command транспортный ключ A2), host-key A1 сверен двумя независимыми путями (ноут known_hosts + keyscan с A2: SHA256:3axGIUT5…) и запинён в /etc/web370-authority/ssh/known_hosts на A2 (internal + public). §3 (Pi fence = stop+mask bookbot/gptbot/signal-* на малинке) намеренно ОТЛОЖЕН до ротации токенов ботов (WEB-413, owner): фенс без готовых A1-ботов = простой ботов без пользы. §4–§5 сразу после фенса, одной сессией. Owner проинформирован 08:00; при «фенс сейчас» — делаю.
Воркер
не привязан — привязать: curl -X POST https://bugs.wool2.online/api/web/assign -H 'content-type: application/json' \ -d '{"issueId":"WEB-405","session":"<имя tmux-сессии>","host":"m4"}'
Обновлён
2026-08-30T13:37:34.987Z