Complete Step 477: architect templates

This commit is contained in:
Bill
2026-02-16 20:59:47 -07:00
parent e9e54974c6
commit 58066d6f46
4 changed files with 394 additions and 0 deletions

View File

@@ -3172,4 +3172,13 @@ target_link_libraries(step476_test PRIVATE
tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go)
add_executable(step477_test tests/step477_test.cpp)
target_include_directories(step477_test PRIVATE src)
target_link_libraries(step477_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,182 @@
#pragma once
// Step 477: Architecture Templates
// Prebuilt architecture skeleton patterns for common project types.
#include "ArchitectSkeletonGenerator.h"
#include <map>
#include <string>
#include <vector>
enum class ArchitectureTemplateKind {
RestApi,
CliTool,
Library,
Microservice,
FullStack
};
struct TemplateInput {
std::string projectName;
std::string primaryEntity; // e.g. "Book"
std::vector<std::string> fields;
std::string authMethod; // e.g. jwt/oauth/none
};
struct TemplateOutput {
ArchitectureTemplateKind kind = ArchitectureTemplateKind::RestApi;
SkeletonProjectSpec skeleton;
std::vector<std::string> notes;
};
class ArchitectTemplates {
public:
static TemplateOutput instantiate(ArchitectureTemplateKind kind,
const TemplateInput& in) {
TemplateOutput out;
out.kind = kind;
switch (kind) {
case ArchitectureTemplateKind::RestApi:
out.skeleton = restApiTemplate(in);
out.notes.push_back("REST API template applied");
break;
case ArchitectureTemplateKind::CliTool:
out.skeleton = cliTemplate(in);
out.notes.push_back("CLI template applied");
break;
case ArchitectureTemplateKind::Library:
out.skeleton = libraryTemplate(in);
out.notes.push_back("Library template applied");
break;
case ArchitectureTemplateKind::Microservice:
out.skeleton = microserviceTemplate(in);
out.notes.push_back("Microservice template applied");
break;
case ArchitectureTemplateKind::FullStack:
out.skeleton = fullStackTemplate(in);
out.notes.push_back("Full Stack template applied");
break;
}
return out;
}
private:
static SkeletonModuleSpec module(const std::string& name,
const std::string& lang,
std::initializer_list<SkeletonFunctionSpec> fns,
std::initializer_list<std::string> deps = {}) {
SkeletonModuleSpec m;
m.moduleName = name;
m.language = lang;
m.dependencies.assign(deps.begin(), deps.end());
m.functions.assign(fns.begin(), fns.end());
return m;
}
static SkeletonFunctionSpec fn(const std::string& name,
const std::string& sig,
const std::string& intent) {
SkeletonFunctionSpec f;
f.name = name;
f.signature = sig;
f.annotations = {
{"@Intent", intent},
{"@Complexity", "medium"},
{"@ContextWidth", "module"},
{"@Automatability", "llm"},
{"@Contract", "pre: valid input; post: expected output"}
};
return f;
}
static SkeletonProjectSpec restApiTemplate(const TemplateInput& in) {
SkeletonProjectSpec sk;
sk.modules.push_back(module("routes", "typescript", {
fn("registerRoutes", "void registerRoutes(App app)", "register REST routes")
}, {"handlers"}));
sk.modules.push_back(module("handlers", "typescript", {
fn("list" + in.primaryEntity + "s", "Response list(Request req)", "list entities"),
fn("create" + in.primaryEntity, "Response create(Request req)", "create entity")
}, {"models", "database", "auth"}));
sk.modules.push_back(module("models", "typescript", {
fn("validate" + in.primaryEntity, "bool validate(Entity e)", "validate entity")
}));
sk.modules.push_back(module("middleware", "typescript", {
fn("authMiddleware", "bool authMiddleware(Request req)", "enforce auth")
}));
sk.modules.push_back(module("database", "sql", {
fn("migrate", "void migrate()", "apply schema migrations")
}));
sk.modules.push_back(module("auth", "typescript", {
fn("authenticate", "AuthResult authenticate(Request req)", "authenticate request")
}));
return sk;
}
static SkeletonProjectSpec cliTemplate(const TemplateInput& in) {
SkeletonProjectSpec sk;
sk.modules.push_back(module("cli", "python", {
fn("parseArgs", "Options parseArgs(List args)", "parse command-line arguments"),
fn("runCommand", "int runCommand(Options opts)", "execute command")
}, {"output"}));
sk.modules.push_back(module("commands", "python", {
fn("handle" + in.primaryEntity, "int handle(Options opts)", "handle primary command")
}));
sk.modules.push_back(module("output", "python", {
fn("formatOutput", "str formatOutput(Result r)", "format command output")
}));
return sk;
}
static SkeletonProjectSpec libraryTemplate(const TemplateInput& in) {
SkeletonProjectSpec sk;
sk.modules.push_back(module("public_api", "cpp", {
fn("create" + in.primaryEntity, "Result create(Input in)", "public API entrypoint")
}, {"internal"}));
sk.modules.push_back(module("internal", "cpp", {
fn("transform", "Data transform(Data in)", "internal transformation")
}));
sk.modules.push_back(module("tests", "cpp", {
fn("testPublicApi", "void testPublicApi()", "library behavior verification")
}));
sk.modules.push_back(module("docs", "markdown", {
fn("generateDocs", "void generateDocs()", "generate documentation stubs")
}));
return sk;
}
static SkeletonProjectSpec microserviceTemplate(const TemplateInput& in) {
SkeletonProjectSpec sk;
sk.modules.push_back(module("service", "go", {
fn("startService", "error startService(Config cfg)", "start microservice")
}, {"transport", "storage"}));
sk.modules.push_back(module("transport", "go", {
fn("handleRequest", "Response handle(Request req)", "transport request handling")
}));
sk.modules.push_back(module("storage", "go", {
fn("save" + in.primaryEntity, "error save(Entity e)", "persist entity")
}));
sk.modules.push_back(module("health", "go", {
fn("healthCheck", "Status healthCheck()", "service health endpoint")
}));
return sk;
}
static SkeletonProjectSpec fullStackTemplate(const TemplateInput& in) {
SkeletonProjectSpec sk;
sk.modules.push_back(module("frontend", "typescript", {
fn("renderApp", "View renderApp(State s)", "render frontend app")
}, {"backend"}));
sk.modules.push_back(module("backend", "python", {
fn("handleApi", "Response handleApi(Request req)", "backend API handling")
}, {"database", "deploy"}));
sk.modules.push_back(module("database", "sql", {
fn("migrate", "void migrate()", "apply database migrations")
}));
sk.modules.push_back(module("deploy", "yaml", {
fn("generateDeployConfig", "void generateDeployConfig()", "deployment config generation")
}));
return sk;
}
};

View File

@@ -0,0 +1,166 @@
// Step 477: Architecture Templates Tests (12 tests)
#include "ArchitectTemplates.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 TemplateInput sampleInput() {
TemplateInput in;
in.projectName = "bookstore";
in.primaryEntity = "Book";
in.fields = {"id", "title", "author"};
in.authMethod = "jwt";
return in;
}
void test_rest_api_template_contains_expected_modules() {
TEST(rest_api_template_contains_expected_modules);
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, sampleInput());
CHECK(out.skeleton.hasModule("routes"), "missing routes");
CHECK(out.skeleton.hasModule("handlers"), "missing handlers");
CHECK(out.skeleton.hasModule("models"), "missing models");
CHECK(out.skeleton.hasModule("middleware"), "missing middleware");
CHECK(out.skeleton.hasModule("database"), "missing database");
PASS();
}
void test_cli_template_contains_cli_command_output_modules() {
TEST(cli_template_contains_cli_command_output_modules);
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::CliTool, sampleInput());
CHECK(out.skeleton.hasModule("cli"), "missing cli");
CHECK(out.skeleton.hasModule("commands"), "missing commands");
CHECK(out.skeleton.hasModule("output"), "missing output");
PASS();
}
void test_library_template_contains_api_internal_tests_docs() {
TEST(library_template_contains_api_internal_tests_docs);
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::Library, sampleInput());
CHECK(out.skeleton.hasModule("public_api"), "missing public_api");
CHECK(out.skeleton.hasModule("internal"), "missing internal");
CHECK(out.skeleton.hasModule("tests"), "missing tests");
CHECK(out.skeleton.hasModule("docs"), "missing docs");
PASS();
}
void test_microservice_template_contains_service_transport_storage_health() {
TEST(microservice_template_contains_service_transport_storage_health);
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::Microservice, sampleInput());
CHECK(out.skeleton.hasModule("service"), "missing service");
CHECK(out.skeleton.hasModule("transport"), "missing transport");
CHECK(out.skeleton.hasModule("storage"), "missing storage");
CHECK(out.skeleton.hasModule("health"), "missing health");
PASS();
}
void test_fullstack_template_contains_frontend_backend_database_deploy() {
TEST(fullstack_template_contains_frontend_backend_database_deploy);
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::FullStack, sampleInput());
CHECK(out.skeleton.hasModule("frontend"), "missing frontend");
CHECK(out.skeleton.hasModule("backend"), "missing backend");
CHECK(out.skeleton.hasModule("database"), "missing database");
CHECK(out.skeleton.hasModule("deploy"), "missing deploy");
PASS();
}
void test_template_functions_are_annotated() {
TEST(template_functions_are_annotated);
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, sampleInput());
auto m = out.skeleton.getModule("handlers");
CHECK(!m.functions.empty(), "missing handler functions");
bool hasIntent = false, hasContract = false;
for (const auto& a : m.functions[0].annotations) {
if (a.key == "@Intent") hasIntent = true;
if (a.key == "@Contract") hasContract = true;
}
CHECK(hasIntent && hasContract, "missing expected annotations");
PASS();
}
void test_template_is_parameterized_by_primary_entity() {
TEST(template_is_parameterized_by_primary_entity);
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, sampleInput());
auto handlers = out.skeleton.getModule("handlers");
bool hasCreateBook = false;
for (const auto& f : handlers.functions) if (f.name == "createBook") hasCreateBook = true;
CHECK(hasCreateBook, "expected entity-parameterized function name");
PASS();
}
void test_template_module_dependencies_present() {
TEST(template_module_dependencies_present);
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, sampleInput());
auto routes = out.skeleton.getModule("routes");
bool hasHandlersDep = false;
for (const auto& d : routes.dependencies) if (d == "handlers") hasHandlersDep = true;
CHECK(hasHandlersDep, "expected routes->handlers dependency");
PASS();
}
void test_template_output_contains_template_note() {
TEST(template_output_contains_template_note);
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::CliTool, sampleInput());
CHECK(!out.notes.empty(), "expected template note");
PASS();
}
void test_template_module_languages_match_expected_defaults() {
TEST(template_module_languages_match_expected_defaults);
auto rest = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, sampleInput());
auto micro = ArchitectTemplates::instantiate(ArchitectureTemplateKind::Microservice, sampleInput());
auto full = ArchitectTemplates::instantiate(ArchitectureTemplateKind::FullStack, sampleInput());
CHECK(rest.skeleton.getModule("handlers").language == "typescript", "rest handlers language mismatch");
CHECK(micro.skeleton.getModule("service").language == "go", "microservice language mismatch");
CHECK(full.skeleton.getModule("backend").language == "python", "fullstack backend language mismatch");
PASS();
}
void test_template_outputs_are_nonempty_across_all_kinds() {
TEST(template_outputs_are_nonempty_across_all_kinds);
auto in = sampleInput();
auto a = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, in);
auto b = ArchitectTemplates::instantiate(ArchitectureTemplateKind::CliTool, in);
auto c = ArchitectTemplates::instantiate(ArchitectureTemplateKind::Library, in);
auto d = ArchitectTemplates::instantiate(ArchitectureTemplateKind::Microservice, in);
auto e = ArchitectTemplates::instantiate(ArchitectureTemplateKind::FullStack, in);
CHECK(!a.skeleton.modules.empty(), "rest template empty");
CHECK(!b.skeleton.modules.empty(), "cli template empty");
CHECK(!c.skeleton.modules.empty(), "library template empty");
CHECK(!d.skeleton.modules.empty(), "microservice template empty");
CHECK(!e.skeleton.modules.empty(), "fullstack template empty");
PASS();
}
void test_templates_include_auth_module_for_rest_api() {
TEST(templates_include_auth_module_for_rest_api);
auto out = ArchitectTemplates::instantiate(ArchitectureTemplateKind::RestApi, sampleInput());
CHECK(out.skeleton.hasModule("auth"), "expected auth module in REST template");
PASS();
}
int main() {
std::cout << "Step 477: Architecture Templates Tests\n";
test_rest_api_template_contains_expected_modules(); // 1
test_cli_template_contains_cli_command_output_modules(); // 2
test_library_template_contains_api_internal_tests_docs(); // 3
test_microservice_template_contains_service_transport_storage_health(); // 4
test_fullstack_template_contains_frontend_backend_database_deploy(); // 5
test_template_functions_are_annotated(); // 6
test_template_is_parameterized_by_primary_entity(); // 7
test_template_module_dependencies_present(); // 8
test_template_output_contains_template_note(); // 9
test_template_module_languages_match_expected_defaults(); // 10
test_template_outputs_are_nonempty_across_all_kinds(); // 11
test_templates_include_auth_module_for_rest_api(); // 12
std::cout << "\nResults: " << passed << "/" << (passed + failed)
<< " passed\n";
return failed == 0 ? 0 : 1;
}

