using System.Collections.Generic;
using System.Linq;
using Unity.Pipeline.Commands;
using Unity.Pipeline.Telemetry;
namespace Unity.Pipeline.Runtime.Commands
{
///
/// Read-back command for the local eval-usage telemetry (AUTHAPI-29). Aggregates
/// Library/Pipeline/eval-usage.jsonl — merged with the rotated eval-usage.old.jsonl,
/// so the report sees the full retained history (~2× the size cap) — into a ranked report: API
/// fingerprint frequency, one-liner vs multi-statement split, error rate. It cross-references the
/// fingerprints against the live command catalog to flag patterns already coverable by an existing
/// command and the top uncovered patterns. This is the artifact that steers eval-displacement
/// backlog triage (AUTHAPI-24). Read-only and off the main thread, so it stays servable even while
/// the Editor is settling. The ranked lists are capped by top; the report's
/// distinctFingerprints total makes any truncation visible.
///
static class EvalTelemetryCommand
{
[CliCommand("report_evals",
"Aggregate local eval-usage telemetry into a ranked report: API fingerprint frequency, one-liner percentage, error rate, and command-coverage suggestions.",
MainThreadRequired = false,
Tags = new[] { "observability/eval_usage" })]
public static EvalUsageReport ReportEvals(
[CliArg("top", "Maximum entries in each ranked list (API fingerprints, and uncovered patterns suggested as commands). Accepted range: 0 or greater; negative values fall back to the default (50).")] int top = 50)
{
// Clamp, don't reject: a negative cap has no meaning, so fall back to the default rather
// than fail the command or return an unbounded report.
if (top < 0)
top = EvalUsageAggregator.DefaultFingerprintLimit;
var records = EvalUsageTelemetry.ReadRecords(EvalUsageTelemetry.ResolveDirectory());
// Cross-reference against the live catalog. Discovery is already warm (the server queried
// it to route this very request), so this reads the cache and touches no main-thread API.
var availableCommands = new HashSet(
CommandRegistry.DiscoverCommands().Select(c => c.Name));
return EvalUsageAggregator.Build(records, availableCommands, topUncoveredLimit: top, fingerprintLimit: top);
}
}
}