Skip to content

Feat/binary resultframe decoder#7

Merged
NicholasEhsanRoy merged 5 commits into
mainfrom
feat/binary-resultframe-decoder
May 23, 2026
Merged

Feat/binary resultframe decoder#7
NicholasEhsanRoy merged 5 commits into
mainfrom
feat/binary-resultframe-decoder

Conversation

@NicholasEhsanRoy

Copy link
Copy Markdown
Contributor

Implemented binary encoder + handshake with MIME to decide between json or binary communication. Also improved some minor UI aspects, like adding a notice widget for the 3d viewport.

NicholasEhsanRoy and others added 5 commits May 22, 2026 16:15
MIME's runner now offers an opt-in binary wire format on ZMQ 5556
(v0.2 fit-up §8). MICROROBOTICA negotiates the format via a stream_info
handshake on connect and decodes whichever the runner declares.

- binary_frame_decoder: parse the stream_info schema and decode
  [8B float64 sim_time][N x float32] frames into core::ResultFrame,
  the same struct the JSON path produces. Supports compression "none"
  and "zstd" (when built with libzstd); errors clearly on "zstd+xor".
- MimePhysicsProcess: stream_info handshake on launch(), lazy schema
  re-query (the runner builds its encoder on the first frame), and a
  per-message JSON/binary discriminator in the worker loop. The
  one-time {"type":"params"} notice is recognised in both modes.
- JSON remains the fallback when stream_info is unavailable.
- Optional zstd autodetection in CMake; zstd added to vcpkg.json.
- test_binary_decoder: decoder round-trip, error cases, and an
  end-to-end ZMQ test with a faithful runner mock.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…tation

Wires the binary ResultFrame path through to the UI so it can be tested
and benchmarked against a live MIME runner.

Phase 1 — selectable format:
- RunConfigPanel gains a "Stream format" combo (Auto / JSON / Binary).
- ExperimentRunner::start() forwards the choice to the spawned runner as
  the MIME_STREAM_FORMAT environment variable.
- MainWindow passes the panel's choice through on launch.

Phase 2 — benchmark instrumentation:
- core::StreamStats: format, bytes/frame, decode latency, wire fps,
  drop/error counts. New virtual PhysicsProcess::streamStats().
- MimePhysicsProcess instruments the SUB worker — times every decode,
  counts bytes and frames, tracks an EWMA frame rate. decodeJsonMessage()
  replaces handleJsonMessage(), returning an optional so JSON and binary
  decode are timed symmetrically.
- TimelinePanel shows a live readout (format, B/frame, decode us, drops).
- SimulationController::stop() logs a one-line benchmark summary and
  appends a row to microbotica_stream_benchmark.csv for JSON-vs-binary
  comparison across runs.
- test_binary_decoder: the end-to-end test now also asserts streamStats.

All 98 tests pass; both targets build clean under -Wall -Wextra -Werror.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ames

Adds tests that de-risk a live runner connection:

- JSON-stream end-to-end: handshake declares json, the worker decodes
  JSON ResultFrames and skips the params notice, streamStats reports
  format=json. Exercises the fallback path with the refactored worker.
- 0x7B collision: a binary frame whose float64 sim_time begins with
  0x7B (the JSON discriminator byte) — ~1/256 of real frames. Covered
  both as a decoder unit test and end-to-end, asserting such frames
  fall through to the binary decoder rather than counting as errors.
- Corrupt frame: a wrong-sized message is rejected, increments
  decodeErrors, and does not stall the stream.
- Schema field out of range is rejected; the round-trip test now uses
  a distinct-valued quaternion so a wrong w/x/y/z order would fail.

103 tests pass (16 in the binary suite).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Convert LocalViewport from QOpenGLWidget to a native QOpenGLWindow embedded via createWindowContainer; the composited-present path failed in the Docker'd-X environment, leaving the viewport drawing only during camera motion. Restore MSAA for translucency and add bounds-based near/far clip planes. Record the geometry-budget guard idea in RUNTIME_VALIDATION_DEFERRED.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ment

Three closely-related UX fixes around opening and launching an experiment.

1) Non-blocking MIME runner wait.
   onSimulationStart used to call waitUntilReady (a 30s blocking sleep loop)
   on the UI thread, freezing the whole app while the runner JIT-compiled.
   The wait is now driven by a QTimer that polls a new ExperimentRunner::
   probeReady — a single non-blocking TCP probe — every 150 ms, so the
   viewport stays interactive throughout. waitUntilReady now delegates to
   the same probe primitive and is kept for tests.

2) Viewport notice overlay (noice.nvim-style).
   New microbotica::viewport::NoticeOverlay — a top-level frameless,
   transparent-input tool window that tracks the viewport's geometry via
   an event filter. Renders stacked rounded cards (severity glyph + accent
   stroke, dim body) in the top-right corner; inputs pass straight through.
   Required as a separate window because LocalViewport is a native
   QOpenGLWindow which hides any sibling Qt widgets behind it.

   Notices are keyed by id (add/replace/remove), and Settings → General
   gains an "enabled" checkbox + opacity slider stored under notices/* in
   QSettings. MainWindow shows the "Starting MIME runner" notice during
   the async wait and removes it on success/failure.

3) Open Experiment plumbing.
   - RunConfigPanel's folder edit was never updated when an experiment
     was opened from the File menu (the existing QSignalBlocker'd emit
     suppressed even the slot it was trying to invoke). New
     RunConfigPanel::setExperimentDir() sets the text without emitting
     experimentDirChanged, and initExperiment now calls it on every
     entry point.
   - Switching experiments left the previous USD scene on screen because
     initExperiment skipped loadScene when one was already loaded. It now
     closes the previous scene first so the new world.usda is applied.

All 103 tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@NicholasEhsanRoy NicholasEhsanRoy merged commit f653fb1 into main May 23, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant