import type { AgentFact, AttributionManifest } from "../types.js"; export interface AgentUtility { usedFindingRatio: number; uniqueContributionRatio: number; duplicateRatio: number; zeroImpact: boolean; creditsPerUsedFinding: number; creditsPerAcceptedDecision: number } export function attributionUtility(facts: AgentFact[], manifest: AttributionManifest, credits: number): AgentUtility { const used = facts.filter((fact) => manifest.usedFactIds.includes(fact.id)); const rejected = new Set(manifest.rejectedFactIds.filter((entry) => entry.reason === "duplicate").map((entry) => entry.id)); return { usedFindingRatio: facts.length ? used.length / facts.length : 0, uniqueContributionRatio: facts.length ? used.filter((fact) => !rejected.has(fact.id)).length / facts.length : 0, duplicateRatio: facts.length ? rejected.size / facts.length : 0, zeroImpact: used.length === 0, creditsPerUsedFinding: used.length ? credits / used.length : credits, creditsPerAcceptedDecision: manifest.decisions.length ? credits / manifest.decisions.length : credits }; } export function validateAttributionManifest(manifest: AttributionManifest, facts: readonly AgentFact[]): void { const factIds = new Set(facts.map((fact) => fact.id)); const referenced = [...manifest.usedFactIds, ...manifest.rejectedFactIds.map((entry) => entry.id), ...manifest.decisions.flatMap((decision) => decision.supportingFactIds)]; if (referenced.some((id) => !factIds.has(id))) throw new Error("Attribution manifest references an unknown fact"); const used = new Set(manifest.usedFactIds); if (manifest.rejectedFactIds.some((entry) => used.has(entry.id))) throw new Error("Attribution manifest both uses and rejects the same fact"); const decisionIds = manifest.decisions.map((decision) => decision.decisionId); if (new Set(decisionIds).size !== decisionIds.length) throw new Error("Attribution manifest contains duplicate decision IDs"); const decisions = new Set(decisionIds); if (manifest.changes.some((change) => change.supportingDecisionIds.some((id) => !decisions.has(id)))) throw new Error("Attribution manifest change references an unknown decision"); }