Repository navigation
feat(sdk): host surfaces for derived objects and builtin field tables (0.36.0) - #202
Alvvalencia wants to merge 23 commits into
Conversation
…ocessor contract Add header-only FieldTable<T> descriptions for PointCloud, FrameTransforms, SceneEntities and ImageAnnotations with a describe(BuiltinObjectType) registry, so a generic script binder and a topic describer read one source of truth. Document kind="on_demand" (typed "name:type" outputs, luau only) and add the DataProcessorsHostView::createOnDemand shim. Client-side only: no ABI or wire change, host contract unchanged.
The pj.data_processors.v1 vtable had no layout sentinels, so tail slots appended to it could drift unnoticed. Pin the seven existing slots and the fat pointer before the on-demand slots are appended. VERSION moves to 0.35.0 (minor: additions only); the CHANGELOG entry is filled in with the new surfaces once they exist.
…t v2, typed data-processor requests, evaluation handles, scene views Tail-appended, struct_size-gated additions (host contract extended, floor 0.35.0): - PJ_toolbox_host_vtable_t::acquire_catalog_snapshot_v2 returns the scalar catalog plus every object topic with dataset, builtin type, entry count and raw time range in one deep copy (PJ_catalog_snapshot_v2_t, fixed strides). - PJ_data_processors_host_vtable_t gains create_data_processor_v2 (typed outputs, label, INSTANT pin or WINDOW), and the submit/poll/release evaluation triple: an evaluation of an installed on_demand node or of an ephemeral recipe, at an instant or over a window under a cooperative budget, read back as a JSON report through a per-host handle. The host may complete the work inline or in the background; the contract is the same. - pj.scene_views.v1: plugin-owned 3D/2D views with attach/detach/focus and a read-back config, the object counterpart of pj.plot_tabs.v1. - pj_snapshot object-topic metadata marker for clear-and-replace topics. C++ views, layout sentinels, fake-host tests, feature floors, snapshot and docs updated; abidiff shows no additional change over the existing baseline.
Eight builtin types now describe themselves. Two additive descriptor features were needed: an optional-number kind for the compressed depth range, and in-place element replacement for fixed-size arrays (camera matrices), which cannot grow. Raw image buffers expose their pixel record layout when the encoding is a known raw layout; compressed and video payloads keep the codec name and no static record size. Client-side only: no host-contract change.
Client-side helper next to the depth image utilities: a pixel with a positive metric depth and a conventional pinhole K unprojects to a camera frame point; singular, non-finite or skewed intrinsics are rejected.
…image_topic Both are struct fields that never reached the wire, so a canonical or recorded annotations topic could not say which image it belongs to. Written only when set, so existing payloads are byte-identical; readers that predate the fields skip them.
Keep feature floors and metadata coherent with the experimental host contract. Include the official zero-copy point-cloud codec and its regression coverage. Validation: 99 ordinary SDK tests passed; historical ABI comparator remains a known failing gate. Local Conan package and matching consumers built.
Resolved VERSION to 0.36.0 (ours) and CHANGELOG.md by retitling the [0.36.0] section to Unreleased (dropping the experimental-identity language) and appending the official [0.35.0] section from the tag below it.
pj.scene_views.v1 (never released) duplicated pj.plot_tabs.v1: both manage plugin-owned tabs in the same workspace. Scene 3D/2D tabs become kinds of plot tabs through four tail slots of PJ_plot_tab_host_vtable_t: create_tab_v2 (kind plot/3d/2d), attach_topic, detach_topic and focus_tab. The seven v1 slots, their offsets and the plot tab_config JSON are unchanged; a host without a scene workspace leaves the tail slots NULL. PlotTabHostView gains createV2/attachTopic/detachTopic/focus/hasSceneTabs.
Lets a plugin ask whether the host offers the typed request surface (create_data_processor_v2 and the evaluation handles) before offering features that need it, instead of probing a call and parsing its error.
A plugin can declare "badge" (e.g. "AI"), a short label the host shows next to what the plugin created. Absent, the host falls back to the plugin's name.
…eturns PJ_DATA_PROCESSOR_FLAG_INFER_OUTPUTS lets a transient evaluation run with no declared outputs: the host names and types each returned value and lists them under "outputs" in the report. On create, the declared outputs are the ones a trial run learned. Available since 0.36.0.
WidgetData::setSceneView(name, "3d"|"2d") and setSceneTopics turn a plugin QFrame into a live scene view bound to object topics; clearSceneView removes it. Hosts without support leave the frame empty. Available since 0.36.0.
…, unknown poll state is an error - struct_size of the typed request and the evaluation budget: the host reads the prefix it knows and accepts a larger size; a later field is announced by a flag bit, never by the size. - on_demand out_topics returns <owner>/<id>/<name> for number outputs too. - pollEvaluation reports an unknown state as an error instead of pending. - document coverage.error, coverage.gaps and the poll limits.
…ics_editor, plot-tab renames - ToolboxHostView::hasCatalogSnapshotV2 and the capability-detection rule, stated once in plugin_data_api.h. - PJ_DIALOG_HOST_EMBEDS_SCENE_VIEWS (bit 5) plus DialogPluginBase hostCapabilities()/hostHas() over the existing set_host_info slot. - PluginDescriptor::custom_topics_editor manifest flag. - sdk::kDerivedMetadataKey / kDerivedOnDemandValue. - PlotTabHostView::createV2 -> createTabV2, focus -> focusTab. - @SInCE 0.36.0 on every slot, struct and wrapper added on this line. - floors keys follow the renames; kTabledTypeCount text fixed.
…on probe Document EPHEMERAL / HISTORY_EXEMPT / pinned lifetime, what each kind does with label and WINDOW, Python as an optional per-host on_demand language, plot-tab replace semantics, attach idempotency, the non-atomic snapshot v2, scene_view limits and the badge fallback. Update the toolbox guide, the architecture data-processors section, the dialog guide and the plugin skill reference; fix a stray backtick in plugin_data_api.hpp.
hostHas reads DialogHostInfo::has and hostCapabilities() goes. The on_demand out_topics rule, the read-prefix rule and the Python probe are stated once in plugin_data_api.h; the C++ wrappers point to it.
…tinel to 120 columns
Pre-tag review of 0.36.0 (head b40bf62)I ran a correctness and ABI review and a simplify pass (reuse, simplification, efficiency, altitude) over this PR. I checked it against the host in PJ4 #697–#699 and the plugins on Verdict: no critical defect.
The cleanups that change no contract are in the stacked #203: helper reuse, deduced table sizes, Everything below changes the contract. Once 0.36.0 is tagged these become permanent, so each needs a decision before the tag. Line numbers are at b40bf62. Contract decisions before the tag
Additive, any later minor
Host and plugin follow-ups (do not block the tag)
🤖 Generated with Claude Code |
Follow-up: decisions on the contract itemsThe numbers refer to the pre-tag review above. DecidedUnless you see a problem with one of them, these can be folded in as they are.
Also decided: no Open, for you
Proposal: release in two steps
Why:
Cost: a small new PR for the header-only part, #202 rebased as the next minor, and the plugin PRs re-pinned. PJ4 side
🤖 Generated with Claude Code |
Review and merge order: SDK #202 → publish plotjuggler_sdk 0.36.0 → PJ4 #697 → #698 → #699. Plugins after the SDK: #327 → #328.
Summary
The PJ4 side is three stacked PRs to
release-4.1(PlotJuggler/PJ4#697, #698, #699); the plugins side is PlotJuggler/pj-official-plugins#327 and #328. Both build and pass their tests against this branch with--sdk-local. 0.36.0 is released after this merge; then they pin it.This is the SDK half of derived objects in PlotJuggler 4: scripts (Luau, Python) that compute point clouds, scene entities and image annotations from recorded data, evaluated at the cursor, in batch, or incrementally. 22 commits on top of v0.35.0; size breakdown below.
VERSION0.36.0,CHANGELOG[0.36.0] — Unreleased, floors updated (check_feature_floors.pyOK).Size
.md, CHANGELOG)Of the production lines, 1 307 are the field tables (
builtin/*_fields.hpp,field_table*.hpp: headers, no ABI) and 778 areplugin_data_api.h/.hpp(the data-processor and plot-tab contract, mostly doc-comments). This PR's own CI can run (the SDK builds itself); the PJ4 and plugins PRs cannot until v0.36.0 is tagged.What is in it, and what to decide
builtin/field_table.hpp,*_fields.hppfor 8 types,describe(BuiltinObjectType))FieldKindvocabulary (kOptionalNumber, fixedkListwithlist_replace,kBufferwithBufferLayout) the contract we want binders to rely on?create_data_processor_v2,submit_evaluation/poll_evaluation/release_evaluation,PJ_DATA_PROCESSOR_TIME_FLAG_WINDOW/INSTANTPJ_data_processors_host_vtable_t, gated bystruct_size; new request/output/budget structs with their ownstruct_size; layout pinned by sentinelspoll_evaluationthe right boundary, and isrelease_evaluationmandatory for every submitted handle?acquire_catalog_snapshot_v2(PJ_catalog_snapshot_v2_t,PJ_object_topic_info_t)PJ_toolbox_host_vtable_t; new structpj.plot_tabs.v1tabs: tail slotscreate_tab_v2,attach_topic,detach_topic,focus_tabPJ_plot_tab_host_vtable_t(64 → 96 bytes); the 7 v1 slots and the plottab_configJSON are unchanged; slots are NULL when the host has no scene workspacelist_tab_idsdoes not return the kind, so a client that wants only scene tabs reads eachtab_config. Worth a kind-aware listing slot now, or later if a client needs it?ImageAnnotationswire: top-leveltimestampandimage_topic(field 6)unprojectPixelfor rectified metric depth (depth_image_utils.hpp)pj_snapshotobject-topic metadata keyPJ_DATA_PROCESSOR_FLAG_INFER_OUTPUTS; the report carries a rootoutputsarrayvalue,text,cloud, …) lives in the host. OK as host policy, documented here?struct_sizeread-prefix rule forPJ_data_processor_request_tandPJ_evaluation_budget_t: hosts read the prefix they know and accept a larger struct; a new field is announced by a new flag bitout_topicsfor on_demand number outputs = the catalog key of the series the host writes;coverage.errorin the poll report; an unknown poll state is an error inpollEvaluationhasTypedRequests(),hasCatalogSnapshotV2(),hasSceneTabs(); flag bits are not probed; Python is probed withvalidateScriptWidgetData::setSceneView/setSceneTopics/clearSceneView, dialog host bitPJ_DIALOG_HOST_EMBEDS_SCENE_VIEWS(hostHas())badge(short label shown next to what a plugin creates) andcustom_topics_editor(the toolbox the host opens to create/edit derived topics)PlotTabHostView::createV2/focusrenamedcreateTabV2/focusTab;kDerivedMetadataKey;@since 0.36.0on every new surfaceconfiganswers the owner's own ephemerals, chart auto-zoom semanticsIf you prefer smaller PRs
Possible cuts: (a) 1 + 6 + 7 + 8, no ABI; (b) 2 + 3, data-processor and catalog host contract; (c) 4, scene tabs; (d) 5, wire. Each cut needs its own CHANGELOG/VERSION/floors share, and PJ4 needs all of them before it can pin 0.36.0.
Test plan
./build.sh --debug && ./test.sh: 98/99. The only red isabi_check_test(the historical abidiff baseline), red before this branch as well.check_feature_floors.py,test_sdk_install.sh--sdk-localb40bf62(one ABI sentinel wrapped to 120 columns): pre-commit, ubuntu-22.04 and windows-2022 green; the Linux/macOS/Windowsbuildjobs and macos-15-intel queuedChanges after the architecture review (2026-10-05)
PJ_data_processor_output_tgainsuint64_t reserved[2](stride 48): the one array element of the typed request that could not grow is now extensible; a host rejects nonzeroreserved.PJ_DATA_PROCESSOR_REQUEST_V1_MIN_SIZE/PJ_EVALUATION_BUDGET_V1_MIN_SIZEname the read-prefix minimums (pinned by the ABI sentinels).outputs[].type"unknown" excepted); evaluation budgets and handle/report limits are host policy (no PJ4 numbers in the contract;coverage.stoppedsays which budget ended an evaluation); inferred output names are chosen by the host; the v1"name:type"suffix ofcreate_data_processoris deprecated (no client uses it).data_processor_config"series" block documents optionaldone/total(replay progress).hostCapabilities()removed from the docs: it never existed;hostHas()is the API.Tests: 98/99; the one failure is the historical
abi_check_testbaseline comparison, red before this branch.