diff --git a/CHANGELOG.md b/CHANGELOG.md index 70e2f57c..9233c011 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to `plotjuggler_sdk` are recorded here. Versioning policy is in [`CLAUDE.md`](./CLAUDE.md) → "Release Versioning". +## [0.34.0] + +Host contract: extended: PJ_DATA_PROCESSOR_FLAG_HISTORY_EXEMPT (floor 0.34.0). + +- Add `PJ_DATA_PROCESSOR_FLAG_HISTORY_EXEMPT` to `create_data_processor`'s + `flags` bitset: the node is persisted in the layout file like any other + processor, but the host's undo/redo history never restores, recreates or + removes it — history has no authority over it. Orthogonal to + `PJ_DATA_PROCESSOR_FLAG_EPHEMERAL` (never persisted at all, so this bit is + irrelevant on it). Supporting hosts return the boolean `history_exempt` + through `data_processor_config` for transforms and markers. Only a returned + `true` confirms protection: older hosts may silently ignore unknown bits. + Conforming hosts reject unknown flags under the reserved-bits rule, allowing + a deliberate retry without the bit. A missing/false config property or a + failed config read also requires disclosing that protection is unavailable. + ## [0.33.0] Host contract: unchanged (no floor impact) — this release adds the floor diff --git a/VERSION b/VERSION index be386c9e..85e60ed1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.33.0 +0.34.0 diff --git a/pj_base/feature_floors.json b/pj_base/feature_floors.json index 92c8c77b..70d5dd84 100644 --- a/pj_base/feature_floors.json +++ b/pj_base/feature_floors.json @@ -11,6 +11,9 @@ }, "0.32.0": { "setDatasetMetadata": "PJ_data_source_runtime_host_vtable_t::set_dataset_metadata" + }, + "0.34.0": { + "PJ_DATA_PROCESSOR_FLAG_HISTORY_EXEMPT": "" } }, "baseline": [ diff --git a/pj_base/include/pj_base/plugin_data_api.h b/pj_base/include/pj_base/plugin_data_api.h index 6e1a4caa..5ee65d51 100644 --- a/pj_base/include/pj_base/plugin_data_api.h +++ b/pj_base/include/pj_base/plugin_data_api.h @@ -939,7 +939,10 @@ typedef struct { * {"scope":"all"} makes a global node publish across EVERY dataset; * absent = active dataset. * - flags : bitset; PJ_DATA_PROCESSOR_FLAG_EPHEMERAL marks a preview (never - * persisted, dropped on remove). Reserved bits must be 0. + * persisted, dropped on remove). PJ_DATA_PROCESSOR_FLAG_HISTORY_EXEMPT + * marks a node the host's undo/redo history has no authority over + * (still persisted like any other node; history never restores, + * recreates or removes it). Reserved bits must be 0. * * DATASET-QUALIFIED NAMES — a series' full identity is (dataset, topic, field); a * bare "topic/field" name is an abbreviation that stops being unique the moment @@ -974,6 +977,14 @@ typedef struct { /* create_data_processor flags. */ #define PJ_DATA_PROCESSOR_FLAG_EPHEMERAL (1u << 0) /* preview: never persisted, dropped on remove_data_processor */ +/* Persisted in the layout file like any other processor, but the host's undo/redo + * history never restores, recreates or removes it -- history has no authority over + * it. Orthogonal to EPHEMERAL: an EPHEMERAL processor is never persisted at all, so + * this bit is irrelevant on it. A conforming host rejects unknown flag bits. + * To confirm protection even on a host that silently ignores unknown bits, + * read data_processor_config after creation: only history_exempt=true confirms + * the property. A missing/false property or failed read does not confirm it. */ +#define PJ_DATA_PROCESSOR_FLAG_HISTORY_EXEMPT (1u << 1) typedef struct PJ_data_processors_host_vtable_t { uint32_t protocol_version; // = 1 @@ -1010,7 +1021,10 @@ typedef struct PJ_data_processors_host_vtable_t { /* [main-thread] Read a node's full recipe as JSON * {"kind":"...","language":"...","inputs":[...],"outputs":[...],"params":{...}} for * re-edit (e.g. after a session reload). *out_recipe_json is borrowed, valid only - * until the next call on this vtable. An unknown id is an error. */ + * until the next call on this vtable. An unknown id is an error. + * Hosts supporting PJ_DATA_PROCESSOR_FLAG_HISTORY_EXEMPT include the boolean + * "history_exempt" for transforms and markers, reflecting the node's actual + * property. Callers must not infer support from a successful create alone. */ bool (*data_processor_config)( void* ctx, PJ_string_view_t id, PJ_string_view_t* out_recipe_json, PJ_error_t* out_error) PJ_NOEXCEPT; diff --git a/pj_base/include/pj_base/sdk/plugin_data_api.hpp b/pj_base/include/pj_base/sdk/plugin_data_api.hpp index 5e18d964..a1df513c 100644 --- a/pj_base/include/pj_base/sdk/plugin_data_api.hpp +++ b/pj_base/include/pj_base/sdk/plugin_data_api.hpp @@ -1517,7 +1517,9 @@ class DataProcessorsHostView { /// Create or replace (upsert by id) a data processor of `kind` ("transform" or /// "markers"). `outputs` may be empty for an ephemeral preview (flags & - /// PJ_DATA_PROCESSOR_FLAG_EPHEMERAL), in which case the host names the sink(s). + /// PJ_DATA_PROCESSOR_FLAG_EPHEMERAL), in which case the host names the sink(s); + /// flags & PJ_DATA_PROCESSOR_FLAG_HISTORY_EXEMPT instead marks a persisted node the + /// host's undo/redo history has no authority over. /// Returns the resolved physical output topic name(s) (owned copies) so the caller /// can read results back through the kind's read surface. `params_json` is forwarded /// verbatim to the script. Input names MAY carry the dataset qualifier diff --git a/tools/feature_floors/host_surfaces.snapshot b/tools/feature_floors/host_surfaces.snapshot index 8ed8d06d..9834fc27 100644 --- a/tools/feature_floors/host_surfaces.snapshot +++ b/tools/feature_floors/host_surfaces.snapshot @@ -1,4 +1,5 @@ PJ_DATA_PROCESSOR_FLAG_EPHEMERAL +PJ_DATA_PROCESSOR_FLAG_HISTORY_EXEMPT PJ_DESCRIPTOR_IMPORT_START_FLAGS_V1_MASK PJ_DESCRIPTOR_IMPORT_START_FLAG_NONE PJ_INGEST_COMPLETION_FLAGS_V1_MASK