Step 503: integrate phase 25b scenarios and gates
This commit is contained in:
@@ -3406,4 +3406,13 @@ target_link_libraries(step502_test PRIVATE
|
||||
tree_sitter_javascript tree_sitter_typescript
|
||||
tree_sitter_java tree_sitter_rust tree_sitter_go)
|
||||
|
||||
add_executable(step503_test tests/step503_test.cpp)
|
||||
target_include_directories(step503_test PRIVATE src)
|
||||
target_link_libraries(step503_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)
|
||||
|
||||
@@ -24,7 +24,7 @@ struct TypeMapping {
|
||||
std::string note; // compatibility note
|
||||
};
|
||||
|
||||
struct ContractAnnotation {
|
||||
struct APIMigrationContract {
|
||||
std::string functionName;
|
||||
std::string precondition;
|
||||
std::string postcondition;
|
||||
@@ -43,7 +43,7 @@ struct APIBoundaryReport {
|
||||
std::string targetLanguage;
|
||||
std::vector<FunctionSignature> publicAPI;
|
||||
std::vector<TypeMapping> typeMappings;
|
||||
std::vector<ContractAnnotation> contracts;
|
||||
std::vector<APIMigrationContract> contracts;
|
||||
std::vector<FFIBoundary> ffiBoundaries;
|
||||
bool apiPreserved = true;
|
||||
|
||||
@@ -198,11 +198,11 @@ private:
|
||||
return mappings;
|
||||
}
|
||||
|
||||
static std::vector<ContractAnnotation> generateContracts(
|
||||
static std::vector<APIMigrationContract> generateContracts(
|
||||
const std::vector<FunctionSignature>& api, const std::string& source) {
|
||||
std::vector<ContractAnnotation> contracts;
|
||||
std::vector<APIMigrationContract> contracts;
|
||||
for (const auto& f : api) {
|
||||
ContractAnnotation c;
|
||||
APIMigrationContract c;
|
||||
c.functionName = f.name;
|
||||
// Generate pre/post conditions from signature
|
||||
if (!f.paramTypes.empty()) {
|
||||
|
||||
@@ -176,7 +176,7 @@ private:
|
||||
}
|
||||
|
||||
static std::string generateReturnEdgeCaseBody(const FunctionSignature& func,
|
||||
const ContractAnnotation& contract,
|
||||
const APIMigrationContract& contract,
|
||||
const std::string& lang) {
|
||||
if (lang == "rust") {
|
||||
return "#[test]\nfn test_" + func.name + "_return_contract() {\n"
|
||||
|
||||
229
editor/src/Phase25bIntegration.h
Normal file
229
editor/src/Phase25bIntegration.h
Normal file
@@ -0,0 +1,229 @@
|
||||
#pragma once
|
||||
|
||||
// Step 503: Phase 25b Integration
|
||||
// Integrates the four end-to-end scenario runners from steps 499-502.
|
||||
|
||||
#include "CrossLanguagePortScenarioRunner.h"
|
||||
#include "GreenfieldScenarioRunner.h"
|
||||
#include "LegacyModernizationScenarioRunner.h"
|
||||
#include "MultiModelOrchestrationScenarioRunner.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct Phase25bEvent {
|
||||
std::string scenario;
|
||||
std::string stage;
|
||||
std::string detail;
|
||||
};
|
||||
|
||||
struct ScenarioCostSnapshot {
|
||||
std::string scenario;
|
||||
int estimatedTokens = 0;
|
||||
int actualTokens = 0;
|
||||
|
||||
int delta() const { return std::abs(estimatedTokens - actualTokens); }
|
||||
};
|
||||
|
||||
struct Phase25bIntegrationResult {
|
||||
GreenfieldScenarioResult greenfield;
|
||||
LegacyModernizationScenarioResult legacy;
|
||||
CrossLanguagePortScenarioResult crossLanguage;
|
||||
MultiModelOrchestrationScenarioResult multiModel;
|
||||
|
||||
std::vector<ScenarioCostSnapshot> costs;
|
||||
std::vector<Phase25bEvent> events;
|
||||
std::map<std::string, bool> scenarioPass;
|
||||
int totalSecurityFindings = 0;
|
||||
bool allScenariosPassed = false;
|
||||
bool uniqueWorkflowPathsObserved = false;
|
||||
bool costTrackingAccurate = false;
|
||||
bool eventStreamComplete = false;
|
||||
std::vector<std::string> notes;
|
||||
};
|
||||
|
||||
class Phase25bIntegration {
|
||||
public:
|
||||
static Phase25bIntegrationResult run() {
|
||||
Phase25bIntegrationResult out;
|
||||
|
||||
emit(out, "greenfield", "start", "execute scenario");
|
||||
out.greenfield = GreenfieldScenarioRunner::run(tempRoot(), "phase25b_greenfield");
|
||||
emit(out, "greenfield", "complete", "tasks=" + std::to_string(out.greenfield.tasks.size()));
|
||||
|
||||
emit(out, "legacy", "start", "execute scenario");
|
||||
out.legacy = LegacyModernizationScenarioRunner::run();
|
||||
emit(out, "legacy", "complete",
|
||||
"suggestions=" + std::to_string(out.legacy.modernizationReport.suggestions.size()));
|
||||
|
||||
emit(out, "cross-language", "start", "execute scenario");
|
||||
out.crossLanguage = CrossLanguagePortScenarioRunner::run();
|
||||
emit(out, "cross-language", "complete",
|
||||
"functions=" + std::to_string(out.crossLanguage.functions.size()));
|
||||
|
||||
emit(out, "multi-model", "start", "execute scenario");
|
||||
out.multiModel = MultiModelOrchestrationScenarioRunner::run();
|
||||
emit(out, "multi-model", "complete",
|
||||
"tasks=" + std::to_string(out.multiModel.tasks.size()));
|
||||
|
||||
evaluatePassFlags(out);
|
||||
buildCostSnapshots(out);
|
||||
evaluateIntegrationSignals(out);
|
||||
|
||||
out.notes.push_back("Phase 25b integration pipeline executed");
|
||||
out.notes.push_back(out.allScenariosPassed ? "all scenarios passed" : "one or more scenarios failed");
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
static void emit(Phase25bIntegrationResult& out,
|
||||
const std::string& scenario,
|
||||
const std::string& stage,
|
||||
const std::string& detail) {
|
||||
out.events.push_back({scenario, stage, detail});
|
||||
}
|
||||
|
||||
static std::string tempRoot() {
|
||||
return "/tmp";
|
||||
}
|
||||
|
||||
static void evaluatePassFlags(Phase25bIntegrationResult& out) {
|
||||
out.scenarioPass["greenfield"] =
|
||||
out.greenfield.scaffoldApplied && !out.greenfield.createdPaths.empty();
|
||||
out.scenarioPass["legacy"] =
|
||||
!out.legacy.modernizationReport.suggestions.empty() &&
|
||||
out.legacy.migrationPlan.targetLanguage == "rust";
|
||||
out.scenarioPass["cross-language"] =
|
||||
out.crossLanguage.sourceLanguage == "python" &&
|
||||
out.crossLanguage.targetLanguage == "rust" &&
|
||||
!out.crossLanguage.functions.empty();
|
||||
out.scenarioPass["multi-model"] =
|
||||
out.multiModel.tasks.size() == 20 && out.multiModel.reviewGatesExercised;
|
||||
|
||||
out.allScenariosPassed = true;
|
||||
for (const auto& kv : out.scenarioPass) {
|
||||
if (!kv.second) out.allScenariosPassed = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void buildCostSnapshots(Phase25bIntegrationResult& out) {
|
||||
ScenarioCostSnapshot g;
|
||||
g.scenario = "greenfield";
|
||||
g.estimatedTokens = static_cast<int>(out.greenfield.tasks.size()) * 500;
|
||||
g.actualTokens = estimateGreenfieldActual(out.greenfield);
|
||||
out.costs.push_back(g);
|
||||
|
||||
ScenarioCostSnapshot l;
|
||||
l.scenario = "legacy";
|
||||
l.estimatedTokens = static_cast<int>(out.legacy.modernizationWorkflow.items.size()) * 550;
|
||||
l.actualTokens = estimateLegacyActual(out.legacy);
|
||||
out.costs.push_back(l);
|
||||
|
||||
ScenarioCostSnapshot c;
|
||||
c.scenario = "cross-language";
|
||||
c.estimatedTokens = static_cast<int>(out.crossLanguage.functions.size()) * 700;
|
||||
c.actualTokens = estimateCrossLanguageActual(out.crossLanguage);
|
||||
out.costs.push_back(c);
|
||||
|
||||
ScenarioCostSnapshot m;
|
||||
m.scenario = "multi-model";
|
||||
m.estimatedTokens = out.multiModel.estimatedTotalTokens;
|
||||
m.actualTokens = out.multiModel.actualTotalTokens;
|
||||
out.costs.push_back(m);
|
||||
}
|
||||
|
||||
static void evaluateIntegrationSignals(Phase25bIntegrationResult& out) {
|
||||
out.totalSecurityFindings =
|
||||
static_cast<int>(out.greenfield.securityFindings.size()) +
|
||||
static_cast<int>(out.legacy.safetyReport.findings.size());
|
||||
|
||||
out.uniqueWorkflowPathsObserved =
|
||||
hasUniquePathGreenfield(out.greenfield) &&
|
||||
hasUniquePathLegacy(out.legacy) &&
|
||||
hasUniquePathCrossLanguage(out.crossLanguage) &&
|
||||
hasUniquePathMultiModel(out.multiModel);
|
||||
|
||||
out.costTrackingAccurate = true;
|
||||
for (const auto& c : out.costs) {
|
||||
if (c.estimatedTokens <= 0 || c.actualTokens < 0) {
|
||||
out.costTrackingAccurate = false;
|
||||
break;
|
||||
}
|
||||
if (c.delta() > c.estimatedTokens) {
|
||||
out.costTrackingAccurate = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out.eventStreamComplete = true;
|
||||
for (const auto& name : {"greenfield", "legacy", "cross-language", "multi-model"}) {
|
||||
bool hasStart = false;
|
||||
bool hasComplete = false;
|
||||
for (const auto& e : out.events) {
|
||||
if (e.scenario != name) continue;
|
||||
if (e.stage == "start") hasStart = true;
|
||||
if (e.stage == "complete") hasComplete = true;
|
||||
}
|
||||
if (!hasStart || !hasComplete) out.eventStreamComplete = false;
|
||||
}
|
||||
}
|
||||
|
||||
static int estimateGreenfieldActual(const GreenfieldScenarioResult& r) {
|
||||
int total = 0;
|
||||
for (const auto& t : r.tasks) {
|
||||
if (t.routeTo == "deterministic") total += 0;
|
||||
else if (t.routeTo == "llm") total += 700;
|
||||
else total += 0;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static int estimateLegacyActual(const LegacyModernizationScenarioResult& r) {
|
||||
int total = 0;
|
||||
for (const auto& i : r.modernizationWorkflow.items) {
|
||||
if (i.routing == WorkItemRouting::Deterministic) total += 80;
|
||||
else if (i.routing == WorkItemRouting::LLM) total += 500;
|
||||
else total += 0;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static int estimateCrossLanguageActual(const CrossLanguagePortScenarioResult& r) {
|
||||
int total = 0;
|
||||
for (const auto& f : r.functions) {
|
||||
if (f.confidence.reviewRequired) total += 800;
|
||||
else total += 450;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static bool hasUniquePathGreenfield(const GreenfieldScenarioResult& r) {
|
||||
bool hasDet = false, hasLlm = false, hasHuman = false;
|
||||
for (const auto& t : r.tasks) {
|
||||
if (t.routeTo == "deterministic") hasDet = true;
|
||||
if (t.routeTo == "llm") hasLlm = true;
|
||||
if (t.routeTo == "human") hasHuman = true;
|
||||
}
|
||||
return hasDet && hasLlm && hasHuman;
|
||||
}
|
||||
|
||||
static bool hasUniquePathLegacy(const LegacyModernizationScenarioResult& r) {
|
||||
return r.modernizationWorkflow.countByRouting(WorkItemRouting::Deterministic) > 0 &&
|
||||
r.modernizationWorkflow.countByRouting(WorkItemRouting::LLM) > 0;
|
||||
}
|
||||
|
||||
static bool hasUniquePathCrossLanguage(const CrossLanguagePortScenarioResult& r) {
|
||||
return !r.reviewRequiredFunctions.empty() &&
|
||||
r.concurrencyAnalysis.hasPattern("async/await");
|
||||
}
|
||||
|
||||
static bool hasUniquePathMultiModel(const MultiModelOrchestrationScenarioResult& r) {
|
||||
return r.routedCounts.count("deterministic") &&
|
||||
r.routedCounts.count("template") &&
|
||||
r.routedCounts.count("slm") &&
|
||||
r.routedCounts.count("llm") &&
|
||||
r.routedCounts.count("human");
|
||||
}
|
||||
};
|
||||
97
editor/tests/step503_test.cpp
Normal file
97
editor/tests/step503_test.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
// Step 503: Phase 25b Integration Tests (8 tests)
|
||||
|
||||
#include "Phase25bIntegration.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 Phase25bIntegrationResult runNow() {
|
||||
return Phase25bIntegration::run();
|
||||
}
|
||||
|
||||
void test_all_four_scenarios_run_successfully() {
|
||||
TEST(all_four_scenarios_run_successfully);
|
||||
auto r = runNow();
|
||||
CHECK(r.scenarioPass.size() == 4, "expected 4 scenario pass flags");
|
||||
CHECK(r.allScenariosPassed, "all scenarios should pass");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_each_scenario_exercises_distinct_workflow_path_signals() {
|
||||
TEST(each_scenario_exercises_distinct_workflow_path_signals);
|
||||
auto r = runNow();
|
||||
CHECK(r.uniqueWorkflowPathsObserved, "expected unique workflow path coverage");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_cost_tracking_contains_all_scenarios_and_positive_estimates() {
|
||||
TEST(cost_tracking_contains_all_scenarios_and_positive_estimates);
|
||||
auto r = runNow();
|
||||
CHECK(r.costs.size() == 4, "expected 4 cost snapshots");
|
||||
for (const auto& c : r.costs) {
|
||||
CHECK(c.estimatedTokens > 0, "estimated tokens must be positive");
|
||||
CHECK(c.actualTokens >= 0, "actual tokens must be non-negative");
|
||||
}
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_cost_tracking_accuracy_gate_passes_for_integration() {
|
||||
TEST(cost_tracking_accuracy_gate_passes_for_integration);
|
||||
auto r = runNow();
|
||||
CHECK(r.costTrackingAccurate, "cost tracking should be marked accurate");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_security_findings_are_aggregated_from_generated_code_paths() {
|
||||
TEST(security_findings_are_aggregated_from_generated_code_paths);
|
||||
auto r = runNow();
|
||||
CHECK(r.totalSecurityFindings > 0, "expected aggregated security findings");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_event_stream_captures_start_and_complete_for_each_scenario() {
|
||||
TEST(event_stream_captures_start_and_complete_for_each_scenario);
|
||||
auto r = runNow();
|
||||
CHECK(r.eventStreamComplete, "expected complete start/complete event pairs");
|
||||
CHECK(r.events.size() >= 8, "expected at least start+complete for 4 scenarios");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_multi_model_scenario_keeps_review_gates_exercised_in_integration() {
|
||||
TEST(multi_model_scenario_keeps_review_gates_exercised_in_integration);
|
||||
auto r = runNow();
|
||||
CHECK(r.multiModel.reviewGatesExercised, "multi-model review gates should be exercised");
|
||||
CHECK(r.multiModel.reviewGateCount >= 5, "expected review gates from llm + human tasks");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_integration_notes_include_execution_summary_and_status() {
|
||||
TEST(integration_notes_include_execution_summary_and_status);
|
||||
auto r = runNow();
|
||||
CHECK(r.notes.size() >= 2, "expected integration notes");
|
||||
CHECK(r.notes[0].find("integration pipeline executed") != std::string::npos,
|
||||
"missing execution summary");
|
||||
PASS();
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "Step 503: Phase 25b Integration Tests\n";
|
||||
|
||||
test_all_four_scenarios_run_successfully(); // 1
|
||||
test_each_scenario_exercises_distinct_workflow_path_signals(); // 2
|
||||
test_cost_tracking_contains_all_scenarios_and_positive_estimates(); // 3
|
||||
test_cost_tracking_accuracy_gate_passes_for_integration(); // 4
|
||||
test_security_findings_are_aggregated_from_generated_code_paths(); // 5
|
||||
test_event_stream_captures_start_and_complete_for_each_scenario(); // 6
|
||||
test_multi_model_scenario_keeps_review_gates_exercised_in_integration(); // 7
|
||||
test_integration_notes_include_execution_summary_and_status(); // 8
|
||||
|
||||
std::cout << "\nResults: " << passed << "/" << (passed + failed)
|
||||
<< " passed\n";
|
||||
return failed == 0 ? 0 : 1;
|
||||
}
|
||||
44
progress.md
44
progress.md
@@ -7745,3 +7745,47 @@ that exercises all worker classes and review gates.
|
||||
- `editor/src/MultiModelOrchestrationScenarioRunner.h` within header-size limit (`177` <= `600`)
|
||||
- `editor/tests/step502_test.cpp` within test-file size guidance (`152` lines)
|
||||
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`
|
||||
|
||||
### Step 503: Phase 25b Integration
|
||||
**Status:** PASS (8/8 tests)
|
||||
|
||||
Integrates all four Phase 25b scenario runners (steps 499-502) into a single
|
||||
integration pass with scenario-level status, cost snapshots, security aggregation,
|
||||
workflow-path diversity checks, and event-stream completeness signals.
|
||||
|
||||
**Files added:**
|
||||
- `editor/src/Phase25bIntegration.h` - integration compositor:
|
||||
- executes Greenfield, Legacy Modernization, Cross-Language Port, and Multi-Model scenarios
|
||||
- emits per-scenario start/complete events
|
||||
- computes per-scenario estimated vs actual token snapshots
|
||||
- validates cross-scenario path diversity and cost/event gating
|
||||
- aggregates security findings from generated code/audits
|
||||
- `editor/tests/step503_test.cpp` - 8 integration tests covering:
|
||||
- all-scenario pass state
|
||||
- unique workflow-path signal coverage
|
||||
- cost tracking shape/accuracy gating
|
||||
- security finding aggregation
|
||||
- event stream completeness
|
||||
- integrated review-gate behavior retention
|
||||
- `editor/CMakeLists.txt` - `step503_test` target
|
||||
|
||||
**Compatibility fix applied during integration:**
|
||||
- `editor/src/APIBoundaryPreserver.h`
|
||||
- `editor/src/MigrationTestGenerator.h`
|
||||
- renamed API migration contract struct to `APIMigrationContract` to resolve
|
||||
a symbol collision with AST `ContractAnnotation` when scenario headers are composed
|
||||
in one translation unit.
|
||||
|
||||
**Verification run:**
|
||||
- `cmake -S editor -B editor/build-native` - PASS
|
||||
- `cmake --build editor/build-native --target step503_test step502_test` - PASS
|
||||
- `./editor/build-native/step503_test` - PASS (8/8)
|
||||
- `./editor/build-native/step502_test` - PASS (12/12) regression coverage
|
||||
|
||||
**Architecture gate check:**
|
||||
- `editor/src/Phase25bIntegration.h` within header-size limit (`229` <= `600`)
|
||||
- `editor/tests/step503_test.cpp` within test-file size guidance (`97` lines)
|
||||
- Updated integration dependencies remain within header-size limits:
|
||||
- `editor/src/APIBoundaryPreserver.h` (`253` <= `600`)
|
||||
- `editor/src/MigrationTestGenerator.h` (`213` <= `600`)
|
||||
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`
|
||||
|
||||
Reference in New Issue
Block a user