Harden RF node control and agent updates
This commit is contained in:
223
docs/handoff/RF001_BOOTSTRAP_20260929_5_ATTEMPT.md
Normal file
223
docs/handoff/RF001_BOOTSTRAP_20260929_5_ATTEMPT.md
Normal file
@@ -0,0 +1,223 @@
|
||||
# RF001 bootstrap 2026.09.29.5
|
||||
|
||||
Дата: 29 сентября 2026 года.
|
||||
|
||||
## Production fix
|
||||
|
||||
Launcher теперь проверяет два допустимых варианта process identity:
|
||||
|
||||
- `DIRECT`: health PID совпадает с `Popen.pid`;
|
||||
- `WINDOWS_VENV_WRAPPER`: health PID принадлежит единственному непосредственному потомку проверенного venv wrapper.
|
||||
|
||||
В обоих вариантах проверяются живой процесс, PID, PPID, creation time, полный путь executable, точная командная строка, release ID, agent version, одноразовый launch nonce и `state=RUNNING`. Перед принятием health process identity проверяется второй раз. Failure cleanup завершает только доказанную lineage и не выбирает процессы по имени.
|
||||
|
||||
Health schema и `rf001_rx_http_agent.py` не изменялись.
|
||||
|
||||
Локальные проверки: `102 passed`. Python compile и PowerShell parse прошли. Ruff и Pyright отсутствуют, поэтому не запускались.
|
||||
|
||||
## Windows integration
|
||||
|
||||
Изолированный запуск на RX использовал настоящий Windows venv, исправленный production launcher, canonical release A и настоящий agent health writer. Scheduled Task и legacy agent не изменялись.
|
||||
|
||||
- `Popen.pid`: 11000;
|
||||
- health PID: 13248;
|
||||
- topology: wrapper 11000 -> direct child 13248;
|
||||
- production `start_release()`: PASS;
|
||||
- strict target identity: PASS;
|
||||
- cleanup: PASS;
|
||||
- orphan: 0;
|
||||
- HTTP task polling: false;
|
||||
- hardware accessed: false;
|
||||
- RF TX: 0.
|
||||
|
||||
Evidence:
|
||||
|
||||
```text
|
||||
C:\Users\Professional\Downloads\SDR_Rover_Diagnostics\launcher_identity_fix_20260929T135321Z\evidence\diagnostic_summary.json
|
||||
```
|
||||
|
||||
## Bootstrap
|
||||
|
||||
- ID: `rf001-bootstrap-2026.09.29.5`;
|
||||
- SHA256: `4833cd22f3f1bd41ae1a847c66f258ccf9d4c6fb4eec5feb2d36e688324c6554`;
|
||||
- размер: 1 506 140 байт;
|
||||
- HMAC: PASS;
|
||||
- manifest-файлы: 17, расхождений 0;
|
||||
- release A: 10 файлов из 10 побайтно совпадают с `.4`, включая `READY.json`;
|
||||
- signed `agent_release_bootstrap_id`: `rf001-bootstrap-2026.09.29.4`;
|
||||
- `.1`, `.2`, `.3` и `.4` не изменялись;
|
||||
- SOURCE/RX SHA256: MATCH.
|
||||
|
||||
## Единственная попытка установки
|
||||
|
||||
`INSTALL_RX_AGENT.cmd` был запущен один раз. Результат: `exit code 1`, fail-closed.
|
||||
|
||||
Фактическая ошибка:
|
||||
|
||||
```text
|
||||
Unexpected file in the bootstrap package: install.stderr.txt
|
||||
```
|
||||
|
||||
Причина доказана. Оркестратор заранее создал `install.stdout.txt` и `install.stderr.txt` внутри распакованного bootstrap-каталога, чтобы перенаправить вывод `cmd.exe`. Installer затем проверил строгий allowlist всех файлов каталога и отверг созданный оркестратором `install.stderr.txt` как посторонний файл. Ошибка возникла до копирования launcher, изменения Scheduled Task и остановки legacy agent.
|
||||
|
||||
Это не ошибка HMAC, manifest, immutable release A или process identity fix. Bootstrap `.5` остался подписанным и прошёл preflight. Повторная установка запрещена текущим STOP-условием. `.6` не создавался.
|
||||
|
||||
Для следующей отдельно разрешённой попытки вывод установщика должен сохраняться вне распакованного bootstrap-каталога, а запуск должен использовать новый чистый каталог распаковки. Текущий загрязнённый каталог не следует использовать повторно.
|
||||
|
||||
## Безопасное состояние после отказа
|
||||
|
||||
- Scheduled Task: `Running`, прежнее legacy action;
|
||||
- active agent: `2026.09.25.1`;
|
||||
- MAIN heartbeat: свежий;
|
||||
- unfinished tasks: 0;
|
||||
- installed launcher SHA256: `fb99882351ee96802d1edd9de947634f2a559e849399c8153a1290688030ed79`, прежний `.4` launcher;
|
||||
- production agent topology: PID 7980 -> PID 17568;
|
||||
- `hackrf_transfer`: 0;
|
||||
- RX capture: 0;
|
||||
- B update: NOT_RUN;
|
||||
- staircase search: NOT_RUN;
|
||||
- new RX: 0;
|
||||
- new RF TX: 0.
|
||||
|
||||
## Отдельно разрешённая попытка 2
|
||||
|
||||
После нового разрешения тот же неизменный ZIP `.5` повторно проверен на MAIN и
|
||||
RX. SHA256 в обоих случаях:
|
||||
|
||||
```text
|
||||
4833cd22f3f1bd41ae1a847c66f258ccf9d4c6fb4eec5feb2d36e688324c6554
|
||||
```
|
||||
|
||||
Первая распаковка с `install.stdout.txt` и `install.stderr.txt` сохранена без
|
||||
изменений: 21 файл до и после второй попытки. Для второй попытки создан новый
|
||||
каталог:
|
||||
|
||||
```text
|
||||
C:\Users\Professional\Downloads\SDR_Rover_Bootstrap\rf001-bootstrap-2026.09.29.5_attempt2_clean
|
||||
```
|
||||
|
||||
До запуска установщика получены следующие результаты:
|
||||
|
||||
- HMAC: PASS;
|
||||
- manifest: 17/17;
|
||||
- файлов в пакете с двумя файлами аутентификации: 19/19;
|
||||
- unexpected: 0;
|
||||
- missing: 0;
|
||||
- mismatch: 0;
|
||||
- release A: 10/10;
|
||||
- `INSTALL_RX_AGENT.cmd`: присутствует;
|
||||
- canonical release A: 10/10, расхождений 0;
|
||||
- active task: отсутствует;
|
||||
- unfinished tasks: 0;
|
||||
- unfinished hardware tasks: 0;
|
||||
- `hackrf_transfer`: 0;
|
||||
- RX capture process: 0.
|
||||
|
||||
Все runtime-файлы второй попытки сохранены вне bootstrap-каталога:
|
||||
|
||||
```text
|
||||
C:\Users\Professional\AppData\Local\SDR_Rover_RX_Agent\install_logs\bootstrap_2026.09.29.5_attempt2_20260929T150351603Z
|
||||
```
|
||||
|
||||
Установщик запущен ровно один раз из чистого каталога с явным рабочим
|
||||
каталогом. Результат: `exit code 0`, stderr пуст. Дерево пакета сразу после
|
||||
старта и после завершения побайтно не изменилось; timestamps также совпали.
|
||||
Карантин из 11 файлов и первая загрязнённая распаковка не изменились.
|
||||
|
||||
После установки Scheduled Task запускает versioned launcher. Release A
|
||||
`2026.09.29.1` сообщил свежий MAIN heartbeat, launcher status перешёл в
|
||||
`RUNNING / TARGET_HEALTHY`, active task отсутствовал. Legacy-процессов: 0.
|
||||
Наблюдаемая цепочка Windows состояла из launcher wrapper, его Python-потомка,
|
||||
agent wrapper и единственного agent child с одним launch nonce. Это одна
|
||||
production lineage, а не два экземпляра агента.
|
||||
|
||||
## Обновление A -> B
|
||||
|
||||
Пакет `rf001-agent-2026.09.29.2.zip` проверен до постановки задачи:
|
||||
|
||||
- SHA256: `225a032a927b672343f4ccf7a0ef0662f462e1ec45782c0437ba50ab73bac203`;
|
||||
- release ID: `rf001-agent-2026.09.29.2`;
|
||||
- agent version: `2026.09.29.2`;
|
||||
- внутренний manifest: 9 файлов, расхождений 0;
|
||||
- зарегистрированный HMAC: PASS.
|
||||
|
||||
Обновление выполнено только через подписанный HTTP-канал:
|
||||
|
||||
```text
|
||||
UPDATE_20260929T151002Z_8B82A943
|
||||
```
|
||||
|
||||
Задача завершилась со статусом `COMPLETE`, self-test вернул 0. Launcher
|
||||
переключился на B, active release и свежий MAIN heartbeat показывают
|
||||
`2026.09.29.2`, launcher status: `RUNNING / TARGET_HEALTHY`. Rollback не
|
||||
использовался. SCP/SSH-установка B не выполнялась.
|
||||
|
||||
## Полный поиск лестницы
|
||||
|
||||
После подтверждения B поставлена одна задача:
|
||||
|
||||
```text
|
||||
STAIRCASE_20260929T151048Z_EF3AA9DE
|
||||
```
|
||||
|
||||
Итог:
|
||||
|
||||
- session: `RF001A_20260925T125829Z_227EADB4`;
|
||||
- coverage: 0...2 400 000 000 комплексных отсчётов, 300,0 с;
|
||||
- RX SHA256: подтверждён;
|
||||
- reference SHA256: подтверждён;
|
||||
- result: `NOT_DETECTED`;
|
||||
- лучший кандидат: sample 474 212 320, 59,27654 с;
|
||||
- CFO: -3,0 Гц;
|
||||
- candidate score: 0,009649134828942169;
|
||||
- contrast to background p99: 4,052909297771804 дБ, ниже порога;
|
||||
- spectral contrast: 3,6405801238037765 дБ;
|
||||
- step pattern: FAIL;
|
||||
- наблюдаемые ступени: +2,879031, -2,205885 и +15,541302 дБ при ожидаемых
|
||||
+6,0 дБ;
|
||||
- maximum absolute step error: 9,54130207648743 дБ;
|
||||
- analysis time: 263,3271906 с;
|
||||
- peak additional memory: 496 549 888 байт;
|
||||
- peak process memory: 536 199 168 байт;
|
||||
- hardware accessed: false;
|
||||
- RF TX: 0.
|
||||
|
||||
Причины вердикта: корреляция ниже порога, контраст пика к фону ниже порога,
|
||||
структура ступеней или спектральное подтверждение не прошли. Пороги и алгоритм
|
||||
не менялись, повтор задачи не выполнялся.
|
||||
|
||||
Отчёт на RX:
|
||||
|
||||
```text
|
||||
C:\Users\Professional\Documents\SDR_Rover_Runtime\rx_capture\RF001A_20260925T125829Z_227EADB4\staircase_search_report.json
|
||||
SHA256=b34ad21ae70a4290a0394a3ee3317bdd560e43dbe266aa3d7e1ce1c967c11dd7
|
||||
```
|
||||
|
||||
Результат принят MAIN и сохранён в
|
||||
`.local/rf001_http_server_state.json` под указанным task ID.
|
||||
|
||||
## Исправление MAIN-оркестрации
|
||||
|
||||
Подписанный `.5` не изменялся. На MAIN добавлена отдельная утилита
|
||||
`tools/rf001_bootstrap_install_orchestrator.py`. Она до запуска проверяет HMAC,
|
||||
manifest, SHA256 и точный allowlist, запрещает каталог доказательств внутри
|
||||
package tree, перенаправляет stdout/stderr только наружу и сравнивает снимки
|
||||
пакета сразу после старта и после завершения.
|
||||
|
||||
Регрессии в `tests/test_rf001_bootstrap_install_orchestrator.py` проверяют:
|
||||
|
||||
- чистый пакет до запуска;
|
||||
- внешние stdout/stderr;
|
||||
- неизменность package tree;
|
||||
- успешный точный allowlist;
|
||||
- fail-closed для пакета с посторонним файлом;
|
||||
- отказ от evidence-каталога внутри пакета.
|
||||
|
||||
Итоговый RF001-набор: `122 passed`. Полный набор репозитория: `1296 passed`,
|
||||
`4 failed`, `2 skipped`. Четыре сбоя находятся вне изменённого контура: два
|
||||
старых теста `capture_process_runner.ps1` получили `sha256=null`, один тест
|
||||
требует отсутствующий `data/raw/lab064/tx_metadata.json`, ещё один требует
|
||||
недоступный Numba backend. Новая утилита компилируется; её отдельные регрессии:
|
||||
`4 passed`.
|
||||
|
||||
Новый bootstrap `.6` для этого исправления не требуется.
|
||||
Reference in New Issue
Block a user