Part of the Pre-Wave-5 consistency reconciliation pass (Tier-0 gates G3, G5 + contract P5). Paper decisions that extend the Wave-5 design addendum (D1–D3) with three shapes the audit found D1–D3 don't cover. No code until these are frozen.
G3 — SDK DeviceSpec shape (impedance mismatch)
The config-layer device spec diverges in shape, not just naming:
- ezo / bread — typed I2C identity:
type enum + numeric address, with cross-device dup-id/dup-address std::set enforcement (ezo config/provider_config.hpp:16-37, bread :25-41).
- sim — opaque
std::map<std::string, YAML::Node> subtree, dup-id only (config.hpp:42-46), because sim devices have free-form, device-type-specific schemas validated downstream.
A too-narrow SDK DeviceSpec (assuming numeric address) breaks sim; a too-loose one (opaque map) loses ezo/bread's dup-address + range validation.
G5 — quality / staleness hook
ezo's read path centralizes quality/staleness/metadata computation in populate_signal_value (src/core/handlers.cpp:304-332): derives QUALITY_OK/STALE/FAULT/UNKNOWN from available/has_value/last_read_ok/age_ms vs stale_after_ms, and packs age_ms/reason/success+failure counts into SignalValue.metadata. sim and bread have no analog (both hard-code QUALITY_OK: sim device_common.hpp:105, bread adapter_helpers.hpp:180).
The D1 SignalSample→SignalValue migration would delete this if done as a naive type swap. This is the real reason D1 is "the highest-risk single step."
P5 — §7.2 default_signal_ids contract
The default-signal-set (§7.2) is satisfied at three different layers: ezo at the handler (default_signal_ids, handlers.cpp:410-416), sim in the device adapter (device_manager.cpp:440), bread per-device via is_default_signal() (rlht_adapter.cpp:76, dcmt_adapter.cpp:117). Only ezo's placement is liftable into a shared handler.
Deliverable: append decisions to working/provider-sdk-wave5-design-addendum.md. Evidence: audit note (G3/G5/P5). Gates the result-type + descriptor lift in #45.
Part of the Pre-Wave-5 consistency reconciliation pass (Tier-0 gates G3, G5 + contract P5). Paper decisions that extend the Wave-5 design addendum (D1–D3) with three shapes the audit found D1–D3 don't cover. No code until these are frozen.
G3 — SDK
DeviceSpecshape (impedance mismatch)The config-layer device spec diverges in shape, not just naming:
typeenum + numericaddress, with cross-device dup-id/dup-addressstd::setenforcement (ezoconfig/provider_config.hpp:16-37, bread:25-41).std::map<std::string, YAML::Node>subtree, dup-id only (config.hpp:42-46), because sim devices have free-form, device-type-specific schemas validated downstream.A too-narrow SDK
DeviceSpec(assuming numeric address) breaks sim; a too-loose one (opaque map) loses ezo/bread's dup-address + range validation.{id, label, optional address, type-as-string}+ opaqueextrasubtree; providers layer their typed enum (ezo/bread) or consume the subtree (sim). Resolve on paper before any config code moves — else it forces a second SDK breaking change.G5 — quality / staleness hook
ezo's read path centralizes quality/staleness/metadata computation in
populate_signal_value(src/core/handlers.cpp:304-332): derivesQUALITY_OK/STALE/FAULT/UNKNOWNfromavailable/has_value/last_read_ok/age_msvsstale_after_ms, and packsage_ms/reason/success+failure counts intoSignalValue.metadata. sim and bread have no analog (both hard-codeQUALITY_OK: simdevice_common.hpp:105, breadadapter_helpers.hpp:180).The D1
SignalSample→SignalValuemigration would delete this if done as a naive type swap. This is the real reason D1 is "the highest-risk single step."quality_from(available, has_value, last_read_ok, age, stale_after) → (QualityCode, metadata)(so all providers can opt in), or keep it inside the ezo adapter. Design before/with the ezo D1 cut.P5 — §7.2
default_signal_idscontractThe default-signal-set (§7.2) is satisfied at three different layers: ezo at the handler (
default_signal_ids,handlers.cpp:410-416), sim in the device adapter (device_manager.cpp:440), bread per-device viais_default_signal()(rlht_adapter.cpp:76,dcmt_adapter.cpp:117). Only ezo's placement is liftable into a shared handler.DeviceDescriptor.default_signal_idscontract surfaced to the SDK; sim/bread expose their curated default set through it so the lifted handler owns the empty-signal_idsbranch uniformly.Deliverable: append decisions to
working/provider-sdk-wave5-design-addendum.md. Evidence: audit note (G3/G5/P5). Gates the result-type + descriptor lift in #45.