View File

@@ -6663,3 +6663,40 @@ skeleton generation → architect review/approval → workflow task materializat
- annotated multi-module skeleton generation
- architect review/modify/approve state model
- end-to-end architect-mode flow readiness for phase 23b scaffolding
### Step 477: Architect Templates
**Status:** PASS (12/12 tests)
Introduces reusable architecture templates that instantiate starter module
layouts, dependencies, function stubs, and annotations for common product
shapes (REST API, CLI, library, microservice, full stack).
**Files added:**
- `editor/src/ArchitectTemplates.h` — template library:
- `ArchitectureTemplateKind`, `TemplateInput`, `TemplateOutput`
- `ArchitectTemplates::instantiate(...)`
- template-specific module graphs and function stubs
- default annotation emission for generated functions:
- `@Intent`
- `@Complexity`
- `@ContextWidth`
- `@Automatability`
- `@Contract`
- `editor/tests/step477_test.cpp` — 12 tests covering:
- expected module sets for each template kind
- annotation presence on generated function stubs
- `primaryEntity` parameterization (e.g. `createBook`)
- dependency expectations (e.g. `routes -> handlers`)
- template metadata notes and language defaults
- non-empty outputs across all template kinds
- `editor/CMakeLists.txt``step477_test` target
**Verification run:**
- `cmake --build editor/build-native --target step477_test step476_test` — PASS
- `./editor/build-native/step477_test` — PASS (12/12)
- `./editor/build-native/step476_test` — PASS (8/8) regression coverage
**Architecture gate check:**
- `editor/src/ArchitectTemplates.h` within header-size limit (`182` <= `600`)
- `editor/tests/step477_test.cpp` within test-file size guidance (`166` lines)
- Naming/style aligned with `ARCHITECTURE.md` conventions (`PascalCase` types, `camelCase` functions)