Files
NODEDC_MISSION_CORE/docs/audits/2026-09-05-rerun-customization-inventory.md
T
DCCONSTRUCTIONS e515ab1b8c feat(planning): consolidate recorded-route localization and spatial scene
Preserve the completed teach-and-repeat laboratory stage: reference preparation, cascaded acquisition, local tracking and recovery, recording lifecycle, replay qualification, and persistent Rerun scene controls. Document the open grid-picking regression and Rerun upgrade contract. No autonomous driving or loop-closure optimization is claimed.
2026-09-21 08:47:19 +03:00

38 KiB
Raw Blame History

Полная карта интеграции и кастомизации Rerun

Дополнение от 21 сентября: профиль планирования, сохранение камеры, окна инструментов и открытая регрессия выделения сетки. Оно дополняет, а не заменяет исторический аудит ниже.

Снимок кода b2a1b23131642ac496829e467c20c8c069915be9, 2026-09-05. Ревизия подготовлена для карточки MISSION CORE #74 «Additional Core · Переносимая кастомизация Rerun». Изменения в runtime в рамках аудита не выполнялись.

Зафиксированное состояние · 5 сентября 2026

Репозиторий NODEDC_MISSION_CORE_m5_observatory. Принятый код: b2a1b23131. Ветка codex/m5-1-observatory перенесена в main fast-forward; прежний main 7fba39a629 является предком. main опубликован без переписывания истории. Остальные worktree сохранены.

Это аудит фактической реализации и карта переноса, а не обновление Rerun или новый рефакторинг. Точка отсчёта — официальный Rerun 0.36.3. Исторические формулировки ADR 0045 и карточки #66, не совпадающие с перечисленными ниже файлами, не следует считать описанием текущего кода.

Версионируемый снимок: docs/audits/2026-09-05-rerun-customization-inventory.md; машинные свидетельства происхождения: docs/audits/2026-09-05-rerun-upstream-evidence.json. Карточка #74 — полный рабочий реестр; #66 — канон интеграции.

Официальное ядро и проверка происхождения

Активные версии строго закреплены: @rerun-io/web-viewer=0.36.3 в apps/control-station/package.json и package-lock.json; rerun-sdk==0.36.3 в pyproject.toml и uv.lock. Upstream tag 0.36.3 и npm gitHead: 6ded109d33c549e98185f7c95fa8009d44e4adef.

Заново скачан официальный npm-архив; SHA-512 совпадает с registry и lockfile. Все 12 опубликованных файлов побайтно совпадают с установленным пакетом. SHA-256 re_viewer_bg.wasm: 02d6d9c3a569d3faceb01cf89104342d970fc85e7c31a08dedd357b6c7104d2f. Тот же хеш у WASM в apps/control-station/dist/assets/re_viewer_bg-BO4B44yr.wasm. SHA-256 re_viewer.js: d2a94836dd0e6de40538c4d657cfb423b1803e354e6ee0cd550735eb5aaab09b.

Заново скачан официальный macOS ARM64 wheel Python SDK: rerun_sdk-0.36.3-cp310-abi3-macosx_11_0_arm64.whl. SHA-256 804067d6e71747f8461104988be82543b318b583a2837935558a5e79a5e9befd совпал с PyPI и uv.lock. Все 507 файлов пакетов rerun_sdk/ и rerun_bindings/ совпали с установленной .venv.

Активного postinstall-патча и импорта архивного vendor нет. vite.config.ts использует стандартный wasm plugin, target esnext, отдельный rerun-runtime.html и исключение Web Viewer из optimizeDeps ради корректного относительного URL WASM. Активный WASM и SDK не модифицированы. Это не означает отсутствия зависимостей надстроек от внутренних API: они перечислены отдельно.

Граница и владельцы надстроек

Rerun владеет визуализацией, native store, декодированием и камерой; Mission Core владеет источниками, конфигурацией, адаптерами, внешними контролами и сохранённым display profile. Ни viewer, ни его cache не являются владельцем raw evidence, AI worker или управления оборудованием.

