Step 582: add intake to queue simulation harness
This commit is contained in:
@@ -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)
|
||||
|
||||
96
editor/src/IntakeToQueueSimulationHarness.h
Normal file
96
editor/src/IntakeToQueueSimulationHarness.h
Normal file
@@ -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 <string>
|
||||
#include <vector>
|
||||
|
||||
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<BoundTaskitem> queue;
|
||||
std::vector<std::string> 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<GeneratedTaskitem> generated;
|
||||
if (!TaskitemGeneratorV2::generate(plan, &generated, &error)) {
|
||||
result.notes.push_back("fail:generate");
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<AnnotatedTaskitem> annotated;
|
||||
if (!TaskitemConfidenceAmbiguity::annotate(generated, normalized, &annotated, &error)) {
|
||||
result.notes.push_back("fail:annotate");
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<BoundTaskitem> 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;
|
||||
}
|
||||
};
|
||||
193
editor/tests/step582_test.cpp
Normal file
193
editor/tests/step582_test.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
// Step 582: Intake-to-Queue Simulation Harness (12 tests)
|
||||
|
||||
#include "IntakeToQueueSimulationHarness.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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;
|
||||
}
|
||||
33
progress.md
33
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`
|
||||
|
||||
Reference in New Issue
Block a user