Harden RF node control and agent updates

This commit is contained in:
LittleSam129
2026-09-30 11:42:19 +03:00
parent a94f2db4ee
commit 0d6fff224e
34 changed files with 14010 additions and 0 deletions

View 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` для этого исправления не требуется.