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:
Bill
2026-03-02 10:21:06 -07:00
parent a410c9c756
commit 03dc4dc208
11 changed files with 842 additions and 0 deletions

View 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

View 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

View 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

View 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

View 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