From 748a173b0f9db090833468020cdd7b4fa8f584a1 Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 17 Feb 2026 21:39:37 -0700 Subject: [PATCH] Step 636: drone error synthesis --- editor/CMakeLists.txt | 9 +++ editor/src/DroneErrorSynthesis.h | 62 ++++++++++++++++++ editor/tests/step636_test.cpp | 109 +++++++++++++++++++++++++++++++ progress.md | 32 +++++++++ 4 files changed, 212 insertions(+) create mode 100644 editor/src/DroneErrorSynthesis.h create mode 100644 editor/tests/step636_test.cpp diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index e3d7520..03f1fb1 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -4603,4 +4603,13 @@ target_link_libraries(step635_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step636_test tests/step636_test.cpp) +target_include_directories(step636_test PRIVATE src) +target_link_libraries(step636_test PRIVATE + nlohmann_json::nlohmann_json + unofficial::tree-sitter::tree-sitter + tree_sitter_python tree_sitter_cpp tree_sitter_elisp + tree_sitter_javascript tree_sitter_typescript + tree_sitter_java tree_sitter_rust tree_sitter_go) + # Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies) diff --git a/editor/src/DroneErrorSynthesis.h b/editor/src/DroneErrorSynthesis.h new file mode 100644 index 0000000..9ddf051 --- /dev/null +++ b/editor/src/DroneErrorSynthesis.h @@ -0,0 +1,62 @@ +#pragma once +// Step 636: Error type synthesis for drone + +#include +#include + +enum class DroneErrorKind { + MqttError, + NexusError, + ExecutionError, + CapabilityMismatch +}; + +struct DroneErrorSpec { + DroneErrorKind kind = DroneErrorKind::ExecutionError; + std::string message; + int code = 0; + bool retryable = false; +}; + +class DroneErrorSynthesis { +public: + static std::string className(DroneErrorKind kind) { + if (kind == DroneErrorKind::MqttError) return "MqttError"; + if (kind == DroneErrorKind::NexusError) return "NexusError"; + if (kind == DroneErrorKind::ExecutionError) return "ExecutionError"; + return "CapabilityMismatch"; + } + + static std::string toErrorCodeCategory(DroneErrorKind kind) { + if (kind == DroneErrorKind::MqttError) return "mqtt"; + if (kind == DroneErrorKind::NexusError) return "nexus"; + if (kind == DroneErrorKind::ExecutionError) return "execution"; + return "capability"; + } + + static std::string expectedAlias(DroneErrorKind kind, + const std::string& valueType = "void") { + return "std::expected<" + valueType + ", " + className(kind) + ">"; + } + + static bool isRetryable(const DroneErrorSpec& spec) { + if (spec.kind == DroneErrorKind::CapabilityMismatch) return false; + if (spec.code < 0) return false; + return spec.retryable; + } + + static std::string synthesizeHeader(const std::string& ns = "whetstone") { + if (ns.empty()) return ""; + std::string code; + code += "#pragma once\n"; + code += "#include \n"; + code += "#include \n\n"; + code += "namespace " + ns + " {\n"; + code += "struct MqttError { int code = 0; std::string message; };\n"; + code += "struct NexusError { int code = 0; std::string message; };\n"; + code += "struct ExecutionError { int code = 0; std::string message; };\n"; + code += "struct CapabilityMismatch { int code = 0; std::string message; };\n"; + code += "} // namespace " + ns + "\n"; + return code; + } +}; diff --git a/editor/tests/step636_test.cpp b/editor/tests/step636_test.cpp new file mode 100644 index 0000000..13e5687 --- /dev/null +++ b/editor/tests/step636_test.cpp @@ -0,0 +1,109 @@ +// Step 636: Error type synthesis for drone (12 tests) + +#include "DroneErrorSynthesis.h" + +#include + +static int passed = 0, failed = 0; +#define TEST(name) { std::cout << " " << #name << "... "; } +#define PASS() { std::cout << "PASS\n"; ++passed; } +#define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; } +#define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; } + +void test_class_name_for_mqtt_error() { + TEST(class_name_for_mqtt_error); + CHECK(DroneErrorSynthesis::className(DroneErrorKind::MqttError) == "MqttError", "name mismatch"); + PASS(); +} + +void test_class_name_for_nexus_error() { + TEST(class_name_for_nexus_error); + CHECK(DroneErrorSynthesis::className(DroneErrorKind::NexusError) == "NexusError", "name mismatch"); + PASS(); +} + +void test_category_for_execution_error() { + TEST(category_for_execution_error); + CHECK(DroneErrorSynthesis::toErrorCodeCategory(DroneErrorKind::ExecutionError) == "execution", "category mismatch"); + PASS(); +} + +void test_category_for_capability_mismatch() { + TEST(category_for_capability_mismatch); + CHECK(DroneErrorSynthesis::toErrorCodeCategory(DroneErrorKind::CapabilityMismatch) == "capability", "category mismatch"); + PASS(); +} + +void test_expected_alias_default_value_type() { + TEST(expected_alias_default_value_type); + CHECK(DroneErrorSynthesis::expectedAlias(DroneErrorKind::MqttError) == "std::expected", "alias mismatch"); + PASS(); +} + +void test_expected_alias_custom_value_type() { + TEST(expected_alias_custom_value_type); + CHECK(DroneErrorSynthesis::expectedAlias(DroneErrorKind::NexusError, "int") == "std::expected", "alias mismatch"); + PASS(); +} + +void test_retryable_true_for_mqtt_positive_code() { + TEST(retryable_true_for_mqtt_positive_code); + DroneErrorSpec spec{DroneErrorKind::MqttError, "timeout", 1, true}; + CHECK(DroneErrorSynthesis::isRetryable(spec), "expected retryable"); + PASS(); +} + +void test_retryable_false_for_capability_mismatch() { + TEST(retryable_false_for_capability_mismatch); + DroneErrorSpec spec{DroneErrorKind::CapabilityMismatch, "missing cap", 1, true}; + CHECK(!DroneErrorSynthesis::isRetryable(spec), "capability mismatch should not retry"); + PASS(); +} + +void test_retryable_false_for_negative_code() { + TEST(retryable_false_for_negative_code); + DroneErrorSpec spec{DroneErrorKind::NexusError, "fatal", -1, true}; + CHECK(!DroneErrorSynthesis::isRetryable(spec), "negative code should not retry"); + PASS(); +} + +void test_synthesize_header_contains_mqtt_error() { + TEST(synthesize_header_contains_mqtt_error); + auto code = DroneErrorSynthesis::synthesizeHeader(); + CHECK(code.find("struct MqttError") != std::string::npos, "mqtt struct missing"); + PASS(); +} + +void test_synthesize_header_contains_expected_include() { + TEST(synthesize_header_contains_expected_include); + auto code = DroneErrorSynthesis::synthesizeHeader(); + CHECK(code.find("#include ") != std::string::npos, "expected include missing"); + PASS(); +} + +void test_synthesize_header_rejects_empty_namespace() { + TEST(synthesize_header_rejects_empty_namespace); + auto code = DroneErrorSynthesis::synthesizeHeader(""); + CHECK(code.empty(), "empty namespace should produce empty output"); + PASS(); +} + +int main() { + std::cout << "Step 636: Error type synthesis for drone\n"; + + test_class_name_for_mqtt_error(); + test_class_name_for_nexus_error(); + test_category_for_execution_error(); + test_category_for_capability_mismatch(); + test_expected_alias_default_value_type(); + test_expected_alias_custom_value_type(); + test_retryable_true_for_mqtt_positive_code(); + test_retryable_false_for_capability_mismatch(); + test_retryable_false_for_negative_code(); + test_synthesize_header_contains_mqtt_error(); + test_synthesize_header_contains_expected_include(); + test_synthesize_header_rejects_empty_namespace(); + + std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n"; + return failed == 0 ? 0 : 1; +} diff --git a/progress.md b/progress.md index 496d2f6..ae7889e 100644 --- a/progress.md +++ b/progress.md @@ -12888,3 +12888,35 @@ a header-only `supports(...)` helper. - `editor/src/CapabilityDeclarationGenerator.h` (`68` <= `600`) - `editor/tests/step635_test.cpp` within test-file size guidance (`116` lines) - Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md` + +### Step 636: Error type synthesis for drone +**Status:** PASS (12/12 tests) + +Adds a drone error synthesis module covering `MqttError`, `NexusError`, +`ExecutionError`, and `CapabilityMismatch` with category mapping, retryability +rules, and `std::expected` alias generation helpers. + +**Files added:** +- `editor/src/DroneErrorSynthesis.h` - error synthesis model: + - error kind and spec modeling + - category and expected-alias helpers + - header text synthesis for generated drone error types +- `editor/tests/step636_test.cpp` - 12 tests covering: + - class/category mapping correctness + - expected-alias generation behavior + - retryability edge cases + - synthesized-header content and empty-namespace handling + +**Files modified:** +- `editor/CMakeLists.txt` - `step636_test` target + +**Verification run:** +- `cmake -S editor -B editor/build-native` - PASS +- `cmake --build editor/build-native --target step636_test step635_test` - PASS +- `./editor/build-native/step636_test` - PASS (12/12) +- `./editor/build-native/step635_test` - PASS (12/12) regression coverage + +**Architecture gate check:** +- `editor/src/DroneErrorSynthesis.h` (`62` <= `600`) +- `editor/tests/step636_test.cpp` within test-file size guidance (`109` lines) +- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`