Skip to content

fix(streams): system_clock timestamps; dialog manifest + overload-guard consistency sweep#230

Merged
facontidavide merged 2 commits into
mainfrom
fix/stream-clock-and-dialog-consistency
Jul 18, 2026
Merged

fix(streams): system_clock timestamps; dialog manifest + overload-guard consistency sweep#230
facontidavide merged 2 commits into
mainfrom
fix/stream-clock-and-dialog-consistency

Conversation

@facontidavide

Copy link
Copy Markdown
Contributor

Four fixes surfaced by the plugin-authoring audit done for plotjuggler_sdk#151:

1. Genuine bug — wrong clock for receive timestamps (mqtt / udp / zmq)

data_stream_mqtt, data_stream_udp, and data_stream_zmq stamped received messages with std::chrono::high_resolution_clock. That clock aliases steady_clock on MSVC and libc++, so on Windows (which this repo builds for) and macOS the timestamps are nanoseconds since boot, not since the Unix epoch — silently wrong time axes. Switched to system_clock, matching what data_stream_dummy, data_stream_ros2, and data_stream_webrtc already do. Three one-line changes.

2. Latent — missing onValueChanged name-hiding guard (parser_json / parser_protobuf)

Both dialogs override onValueChanged(int) without the fleet-standard using PJ::DialogPluginTyped::onValueChanged;, silently hiding the double overload. Harmless today (neither dialog has a double-valued widget), but a landmine for the next widget added; the other 10 dialogs all carry the guard.

3. Quaternion dialog manifest missing required id

QuaternionDialog::manifest() returned a hand-written literal without id. Now returns the embedded kQuaternionManifest (generated from manifest.json, which has the full metadata), matching every other dialog.

4. Fleet-wide: two-arg PJ_DIALOG_PLUGIN(Class, manifest) migration

All 20 dialog registration sites used the legacy one-arg form; the SDK header explicitly prefers passing the manifest literal so catalog scans can read dialog metadata without instantiating the plugin. Each site now passes the same embedded-manifest constant its manifest() override already returns — verified in scope at every site, no new includes needed. CLAUDE.md and porting_guide.md updated to teach the two-arg form. (data_stream_ros2 hand-rolls its dialogVtableFor<> specialization and has no macro — untouched.)

Validation

  • Full fleet build: 168/168 targets clean.
  • ctest: 26/26 tests passed.
  • Pre-commit hooks (incl. clang-format) passed.

🤖 Generated with Claude Code

facontidavide and others added 2 commits July 18, 2026 10:18
…rd consistency sweep

Four fixes surfaced by an SDK-side documentation audit:

- data_stream_mqtt/udp/zmq stamped received messages with
  std::chrono::high_resolution_clock, which aliases steady_clock on MSVC
  and libc++ — producing since-boot instead of since-epoch timestamps on
  Windows/macos builds. Use system_clock, matching dummy/ros2/webrtc.
- parser_json / parser_protobuf dialogs override onValueChanged(int)
  without the fleet-standard `using PJ::DialogPluginTyped::onValueChanged;`
  guard, silently hiding the double overload. Latent (no double-valued
  widgets today); aligned with the other dialogs.
- toolbox_quaternion's dialog manifest() returned a hand-written literal
  missing the required "id"; return the embedded kQuaternionManifest like
  every other dialog.
- Migrate all 20 PJ_DIALOG_PLUGIN(Class) call sites to the two-arg
  PJ_DIALOG_PLUGIN(Class, kXxxManifest) form the SDK header recommends,
  so catalog scans read dialog metadata without instantiating the plugin.
  Each site passes the same embedded-manifest constant its manifest()
  override already returns (all constants already in scope — no new
  includes). CLAUDE.md / porting_guide.md updated to the two-arg form.

