Sessions: persistence and serialization#
This page documents Cellucid’s session bundle system: what gets saved, how it is encoded, and how restore is staged to get “first pixels” quickly while heavier artifacts load in the background.
It is written for:
contributors changing state fields/UI controls,
anyone debugging “why didn’t my session restore X?”,
anyone hosting
.cellucid-sessionbundles alongside dataset exports.
At a glance#
Audience
Wet lab / non-technical: read “What sessions are (and aren’t)” + “Troubleshooting”.
Computational users: read “Coverage: what is saved” + “Dataset mismatch behavior”.
Developers: read everything; this is a common source of subtle bugs.
Time
30–60 minutes
Prerequisites
State (DataState) and events (for understanding what state is)
What sessions are (and aren’t)#
Sessions are…#
A portable snapshot of UI + app state for a dataset.
Downloadable as a single
.cellucid-sessionfile.Restorable later to recover:
camera/view layout,
active fields and filters,
highlights and highlight pages (and optionally heavy artifacts),
some UI control state.
Sessions are NOT…#
The dataset itself (no data files are embedded).
A guarantee of long-term backward compatibility (dev-phase constraint).
A copy of network/auth state (community annotation tokens are not included).
Where the session system lives (code map)#
Session orchestrator:
cellucid/assets/js/app/session/session-serializer.js
Bundle container framing:
cellucid/assets/js/app/session/bundle/format.js
Feature contributors (what chunks are emitted/restored):
cellucid/assets/js/app/session/contributors/
Helpers for capturing/restoring state:
cellucid/assets/js/app/state-serializer/cellucid/assets/js/app/state-serializer/README.md(detailed coverage list)
UI wiring:
cellucid/assets/js/app/ui/modules/session-controls.js
Bundle format (how .cellucid-session is encoded)#
Cellucid session bundles are a single binary container with:
MAGIC bytes (ASCII):
CELLUCID_SESSION\nmanifestByteLength(u32 little-endian)manifest JSON bytes (UTF‑8)
repeated chunks:
chunkByteLength(u32 little-endian)chunkBytes...
Code:
cellucid/assets/js/app/session/bundle/format.js
Chunk metadata (what the manifest contains)#
The manifest contains a chunks array.
Each chunk describes:
id: unique identifiercontributorId: which contributor handles itpriority:eagerorlazykind:jsonorbinarycodec:noneorgziplabel: display label for UI/progress reportingdatasetDependent: whether it should be skipped on dataset mismatchstoredBytes: size after codec (on disk)uncompressedBytes: expected decoded size (guard)dependsOn(optional): chunk ordering constraints
Design constraints (dev phase):
No version fields, no migrations.
Session files are treated as untrusted input (strict bounds checks; size guards).
Restore staging (eager vs lazy)#
Restoring a session is intentionally staged:
Eager chunks restore “first pixels + UI-ready” state quickly:
camera, layout, active fields, filters, core UI controls.
Lazy chunks restore heavier state in the background:
highlight memberships (large per-cell index lists),
user-defined field codes (potentially large),
analysis caches/artifacts.
Why this matters:
A session restore should feel fast even for large datasets.
Heavy artifacts can be cancelled if the user switches datasets or closes the tab.
Implementation:
cellucid/assets/js/app/session/session-serializer.jsprocesses eager chunks first, then schedules lazy processing with yielding between chunks.
Coverage (what is saved/restored)#
The authoritative list is in:
cellucid/assets/js/app/state-serializer/README.md
High-level summary:
Core visualization + UI (“first pixels”)#
Saved/restored (eager):
camera state
locked cameras: one global camera
unlocked cameras: per-view cameras
live vs snapshot view layout
active view id
per-view dimension levels
active field selection (obs/var) per view
active filters (modified-only)
generic sidebar controls (by DOM id), with explicit exclusions
floating panels layout (non-analysis)
Registries and overlays#
Saved/restored (eager):
field rename registry
field delete/purge registry
user-defined fields metadata (but large codes may be lazy)
Highlights and analysis artifacts (heavier)#
Saved/restored (often lazy):
highlight pages/groups and memberships
user-defined field codes (if large)
analysis caches/artifacts
Exclusions (intentional)#
Not saved/restored:
the dataset itself
dataset selection/connection UI inputs
figure export UI state
benchmark UI state
community annotation state (auth, votes, drafts, moderation UI)
DOM/WebGL runtime objects (only declarative state is stored)
Auto-load on startup from dataset exports#
Cellucid supports a legacy-but-useful workflow:
datasets can ship “latest session snapshot” pointers in their exports folder
Mechanism:
On startup,
main.jscallssessionSerializer.restoreLatestFromDatasetExports().The serializer reads
state-snapshots.jsonin the current dataset base URL and loads the last.cellucid-sessionentry.
Expected files:
<dataset_base_url>/state-snapshots.json<dataset_base_url>/cellucid-session-....cellucid-session
Supported state-snapshots.json shapes (dev-phase):
{ "states": ["file.cellucid-session", ...] }(recommended)["file.cellucid-session", ...](also accepted)
Security model:
Still treated as untrusted input (bounds checks apply).
Dataset mismatch behavior#
Sessions contain a dataset fingerprint. If the current dataset does not match the session’s dataset:
dataset-dependent chunks are skipped (highlights/caches/core state)
dataset-agnostic layout can still restore (e.g. floating panels)
This is a safety feature:
restoring highlights/caches against the wrong dataset can silently corrupt user interpretation.
Adding a new persisted feature (developer workflow)#
If you add a new feature and want it to persist:
Decide what kind of state it is:
“first pixels” (eager, small, required for UI coherence)
“heavy artifact” (lazy, large, optional)
Add or extend a contributor in:
cellucid/assets/js/app/session/contributors/
Ensure the serialized payload is:
bounded in size (guarded)
JSON-safe (or encode as binary)
deterministic (avoid including transient runtime-only values)
Update exclusions if needed:
UI controls:
data-state-serializer-skip="true"(DOM-level exclusion)Analysis windows: handled by analysis module exclusions
Update docs and add a troubleshooting entry (symptoms users will see).
Troubleshooting (symptom → diagnosis → fix)#
Symptom: “Load session does nothing (no UI change)”#
Likely causes (ordered):
User cancelled file picker.
Session file is corrupt or truncated.
Restore was cancelled because a dataset reload started.
How to confirm:
DevTools → Console: look for session serializer warnings/errors.
DevTools → Network: if auto-load, check whether
state-snapshots.jsonand the.cellucid-sessionfile were fetched.
Fix:
Try a known-good small session file.
If hosting sessions, ensure the server serves the binary file correctly (no HTML fallback).
Symptom: “Session loads, but highlights are missing”#
Likely causes:
Highlights are stored in lazy chunks and are still loading.
Dataset mismatch caused dataset-dependent highlight chunks to be skipped.
How to confirm:
Watch notifications (lazy chunk progress).
Check console logs for “dataset mismatch” skips.
Fix:
Ensure you loaded the same dataset id/fingerprint.
Wait for lazy chunks (or inspect which chunks are present in the manifest).
Symptom: “Invalid chunk length … (session file truncated?)”#
Likely cause:
The
.cellucid-sessionresponse is incomplete/corrupt.
Fix:
Re-download the session.
If serving from a host/proxy, ensure it is not truncating large binary responses.
Next: Analysis architecture (analysis uses sessions for reopening windows and optionally restoring artifacts).