Complete step474 skeleton generation from requirements with tests

This commit is contained in:
Bill
2026-02-16 20:54:22 -07:00
parent 6d4035f44c
commit fe490c1b1a
4 changed files with 437 additions and 0 deletions

View File

@@ -3145,4 +3145,13 @@ target_link_libraries(step473_test PRIVATE
tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go)
add_executable(step474_test tests/step474_test.cpp)
target_include_directories(step474_test PRIVATE src)
target_link_libraries(step474_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,198 @@
#pragma once
// Step 474: Skeleton Generation from Requirements
// Produces a multi-module annotated skeleton project specification from
// requirements, module graph, and selected technology stack.
#include "ArchitectTechStackSelector.h"
#include <algorithm>
#include <set>
#include <string>
#include <vector>
struct SkeletonAnnotation {
std::string key; // e.g. @Intent
std::string value; // e.g. "user authentication"
};
struct SkeletonFunctionSpec {
std::string name;
std::string signature;
std::vector<SkeletonAnnotation> annotations;
};
struct SkeletonModuleSpec {
std::string moduleName;
std::string language;
std::string framework;
std::string database;
std::vector<std::string> dependencies;
std::vector<SkeletonFunctionSpec> functions;
};
struct SkeletonProjectSpec {
std::vector<SkeletonModuleSpec> modules;
bool hasModule(const std::string& moduleName) const {
for (const auto& m : modules) if (m.moduleName == moduleName) return true;
return false;
}
SkeletonModuleSpec getModule(const std::string& moduleName) const {
for (const auto& m : modules) if (m.moduleName == moduleName) return m;
return {};
}
};
class ArchitectSkeletonGenerator {
public:
static SkeletonProjectSpec generate(const StructuredRequirements& reqs,
const ModuleGraph& graph,
const TechStackDecision& stack) {
SkeletonProjectSpec out;
for (const auto& choice : stack.choices) {
SkeletonModuleSpec mod;
mod.moduleName = choice.moduleName;
mod.language = choice.language;
mod.framework = choice.framework;
mod.database = choice.database;
mod.dependencies = collectDependencies(graph, choice.moduleName);
mod.functions = generateFunctions(reqs, graph, choice.moduleName);
out.modules.push_back(std::move(mod));
}
// Ensure all non-cross-cutting modules are present even if stack choice was sparse.
for (const auto& n : graph.nodes) {
if (n.crossCutting) continue;
if (!out.hasModule(n.name)) {
SkeletonModuleSpec mod;
mod.moduleName = n.name;
mod.language = "python";
mod.dependencies = collectDependencies(graph, n.name);
mod.functions = generateFunctions(reqs, graph, n.name);
out.modules.push_back(std::move(mod));
}
}
return out;
}
private:
static std::vector<std::string> collectDependencies(const ModuleGraph& graph,
const std::string& moduleName) {
std::set<std::string> deps;
for (const auto& e : graph.edges) {
if (e.from == moduleName) deps.insert(e.to);
}
return std::vector<std::string>(deps.begin(), deps.end());
}
static std::vector<SkeletonFunctionSpec> generateFunctions(const StructuredRequirements& reqs,
const ModuleGraph& graph,
const std::string& moduleName) {
std::vector<SkeletonFunctionSpec> out;
// Seed function names per module role.
if (moduleName == "api") {
out.push_back(makeFn("handleRequest", "Response handleRequest(Request req)", reqs, graph, moduleName));
out.push_back(makeFn("validateRequest", "bool validateRequest(Request req)", reqs, graph, moduleName));
} else if (moduleName == "auth") {
out.push_back(makeFn("authenticateUser", "AuthResult authenticateUser(Credentials creds)", reqs, graph, moduleName));
out.push_back(makeFn("authorizeAction", "bool authorizeAction(User user, Action action)", reqs, graph, moduleName));
} else if (moduleName == "ui") {
out.push_back(makeFn("renderView", "View renderView(State state)", reqs, graph, moduleName));
out.push_back(makeFn("handleInteraction", "State handleInteraction(Event event)", reqs, graph, moduleName));
} else if (moduleName == "data") {
out.push_back(makeFn("saveEntity", "bool saveEntity(Entity entity)", reqs, graph, moduleName));
out.push_back(makeFn("loadEntity", "Entity loadEntity(Id id)", reqs, graph, moduleName));
} else if (moduleName == "search") {
out.push_back(makeFn("search", "Results search(Query query)", reqs, graph, moduleName));
} else if (moduleName == "reporting") {
out.push_back(makeFn("generateReport", "Report generateReport(Filter filter)", reqs, graph, moduleName));
} else if (moduleName == "notifications") {
out.push_back(makeFn("sendNotification", "bool sendNotification(Message msg)", reqs, graph, moduleName));
} else if (moduleName == "integrations") {
out.push_back(makeFn("callExternalService", "ExternalResult callExternalService(Payload payload)", reqs, graph, moduleName));
} else {
out.push_back(makeFn("execute", "void execute()", reqs, graph, moduleName));
}
return out;
}
static SkeletonFunctionSpec makeFn(const std::string& name,
const std::string& sig,
const StructuredRequirements& reqs,
const ModuleGraph& graph,
const std::string& moduleName) {
SkeletonFunctionSpec fn;
fn.name = name;
fn.signature = sig;
// Intent annotation from module + functional requirements.
fn.annotations.push_back({"@Intent", inferIntent(reqs, moduleName, name)});
// Routing annotations
fn.annotations.push_back({"@Complexity", inferComplexity(graph, moduleName)});
fn.annotations.push_back({"@ContextWidth", inferContextWidth(moduleName)});
fn.annotations.push_back({"@Automatability", inferAutomatability(moduleName, name)});
// Contract annotation from functional requirements
fn.annotations.push_back({"@Contract", inferContract(reqs, moduleName, name)});
return fn;
}
static std::string inferIntent(const StructuredRequirements& reqs,
const std::string& moduleName,
const std::string& fnName) {
std::string seed = moduleName + ":" + fnName;
if (!reqs.functionalRequirements.empty()) {
seed += " " + reqs.functionalRequirements[0].text;
}
return seed;
}
static std::string inferComplexity(const ModuleGraph& graph, const std::string& moduleName) {
for (const auto& n : graph.nodes) {
if (n.name == moduleName) {
if (n.complexity >= 8) return "high";
if (n.complexity >= 4) return "medium";
return "low";
}
}
return "medium";
}
static std::string inferContextWidth(const std::string& moduleName) {
if (moduleName == "api" || moduleName == "core" || moduleName == "auth") return "project";
if (moduleName == "integrations" || moduleName == "reporting") return "module";
return "file";
}
static std::string inferAutomatability(const std::string& moduleName,
const std::string& fnName) {
(void)fnName;
if (moduleName == "security" || moduleName == "auth") return "human";
if (moduleName == "api" || moduleName == "data") return "llm";
return "deterministic";
}
static std::string inferContract(const StructuredRequirements& reqs,
const std::string& moduleName,
const std::string& fnName) {
std::string contract = "pre: valid input; post: deterministic output";
if (moduleName == "auth") {
contract = "pre: credentials provided; post: auth decision emitted";
} else if (moduleName == "data") {
contract = "pre: entity schema valid; post: persistence consistency";
} else if (moduleName == "api" && fnName.find("validate") != std::string::npos) {
contract = "pre: request shape provided; post: validation status";
}
if (!reqs.nonFunctionalRequirements.empty() &&
reqs.nonFunctionalRequirements[0].text.find("secure") != std::string::npos) {
contract += "; sec: enforce security constraints";
}
return contract;
}
};

View File

@@ -0,0 +1,187 @@
// Step 474: Skeleton Generation from Requirements Tests (12 tests)
#include "ArchitectSkeletonGenerator.h"
#include <iostream>
static int passed = 0, failed = 0;
#define TEST(name) { std::cout << " " << #name << "... " << std::flush; }
#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 StructuredRequirements reqFrom(const std::string& s) {
return ArchitectProblemParser::parse(s);
}
static SkeletonProjectSpec makeSkeleton(const std::string& prompt) {
auto req = reqFrom(prompt);
auto graph = ArchitectModuleDecomposer::decompose(req, DecompositionStrategy::Layered);
auto stack = ArchitectTechStackSelector::select(req, graph);
return ArchitectSkeletonGenerator::generate(req, graph, stack);
}
void test_generates_modules_from_graph_and_stack() {
TEST(generates_modules_from_graph_and_stack);
auto sk = makeSkeleton("Build a web REST API with auth and PostgreSQL.");
CHECK(sk.hasModule("api"), "missing api module");
CHECK(sk.hasModule("auth"), "missing auth module");
CHECK(sk.hasModule("data"), "missing data module");
PASS();
}
void test_module_languages_match_stack_choices() {
TEST(module_languages_match_stack_choices);
auto sk = makeSkeleton("Build a web REST API with auth and PostgreSQL.");
auto ui = sk.getModule("ui");
auto api = sk.getModule("api");
CHECK(ui.language == "typescript", "expected typescript ui");
CHECK(!api.language.empty(), "expected backend language");
PASS();
}
void test_generates_skeleton_functions_per_module() {
TEST(generates_skeleton_functions_per_module);
auto sk = makeSkeleton("Build a REST API with auth.");
auto api = sk.getModule("api");
auto auth = sk.getModule("auth");
CHECK(api.functions.size() >= 1, "expected api functions");
CHECK(auth.functions.size() >= 1, "expected auth functions");
PASS();
}
void test_adds_intent_annotations() {
TEST(adds_intent_annotations);
auto sk = makeSkeleton("Build a REST API with auth.");
CHECK(sk.hasModule("api"), "missing api module");
auto api = sk.getModule("api");
CHECK(!api.functions.empty(), "missing api functions");
bool foundIntent = false;
for (const auto& a : api.functions[0].annotations) {
if (a.key == "@Intent" && !a.value.empty()) foundIntent = true;
}
CHECK(foundIntent, "missing @Intent annotation");
PASS();
}
void test_adds_routing_annotations_complexity_context_automatability() {
TEST(adds_routing_annotations_complexity_context_automatability);
auto sk = makeSkeleton("Build a secure low-latency REST API with auth.");
CHECK(sk.hasModule("api"), "missing api module");
auto api = sk.getModule("api");
CHECK(!api.functions.empty(), "missing api functions");
bool hasComplexity = false, hasContext = false, hasAutomatability = false;
for (const auto& a : api.functions[0].annotations) {
if (a.key == "@Complexity") hasComplexity = true;
if (a.key == "@ContextWidth") hasContext = true;
if (a.key == "@Automatability") hasAutomatability = true;
}
CHECK(hasComplexity && hasContext && hasAutomatability, "missing routing annotations");
PASS();
}
void test_adds_contract_annotations() {
TEST(adds_contract_annotations);
auto sk = makeSkeleton("Build a secure REST API with auth.");
CHECK(sk.hasModule("auth"), "missing auth module");
auto auth = sk.getModule("auth");
CHECK(!auth.functions.empty(), "missing auth functions");
bool hasContract = false;
for (const auto& a : auth.functions[0].annotations) {
if (a.key == "@Contract" && a.value.find("auth") != std::string::npos) hasContract = true;
}
CHECK(hasContract, "missing @Contract annotation");
PASS();
}
void test_adds_dependency_annotations_between_modules() {
TEST(adds_dependency_annotations_between_modules);
auto sk = makeSkeleton("Build a web REST API with auth and PostgreSQL.");
auto api = sk.getModule("api");
bool hasAuthDep = false;
for (const auto& d : api.dependencies) {
if (d == "auth") hasAuthDep = true;
}
CHECK(hasAuthDep, "expected api->auth dependency");
PASS();
}
void test_generates_multifile_multi_module_spec() {
TEST(generates_multifile_multi_module_spec);
auto sk = makeSkeleton("Build a web dashboard API with auth, search, reporting, and PostgreSQL.");
CHECK(sk.modules.size() >= 4, "expected multi-module skeleton");
PASS();
}
void test_fallback_module_generated_when_stack_sparse() {
TEST(fallback_module_generated_when_stack_sparse);
StructuredRequirements req;
ModuleGraph g;
g.nodes.push_back({"core", {"core behavior"}, 3, false});
TechStackDecision d;
auto sk = ArchitectSkeletonGenerator::generate(req, g, d);
CHECK(sk.hasModule("core"), "expected fallback module generation");
PASS();
}
void test_context_width_varies_by_module_role() {
TEST(context_width_varies_by_module_role);
auto sk = makeSkeleton("Build a REST API with auth and Stripe integration.");
CHECK(sk.hasModule("api"), "missing api module");
CHECK(sk.hasModule("integrations"), "missing integrations module");
auto api = sk.getModule("api");
auto integ = sk.getModule("integrations");
CHECK(!api.functions.empty(), "missing api functions");
CHECK(!integ.functions.empty(), "missing integrations functions");
std::string apiCtx, integCtx;
for (const auto& a : api.functions[0].annotations) if (a.key == "@ContextWidth") apiCtx = a.value;
for (const auto& a : integ.functions[0].annotations) if (a.key == "@ContextWidth") integCtx = a.value;
CHECK(apiCtx == "project", "expected project context for api");
CHECK(integCtx == "module", "expected module context for integrations");
PASS();
}
void test_automatability_human_for_auth_module() {
TEST(automatability_human_for_auth_module);
auto sk = makeSkeleton("Build a secure API with auth.");
CHECK(sk.hasModule("auth"), "missing auth module");
auto auth = sk.getModule("auth");
CHECK(!auth.functions.empty(), "missing auth functions");
std::string autoValue;
for (const auto& a : auth.functions[0].annotations) if (a.key == "@Automatability") autoValue = a.value;
CHECK(autoValue == "human", "expected human automatability for auth");
PASS();
}
void test_contract_enriched_for_secure_requirement() {
TEST(contract_enriched_for_secure_requirement);
auto sk = makeSkeleton("Build a secure API with auth and postgres.");
CHECK(sk.hasModule("api"), "missing api module");
auto api = sk.getModule("api");
CHECK(!api.functions.empty(), "missing api functions");
std::string contract;
for (const auto& a : api.functions[0].annotations) if (a.key == "@Contract") contract = a.value;
CHECK(contract.find("sec:") != std::string::npos, "expected security contract enrichment");
PASS();
}
int main() {
std::cout << "Step 474: Skeleton Generation from Requirements Tests\n";
test_generates_modules_from_graph_and_stack(); // 1
test_module_languages_match_stack_choices(); // 2
test_generates_skeleton_functions_per_module(); // 3
test_adds_intent_annotations(); // 4
test_adds_routing_annotations_complexity_context_automatability(); // 5
test_adds_contract_annotations(); // 6
test_adds_dependency_annotations_between_modules(); // 7
test_generates_multifile_multi_module_spec(); // 8
test_fallback_module_generated_when_stack_sparse(); // 9
test_context_width_varies_by_module_role(); // 10
test_automatability_human_for_auth_module(); // 11
test_contract_enriched_for_secure_requirement(); // 12
std::cout << "\nResults: " << passed << "/" << (passed + failed)
<< " passed\n";
return failed == 0 ? 0 : 1;
}

