Step 578: integrate phase 32a markdown intake pipeline

This commit is contained in:
Bill
2026-02-17 11:08:37 -07:00
parent 820b2743fd
commit 31cb1c8bff
4 changed files with 289 additions and 0 deletions

View File

@@ -4081,4 +4081,13 @@ target_link_libraries(step577_test PRIVATE
tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go)
add_executable(step578_test tests/step578_test.cpp)
target_include_directories(step578_test PRIVATE src)
target_link_libraries(step578_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)

View File

@@ -0,0 +1,104 @@
#pragma once
// Step 578: Phase 32a Integration
#include "ArchitectReviewSurface.h"
#include "MarkdownSpecParser.h"
#include "RequirementNormalizationConflictDetector.h"
#include "ScopeMilestoneDecomposer.h"
#include <string>
#include <vector>
struct Phase32aInput {
std::string markdown;
std::string reviewer = "architect";
bool autoApproveConstraints = true;
bool forceRejectFirstConstraint = false;
};
struct Phase32aResult {
bool parseReady = false;
bool normalizationReady = false;
bool decompositionReady = false;
bool reviewReady = false;
bool phase32aPass = false;
std::size_t parsedSectionCount = 0;
std::size_t conflictCount = 0;
int overallUncertainty = 0;
ConstraintReviewSummary reviewSummary;
std::vector<std::string> notes;
};
class Phase32aIntegration {
public:
static Phase32aResult run(const Phase32aInput& input) {
Phase32aResult result;
ParsedMarkdownSpec parsed;
std::string error;
if (!MarkdownSpecParser::parse(input.markdown, &parsed, &error)) {
result.notes.push_back("fail:markdown_parse");
return finalize(result);
}
result.parseReady = true;
result.parsedSectionCount = parsed.sections.size();
RequirementNormalizationResult normalized;
if (!RequirementNormalizationConflictDetector::normalize(parsed, &normalized, &error)) {
result.notes.push_back("fail:normalization");
return finalize(result);
}
result.normalizationReady = true;
result.conflictCount = normalized.conflicts.size();
DecomposedScopePlan plan;
if (!ScopeMilestoneDecomposer::decompose(normalized, &plan, &error)) {
result.notes.push_back("fail:decomposition");
return finalize(result);
}
result.decompositionReady = true;
result.overallUncertainty = plan.overallUncertainty;
ArchitectReviewSurface review;
if (!review.loadConstraints(normalized.requirements, &error)) {
result.notes.push_back("fail:review_load");
return finalize(result);
}
const auto items = review.items();
for (std::size_t i = 0; i < items.size(); ++i) {
const auto& item = items[i];
bool ok = false;
if (input.forceRejectFirstConstraint && i == 0) {
ok = review.reject(item.requirementId, input.reviewer, &error);
} else if (input.autoApproveConstraints) {
ok = review.approve(item.requirementId, input.reviewer, &error);
} else {
ok = review.modify(item.requirementId, item.originalText + " reviewed", input.reviewer, &error);
}
if (!ok) {
result.notes.push_back("fail:review_decision");
return finalize(result);
}
}
result.reviewSummary = review.summarize();
result.reviewReady = result.reviewSummary.allDecided;
if (!result.reviewReady) {
result.notes.push_back("fail:review_incomplete");
return finalize(result);
}
result.notes.push_back("phase32a:markdown_intake_cycle_ready");
return finalize(result);
}
private:
static Phase32aResult finalize(Phase32aResult result) {
result.phase32aPass = result.parseReady &&
result.normalizationReady &&
result.decompositionReady &&
result.reviewReady;
if (!result.phase32aPass) result.notes.push_back("phase32a:blocked");
return result;
}
};

View File