Основной компонент: apps/control-station/src/components/RerunViewport.tsx. Recorded-путь запускает обычный WebViewer внутри одноразового same-origin iframe; live-путь импортирует официальный WebViewer напрямую. Существует ровно один native renderer и clock на смонтированный recorded viewer, а не отдельный экземпляр на каждую половину LAB.

Действующие файлы в apps/control-station/src/components/rerun/: isolatedRerunEntry.ts, isolatedRerunHost.ts, isolatedRerunInput.ts, recordedRerunProtocol.ts, recordedRerunOwner.ts, recordedRerunFacade.ts, recordedRerunCameraJournal.ts. Прежние названия isolatedRerunOwner/rerunFacade/rerunProtocol в этой карточке были неточными.

Публичный JS-контракт: start(rrd,parent,options), stop, ready, on, open, close, open_channel, override_panel_state; get_active_recording_id/get_active_timeline/get_current_time/get_playing/get_time_range; set_active_timeline/set_current_time/set_playing. configure/get-camera-eye — методы нашей границы, не официальный API чтения native камеры.

Изолированный runtime, протокол и освобождение ресурсов

rerun-runtime.html и isolatedRerunEntry.ts создают runtime; isolatedRerunHost.ts владеет iframe, handshake версии 2 и таймаутом 30 секунд. recordedRerunProtocol.ts задаёт команды/события; recordedRerunFacade.ts передаёт primitive JSON и синхронные Uint8Array; recordedRerunOwner.ts владеет SDK, каналами, подписками и журналом камеры внутри iframe.

SDK handles, DOM, native closures и startup promise не выдаются родителю. Dispose отклоняет родительское ожидание, закрывает каждый канал независимо от ошибок других, отписывает события и удаляет iframe. Завершившийся после dispose поздний SDK start останавливается повторно. Это прикладная изоляция жизненного цикла, не sandbox безопасности.

isolatedRerunInput.ts сейчас ретранслирует только Escape. Старое утверждение ADR о передаче pointer events родителю устарело: native gestures остаются в iframe, журнал навигации тоже находится там. Pagehide/pageshow и stale generation управляются RerunViewport и core/observation/recordedRerunLifecycle.ts.

При обновлении проверять start/stop, закрытие до загрузки iframe, закрытие во время SDK start, ошибки каналов, late callbacks, восстановление страницы. Снятие DOM само по себе не доказывает освобождение памяти: повторять последовательные open/close и измерять процесс без принудительного GC.

Источники, admission и единые часы

Контракты: core/observation/viewerProfile.ts, recordedObservationSources.ts, recordedSessionAdmission.ts, useRecordedSessionAdmission.ts и recordedRerunLifecycle.ts; операторский playback — RerunViewport.tsx и ObservationTimeline.tsx.

Live использует stream_time и отдельную acquisition identity. Recorded использует session_time, immutable source URL/generation, согласованные application_id/recording_id, SHA-256 и byte length. Native receiver читает URL RRD; слой приложения не собирает основной архив в постоянно растущий JS Blob. Blueprint и необязательные perception/color sidecars входят в тот же store и clock.

Различать три пути: live → прямой upstream; Saved Sessions/Data → свой admission и внешняя RecordedFmp4Player.tsx для записанного видео; canonical LAB → merged RRD с native AssetVideo/VideoFrameReference внутри изолированного upstream viewer. Старый лабораторный fMP4/Three.js путь сохранён только для явно выбранного legacy comparison.

CanonicalResultRerunReplay.tsx сейчас задаёт presentationGate="ready": canonical LAB может ожидать полной native готовности. Прогрессивная политика Saved Sessions не доказывает быстрый cold open LAB. Подготовка merged RRD, загрузка/декодирование и inference модели — разные измерения. Аудит не подтверждает real-time inference.

Границы текущей реализации: blueprint transport до 1 MiB, необязательный perception payload до 512 MiB; canonical producer source/overlay/replay до 768/256/1024 MiB. Это transport/resource ограничения, не лимиты точного ввода накопления.

Blueprint: слои, идентичность и внутренние Python API

Владелец — src/k1link/viewer/recorded.py; HTTP-контракт — src/k1link/web/session_api.py, POST /api/v1/observation-sessions/{session_id}/blueprint.rrd.

