Category: feature — Breaking: no
PipelineSummary exists only in-process (Engine/Executors/PipelineSummaryFactory.cs); no code serializes it to disk. The estimated-times store keeps only the latest duration per module (single overwritten file in FileSystemModuleEstimatedTimeProvider), so no trend data survives. IModuleResultRepository ships NoOp-only. Precedent: Gradle build scans, Bazel BEP, GitHub check runs.
Proposal: builder.WriteRunReport("artifacts/run-report.json") (auto-enabled in detected CI): schema-versioned JSON with modules, statuses, durations, skip reasons, exception details, command counts — consumable by dashboards and cross-run tooling ("look across multiple runs for job output"). Add IRunHistoryStore with a local default retaining the last N reports, and render an end-of-run delta column ("BuildModule 2m10s, +32s vs previous"). Distributed serialization helpers already cover the tricky types. Perf: one serialize at pipeline end; history pruning bounded at N files.
Part of #3239 (round 2).
Category: feature — Breaking: no
PipelineSummaryexists only in-process (Engine/Executors/PipelineSummaryFactory.cs); no code serializes it to disk. The estimated-times store keeps only the latest duration per module (single overwritten file in FileSystemModuleEstimatedTimeProvider), so no trend data survives.IModuleResultRepositoryships NoOp-only. Precedent: Gradle build scans, Bazel BEP, GitHub check runs.Proposal:
builder.WriteRunReport("artifacts/run-report.json")(auto-enabled in detected CI): schema-versioned JSON with modules, statuses, durations, skip reasons, exception details, command counts — consumable by dashboards and cross-run tooling ("look across multiple runs for job output"). AddIRunHistoryStorewith a local default retaining the last N reports, and render an end-of-run delta column ("BuildModule 2m10s, +32s vs previous"). Distributed serialization helpers already cover the tricky types. Perf: one serialize at pipeline end; history pruning bounded at N files.Part of #3239 (round 2).