@@ -0,0 +1,139 @@
// Step 578: Phase 32a Integration (8 tests)
#include "Phase32aIntegration.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 bool hasNote(const Phase32aResult& r, const std::string& note) {
for (const auto& n : r.notes) if (n == note) return true;
return false;
}
static std::string validMarkdown() {
return R"(## Goals
- Improve intake reliability
## Constraints
- Enable deterministic parsing
- Do not enable deterministic parsing
## Dependencies
- CMake
## Acceptance Criteria
- Parse all required sections
)";
}
void test_full_cycle_passes_with_auto_approval() {
TEST(full_cycle_passes_with_auto_approval);
Phase32aInput input;
input.markdown = validMarkdown();
auto result = Phase32aIntegration::run(input);
CHECK(result.phase32aPass, "phase should pass");
CHECK(result.parseReady, "parse should be ready");
CHECK(result.normalizationReady, "normalization should be ready");
CHECK(result.decompositionReady, "decomposition should be ready");
CHECK(result.reviewReady, "review should be ready");
CHECK(hasNote(result, "phase32a:markdown_intake_cycle_ready"), "success note missing");
PASS();
}
void test_parse_failure_blocks_phase() {
TEST(parse_failure_blocks_phase);
Phase32aInput input;
input.markdown = "";
auto result = Phase32aIntegration::run(input);
CHECK(!result.phase32aPass, "phase should fail");
CHECK(hasNote(result, "fail:markdown_parse"), "parse failure note expected");
PASS();
}
void test_normalization_failure_blocks_phase() {
TEST(normalization_failure_blocks_phase);
Phase32aInput input;
input.markdown = "## Notes\ntext only";
auto result = Phase32aIntegration::run(input);
CHECK(!result.phase32aPass, "phase should fail");
CHECK(hasNote(result, "fail:normalization"), "normalization failure note expected");
PASS();
}
void test_review_load_failure_when_no_constraints() {
TEST(review_load_failure_when_no_constraints);
Phase32aInput input;
input.markdown = R"(## Goals
- goal
## Acceptance Criteria
- done
)";
auto result = Phase32aIntegration::run(input);
CHECK(!result.phase32aPass, "phase should fail");
CHECK(hasNote(result, "fail:review_load"), "review load failure note expected");
PASS();
}
void test_modify_mode_passes_and_counts_modified() {
TEST(modify_mode_passes_and_counts_modified);
Phase32aInput input;
input.markdown = validMarkdown();
input.autoApproveConstraints = false;
auto result = Phase32aIntegration::run(input);
CHECK(result.phase32aPass, "phase should pass");
CHECK(result.reviewSummary.modified == 2, "modified count mismatch");
PASS();
}
void test_force_reject_first_constraint_counts_rejected() {
TEST(force_reject_first_constraint_counts_rejected);
Phase32aInput input;
input.markdown = validMarkdown();
input.forceRejectFirstConstraint = true;
auto result = Phase32aIntegration::run(input);
CHECK(result.phase32aPass, "phase should still pass");
CHECK(result.reviewSummary.rejected == 1, "one rejected expected");
CHECK(result.reviewSummary.approved == 1, "one approved expected");
PASS();
}
void test_conflict_count_exposed() {
TEST(conflict_count_exposed);
Phase32aInput input;
input.markdown = validMarkdown();
auto result = Phase32aIntegration::run(input);
CHECK(result.phase32aPass, "phase should pass");
CHECK(result.conflictCount >= 1, "conflict count should be exposed");
PASS();
}
void test_parsed_section_count_exposed() {
TEST(parsed_section_count_exposed);
Phase32aInput input;
input.markdown = validMarkdown();
auto result = Phase32aIntegration::run(input);
CHECK(result.phase32aPass, "phase should pass");
CHECK(result.parsedSectionCount == 4, "section count mismatch");
PASS();
}
int main() {
std::cout << "Step 578: Phase 32a Integration\n";
test_full_cycle_passes_with_auto_approval(); // 1
test_parse_failure_blocks_phase(); // 2
test_normalization_failure_blocks_phase(); // 3
test_review_load_failure_when_no_constraints(); // 4
test_modify_mode_passes_and_counts_modified(); // 5
test_force_reject_first_constraint_counts_rejected(); // 6
test_conflict_count_exposed(); // 7
test_parsed_section_count_exposed(); // 8
std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n";
return failed == 0 ? 0 : 1;
}

View File

@@ -10696,3 +10696,40 @@ enabling approve/modify/reject decisions before task generation.
- `editor/src/ArchitectReviewSurface.h` within header-size limit (`126` <= `600`)
- `editor/tests/step577_test.cpp` within test-file size guidance (`178` lines)
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`
### Step 578: Phase 32a Integration
**Status:** PASS (8/8 tests)
Integrates the Phase 32a markdown intake pipeline across parser,
normalization/conflict detection, decomposition, and architect review workflow.
**Files added:**
- `editor/src/Phase32aIntegration.h` - Phase 32a integration module:
- markdown parse + normalization orchestration
- conflict and uncertainty signal propagation
- decomposition and review-load gating
- review decision automation modes (approve/modify/reject-first)
- phase readiness and failure-note synthesis
- `editor/tests/step578_test.cpp` - 8 tests covering:
- full-cycle happy path behavior
- parse/normalize/review-load failure behavior
- modify/reject review decision behavior
- conflict count and parsed section count exposure behavior
**Files modified:**
- `editor/CMakeLists.txt` - `step578_test` target
**Verification run:**
- `cmake -S editor -B editor/build-native` - PASS
- `cmake --build editor/build-native --target step578_test step577_test` - PASS
- `./editor/build-native/step578_test` - PASS (8/8)
- `./editor/build-native/step577_test` - PASS (12/12) regression coverage
**Architecture gate check:**
- `editor/src/Phase32aIntegration.h` within header-size limit (`104` <= `600`)
- `editor/tests/step578_test.cpp` within test-file size guidance (`139` lines)
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`
**Phase 32a totals (574-578):**
- **Steps completed:** 5
- **New tests in this phase plan:** 56/56 passing