Sprint 289: Integration into generate_taskitems (steps 1973-1977)
EnrichedExecutionContract, TaskitemLibraryAnnotator, AnnotatedTaskitemValidator, DispatchJustificationReport, Sprint289IntegrationSummary. 25/25 tests passing. Full pipeline: spec -> classifier -> selector -> advisor -> enriched contracts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
59
editor/src/AnnotatedTaskitemValidator.h
Normal file
59
editor/src/AnnotatedTaskitemValidator.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
// Step 1975: AnnotatedTaskitemValidator
|
||||
// Validates enrichment of EnrichedExecutionContracts.
|
||||
// ValidationReport { passCount, failCount, errors (include taskDescription) }.
|
||||
// If enrichmentRequired=true, any unenriched contract is an error.
|
||||
// Also validates capabilityScore in [0,1] for enriched contracts.
|
||||
|
||||
#include "EnrichedExecutionContract.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace whetstone {
|
||||
|
||||
struct ValidationReport {
|
||||
int passCount = 0;
|
||||
int failCount = 0;
|
||||
std::vector<std::string> errors;
|
||||
|
||||
bool allPassed() const { return failCount == 0; }
|
||||
};
|
||||
|
||||
class AnnotatedTaskitemValidator {
|
||||
public:
|
||||
ValidationReport validate(
|
||||
const std::vector<EnrichedExecutionContract>& contracts,
|
||||
bool enrichmentRequired) const {
|
||||
|
||||
ValidationReport report;
|
||||
|
||||
for (const auto& c : contracts) {
|
||||
const std::string desc = c.taskDescription.empty()
|
||||
? "(unnamed task)" : c.taskDescription;
|
||||
|
||||
bool pass = true;
|
||||
|
||||
// Check enrichment requirement
|
||||
if (enrichmentRequired && !c.isEnriched()) {
|
||||
report.errors.push_back("task not enriched: " + desc);
|
||||
pass = false;
|
||||
}
|
||||
|
||||
// Validate fields on enriched contracts
|
||||
if (c.isEnriched()) {
|
||||
if (c.capabilityScore < 0.0f || c.capabilityScore > 1.0f) {
|
||||
report.errors.push_back(
|
||||
"capabilityScore out of range [0,1] for: " + desc);
|
||||
pass = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pass) ++report.passCount;
|
||||
else ++report.failCount;
|
||||
}
|
||||
|
||||
return report;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace whetstone
|
||||
78
editor/src/DispatchJustificationReport.h
Normal file
78
editor/src/DispatchJustificationReport.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
// Step 1976: DispatchJustificationReport
|
||||
// Per-project structured report of every task -> library choice -> score -> why.
|
||||
// finalize() computes averageScore from enriched entries (non-empty selectedLibrary).
|
||||
// serialize() returns JSON string via nlohmann::json.
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace whetstone {
|
||||
|
||||
struct JustificationEntry {
|
||||
std::string taskDescription;
|
||||
std::string selectedLibrary; // empty if unenriched
|
||||
std::string operationDomain;
|
||||
float capabilityScore = 0.0f;
|
||||
std::string justification;
|
||||
std::vector<std::string> avoidedLibraries; // names only
|
||||
};
|
||||
|
||||
class DispatchJustificationReport {
|
||||
public:
|
||||
std::string projectId;
|
||||
std::vector<JustificationEntry> entries;
|
||||
int totalTasks = 0;
|
||||
int enrichedCount = 0;
|
||||
float averageScore = 0.0f;
|
||||
|
||||
void add(JustificationEntry entry) {
|
||||
++totalTasks;
|
||||
if (!entry.selectedLibrary.empty()) ++enrichedCount;
|
||||
entries.push_back(std::move(entry));
|
||||
}
|
||||
|
||||
// Compute averageScore from enriched entries.
|
||||
void finalize() {
|
||||
if (enrichedCount == 0) {
|
||||
averageScore = 0.0f;
|
||||
return;
|
||||
}
|
||||
float sum = 0.0f;
|
||||
int count = 0;
|
||||
for (const auto& e : entries) {
|
||||
if (!e.selectedLibrary.empty()) {
|
||||
sum += e.capabilityScore;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
averageScore = count > 0 ? sum / static_cast<float>(count) : 0.0f;
|
||||
}
|
||||
|
||||
// Serialize to JSON string (2-space indent).
|
||||
std::string serialize() const {
|
||||
nlohmann::json j;
|
||||
j["projectId"] = projectId;
|
||||
j["totalTasks"] = totalTasks;
|
||||
j["enrichedCount"] = enrichedCount;
|
||||
j["averageScore"] = averageScore;
|
||||
|
||||
nlohmann::json jEntries = nlohmann::json::array();
|
||||
for (const auto& e : entries) {
|
||||
nlohmann::json je;
|
||||
je["taskDescription"] = e.taskDescription;
|
||||
je["selectedLibrary"] = e.selectedLibrary;
|
||||
je["operationDomain"] = e.operationDomain;
|
||||
je["capabilityScore"] = e.capabilityScore;
|
||||
je["justification"] = e.justification;
|
||||
je["avoidedLibraries"] = e.avoidedLibraries;
|
||||
jEntries.push_back(je);
|
||||
}
|
||||
j["entries"] = jEntries;
|
||||
|
||||
return j.dump(2);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace whetstone
|
||||
33
editor/src/EnrichedExecutionContract.h
Normal file
33
editor/src/EnrichedExecutionContract.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
// Step 1973: EnrichedExecutionContract
|
||||
// Extends base execution contract with library dispatch fields.
|
||||
// isEnriched() is true only when selectedLibrary and operationDomain are both set.
|
||||
// Default-constructed contracts are not enriched.
|
||||
|
||||
#include "LibrarySelection.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace whetstone {
|
||||
|
||||
struct EnrichedExecutionContract {
|
||||
// Base contract fields
|
||||
std::string language;
|
||||
std::string stepId;
|
||||
std::string taskDescription;
|
||||
|
||||
// Library dispatch fields (empty by default — not enriched)
|
||||
std::string selectedLibrary;
|
||||
std::string operationDomain;
|
||||
float capabilityScore = 0.0f;
|
||||
std::vector<std::string> preferredAPIs;
|
||||
std::vector<AvoidedLibrary> avoidedLibraries;
|
||||
std::string justification;
|
||||
|
||||
// True when selectedLibrary and operationDomain are both non-empty.
|
||||
bool isEnriched() const {
|
||||
return !selectedLibrary.empty() && !operationDomain.empty();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace whetstone
|
||||
99
editor/src/Sprint289IntegrationSummary.h
Normal file
99
editor/src/Sprint289IntegrationSummary.h
Normal file
@@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
// Step 1977: Sprint 289 Integration Summary
|
||||
// Full pipeline: spec -> classifier -> selector -> advisor -> enriched taskitems.
|
||||
// 4 named tasks annotated using seed ledger (Sprint 286) + seed catalog (Sprint 288).
|
||||
//
|
||||
// Tasks:
|
||||
// 1. "implement JSON serialization" -> serialization.json -> nlohmann_json (0.92)
|
||||
// 2. "perform matrix multiply on GPU" -> compute.matrix -> cublas (0.99)
|
||||
// 3. "serialize binary IPC message" -> serialization.binary -> protobuf (0.95)
|
||||
// 4. "parallel array sort on GPU" -> compute.parallel -> thrust (0.97)
|
||||
|
||||
#include "TaskitemLibraryAnnotator.h"
|
||||
#include "AnnotatedTaskitemValidator.h"
|
||||
#include "DispatchJustificationReport.h"
|
||||
#include "Sprint286IntegrationSummary.h"
|
||||
#include "Sprint288IntegrationSummary.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace whetstone {
|
||||
|
||||
class Sprint289IntegrationSummary {
|
||||
public:
|
||||
int stepsCompleted = 5;
|
||||
bool success = true;
|
||||
|
||||
std::string sprintName() const {
|
||||
return "Sprint 289: generate_taskitems Integration";
|
||||
}
|
||||
|
||||
// Build seed ledger + catalog, annotate 4 tasks, return enriched contracts.
|
||||
static std::vector<EnrichedExecutionContract> buildAnnotatedTaskitems() {
|
||||
auto ledger = Sprint286IntegrationSummary::buildSeedLedger();
|
||||
auto catalog = Sprint288IntegrationSummary::buildSeedCatalog();
|
||||
TaskitemLibraryAnnotator annotator;
|
||||
|
||||
std::vector<EnrichedExecutionContract> result;
|
||||
|
||||
// Task 1: JSON serialization (nlohmann_json vs protobuf)
|
||||
result.push_back(annotator.annotate(
|
||||
"implement JSON serialization",
|
||||
{"nlohmann_json", "protobuf"},
|
||||
ledger, catalog));
|
||||
|
||||
// Task 2: GPU matrix multiply (cublas vs numpy)
|
||||
result.push_back(annotator.annotate(
|
||||
"perform matrix multiply on GPU",
|
||||
{"cublas", "numpy"},
|
||||
ledger, catalog));
|
||||
|
||||
// Task 3: Binary IPC serialization (protobuf dominates)
|
||||
result.push_back(annotator.annotate(
|
||||
"serialize binary IPC message",
|
||||
{"protobuf", "nlohmann_json"},
|
||||
ledger, catalog));
|
||||
|
||||
// Task 4: Parallel GPU sort (thrust dominates)
|
||||
result.push_back(annotator.annotate(
|
||||
"parallel array sort on GPU",
|
||||
{"thrust", "numpy"},
|
||||
ledger, catalog));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns true when all 4 contracts are enriched.
|
||||
static bool verifyAllEnriched() {
|
||||
auto contracts = buildAnnotatedTaskitems();
|
||||
if (contracts.size() != 4) return false;
|
||||
for (const auto& c : contracts) {
|
||||
if (!c.isEnriched()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Build DispatchJustificationReport from the 4 annotated tasks.
|
||||
static DispatchJustificationReport buildJustificationReport() {
|
||||
auto contracts = buildAnnotatedTaskitems();
|
||||
DispatchJustificationReport report;
|
||||
report.projectId = "sprint289-proof";
|
||||
|
||||
for (const auto& c : contracts) {
|
||||
JustificationEntry entry;
|
||||
entry.taskDescription = c.taskDescription;
|
||||
entry.selectedLibrary = c.selectedLibrary;
|
||||
entry.operationDomain = c.operationDomain;
|
||||
entry.capabilityScore = c.capabilityScore;
|
||||
entry.justification = c.justification;
|
||||
for (const auto& a : c.avoidedLibraries) {
|
||||
entry.avoidedLibraries.push_back(a.name);
|
||||
}
|
||||
report.add(entry);
|
||||
}
|
||||
report.finalize();
|
||||
return report;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace whetstone
|
||||
64
editor/src/TaskitemLibraryAnnotator.h
Normal file
64
editor/src/TaskitemLibraryAnnotator.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
// Step 1974: TaskitemLibraryAnnotator
|
||||
// Runs OperationClassifier -> PerTaskLibrarySelector -> LibrarySymbolAdvisor per taskitem.
|
||||
// Returns EnrichedExecutionContract. Unenriched if domain unknown or no library scores > 0.
|
||||
// Always sets taskDescription on the returned contract.
|
||||
|
||||
#include "EnrichedExecutionContract.h"
|
||||
#include "OperationClassifier.h"
|
||||
#include "PerTaskLibrarySelector.h"
|
||||
#include "LibrarySymbolAdvisor.h"
|
||||
#include "LibraryCapabilityLedger.h"
|
||||
#include "LibrarySymbolCatalog.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace whetstone {
|
||||
|
||||
class TaskitemLibraryAnnotator {
|
||||
public:
|
||||
EnrichedExecutionContract annotate(
|
||||
const std::string& taskDescription,
|
||||
const std::vector<std::string>& availableLibraries,
|
||||
const LibraryCapabilityLedger& ledger,
|
||||
const LibrarySymbolCatalog& catalog) const {
|
||||
|
||||
EnrichedExecutionContract ec;
|
||||
ec.taskDescription = taskDescription;
|
||||
|
||||
// Step 1: classify the task description into an operation domain
|
||||
auto classifier = OperationClassifier::withDefaultTaxonomy();
|
||||
auto cr = classifier.classify(taskDescription);
|
||||
if (!cr.isKnown) {
|
||||
return ec; // domain unknown — unenriched
|
||||
}
|
||||
|
||||
// Step 2: select best library for the domain
|
||||
PerTaskLibrarySelector selector;
|
||||
auto sel = selector.select(cr.domain, availableLibraries, ledger);
|
||||
if (!sel.hasSelection()) {
|
||||
return ec; // no library scores > 0 — unenriched
|
||||
}
|
||||
|
||||
// Step 3: populate enriched fields from selection
|
||||
ec.selectedLibrary = sel.selectedLibrary;
|
||||
ec.operationDomain = sel.operationDomain;
|
||||
ec.capabilityScore = sel.capabilityScore;
|
||||
ec.preferredAPIs = sel.preferredAPIs;
|
||||
ec.avoidedLibraries = sel.avoidedLibraries;
|
||||
ec.justification = sel.justification;
|
||||
|
||||
// Step 4: supplement preferredAPIs from symbol advisor if not already populated
|
||||
if (ec.preferredAPIs.empty()) {
|
||||
LibrarySymbolAdvisor advisor;
|
||||
auto syms = advisor.advise(sel.selectedLibrary, sel.operationDomain, catalog);
|
||||
for (const auto& s : syms) {
|
||||
ec.preferredAPIs.push_back(s.functionName);
|
||||
}
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace whetstone
|
||||
Reference in New Issue
Block a user