From 5aa45654b0e5690b15d20884fba5cb8afce60045 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:11:20 +0200 Subject: [PATCH 01/33] test: reproduce EventMonitor structured payload safety cases (#7) --- tests/test_event_monitor_payload_safety.cpp | 76 +++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 tests/test_event_monitor_payload_safety.cpp diff --git a/tests/test_event_monitor_payload_safety.cpp b/tests/test_event_monitor_payload_safety.cpp new file mode 100644 index 0000000..29eed2a --- /dev/null +++ b/tests/test_event_monitor_payload_safety.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include + +#include +#include + +using namespace ESPressio; + +static void AppendU16(std::vector& data, uint16_t value) { + data.push_back(static_cast(value & 0xffu)); + data.push_back(static_cast((value >> 8u) & 0xffu)); +} + +static std::vector DeepPayload(unsigned depth) { + std::vector data = {'E', 'S', 'P', 'B', 2u}; + for (unsigned level = 0; level < depth; ++level) { + data.push_back(static_cast( + Serializable::SerializationNodeType::Object + )); + AppendU16(data, 1); + AppendU16(data, 1); + data.push_back('x'); + } + data.push_back(static_cast( + Serializable::SerializationNodeType::Null + )); + return data; +} + +int main() { + Serial::EventMonitorConfig config; + config.MaximumStructuredDepth = 8; + config.MaximumStructuredNodes = 128; + config.MaximumCollectionItems = 32; + config.MaximumStringLength = 128; + + Serializable::BinaryArchive validArchive; + validArchive.Write("value", uint32_t(42)); + const auto valid = validArchive.GetData(); + assert(Serial::ValidateStructuredEventPayload( + valid.data(), valid.size(), config + )); + + const auto deep = DeepPayload(16); + assert(!Serial::ValidateStructuredEventPayload( + deep.data(), deep.size(), config + )); + + const std::vector truncated = { + 'E', 'S', 'P', 'B', 2u, + static_cast(Serializable::SerializationNodeType::Object), + 1u, 0u + }; + assert(!Serial::ValidateStructuredEventPayload( + truncated.data(), truncated.size(), config + )); + + // Stress the diagnostic guard with deterministic arbitrary byte sequences. + // The contract is not that random data becomes valid; it is that validation + // remains bounded and never destabilizes the caller. + std::mt19937 rng(0x45564D4Fu); + for (unsigned iteration = 0; iteration < 5000; ++iteration) { + const std::size_t size = 1 + (rng() % 512); + std::vector bytes(size); + for (auto& byte : bytes) { + byte = static_cast(rng()); + } + (void)Serial::ValidateStructuredEventPayload( + bytes.data(), bytes.size(), config + ); + } + + return 0; +} From b7dbb1a6c41abf96d14919341a1fb6cc3f186895 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:11:29 +0200 Subject: [PATCH 02/33] fix: add bounded EventMonitor payload validation (#7) --- .../ESPressio_EventMonitorPayloadSafety.hpp | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/event/ESPressio_EventMonitorPayloadSafety.hpp diff --git a/src/event/ESPressio_EventMonitorPayloadSafety.hpp b/src/event/ESPressio_EventMonitorPayloadSafety.hpp new file mode 100644 index 0000000..1cbfba0 --- /dev/null +++ b/src/event/ESPressio_EventMonitorPayloadSafety.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include +#include +#include + +#include + +#include "../ESPressio_SerialTypes.hpp" + +namespace ESPressio::Serial { + +inline Serializable::BinaryArchiveDecodeLimits +BuildEventMonitorDecodeLimits( + const EventMonitorConfig& config +) noexcept { + Serializable::BinaryArchiveDecodeLimits limits; + + limits.MaximumDepth = + config.MaximumStructuredDepth; + + limits.MaximumTotalNodes = + std::max( + config.MaximumStructuredNodes, + 1 + ); + + const auto maximumCollectionItems = + std::max( + config.MaximumCollectionItems, + 1 + ); + + limits.MaximumObjectMembers = + static_cast( + std::min( + maximumCollectionItems, + UINT32_MAX + ) + ); + + limits.MaximumArrayElements = + static_cast( + std::min( + maximumCollectionItems, + UINT32_MAX + ) + ); + + limits.MaximumNameLength = + std::max( + config.MaximumStringLength, + 1 + ); + + limits.MaximumStringLength = + std::max( + config.MaximumStringLength, + 1 + ); + + return limits; +} + + +inline bool ValidateStructuredEventPayload( + const uint8_t* payload, + std::size_t size, + const EventMonitorConfig& config +) noexcept { + if ( + payload == nullptr || + size == 0 + ) { + return false; + } + + Serializable::BinaryArchive archive; + + return archive.Load( + payload, + size, + BuildEventMonitorDecodeLimits(config) + ); +} + +} // namespace ESPressio::Serial From df280a1fdb3b34399b33973d890bff96669edd19 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:11:36 +0200 Subject: [PATCH 03/33] fix: bound EventMonitor structured node budget (#7) --- src/ESPressio_SerialTypes.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ESPressio_SerialTypes.hpp b/src/ESPressio_SerialTypes.hpp index ed06b91..d44e549 100644 --- a/src/ESPressio_SerialTypes.hpp +++ b/src/ESPressio_SerialTypes.hpp @@ -43,6 +43,7 @@ struct EventMonitorConfig { std::size_t MaximumHexPayloadBytes = 256; std::size_t MaximumCollectionItems = 64; std::size_t MaximumStringLength = 512; + std::size_t MaximumStructuredNodes = 1024; uint8_t MaximumStructuredDepth = 12; uint8_t IndentSpaces = 2; }; From 48e8a4dbf70c6bb8828c6026a02ca5558fe302d1 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:11:57 +0200 Subject: [PATCH 04/33] fix: make EventMonitor structured diagnostics fail safe (#7) --- src/event/ESPressio_EventMonitor.hpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/event/ESPressio_EventMonitor.hpp b/src/event/ESPressio_EventMonitor.hpp index 67c8545..21c0568 100644 --- a/src/event/ESPressio_EventMonitor.hpp +++ b/src/event/ESPressio_EventMonitor.hpp @@ -5,7 +5,7 @@ #endif #if !__has_include() -#error "ESPressio EventMonitor requires ESPressio Serializable >= 0.9.0 < 1.0.0." +#error "ESPressio EventMonitor requires ESPressio Serializable >= 0.10.1 < 1.0.0." #endif #include @@ -15,6 +15,7 @@ #include "../ESPressio_SerialTypes.hpp" #include "ESPressio_EventMonitorFormatter.hpp" +#include "ESPressio_EventMonitorPayloadSafety.hpp" namespace ESPressio::Serial { @@ -163,11 +164,32 @@ class EventMonitor final : return; } + EventMonitorConfig effectiveConfig = + _config; + + if ( + effectiveConfig.PayloadFormat == + EventMonitorPayloadFormat::Structured && + transaction.Payload != nullptr && + transaction.PayloadSize != 0 && + !ValidateStructuredEventPayload( + transaction.Payload, + transaction.PayloadSize, + effectiveConfig + ) + ) { + // Diagnostics must never make an invalid/unreasonable payload + // fatal to the application. Preserve visibility with a bounded + // hex fallback instead of attempting structured tree rendering. + effectiveConfig.PayloadFormat = + EventMonitorPayloadFormat::Hex; + } + EventMonitorFormatter:: PrintTransaction( *_output, transaction, - _config + effectiveConfig ); } }; From 1b7fe5eaf700deaa6f3422a81706a2a51c982ae2 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:12:10 +0200 Subject: [PATCH 05/33] test: add EventMonitor payload safety target (#7) --- tests/CMakeLists.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 29beb05..2288acb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,6 +5,7 @@ enable_testing() set(ESPRESSIO_COMMAND_INCLUDE_DIR "" CACHE PATH "Path containing ESPressio_Command.hpp") set(ESPRESSIO_OBSERVABLE_INCLUDE_DIR "" CACHE PATH "Path containing ESPressio_Observable.hpp") +set(ESPRESSIO_SERIALIZABLE_INCLUDE_DIR "" CACHE PATH "Path containing ESPressio_BinaryArchive.hpp") add_executable( test_console @@ -35,3 +36,18 @@ target_compile_features(test_command_console PRIVATE cxx_std_17) target_compile_options(test_command_console PRIVATE -Wall -Wextra -Wpedantic -Werror) target_include_directories(test_command_console PRIVATE stubs ../src ${ESPRESSIO_COMMAND_INCLUDE_DIR} ${ESPRESSIO_OBSERVABLE_INCLUDE_DIR}) add_test(NAME CommandConsoleContract COMMAND test_command_console) + +add_executable( + test_event_monitor_payload_safety + test_event_monitor_payload_safety.cpp +) + +target_compile_features(test_event_monitor_payload_safety PRIVATE cxx_std_17) +target_compile_options(test_event_monitor_payload_safety PRIVATE -Wall -Wextra -Wpedantic -Werror) +target_include_directories( + test_event_monitor_payload_safety + PRIVATE + ../src + ${ESPRESSIO_SERIALIZABLE_INCLUDE_DIR} +) +add_test(NAME EventMonitorPayloadSafety COMMAND test_event_monitor_payload_safety) From 430c2fd83cd55f816e3b758bfb26881a08d816fb Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:12:29 +0200 Subject: [PATCH 06/33] ci: validate Serial #7 against Serializable #2 fix branch (#7) --- .github/workflows/host-tests.yml | 34 ++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/.github/workflows/host-tests.yml b/.github/workflows/host-tests.yml index de55e1b..5666e49 100644 --- a/.github/workflows/host-tests.yml +++ b/.github/workflows/host-tests.yml @@ -2,7 +2,7 @@ name: Host Tests on: push: - branches: [main, feature/observable-callback-coverage] + branches: [main, bugfix/7-event-monitor-structured-payload-safety] pull_request: jobs: @@ -23,11 +23,18 @@ jobs: repository: Flowduino/ESPressio-Observable ref: 3.0.1 path: deps/ESPressio-Observable + - name: Checkout ESPressio Serializable #2 fix + uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Serializable + ref: bugfix/2-binary-archive-decode-limits + path: deps/ESPressio-Serializable - name: Configure run: >- cmake -S tests -B build -DESPRESSIO_COMMAND_INCLUDE_DIR="$GITHUB_WORKSPACE/deps/ESPressio-Command/src" -DESPRESSIO_OBSERVABLE_INCLUDE_DIR="$GITHUB_WORKSPACE/deps/ESPressio-Observable/src" + -DESPRESSIO_SERIALIZABLE_INCLUDE_DIR="$GITHUB_WORKSPACE/deps/ESPressio-Serializable/src" - name: Build run: cmake --build build --parallel - name: Test @@ -58,6 +65,24 @@ jobs: repository: Flowduino/ESPressio-Timing ref: 2.2.2 path: project/dependencies/ESPressio-Timing + - name: Checkout ESPressio Threads 3.1.2 + uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Threads + ref: 3.1.2 + path: project/dependencies/ESPressio-Threads + - name: Checkout ESPressio Serializable #2 fix + uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Serializable + ref: bugfix/2-binary-archive-decode-limits + path: project/dependencies/ESPressio-Serializable + - name: Checkout ESPressio Event 5.8.0 + uses: actions/checkout@v4 + with: + repository: Flowduino/ESPressio-Event + ref: 5.8.0 + path: project/dependencies/ESPressio-Event - name: Checkout ESPressio Command 0.3.0 uses: actions/checkout@v4 with: @@ -111,6 +136,9 @@ jobs: ../dependencies/ESPressio-Observable ../dependencies/ESPressio-Units ../dependencies/ESPressio-Timing + ../dependencies/ESPressio-Threads + ../dependencies/ESPressio-Serializable + ../dependencies/ESPressio-Event ../ESPressio-Serial EOF cat > project/compile/src/main.cpp <<'EOF' @@ -121,9 +149,11 @@ jobs: #include #include #include + #include + #include void setup() {} void loop() {} EOF - - name: Compile ESP32 Observable monitors + - name: Compile ESP32 Observable and Event monitors run: pio run -d project/compile From 8c2f07ec3037f4e48a8fdb6de711a98272a70810 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:13:22 +0200 Subject: [PATCH 07/33] docs: add Serial 0.5.1 EventMonitor safety changelog (#7) --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0aae0e..5461207 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,23 @@ +## 0.5.1 + +### Fixed + +- Hardened structured `EventMonitor` payload diagnostics so malformed, truncated, excessively nested, or otherwise unreasonable Event Transport payloads cannot be reparsed without monitor-specific decode limits. +- Added fail-safe fallback from `Structured` to bounded `Hex` output whenever a payload fails structured validation. +- Updated Event Monitor's optional Serializable baseline to ESPressio Serializable >= 0.10.1 < 1.0.0, consuming the bounded `BinaryArchive` decoder introduced for Flowduino/ESPressio-Serializable#2. + +### Added + +- Added `MaximumStructuredNodes` to `EventMonitorConfig` alongside the existing collection, string, and nesting limits. +- Added deterministic malformed/deep/random payload regression and stress coverage for the EventMonitor structured-payload validation path. +- Added ESP32 compile validation for `EventMonitor` against Event 5.8.0 and the Serializable 0.10.1 bug-fix generation. + +### Compatibility + +- Core Serial remains dependency-free. +- EventMonitor remains opt-in. +- Existing structured output remains unchanged for payloads that validate successfully. + ## 0.5.0 - Added opt-in `CommandMonitor` for ESPressio Command 0.3.x registry lifecycle observation. From c5f2271249b0be2e4b0f6add64d40d661fd79fcc Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:13:29 +0200 Subject: [PATCH 08/33] build: prepare Serial 0.5.1 patch metadata (#7) --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index bea5822..67f6bb2 100644 --- a/library.json +++ b/library.json @@ -16,7 +16,7 @@ "type": "git", "url": "https://github.com/Flowduino/ESPressio-Serial.git" }, - "version": "0.5.0", + "version": "0.5.1", "license": "Apache-2.0", "frameworks": "arduino", "platforms": "espressif32" From 85c5ad12b5e739b3090f52a482244495b9631328 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:13:36 +0200 Subject: [PATCH 09/33] build: align Arduino metadata for 0.5.1 (#7) --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index c1af497..6c52610 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESPressio-Serial -version=0.5.0 +version=0.5.1 author=Flowduino maintainer=Flowduino sentence=Serial console, diagnostics, logging and operator tooling for the ESPressio ecosystem. From 6d421414195d4b7bc47c21dbecf49122fbf6ffda Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:15:18 +0200 Subject: [PATCH 10/33] docs: update Serial 0.5.1 dependency baseline (#7) --- ESPRESSIO_DEPENDENCY_CHART.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ESPRESSIO_DEPENDENCY_CHART.md b/ESPRESSIO_DEPENDENCY_CHART.md index df06c04..f767346 100644 --- a/ESPRESSIO_DEPENDENCY_CHART.md +++ b/ESPRESSIO_DEPENDENCY_CHART.md @@ -4,7 +4,7 @@ ## Purpose -This document describes the current dependency relationships between ESPressio libraries relevant to ESPressio Serial 0.5.0. +This document describes the current dependency relationships between ESPressio libraries relevant to ESPressio Serial 0.5.1. The chart is hierarchical: libraries with no **required** ESPressio dependencies appear at the top, while libraries that build on progressively more of the ecosystem appear lower. @@ -12,7 +12,7 @@ The chart is hierarchical: libraries with no **required** ESPressio dependencies - **Dashed arrow** — opt-in dependency activated only by the associated feature/header. - Arrows point from the dependent library to the library it consumes. -## ESPressio Serial 0.5.0 +## ESPressio Serial 0.5.1 The ESPressio Serial core and generic `Console` have no required ESPressio dependency. @@ -71,20 +71,20 @@ ESP-Now supplies the Observable transport, peer, and send lifecycle contract. ```text ESPressio Event >= 5.8.0 < 6.0.0 -ESPressio Serializable >= 0.10.0 < 1.0.0 +ESPressio Serializable >= 0.10.1 < 1.0.0 ``` -Event supplies the Event Transport Transaction Observation stream. Serializable supplies structured payload decoding used for human-readable diagnostic output. +Event supplies the Event Transport Transaction Observation stream. Serializable supplies structured payload decoding used for human-readable diagnostic output. Serial 0.5.1 relies on Serializable 0.10.1's bounded `BinaryArchive` decoding and applies additional EventMonitor-specific limits before structured rendering. The legacy EventConsole initialization path remains supported for compatibility. The recommended Command-backed EventConsole integration consumes: ```text ESPressio Command >= 0.3.0 < 1.0.0 ESPressio Event >= 5.8.0 < 6.0.0 -ESPressio Serializable >= 0.10.0 < 1.0.0 +ESPressio Serializable >= 0.10.1 < 1.0.0 ``` -Command supplies the shared `event`/`events` command tree and scoped registration lifetime. Event supplies runtime Serializable Event discovery, descriptors, construction and dispatch. Serializable supplies `JsonArchive` and validation diagnostics. +Command supplies the shared `event`/`events` command tree and scoped registration lifetime. Event supplies runtime Serializable Event discovery, descriptors, construction and dispatch. Serializable supplies `JsonArchive`, validation diagnostics, and bounded BinaryArchive decoding for Event monitoring. The external ArduinoJson dependency is required only by the optional Serializable `JsonArchive`; it is outside this ESPressio-to-ESPressio dependency chart. @@ -104,14 +104,14 @@ ESPressio Threads >= 3.1.2 < 4.0.0 ### Event bridges versus Serial monitors -The 0.5.0 Observable monitors subscribe directly to the originating subsystem. They do not require ESPressio Event. +The 0.5.x Observable monitors subscribe directly to the originating subsystem. They do not require ESPressio Event. ESPressio Event 5.8.0 separately supplies optional Event bridges for Command, Security, Sockets, and ESP-Now when asynchronous Event conversion is desired. Serial diagnostics therefore remain usable without introducing Event as an intermediary. ## Current ecosystem relationships - Observable 3.0.1 has no mandatory ESPressio dependencies. -- Serializable 0.10.0 has no mandatory ESPressio dependencies. +- Serializable 0.10.1 has no mandatory ESPressio dependencies. - Units 0.2.1 optionally consumes Serializable for Serializable Unit counterparts. - Timing 2.2.2 requires Units and Observable. - Threads 3.1.2 requires Timing and Observable. @@ -120,6 +120,6 @@ ESPressio Event 5.8.0 separately supplies optional Event bridges for Command, Se - Sockets 0.5.0 consumes Observable for lifecycle observation and optionally integrates Command and Security. - ESP-Now 0.5.0 requires Timing and Observable and optionally integrates Command, Security, and Event transport functionality. - Event 5.8.0 requires Threads, Timing, and Observable and optionally bridges Security, Command, Sockets, and ESP-Now observer contracts. -- Serial 0.5.0 has no mandatory ESPressio dependencies; Command, Security, Sockets, ESP-Now, Event, Serializable, Timing, and Threads integrations are all opt-in. +- Serial 0.5.1 has no mandatory ESPressio dependencies; Command, Security, Sockets, ESP-Now, Event, Serializable, Timing, and Threads integrations are all opt-in. Applications using only the core ESPressio Serial layer acquire none of these optional ESPressio dependencies. From f83953499225076e1b60c7ed52c0e31ebf6d57e9 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:17:24 +0200 Subject: [PATCH 11/33] fix: report EventMonitor structured decode fallback (#7) --- src/event/ESPressio_EventMonitor.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/event/ESPressio_EventMonitor.hpp b/src/event/ESPressio_EventMonitor.hpp index 21c0568..e4c4580 100644 --- a/src/event/ESPressio_EventMonitor.hpp +++ b/src/event/ESPressio_EventMonitor.hpp @@ -181,6 +181,10 @@ class EventMonitor final : // Diagnostics must never make an invalid/unreasonable payload // fatal to the application. Preserve visibility with a bounded // hex fallback instead of attempting structured tree rendering. + _output->println( + "[ESPressio Event] structured payload rejected; using bounded hex fallback" + ); + effectiveConfig.PayloadFormat = EventMonitorPayloadFormat::Hex; } From 6f40aa8807973d3c0bec15f1a41f0f5d755ab74b Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:22:13 +0200 Subject: [PATCH 12/33] fix: stream structured Event payloads without tree allocation (#7) --- .../ESPressio_EventMonitorPayloadSafety.hpp | 369 +++++++++++++++++- 1 file changed, 365 insertions(+), 4 deletions(-) diff --git a/src/event/ESPressio_EventMonitorPayloadSafety.hpp b/src/event/ESPressio_EventMonitorPayloadSafety.hpp index 1cbfba0..f42e4f0 100644 --- a/src/event/ESPressio_EventMonitorPayloadSafety.hpp +++ b/src/event/ESPressio_EventMonitorPayloadSafety.hpp @@ -1,10 +1,14 @@ #pragma once #include +#include #include #include +#include +#include -#include +#include +#include #include "../ESPressio_SerialTypes.hpp" @@ -67,20 +71,377 @@ inline bool ValidateStructuredEventPayload( const uint8_t* payload, std::size_t size, const EventMonitorConfig& config +) noexcept { + return Serializable::ValidateBinaryArchive( + payload, + size, + BuildEventMonitorDecodeLimits(config) + ); +} + + +namespace EventMonitorPayloadSafetyDetail { + +inline void PrintIndent( + Print& output, + std::size_t depth, + uint8_t spaces +) noexcept { + const std::size_t count = + depth * static_cast(spaces); + + for (std::size_t index = 0; index < count; ++index) { + output.write(static_cast(' ')); + } +} + + +inline void PrintEscapedString( + Print& output, + std::string_view value, + std::size_t maximumLength +) noexcept { + output.write(static_cast('"')); + + const std::size_t length = + std::min(value.size(), maximumLength); + + for (std::size_t index = 0; index < length; ++index) { + const unsigned char character = + static_cast(value[index]); + + switch (character) { + case '"': output.print("\\\""); break; + case '\\': output.print("\\\\"); break; + case '\b': output.print("\\b"); break; + case '\f': output.print("\\f"); break; + case '\n': output.print("\\n"); break; + case '\r': output.print("\\r"); break; + case '\t': output.print("\\t"); break; + + default: + if (character < 0x20u) { + char escaped[7]; + std::snprintf( + escaped, + sizeof(escaped), + "\\u%04X", + static_cast(character) + ); + output.print(escaped); + } else { + output.write(static_cast(character)); + } + break; + } + } + + if (value.size() > maximumLength) { + output.print("..."); + } + + output.write(static_cast('"')); +} + + +class StructuredPayloadPrinter final : + public Serializable::BinaryArchiveVisitor { +private: + Print& _output; + const EventMonitorConfig& _config; + + void BeforeCollectionItem( + uint32_t index, + std::size_t depth + ) noexcept { + if (index > 0) { + _output.write(static_cast(',')); + } + + if (_config.PrettyStructuredPayload) { + _output.println(); + PrintIndent( + _output, + depth + 1, + _config.IndentSpaces + ); + } + } + + void CloseCollection( + uint32_t count, + std::size_t depth, + char close + ) noexcept { + if ( + _config.PrettyStructuredPayload && + count > 0 + ) { + _output.println(); + PrintIndent( + _output, + depth, + _config.IndentSpaces + ); + } + + _output.write(static_cast(close)); + } + +public: + StructuredPayloadPrinter( + Print& output, + const EventMonitorConfig& config + ) noexcept : + _output(output), + _config(config) { + } + + bool OnObjectBegin( + uint32_t, + std::size_t + ) noexcept override { + _output.write(static_cast('{')); + return true; + } + + bool OnObjectProperty( + std::string_view name, + uint32_t index, + uint32_t, + std::size_t depth + ) noexcept override { + BeforeCollectionItem(index, depth); + PrintEscapedString( + _output, + name, + _config.MaximumStringLength + ); + _output.print( + _config.PrettyStructuredPayload + ? ": " + : ":" + ); + return true; + } + + bool OnObjectEnd( + uint32_t count, + std::size_t depth + ) noexcept override { + CloseCollection(count, depth, '}'); + return true; + } + + bool OnArrayBegin( + uint32_t, + std::size_t + ) noexcept override { + _output.write(static_cast('[')); + return true; + } + + bool OnArrayElement( + uint32_t index, + uint32_t, + std::size_t depth + ) noexcept override { + BeforeCollectionItem(index, depth); + return true; + } + + bool OnArrayEnd( + uint32_t count, + std::size_t depth + ) noexcept override { + CloseCollection(count, depth, ']'); + return true; + } + + bool OnNull( + std::size_t + ) noexcept override { + _output.print("null"); + return true; + } + + bool OnBoolean( + bool value, + std::size_t + ) noexcept override { + _output.print(value ? "true" : "false"); + return true; + } + + bool OnSignedInteger( + int64_t value, + std::size_t + ) noexcept override { + char buffer[32]; + std::snprintf( + buffer, + sizeof(buffer), + "%" PRId64, + value + ); + _output.print(buffer); + return true; + } + + bool OnUnsignedInteger( + uint64_t value, + std::size_t + ) noexcept override { + char buffer[32]; + std::snprintf( + buffer, + sizeof(buffer), + "%" PRIu64, + value + ); + _output.print(buffer); + return true; + } + + bool OnFloat32( + float value, + std::size_t + ) noexcept override { + char buffer[32]; + std::snprintf( + buffer, + sizeof(buffer), + "%.7g", + static_cast(value) + ); + _output.print(buffer); + return true; + } + + bool OnFloat64( + double value, + std::size_t + ) noexcept override { + char buffer[48]; + std::snprintf( + buffer, + sizeof(buffer), + "%.15g", + value + ); + _output.print(buffer); + return true; + } + + bool OnString( + std::string_view value, + std::size_t + ) noexcept override { + PrintEscapedString( + _output, + value, + _config.MaximumStringLength + ); + return true; + } +}; + + +inline void PrintHexPayload( + Print& output, + const uint8_t* payload, + std::size_t size, + std::size_t maximumBytes +) noexcept { + if ( + payload == nullptr || + size == 0 + ) { + output.print(""); + return; + } + + const std::size_t count = + std::min(size, maximumBytes); + + for (std::size_t index = 0; index < count; ++index) { + if (index > 0) { + output.write(static_cast(' ')); + } + + char byte[3]; + std::snprintf( + byte, + sizeof(byte), + "%02X", + static_cast(payload[index]) + ); + output.print(byte); + } + + if (count < size) { + output.print(" ..."); + } +} + +} // namespace EventMonitorPayloadSafetyDetail + + +inline bool PrintStructuredEventPayload( + Print& output, + const uint8_t* payload, + std::size_t size, + const EventMonitorConfig& config ) noexcept { if ( payload == nullptr || size == 0 + ) { + output.print(""); + return true; + } + + const auto limits = + BuildEventMonitorDecodeLimits(config); + + // Validate first so malformed input never leaves a partially rendered + // structured diagnostic line. Both passes are allocation-free. + if ( + !Serializable::ValidateBinaryArchive( + payload, + size, + limits + ) ) { return false; } - Serializable::BinaryArchive archive; + EventMonitorPayloadSafetyDetail:: + StructuredPayloadPrinter visitor( + output, + config + ); - return archive.Load( + return Serializable::TraverseBinaryArchive( payload, size, - BuildEventMonitorDecodeLimits(config) + visitor, + limits + ); +} + + +inline void PrintEventPayloadHexFallback( + Print& output, + const uint8_t* payload, + std::size_t size, + const EventMonitorConfig& config +) noexcept { + EventMonitorPayloadSafetyDetail::PrintHexPayload( + output, + payload, + size, + config.MaximumHexPayloadBytes ); } From 3cf8251decc64973a07092353980d4f9e2c35ad4 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:22:34 +0200 Subject: [PATCH 13/33] fix: bypass tree-building formatter for structured payloads (#7) --- src/event/ESPressio_EventMonitor.hpp | 68 ++++++++++++++++++---------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/src/event/ESPressio_EventMonitor.hpp b/src/event/ESPressio_EventMonitor.hpp index e4c4580..caf84b9 100644 --- a/src/event/ESPressio_EventMonitor.hpp +++ b/src/event/ESPressio_EventMonitor.hpp @@ -4,7 +4,7 @@ #error "ESPressio EventMonitor requires ESPressio Event >= 5.6.2 < 6.0.0." #endif -#if !__has_include() +#if !__has_include() #error "ESPressio EventMonitor requires ESPressio Serializable >= 0.10.1 < 1.0.0." #endif @@ -164,37 +164,59 @@ class EventMonitor final : return; } - EventMonitorConfig effectiveConfig = - _config; - if ( - effectiveConfig.PayloadFormat == - EventMonitorPayloadFormat::Structured && - transaction.Payload != nullptr && - transaction.PayloadSize != 0 && - !ValidateStructuredEventPayload( - transaction.Payload, - transaction.PayloadSize, - effectiveConfig - ) + _config.PayloadFormat != + EventMonitorPayloadFormat::Structured ) { - // Diagnostics must never make an invalid/unreasonable payload - // fatal to the application. Preserve visibility with a bounded - // hex fallback instead of attempting structured tree rendering. - _output->println( - "[ESPressio Event] structured payload rejected; using bounded hex fallback" - ); - - effectiveConfig.PayloadFormat = - EventMonitorPayloadFormat::Hex; + EventMonitorFormatter:: + PrintTransaction( + *_output, + transaction, + _config + ); + return; } + // Print the transaction metadata through the established formatter, but + // suppress its legacy tree-building structured payload path. The + // payload itself is then traversed directly from ESPB bytes without + // constructing a second SerializationNode tree. + EventMonitorConfig metadataConfig = + _config; + metadataConfig.PayloadFormat = + EventMonitorPayloadFormat::None; + EventMonitorFormatter:: PrintTransaction( *_output, transaction, - effectiveConfig + metadataConfig ); + + _output->print(" payload: "); + + if ( + PrintStructuredEventPayload( + *_output, + transaction.Payload, + transaction.PayloadSize, + _config + ) + ) { + _output->println(); + return; + } + + _output->print( + " " + ); + PrintEventPayloadHexFallback( + *_output, + transaction.Payload, + transaction.PayloadSize, + _config + ); + _output->println(); } }; From f3b667845b7604551249612eaa98a2c998a625cd Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:22:52 +0200 Subject: [PATCH 14/33] test: verify allocation-free structured EventMonitor output (#7) --- tests/test_event_monitor_payload_safety.cpp | 54 ++++++++++++++++++--- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/tests/test_event_monitor_payload_safety.cpp b/tests/test_event_monitor_payload_safety.cpp index 29eed2a..8df9389 100644 --- a/tests/test_event_monitor_payload_safety.cpp +++ b/tests/test_event_monitor_payload_safety.cpp @@ -1,13 +1,25 @@ #include #include #include +#include #include +#include #include #include using namespace ESPressio; +class BufferPrint final : public Print { +public: + std::string Data; + + std::size_t write(uint8_t value) override { + Data.push_back(static_cast(value)); + return 1; + } +}; + static void AppendU16(std::vector& data, uint16_t value) { data.push_back(static_cast(value & 0xffu)); data.push_back(static_cast((value >> 8u) & 0xffu)); @@ -43,10 +55,36 @@ int main() { valid.data(), valid.size(), config )); + // Structured output is rendered directly from ESPB bytes and does not need + // a second SerializationNode tree. + { + BufferPrint output; + assert(Serial::PrintStructuredEventPayload( + output, + valid.data(), + valid.size(), + config + )); + assert(output.Data.find("\"value\"") != std::string::npos); + assert(output.Data.find("42") != std::string::npos); + } + const auto deep = DeepPayload(16); assert(!Serial::ValidateStructuredEventPayload( deep.data(), deep.size(), config )); + { + BufferPrint output; + assert(!Serial::PrintStructuredEventPayload( + output, + deep.data(), + deep.size(), + config + )); + // Validation runs before presentation, so rejected input never emits a + // half-rendered structured payload. + assert(output.Data.empty()); + } const std::vector truncated = { 'E', 'S', 'P', 'B', 2u, @@ -57,18 +95,18 @@ int main() { truncated.data(), truncated.size(), config )); - // Stress the diagnostic guard with deterministic arbitrary byte sequences. - // The contract is not that random data becomes valid; it is that validation - // remains bounded and never destabilizes the caller. + // Stress the allocation-free diagnostic guard with deterministic arbitrary + // byte sequences. The contract is bounded rejection without constructing + // tree state or destabilizing the caller. std::mt19937 rng(0x45564D4Fu); + std::vector bytes(512); for (unsigned iteration = 0; iteration < 5000; ++iteration) { - const std::size_t size = 1 + (rng() % 512); - std::vector bytes(size); - for (auto& byte : bytes) { - byte = static_cast(rng()); + const std::size_t size = 1 + (rng() % bytes.size()); + for (std::size_t index = 0; index < size; ++index) { + bytes[index] = static_cast(rng()); } (void)Serial::ValidateStructuredEventPayload( - bytes.data(), bytes.size(), config + bytes.data(), size, config ); } From e9b48b7017c503e81fb1e3ba724bb2ccbbc1ca11 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:23:09 +0200 Subject: [PATCH 15/33] test: compile EventMonitor safety test with Arduino Print stub (#7) --- tests/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2288acb..10eddfc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -47,6 +47,7 @@ target_compile_options(test_event_monitor_payload_safety PRIVATE -Wall -Wextra - target_include_directories( test_event_monitor_payload_safety PRIVATE + stubs ../src ${ESPRESSIO_SERIALIZABLE_INCLUDE_DIR} ) From 3d19ae65efbc2c18ece503cf46b337bb1973aee4 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:28:41 +0200 Subject: [PATCH 16/33] docs: document Serial 0.5.1 allocation-free EventMonitor diagnostics (#7) --- README.md | 51 +++++++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index a2b9561..c4a3c23 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ Serial and console-oriented components for the Flowduino ESPressio Development Platform. -Version 0.5.0 expands ESPressio Serial diagnostics with opt-in Observable-backed monitors for ESPressio Command, Security, Sockets, and ESP-Now while preserving the dependency-free Serial core and existing Console/Event integrations. +Version 0.5.1 hardens the opt-in Event Monitor so structured Event Transport diagnostics are rendered directly from bounded ESPB bytes without constructing a second heap-backed `SerializationNode` tree. It retains the Observable-backed monitors introduced in 0.5.0 while preserving the dependency-free Serial core and existing Console/Event integrations. -## Current Version — 0.5.0 +## Current Version — 0.5.1 -Version **0.5.0** extends Serial's diagnostics layer to consume the Observable lifecycle contracts provided by ESPressio Command, Security, Sockets, and ESP-Now. +Version **0.5.1** fixes the structured EventMonitor crash path reproduced on ESP32 under low-memory conditions. Structured diagnostics now use ESPressio Serializable 0.10.1's allocation-free BinaryArchive traversal API with explicit depth, aggregate-node, collection, name, and string limits. Invalid or outside-limit payloads fall back to bounded hexadecimal output rather than becoming fatal diagnostic work. -Core ESPressio Serial remains free of mandatory ESPressio-library dependencies. The new monitors are selected only when their corresponding upstream headers are available: +The Observable-backed monitor integrations introduced in 0.5.0 remain available unchanged: ```text CommandMonitor @@ -76,10 +76,10 @@ The Event Monitor is deliberately opt-in and requires: ```text ESPressio Event >= 5.8.0 < 6.0.0 -ESPressio Serializable >= 0.10.0 < 1.0.0 +ESPressio Serializable >= 0.10.1 < 1.0.0 ``` -The additional opt-in monitoring dependencies for 0.5.0 are listed above. Historical sections below retain older release-specific baselines where those versions are part of the documented history. +The additional opt-in monitoring dependencies for the 0.5.x line are listed above. Historical sections below retain older release-specific baselines where those versions are part of the documented history. For the complete ecosystem hierarchy, see: @@ -672,7 +672,7 @@ ThreadMonitor EventMonitor - - -> ESPressio Event >= 5.8.0 < 6.0.0 - - - -> ESPressio Serializable >= 0.10.0 < 1.0.0 + - - -> ESPressio Serializable >= 0.10.1 < 1.0.0 ``` All ESPressio relationships remain opt-in. The 0.5.0 observer monitors add the additional optional relationships documented near the top of this README. @@ -876,16 +876,13 @@ config.MaximumHexPayloadBytes `Structured` is the default. -ESPressio Event Transport serializes Event payloads using ESPressio Serializable's `BinaryArchive`. - -The monitor decodes that Binary Archive into Serializable's generic `SerializationNode` tree and renders it directly as JSON-like structured text. +ESPressio Event Transport serializes Event payloads using ESPressio Serializable's BinaryArchive ESPB v2 representation. -This has two important advantages: +Beginning with Serial 0.5.1, EventMonitor does **not** decode that payload into a second `SerializationNode` tree merely for presentation. Instead, it uses Serializable 0.10.1's `TraverseBinaryArchive()` API to validate and stream the existing ESPB bytes directly to the selected Arduino `Print` destination. -1. the monitor does not need to know the concrete C++ Event type; -2. it does not require ArduinoJson merely to present human-readable diagnostics. +This keeps human-readable structured diagnostics independent of the concrete C++ Event type and avoids ArduinoJson, while removing duplicate payload-tree allocations from the synchronous Event Transport observer path. -The monitor is therefore able to inspect arbitrary transported Serializable Event payloads using the schema already encoded in the Binary Archive. +If the payload is malformed or exceeds the configured diagnostic limits, EventMonitor prints a bounded hexadecimal fallback rather than attempting structured tree construction. --- @@ -898,12 +895,13 @@ Configuration includes: ```cpp MaximumCollectionItems MaximumStringLength +MaximumStructuredNodes MaximumStructuredDepth IndentSpaces PrettyStructuredPayload ``` -These provide deterministic limits when monitoring large or deeply nested Event payloads. +These limits are applied while validating/traversing ESPB bytes before structured output is emitted. `MaximumStructuredNodes` bounds aggregate payload-tree breadth as well as the existing collection/string/depth controls. --- @@ -932,11 +930,11 @@ Inbound and outbound monitoring can also be enabled independently. # Borrowed Event Transport data -ESPressio Event 5.5 transaction snapshots expose borrowed Event/payload references valid only during the Observer callback. +ESPressio Event transaction snapshots expose borrowed Event/payload references valid only during the Observer callback. `EventMonitor` consumes those values synchronously and does not retain borrowed transaction pointers after the callback returns. -Structured decoding is therefore performed while the payload is valid. +Structured traversal is therefore performed while the payload is valid, without copying it into a second tree. --- @@ -971,7 +969,7 @@ examples/ The example uses a small local `LoopbackEventTransport` so both outbound and inbound transactions can be demonstrated on a single ESP32 without networking or additional hardware. -It defines a Serializable counter Event, transports it through Event 5.5, and renders the Binary payload as structured text. +It defines a Serializable counter Event, transports it through Event, and renders the Binary payload as structured text. --- @@ -981,16 +979,16 @@ A project using only the core Serial library: ```ini lib_deps = - flowduino/ESPressio-Serial@^0.5.0 + flowduino/ESPressio-Serial@^0.5.1 ``` An application using Event Monitor requires: ```ini lib_deps = - flowduino/ESPressio-Serial@^0.5.0 + flowduino/ESPressio-Serial@^0.5.1 flowduino/ESPressio-Event@^5.8.0 - flowduino/ESPressio-Serializable@^0.10.0 + flowduino/ESPressio-Serializable@^0.10.1 ``` The Event/Serializable dependencies are intentionally not declared as mandatory package dependencies of ESPressio Serial because they are required only by the opt-in Event Monitor feature. @@ -1004,16 +1002,16 @@ The generic console requires only ESPressio Serial: ```ini lib_deps = - flowduino/ESPressio-Serial@^0.5.0 + flowduino/ESPressio-Serial@^0.5.1 ``` The Event Console additionally requires the runtime Event and JSON stacks: ```ini lib_deps = - flowduino/ESPressio-Serial@^0.5.0 + flowduino/ESPressio-Serial@^0.5.1 flowduino/ESPressio-Event@^5.8.0 - flowduino/ESPressio-Serializable@^0.10.0 + flowduino/ESPressio-Serializable@^0.10.1 bblanchon/ArduinoJson ``` @@ -1045,7 +1043,7 @@ Hardware-radio implementations belong in the planned **ESPressio Radio** library # Summary -ESPressio Serial 0.3.0 provides three complementary layers: +ESPressio Serial provides three complementary layers: ```text CORE @@ -1060,6 +1058,7 @@ DIAGNOSTICS / LOGGING SystemClockMonitor [opt-in Timing] ThreadMonitor [opt-in Threads] EventMonitor [opt-in Event + Serializable] + Command/Security/Sockets/ESP-Now monitors [opt-in] DiagnosticMonitor OPERATOR CONSOLE @@ -1068,7 +1067,7 @@ OPERATOR CONSOLE Print output extensible commands - EventConsole [opt-in Event 5.6 + Serializable JSON] + EventConsole [opt-in Event + Serializable JSON] runtime Event discovery schema description JSON composition From ff12bcb5d9f292e8edce9171977298afca9ecb2e Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:29:17 +0200 Subject: [PATCH 17/33] docs: record allocation-free structured EventMonitor path (#7) --- CHANGELOG.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5461207..5a63355 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,10 @@ ### Fixed -- Hardened structured `EventMonitor` payload diagnostics so malformed, truncated, excessively nested, or otherwise unreasonable Event Transport payloads cannot be reparsed without monitor-specific decode limits. -- Added fail-safe fallback from `Structured` to bounded `Hex` output whenever a payload fails structured validation. -- Updated Event Monitor's optional Serializable baseline to ESPressio Serializable >= 0.10.1 < 1.0.0, consuming the bounded `BinaryArchive` decoder introduced for Flowduino/ESPressio-Serializable#2. +- Replaced EventMonitor's tree-building `BinaryArchive::Load()` diagnostic path with bounded, allocation-free ESPB traversal from ESPressio Serializable 0.10.1, preventing valid payload diagnostics from requiring a second heap-backed `SerializationNode` tree. +- Hardened structured `EventMonitor` payload diagnostics so malformed, truncated, excessively nested, or otherwise unreasonable Event Transport payloads are rejected under monitor-specific decode limits. +- Added fail-safe fallback from `Structured` to bounded `Hex` output whenever a payload fails structured validation or exceeds the configured monitor limits. +- Updated Event Monitor's optional Serializable baseline to ESPressio Serializable >= 0.10.1 < 1.0.0, consuming the bounded/allocation-free BinaryArchive facilities introduced for Flowduino/ESPressio-Serializable#2. ### Added @@ -16,7 +17,7 @@ - Core Serial remains dependency-free. - EventMonitor remains opt-in. -- Existing structured output remains unchanged for payloads that validate successfully. +- Existing structured output remains JSON-like and source-compatible for payloads that validate successfully. ## 0.5.0 From 0d0bc2f6fcebb1bc55b79dd6b947f8b3e2d67bb1 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 22:30:22 +0200 Subject: [PATCH 18/33] ci: pin Serializable #2 validation commit (#7) --- .github/workflows/host-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/host-tests.yml b/.github/workflows/host-tests.yml index 5666e49..977a704 100644 --- a/.github/workflows/host-tests.yml +++ b/.github/workflows/host-tests.yml @@ -27,7 +27,7 @@ jobs: uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Serializable - ref: bugfix/2-binary-archive-decode-limits + ref: b4c5fa6045c8debf1371f74512ea8bf602d25877 path: deps/ESPressio-Serializable - name: Configure run: >- @@ -75,7 +75,7 @@ jobs: uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Serializable - ref: bugfix/2-binary-archive-decode-limits + ref: b4c5fa6045c8debf1371f74512ea8bf602d25877 path: project/dependencies/ESPressio-Serializable - name: Checkout ESPressio Event 5.8.0 uses: actions/checkout@v4 From 18f3b90fb6b8dfd168e463808ce8b554bf752b01 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 23:49:30 +0200 Subject: [PATCH 19/33] ci: refresh Serial 0.5.1 README on dependency branch (#8) --- .github/workflows/readme-refresh.yml | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/readme-refresh.yml diff --git a/.github/workflows/readme-refresh.yml b/.github/workflows/readme-refresh.yml new file mode 100644 index 0000000..0296e5b --- /dev/null +++ b/.github/workflows/readme-refresh.yml @@ -0,0 +1,50 @@ +name: Refresh dependency README + +on: + push: + branches: + - feature/8-dependency-refresh-0.5.1 + +permissions: + contents: write + +jobs: + refresh: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: feature/8-dependency-refresh-0.5.1 + - name: Refresh current-version documentation + shell: python + run: | + from pathlib import Path + path = Path('README.md') + text = path.read_text() + replacements = [ + ('ESPNowTransportMonitor\n - - -> ESPressio ESP-Now >= 0.5.0 < 1.0.0', 'ESPNowTransportMonitor\n - - -> ESPressio ESP-Now >= 0.5.1 < 1.0.0'), + ('Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.0.', 'Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.1.'), + ('ESPressio Event >= 5.8.0 < 6.0.0\nESPressio Serializable >= 0.10.1 < 1.0.0', 'ESPressio Event >= 5.8.1 < 6.0.0\nESPressio Serializable >= 0.10.1 < 1.0.0'), + ] + for old, new in replacements: + if old not in text: + raise SystemExit(f'missing expected README text: {old}') + text = text.replace(old, new, 1) + text = text.replace('flowduino/ESPressio-Event@^5.8.0', 'flowduino/ESPressio-Event@^5.8.1') + text = text.replace('flowduino/ESPressio-Serial@^0.5.0', 'flowduino/ESPressio-Serial@^0.5.1') + marker = 'Historical documentation for earlier release generations remains below where useful.\n' + addition = marker + '\nCurrent coordinated dependency baselines for the 0.5.1 release are Units 0.2.2, Timing 2.2.3, Threads 3.1.3, ESP-Now 0.5.1, Event 5.8.1, and Serializable 0.10.1. Command 0.3.0, Security 0.2.0, and Sockets 0.5.0 remain the current optional integration baselines.\n' + if addition not in text: + if marker not in text: + raise SystemExit('missing historical marker') + text = text.replace(marker, addition, 1) + path.write_text(text) + - name: Commit README + run: | + if git diff --quiet -- README.md; then exit 0; fi + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + git add -- README.md + git commit -m 'docs: refresh Serial 0.5.1 dependency README (#8)' + git push origin HEAD:feature/8-dependency-refresh-0.5.1 From 75fd7ee8d5bbcbe9c756ed7ad7ad8a01f8176df4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2026 21:49:40 +0000 Subject: [PATCH 20/33] docs: refresh Serial 0.5.1 dependency README (#8) --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c4a3c23..88e0fae 100644 --- a/README.md +++ b/README.md @@ -25,15 +25,17 @@ SocketSecuritySessionMonitor - - -> ESPressio Security >= 0.2.0 < 1.0.0 ESPNowTransportMonitor - - - -> ESPressio ESP-Now >= 0.5.0 < 1.0.0 + - - -> ESPressio ESP-Now >= 0.5.1 < 1.0.0 ``` `DiagnosticMonitor` can additionally compose `CommandMonitor` and `ESPNowTransportMonitor` when those dependencies are present. Security and Socket monitors remain instance-oriented because the application must choose the specific `TransportSecurity`, `SocketWorker`, or `SocketSecuritySession` object to observe. -These monitors subscribe directly to the originating library's Observable contract. They do not invent parallel Serial lifecycle semantics and do not require ESPressio Event. Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.0. +These monitors subscribe directly to the originating library's Observable contract. They do not invent parallel Serial lifecycle semantics and do not require ESPressio Event. Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.1. Historical documentation for earlier release generations remains below where useful. +Current coordinated dependency baselines for the 0.5.1 release are Units 0.2.2, Timing 2.2.3, Threads 3.1.3, ESP-Now 0.5.1, Event 5.8.1, and Serializable 0.10.1. Command 0.3.0, Security 0.2.0, and Sockets 0.5.0 remain the current optional integration baselines. + ## ESPressio Development Platform ESPressio is a collection of discrete, composable component libraries designed around a common development ethos: @@ -75,7 +77,7 @@ The **core ESPressio Serial library has no required ESPressio library dependenci The Event Monitor is deliberately opt-in and requires: ```text -ESPressio Event >= 5.8.0 < 6.0.0 +ESPressio Event >= 5.8.1 < 6.0.0 ESPressio Serializable >= 0.10.1 < 1.0.0 ``` @@ -987,7 +989,7 @@ An application using Event Monitor requires: ```ini lib_deps = flowduino/ESPressio-Serial@^0.5.1 - flowduino/ESPressio-Event@^5.8.0 + flowduino/ESPressio-Event@^5.8.1 flowduino/ESPressio-Serializable@^0.10.1 ``` @@ -1010,7 +1012,7 @@ The Event Console additionally requires the runtime Event and JSON stacks: ```ini lib_deps = flowduino/ESPressio-Serial@^0.5.1 - flowduino/ESPressio-Event@^5.8.0 + flowduino/ESPressio-Event@^5.8.1 flowduino/ESPressio-Serializable@^0.10.1 bblanchon/ArduinoJson ``` From a9e640896b03927d319bd7cfb0f3daad90650dde Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Thu, 20 Aug 2026 23:54:12 +0200 Subject: [PATCH 21/33] docs: refresh Serial 0.5.1 dependency chart (#8) --- ESPRESSIO_DEPENDENCY_CHART.md | 175 +++++++++++++++++----------------- 1 file changed, 89 insertions(+), 86 deletions(-) diff --git a/ESPRESSIO_DEPENDENCY_CHART.md b/ESPRESSIO_DEPENDENCY_CHART.md index f767346..bc893c3 100644 --- a/ESPRESSIO_DEPENDENCY_CHART.md +++ b/ESPRESSIO_DEPENDENCY_CHART.md @@ -1,125 +1,128 @@ -# ESPressio Dependency Chart +# ESPressio Dependency Chart — Serial 0.5.1 ![ESPressio Library Dependency Chart](ESPRESSIO_DEPENDENCY_CHART.png) -## Purpose - -This document describes the current dependency relationships between ESPressio libraries relevant to ESPressio Serial 0.5.1. - -The chart is hierarchical: libraries with no **required** ESPressio dependencies appear at the top, while libraries that build on progressively more of the ecosystem appear lower. - -- **Solid arrow** — required ESPressio dependency. -- **Dashed arrow** — opt-in dependency activated only by the associated feature/header. -- Arrows point from the dependent library to the library it consumes. - ## ESPressio Serial 0.5.1 -The ESPressio Serial core and generic `Console` have no required ESPressio dependency. +The Serial core and generic `Console` have no mandatory ESPressio dependencies. +All ESPressio integrations remain opt-in. -All integrations remain opt-in. - -### CommandConsole and CommandMonitor - -`CommandConsole` and `CommandMonitor` consume: +### Current integration baselines ```text -ESPressio Command >= 0.3.0 < 1.0.0 -``` +CommandConsole / CommandMonitor + - - -> ESPressio Command >= 0.3.0 < 1.0.0 -Command supplies the transport-neutral typed Command registry, parsing, validation, invocation, help/completion metadata, scoped command registration, and Observable registry lifecycle used by Serial's Command integrations. +SecurityMonitor + - - -> ESPressio Security >= 0.2.0 < 1.0.0 -### SecurityMonitor +SocketWorkerMonitor + - - -> ESPressio Sockets >= 0.5.0 < 1.0.0 -`SecurityMonitor` consumes: +SocketSecuritySessionMonitor + - - -> ESPressio Sockets >= 0.5.0 < 1.0.0 + - - -> ESPressio Security >= 0.2.0 < 1.0.0 -```text -ESPressio Security >= 0.2.0 < 1.0.0 -``` +ESPNowTransportMonitor + - - -> ESPressio ESP-Now >= 0.5.1 < 1.0.0 -Security supplies the Observable configuration, secure-session, replay-protection, and failure lifecycle observed directly by the monitor. +SystemClockMonitor + - - -> ESPressio Timing >= 2.2.3 < 3.0.0 -### Socket monitors +ThreadMonitor + - - -> ESPressio Threads >= 3.1.3 < 4.0.0 -`SocketWorkerMonitor` consumes: - -```text -ESPressio Sockets >= 0.5.0 < 1.0.0 +EventMonitor / EventConsole + - - -> ESPressio Event >= 5.8.1 < 6.0.0 + - - -> ESPressio Serializable >= 0.10.1 < 1.0.0 ``` -`SocketSecuritySessionMonitor` consumes: - -```text -ESPressio Sockets >= 0.5.0 < 1.0.0 -ESPressio Security >= 0.2.0 < 1.0.0 -``` +EventMonitor 0.5.1 specifically uses Serializable 0.10.1's bounded, +allocation-free ESPB traversal API for structured diagnostics. -Sockets supplies the Observable socket worker and secure-session lifecycle contracts. Security is only relevant to the secure-session integration. - -### ESPNowTransportMonitor - -`ESPNowTransportMonitor` consumes: +## Current coordinated ecosystem ```text -ESPressio ESP-Now >= 0.5.0 < 1.0.0 +FOUNDATIONAL +├── Observable 3.0.1 +├── Serializable 0.10.1 +├── Units 0.2.2 +├── Security 0.2.0 +└── Command 0.3.0 + +RUNTIME +└── Timing 2.2.3 + ├── Units >= 0.2.2 < 1.0.0 + └── Observable >= 3.0.1 < 4.0.0 + +EXECUTION +└── Threads 3.1.3 + ├── Timing >= 2.2.3 < 3.0.0 + └── Observable >= 3.0.1 < 4.0.0 + +TRANSPORT / INTEGRATION +├── Sockets 0.5.0 +└── ESP-Now 0.5.1 + +EVENT +└── Event 5.8.1 + ├── Threads >= 3.1.3 < 4.0.0 + ├── Timing >= 2.2.3 < 3.0.0 + ├── Observable >= 3.0.1 < 4.0.0 + └── Serializable >= 0.10.1 < 1.0.0 [optional] + +DIAGNOSTICS / OPERATOR +└── Serial 0.5.1 ``` -ESP-Now supplies the Observable transport, peer, and send lifecycle contract. +## Dependency-direction rule -### EventMonitor and EventConsole +Serial is deliberately a terminal/downstream integration layer. It may observe +or operate against Command, Security, Sockets, ESP-Now, Timing, Threads, Event, +and Serializable, but none of those libraries should acquire a Serial +dependency. -`EventMonitor` consumes: +The wider ecosystem should follow the same rule: dependency edges cascade +downstream and integration code belongs with the component that introduces the +additional dependency. -```text -ESPressio Event >= 5.8.0 < 6.0.0 -ESPressio Serializable >= 0.10.1 < 1.0.0 -``` +### Known circular optional relationships -Event supplies the Event Transport Transaction Observation stream. Serializable supplies structured payload decoding used for human-readable diagnostic output. Serial 0.5.1 relies on Serializable 0.10.1's bounded `BinaryArchive` decoding and applies additional EventMonitor-specific limits before structured rendering. - -The legacy EventConsole initialization path remains supported for compatibility. The recommended Command-backed EventConsole integration consumes: +Two existing Event bridge placements violate that preferred direction: ```text -ESPressio Command >= 0.3.0 < 1.0.0 -ESPressio Event >= 5.8.0 < 6.0.0 -ESPressio Serializable >= 0.10.1 < 1.0.0 -``` - -Command supplies the shared `event`/`events` command tree and scoped registration lifetime. Event supplies runtime Serializable Event discovery, descriptors, construction and dispatch. Serializable supplies `JsonArchive`, validation diagnostics, and bounded BinaryArchive decoding for Event monitoring. +Sockets - - -> Event + concrete socket Event transports -The external ArduinoJson dependency is required only by the optional Serializable `JsonArchive`; it is outside this ESPressio-to-ESPressio dependency chart. - -### Timing and Threads monitors - -`SystemClockMonitor` optionally consumes: - -```text -ESPressio Timing >= 2.2.2 < 3.0.0 +Event - - -> Sockets + SocketWorkerEventBridge + SocketSecuritySessionEventBridge ``` -`ThreadMonitor` optionally consumes: +and: ```text -ESPressio Threads >= 3.1.2 < 4.0.0 -``` +ESP-Now - - -> Event + ESPNowEventTransport -### Event bridges versus Serial monitors +Event - - -> ESP-Now + ESPNowTransportEventBridge +``` -The 0.5.x Observable monitors subscribe directly to the originating subsystem. They do not require ESPressio Event. +The optimal resolution is to keep Event transport-neutral and relocate the +transport-specific Observer-to-Event bridges downstream into the corresponding +Sockets/ESP-Now Event integration, or into dedicated integration packages. -ESPressio Event 5.8.0 separately supplies optional Event bridges for Command, Security, Sockets, and ESP-Now when asynchronous Event conversion is desired. Serial diagnostics therefore remain usable without introducing Event as an intermediary. +Generic Event bridges for upstream libraries that do not themselves consume +Event—such as Timing, Threads, Command, and Security—do not create this cycle. -## Current ecosystem relationships +## Why ESP-Now is not pinned to Event 5.8.1 -- Observable 3.0.1 has no mandatory ESPressio dependencies. -- Serializable 0.10.1 has no mandatory ESPressio dependencies. -- Units 0.2.1 optionally consumes Serializable for Serializable Unit counterparts. -- Timing 2.2.2 requires Units and Observable. -- Threads 3.1.2 requires Timing and Observable. -- Security 0.2.0 requires Observable; Event conversion is opt-in downstream through Event 5.8.0. -- Command 0.3.0 requires Observable; Event conversion is opt-in downstream through Event 5.8.0. -- Sockets 0.5.0 consumes Observable for lifecycle observation and optionally integrates Command and Security. -- ESP-Now 0.5.0 requires Timing and Observable and optionally integrates Command, Security, and Event transport functionality. -- Event 5.8.0 requires Threads, Timing, and Observable and optionally bridges Security, Command, Sockets, and ESP-Now observer contracts. -- Serial 0.5.1 has no mandatory ESPressio dependencies; Command, Security, Sockets, ESP-Now, Event, Serializable, Timing, and Threads integrations are all opt-in. +ESP-Now 0.5.1's **required** dependency refresh is Timing 2.2.3. Its Event +transport is optional and can consume a compatible Event 5.x release. Requiring +ESP-Now 0.5.1 to consume Event 5.8.1 while Event also contains an ESP-Now bridge +would strengthen the reciprocal edge and produce unnecessary release churn. -Applications using only the core ESPressio Serial layer acquire none of these optional ESPressio dependencies. +Serial is different: Serial sits downstream of both and therefore validates its +Event integration against Event 5.8.1 and its ESP-Now monitor against ESP-Now +0.5.1. From 5e89732f19f67c41c8d7c731100722d9a3e73f86 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 00:01:27 +0200 Subject: [PATCH 22/33] ci: validate Serial 0.5.1 against dependency-refresh candidates (#8) --- .github/workflows/host-tests.yml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/host-tests.yml b/.github/workflows/host-tests.yml index 977a704..8e218e9 100644 --- a/.github/workflows/host-tests.yml +++ b/.github/workflows/host-tests.yml @@ -2,7 +2,7 @@ name: Host Tests on: push: - branches: [main, bugfix/7-event-monitor-structured-payload-safety] + branches: [main, bugfix/7-event-monitor-structured-payload-safety, feature/8-dependency-refresh-0.5.1] pull_request: jobs: @@ -23,11 +23,11 @@ jobs: repository: Flowduino/ESPressio-Observable ref: 3.0.1 path: deps/ESPressio-Observable - - name: Checkout ESPressio Serializable #2 fix + - name: Checkout ESPressio Serializable 0.10.1 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Serializable - ref: b4c5fa6045c8debf1371f74512ea8bf602d25877 + ref: 0.10.1 path: deps/ESPressio-Serializable - name: Configure run: >- @@ -53,35 +53,35 @@ jobs: repository: Flowduino/ESPressio-Observable ref: 3.0.1 path: project/dependencies/ESPressio-Observable - - name: Checkout ESPressio Units 0.2.1 + - name: Checkout ESPressio Units 0.2.2 candidate uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Units - ref: 0.2.1 + ref: feature/2-serializable-0.10.1-dependency-refresh path: project/dependencies/ESPressio-Units - - name: Checkout ESPressio Timing 2.2.2 + - name: Checkout ESPressio Timing 2.2.3 candidate uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Timing - ref: 2.2.2 + ref: feature/5-units-0.2.2-dependency-refresh path: project/dependencies/ESPressio-Timing - - name: Checkout ESPressio Threads 3.1.2 + - name: Checkout ESPressio Threads 3.1.3 candidate uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Threads - ref: 3.1.2 + ref: feature/45-timing-2.2.3-dependency-refresh path: project/dependencies/ESPressio-Threads - - name: Checkout ESPressio Serializable #2 fix + - name: Checkout ESPressio Serializable 0.10.1 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Serializable - ref: b4c5fa6045c8debf1371f74512ea8bf602d25877 + ref: 0.10.1 path: project/dependencies/ESPressio-Serializable - - name: Checkout ESPressio Event 5.8.0 + - name: Checkout ESPressio Event 5.8.1 candidate uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Event - ref: 5.8.0 + ref: feature/19-dependency-refresh-5.8.1 path: project/dependencies/ESPressio-Event - name: Checkout ESPressio Command 0.3.0 uses: actions/checkout@v4 @@ -101,11 +101,11 @@ jobs: repository: Flowduino/ESPressio-Sockets ref: 0.5.0 path: project/dependencies/ESPressio-Sockets - - name: Checkout ESPressio ESP-Now 0.5.0 + - name: Checkout ESPressio ESP-Now 0.5.1 candidate uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-ESP-Now - ref: 0.5.0 + ref: feature/10-timing-2.2.3-dependency-refresh path: project/dependencies/ESPressio-ESP-Now - uses: actions/setup-python@v5 with: From 1a117821115e7ed9500f0b7ddaf48866f6aa3620 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 00:06:35 +0200 Subject: [PATCH 23/33] chore: remove temporary Serial README helper (#8) --- .github/workflows/readme-refresh.yml | 50 ---------------------------- 1 file changed, 50 deletions(-) delete mode 100644 .github/workflows/readme-refresh.yml diff --git a/.github/workflows/readme-refresh.yml b/.github/workflows/readme-refresh.yml deleted file mode 100644 index 0296e5b..0000000 --- a/.github/workflows/readme-refresh.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Refresh dependency README - -on: - push: - branches: - - feature/8-dependency-refresh-0.5.1 - -permissions: - contents: write - -jobs: - refresh: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: feature/8-dependency-refresh-0.5.1 - - name: Refresh current-version documentation - shell: python - run: | - from pathlib import Path - path = Path('README.md') - text = path.read_text() - replacements = [ - ('ESPNowTransportMonitor\n - - -> ESPressio ESP-Now >= 0.5.0 < 1.0.0', 'ESPNowTransportMonitor\n - - -> ESPressio ESP-Now >= 0.5.1 < 1.0.0'), - ('Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.0.', 'Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.1.'), - ('ESPressio Event >= 5.8.0 < 6.0.0\nESPressio Serializable >= 0.10.1 < 1.0.0', 'ESPressio Event >= 5.8.1 < 6.0.0\nESPressio Serializable >= 0.10.1 < 1.0.0'), - ] - for old, new in replacements: - if old not in text: - raise SystemExit(f'missing expected README text: {old}') - text = text.replace(old, new, 1) - text = text.replace('flowduino/ESPressio-Event@^5.8.0', 'flowduino/ESPressio-Event@^5.8.1') - text = text.replace('flowduino/ESPressio-Serial@^0.5.0', 'flowduino/ESPressio-Serial@^0.5.1') - marker = 'Historical documentation for earlier release generations remains below where useful.\n' - addition = marker + '\nCurrent coordinated dependency baselines for the 0.5.1 release are Units 0.2.2, Timing 2.2.3, Threads 3.1.3, ESP-Now 0.5.1, Event 5.8.1, and Serializable 0.10.1. Command 0.3.0, Security 0.2.0, and Sockets 0.5.0 remain the current optional integration baselines.\n' - if addition not in text: - if marker not in text: - raise SystemExit('missing historical marker') - text = text.replace(marker, addition, 1) - path.write_text(text) - - name: Commit README - run: | - if git diff --quiet -- README.md; then exit 0; fi - git config user.name 'github-actions[bot]' - git config user.email '41898282+github-actions[bot]@users.noreply.github.com' - git add -- README.md - git commit -m 'docs: refresh Serial 0.5.1 dependency README (#8)' - git push origin HEAD:feature/8-dependency-refresh-0.5.1 From b057230c401afb70a5289f160aa9b35ef8c8cc99 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 00:09:06 +0200 Subject: [PATCH 24/33] docs: finalize Serial 0.5.1 dependency baselines (#8) --- CHANGELOG.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a63355..fa92b77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,13 @@ - Added `MaximumStructuredNodes` to `EventMonitorConfig` alongside the existing collection, string, and nesting limits. - Added deterministic malformed/deep/random payload regression and stress coverage for the EventMonitor structured-payload validation path. -- Added ESP32 compile validation for `EventMonitor` against Event 5.8.0 and the Serializable 0.10.1 bug-fix generation. +- Added ESP32 compile validation for `EventMonitor` against the coordinated dependency-refresh candidates: Units 0.2.2, Timing 2.2.3, Threads 3.1.3, ESP-Now 0.5.1, Event 5.8.1, and released Serializable 0.10.1. + +### Changed + +- Raised the current optional Event integration baseline to ESPressio Event >= 5.8.1 < 6.0.0. +- Raised the current optional ESP-Now monitor baseline to ESPressio ESP-Now >= 0.5.1 < 1.0.0. +- Updated current documentation and CI to consume the completed Serializable 0.10.1 dependency cascade rather than intermediate bug-fix commits. ### Compatibility @@ -165,4 +171,4 @@ The structure follows the principles of [Keep a Changelog](https://keepachangelo ### Dependency model - Core ESPressio Serial has no mandatory ESPressio library dependencies. -- Event Monitor is opt-in and requires ESPressio Event 5.5.0 or newer plus ESPressio Serializable 0.9.0 or newer. +- Event Monitor is opt-in and requires ESPressio Event 5.5.0 or newer plus ESPressio Serializable 0.9.0 or newer. \ No newline at end of file From c2759303c20c80ed34300d2d7a0ccee5b48b8819 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 00:40:27 +0200 Subject: [PATCH 25/33] ci: validate released dependency cascade (#8) --- .github/workflows/host-tests.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/host-tests.yml b/.github/workflows/host-tests.yml index 8e218e9..da9d9f6 100644 --- a/.github/workflows/host-tests.yml +++ b/.github/workflows/host-tests.yml @@ -53,23 +53,23 @@ jobs: repository: Flowduino/ESPressio-Observable ref: 3.0.1 path: project/dependencies/ESPressio-Observable - - name: Checkout ESPressio Units 0.2.2 candidate + - name: Checkout ESPressio Units 0.2.2 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Units - ref: feature/2-serializable-0.10.1-dependency-refresh + ref: 0.2.2 path: project/dependencies/ESPressio-Units - - name: Checkout ESPressio Timing 2.2.3 candidate + - name: Checkout ESPressio Timing 2.2.3 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Timing - ref: feature/5-units-0.2.2-dependency-refresh + ref: 2.2.3 path: project/dependencies/ESPressio-Timing - - name: Checkout ESPressio Threads 3.1.3 candidate + - name: Checkout ESPressio Threads 3.1.3 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Threads - ref: feature/45-timing-2.2.3-dependency-refresh + ref: 3.1.3 path: project/dependencies/ESPressio-Threads - name: Checkout ESPressio Serializable 0.10.1 uses: actions/checkout@v4 @@ -77,11 +77,11 @@ jobs: repository: Flowduino/ESPressio-Serializable ref: 0.10.1 path: project/dependencies/ESPressio-Serializable - - name: Checkout ESPressio Event 5.8.1 candidate + - name: Checkout ESPressio Event 5.8.1 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Event - ref: feature/19-dependency-refresh-5.8.1 + ref: 5.8.1 path: project/dependencies/ESPressio-Event - name: Checkout ESPressio Command 0.3.0 uses: actions/checkout@v4 @@ -101,11 +101,11 @@ jobs: repository: Flowduino/ESPressio-Sockets ref: 0.5.0 path: project/dependencies/ESPressio-Sockets - - name: Checkout ESPressio ESP-Now 0.5.1 candidate + - name: Checkout ESPressio ESP-Now 0.5.1 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-ESP-Now - ref: feature/10-timing-2.2.3-dependency-refresh + ref: 0.5.1 path: project/dependencies/ESPressio-ESP-Now - uses: actions/setup-python@v5 with: From 9cbade4eb3016efe2cfcc85167bea96e2f1fae6d Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 08:37:21 +0200 Subject: [PATCH 26/33] docs: refresh Serial 0.5.1 dependency chart for Serializable 0.10.2 cascade (#8) --- ESPRESSIO_DEPENDENCY_CHART.md | 47 ++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/ESPRESSIO_DEPENDENCY_CHART.md b/ESPRESSIO_DEPENDENCY_CHART.md index bc893c3..491818b 100644 --- a/ESPRESSIO_DEPENDENCY_CHART.md +++ b/ESPRESSIO_DEPENDENCY_CHART.md @@ -24,52 +24,53 @@ SocketSecuritySessionMonitor - - -> ESPressio Security >= 0.2.0 < 1.0.0 ESPNowTransportMonitor - - - -> ESPressio ESP-Now >= 0.5.1 < 1.0.0 + - - -> ESPressio ESP-Now >= 0.5.2 < 1.0.0 SystemClockMonitor - - - -> ESPressio Timing >= 2.2.3 < 3.0.0 + - - -> ESPressio Timing >= 2.2.4 < 3.0.0 ThreadMonitor - - - -> ESPressio Threads >= 3.1.3 < 4.0.0 + - - -> ESPressio Threads >= 3.1.4 < 4.0.0 EventMonitor / EventConsole - - - -> ESPressio Event >= 5.8.1 < 6.0.0 - - - -> ESPressio Serializable >= 0.10.1 < 1.0.0 + - - -> ESPressio Event >= 5.8.2 < 6.0.0 + - - -> ESPressio Serializable >= 0.10.2 < 1.0.0 ``` -EventMonitor 0.5.1 specifically uses Serializable 0.10.1's bounded, -allocation-free ESPB traversal API for structured diagnostics. +EventMonitor 0.5.1 uses Serializable 0.10.2's bounded, allocation-free ESPB +traversal API for structured diagnostics. Serializable 0.10.2 also contains the +strict-build warning correction required by Serial's `-Werror` host validation. ## Current coordinated ecosystem ```text FOUNDATIONAL ├── Observable 3.0.1 -├── Serializable 0.10.1 -├── Units 0.2.2 +├── Serializable 0.10.2 +├── Units 0.2.3 ├── Security 0.2.0 └── Command 0.3.0 RUNTIME -└── Timing 2.2.3 - ├── Units >= 0.2.2 < 1.0.0 +└── Timing 2.2.4 + ├── Units >= 0.2.3 < 1.0.0 └── Observable >= 3.0.1 < 4.0.0 EXECUTION -└── Threads 3.1.3 - ├── Timing >= 2.2.3 < 3.0.0 +└── Threads 3.1.4 + ├── Timing >= 2.2.4 < 3.0.0 └── Observable >= 3.0.1 < 4.0.0 TRANSPORT / INTEGRATION ├── Sockets 0.5.0 -└── ESP-Now 0.5.1 +└── ESP-Now 0.5.2 EVENT -└── Event 5.8.1 - ├── Threads >= 3.1.3 < 4.0.0 - ├── Timing >= 2.2.3 < 3.0.0 +└── Event 5.8.2 + ├── Threads >= 3.1.4 < 4.0.0 + ├── Timing >= 2.2.4 < 3.0.0 ├── Observable >= 3.0.1 < 4.0.0 - └── Serializable >= 0.10.1 < 1.0.0 [optional] + └── Serializable >= 0.10.2 < 1.0.0 [optional] DIAGNOSTICS / OPERATOR └── Serial 0.5.1 @@ -116,13 +117,13 @@ Sockets/ESP-Now Event integration, or into dedicated integration packages. Generic Event bridges for upstream libraries that do not themselves consume Event—such as Timing, Threads, Command, and Security—do not create this cycle. -## Why ESP-Now is not pinned to Event 5.8.1 +## Why ESP-Now is not pinned to Event 5.8.2 -ESP-Now 0.5.1's **required** dependency refresh is Timing 2.2.3. Its Event +ESP-Now 0.5.2's **required** dependency refresh is Timing 2.2.4. Its Event transport is optional and can consume a compatible Event 5.x release. Requiring -ESP-Now 0.5.1 to consume Event 5.8.1 while Event also contains an ESP-Now bridge +ESP-Now 0.5.2 to consume Event 5.8.2 while Event also contains an ESP-Now bridge would strengthen the reciprocal edge and produce unnecessary release churn. Serial is different: Serial sits downstream of both and therefore validates its -Event integration against Event 5.8.1 and its ESP-Now monitor against ESP-Now -0.5.1. +Event integration against Event 5.8.2 and its ESP-Now monitor against ESP-Now +0.5.2. From a63702fdd5393c3368b3780ca7508edbb374d5e5 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 08:38:52 +0200 Subject: [PATCH 27/33] ci: validate Serial 0.5.1 against Serializable 0.10.2 cascade candidates (#8) --- .github/workflows/host-tests.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/host-tests.yml b/.github/workflows/host-tests.yml index da9d9f6..6eccb7e 100644 --- a/.github/workflows/host-tests.yml +++ b/.github/workflows/host-tests.yml @@ -23,11 +23,11 @@ jobs: repository: Flowduino/ESPressio-Observable ref: 3.0.1 path: deps/ESPressio-Observable - - name: Checkout ESPressio Serializable 0.10.1 + - name: Checkout ESPressio Serializable 0.10.2 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Serializable - ref: 0.10.1 + ref: 0.10.2 path: deps/ESPressio-Serializable - name: Configure run: >- @@ -53,35 +53,35 @@ jobs: repository: Flowduino/ESPressio-Observable ref: 3.0.1 path: project/dependencies/ESPressio-Observable - - name: Checkout ESPressio Units 0.2.2 + - name: Checkout ESPressio Units 0.2.3 candidate uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Units - ref: 0.2.2 + ref: feature/4-serializable-0.10.2-dependency-refresh path: project/dependencies/ESPressio-Units - - name: Checkout ESPressio Timing 2.2.3 + - name: Checkout ESPressio Timing 2.2.4 candidate uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Timing - ref: 2.2.3 + ref: feature/7-units-0.2.3-dependency-refresh path: project/dependencies/ESPressio-Timing - - name: Checkout ESPressio Threads 3.1.3 + - name: Checkout ESPressio Threads 3.1.4 candidate uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Threads - ref: 3.1.3 + ref: feature/47-timing-2.2.4-dependency-refresh path: project/dependencies/ESPressio-Threads - - name: Checkout ESPressio Serializable 0.10.1 + - name: Checkout ESPressio Serializable 0.10.2 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Serializable - ref: 0.10.1 + ref: 0.10.2 path: project/dependencies/ESPressio-Serializable - - name: Checkout ESPressio Event 5.8.1 + - name: Checkout ESPressio Event 5.8.2 candidate uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Event - ref: 5.8.1 + ref: feature/21-serializable-0.10.2-cascade-refresh path: project/dependencies/ESPressio-Event - name: Checkout ESPressio Command 0.3.0 uses: actions/checkout@v4 @@ -101,11 +101,11 @@ jobs: repository: Flowduino/ESPressio-Sockets ref: 0.5.0 path: project/dependencies/ESPressio-Sockets - - name: Checkout ESPressio ESP-Now 0.5.1 + - name: Checkout ESPressio ESP-Now 0.5.2 candidate uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-ESP-Now - ref: 0.5.1 + ref: feature/12-timing-2.2.4-dependency-refresh path: project/dependencies/ESPressio-ESP-Now - uses: actions/setup-python@v5 with: From 41099684778940b6539990ef10cfc6fed09cf7f9 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 08:39:12 +0200 Subject: [PATCH 28/33] ci: add temporary Serial dependency documentation helper (#8) --- .../workflows/_dependency-doc-maintenance.yml | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/_dependency-doc-maintenance.yml diff --git a/.github/workflows/_dependency-doc-maintenance.yml b/.github/workflows/_dependency-doc-maintenance.yml new file mode 100644 index 0000000..62715f0 --- /dev/null +++ b/.github/workflows/_dependency-doc-maintenance.yml @@ -0,0 +1,64 @@ +name: Dependency documentation maintenance + +on: + push: + branches: + - feature/8-dependency-refresh-0.5.1 + +permissions: + contents: write + +jobs: + update-docs: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Update current release references + shell: python + run: | + from pathlib import Path + + readme = Path('README.md') + text = readme.read_text() + replacements = { + "Version **0.5.1** fixes the structured EventMonitor crash path reproduced on ESP32 under low-memory conditions. Structured diagnostics now use ESPressio Serializable 0.10.1's allocation-free BinaryArchive traversal API": "Version **0.5.1** fixes the structured EventMonitor crash path reproduced on ESP32 under low-memory conditions. Structured diagnostics now use ESPressio Serializable 0.10.2's allocation-free BinaryArchive traversal API", + 'ESPressio ESP-Now >= 0.5.1 < 1.0.0': 'ESPressio ESP-Now >= 0.5.2 < 1.0.0', + 'Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.1.': 'Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.2.', + 'Current coordinated dependency baselines for the 0.5.1 release are Units 0.2.2, Timing 2.2.3, Threads 3.1.3, ESP-Now 0.5.1, Event 5.8.1, and Serializable 0.10.1.': 'Current coordinated dependency baselines for the 0.5.1 release are Units 0.2.3, Timing 2.2.4, Threads 3.1.4, ESP-Now 0.5.2, Event 5.8.2, and Serializable 0.10.2.', + 'ESPressio Event >= 5.8.1 < 6.0.0\nESPressio Serializable >= 0.10.1 < 1.0.0': 'ESPressio Event >= 5.8.2 < 6.0.0\nESPressio Serializable >= 0.10.2 < 1.0.0' + } + for old, new in replacements.items(): + if old not in text: + raise SystemExit(f'Missing expected README text: {old}') + text = text.replace(old, new, 1) + readme.write_text(text) + + changelog = Path('CHANGELOG.md') + current = changelog.read_text() + replacements = { + "allocation-free ESPB traversal from ESPressio Serializable 0.10.1": "allocation-free ESPB traversal from ESPressio Serializable 0.10.2", + 'ESPressio Serializable >= 0.10.1 < 1.0.0': 'ESPressio Serializable >= 0.10.2 < 1.0.0', + 'Units 0.2.2, Timing 2.2.3, Threads 3.1.3, ESP-Now 0.5.1, Event 5.8.1, and released Serializable 0.10.1': 'Units 0.2.3, Timing 2.2.4, Threads 3.1.4, ESP-Now 0.5.2, Event 5.8.2, and released Serializable 0.10.2', + 'ESPressio Event >= 5.8.1 < 6.0.0': 'ESPressio Event >= 5.8.2 < 6.0.0', + 'ESPressio ESP-Now >= 0.5.1 < 1.0.0': 'ESPressio ESP-Now >= 0.5.2 < 1.0.0', + 'completed Serializable 0.10.1 dependency cascade': 'completed Serializable 0.10.2 dependency cascade' + } + for old, new in replacements.items(): + if old not in current: + raise SystemExit(f'Missing expected CHANGELOG text: {old}') + current = current.replace(old, new, 1) + marker = '- Updated current documentation and CI to consume the completed Serializable 0.10.2 dependency cascade rather than intermediate bug-fix commits.\n' + note = '- Serializable 0.10.2 also resolves the strict-build `-Wmisleading-indentation` warning exposed by Serial\'s warnings-as-errors host validation.\n' + if note not in current: + current = current.replace(marker, marker + note, 1) + changelog.write_text(current) + - name: Commit documentation update + shell: bash + run: | + if git diff --quiet -- README.md CHANGELOG.md; then exit 0; fi + git config user.name github-actions[bot] + git config user.email 41898282+github-actions[bot]@users.noreply.github.com + git add README.md CHANGELOG.md + git commit -m 'docs: refresh Serial 0.5.1 dependency references (#8)' + git push From f585b921a67b9f4f6773ddf7c3c2a63da1c0c606 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 08:39:18 +0200 Subject: [PATCH 29/33] chore: trigger Serial dependency documentation maintenance (#8) --- .dependency-doc-maintenance-trigger | 1 + 1 file changed, 1 insertion(+) create mode 100644 .dependency-doc-maintenance-trigger diff --git a/.dependency-doc-maintenance-trigger b/.dependency-doc-maintenance-trigger new file mode 100644 index 0000000..5c33b15 --- /dev/null +++ b/.dependency-doc-maintenance-trigger @@ -0,0 +1 @@ +trigger From 8241722928f6917ad17b5161a7e5e2607d159e63 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 21 Aug 2026 06:39:25 +0000 Subject: [PATCH 30/33] docs: refresh Serial 0.5.1 dependency references (#8) --- CHANGELOG.md | 13 +++++++------ README.md | 12 ++++++------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa92b77..ff1bf76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,22 +2,23 @@ ### Fixed -- Replaced EventMonitor's tree-building `BinaryArchive::Load()` diagnostic path with bounded, allocation-free ESPB traversal from ESPressio Serializable 0.10.1, preventing valid payload diagnostics from requiring a second heap-backed `SerializationNode` tree. +- Replaced EventMonitor's tree-building `BinaryArchive::Load()` diagnostic path with bounded, allocation-free ESPB traversal from ESPressio Serializable 0.10.2, preventing valid payload diagnostics from requiring a second heap-backed `SerializationNode` tree. - Hardened structured `EventMonitor` payload diagnostics so malformed, truncated, excessively nested, or otherwise unreasonable Event Transport payloads are rejected under monitor-specific decode limits. - Added fail-safe fallback from `Structured` to bounded `Hex` output whenever a payload fails structured validation or exceeds the configured monitor limits. -- Updated Event Monitor's optional Serializable baseline to ESPressio Serializable >= 0.10.1 < 1.0.0, consuming the bounded/allocation-free BinaryArchive facilities introduced for Flowduino/ESPressio-Serializable#2. +- Updated Event Monitor's optional Serializable baseline to ESPressio Serializable >= 0.10.2 < 1.0.0, consuming the bounded/allocation-free BinaryArchive facilities introduced for Flowduino/ESPressio-Serializable#2. ### Added - Added `MaximumStructuredNodes` to `EventMonitorConfig` alongside the existing collection, string, and nesting limits. - Added deterministic malformed/deep/random payload regression and stress coverage for the EventMonitor structured-payload validation path. -- Added ESP32 compile validation for `EventMonitor` against the coordinated dependency-refresh candidates: Units 0.2.2, Timing 2.2.3, Threads 3.1.3, ESP-Now 0.5.1, Event 5.8.1, and released Serializable 0.10.1. +- Added ESP32 compile validation for `EventMonitor` against the coordinated dependency-refresh candidates: Units 0.2.3, Timing 2.2.4, Threads 3.1.4, ESP-Now 0.5.2, Event 5.8.2, and released Serializable 0.10.2. ### Changed -- Raised the current optional Event integration baseline to ESPressio Event >= 5.8.1 < 6.0.0. -- Raised the current optional ESP-Now monitor baseline to ESPressio ESP-Now >= 0.5.1 < 1.0.0. -- Updated current documentation and CI to consume the completed Serializable 0.10.1 dependency cascade rather than intermediate bug-fix commits. +- Raised the current optional Event integration baseline to ESPressio Event >= 5.8.2 < 6.0.0. +- Raised the current optional ESP-Now monitor baseline to ESPressio ESP-Now >= 0.5.2 < 1.0.0. +- Updated current documentation and CI to consume the completed Serializable 0.10.2 dependency cascade rather than intermediate bug-fix commits. +- Serializable 0.10.2 also resolves the strict-build `-Wmisleading-indentation` warning exposed by Serial's warnings-as-errors host validation. ### Compatibility diff --git a/README.md b/README.md index 88e0fae..07a84ab 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Version 0.5.1 hardens the opt-in Event Monitor so structured Event Transport dia ## Current Version — 0.5.1 -Version **0.5.1** fixes the structured EventMonitor crash path reproduced on ESP32 under low-memory conditions. Structured diagnostics now use ESPressio Serializable 0.10.1's allocation-free BinaryArchive traversal API with explicit depth, aggregate-node, collection, name, and string limits. Invalid or outside-limit payloads fall back to bounded hexadecimal output rather than becoming fatal diagnostic work. +Version **0.5.1** fixes the structured EventMonitor crash path reproduced on ESP32 under low-memory conditions. Structured diagnostics now use ESPressio Serializable 0.10.2's allocation-free BinaryArchive traversal API with explicit depth, aggregate-node, collection, name, and string limits. Invalid or outside-limit payloads fall back to bounded hexadecimal output rather than becoming fatal diagnostic work. The Observable-backed monitor integrations introduced in 0.5.0 remain available unchanged: @@ -25,16 +25,16 @@ SocketSecuritySessionMonitor - - -> ESPressio Security >= 0.2.0 < 1.0.0 ESPNowTransportMonitor - - - -> ESPressio ESP-Now >= 0.5.1 < 1.0.0 + - - -> ESPressio ESP-Now >= 0.5.2 < 1.0.0 ``` `DiagnosticMonitor` can additionally compose `CommandMonitor` and `ESPNowTransportMonitor` when those dependencies are present. Security and Socket monitors remain instance-oriented because the application must choose the specific `TransportSecurity`, `SocketWorker`, or `SocketSecuritySession` object to observe. -These monitors subscribe directly to the originating library's Observable contract. They do not invent parallel Serial lifecycle semantics and do not require ESPressio Event. Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.1. +These monitors subscribe directly to the originating library's Observable contract. They do not invent parallel Serial lifecycle semantics and do not require ESPressio Event. Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.2. Historical documentation for earlier release generations remains below where useful. -Current coordinated dependency baselines for the 0.5.1 release are Units 0.2.2, Timing 2.2.3, Threads 3.1.3, ESP-Now 0.5.1, Event 5.8.1, and Serializable 0.10.1. Command 0.3.0, Security 0.2.0, and Sockets 0.5.0 remain the current optional integration baselines. +Current coordinated dependency baselines for the 0.5.1 release are Units 0.2.3, Timing 2.2.4, Threads 3.1.4, ESP-Now 0.5.2, Event 5.8.2, and Serializable 0.10.2. Command 0.3.0, Security 0.2.0, and Sockets 0.5.0 remain the current optional integration baselines. ## ESPressio Development Platform @@ -77,8 +77,8 @@ The **core ESPressio Serial library has no required ESPressio library dependenci The Event Monitor is deliberately opt-in and requires: ```text -ESPressio Event >= 5.8.1 < 6.0.0 -ESPressio Serializable >= 0.10.1 < 1.0.0 +ESPressio Event >= 5.8.2 < 6.0.0 +ESPressio Serializable >= 0.10.2 < 1.0.0 ``` The additional opt-in monitoring dependencies for the 0.5.x line are listed above. Historical sections below retain older release-specific baselines where those versions are part of the documented history. From 6a2de2cd5bf970f6065a252cd32e2a707cd0fe43 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 08:43:09 +0200 Subject: [PATCH 31/33] chore: remove temporary Serial documentation helper (#8) --- .../workflows/_dependency-doc-maintenance.yml | 64 ------------------- 1 file changed, 64 deletions(-) delete mode 100644 .github/workflows/_dependency-doc-maintenance.yml diff --git a/.github/workflows/_dependency-doc-maintenance.yml b/.github/workflows/_dependency-doc-maintenance.yml deleted file mode 100644 index 62715f0..0000000 --- a/.github/workflows/_dependency-doc-maintenance.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Dependency documentation maintenance - -on: - push: - branches: - - feature/8-dependency-refresh-0.5.1 - -permissions: - contents: write - -jobs: - update-docs: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Update current release references - shell: python - run: | - from pathlib import Path - - readme = Path('README.md') - text = readme.read_text() - replacements = { - "Version **0.5.1** fixes the structured EventMonitor crash path reproduced on ESP32 under low-memory conditions. Structured diagnostics now use ESPressio Serializable 0.10.1's allocation-free BinaryArchive traversal API": "Version **0.5.1** fixes the structured EventMonitor crash path reproduced on ESP32 under low-memory conditions. Structured diagnostics now use ESPressio Serializable 0.10.2's allocation-free BinaryArchive traversal API", - 'ESPressio ESP-Now >= 0.5.1 < 1.0.0': 'ESPressio ESP-Now >= 0.5.2 < 1.0.0', - 'Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.1.': 'Event-backed observation remains a separate opt-in integration in ESPressio Event 5.8.2.', - 'Current coordinated dependency baselines for the 0.5.1 release are Units 0.2.2, Timing 2.2.3, Threads 3.1.3, ESP-Now 0.5.1, Event 5.8.1, and Serializable 0.10.1.': 'Current coordinated dependency baselines for the 0.5.1 release are Units 0.2.3, Timing 2.2.4, Threads 3.1.4, ESP-Now 0.5.2, Event 5.8.2, and Serializable 0.10.2.', - 'ESPressio Event >= 5.8.1 < 6.0.0\nESPressio Serializable >= 0.10.1 < 1.0.0': 'ESPressio Event >= 5.8.2 < 6.0.0\nESPressio Serializable >= 0.10.2 < 1.0.0' - } - for old, new in replacements.items(): - if old not in text: - raise SystemExit(f'Missing expected README text: {old}') - text = text.replace(old, new, 1) - readme.write_text(text) - - changelog = Path('CHANGELOG.md') - current = changelog.read_text() - replacements = { - "allocation-free ESPB traversal from ESPressio Serializable 0.10.1": "allocation-free ESPB traversal from ESPressio Serializable 0.10.2", - 'ESPressio Serializable >= 0.10.1 < 1.0.0': 'ESPressio Serializable >= 0.10.2 < 1.0.0', - 'Units 0.2.2, Timing 2.2.3, Threads 3.1.3, ESP-Now 0.5.1, Event 5.8.1, and released Serializable 0.10.1': 'Units 0.2.3, Timing 2.2.4, Threads 3.1.4, ESP-Now 0.5.2, Event 5.8.2, and released Serializable 0.10.2', - 'ESPressio Event >= 5.8.1 < 6.0.0': 'ESPressio Event >= 5.8.2 < 6.0.0', - 'ESPressio ESP-Now >= 0.5.1 < 1.0.0': 'ESPressio ESP-Now >= 0.5.2 < 1.0.0', - 'completed Serializable 0.10.1 dependency cascade': 'completed Serializable 0.10.2 dependency cascade' - } - for old, new in replacements.items(): - if old not in current: - raise SystemExit(f'Missing expected CHANGELOG text: {old}') - current = current.replace(old, new, 1) - marker = '- Updated current documentation and CI to consume the completed Serializable 0.10.2 dependency cascade rather than intermediate bug-fix commits.\n' - note = '- Serializable 0.10.2 also resolves the strict-build `-Wmisleading-indentation` warning exposed by Serial\'s warnings-as-errors host validation.\n' - if note not in current: - current = current.replace(marker, marker + note, 1) - changelog.write_text(current) - - name: Commit documentation update - shell: bash - run: | - if git diff --quiet -- README.md CHANGELOG.md; then exit 0; fi - git config user.name github-actions[bot] - git config user.email 41898282+github-actions[bot]@users.noreply.github.com - git add README.md CHANGELOG.md - git commit -m 'docs: refresh Serial 0.5.1 dependency references (#8)' - git push From 600fbb22a1289539ceb30d68c558dd4b5a009a11 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 08:43:17 +0200 Subject: [PATCH 32/33] chore: remove Serial documentation maintenance trigger (#8) --- .dependency-doc-maintenance-trigger | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .dependency-doc-maintenance-trigger diff --git a/.dependency-doc-maintenance-trigger b/.dependency-doc-maintenance-trigger deleted file mode 100644 index 5c33b15..0000000 --- a/.dependency-doc-maintenance-trigger +++ /dev/null @@ -1 +0,0 @@ -trigger From 964635d918d2c1ebf7d4ee6f29779abab9a0b6a2 Mon Sep 17 00:00:00 2001 From: Simon J Stuart Date: Fri, 21 Aug 2026 10:02:10 +0200 Subject: [PATCH 33/33] ci: validate Serial 0.5.1 against released dependency cascade (#8) --- .github/workflows/host-tests.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/host-tests.yml b/.github/workflows/host-tests.yml index 6eccb7e..8a89fc1 100644 --- a/.github/workflows/host-tests.yml +++ b/.github/workflows/host-tests.yml @@ -53,23 +53,23 @@ jobs: repository: Flowduino/ESPressio-Observable ref: 3.0.1 path: project/dependencies/ESPressio-Observable - - name: Checkout ESPressio Units 0.2.3 candidate + - name: Checkout ESPressio Units 0.2.3 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Units - ref: feature/4-serializable-0.10.2-dependency-refresh + ref: 0.2.3 path: project/dependencies/ESPressio-Units - - name: Checkout ESPressio Timing 2.2.4 candidate + - name: Checkout ESPressio Timing 2.2.4 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Timing - ref: feature/7-units-0.2.3-dependency-refresh + ref: 2.2.4 path: project/dependencies/ESPressio-Timing - - name: Checkout ESPressio Threads 3.1.4 candidate + - name: Checkout ESPressio Threads 3.1.4 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Threads - ref: feature/47-timing-2.2.4-dependency-refresh + ref: 3.1.4 path: project/dependencies/ESPressio-Threads - name: Checkout ESPressio Serializable 0.10.2 uses: actions/checkout@v4 @@ -77,11 +77,11 @@ jobs: repository: Flowduino/ESPressio-Serializable ref: 0.10.2 path: project/dependencies/ESPressio-Serializable - - name: Checkout ESPressio Event 5.8.2 candidate + - name: Checkout ESPressio Event 5.8.2 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-Event - ref: feature/21-serializable-0.10.2-cascade-refresh + ref: 5.8.2 path: project/dependencies/ESPressio-Event - name: Checkout ESPressio Command 0.3.0 uses: actions/checkout@v4 @@ -101,11 +101,11 @@ jobs: repository: Flowduino/ESPressio-Sockets ref: 0.5.0 path: project/dependencies/ESPressio-Sockets - - name: Checkout ESPressio ESP-Now 0.5.2 candidate + - name: Checkout ESPressio ESP-Now 0.5.2 uses: actions/checkout@v4 with: repository: Flowduino/ESPressio-ESP-Now - ref: feature/12-timing-2.2.4-dependency-refresh + ref: 0.5.2 path: project/dependencies/ESPressio-ESP-Now - uses: actions/setup-python@v5 with: