From 3f0e03ae632dd96a7a00fec378312d19dc7c0160 Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 17 Feb 2026 11:14:04 -0700 Subject: [PATCH] Step 582: add intake to queue simulation harness --- editor/CMakeLists.txt | 9 + editor/src/IntakeToQueueSimulationHarness.h | 96 ++++++++++ editor/tests/step582_test.cpp | 193 ++++++++++++++++++++ progress.md | 33 ++++ 4 files changed, 331 insertions(+) create mode 100644 editor/src/IntakeToQueueSimulationHarness.h create mode 100644 editor/tests/step582_test.cpp diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 96af0d5..a2c3485 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -4117,4 +4117,13 @@ target_link_libraries(step581_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step582_test tests/step582_test.cpp) +target_include_directories(step582_test PRIVATE src) +target_link_libraries(step582_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/IntakeToQueueSimulationHarness.h b/editor/src/IntakeToQueueSimulationHarness.h new file mode 100644 index 0000000..a441cbd --- /dev/null +++ b/editor/src/IntakeToQueueSimulationHarness.h @@ -0,0 +1,96 @@ +#pragma once +// Step 582: Intake-to-Queue Simulation Harness + +#include "AcceptanceCriteriaBinding.h" +#include "ArchitectReviewSurface.h" +#include "MarkdownSpecParser.h" +#include "RequirementNormalizationConflictDetector.h" +#include "ScopeMilestoneDecomposer.h" +#include "TaskitemConfidenceAmbiguity.h" +#include "TaskitemGeneratorV2.h" + +#include +#include + +struct IntakeQueueSimulationInput { + std::string markdown; + std::string reviewer = "architect"; + bool modifyConstraints = false; +}; + +struct IntakeQueueSimulationResult { + bool ok = false; + std::size_t queuedCount = 0; + std::size_t escalatedCount = 0; + std::size_t boundCheckCount = 0; + std::vector queue; + std::vector notes; +}; + +class IntakeToQueueSimulationHarness { +public: + static IntakeQueueSimulationResult run(const IntakeQueueSimulationInput& input) { + IntakeQueueSimulationResult result; + ParsedMarkdownSpec parsed; + std::string error; + if (!MarkdownSpecParser::parse(input.markdown, &parsed, &error)) { + result.notes.push_back("fail:parse"); + return result; + } + + RequirementNormalizationResult normalized; + if (!RequirementNormalizationConflictDetector::normalize(parsed, &normalized, &error)) { + result.notes.push_back("fail:normalize"); + return result; + } + + DecomposedScopePlan plan; + if (!ScopeMilestoneDecomposer::decompose(normalized, &plan, &error)) { + result.notes.push_back("fail:decompose"); + return result; + } + + ArchitectReviewSurface review; + if (!review.loadConstraints(normalized.requirements, &error)) { + result.notes.push_back("fail:review_load"); + return result; + } + for (const auto& item : review.items()) { + const bool ok = input.modifyConstraints + ? review.modify(item.requirementId, item.originalText + " reviewed", input.reviewer, &error) + : review.approve(item.requirementId, input.reviewer, &error); + if (!ok) { + result.notes.push_back("fail:review_decision"); + return result; + } + } + + std::vector generated; + if (!TaskitemGeneratorV2::generate(plan, &generated, &error)) { + result.notes.push_back("fail:generate"); + return result; + } + + std::vector annotated; + if (!TaskitemConfidenceAmbiguity::annotate(generated, normalized, &annotated, &error)) { + result.notes.push_back("fail:annotate"); + return result; + } + + std::vector bound; + if (!AcceptanceCriteriaBinding::bind(annotated, normalized.requirements, &bound, &error)) { + result.notes.push_back("fail:bind_acceptance"); + return result; + } + + result.queue = bound; + for (const auto& task : bound) { + if (task.task.base.queueReady && task.hasCoverage) ++result.queuedCount; + if (task.task.escalate) ++result.escalatedCount; + result.boundCheckCount += task.checks.size(); + } + result.ok = !result.queue.empty(); + if (result.ok) result.notes.push_back("queue:ready"); + return result; + } +}; diff --git a/editor/tests/step582_test.cpp b/editor/tests/step582_test.cpp new file mode 100644 index 0000000..71a6949 --- /dev/null +++ b/editor/tests/step582_test.cpp @@ -0,0 +1,193 @@ +// Step 582: Intake-to-Queue Simulation Harness (12 tests) + +#include "IntakeToQueueSimulationHarness.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; } else {} + +static std::string validMarkdown() { + return R"(## Goals +- Improve intake quality + +## Constraints +- Enable deterministic parser behavior + +## Dependencies +- CMake + +## Acceptance Criteria +- Queue includes bound acceptance checks +- Confidence annotations are present +)"; +} + +static bool hasNote(const IntakeQueueSimulationResult& r, const std::string& note) { + for (const auto& n : r.notes) if (n == note) return true; + return false; +} + +void test_full_pipeline_success() { + TEST(full_pipeline_success); + IntakeQueueSimulationInput input; + input.markdown = validMarkdown(); + auto result = IntakeToQueueSimulationHarness::run(input); + CHECK(result.ok, "pipeline should succeed"); + CHECK(hasNote(result, "queue:ready"), "queue ready note expected"); + PASS(); +} + +void test_parse_failure() { + TEST(parse_failure); + IntakeQueueSimulationInput input; + input.markdown = ""; + auto result = IntakeToQueueSimulationHarness::run(input); + CHECK(!result.ok, "pipeline should fail"); + CHECK(hasNote(result, "fail:parse"), "parse failure note expected"); + PASS(); +} + +void test_normalize_failure() { + TEST(normalize_failure); + IntakeQueueSimulationInput input; + input.markdown = "## Notes\ntext"; + auto result = IntakeToQueueSimulationHarness::run(input); + CHECK(!result.ok, "pipeline should fail"); + CHECK(hasNote(result, "fail:normalize"), "normalize failure note expected"); + PASS(); +} + +void test_review_load_failure_when_constraints_missing() { + TEST(review_load_failure_when_constraints_missing); + IntakeQueueSimulationInput input; + input.markdown = R"(## Goals +- Goal +## Acceptance Criteria +- Done +)"; + auto result = IntakeToQueueSimulationHarness::run(input); + CHECK(!result.ok, "pipeline should fail"); + CHECK(hasNote(result, "fail:review_load"), "review load failure expected"); + PASS(); +} + +void test_modify_constraints_mode_still_succeeds() { + TEST(modify_constraints_mode_still_succeeds); + IntakeQueueSimulationInput input; + input.markdown = validMarkdown(); + input.modifyConstraints = true; + auto result = IntakeToQueueSimulationHarness::run(input); + CHECK(result.ok, "pipeline should succeed"); + CHECK(result.queuedCount > 0, "queued count should be positive"); + PASS(); +} + +void test_queue_count_matches_queue_ready_items() { + TEST(queue_count_matches_queue_ready_items); + IntakeQueueSimulationInput input; + input.markdown = validMarkdown(); + auto result = IntakeToQueueSimulationHarness::run(input); + CHECK(result.ok, "pipeline should succeed"); + CHECK(result.queuedCount == result.queue.size(), "all queued items should be queue ready"); + PASS(); +} + +void test_bound_check_count_is_accumulated() { + TEST(bound_check_count_is_accumulated); + IntakeQueueSimulationInput input; + input.markdown = validMarkdown(); + auto result = IntakeToQueueSimulationHarness::run(input); + CHECK(result.ok, "pipeline should succeed"); + CHECK(result.boundCheckCount >= 2, "expected at least two bound checks"); + PASS(); +} + +void test_escalation_count_exposed() { + TEST(escalation_count_exposed); + IntakeQueueSimulationInput input; + input.markdown = R"(## Goals +- Maybe improve quality somehow + +## Constraints +- Enable parser + +## Dependencies +- CMake + +## Acceptance Criteria +- Done +)"; + auto result = IntakeToQueueSimulationHarness::run(input); + CHECK(result.ok, "pipeline should succeed"); + CHECK(result.escalatedCount >= 1, "escalation count should be at least one"); + PASS(); +} + +void test_result_queue_contains_coverage() { + TEST(result_queue_contains_coverage); + IntakeQueueSimulationInput input; + input.markdown = validMarkdown(); + auto result = IntakeToQueueSimulationHarness::run(input); + CHECK(result.ok, "pipeline should succeed"); + CHECK(result.queue[0].hasCoverage, "bound task should have coverage"); + PASS(); +} + +void test_result_queue_contains_task_ids() { + TEST(result_queue_contains_task_ids); + IntakeQueueSimulationInput input; + input.markdown = validMarkdown(); + auto result = IntakeToQueueSimulationHarness::run(input); + CHECK(result.ok, "pipeline should succeed"); + CHECK(!result.queue[0].task.base.taskId.empty(), "task id should not be empty"); + PASS(); +} + +void test_acceptance_binding_failure_propagates() { + TEST(acceptance_binding_failure_propagates); + IntakeQueueSimulationInput input; + input.markdown = R"(## Goals +- improve +## Constraints +- enable parser +## Dependencies +- cmake +)"; + auto result = IntakeToQueueSimulationHarness::run(input); + CHECK(!result.ok, "pipeline should fail"); + CHECK(hasNote(result, "fail:bind_acceptance"), "bind failure note expected"); + PASS(); +} + +void test_queue_ready_note_only_on_success() { + TEST(queue_ready_note_only_on_success); + IntakeQueueSimulationInput input; + input.markdown = ""; + auto result = IntakeToQueueSimulationHarness::run(input); + CHECK(!hasNote(result, "queue:ready"), "queue note should not appear on failure"); + PASS(); +} + +int main() { + std::cout << "Step 582: Intake-to-Queue Simulation Harness\n"; + + test_full_pipeline_success(); // 1 + test_parse_failure(); // 2 + test_normalize_failure(); // 3 + test_review_load_failure_when_constraints_missing();// 4 + test_modify_constraints_mode_still_succeeds(); // 5 + test_queue_count_matches_queue_ready_items(); // 6 + test_bound_check_count_is_accumulated(); // 7 + test_escalation_count_exposed(); // 8 + test_result_queue_contains_coverage(); // 9 + test_result_queue_contains_task_ids(); // 10 + test_acceptance_binding_failure_propagates(); // 11 + test_queue_ready_note_only_on_success(); // 12 + + std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n"; + return failed == 0 ? 0 : 1; +} diff --git a/progress.md b/progress.md index 3f8c8f7..73b4313 100644 --- a/progress.md +++ b/progress.md @@ -10836,3 +10836,36 @@ check identities and generated test-skeleton handles. - `editor/src/AcceptanceCriteriaBinding.h` within header-size limit (`83` <= `600`) - `editor/tests/step581_test.cpp` within test-file size guidance (`185` lines) - Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md` + +### Step 582: Intake-to-Queue Simulation Harness +**Status:** PASS (12/12 tests) + +Implements an end-to-end intake simulation harness from markdown ingestion to +queue-ready taskitems with confidence, escalation, and acceptance coverage. + +**Files added:** +- `editor/src/IntakeToQueueSimulationHarness.h` - end-to-end harness module: + - parser -> normalization -> decomposition -> review -> generation -> annotation -> binding pipeline + - queue metrics aggregation (queued/escalated/check-count) + - failure-stage notes for each pipeline gate + - successful queue readiness signaling +- `editor/tests/step582_test.cpp` - 12 tests covering: + - full pipeline success behavior + - parse/normalize/review/binding failure propagation behavior + - modify-review path behavior + - queue/check/escalation metric behavior + - success-note emission behavior + +**Files modified:** +- `editor/CMakeLists.txt` - `step582_test` target + +**Verification run:** +- `cmake -S editor -B editor/build-native` - PASS +- `cmake --build editor/build-native --target step582_test step581_test` - PASS +- `./editor/build-native/step582_test` - PASS (12/12) +- `./editor/build-native/step581_test` - PASS (12/12) regression coverage + +**Architecture gate check:** +- `editor/src/IntakeToQueueSimulationHarness.h` within header-size limit (`96` <= `600`) +- `editor/tests/step582_test.cpp` within test-file size guidance (`193` lines) +- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`