Штатные Spatial3DView(/world), Spatial2DView(/perception/camera), metrics; unified LAB использует Horizontal(camera,spatial) с column_shares. Обычные режимы spatial/perception/perception3d/metrics используют устойчивые view/container UUID; owner token входит в uuid5, reset generation 0/1 и mode-specific Tabs identity отделяют намеренный reset/смену режима от обновления слоёв. auto_layout и auto_views выключены, native TimePanel скрыт, общий timeline session_time.

EntityBehavior меняет видимость /world/points, /world/trajectory, /world/costmap, perception-слоёв и /perception/camera/{image,detections,segmentation/city,segmentation/vegetation}. VisibleTimeRanges применяет накопление к точкам/траектории; динамическая perception остаётся latest-at без искусственных шлейфов. Размер точек — штатный Points3D visualizer override. План меняет eye, не геометрию данных.

Версионно чувствительная часть: bindings.new_blueprint, RecordingStream._from_native, Blueprint._log_to_stream, bindings.send_blueprint, memory_recording().storage, binary_stream/to_native. Это прямое использование внутренних/низкоуровневых Python hooks, несмотря на неизменённый SDK. Один source blueprint stream живёт на владельца; обновления добавляются последовательно, активная копия повторно активируется.

Обычные переключения слоёв не записывают eye. 3D/план/reset применяют явные пресеты; FOLLOW имеет отдельный протокол восстановления. При обновлении надо проверять семантику active blueprint clone и сохранение runtime eye, а не только то, что Python-функции существуют.

Blueprint lease, bounds и цветовые cache

src/k1link/viewer/recorded_blueprint_lifecycle.py: ключ (application_id, recording_id, blueprint_session_id), idle TTL 300 секунд, reaper 30 секунд, максимум 32 entries, release tombstones до 4096. Renew открытого владельца каждые 30 секунд; render/release сериализованы; активный render не обрывается по TTL. Есть shutdown cleanup. Durable записи при release не удаляются.

Frontend core/observation/recordedBlueprintLifecycle.ts отправляет renew/release в /blueprint-lifecycle; при закрытии bounded keepalive с таймаутом 5 секунд. Эта граница относится к ephemeral viewer resources, не к остановке вычислений.

recorded_camera_bounds.py использует bindings.RrdReaderInternal и названия Arrow-компонентов. LRU на 8 поколений keyed by path/size/mtime хранит scene bounds и индекс translation /world/sensor_pose на session_time. RRD не перечитывается при каждом переключении. Максимальный zoom-out выводится из диагонали сцены и upstream factor 5.

device_plugins/xgrids_k1/recorded_point_colors.py пишет цветовой RRD override в тот же recording, без дублирования геометрии/траектории/видео/AI. Режимы intensity/height/distance/rgb/class; палитры turbo/viridis/plasma/grayscale/custom. Cache индекса по умолчанию 384 MiB, payload 192 MiB; отдельный payload ограничен 256 MiB. Правила fallback/метаданных принадлежат этому адаптеру.

RrdReaderInternal, Arrow component schema, правила слияния override и memory ownership — обязательные точки проверки при смене SDK.

Навигация и FOLLOW: фактический механизм

recordedRerunCameraJournal.ts реконструирует position/lookTarget/eyeUp по pointer orbit/pan/roll и wheel. Публичного WebViewer API для чтения текущего native eye в 0.36.3 нет: журнал не является снимком из ядра.

Скопирована модель поведения из upstream eye.rs: rotation 0.004, pan 0.001 × radius, wheel exp(delta/200), отдельный pinch/ctrl divisor 100, line scroll factor 8, near radius 0.02, ограничение pitch 0.99 × π/2, scene-derived max radius. Эти численные и событийные правила — контракт переноса даже без vendor patch.

Коммит b2a1b23: при FOLLOW off session_api.py добавляет к journal offset текущий /world/sensor_pose и записывает мировую eye-позу; камера остаётся на месте, сканер продолжает движение. При FOLLOW on сначала устанавливается tracking, затем после двух animation frames восстанавливаются направление/up/радиус относительно текущего пивота. Это компенсирует upstream auto-fit нового tracking entity. Обычные TGS/DDRNet/рамки не должны писать eye или пересоздавать viewer.

