feat(perception): integrate calibrated operator pipeline

Add calibrated K1 projection, recorded and near-live perception qualification, unified Rerun operator layers, bounded replay admission, audited viewer controls, worker experiments, and lab evidence.
This commit is contained in:
DCCONSTRUCTIONS
2026-07-23 00:23:28 +03:00
parent ada2a55ee6
commit b53d6d5a45
221 changed files with 55923 additions and 1357 deletions
+47 -37
View File
@@ -15,6 +15,9 @@ fully usable with only their available modalities.
1. Enter the required project name and start a normal acquisition from **Парк →
Локальное устройство**. The NFKC-normalized/trimmed value is local display
metadata, not a filesystem path, and becomes the saved-session catalog name.
A normal acquisition has no duration deadline and runs until the operator
explicitly stops it. Compatibility clients may still request a positive
finite duration, without an application-level maximum.
2. Open **Наблюдение → Пространственная сцена**. Live point cloud, trajectory
and the selected camera remain live-only while acquisition is running.
3. Stop acquisition normally, or allow the local service to recover an
@@ -165,7 +168,8 @@ a separately attested storage root:
export MISSIONCORE_DATA_DIR=/absolute/private/path/mission-core
# Full K1 point-plus-camera evidence must currently remain below the checkout.
export MISSIONCORE_EVIDENCE_DIR=/absolute/path/to/NODEDC_MISSION_CORE/.runtime/mission-core/evidence/sessions
export MISSIONCORE_RRD_CACHE_MAX_BYTES=8589934592
# Optional operator retention quota; unset means no application byte quota.
# export MISSIONCORE_RRD_CACHE_MAX_BYTES=8589934592
export MISSIONCORE_RRD_FREE_SPACE_RESERVE_BYTES=2147483648
uv run k1link serve
```
@@ -226,13 +230,15 @@ keeps the current device scan generation and does not accumulate an earlier
distance after the device resets scan time and route distance. These values are
not reconstructed from pose integration or a browser timer.
Expensive cache misses run through the bounded preparation worker and one global
cross-process export gate to cap peak RAM, CPU and temporary-disk use. Crash
leftovers from candidates, exporter temporary files and staged replay prefixes
are scavenged under that lock before quota accounting. Ready cache hits and
active response leases do not wait behind that gate. The derived cache has an
8 GiB default quota, preserves a 2 GiB default filesystem reserve and evicts
least-recently-used RRDs only; it never deletes native evidence.
Expensive cache misses run through the single-worker preparation queue and one
global cross-process export gate to cap concurrent RAM, CPU and temporary-disk
use. Crash leftovers from candidates, exporter temporary files and staged replay
prefixes are scavenged under that lock before capacity accounting. Ready cache
hits and active response leases do not wait behind that gate. The derived cache
has no application byte quota by default, so a single multi-hour RRD is not
rejected at 8 GiB. It still preserves a 2 GiB default filesystem reserve. An
operator may set `MISSIONCORE_RRD_CACHE_MAX_BYTES` to enable LRU eviction of
derived RRDs only; native evidence is never deleted.
## Capture-clock envelope
@@ -313,7 +319,9 @@ time are not proven to use a shared device clock. Do not infer frame-accurate
calibration from the playback timeline.
Finalized media is prepared once by the same process-owned background job that
materializes the RRD. The gateway records host time only after a complete
materializes the RRD. JSONL indexes are read incrementally and no total index,
segment-count or archive-byte ceiling is used. The gateway records host time
only after a complete
`moof+mdat` fragment has arrived, so that timestamp is an availability/end
anchor, never a fragment-start timestamp. Preparation reads and SHA-verifies
every fragment, parses bounded ISO-BMFF timing tables (`mdhd`, `trex`, `tfhd`,
@@ -332,7 +340,7 @@ coverage can be navigated. A missing, ambiguous, oversized or otherwise
unparseable timing table fails preparation; the archive remains evidence but is
never advertised as seekable media.
The prepared path-free v2 descriptor and full source stat identity (native raw
The durable path-free v2 descriptor and full source stat identity (native raw
and timing metadata plus every camera summary, index, init and segment file) are
written under the private derived cache with a schema, generation and checksum.
Publication uses a private temporary file, file and directory `fsync`, and atomic
@@ -379,8 +387,9 @@ camera acceptance run retained point/pose evidence only.
provisional `transport` generation, but discovery will not use either to
advertise camera coverage. A mismatched origin/envelope/summary fails closed.
- A native capture with a missing final summary is accepted only when the raw
and metadata prefix is bounded, aligned and structurally valid. It is cataloged
as `interrupted`, never silently promoted to `ready`.
and metadata prefix is aligned and structurally valid. Recovery streams the
metadata JSONL one row at a time with no total-byte or message-count ceiling;
it is cataloged as `interrupted`, never silently promoted to `ready`.
- A non-newline metadata crash tail can be ignored. Newline-terminated or
mid-file corruption fails closed.
- Camera recovery retains a contiguous valid segment prefix, quarantines
@@ -426,6 +435,7 @@ POST /api/v1/observation-sessions/{id}/blueprint.rrd
GET /api/v1/observation-sessions/{id}/media/{artifact}/manifest
GET /api/v1/observation-sessions/{id}/media/{artifact}/epochs/{n}/init.mp4
GET /api/v1/observation-sessions/{id}/media/{artifact}/epochs/{n}/segments/{m}.m4s
GET /api/v1/observation-sessions/{id}/media/{artifact}/epochs/{n}/recording.mp4?generation=<sha256>
GET /api/v1/workspace-layouts/observation.spatial
PUT /api/v1/workspace-layouts/observation.spatial
@@ -461,40 +471,40 @@ revision in `If-Match`; stale writers receive HTTP 412 rather than overwriting
another saved profile.
Recorded media routes expose only opaque catalog identifiers and ordinal codec
epochs. The required `missioncore.observation-recorded-media/v2` manifest carries
a strong `generation_sha256`, exact JS-safe aggregate `byte_length`, and finite
epochs. The public compact
`missioncore.observation-recorded-media/v3` manifest carries a strong
`generation_sha256`, exact JS-safe aggregate `byte_length`, and finite
`timeline_start_seconds` / `timeline_end_seconds` for every epoch. Epoch ends
participate in the generation digest. Every epoch also declares its init byte
length/digest and a complete contiguous segment list with sequence, URL, byte
length and digest. The launch source repeats the same aggregate `byte_length`
and uses exactly `max(epoch.timeline_end_seconds)` as its end; the spatial RRD
end must never pad camera coverage. The browser cross-checks launch, manifest and
component lengths. The current browser laboratory policy accepts at most 16
camera sources, 128 MiB per source and 512 MiB across the session. This launch
preflight finishes before the first camera manifest/init/segment GET; admitted
cameras are then downloaded and decode-probed one at a time. Verified raw
buffers remain immutable so route changes and player remounts cannot append
emptied data. This bounded in-memory strategy is deliberate for the laboratory
milestone; an OPFS-backed sealed-generation cache is the next scaling step for
larger rigs and must preserve the same launch/manifest/hash admission contract.
participate in the generation digest. Each epoch declares one generation-bound
`stream_url`, media type and aggregate byte length; thousands of internal
segment rows never enter browser memory. The launch source repeats the same
aggregate `byte_length` and uses exactly `max(epoch.timeline_end_seconds)` as
its end; the spatial RRD end must never pad camera coverage. The browser
cross-checks launch and manifest identity, but applies no duration, per-source
byte or aggregate-session byte admission ceiling.
The manifest response ETag is the exact generation, and the manifest GET itself
requires that generation in `If-Match`. Init and media GETs likewise require the
descriptor's exact SHA `If-Match`, then open through a confined directory file
descriptor with no symlink following, verify the declared SHA-256 and serve
exact-length bytes with immutable private `no-transform` caching and byte-range
support. Physical source ids, RTSP addresses and storage paths never cross the
API boundary.
The `<video>` element reads the immutable virtual fMP4 through native HTTP Range
requests. The server maps each requested interval onto init/segment files,
opens them through confined descriptors with no symlink following and verifies
the digest of each touched component. It never assembles the full video in
backend or JavaScript memory. Responses carry exact `Content-Length` /
`Content-Range`, a generation-and-epoch ETag, `Accept-Ranges: bytes` and private
immutable `no-transform` caching. The manifest ETag is the exact generation and
its GET requires the matching `If-Match`; the stream URL binds that same
generation in its query. The older init/segment routes remain internal
compatibility surfaces. Physical source ids, RTSP addresses and storage paths
never cross the API boundary.
## Current limit
## Current synchronization boundary
The spatial RRD, trajectory, archived device-metric series and archived fMP4
cameras use the same operator scrubber now. Camera epochs are aligned to
zero-based `session_time` from the shared host-arrival monotonic clock and
rendered through MSE. The metric tab carries device-reported route distance,
rendered through the browser's native fMP4/Range pipeline. The metric tab carries
device-reported route distance,
speed and scan time at their `ModelingReport` receive times. The client selects
a camera epoch only inside its declared inclusive interval and verifies that the
decoded MSE seekable duration covers that interval. This remains best-effort
decoded native-media seekable duration covers that interval. This remains best-effort
correlation: codec PTS, K1 sensor exposure time and LiDAR firing time are not
proven to share a device clock. A codec epoch whose init segment does not expose
a browser-supported codec or whose timing cannot be proven remains retained