Files
whetstone_DSL/editor/src/Phase28aIntegration.h

119 lines
4.1 KiB
C++

#pragma once
// Step 538: Phase 28a Integration
#include <algorithm>
#include <string>
#include <vector>
#include <nlohmann/json.hpp>
#include "ArgumentShapeValidator.h"
#include "ConstrainedExecutionTelemetry.h"
#include "OperationSelectorAPI.h"
#include "SymbolSelectorAPI.h"
using json = nlohmann::json;
struct Phase28aRequest {
TaskitemContract contract;
std::string nodeKind;
ScopeSnapshot scope;
std::string requestedOperation;
std::string requestedSymbol;
json args;
int constrainedTokenCount = 0;
int baselineTokenCount = 0;
};
struct Phase28aResult {
bool menuReady = false;
bool executed = false;
std::vector<std::string> errors;
OperationSelectionResult operationMenu;
SymbolSelectionResult symbolMenu;
TelemetrySummary telemetrySummary;
};
class Phase28aIntegration {
public:
static Phase28aResult run(const Phase28aRequest& request,
const LegalOperationGraph& graph,
ConstrainedExecutionTelemetry& telemetry) {
Phase28aResult result;
result.operationMenu = OperationSelectorAPI::select(
request.contract, request.nodeKind, request.scope, graph);
result.symbolMenu = SymbolSelectorAPI::select(request.contract, request.scope);
result.menuReady = result.operationMenu.supported && result.symbolMenu.supported;
TelemetryEvent event;
event.taskitemId = request.contract.id;
event.candidateOperationCount = (int)result.operationMenu.candidates.size();
event.candidateSymbolCount = (int)result.symbolMenu.candidates.size();
event.baselineTokenCount = request.baselineTokenCount;
event.constrainedTokenCount = request.constrainedTokenCount;
if (!result.menuReady) {
result.errors.push_back("menu_unavailable");
event.rejectionReasons.push_back("menu_unavailable");
telemetry.record(event);
result.telemetrySummary = telemetry.summarize();
return result;
}
if (!hasOperation(result.operationMenu, request.requestedOperation)) {
result.errors.push_back("operation_not_in_legal_menu");
event.rejectionReasons.push_back("operation_not_in_legal_menu");
telemetry.record(event);
result.telemetrySummary = telemetry.summarize();
return result;
}
if (!hasSymbol(result.symbolMenu, request.requestedSymbol)) {
result.errors.push_back("symbol_not_in_legal_menu");
event.rejectionReasons.push_back("symbol_not_in_legal_menu");
telemetry.record(event);
result.telemetrySummary = telemetry.summarize();
return result;
}
auto shape = ArgumentShapeValidator::validate(request.contract,
request.requestedOperation,
request.requestedSymbol,
request.args);
if (!shape.valid) {
result.errors.insert(result.errors.end(), shape.errors.begin(), shape.errors.end());
event.rejectionReasons.push_back("invalid_argument_shape");
telemetry.record(event);
result.telemetrySummary = telemetry.summarize();
return result;
}
event.selectedOperation = request.requestedOperation;
event.success = true;
telemetry.record(event);
result.executed = true;
result.telemetrySummary = telemetry.summarize();
return result;
}
private:
static bool hasOperation(const OperationSelectionResult& menu,
const std::string& operation) {
for (const auto& c : menu.candidates) {
if (c.operation == operation) return true;
}
return false;
}
static bool hasSymbol(const SymbolSelectionResult& menu,
const std::string& symbol) {
for (const auto& c : menu.candidates) {
if (c.name == symbol) return true;
}
return false;
}
};