feat(01-01): add taskMetadata to ClassificationResult and export extractTaskMetadata

- Add taskMetadata?: TaskMetadata to ClassificationResult in complexity-classifier.ts
- Add taskMetadata?: TaskMetadata to ClassificationResult in types.ts (duplicate interface)
- Export extractTaskMetadata() so it can be imported by model-router.ts
- Refactor classifyUnitComplexity() to extract metadata once for execute-task (eliminates double-extraction at adaptive learning step)
- Populate taskMetadata field on ClassificationResult for execute-task units
- Set taskMetadata: undefined explicitly on hook unit fast-path
This commit is contained in:
Jeremy 2026-03-26 17:00:06 -05:00
parent 0ccd3fd8a4
commit 409cd77cbc
2 changed files with 10 additions and 4 deletions

View file

@ -16,6 +16,7 @@ export interface ClassificationResult {
tier: ComplexityTier;
reason: string;
downgraded: boolean; // true if budget pressure lowered the tier
taskMetadata?: TaskMetadata;
}
export interface TaskMetadata {
@ -71,17 +72,20 @@ export function classifyUnitComplexity(
): ClassificationResult {
// Hook units default to light
if (unitType.startsWith("hook/")) {
const result: ClassificationResult = { tier: "light", reason: "hook unit", downgraded: false };
const result: ClassificationResult = { tier: "light", reason: "hook unit", downgraded: false, taskMetadata: undefined };
return applyBudgetPressure(result, budgetPct);
}
// Start with the default tier for this unit type
let tier = UNIT_TYPE_TIERS[unitType] ?? "standard";
let reason = `unit type: ${unitType}`;
let taskMeta: TaskMetadata | undefined;
// For execute-task, analyze task metadata for complexity signals
if (unitType === "execute-task") {
const taskAnalysis = analyzeTaskComplexity(unitId, basePath, metadata);
// Extract metadata once and reuse throughout to avoid double-extraction
taskMeta = metadata ?? extractTaskMetadata(unitId, basePath);
const taskAnalysis = analyzeTaskComplexity(unitId, basePath, taskMeta);
tier = taskAnalysis.tier;
reason = taskAnalysis.reason;
}
@ -96,14 +100,15 @@ export function classifyUnitComplexity(
}
// Adaptive learning: check if history suggests bumping the tier
const tags = metadata?.tags ?? extractTaskMetadata(unitId, basePath).tags;
// Use already-extracted taskMeta.tags if available to avoid double-extraction
const tags = taskMeta?.tags ?? metadata?.tags;
const adaptiveAdjustment = getAdaptiveTierAdjustment(unitType, tier, tags);
if (adaptiveAdjustment && tierOrdinal(adaptiveAdjustment) > tierOrdinal(tier)) {
reason = `${reason} (adaptive: high failure rate at ${tier})`;
tier = adaptiveAdjustment;
}
const result: ClassificationResult = { tier, reason, downgraded: false };
const result: ClassificationResult = { tier, reason, downgraded: false, taskMetadata: taskMeta };
return applyBudgetPressure(result, budgetPct);
}

View file

@ -316,6 +316,7 @@ export interface ClassificationResult {
tier: ComplexityTier;
reason: string;
downgraded: boolean;
taskMetadata?: TaskMetadata;
}
export interface TaskMetadata {