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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user