docs(perception): record decoder parity and remaining full-graph bridge
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
# Observatory: четыре этапа создания полного real-time Perception-профиля
|
||||
|
||||
Дата: 2026-09-01; обновлено 2026-09-02 12:35 МСК. **Этап 1 закрыт; этап 2 в работе. Третий инкремент: bounded binary IPC ingress с неизвестной длиной источника подключён к общему lifecycle/byte budget и проверен на Worker.** 103/103 исходных события доставлены без изменения bytes/metadata; камера, LiDAR и pose поступают до End. Это raw-digest consumer, **не** подключённый к этому ingress полный модельный граф. Real-time qualification НЕ выдана: последнее полное измерение остаётся 128/128, p95/p99 124.98/136.12 ms, fresh 76/128. Далее decoder→full graph bridge, network/controller и standalone image; этапы 3–4 не начаты. Default PyTorch, TensorRT parity не принята.
|
||||
Дата: 2026-09-01; обновлено 2026-09-02 13:09 МСК. **Этап 1 закрыт; этап 2 в работе. Четвёртый инкремент: persistent H.264 decoder принимает отдельные fMP4-фрагменты без готового MP4, следующих кадров и EOF.** BGR совпадает с прежним декодером на 128/128 кадрах. Бинарный ingress + decoder отдельно проверены на 103 событиях / 32 кадрах. Это ещё **не** полный граф на новом входе. Последнее полное измерение не меняется: 128/128, p95/p99 124.98/136.12 ms, fresh 76/128, real-time qualification НЕ выдана. Далее causal sensor / supervised decoder → full graph bridge, затем controller/network и standalone image; этапы 3–4 не начаты.
|
||||
|
||||
Последние изменения: `da60fef` — binary v2 mapping существующих LiveIngressEvent, sender/receiver и общий byte budget; `a937400` — корректная фиксация End в probe; `79ce55d` — regression старого raw-first ingress. 276 focused tests PASS. CPU-only Worker probe: 32 camera frames + init + 34 LiDAR + 36 pose, 4,061,693 wire bytes, peak input 553,991 bytes, residue 0. Межпроцессная доставка до raw callback: p95/p99 0.419/0.601 ms; это не model/network latency. Обрыв между фрагментами не выдал payload и завершил lease. Модели/clocks/старые GPU-сервисы не менялись. Прежние lifecycle/lease/full-graph доказательства сохранены; product batch path пока не переключён.
|
||||
Последние изменения: `350366b` — общий byte-only MP4 parser и source-neutral decoder; `f102712` — Worker parity/decoded-ingress probes. 246 focused tests PASS, отдельный повтор session/decoder — 55 PASS; Ruff/mypy PASS. В CPU-only 128-frame 1× пробе p95 нового decoder снизился с 19.927 до 11.156 ms после отказа от повторного demux/probing; это сравнение двух новых decoder-вариантов, не ускорение полного профиля. IPC + decode: 103/103 exact raw events, 32/32 exact BGR, peak input 5,727,751 bytes, остаток 0; первый кадр за 3.071 s до End. Модели не запускались, services/clocks не менялись; product batch path пока не переключён.
|
||||
|
||||
Текущий evidence: [отчёт этапа 1](../experiments/perception/PERCEPTION_STREAM_STAGE1_2026-09-01.md), [ADR 0049](adr/0049-stream-first-perception-profiles.md), [candidate manifest](../config/perception/k1-perception-ddrnet39-rfdetr-tgs-prototype-v1.json). Запрет full-source preload закреплён в новом контракте; старый batch materializer пока не удалён и продуктовый путь не переключён.
|
||||
|
||||
@@ -143,7 +143,7 @@ IPC/сети, копирований и оркестрации. Вычислит
|
||||
|
||||
## Этап 2 — Самостоятельный Docker с полным потоковым вычислением
|
||||
|
||||
**Текущий статус, 12:35 МСК:** в работе. Lifecycle/scheduler/per-cell expiry проверены полным пилотом; новый raw binary ingress — отдельным CPU-only межпроцессным probe. Их decoder/full-graph соединение ещё требуется: новый вход пока принимает и проверяет raw события, не рассчитывает модели. Production admission/recovery, continuous GPU inventory/envelope monitoring, binary network ingress и standalone image ещё не закрыты. GO на этап 3 пока нет.
|
||||
**Текущий статус, 13:09 МСК:** в работе. Lifecycle/scheduler/per-cell expiry проверены полным пилотом; binary ingress и persistent fragment decoder — отдельными CPU-only probes. Новый вход уже выдаёт точные BGR-кадры, но causal cloud/pose binding и передача decoded bundles тому же модельному графу ещё не соединены. Нужны supervised native decoder child, общий ownership/scratch budget при handoff и новый full-graph parity/timing. Production admission/recovery, continuous GPU inventory/envelope monitoring, network ingress и standalone image ещё не закрыты. GO на этап 3 пока нет.
|
||||
|
||||
**Цель:** один самостоятельный контейнер принимает поток и реально рассчитывает DDRNet, детекции, расстояния, motion, TGS/costmap и policy-shadow; ничего не дорисовывается из старых LAB.
|
||||
|
||||
@@ -264,7 +264,11 @@ EoMT — семейство ViT-моделей сегментации изобр
|
||||
|
||||
## Surprises / открытые вопросы
|
||||
|
||||
- IPC probe отделил работоспособность raw ingress от работоспособности decoder/full graph. Наличие codec-init gate не проверяет NAL/IDR, access-unit framing или соответствие fisheye calibration. Оригинальные fMP4 segments не превращаются автоматически в model-ready frames; следующий bounded шаг — persistent incremental decoder и causal sensor adapter с allocation bounds, затем тот же полный граф. Старые model inputs/prepared paths не подмешивать в доказательство нового ingress.
|
||||
- 2026-09-02 13:09 МСК: decoder-инкремент `350366b` / `f102712` принят отдельно от full graph. Evidence `.runtime/perception-stage2-decoded-ingress-worker-20260902T1310MSK/manifest.json`, 43 artifacts, SHA-256 `612295eabbc8f203ad9b037a69ac9cf97b2df3134b087d9e51a9786738423f2f`; связан с отдельными 128-frame demux/direct/reference manifests. Все 128 BGR совпадают; 32-camera binary canary и negative EOF освобождают весь input budget. Четыре Mission Core сервиса не останавливались; модели и GPU clocks не менялись.
|
||||
|
||||
- Повторный `av.open(init + fragment)` не является полнофайловым барьером, но повторяет stream probing на каждом кадре. Принят узкий проверяемый ISO-BMFF layout → один AVCC sample → persistent codec; NumPy импортируется до readiness. p95 первого потокового варианта 19.927 ms → 11.156 ms. Это bounded CPU A/B без модели; не вычитать выигрыш из старого full-graph p99. Codec/parser не импортируют session store или materializer; archive API сохраняет прежние exception contracts. Иной codec/layout, B-frames, multi-sample, пропуск DTS или не-keyframe start требуют нового явно квалифицированного профиля/epoch, а не скрытого fallback.
|
||||
|
||||
- Новый decoder не делает весь bridge готовым. Следом — causal sensor window на момент camera release, supervised CPU child с bounded RPC и передача владения decoded bundle в общий mailbox, затем тот же полный граф. Не подмешивать готовый MP4 или старые masks/geometry. Реальная калибровка в decode/hash probe не используется: совпадение BGR не доказывает calibration admission или field quality.
|
||||
|
||||
- 2026-09-02 12:00 МСК: истечение lease и освобождение GPU разделены. После crash OS lock свободен, но durable `active` не допускает новый запуск. Recovery намеренно отсутствует до trusted resource-release proof; нельзя удалять production marker ради продолжения. В пробах удалены только два заведомо временных experiment-owned volume после сохранения записей и остановки всех probe containers.
|
||||
|
||||
@@ -307,6 +311,6 @@ EoMT — семейство ViT-моделей сегментации изобр
|
||||
|
||||
## Outcomes / retrospective
|
||||
|
||||
Этап 1 остаётся завершённым engineering baseline. Этап 2 теперь имеет общий scheduler, per-cell expiry, subprocess lifecycle/lease и bounded raw binary IPC. Новый ingress прошёл 103 реальных source events без потерь/изменений и отдельный incomplete-fragment отказ. Общий byte budget удерживает raw/reassembly до выхода callback; старые input owners не освобождаются при cancel. Но raw-digest probe не равен полному графу: следующий шаг соединяет incremental decoder/causal sensor adapter с моделями и повторяет full-profile timing/parity на новом входе. Прежний полный p99 136.12 ms остаётся FAIL 125 ms. Network/gRPC/authentication, production controller/recovery/inventory и standalone image не приняты; старый batch/registry/UI не переключены. Четыре сервиса не останавливались в новом CPU-only probe, Ollama/Frigate остаются выключены. Full suite/image build не запускались; исторические baseline-symlink и NVCR403 вопросы не объявлены исправленными.
|
||||
Этап 1 остаётся завершённым engineering baseline. Этап 2 имеет общий scheduler, per-cell expiry, subprocess lifecycle/lease, bounded raw binary IPC и persistent fragment decoder. Новый decoder воспроизвёл 128 BGR без отличий и без future-fragment/EOF barrier; combined IPC/decoder — 32 BGR и 103 raw events. Общий byte budget учитывает raw, scratch и retained codec metadata; normal/error cleanup оставляет 0 bytes. Native codec RSS измеряется отдельно, а его изоляция внутри полного GPU runtime ещё нужна. Следующий шаг соединяет causal sensors и supervised decoder с тем же полным графом и повторяет timing/parity. Прежний full-graph p99 136.12 ms остаётся FAIL 125 ms. Network/gRPC/authentication, production controller/recovery/inventory и standalone image не приняты; старый batch/registry/UI не переключены. GPU-прогонов, full suite и image build в этом инкременте не было; сервис 8000 сохранён, Ollama/Frigate выключены.
|
||||
|
||||
После этапа 4 здесь будут перечислены digest самостоятельного полного образа, измеренные статусы и ошибки по recordings, реально проверенные source/hardware/config комбинации, состояние сохранённого EoMT-варианта и оставшиеся physical-live/quality/vehicle-integration ограничения. Готовый Docker и готовая автономия не отождествляются.
|
||||
|
||||
@@ -140,6 +140,55 @@ feed incremental decode and causal sensors into the same graph without using
|
||||
the old concatenated camera file or precomputed geometry. Product source queues,
|
||||
backend routes and the browser are not switched by this increment.
|
||||
|
||||
Stage-2 decoder increment, 2026-09-02 (`350366b`, `f102712`):
|
||||
`media_fragments.py` now owns the existing bounded ISO-BMFF timing parser.
|
||||
Archive inspection delegates to it and preserves `SessionIntegrityError` at its
|
||||
boundary. `perception.streaming_decoder.FragmentDecoder` imports neither the
|
||||
session store nor its materializer. It receives only bounded init/fragment bytes;
|
||||
source filenames, recording length and EOF are not decoder inputs.
|
||||
|
||||
The measured subset is H.264, one 800×600 frame per fragment, one video track,
|
||||
explicit moof-relative sample size/offset and no composition offset. The first
|
||||
fragment must be random-access and the decoded frame must be keyframe; DTS must
|
||||
remain contiguous. One persistent codec context, one slice thread, no flush or
|
||||
future packet: each call must yield exactly one frame with the same PTS/raster.
|
||||
Reordered/B-frame streams, unknown layouts, discontinuities and invalid output
|
||||
fail closed. Other valid camera formats require explicit qualification, not a
|
||||
hidden decoder fallback. These are current profile bounds, not a new K1 protocol.
|
||||
|
||||
PyAV 18.0.0 is pinned to wheel SHA-256
|
||||
`ae56b40b6f8b067a8ad2dac664fbfbabac7f7a55b9a7bb031eb99289252bc017`.
|
||||
It is installed only into a private experiment target and mounted read-only;
|
||||
standalone packaging must include it. The public
|
||||
[PyAV codec documentation](https://pyav.basswood.io/docs/stable/api/codec.html)
|
||||
describes persistent packet decoding and thread modes; compatibility claims here
|
||||
come from the actual 18.0.0 Worker probe, not from documentation version alone.
|
||||
|
||||
Sequential CPU-only 128-frame 1× comparisons produced exact BGR parity against
|
||||
the previous pinned OpenCV decoder. Direct validated sample extraction replaces
|
||||
opening/demuxing init+fragment on every frame; NumPy loads before readiness.
|
||||
Measured new-decoder p95 improves 19.927→11.156 ms, p99 20.920→18.675 ms.
|
||||
This is one bounded component comparison, not a full-profile speedup claim.
|
||||
The reference full-MP4 path exists only in the separate pixel-comparison process;
|
||||
neither new decoder path mounts/reads that MP4.
|
||||
|
||||
Combined IPC/decoder probe accepts 103 raw events and yields 32 exact BGR frames.
|
||||
31 frames arrive before the source End marker; the final frame drains before
|
||||
the receiver handles End. First decoded callback is 3.071 s before the marker.
|
||||
Input reservations peak at 5,727,751 bytes including conservative decoder scratch
|
||||
and init/extradata retention; normal and truncated-input cleanup return to zero.
|
||||
Native codec/DPB allocations are bounded separately by the CPU-only container;
|
||||
application payload counters alone do not constrain native allocation or execution
|
||||
time. Before full-graph integration, native decoding must run in a supervised CPU
|
||||
child with bounded RPC and explicit decoded-bundle ownership transfer.
|
||||
|
||||
Point/pose are preserved raw in this probe, not causally fused into a scene;
|
||||
calibration identity is explicitly non-scene/synthetic. No full graph, GPU model,
|
||||
network, physical live feed, vehicle control or product cutover is qualified.
|
||||
Next: preserve the existing causal sensor cut at camera release, connect decoded
|
||||
bundles to the same full graph, then repeat full-profile parity/timing. The last
|
||||
full-profile p95/p99 remains 124.98/136.12 ms, not this decoder's timing.
|
||||
|
||||
Open → validate bounded metadata/claim → warm models → Ready → start the replay
|
||||
clock → observations and incremental scenes → stop/drain bounded state → close
|
||||
and asynchronously seal the immutable receipt. A live source already producing
|
||||
|
||||
@@ -1454,3 +1454,112 @@ camera decoder и causal sensor adapter, соединяющие этот ingress
|
||||
parity/timing на новом входе. Network/gRPC/authentication, constant controller
|
||||
root/recovery/inventory, standalone image и product cutover остаются открытыми.
|
||||
Этап 2 не закрыт, этапы 3–4 не начаты; actuation=false.
|
||||
|
||||
## 2026-09-02 13:09 МСК — этап 2, инкремент 4: fMP4 → persistent decoder
|
||||
|
||||
Коммиты: `350366b` (общий parser/decoder и synthetic tests), `f102712`
|
||||
(Worker probes). Это входная часть runtime, **не новый запуск полного графа**.
|
||||
Никакие модели, thresholds, source clock, GPU clocks или ограничения Docker
|
||||
полного профиля не менялись. Четыре Mission Core GPU-сервиса не останавливались.
|
||||
|
||||
### Реализованная граница
|
||||
|
||||
Из `sessions.media` выделен прежний bounded ISO-BMFF timing parser; archive API
|
||||
сохраняет свои исключения. Новый decoder не импортирует session store/materializer,
|
||||
не принимает path, frame count, duration или EOF. Принимает init ≤64 KiB и один
|
||||
полный fMP4 fragment ≤1 MiB. Объявленный subset: H.264, один video track, native
|
||||
800×600, один sample, явные moof-relative offset/size, без composition offset.
|
||||
Первый fragment/frame проверяется как random-access/keyframe; DTS непрерывен.
|
||||
Persistent codec выдаёт ровно один BGR кадр текущего PTS, без flush и будущих
|
||||
пакетов. B-frames, иной layout/raster, multi-sample, пропуск или неоднозначный
|
||||
native output завершают decoder; молчаливого fallback нет.
|
||||
|
||||
Первый рабочий вариант открывал `init + current fragment` через PyAV на каждом
|
||||
кадре. Полнофайлового барьера уже не было, но повторялся stream probing.
|
||||
В принятом варианте bounded parser проверяет размер/offset единственного AVCC
|
||||
sample и передаёт его непосредственно persistent H.264 codec. NumPy импортируется
|
||||
до readiness. Только init открывается через PyAV; decode не читает файлов.
|
||||
|
||||
### Worker CPU-only A/B и отдельный reference
|
||||
|
||||
Эксперименты `perception-stage2-decoder-worker-20260902T1250MSK` и
|
||||
`perception-stage2-decoder-direct-worker-20260902T1305MSK`: последовательно,
|
||||
network none, без GPU request, 2 CPU / 512 MiB; process address-space limit 1 GiB.
|
||||
Исходные 128 fMP4 fragments поступают по одному на исходном 1× времени.
|
||||
Старая готовая MP4 используется **только** отдельным reference-процессом OpenCV
|
||||
для сравнения пикселей, не монтируется в новые decoder-прогоны. Reference не
|
||||
paced, поэтому его throughput не сравнивается с новым source-paced latency.
|
||||
|
||||
| Метрика, ms | Первый per-fragment demux | Direct sample / persistent codec |
|
||||
| --- | ---: | ---: |
|
||||
| p50 | 10.506 | 5.984 |
|
||||
| p95 | 19.927 | 11.156 |
|
||||
| p99 | 20.920 | 18.675 |
|
||||
| max | 68.909 | 38.066 |
|
||||
| Первый кадр | 68.909 | 18.675 |
|
||||
| Codec init, отдельно | 17.854 | 21.103 |
|
||||
| BGR parity с reference | 128/128 exact | 128/128 exact |
|
||||
|
||||
Каждый кадр декодирован до чтения следующего source fragment. Direct peak RSS
|
||||
59,192 KiB. Это один bounded CPU A/B, не статистическая квалификация всего
|
||||
профиля и не обещание аналогичного выигрыша при одновременной CPU-части графа.
|
||||
|
||||
### Бинарный вход с настоящим декодером
|
||||
|
||||
`perception-stage2-decoded-ingress-worker-20260902T1310MSK`: существующий
|
||||
отдельный source process → IPC v2 → FragmentDecoder в CPU-only probe container
|
||||
(2 CPU / 768 MiB). Receiver по-прежнему не получает длину записи. Защита raw
|
||||
headers/reassembly сохранена; init/extradata и decoder scratch резервируются
|
||||
в общем 16-MiB mailbox **до** использования. Native codec/DPB дополнительно
|
||||
ограничены container RSS envelope; это не всеобъемлющий Python byte counter.
|
||||
|
||||
- 103/103 raw events exact: init 1 + camera 32 + LiDAR 34 + pose 36; timestamp,
|
||||
sequence, source identity, payload length/SHA сохранены.
|
||||
- 32/32 decoded BGR exact против независимого reference. Первый decoded callback
|
||||
за 3.071 s до source End marker; 31/32 до marker, последний дренируется перед
|
||||
обработкой End получателем. Это нормальная финальная доставка, не EOF barrier.
|
||||
- Source-due → decoded/hash callback p50/p95/p99/max:
|
||||
9.257 / 19.317 / 26.019 / 26.019 ms. Decode+hash p95/p99 11.635/19.698 ms.
|
||||
Эти интервалы не включают модели, geometry, result scene, сеть или browser.
|
||||
- Wire 4,061,695 bytes; peak accounted input 5,727,751 bytes; остаток 0;
|
||||
cgroup peak 84,332,544 bytes. Source release lag max 5.838 ms.
|
||||
- Negative EOF между фрагментами: started=1, completed=0, incomplete=1;
|
||||
никакого payload callback, terminal=failed, lease/input bytes освобождены.
|
||||
|
||||
PyAV18 wheel отсутствовал в исходном diagnostic image. Загружен публичный
|
||||
`av==18.0.0` (35,536,910 bytes, SHA-256
|
||||
`ae56b40b6f8b067a8ad2dac664fbfbabac7f7a55b9a7bb031eb99289252bc017`), затем
|
||||
установлен offline/no-deps в приватный experiment target. Общая система,
|
||||
Goose Python и image не менялись. Target read-only; его file hashes сохранены
|
||||
в dependency manifest. Это явный временный mount, не standalone packaging.
|
||||
|
||||
246 focused tests PASS; повтор session API + decoder — 55 PASS. Ruff и mypy
|
||||
трёх source modules PASS; full suite и модели на Mac не запускались.
|
||||
Все временные probe/dependency containers и source children завершены.
|
||||
Triton ready=200, Mac 8000=200, 8765 закрыт. Ollama/Frigate exited/restart=no;
|
||||
GPU auto P8, 982 MiB, power limit 450 W, без изменения частот.
|
||||
|
||||
### Evidence и следующий шаг
|
||||
|
||||
Принятый manifest: 43 artifacts, SHA-256
|
||||
`612295eabbc8f203ad9b037a69ac9cf97b2df3134b087d9e51a9786738423f2f`,
|
||||
`.runtime/perception-stage2-decoded-ingress-worker-20260902T1310MSK/manifest.json`.
|
||||
Связанные sealed manifests: demux/reference/dependency —
|
||||
`6a0090f6e1ec11aba436441afacdc0146902a5f911a57a8f989038764dab5d2f`
|
||||
(22 artifacts); direct decoder —
|
||||
`0eb32c2c5823130dec87b4e11d825d984b7ee373453b8b4f8b17a4729d5f8134`
|
||||
(14 artifacts). Снимки code packs, отчёты, per-frame hashes, timestamps,
|
||||
команды и dependency inventory сохранены; реальные inputs в Git не добавлены.
|
||||
|
||||
**Граница:** cloud/pose пока передаются без изменения, но не связываются здесь
|
||||
в causal scene; calibration identity у hash/decode probe синтетическая и не
|
||||
допускает model scene. Нативный decoder ещё требуется изолировать supervised
|
||||
CPU child внутри полного runtime; добавить bounded RPC, causal sensor cut на
|
||||
момент camera release и handoff decoded ownership в общий mailbox. После этого
|
||||
запустить тот же DDRNet/RF-DETR/geometry/motion/TGS/policy граф и проверить
|
||||
raw parity / timing на новом binary input, без `/source.mp4`.
|
||||
|
||||
Последний **полный** p95/p99 остаётся 124.98/136.12 ms, fresh 76/128. Не вычитать
|
||||
decoder-выигрыш из этих значений и не объявлять real-time qualification.
|
||||
Network/controller/recovery/inventory, standalone image и product cutover
|
||||
остаются открытыми. Этап 2 продолжается; этапы 3–4 не начаты; actuation=false.
|
||||
|
||||
Reference in New Issue
Block a user