Проверенный сценарий и результаты предыдущей browser acceptance сохранены отдельным историческим блоком. Не распространять это доказательство на все native gestures: WASD, double-click/picking fit, inertia и другие неотражённые журналом действия могут расходиться с восстановленной позой. Полная замена журнала официальным pose API — возможное последующее улучшение, если такой API появится; в этой ревизии не выполнялась.

Точная исходная опора: https://github.com/rerun-io/rerun/blob/0.36.3/crates/viewer/re_view_spatial/src/eye.rs .

Viewport UI, разделитель и native chrome

apps/control-station/src/components/laboratory/CanonicalRecordedLabReplay.tsx размещает внешний @nodedc/ui-react SplitPane над одним native viewer. Контролы принадлежат секциям overlay; separator меняет controlled primarySize. CanonicalResultRerunReplay.tsx передаёт размер в native Horizontal column_shares с debounce 75 ms. Это управляемая внешняя компоновка плюс синхронизация blueprint, а не отслеживание перетаскивания native Rerun divider.

У canonical result начальное соотношение 46/54. Внешний SplitPane ограничивает обе стороны минимумом 24%, backend share принимает 10–90%. Если источники дают только camera или spatial, выбирается одно окно. Панель каждого окна находится сверху слева в его границах; pointer-events разрешены для контролов/разделителя, прозрачная остальная область не должна блокировать native input.

styles/m4-replay-threat.css: flex-wrap и display:contents обеспечивают перенос отдельных групп/контролов по доступной ширине; под глобальные refresh/fullscreen резервируется 7rem справа. 3D/план и FOLLOW остаются в общей адаптивной строке spatial-панели. Общие действия принадлежат LaboratoryEvidenceViewer.tsx. Refresh здесь — явный сброс положения видов через reset generation; не произвольная перезагрузка данных.

styles/spatial.css обрезает native chrome сверху на 72px (три ряда по 24px). Это чувствительно к версии native UI и масштабу, хоть WASM не патчится. Старый фиксированный camera interaction lock не включён в canonical profile.

Сегодня это реализация camera + spatial/single pane с фиксированными видами, а не готовый универсальный редактор дерева из 50 viewport. Расширение дерева компоновки и проверка resource budget для десятков окон остаются отдельной задачей.

Конфигурация, онтология и точный смысл кнопок

Проекция модулей и viewer layers: src/k1link/observatory/domain_ontology.py, portable_setup_projection.py, frontend core/observatory и CanonicalResultRerunReplay.tsx. Сохранённые moduleIds/viewerLayers определяют доступные панели и кнопки; отсутствующие возможности не должны появляться из текста заголовка. Точные конфигурационные значения и display profile отделены от immutable результатов расчёта.

КАМЕРА управляет только /perception/camera/image; рамки и segmentation независимы от фона камеры. РАМКИ доступны по наличию detections. EOMT → segmentation/city, DDRNET → segmentation/vegetation. Если оба semantic toggles включены, текущий selector отдаёт приоритет EoMT; это не одновременная визуализация двух масок.

TGS → /world/costmap. ИСХ. ТОЧКИ и ЛОК. SLAM используют одно sealed /world/points: showPoints = source || localSLAM; SLAM дополнительно включает trajectory и выбранное накопление, source-only использует 0. Это не два разных набора математических/декоративных точек. Настройки не меняют расчётные raw данные.

3D/ПЛАН — явные camera presets; СЛЕДОВАТЬ — tracking текущего sensor_pose с восстановлением eye. Профиль отсутствующего слоя не должен запускать inference или создавать имитацию evidence.

Display profile LAB: хранение и применяемые поля

Frontend: CanonicalResultRerunReplay.tsx, core/observatory/labViewProfile.ts. Backend: src/k1link/observatory/lab_view_profiles.py, web/modular_observatory_api.py. Профиль привязан к result_id, хранится отдельно от immutable calculation config; запись файла через temp/fsync/atomic replace.

Изменения отображаются сразу; localStorage хранит локальный draft, при открытии читается серверный профиль. Закрытие окна настроек отправляет PUT. Окно закрывается и при ошибке; compact error toast сообщает, что серверная запись не подтверждена. Успех в памяти или localStorage не равен подтверждённому сохранению на сервере.

