fix(archive): preserve prepared sessions across restarts
This commit is contained in:
@@ -57,22 +57,26 @@ not mutate playback state, so changing accumulation, size, color or visibility
|
||||
does not pause the active replay or replace its camera view.
|
||||
|
||||
Completed and recovered sessions are discovered on startup and by the catalog
|
||||
reconciler, then deduplicated into one bounded, single-worker preparation queue.
|
||||
The worker validates the native source, exports point/pose data, verifies source
|
||||
stability and both SHA-256 digests, finalizes once, and atomically publishes the
|
||||
reconciler. The first scan is only a historical baseline: it never enqueues the
|
||||
existing archive. A session that becomes finalized after that baseline is
|
||||
deduplicated into the bounded, single-worker preparation queue. The worker
|
||||
validates the native source, exports point/pose data, verifies source stability
|
||||
and both SHA-256 digests, finalizes once, and atomically publishes the
|
||||
digest-bound derived RRD plus its cache sidecar. Before the same job becomes
|
||||
`ready`, it also parses and validates every archived camera index and retains
|
||||
the immutable manifest generation in memory. The catalog exposes preparation
|
||||
state and progress while this runs; a recording URL and camera descriptors are
|
||||
returned only after the complete launch generation has passed validation.
|
||||
`ready`, it also parses and validates every archived camera index and publishes
|
||||
the immutable media-manifest sidecar. The catalog exposes preparation state and
|
||||
progress while this runs; a recording URL and camera descriptors are returned
|
||||
only after the complete launch generation has passed validation.
|
||||
|
||||
Preparation is a backend lifecycle, not a viewer action: sealing or recovering
|
||||
a native session makes it eligible for the reconciler, which builds the derived
|
||||
RRD once in the background. Reopening, seeking or changing the workspace reads
|
||||
that prepared artifact and never reruns conversion. A cold process may validate
|
||||
an existing cache and rebuild its in-memory camera manifest in the worker, but
|
||||
no replay, status, RRD or manifest request hashes native evidence or parses a
|
||||
camera index synchronously.
|
||||
Preparation is a backend lifecycle, not a viewer computation. Reopening,
|
||||
seeking, refreshing the catalog or changing the workspace never reruns a
|
||||
published conversion. After a process restart, a catalog/replay read restores a
|
||||
complete compatible RRD and camera package from its durable sidecars using
|
||||
bounded schema and stat-identity checks; it does not hash native evidence, parse
|
||||
camera indexes or invoke the exporter. A historical session whose package is
|
||||
missing, stale or from an incompatible cache schema remains cold. Only an
|
||||
explicit replay/RRD request schedules that one session for preparation; listing
|
||||
the catalog and finalizing another session do not schedule it.
|
||||
|
||||
The session menu uses three operator indicators:
|
||||
|
||||
@@ -80,6 +84,7 @@ The session menu uses three operator indicators:
|
||||
| --- | --- | --- |
|
||||
| Solid green + `Готово` | `ready` | Verified RRD is available. |
|
||||
| Pulsing green + `Обработка` | `queued`, `validating`, `exporting`, `finalizing` | Background preparation is active. |
|
||||
| Solid gray + `Подготовить` | replayable session with no compatible published package | No work is running; choosing the row schedules this session only. |
|
||||
| Dim gray + `Ошибка` | failed, cancelled, non-replayable or invalid session | No launchable recording; inspect the message or retry. |
|
||||
|
||||
Saved-session status never uses yellow or red. Switching sessions aborts only
|
||||
@@ -93,7 +98,8 @@ Later openings reuse a verified, digest-bound cache. Derived RRD cache v9 is
|
||||
intentionally incompatible with v8 and older generations. In addition to plugin
|
||||
and ordered-artifact identity, it binds the durable clock origin and active
|
||||
envelope and materializes real `session_time = 0` origin and sealed completion
|
||||
rows. Older generations are rebuilt once in the background.
|
||||
rows. Older generations remain cold after startup and are rebuilt only when an
|
||||
operator explicitly opens that session.
|
||||
The browser may use the strict `source_url` with `If-Match`, while the embedded
|
||||
Rerun loader uses the canonical `viewer_source_url` whose lowercase SHA-256
|
||||
`generation` query is bound to the same launch descriptor. A missing or stale
|
||||
@@ -194,11 +200,13 @@ Native `.k1mqtt` bytes with aligned metadata, the capture-clock artifacts and
|
||||
canonical camera fMP4 archives are the evidence source of truth. The derived RRD
|
||||
contains every decodable point and pose frame plus every valid `ModelingReport`
|
||||
distance/speed/scan-time sample from that source, but remains a rebuildable view
|
||||
rather than an evidence master. A cache entry is rebuilt only when native source
|
||||
identity/digests change or an incompatible derived-data export revision is
|
||||
introduced. A UI blueprint or workspace-layout revision never invalidates or
|
||||
rewrites the data RRD. Cache v8 and older payloads are not reusable as v9 because
|
||||
they do not bind both real capture-envelope endpoints.
|
||||
rather than an evidence master. A cache entry is eligible for rebuild only when
|
||||
native source identity/digests change or an incompatible derived-data export
|
||||
revision is introduced. Historical entries are not rebuilt during startup or
|
||||
because another session is finalized; an explicit open schedules the affected
|
||||
entry. A UI blueprint or workspace-layout revision never invalidates or rewrites
|
||||
the data RRD. Cache v8 and older payloads are not reusable as v9 because they do
|
||||
not bind both real capture-envelope endpoints.
|
||||
|
||||
`ModelingReport` time is the device's `ScanTime` counter at two ticks per second;
|
||||
distance and speed are the reported `MoveDistance`/`MoveSpeed` values. Live state
|
||||
@@ -318,9 +326,10 @@ written under the private derived cache with a schema, generation and checksum.
|
||||
Publication uses a private temporary file, file and directory `fsync`, and atomic
|
||||
rename; startup scavenges crash-left temporary files. A restart reuses this
|
||||
sidecar after confined O(n) stat validation, without rereading, hashing or parsing
|
||||
media. A missing, corrupt or stale sidecar is rebuilt only by the background
|
||||
worker. No replay, status, manifest or payload request performs conversion or
|
||||
recalculates these intervals.
|
||||
media. A missing, corrupt or stale sidecar remains cold until an explicit open
|
||||
schedules the complete session package in the background worker. No catalog,
|
||||
status, manifest or payload request itself performs conversion or recalculates
|
||||
these intervals.
|
||||
|
||||
Every derived RRD contains a real `session_time = 0` row at the internal
|
||||
`/__mission_core/session_origin` entity. The anchor is deliberately outside
|
||||
|
||||
@@ -73,11 +73,15 @@ committed metadata; replay stops at the last validated aligned boundary.
|
||||
|
||||
### Recorded spatial playback
|
||||
|
||||
When a native capture is normally sealed or recovery-sealed, a bounded
|
||||
single-worker reconciler automatically prepares its private derived `.rrd`.
|
||||
Preparation is a backend lifecycle and is never executed by an HTTP replay
|
||||
request. Reopening, seeking, switching tabs or changing display settings reads
|
||||
the already prepared artifact and does not rerun conversion. Export is lossless
|
||||
When a native capture is normally sealed or recovery-sealed during the current
|
||||
process lifetime, a bounded single-worker reconciler automatically prepares its
|
||||
private derived `.rrd`. The reconciler's first scan establishes a historical
|
||||
baseline and does not enqueue old sessions. Preparation is a backend lifecycle
|
||||
and is never executed inside an HTTP replay request: an explicit request may
|
||||
enqueue one cold historical package and returns `202` while the worker owns the
|
||||
conversion. Reopening, seeking, switching tabs, listing the catalog or changing
|
||||
display settings reads the already published artifact and does not rerun
|
||||
conversion. Export is lossless
|
||||
with respect to every decodable point and pose message in the native capture;
|
||||
it does not pass through the bounded live-preview queue. The RRD uses the
|
||||
recording-local `session_time` duration timeline, while the receive wall clock
|
||||
@@ -123,21 +127,23 @@ future replay v3 will need distinct spatial and session-union ranges.
|
||||
The path-free descriptor is atomically persisted in the private derived cache
|
||||
with its checksum and a stat identity covering the native timing origin and
|
||||
every camera summary, index, init and segment file. Restart performs confined
|
||||
stat validation and reuses an unchanged descriptor without reading/hashing media;
|
||||
a missing, corrupt or stale sidecar is rebuilt in the background. An unparseable
|
||||
or ambiguous fragment fails readiness rather than exposing a fake seekable
|
||||
camera. Replay requests consume the prepared descriptor and never repeat media
|
||||
conversion or timing analysis. Launch and manifest aggregate byte counts must
|
||||
agree before the browser admits camera payload downloads.
|
||||
stat validation and reuses an unchanged descriptor without reading/hashing media.
|
||||
A missing, corrupt or stale historical sidecar stays cold until that session is
|
||||
explicitly opened; startup, catalog reads and completion of another session do
|
||||
not rebuild it. An unparseable or ambiguous fragment fails readiness rather than
|
||||
exposing a fake seekable camera. Replay requests consume the prepared descriptor
|
||||
and never repeat media conversion or timing analysis. Launch and manifest
|
||||
aggregate byte counts must agree before the browser admits camera payload
|
||||
downloads.
|
||||
|
||||
The derived RRD writes an actual zero-time anchor at the internal
|
||||
`/__mission_core/session_origin` entity. Keeping it outside `/world` prevents a
|
||||
synthetic visualization layer while ensuring that the decoded RRD timeline,
|
||||
not merely its summary document, begins at session time zero. This changes the
|
||||
derived payload contract. Cache v7 keeps that anchor and additionally binds the
|
||||
derived recording to the owning plugin ID, primary artifact and ordered source
|
||||
artifact set; it rejects v6 and older sidecars and performs one background
|
||||
rebuild.
|
||||
derived payload contract. Cache v9 keeps that anchor, binds the owning plugin,
|
||||
ordered source artifacts and capture-envelope endpoints, and materializes the
|
||||
sealed completion rows. Older sidecars are incompatible and remain cold until
|
||||
that session is explicitly opened.
|
||||
|
||||
Replay v2 exposes two paths to the same pinned generation. `source_url` retains
|
||||
the strict `If-Match: "sha256:…"` contract for Mission Core clients;
|
||||
|
||||
Reference in New Issue
Block a user