Validated: full fleet build (168/168 targets) and ctest (26/26 passed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…breaks on MSVC legacy preprocessor

CI Windows failed on the two-arg PJ_DIALOG_PLUGIN(Class, kManifest) form:
without /Zc:preprocessor, MSVC's traditional preprocessor forwards
__VA_ARGS__ into PJ_DIALOG_PLUGIN_SELECT as a single argument, so the
arity dispatch picks the one-arg LEGACY branch with the glued pair as
ClassName — yielding C2064 (new JsonParserDialog, kJsonManifest())
and C2912 (dialogVtableFor<Class, &kManifest>).

Call PJ_DIALOG_PLUGIN_WITH_MANIFEST(Class, kManifest) directly at all
20 sites instead: a plain 2-param macro, identical expansion on every
preprocessor. Docs updated with the why.

(The underlying SDK dispatch macro needs the classic EXPAND(x) x
indirection to be MSVC-legacy-PP-safe — reported upstream.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@facontidavide

Copy link
Copy Markdown
Contributor Author

CI Windows failure — root cause and fix (781e702):

The two-arg PJ_DIALOG_PLUGIN(Class, kManifest) form is broken under MSVC's legacy preprocessor (this repo doesn't set /Zc:preprocessor): __VA_ARGS__ is forwarded into PJ_DIALOG_PLUGIN_SELECT as a single argument, so the arity dispatch picks the one-arg LEGACY branch with the glued pair as ClassName — hence error C2064 (new JsonParserDialog, kJsonManifest()) and error C2912 (dialogVtableFor<Class, &kManifest>). Linux CI passed because GCC/Clang expand the dispatch correctly; the other 18 sites never got compiled before ninja aborted.

Fixed by calling PJ_DIALOG_PLUGIN_WITH_MANIFEST(Class, kManifest) directly at all 20 sites — a plain 2-param macro with identical expansion on every preprocessor. Docs updated.

Upstream note: this is latent in plotjuggler_sdk itself — pj_plugins/dialog_protocol/.../dialog_plugin_base.hpp's PJ_DIALOG_PLUGIN dispatch needs the classic EXPAND(x) x indirection to be MSVC-legacy-PP-safe. Any Windows plugin author using the header's recommended two-arg form hits this. Worth a PATCH fix in the SDK, after which the pretty form works everywhere.

@facontidavide
facontidavide merged commit eba39e3 into main Jul 18, 2026
31 checks passed
@facontidavide
facontidavide deleted the fix/stream-clock-and-dialog-consistency branch July 18, 2026 14:18
facontidavide added a commit that referenced this pull request Jul 18, 2026
…LUGIN (#232)

Two leftovers from the #229/#230 merge race:

- extern/plotjuggler_core -> 9def534, the RETAGGED v0.18.0 (#229 merged
  moments before the repin landed, so main pinned the pre-retag 7abaccb
  and missed the sort-key-aware table deltas, plotjuggler_sdk#154).
  SDK_VERSION already reads 0.18.0.
- All 20 dialog registration sites back to the documented two-arg
  PJ_DIALOG_PLUGIN(Class, kManifest) form (+ docs). The WITH_MANIFEST
  spelling was a Windows workaround for the macro dispatch bug that
  v0.18.0 fixes (plotjuggler_sdk#153), so it is no longer needed now
  that main pins 0.18.0.

Validated: fleet rebuilt against the retagged SDK (168/168), ctest
26/26 passed.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
facontidavide added a commit that referenced this pull request Jul 18, 2026
…o ~10-15 (#231)

The Windows job rebuilt the entire Conan closure (Arrow, boost,
protobuf/gRPC, ...) from source with MSVC on every run: setup-conan's
coarse cache_packages archive is keyed per workflow rather than per
dependency graph, and the JFrog binary path was PR-skipped and now
retired org-wide. PR #230's run took 68 minutes.

Adopt the portable parts of PJ4's current windows-ci.yml (staying on
GitHub-hosted windows-2022 — Depot runners postponed):

- Explicitly keyed actions/cache for ~/.conan2: key =
  hash(conanfile.py + SDK_VERSION), prefix restore-keys so an older
  closure for the same toolchain seeds unchanged deps. Trim
  build/source/temp trees before saving; save under always() so a
  failed plugin compile still persists the expensive closure.
- sccache (GitHub Actions cache backend) wired into the plugin compile
  via CMAKE_*_COMPILER_LAUNCHER under the Ninja generator; optional —
  a flaked install degrades to an uncached build.
- setup-conan cache_packages: false (replaced by the keyed cache).
- JFrog remote-config and upload steps removed; ensure_core.sh already
  falls back to cache-or-submodule when the remote is absent, and the
  built SDK package persists in the keyed cache from the first run.
- timeout-minutes: 150 backstop against hangs.

Expected: cold run (dependency change) ~25-40 min once, then warm runs
~10-15 min; PRs restore caches published by main.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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