Поля: point_size, accumulation_seconds, color_mode, palette, show_grid, show_labels, show_camera_frustums. Накопление: slider 0–500 s, точный ввод конечного значения ≥0 без верхнего product cap. Point size: slider 0.110 px, точный ввод ≥0.1 без верхнего cap. Нормализация: накопление до целой секунды, размер до одного десятичного знака; отрицательные/NaN/Infinity недопустимы.

Размер, диапазон накопления, цвет/палитра и grid подключены к viewer. show_labels и show_camera_frustums сохраняются и доступны в UI, но не входят в blueprint request/recorded.py текущего canonical LAB: визуальное применение этих двух настроек НЕ подтверждено и не реализовано в этом пути.

Layer toggles, FOLLOW, camera eye и split ratio не записываются в этот durable display profile; это состояние текущего просмотра. Проверка cache-clear должна касаться серверно сохранённых полей, а не обещать сохранение всего состояния viewport.

RRD producers и данные для официального viewer

Данные — отдельная часть карты совместимости, не патч ядра. src/k1link/device_plugins/xgrids_k1/rrd_export.py экспортирует базовые points/pose/trajectory; viewer/rerun_bridge.py обслуживает live SDK/GRPC, RH_Z_UP и stream_time. calibrated_overlay.py добавляет калиброванную evidence projection.

src/k1link/laboratory/canonical_rerun_overlay.py формирует совместимые AssetVideo, VideoFrameReference, EncodedImage masks, Boxes2D и Clear. Renderer identity: upstream-rerun-0.36.3-encoded-optimized-v6, replay identity: upstream-rerun-0.36.3-canonical-replay-v1. Источник store identity читается через RrdReaderInternal. Видео приводится ffmpeg к native-compatible H.264; immutable lineage/digest связывают cache с исходной записью и renderer.

CLI Rerun применяется для merge/optimize. Профиль оптимизации overlay: object-store, max-size 4MiB, max-rows 512, num-pass 20. Поведение CLI, поддержка codecs/components, store identity и порядок latest-at/Clear должны повторно проверяться при обновлении; менять имя renderer без повторной materialization недостаточно.

Другие владельцы Rerun evidence: observatory/portable_replay.py, portable_semantic_replay.py, portable_object_replay.py, portable_tgs_replay.py; sessions/lab_cache.py и canonical_lab_spatial.py; compute/results.py, integrated_perception.py, fusion_epoch.py. Их логирование надо сверять с SDK при обновлении даже если viewport UI не менялся.

application_id, recording_id, временная шкала и entity paths обязаны совпадать у base/sidecar. Старые sealed results нельзя переписывать ради смены viewer: производные cache перестраиваются с новой renderer identity и проверкой lineage.

Архивный форк 0.34.1 · сохранён, не активен

Полный старый набор находится в apps/control-station/vendor/rerun-web-viewer-0.34.1/: BUILD_INFO.md, NODEDC_ZOOM_TO_CURSOR.patch, re_viewer.nodedc.js, re_viewer_bg.nodedc.wasm. Upstream commit 4efb18f17f6f0e41985cda99a2bdcd012febc8d5; история до миграции помечена baseline/custom-legacy-before-canonical-rerun-2026-08-30.

Rust patch менял eye.rs и ui_3d.rs: zoom вокруг точки под курсором/focus plane, orbit вокруг picked point, dolly после near radius 0.02, scene-scale floor скорости, persistent follow при orbit/zoom, восстановление последнего rendered eye после blueprint activation. Эти возможности не следует автоматически приписывать текущему upstream 0.36.3.

scripts/patch-rerun-web-viewer.mjs также содержал ready/handle guard watchdog и общий keyup listener; scripts/transform-rerun-web-viewer-glue.mjs — per-instance WASM glue, teardown/finalization/destructor guards. Installer проверяет версию строго 0.34.1 и известные хеши. Он больше не вызывается postinstall; импортов архивной пары в активной сборке нет. Не запускать его для 0.36.3.

Воспроизводимость старой сборки описана BUILD_INFO.md: Rust 1.92.0, Binaryen 117, rust:1.92-bookworm с digest e90e846de4124376164ddfbaab4b0774c7bdeef5e738866295e5a90a34a307a2, upstream builder и transform script. Исторические Rust tests: 10 passed, не повторялись в этом аудите.

Архивный WASM SHA-256 ffe7543d28bb3394f289f6299de43d038767eef83d781c2b7f8f5683308a0469; glue SHA-256 0f7b76c9f24cbd8437021b5d37499894aeadc586183e422ebc82ef556d7b8339. Этот архив — свидетельство прежних изменений, не инструкция автоматически возвращать их при следующем обновлении.

Что остаётся чувствительным и что не подтверждено

  1. SDK не изменён, но blueprint transport и чтение RRD зависят от private bindings. Универсальная переносимость без адаптации не доказана.
  2. Журнал камеры повторяет часть native navigation. Полная идентичность для всех способов навигации не доказана; текущая FOLLOW-компенсация зависит от auto-fit и порядка кадров.
  3. Native chrome crop 72px и синхронизация external/native layout зависят от UI и blueprint поведения Rerun.
  4. show_labels/show_camera_frustums сохраняются без применения в canonical LAB; два semantic toggles не дают две одновременно показанные маски.
  5. Source/SLAM — два способа представления одной геометрии. Раздельные raw/math и decorative geometry здесь не реализованы.
  6. Конструктор произвольного числа viewport и работа 50 окон не реализованы/не квалифицированы. Лимит blueprint owners 32 нельзя трактовать как поддержку 50 viewers.
  7. Cold materialization, полная готовность LAB и освобождение memory требуют самостоятельных измерений. Быстрое переключение слоёв не доказывает real-time inference.

Эта ревизия фиксирует ограничения, не устраняет их рискованным изменением принятого viewer. При следующем обновлении сначала квалифицировать новые публичные API и затем отдельно решать, какие private adapters можно упростить.

Свидетельства этой ревизии и воспроизведение

5 сентября 2026 повторно сверены upstream npm/PyPI archive hashes, installed files и built WASM. Матрица файлов/методов составлена по коду b2a1b23, а camera/blueprint зависимости — по исходникам официального тега 0.36.3. Исходные хеши и archive URLs записаны в JSON-свидетельстве.

Повторно запущено: node --test test/rerunWebViewerVendor.test.mjs test/recordedRerunCameraJournal.test.mjs test/recordedViewerResourceLifecycle.test.mjs из apps/control-station — 16 passed. Из корня: .venv/bin/python -m pytest -q tests/test_recorded_blueprint_lifecycle.py tests/test_recorded_camera_bounds.py tests/test_observatory_lab_view_profiles.py — 12 passed.

Полная предыдущая проверка принятого FOLLOW-кода: 759 frontend tests, 65 backend tests, typecheck/build/Ruff и ручной browser-сценарий указаны в историческом блоке; в этом документальном аудите полные suites и browser-сценарий заново не выполнялись. Runtime-код не изменён.

Для независимого повторения происхождения: получить архив точной версии из npm registry/PyPI; сверить digest с lockfile и registry; сравнить каждый файл npm package с node_modules, файлы rerun_sdk/rerun_bindings из wheel с .venv; отдельно SHA-256 установленного и dist WASM. Не считать один version string доказательством неизменённого пакета.

Официальные исходники: https://github.com/rerun-io/rerun/blob/0.36.3/rerun_js/web-viewer/index.ts ; https://github.com/rerun-io/rerun/blob/0.36.3/crates/viewer/re_view_spatial/src/eye.rs ; https://github.com/rerun-io/rerun/blob/0.36.3/rerun_py/rerun_sdk/rerun/blueprint/api.py .