View File

@@ -6538,3 +6538,46 @@ and preference overrides.
**Architecture gate check:**
- `editor/src/ArchitectTechStackSelector.h` within header-size limit (`156` <= `600`)
- `editor/tests/step473_test.cpp` within test-file size guidance (`168` lines)
### Step 474: Skeleton Generation from Requirements
**Status:** PASS (12/12 tests)
Builds an annotated multi-module skeleton project spec from requirements,
module graph, and technology choices, including routing/contract/dependency
annotations suitable for workflow creation.
**Files added:**
- `editor/src/ArchitectSkeletonGenerator.h` — skeleton generator:
- output model:
- `SkeletonAnnotation`
- `SkeletonFunctionSpec`
- `SkeletonModuleSpec`
- `SkeletonProjectSpec`
- module-level skeleton assembly from stack decisions
- function stub generation by module role (api/auth/ui/data/etc.)
- annotation generation:
- `@Intent`
- `@Complexity`
- `@ContextWidth`
- `@Automatability`
- `@Contract`
- dependency capture from module graph edges
- sparse/partial stack fallback behavior
- `editor/tests/step474_test.cpp` — 12 tests covering:
- module and language propagation from graph + stack
- function skeleton generation by module
- annotation presence and value behavior
- dependency propagation
- context/automatability routing semantics
- contract enrichment under security requirements
- sparse-input fallback behavior
- `editor/CMakeLists.txt``step474_test` target
**Verification run:**
- `cmake --build editor/build-native --target step474_test` — PASS
- `./editor/build-native/step474_test` — PASS (12/12)
- `./editor/build-native/step473_test` — PASS (12/12) regression coverage
**Architecture gate check:**
- `editor/src/ArchitectSkeletonGenerator.h` within header-size limit (`198` <= `600`)
- `editor/tests/step474_test.cpp` within test-file size guidance (`187` lines)