Steps 266-268: Phase 10a — semantic annotation core + sidecar persistence (32/32 tests)
Step 266: 5 semantic annotation AST types (Intent, Complexity, Risk, Contract, SemanticTag) with JSON roundtrip and compact AST integration. Step 267: Sidecar AST persistence (.whetstone/<file>.ast.json) with save/load/list RPC methods, MCP tools, and permission enforcement. Step 268: Phase 10a integration tests — multi-file sidecar workflow, all 5 types in compact view, idempotent roundtrip, source isolation. Also includes Sprint 10 plan, GUI/installer polish, and Emacs integration fixes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
@@ -141,3 +141,44 @@ class ConstExprAnnotation : public Annotation {
|
||||
public:
|
||||
ConstExprAnnotation() { conceptType = "ConstExprAnnotation"; }
|
||||
};
|
||||
|
||||
// Semantic annotations for AI guidance (Sprint 10, Step 266)
|
||||
|
||||
class IntentAnnotation : public Annotation {
|
||||
public:
|
||||
std::string summary; // 1-sentence description of what/why
|
||||
std::string category; // "validation", "transformation", "io",
|
||||
// "coordination", "computation", "initialization"
|
||||
IntentAnnotation() { conceptType = "IntentAnnotation"; }
|
||||
};
|
||||
|
||||
class ComplexityAnnotation : public Annotation {
|
||||
public:
|
||||
std::string timeComplexity; // "O(1)", "O(n)", "O(n^2)", etc.
|
||||
int cognitiveComplexity = 0; // 1-10 scale
|
||||
int linesOfLogic = 0;
|
||||
ComplexityAnnotation() { conceptType = "ComplexityAnnotation"; }
|
||||
};
|
||||
|
||||
class RiskAnnotation : public Annotation {
|
||||
public:
|
||||
std::string level; // "low", "medium", "high", "critical"
|
||||
std::string reason;
|
||||
int dependentCount = 0; // how many callers/consumers
|
||||
RiskAnnotation() { conceptType = "RiskAnnotation"; }
|
||||
};
|
||||
|
||||
class ContractAnnotation : public Annotation {
|
||||
public:
|
||||
std::string preconditions;
|
||||
std::string postconditions;
|
||||
std::string returnShape; // human-readable type/shape description
|
||||
std::string sideEffects; // "none", "io", "mutation", "network"
|
||||
ContractAnnotation() { conceptType = "ContractAnnotation"; }
|
||||
};
|
||||
|
||||
class SemanticTagAnnotation : public Annotation {
|
||||
public:
|
||||
std::vector<std::string> tags; // e.g. ["@serialize", "@validation"]
|
||||
SemanticTagAnnotation() { conceptType = "SemanticTagAnnotation"; }
|
||||
};
|
||||
|
||||
@@ -134,6 +134,35 @@ inline json propertiesToJson(const ASTNode* node) {
|
||||
if (!n->semanticHint.empty()) props["semanticHint"] = n->semanticHint;
|
||||
if (!n->position.empty()) props["position"] = n->position;
|
||||
}
|
||||
// Semantic annotations (Sprint 10)
|
||||
else if (ct == "IntentAnnotation") {
|
||||
auto* n = static_cast<const IntentAnnotation*>(node);
|
||||
if (!n->summary.empty()) props["summary"] = n->summary;
|
||||
if (!n->category.empty()) props["category"] = n->category;
|
||||
}
|
||||
else if (ct == "ComplexityAnnotation") {
|
||||
auto* n = static_cast<const ComplexityAnnotation*>(node);
|
||||
if (!n->timeComplexity.empty()) props["timeComplexity"] = n->timeComplexity;
|
||||
props["cognitiveComplexity"] = n->cognitiveComplexity;
|
||||
props["linesOfLogic"] = n->linesOfLogic;
|
||||
}
|
||||
else if (ct == "RiskAnnotation") {
|
||||
auto* n = static_cast<const RiskAnnotation*>(node);
|
||||
if (!n->level.empty()) props["level"] = n->level;
|
||||
if (!n->reason.empty()) props["reason"] = n->reason;
|
||||
props["dependentCount"] = n->dependentCount;
|
||||
}
|
||||
else if (ct == "ContractAnnotation") {
|
||||
auto* n = static_cast<const ContractAnnotation*>(node);
|
||||
if (!n->preconditions.empty()) props["preconditions"] = n->preconditions;
|
||||
if (!n->postconditions.empty()) props["postconditions"] = n->postconditions;
|
||||
if (!n->returnShape.empty()) props["returnShape"] = n->returnShape;
|
||||
if (!n->sideEffects.empty()) props["sideEffects"] = n->sideEffects;
|
||||
}
|
||||
else if (ct == "SemanticTagAnnotation") {
|
||||
auto* n = static_cast<const SemanticTagAnnotation*>(node);
|
||||
if (!n->tags.empty()) props["tags"] = n->tags;
|
||||
}
|
||||
// NullLiteral, ListLiteral, IndexAccess, Block, Assignment, IfStatement,
|
||||
// WhileLoop, Return, ExpressionStatement, ListType, SetType, MapType,
|
||||
// TupleType, ArrayType, OptionalType — no extra properties
|
||||
@@ -206,6 +235,11 @@ inline ASTNode* createNode(const std::string& conceptName) {
|
||||
if (conceptName == "DerefStrategy") return new DerefStrategy();
|
||||
if (conceptName == "OptimizationLock") return new OptimizationLock();
|
||||
if (conceptName == "LangSpecific") return new LangSpecific();
|
||||
if (conceptName == "IntentAnnotation") return new IntentAnnotation();
|
||||
if (conceptName == "ComplexityAnnotation") return new ComplexityAnnotation();
|
||||
if (conceptName == "RiskAnnotation") return new RiskAnnotation();
|
||||
if (conceptName == "ContractAnnotation") return new ContractAnnotation();
|
||||
if (conceptName == "SemanticTagAnnotation") return new SemanticTagAnnotation();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -328,13 +362,53 @@ inline void setPropertiesFromJson(ASTNode* node, const json& props) {
|
||||
if (props.contains("semanticHint")) n->semanticHint = props["semanticHint"].get<std::string>();
|
||||
if (props.contains("position")) n->position = props["position"].get<std::string>();
|
||||
}
|
||||
// Semantic annotations (Sprint 10)
|
||||
else if (ct == "IntentAnnotation") {
|
||||
auto* n = static_cast<IntentAnnotation*>(node);
|
||||
if (props.contains("summary")) n->summary = props["summary"].get<std::string>();
|
||||
if (props.contains("category")) n->category = props["category"].get<std::string>();
|
||||
}
|
||||
else if (ct == "ComplexityAnnotation") {
|
||||
auto* n = static_cast<ComplexityAnnotation*>(node);
|
||||
if (props.contains("timeComplexity")) n->timeComplexity = props["timeComplexity"].get<std::string>();
|
||||
if (props.contains("cognitiveComplexity")) n->cognitiveComplexity = props["cognitiveComplexity"].get<int>();
|
||||
if (props.contains("linesOfLogic")) n->linesOfLogic = props["linesOfLogic"].get<int>();
|
||||
}
|
||||
else if (ct == "RiskAnnotation") {
|
||||
auto* n = static_cast<RiskAnnotation*>(node);
|
||||
if (props.contains("level")) n->level = props["level"].get<std::string>();
|
||||
if (props.contains("reason")) n->reason = props["reason"].get<std::string>();
|
||||
if (props.contains("dependentCount")) n->dependentCount = props["dependentCount"].get<int>();
|
||||
}
|
||||
else if (ct == "ContractAnnotation") {
|
||||
auto* n = static_cast<ContractAnnotation*>(node);
|
||||
if (props.contains("preconditions")) n->preconditions = props["preconditions"].get<std::string>();
|
||||
if (props.contains("postconditions")) n->postconditions = props["postconditions"].get<std::string>();
|
||||
if (props.contains("returnShape")) n->returnShape = props["returnShape"].get<std::string>();
|
||||
if (props.contains("sideEffects")) n->sideEffects = props["sideEffects"].get<std::string>();
|
||||
}
|
||||
else if (ct == "SemanticTagAnnotation") {
|
||||
auto* n = static_cast<SemanticTagAnnotation*>(node);
|
||||
if (props.contains("tags") && props["tags"].is_array()) {
|
||||
n->tags.clear();
|
||||
for (const auto& tag : props["tags"]) {
|
||||
if (tag.is_string()) n->tags.push_back(tag.get<std::string>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string generateNodeId() {
|
||||
static int counter = 0;
|
||||
return "node_" + std::to_string(++counter);
|
||||
}
|
||||
|
||||
inline ASTNode* fromJson(const json& j) {
|
||||
ASTNode* node = createNode(j["concept"].get<std::string>());
|
||||
if (!node) return nullptr;
|
||||
|
||||
node->id = j["id"].get<std::string>();
|
||||
node->id = j.contains("id") ? j["id"].get<std::string>()
|
||||
: generateNodeId();
|
||||
if (j.contains("span")) {
|
||||
const auto& span = j["span"];
|
||||
if (span.contains("start") && span.contains("end")) {
|
||||
|
||||
Reference in New Issue
Block a user