Обязательная проверка при следующем обновлении

  • Создать отдельную ветку от зафиксированного main; записать старую/новую пару SDK+Web Viewer, upstream commit, lockfile и archive hashes. Не запускать installer архивного форка.
  • Сверить публичный WebViewer API, загрузку Vite/WASM, iframe handshake/facade и события; проверить stop, late start и закрытие всех каналов.
  • Сверить private blueprint hooks, RrdReaderInternal/Arrow schema, active clone semantics, UUID/reset identity; отдельно подтвердить lifecycle renew/release/TTL.
  • Сопоставить eye.rs/ui_3d.rs: orbit/pan/roll/wheel/pinch, min/max radius, tracking auto-fit; повторить FOLLOW off/static/on при текущем pivot с тем же масштабом.
  • Проверить native chrome crop и layout на обычном/полном экране; подвигать разделитель в обе стороны, проверить локальные панели и перенос без перекрытия refresh/fullscreen.
  • Открыть полную LAB, DDRNet и TRAVEL TGS; отдельно camera-only/spatial-only. Проверить каждую доступную кнопку, raw camera off при работающих masks/boxes и все слои off.
  • При play и pause переключить TGS/DDRNet/boxes/source/SLAM: eye и zoom сохраняются, нет прежней двухсекундной задержки. Записать измерения, не ограничиваться видом активной кнопки.
  • Приблизиться, отдалиться, pan/orbit/roll, использовать native keyboard/double-click и повторить follow. Несовпадения журнала отмечать отдельно, не скрывать.
  • Сохранить cloud profile через закрытие, проверить server readback, открыть после очистки browser storage. Проверить 300/500 секунд и точный ввод выше slider; ошибка PUT не запирает окно.
  • Квалифицировать show_labels/show_camera_frustums и двойной semantic selection; известный пробел не отмечать выполненным без подключения и UI-проверки.
  • Проверить export/merge/optimize, codecs, masks/boxes/Clear, color override и lineage на новых SDK. Новый renderer digest и cache строить без изменения sealed source/results.
  • Проверить Saved Sessions и live отдельно от canonical LAB: admission, пять seek на pause, play/resume, clocks, decoder recovery, отсутствие зависимости replay от worker.
  • Измерить cold/warm open и последовательные open/close memory без forced GC; RRD/receiver/canvas identity стабильна при playback/layer changes.
  • Запустить профильные tests, typecheck/build и ручную UI acceptance. Зафиксировать версии, diff адаптеров, результаты, отклонения и пригодный scoped rollback до main.
  • Rollback делать откатом коммита обновления/lockfiles и пересборкой его dist/cache; не применять старый vendor patch или глобальный reset параллельной работы. Канонический сервис оставить на 8000.

Исправление FOLLOW · 5 сентября 2026

Коммит b2a1b23, ветка codex/m5-1-observatory. При FOLLOW off журнал камеры раньше передавал координаты без смещения текущего /world/sensor_pose: камера возвращалась к началу маршрута. При FOLLOW on upstream Rerun 0.36.3 выполняет автоматическое кадрирование нового tracking entity и меняет дистанцию.

Исправление в надстройке: recorded_camera_bounds.py индексирует translation /world/sensor_pose в том же generation-keyed LRU; session_api.py переводит eye offset относительно пивота в мировые координаты на текущем cursor. При отключении FOLLOW записывается текущая мировая поза. При включении сначала устанавливается native tracking, затем после двух animation frames восстанавливаются направление, up и радиус оператора относительно текущего пивота. Обычные переключения слоёв не записывают eye. recorded.py больше не применяет стартовый пресет при смене FOLLOW; пресеты остаются для явных 3D/план/reset.

Файлы: apps/control-station/src/components/RerunViewport.tsx; src/k1link/viewer/{recorded.py,recorded_camera_bounds.py}; src/k1link/web/session_api.py. Ядро и vendor-сборка Rerun не изменены.

Проверено: 65 backend-тестов по camera bounds, RRD export и session API; 759 frontend unit-тестов; typecheck; production build; Ruff; git diff --check. Browser acceptance на RAVNOVES004TREE с DDRNet-39, RF-DETR, TRAVEL TGS и LiDAR: приближение при FOLLOW on, off без изменения кадра, воспроизведение с неподвижной мировой камерой от 00:39.215 до 01:26.491, on с переносом к текущему пивоту при сохранении масштаба, повторный off без прыжка к старту. Ошибок уровня error в браузере не зарегистрировано.

При обновлении Rerun повторно проверить правило auto-fit нового tracking entity, порядок активации blueprint и математику журнала навигации. Основание upstream: https://github.com/rerun-io/rerun/blob/0.36.3/crates/viewer/re_view_spatial/src/eye.rs#L893-L991 .