Skip to content

Pending changes exported from your codespace - #4

Open
ctx-eng wants to merge 4 commits into
khulnasoft:mainfrom
ctx-eng:codespace-orange-sniffle-qvv74xxqjp9gh9vq6
Open

Pending changes exported from your codespace#4
ctx-eng wants to merge 4 commits into
khulnasoft:mainfrom
ctx-eng:codespace-orange-sniffle-qvv74xxqjp9gh9vq6

Conversation

@ctx-eng

@ctx-eng ctx-eng commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Description

Related Issue

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Performance improvement
  • Refactoring
  • CI / build change

Checklist

  • cargo check compiles without warnings
  • cargo test passes
  • cargo fmt has been run
  • cargo clippy is clean
  • README updated if CLI surface changed
  • Tests added for new functionality (if applicable)

Summary by Sourcery

Add persistent build timing collection, richer tracing dashboard, CI policy/budget controls, feature flag auditing, and cross-crate split guidance to improve performance observability and optimization across Rust workspaces.

New Features:

  • Introduce a unified timing store for build commands with CLI querying to track historical performance across benchmark, regression, and trend runs.
  • Add a dependency feature audit and optional automatic Cargo.toml feature optimization command.
  • Extend the trace command with per-crate timing collection, historical trend visualizations, and an interactive HTML dashboard.
  • Add CI configuration options for enforcing performance policies and build time budgets, plus a generated pre-commit hook for local policy checks.
  • Provide cross-crate split suggestions based on workspace structure and lines-of-code analysis.
  • Expose a CLI to validate remote sccache cache configuration and connectivity.

Enhancements:

  • Make profile and parallelism recommendations CPU-aware using detected core counts in doctor, build audit, and profile settings.
  • Enhance CI workflow generation to conditionally include regression and policy-check jobs based on user options.
  • Improve workspace analysis by exposing lines-of-code counting publicly and surfacing split suggestions in the graph command output.
  • Enrich build tracing and trend tracking with shared timestamp helpers and consistent date formatting.
  • Update optimizer and main command wiring to pass new options through to CI, timing, and feature subcommands.

Documentation:

  • Update README links to point to the new GitHub organization and installer URLs.

Tests:

  • Add extensive unit tests for timing storage, HTML dashboard generation, CI workflow builder, remote cache validation, feature audit/optimization, crate split suggestion logic, and new CLI parsing paths.

Summary by CodeRabbit

  • New Features

    • Added new commands for feature audits, timing history, and remote cache validation.
    • CI checks can now be run with policy enforcement and a configurable regression budget.
    • Build reports now include historical timing trends and per-crate timing data.
  • Bug Fixes

    • Improved CPU-aware parallelism guidance and build profile recommendations.
    • Better cache and CI diagnostics when local tooling or configuration is missing.
  • Documentation

    • Updated repository references in the README.
    • Added a roadmap document outlining upcoming improvements.

@sourcery-ai

sourcery-ai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Introduce a unified timing/metrics subsystem, richer performance visualization and analysis (HTML dashboard, per-crate timings, historical trends), smarter CI and cache tooling, and feature/profile optimization plumbing across the CLI, while wiring everything together in main and docs.

Sequence diagram for tracer HTML dashboard generation with trends and per-crate timings

sequenceDiagram
    participant Main as main
    participant Tracer as tracer_run
    participant Cargo as collect_per_crate_timings
    participant Store as TimingStore
    participant Trend as load_trend_data
    participant HTML as generate_html_report

    Main->>Tracer: run(TraceOptions)
    Tracer->>Tracer: measure_phases(root)
    Tracer->>Tracer: identify_bottlenecks(phases)

    alt options.collect_per_crate
        Tracer->>Cargo: collect_per_crate_timings(root)
        Cargo-->>Tracer: Vec<PerCrateTiming>
    else
        Tracer->>Tracer: per_crate_data = Vec::new()
    end

    Tracer->>Trend: load_trend_data(root)
    Trend->>Store: TimingStore::load(get_store_path(root))
    Store-->>Trend: TimingStore
    Trend-->>Tracer: HashMap<String, Vec<(u64,u64)>>

    opt export_html
        Tracer->>HTML: generate_html_report(&DashboardData)
        HTML-->>Tracer: String (html)
        Tracer->>Tracer: fs::write(html_path, html)
    end

    Tracer-->>Main: Result<()>
Loading

File-Level Changes

Change Details Files
Add a unified timing store and CLI to record, query, and pretty-print build timing history used by benchmark, regression, trend, and trace subsystems.
  • Introduce BuildRun and TimingStore types with JSON load/save, ID allocation, query helpers, and duration statistics APIs.
  • Provide helpers to capture git branch/commit, current timestamp, and to record a build run tagged with command/profile/label.
  • Add a timings.json location helper and a run_list function plus ListArgs to list recent runs or filter by command with formatted table output and time formatting utilities.
  • Back timing operations with comprehensive unit tests for store behavior, queries, serialization round-trips, and formatting utilities.
src/timings.rs
Upgrade tracing to produce an interactive HTML dashboard, integrate unified timing trends, and optionally collect per-crate timings via cargo --timings.
  • Extend TraceOptions with per-crate collection and introduce PerCrateTiming and DashboardData to carry phases, bottlenecks, per-crate, and trend data.
  • Add load_trend_data to read TimingStore into per-command time series, and collect_per_crate_timings/parse_timings_json_dir to aggregate crate-level durations.
  • Rewrite generate_html_report to emit a Plotly-based dashboard (Gantt, treemap/bar, trend chart) backed by build_gantt_json, build_flame_json, build_trend_json, render_bottlenecks_html, and HTML escaping utilities.
  • Add a local chrono_like_timestamp/time_to_datetime implementation for the HTML trend axis and expand tests to cover all new helpers and error paths.
src/tracer.rs
Enhance workspace graph analysis with cross-crate split suggestions and persistence for later review.
  • Define SplitSuggestion and SplitReport types and helper to find workspace member directories.
  • Implement suggest_crate_splits using workspace metadata, LOC, dependency counts, and fan-in/out metrics (via edges) to identify large/wide/utility-hub crates and estimate compile cost/savings.
  • Generate heuristic module split names with propose_modules, save suggestions to .cargo-accelerate/splits.toml, and print human-readable recommendations via print_split_suggestions.
  • Update graph::run to compute and emit split suggestions, make count_rust_loc public within workspace, and add tests for the suggestion heuristics, serialization, and printing paths.
src/graph.rs
src/workspace.rs
Make CI generation configurable with enforcement/budget options, add a pre-commit hook template, and improve CI parity checks.
  • Introduce CiOptions and replace the monolithic workflow template with BASE_WORKFLOW_HEAD, REGRESSION_CHECK_JOB, and POLICY_CHECK_JOB fragments, plus build_workflow(enforce_policy,budget).
  • Add a pre-commit hook script template to run cargo accelerate audit (and optional regression) and have ci::run generate it under .cargo-accelerate with executable permissions on Unix.
  • Extend CI parity checks to use Path, clean up messaging, and add print_enforcement_summary to surface enforcement/budget configuration to the user.
  • Add a focused test module that validates workflow generation under different combos, hook content, enforcement summary behavior, Dockerfile invariants, and a parity-check happy path.
src/ci.rs
Improve remote cache tooling by adding a connectivity validator that checks sccache setup, environment, and dist status.
  • Extend CacheAction and dispatcher to handle a new ValidateRemote action.
  • Implement validate_remote_cache to verify sccache/sccache-dist presence, inspect SCCACHE_* env vars, run sccache --dist-status if possible, and print structured summary including latency and guidance.
  • Add tests that exercise validate_remote_cache under different env setups, ensuring it is robust when tools or env vars are missing.
src/cache.rs
src/cli.rs
Refine build audit to use feature analysis results and CPU-aware codegen-units guidance instead of hard-coded heuristics.
  • Change dependency feature checks to delegate to the new features::analyze_features API, emit concrete suggestions with estimated savings, and push structured issues when defaults are suboptimal.
  • Introduce utils::available_cpus and use it in check_parallel_build to compute suggested codegen-units ranges, detect too-low or too-high values relative to core count, and improve messaging, including jobs hints.
  • Adjust tests to assert behavior relative to CPU count (handling low/high cases) and add explicit tests for high codegen-units overhead warnings.
src/build_audit.rs
src/utils.rs
Extend the CLI surface to cover new timing, feature, CI, trace, and cache capabilities and wire them into main.
  • Add Features { optimize }, Timings { command,last }, extended Ci { enforce_policy,budget }, Trace { collect_timings }, and CacheAction::ValidateRemote variants to the Commands enum.
  • Update main dispatch to call features::run, ci::run with CiOptions, tracer::run with collect_per_crate flag, and timings::run_list for the new Timings command.
  • Expand CLI tests to cover parsing of the new subcommands/flags, including CI flag combinations, cache validate-remote, features optimize, and trace collect_timings defaulting.
src/cli.rs
src/main.rs
Make doctor output CPU-aware parallelism recommendations and slightly reorder checks.
  • Use available_cpus to report detected cores, analyze codegen-units ratio to CPUs, and add recommendations for under/over-parallelization in dev profiles.
  • On high-core machines with a .cargo/config.toml, prompt users to consider setting build.jobs when absent and adjust numbering/comments of subsequent checks.
  • Leave existing tool/policy/baseline checks intact while ensuring the new recommendations are surfaced and can populate the recommendations list.
src/doctor.rs
Make profile selection CPU-aware by deriving dev/test codegen-units from available cores instead of a constant.
  • Use available_cpus in ProfileSettings::for_scenario to set dev/test codegen_units to min(cpus*2, 256), keeping other profile knobs unchanged.
  • Update tests to compute expected values dynamically via available_cpus so they remain valid across environments, and assert TOML serialization and application reflect the new defaults.
src/profile.rs
Integrate the unified timings store into benchmark, regression, and trend workflows so measurements are persistently recorded.
  • In benchmark, load TimingStore at the start of run_benchmark_sequence, record phase durations for "before" and "after" using a new record_benchmark_timings helper, and save back to timings.json.
  • In regression, pass a mutable TimingStore into compare_with_baseline and record current build/check times as regression runs before printing the report.
  • In trend, load TimingStore alongside TrendHistory and record each new check/build measurement as labeled trend runs using timings::get_current_timestamp.
src/benchmark.rs
src/regression.rs
src/trend.rs
src/timings.rs
Introduce a dedicated features analysis module that can audit and optionally rewrite dependency feature sets based on known minimal profiles.
  • Define FeatureSuggestion/FeatureAudit/FeaturesConfig and FeaturesOptions, along with a known_feature_suggestions map for high-impact crates (tokio, syn, clap, hyper, reqwest, etc.).
  • Implement analyze_features to walk direct dependencies via Cargo.toml + cargo_metadata, compare current defaults against known recommendations, estimate potential savings, and rank suggestions.
  • Provide save_suggestions to persist recommended feature sets to .cargo-accelerate/features.toml and optimize_dependencies to rewrite Cargo.toml using toml_edit (string and table forms) to disable defaults and set explicit features.
  • Implement a top-level run that prints a tabular feature audit report, summarizes optimization opportunities, saves suggestions, and optionally applies changes when --optimize is used, with extensive unit tests for all code paths.
src/features.rs
Add supporting utilities, documentation updates, and non-functional files.
  • Add plan.md as an internal project analysis and improvement plan document (not consumed by the binary).
  • Expose workspace::count_rust_loc as pub(crate) for reuse by graph analyses.
  • Add a placeholder scripts/install_rust file (currently empty) for future installer tooling.
  • Update README references from the old GitHub org (anomalyco) to khulnasoft for badges and installation instructions.
  • Adjust optimizer::run to construct CiOptions and call the updated ci::run API.
plan.md
src/workspace.rs
scripts/install_rust
README.md
src/optimizer.rs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@ctx-eng, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 9 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1dd16607-b58b-4aa0-b0e9-a304f4a14a8a

📥 Commits

Reviewing files that changed from the base of the PR and between 290e066 and 31a578a.

📒 Files selected for processing (3)
  • plan.md
  • src/timings.rs
  • src/tracer.rs

Walkthrough

Adds a persistent build-timing store used across benchmark, regression, trend, and tracer modules; introduces CPU-aware heuristics for codegen-units and parallel build checks; adds a dependency feature audit module and cross-crate split suggestions; extends CI with enforcement/policy options and remote cache validation; updates CLI, docs, and scripts.

Changes

Cargo Accelerate feature additions

Layer / File(s) Summary
Timing store core
src/timings.rs
Adds BuildRun/TimingStore structs with load/save persistence, query helpers, median/avg calculations, and a CLI listing function with tests.
Timing store wiring
src/benchmark.rs, src/regression.rs, src/trend.rs, src/tracer.rs, src/main.rs, src/cli.rs
Integrates the timing store into benchmark/regression/trend recording, tracer trend loading, and adds the Timings CLI subcommand and collect_timings trace flag.
Tracer dashboard rewrite
src/tracer.rs
Replaces the table-based HTML report with a Plotly-driven dashboard (gantt, flame, trend charts, bottlenecks).
CPU-aware heuristics
src/utils.rs, src/profile.rs, src/build_audit.rs, src/doctor.rs
Adds available_cpus() and uses it to derive codegen_units, parallel-build scoring, and doctor CPU/parallelism diagnostics.
Feature audit module
src/features.rs, src/build_audit.rs, src/cli.rs, src/main.rs
Adds dependency feature analysis, suggestion saving, and Cargo.toml rewriting, wired into build audit and a new features CLI subcommand.
Cross-crate split suggestions
src/graph.rs, src/workspace.rs
Adds SplitSuggestion/SplitReport models, workspace-aware split analysis, and persistence to splits.toml.
CI enforcement and pre-commit hook
src/ci.rs, src/cli.rs, src/main.rs, src/optimizer.rs
Adds CiOptions (enforce_policy, budget), parameterized workflow generation, policy-check job, and a generated pre-commit hook.
Remote cache validation
src/cache.rs, src/cli.rs
Adds CacheAction::ValidateRemote and validate_remote_cache checking sccache tooling, env vars, and dist-status connectivity.
Docs and scripts
README.md, plan.md, scripts/install_rust
Updates repository links, adds a roadmap document, and adds a Rust install CI script.

Estimated code review effort: 4 (Complex) | ~75 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant CiModule
  participant Filesystem

  CLI->>CiModule: run(CiOptions{enforce_policy, budget})
  CiModule->>CiModule: build_workflow(enforce_policy, budget)
  CiModule->>Filesystem: write build.yml
  CiModule->>Filesystem: write .cargo-accelerate/pre-commit.sh
  CiModule->>CiModule: check_ci_parity()
  CiModule->>CLI: print_enforcement_summary()
Loading
sequenceDiagram
  participant BuildAudit
  participant TimingStore
  participant Disk

  BuildAudit->>TimingStore: load(store_path)
  BuildAudit->>TimingStore: record_build_run(command, duration)
  TimingStore->>Disk: save(store_path)
Loading

Estimated code review effort: 4 (Complex) | ~75 minutes

Poem

A rabbit hopped through logs and code,
Timed each build along the road,
CPUs counted, features trimmed,
Splits proposed and hooks pre-primed,
Hop, hop, hooray — the CI's aglow! 🐇⏱️

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.35% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is generic and does not describe the actual documentation, CLI, and Rust tooling changes in the PR. Replace it with a concise summary of the main change, such as adding timing, CI, and feature-audit tooling updates.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 4 issues, and left some high level feedback:

  • The timestamp helpers (chrono_like_timestamp, time_to_datetime, is_leap) are now implemented in both timings.rs and tracer.rs; consider centralizing these in a shared module to avoid duplication and keep their behavior consistent.
  • The validate_remote_cache tests mutate process environment variables globally (and even use unsafe around set_var/remove_var); consider wrapping env changes in a small helper that saves/restores the previous values to reduce flakiness when tests run in parallel and avoid unsafe here altogether.
  • plan.md appears to include AI-style narrative text (e.g., "I'll help you analyze the repository...") and a long internal plan; if this is not intended as user-facing documentation, consider either removing it from the repo or trimming it to a concise, project-appropriate design document.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The timestamp helpers (`chrono_like_timestamp`, `time_to_datetime`, `is_leap`) are now implemented in both `timings.rs` and `tracer.rs`; consider centralizing these in a shared module to avoid duplication and keep their behavior consistent.
- The `validate_remote_cache` tests mutate process environment variables globally (and even use `unsafe` around `set_var`/`remove_var`); consider wrapping env changes in a small helper that saves/restores the previous values to reduce flakiness when tests run in parallel and avoid `unsafe` here altogether.
- `plan.md` appears to include AI-style narrative text (e.g., "I'll help you analyze the repository...") and a long internal plan; if this is not intended as user-facing documentation, consider either removing it from the repo or trimming it to a concise, project-appropriate design document.

## Individual Comments

### Comment 1
<location path="src/timings.rs" line_range="31-32" />
<code_context>
+impl TimingStore {
+    pub fn load(path: &Path) -> Result<Self> {
+        if path.exists() {
+            let content = fs::read_to_string(path)?;
+            Ok(serde_json::from_str(&content).unwrap_or_default())
+        } else {
+            Ok(Self::default())
</code_context>
<issue_to_address>
**issue (bug_risk):** Avoid silently discarding corrupted timings.json by using `unwrap_or_default()`.

`serde_json::from_str(&content).unwrap_or_default()` makes any parse error indistinguishable from a legitimate "no data yet" case, which can mask file corruption or partial writes. Instead, consider propagating the `serde_json` error with `?`, or at least logging a warning and backing up/renaming the bad file before creating a new empty store so corruption is visible and not silently ignored.
</issue_to_address>

### Comment 2
<location path="src/tracer.rs" line_range="572-581" />
<code_context>
+fn chrono_like_timestamp(unix_ts: u64) -> String {
</code_context>
<issue_to_address>
**suggestion:** Time formatting helpers are duplicated between `timings.rs` and `tracer.rs`.

This module reimplements `chrono_like_timestamp`, `time_to_datetime`, and `is_leap` instead of reusing the versions in `timings.rs`. Please extract these helpers into a shared module (e.g., `timings` or a `utils` module) and call them from both places, adding small formatting/config options if needed rather than maintaining duplicate logic.

Suggested implementation:

```rust
fn chrono_like_timestamp(unix_ts: u64) -> String {
    // Delegate to the shared implementation in the timings module
    crate::timings::chrono_like_timestamp(unix_ts)
}

```

To fully implement your suggestion and remove duplicated logic:
1. Extract the shared helpers into a common module (e.g. `timings.rs` or `utils/time.rs`) if not already present:
   - `pub fn chrono_like_timestamp(unix_ts: u64) -> String`
   - `pub fn time_to_datetime(secs: i64, nanos: u32) -> (i32, u32, u32, u32, u32, u32)`
   - `pub fn is_leap(year: i32) -> bool`
2. In `src/tracer.rs`, remove the local implementations of `time_to_datetime` and `is_leap` entirely and replace any internal calls with the shared versions:
   - Add `use crate::timings::{chrono_like_timestamp, time_to_datetime, is_leap};` (or the appropriate module path).
   - If you prefer to keep local wrapper fns for clarity, make them simple pass-through delegates as done for `chrono_like_timestamp`.
3. In `src/timings.rs` (or wherever the existing implementations live), ensure the functions are marked `pub` and are the single source of truth for the logic currently duplicated in `tracer.rs`.
4. Run `cargo fmt` and `cargo clippy` to confirm there are no unused functions left in `tracer.rs` and that all call sites now use the shared helpers.
</issue_to_address>

### Comment 3
<location path="plan.md" line_range="1" />
<code_context>
+I'll help you analyze the repository and create an improvement plan for a high-performance build system for Rust codebases. Let me start by gathering comprehensive information about the repository.Now let me explore the source directory structure and key files:Now I have a comprehensive view of the repository. Let me create a detailed improvement plan document.
+
+---
</code_context>
<issue_to_address>
**issue (typo):** Fix missing spaces and run-together sentences in the opening paragraph.

In particular, there are missing spaces after periods at "repository.Now" and "files:Now", which makes the sentences run together and harder to read.

```suggestion
I'll help you analyze the repository and create an improvement plan for a high-performance build system for Rust codebases. Let me start by gathering comprehensive information about the repository. Now let me explore the source directory structure and key files: Now I have a comprehensive view of the repository. Let me create a detailed improvement plan document.
```
</issue_to_address>

### Comment 4
<location path="plan.md" line_range="47-56" />
<code_context>
+  optimize.rs       Auto-apply all optimizations to Cargo.toml/.cargo/config.toml
</code_context>
<issue_to_address>
**suggestion (typo):** Use a consistent filename: `optimize.rs` vs `optimizer.rs`.

The architecture overview lists `optimize.rs`, but the control flow section uses `optimizer.rs`. Please update both to use the same filename to avoid confusion for readers locating the source file.

Suggested implementation:

```
optimize.rs

```

The snippet you provided from the "How It's Organized" section already uses `optimize.rs`, so no change is needed there. The above edit assumes the "Control Flow" section (or any other sections) refer to `optimizer.rs`; those references should be updated to `optimize.rs` to keep the filename consistent with the architecture overview and the actual source file.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/timings.rs
Comment on lines +31 to +32
let content = fs::read_to_string(path)?;
Ok(serde_json::from_str(&content).unwrap_or_default())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Avoid silently discarding corrupted timings.json by using unwrap_or_default().

serde_json::from_str(&content).unwrap_or_default() makes any parse error indistinguishable from a legitimate "no data yet" case, which can mask file corruption or partial writes. Instead, consider propagating the serde_json error with ?, or at least logging a warning and backing up/renaming the bad file before creating a new empty store so corruption is visible and not silently ignored.

Comment thread src/tracer.rs
Comment on lines +572 to +581
fn chrono_like_timestamp(unix_ts: u64) -> String {
let secs = unix_ts as i64;
let nanos = 0u32;
let dt = time_to_datetime(secs, nanos);
format!(
"{:04}-{:02}-{:02} {:02}:{:02}",
dt.0, dt.1, dt.2, dt.3, dt.4
)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Time formatting helpers are duplicated between timings.rs and tracer.rs.

This module reimplements chrono_like_timestamp, time_to_datetime, and is_leap instead of reusing the versions in timings.rs. Please extract these helpers into a shared module (e.g., timings or a utils module) and call them from both places, adding small formatting/config options if needed rather than maintaining duplicate logic.

Suggested implementation:

fn chrono_like_timestamp(unix_ts: u64) -> String {
    // Delegate to the shared implementation in the timings module
    crate::timings::chrono_like_timestamp(unix_ts)
}

To fully implement your suggestion and remove duplicated logic:

  1. Extract the shared helpers into a common module (e.g. timings.rs or utils/time.rs) if not already present:
    • pub fn chrono_like_timestamp(unix_ts: u64) -> String
    • pub fn time_to_datetime(secs: i64, nanos: u32) -> (i32, u32, u32, u32, u32, u32)
    • pub fn is_leap(year: i32) -> bool
  2. In src/tracer.rs, remove the local implementations of time_to_datetime and is_leap entirely and replace any internal calls with the shared versions:
    • Add use crate::timings::{chrono_like_timestamp, time_to_datetime, is_leap}; (or the appropriate module path).
    • If you prefer to keep local wrapper fns for clarity, make them simple pass-through delegates as done for chrono_like_timestamp.
  3. In src/timings.rs (or wherever the existing implementations live), ensure the functions are marked pub and are the single source of truth for the logic currently duplicated in tracer.rs.
  4. Run cargo fmt and cargo clippy to confirm there are no unused functions left in tracer.rs and that all call sites now use the shared helpers.

Comment thread plan.md Outdated
Comment thread plan.md
Comment on lines +47 to +56
optimize.rs Auto-apply all optimizations to Cargo.toml/.cargo/config.toml
benchmark.rs Before/after build time comparison
profile.rs Scenario-aware build profiles (dev/test/ci/release)

cache.rs sccache management (enable/disable/remote)
linker.rs Fast linker configuration (mold/lld)
installer.rs Tool auto-installation (sccache, mold, nextest, etc.)

graph.rs Build graph analysis & critical path detection
workspace.rs Crate architecture analysis (LoC, compile weight)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (typo): Use a consistent filename: optimize.rs vs optimizer.rs.

The architecture overview lists optimize.rs, but the control flow section uses optimizer.rs. Please update both to use the same filename to avoid confusion for readers locating the source file.

Suggested implementation:

optimize.rs

The snippet you provided from the "How It's Organized" section already uses optimize.rs, so no change is needed there. The above edit assumes the "Control Flow" section (or any other sections) refer to optimizer.rs; those references should be updated to optimize.rs to keep the filename consistent with the architecture overview and the actual source file.

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Signed-off-by: NxPKG <116948796+NxPKG@users.noreply.github.com>
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Implement timings storage, feature audit, CI enforcement, and interactive HTML dashboard

✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Adds src/timings.rs: a persistent JSON-backed TimingStore that records every build run
 (command, duration, branch, commit) and exposes query/stats APIs; integrated into benchmark,
 regression, and trend commands.
• Adds src/features.rs: a new features subcommand that audits dependency feature flags against a
 known-good minimal-feature map, estimates compile-time savings, and optionally rewrites Cargo.toml
 with default-features = false.
• Extends src/ci.rs: ci command now accepts --enforce-policy and --budget flags,
 conditionally appending regression-check and policy-check CI jobs and generating a pre-commit hook
 under .cargo-accelerate/pre-commit.sh.
• Upgrades src/tracer.rs HTML export to a full Plotly.js interactive dashboard (Gantt,
 treemap/flame, trend sparklines) and adds --collect-timings for per-crate breakdown via `cargo
 build --timings=json`.
• Makes codegen-units CPU-aware across profile.rs, build_audit.rs, and doctor.rs using a new
 utils::available_cpus() helper; suggestions now scale with detected core count.
• Adds crate-split suggestions to src/graph.rs based on LoC, fan-in/fan-out, and external-dep
 density, saving results to .cargo-accelerate/splits.toml.
• Updates README.md CI badge URL from anomalyco to khulnasoft org; adds plan.md project
 analysis document and scripts/install_rust CI helper script.
Diagram

graph TD
    CLI["cli.rs\nCLI Parser"] --> MAIN["main.rs\nDispatcher"]
    MAIN --> FEAT["features.rs\nFeature Audit"]
    MAIN --> TIMING["timings.rs\nTimingStore"]
    MAIN --> CI["ci.rs\nCI Generator"]
    MAIN --> TRACER["tracer.rs\nTrace + Dashboard"]
    MAIN --> BENCH["benchmark.rs\nBenchmark"]
    MAIN --> REG["regression.rs\nRegression"]
    MAIN --> TREND["trend.rs\nTrend"]
    MAIN --> GRAPH["graph.rs\nGraph + Splits"]
    MAIN --> AUDIT["build_audit.rs\nBuild Audit"]
    MAIN --> DOCTOR["doctor.rs\nDoctor"]
    MAIN --> PROFILE["profile.rs\nProfiles"]
    BENCH --> TIMING
    REG --> TIMING
    TREND --> TIMING
    TRACER --> TIMING
    AUDIT --> FEAT
    GRAPH --> WS["workspace.rs\ncount_rust_loc"]
    PROFILE --> UTILS["utils.rs\navailable_cpus"]
    AUDIT --> UTILS
    DOCTOR --> UTILS
    TIMING --> FS[("timings.json")]
    FEAT --> FS2[("features.toml")]
    GRAPH --> FS3[("splits.toml")]
    CI --> FS4[("build.yml +\npre-commit.sh")]
    TRACER --> HTML[("HTML Dashboard")]

    subgraph Legend
      direction LR
      _mod["Module"] ~~~ _db[("File/Store")] ~~~ _out["Output"]
    end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use SQLite via rusqlite for TimingStore
  • ➕ Enables efficient range queries, aggregations, and multi-branch tracking without loading the full file
  • ➕ Avoids the custom datetime formatter (use chrono or time crate instead)
  • ➕ Scales to thousands of runs without memory pressure
  • ➖ Adds a native dependency (libsqlite3 or bundled feature)
  • ➖ Increases binary size and compile time — ironic for a compile-time optimizer
  • ➖ More complex setup for users on minimal environments
2. Reuse chrono crate for timestamp formatting in timings.rs
  • ➕ Eliminates the 60-line hand-rolled time_to_datetime / is_leap implementation duplicated between timings.rs and tracer.rs
  • ➕ Less maintenance burden; correct handling of edge cases
  • ➖ Adds a dependency (though chrono is already common in the Rust ecosystem)
  • ➖ Minor binary size increase

Recommendation: The PR's approach of a custom JSON-backed TimingStore is reasonable for a zero-dependency CLI tool, but there are two areas worth considering alternatives.

Files changed (20) +3276 / -153

Enhancement (10) +1358 / -85
tracer.rsUpgrade HTML export to interactive Plotly.js dashboard with per-crate timings +576/-53

Upgrade HTML export to interactive Plotly.js dashboard with per-crate timings

• Replaces the static HTML table report with a full Plotly.js dashboard containing a Gantt phase timeline, a treemap/flame chart for per-crate breakdown, and a historical trend sparkline. Adds '--collect-timings' flag that runs 'cargo build --timings=json' and parses the output. Loads trend data from the new 'TimingStore'. Adds HTML-escaping and structured 'DashboardData' type.

src/tracer.rs

ci.rsAdd --enforce-policy and --budget flags with conditional CI job generation +199/-11

Add --enforce-policy and --budget flags with conditional CI job generation

• Splits the monolithic 'WORKFLOW_TEMPLATE' into composable constants ('BASE_WORKFLOW_HEAD', 'REGRESSION_CHECK_JOB', 'POLICY_CHECK_JOB'). The 'build_workflow' function conditionally appends regression and policy-check jobs based on 'CiOptions'. Also generates a pre-commit hook script at '.cargo-accelerate/pre-commit.sh' and sets Unix execute permissions. Adds a comprehensive test suite for all workflow combinations.

src/ci.rs

graph.rsAdd cross-crate split suggestions based on LoC, fan-in/fan-out, and dep density +302/-1

Add cross-crate split suggestions based on LoC, fan-in/fan-out, and dep density

• Introduces 'suggest_crate_splits' which iterates workspace members, counts LoC via 'workspace::count_rust_loc', computes external-dep density, and flags large (>3000 LoC), wide (>1000 LoC, low dep ratio), or utility-hub (fan-in > 3) crates as split candidates. Proposed sub-crate names are generated by 'propose_modules'. Results are printed and saved to '.cargo-accelerate/splits.toml'.

src/graph.rs

doctor.rsAdd CPU parallelism analysis section to doctor diagnostics +58/-6

Add CPU parallelism analysis section to doctor diagnostics

• Inserts a new step (step 3) that detects CPU count via 'available_cpus()', evaluates the 'codegen-units' ratio, and emits warnings for over- or under-utilization. Also checks whether 'build.jobs' is set for machines with more than 8 cores.

src/doctor.rs

profile.rsMake dev/test codegen-units CPU-aware instead of hardcoded 256 +13/-5

Make dev/test codegen-units CPU-aware instead of hardcoded 256

• Replaces the static 'codegen_units: Some(256)' in 'Scenario::Dev' and 'Scenario::Test' with '(cpus * 2).min(256)' using the new 'available_cpus()' helper. Updates all affected tests to compute the expected value dynamically.

src/profile.rs

benchmark.rsPersist before/after benchmark timings to the unified TimingStore +15/-0

Persist before/after benchmark timings to the unified TimingStore

• Loads the 'TimingStore' at the start of 'run_benchmark_sequence' and calls 'record_benchmark_timings' after each measurement phase (before and after optimization), saving check/build/test/clippy durations with phase-prefixed labels.

src/benchmark.rs

regression.rsRecord regression comparison timings into the unified TimingStore +13/-2

Record regression comparison timings into the unified TimingStore

• Loads 'TimingStore' at the start of 'run' and passes it through to 'compare_with_baseline'. After measuring current builds, records build and check durations with 'regression-current' and 'regression-estimated' labels before saving.

src/regression.rs

trend.rsFeed trend measurements into the unified TimingStore +11/-4

Feed trend measurements into the unified TimingStore

• Loads 'TimingStore' alongside the existing 'TrendHistory', records check and build times with 'trend-check'/'trend-build' labels, and saves the store. Replaces the inline 'SystemTime' timestamp with 'timings::get_current_timestamp()'.

src/trend.rs

cli.rsAdd Features, Timings subcommands; extend Ci and Trace with new flags +146/-2

Add Features, Timings subcommands; extend Ci and Trace with new flags

• Adds 'Commands::Features { optimize }' and 'Commands::Timings { command, last }' variants. Converts 'Commands::Ci' from a unit variant to a struct variant with 'enforce_policy' and 'budget' fields. Adds 'collect_timings' flag to 'Commands::Trace'. Adds 'CacheAction::ValidateRemote' variant. Extends the test suite with coverage for all new CLI shapes.

src/cli.rs

main.rsWire new features and timings modules into the command dispatcher +25/-1

Wire new features and timings modules into the command dispatcher

• Declares 'mod features' and 'mod timings'. Adds dispatch arms for 'Commands::Features', 'Commands::Timings', and the updated 'Commands::Ci' with its new options struct. Passes 'collect_timings' through to 'TraceOptions'.

src/main.rs

Bug fix (1) +5 / -1
optimizer.rsPass CiOptions to ci::run() call in optimizer +5/-1

Pass CiOptions to ci::run() call in optimizer

• Updates the 'ci::run()' call site to pass a default 'CiOptions { enforce_policy: false, budget: None }' to match the updated function signature.

src/optimizer.rs

Refactor (3) +132 / -64
build_audit.rsReplace hardcoded feature check with features module; make codegen-units CPU-aware +117/-63

Replace hardcoded feature check with features module; make codegen-units CPU-aware

• Delegates 'check_dependency_features' to 'crate::features::analyze_features' for richer per-dependency reporting with estimated savings. Replaces the fixed 'codegen-units >= 128' threshold in 'check_parallel_build' with CPU-aware thresholds: suggests 'cpus * 2' as the dev target and warns when units exceed 'cpus * 4'. Updates tests to be machine-adaptive.

src/build_audit.rs

utils.rsExtract available_cpus() as a shared utility function +14/-0

Extract available_cpus() as a shared utility function

• Adds 'pub fn available_cpus() -> usize' wrapping 'std::thread::available_parallelism()' with a fallback of 1. Adds a test asserting the result is in the range [1, 1024).

src/utils.rs

workspace.rsMake count_rust_loc pub(crate) for use in graph split analysis +1/-1

Make count_rust_loc pub(crate) for use in graph split analysis

• Changes 'count_rust_loc' visibility from private to 'pub(crate)' so 'graph.rs' can call it when computing LoC for crate-split candidates.

src/workspace.rs

Documentation (2) +376 / -3
README.mdUpdate CI badge and clone URLs from anomalyco to khulnasoft org +3/-3

Update CI badge and clone URLs from anomalyco to khulnasoft org

• Replaces three occurrences of 'anomalyco/cargo-accelerate' with 'khulnasoft/cargo-accelerate' in the CI badge, git clone example, and installer curl command.

README.md

plan.mdAdd comprehensive project analysis and improvement roadmap document +373/-0

Add comprehensive project analysis and improvement roadmap document

• New 373-line document covering architecture overview, gap analysis across 5 phases (foundation, observability, advanced analysis, usability, documentation), a prioritized Q3 2026–Q1 2027 roadmap, technical debt table, and success metrics.

plan.md

Other (4) +1405 / -0
timings.rsNew persistent build-run timing store with query and stats APIs +661/-0

New persistent build-run timing store with query and stats APIs

• Introduces 'TimingStore' backed by a JSON file at '.cargo-accelerate/timings.json'. Each 'BuildRun' record captures command, duration, profile, git branch, and commit hash. Provides query methods (by command, profile, branch, label, since-timestamp, latest-N) plus median/average aggregations. Includes a 'run_list' entry point for the new 'timings' CLI subcommand and a custom no-dependency datetime formatter.

src/timings.rs

features.rsNew dependency feature-flag audit and auto-optimization module +514/-0

New dependency feature-flag audit and auto-optimization module

• Implements 'analyze_features' which cross-references direct dependencies against a static map of known minimal feature sets (syn, tokio, clap, hyper, reqwest, etc.) and uses 'cargo_metadata' to read actual default feature lists. Computes estimated compile-time savings percentage. 'optimize_dependencies' rewrites 'Cargo.toml' using 'toml_edit' to set 'default-features = false' and inject recommended features. Results are also saved to '.cargo-accelerate/features.toml'.

src/features.rs

cache.rsAdd validate-remote subcommand for sccache connectivity diagnostics +191/-0

Add validate-remote subcommand for sccache connectivity diagnostics

• Implements 'validate_remote_cache()' which checks sccache/sccache-dist installation, inspects 'SCCACHE_ENDPOINT'/'SCCACHE_BUCKET'/'SCCACHE_REGION'/'SCCACHE_DIST' env vars, runs 'sccache --dist-status' with latency measurement, and prints a summary. Adds three tests covering no-sccache, env-var, and dist-disabled scenarios.

src/cache.rs

install_rustAdd CI script to install Rust via rustup with GitHub Actions support +39/-0

Add CI script to install Rust via rustup with GitHub Actions support

• New bash script that checks for an existing 'cargo' binary, installs Rust via 'rustup' if missing, sources '~/.cargo/env', and handles the GitHub Actions non-interactive flag via 'CI_FLAGS'.

scripts/install_rust

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (6) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Secrets logged in cache 🐞 Bug ⛨ Security
Description
validate_remote_cache() prints SCCACHE_* environment variable values and echoes `sccache
--dist-status` output to stdout, which can leak internal endpoints/credentials into CI logs. This is
a security exposure when logs are persisted or publicly visible.
Code

src/cache.rs[R141-221]

+    // 2. Check environment variables
+    let endpoint = std::env::var("SCCACHE_ENDPOINT").ok();
+    let bucket = std::env::var("SCCACHE_BUCKET").ok();
+    let region = std::env::var("SCCACHE_REGION").ok();
+    let dist_enabled = std::env::var("SCCACHE_DIST").ok();
+
+    println!("\n  Environment:");
+    match &endpoint {
+        Some(v) => println!("  ✓ SCCACHE_ENDPOINT = {}", v.green()),
+        None => println!("  ✗ SCCACHE_ENDPOINT = {}", "not set".red()),
+    }
+    match &bucket {
+        Some(v) => println!("  ✓ SCCACHE_BUCKET  = {}", v.green()),
+        None => println!("  ⚠ SCCACHE_BUCKET  = {}", "not set (may not be needed)".yellow()),
+    }
+    match &region {
+        Some(v) => println!("  ✓ SCCACHE_REGION  = {}", v.green()),
+        None => println!("  ⚠ SCCACHE_REGION  = {}", "not set (may not be needed)".yellow()),
+    }
+    match &dist_enabled {
+        Some(v) if v == "true" || v == "1" => {
+            println!("  ✓ SCCACHE_DIST    = {}", v.green());
+        }
+        Some(v) => {
+            println!("  ⚠ SCCACHE_DIST    = {}", v.yellow());
+            println!("    Set SCCACHE_DIST=true to enable distributed caching.");
+        }
+        None => {
+            println!("  ⚠ SCCACHE_DIST    = {}", "not set".yellow());
+            println!("    Set SCCACHE_DIST=true to enable distributed caching.");
+        }
+    }
+
+    // 3. Test connectivity
+    println!("\n  Connectivity test:");
+    if endpoint.is_some() {
+        let start = std::time::Instant::now();
+        let output = std::process::Command::new("sccache")
+            .args(["--dist-status"])
+            .output();
+        let elapsed = start.elapsed();
+
+        match output {
+            Ok(out) => {
+                let stdout = String::from_utf8_lossy(&out.stdout);
+                let stderr = String::from_utf8_lossy(&out.stderr);
+                let combined = format!("{}{}", stdout, stderr);
+                let latency_ms = elapsed.as_millis();
+
+                if out.status.success() {
+                    if combined.to_lowercase().contains("connected")
+                        || combined.to_lowercase().contains("ok")
+                        || combined.to_lowercase().contains("available")
+                    {
+                        println!(
+                            "  ✓ Remote cache {} (latency: {}ms)",
+                            "reachable".green(),
+                            latency_ms.to_string().cyan()
+                        );
+                    } else {
+                        println!(
+                            "  ⚠ Remote cache responded but status unclear (latency: {}ms)",
+                            latency_ms.to_string().cyan()
+                        );
+                    }
+                } else {
+                    println!(
+                        "  ✗ Remote cache {} (latency: {}ms)",
+                        "unreachable".red(),
+                        latency_ms.to_string().cyan()
+                    );
+                }
+
+                // Print any non-empty output
+                let trimmed = combined.trim();
+                if !trimmed.is_empty() {
+                    println!("\n  sccache --dist-status output:\n");
+                    for line in trimmed.lines() {
+                        println!("    {}", line.trim());
+                    }
+                }
Evidence
The remote-cache validation command prints env var values and then prints every line from the
sccache --dist-status output, which can disclose sensitive configuration details into logs.

src/cache.rs[114-262]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`validate_remote_cache()` prints potentially sensitive values (SCCACHE_ENDPOINT/BUCKET/REGION and command output) directly to stdout. In CI this can leak secrets or internal infrastructure details.

### Issue Context
This is a user-facing diagnostic command, but it is likely to be run in CI and the output ends up in logs.

### Fix Focus Areas
- src/cache.rs[141-221]

### Suggested fix
- Print only whether each env var is set, not the value (e.g., `SCCACHE_ENDPOINT = set`).
- If you still need values for troubleshooting, gate them behind an explicit `--verbose` / `--show-values` flag.
- Avoid printing full `sccache --dist-status` output by default; either summarize status or print only on verbose mode.
- Consider masking common secret patterns (URLs with credentials, tokens) if values must be shown.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Feature audit ignores root 🐞 Bug ≡ Correctness
Description
features::analyze_features(root) reads root/Cargo.toml but fetches cargo metadata via
get_cached_metadata_with_deps() which is not scoped to root and is cached globally. This can
produce incorrect/missing feature information when analyzing a different workspace path than the
current process directory.
Code

src/features.rs[R56-86]

+pub fn analyze_features(root: &Path) -> Result<FeatureAudit> {
+    let cargo_toml = get_cargo_toml_path(root);
+    if !cargo_toml.exists() {
+        return Ok(FeatureAudit::default());
+    }
+
+    let content = fs::read_to_string(&cargo_toml)?;
+    let parsed: toml::Value = toml::from_str(&content)?;
+
+    let metadata = get_cached_metadata_with_deps()?;
+    let known = known_feature_suggestions();
+
+    let mut suggestions = Vec::new();
+
+    let direct_deps = parsed
+        .get("dependencies")
+        .and_then(|d| d.as_table())
+        .map(|t| {
+            t.iter()
+                .map(|(k, _)| k.clone())
+                .collect::<Vec<_>>()
+        })
+        .unwrap_or_default();
+
+    for dep_name in &direct_deps {
+        let package = metadata.packages.iter().find(|p| p.name == *dep_name);
+        let package = match package {
+            Some(p) => p,
+            None => continue,
+        };
+
Evidence
analyze_features calls get_cached_metadata_with_deps() without passing root, while
get_cached_metadata_with_deps() executes cargo metadata without setting a working directory and
caches it globally, so the metadata may not correspond to the provided root.

src/features.rs[56-66]
src/utils.rs[31-38]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`analyze_features(root)` uses `get_cached_metadata_with_deps()` which runs `cargo metadata` without setting `current_dir` to `root`. Because metadata is cached globally, the audit can analyze the wrong workspace.

### Issue Context
`analyze_features` already takes a `root: &Path`, so it should use that consistently for both parsing Cargo.toml and running cargo metadata.

### Fix Focus Areas
- src/features.rs[56-86]
- src/utils.rs[31-38]

### Suggested fix
- Replace `get_cached_metadata_with_deps()` usage with a `cargo_metadata::MetadataCommand::new().current_dir(root).exec()?`.
- If caching is desired, cache by root path (keyed map) rather than a single global `OnceLock`.
- Add a test that uses a temp Cargo.toml with a dependency and verifies the metadata lookup is done relative to that temp root (or refactor to inject metadata for tests).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Timings load drops history 🐞 Bug ☼ Reliability
Description
TimingStore::load() uses serde_json::from_str(...).unwrap_or_default(), silently replacing
corrupted or schema-incompatible timing files with an empty store. This can erase all historical
timing data without any warning to the user.
Code

src/timings.rs[R28-36]

+impl TimingStore {
+    pub fn load(path: &Path) -> Result<Self> {
+        if path.exists() {
+            let content = fs::read_to_string(path)?;
+            Ok(serde_json::from_str(&content).unwrap_or_default())
+        } else {
+            Ok(Self::default())
+        }
+    }
Evidence
The implementation explicitly uses unwrap_or_default() on JSON parsing, which turns any parse
failure into an empty store instead of surfacing an error or preserving the data.

src/timings.rs[28-36]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`TimingStore::load()` silently falls back to a default (empty) store on parse errors, losing history.

### Issue Context
Timings are used for trend/regression/dashboard features; silent data loss makes these features unreliable.

### Fix Focus Areas
- src/timings.rs[28-36]

### Suggested fix
- On parse failure, return an error with context (preferred), or at least print a warning and preserve the original file (e.g., rename to `timings.json.bak`).
- Add `#[serde(default)]` to new/optional fields (e.g., `next_id`) so old files remain readable.
- Consider recomputing `next_id` as `max(id)+1` when loading if the stored value is missing/zero.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Trace runs extra build 🐞 Bug ➹ Performance
Description
When --collect-timings is enabled, trace runs an additional cargo build --timings=json after
already running cargo build during phase measurement, significantly increasing runtime and
mutating build artifacts. It also deletes target/cargo-timings on each run, which can disrupt
other tooling that relies on those files.
Code

src/tracer.rs[R131-152]

+fn collect_per_crate_timings(root: &Path) -> Result<Vec<PerCrateTiming>> {
+    // Run cargo build with --timings=json to get per-crate breakdown
+    let timings_dir = root.join("target").join("cargo-timings");
+    // Clean previous timings so we only parse the new one
+    if timings_dir.exists() {
+        let _ = fs::remove_dir_all(&timings_dir);
+    }
+
+    let status = Command::new("cargo")
+        .args(["build", "--timings=json"])
+        .current_dir(root)
+        .stdout(std::process::Stdio::null())
+        .stderr(std::process::Stdio::null())
+        .status()
+        .context("Failed to run cargo build --timings=json")?;
+
+    if !status.success() {
+        return Ok(Vec::new());
+    }
+
+    parse_timings_json_dir(&timings_dir)
+}
Evidence
measure_phases() runs cargo build, and enabling per-crate timings triggers another cargo build
plus a directory delete, directly increasing work and causing side effects.

src/tracer.rs[37-57]
src/tracer.rs[131-152]
src/tracer.rs[210-239]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`trace --collect-timings` runs a second cargo build solely to collect timings and deletes `target/cargo-timings` beforehand. This is expensive and introduces side effects.

### Issue Context
`measure_phases()` already executes `cargo build` (plus test/clippy). The per-crate timings collection should avoid duplicating that work where possible.

### Fix Focus Areas
- src/tracer.rs[37-57]
- src/tracer.rs[131-152]
- src/tracer.rs[210-239]

### Suggested fix
- Run a single `cargo build --timings=json` when per-crate timings are requested, and reuse that run for the phase timing (or skip the separate build phase).
- Avoid deleting `target/cargo-timings`; instead, parse the newest timings file or write to a dedicated/unique directory.
- If a second build is unavoidable, clearly warn the user that it will rebuild and mutate artifacts.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Per-crate JSON parsing fragile 🐞 Bug ≡ Correctness
Description
parse_timings_json_dir() parses each timings file line-by-line and attempts to deserialize each
line as a standalone JSON value, ignoring parse errors. If the timings output is a normal JSON
document (not JSONL), per-crate timing data will be missing and the dashboard will be incorrect.
Code

src/tracer.rs[R154-183]

+fn parse_timings_json_dir(dir: &Path) -> Result<Vec<PerCrateTiming>> {
+    if !dir.exists() {
+        return Ok(Vec::new());
+    }
+    let mut results = Vec::new();
+    let entries = fs::read_dir(dir)?;
+    for entry in entries {
+        let entry = entry?;
+        let path = entry.path();
+        if path.extension().and_then(|s| s.to_str()) == Some("json") {
+            let content = fs::read_to_string(&path)?;
+            for line in content.lines() {
+                if line.trim().is_empty() {
+                    continue;
+                }
+                if let Ok(val) = serde_json::from_str::<serde_json::Value>(line) {
+                    if val.get("event").and_then(|v| v.as_str()) == Some("compiler_artifact") {
+                        if let (Some(crate_name), Some(dur)) = (
+                            val.get("crate_name").and_then(|v| v.as_str()),
+                            val.get("duration").and_then(|v| v.as_f64()),
+                        ) {
+                            results.push(PerCrateTiming {
+                                crate_name: crate_name.to_string(),
+                                duration_ms: dur as u64,
+                            });
+                        }
+                    }
+                }
+            }
+        }
Evidence
The code reads the file then deserializes each line independently; any multi-line JSON object/array
will fail per-line parsing and be silently skipped, leading to missing results.

src/tracer.rs[154-199]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The per-crate timings parser assumes line-delimited JSON and ignores parse failures. This is brittle and can yield empty/incomplete results.

### Issue Context
The dashboard relies on `per_crate_data`; if parsing fails, users will see a fallback chart or incorrect breakdown.

### Fix Focus Areas
- src/tracer.rs[154-199]

### Suggested fix
- Parse the entire file content as JSON once (e.g., `serde_json::from_str(&content)`), then traverse the expected structure to extract crate durations.
- If multiple formats are possible, detect JSONL vs JSON document and support both.
- On parse failure, surface a warning that includes the file name and a short error summary so users know why per-crate data is missing.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
6. Parallel audit zero silently 🐞 Bug ☼ Reliability
Description
When codegen-units is unset and the default is deemed too high, check_parallel_build() prints
only an informational message but returns score = 0 without adding an issue, so the audit summary
can report fewer passed checks with no actionable reason. This makes the audit results misleading
and hard to interpret, especially when used in CI gating.
Code

src/build_audit.rs[R210-224]

        None => {
-            println!("  ✔ codegen-units not set (defaults to 256 in dev)");
-            score += 1;
+            let default_cu = 256i64;
+            if default_cu > overhead_threshold {
+                println!(
+                    "  ℹ  codegen-units defaults to 256 — {} CPU cores detected, suggest reducing to {} (4× {} CPUs) to avoid overhead",
+                    cpus, overhead_threshold, cpus
+                );
+            } else {
+                println!(
+                    "  ✔ codegen-units defaults to 256 (well-matched to {} CPU cores)",
+                    cpus
+                );
+                score += 1;
+            }
        }
Evidence
The audit summary reports passed checks based on the numeric score, but the default-codegen
informational branch does not increment the score or add an issue, creating a mismatch between pass
count and listed issues.

src/build_audit.rs[28-71]
src/build_audit.rs[161-241]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`check_parallel_build()` can return 0 in a scenario where it only prints ℹ output and adds no issue. The audit summary uses the numeric score as "checks passed", so this yields confusing results.

### Issue Context
`build_audit::run()` increments `passed` by the returned score and prints `issues` separately.

### Fix Focus Areas
- src/build_audit.rs[28-71]
- src/build_audit.rs[210-241]

### Suggested fix
- Decide whether the ℹ case is a pass or a fail:
 - If it’s informational, increment `score` (treat as pass).
 - If it’s a problem, push an issue explaining what to change.
- Alternatively, return a richer result type (pass/warn/fail) instead of overloading an integer score.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread src/cache.rs
Comment on lines +141 to +221
// 2. Check environment variables
let endpoint = std::env::var("SCCACHE_ENDPOINT").ok();
let bucket = std::env::var("SCCACHE_BUCKET").ok();
let region = std::env::var("SCCACHE_REGION").ok();
let dist_enabled = std::env::var("SCCACHE_DIST").ok();

println!("\n Environment:");
match &endpoint {
Some(v) => println!(" ✓ SCCACHE_ENDPOINT = {}", v.green()),
None => println!(" ✗ SCCACHE_ENDPOINT = {}", "not set".red()),
}
match &bucket {
Some(v) => println!(" ✓ SCCACHE_BUCKET = {}", v.green()),
None => println!(" ⚠ SCCACHE_BUCKET = {}", "not set (may not be needed)".yellow()),
}
match &region {
Some(v) => println!(" ✓ SCCACHE_REGION = {}", v.green()),
None => println!(" ⚠ SCCACHE_REGION = {}", "not set (may not be needed)".yellow()),
}
match &dist_enabled {
Some(v) if v == "true" || v == "1" => {
println!(" ✓ SCCACHE_DIST = {}", v.green());
}
Some(v) => {
println!(" ⚠ SCCACHE_DIST = {}", v.yellow());
println!(" Set SCCACHE_DIST=true to enable distributed caching.");
}
None => {
println!(" ⚠ SCCACHE_DIST = {}", "not set".yellow());
println!(" Set SCCACHE_DIST=true to enable distributed caching.");
}
}

// 3. Test connectivity
println!("\n Connectivity test:");
if endpoint.is_some() {
let start = std::time::Instant::now();
let output = std::process::Command::new("sccache")
.args(["--dist-status"])
.output();
let elapsed = start.elapsed();

match output {
Ok(out) => {
let stdout = String::from_utf8_lossy(&out.stdout);
let stderr = String::from_utf8_lossy(&out.stderr);
let combined = format!("{}{}", stdout, stderr);
let latency_ms = elapsed.as_millis();

if out.status.success() {
if combined.to_lowercase().contains("connected")
|| combined.to_lowercase().contains("ok")
|| combined.to_lowercase().contains("available")
{
println!(
" ✓ Remote cache {} (latency: {}ms)",
"reachable".green(),
latency_ms.to_string().cyan()
);
} else {
println!(
" ⚠ Remote cache responded but status unclear (latency: {}ms)",
latency_ms.to_string().cyan()
);
}
} else {
println!(
" ✗ Remote cache {} (latency: {}ms)",
"unreachable".red(),
latency_ms.to_string().cyan()
);
}

// Print any non-empty output
let trimmed = combined.trim();
if !trimmed.is_empty() {
println!("\n sccache --dist-status output:\n");
for line in trimmed.lines() {
println!(" {}", line.trim());
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Secrets logged in cache 🐞 Bug ⛨ Security

validate_remote_cache() prints SCCACHE_* environment variable values and echoes `sccache
--dist-status` output to stdout, which can leak internal endpoints/credentials into CI logs. This is
a security exposure when logs are persisted or publicly visible.
Agent Prompt
### Issue description
`validate_remote_cache()` prints potentially sensitive values (SCCACHE_ENDPOINT/BUCKET/REGION and command output) directly to stdout. In CI this can leak secrets or internal infrastructure details.

### Issue Context
This is a user-facing diagnostic command, but it is likely to be run in CI and the output ends up in logs.

### Fix Focus Areas
- src/cache.rs[141-221]

### Suggested fix
- Print only whether each env var is set, not the value (e.g., `SCCACHE_ENDPOINT = set`).
- If you still need values for troubleshooting, gate them behind an explicit `--verbose` / `--show-values` flag.
- Avoid printing full `sccache --dist-status` output by default; either summarize status or print only on verbose mode.
- Consider masking common secret patterns (URLs with credentials, tokens) if values must be shown.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/features.rs
Comment on lines +56 to +86
pub fn analyze_features(root: &Path) -> Result<FeatureAudit> {
let cargo_toml = get_cargo_toml_path(root);
if !cargo_toml.exists() {
return Ok(FeatureAudit::default());
}

let content = fs::read_to_string(&cargo_toml)?;
let parsed: toml::Value = toml::from_str(&content)?;

let metadata = get_cached_metadata_with_deps()?;
let known = known_feature_suggestions();

let mut suggestions = Vec::new();

let direct_deps = parsed
.get("dependencies")
.and_then(|d| d.as_table())
.map(|t| {
t.iter()
.map(|(k, _)| k.clone())
.collect::<Vec<_>>()
})
.unwrap_or_default();

for dep_name in &direct_deps {
let package = metadata.packages.iter().find(|p| p.name == *dep_name);
let package = match package {
Some(p) => p,
None => continue,
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Feature audit ignores root 🐞 Bug ≡ Correctness

features::analyze_features(root) reads root/Cargo.toml but fetches cargo metadata via
get_cached_metadata_with_deps() which is not scoped to root and is cached globally. This can
produce incorrect/missing feature information when analyzing a different workspace path than the
current process directory.
Agent Prompt
### Issue description
`analyze_features(root)` uses `get_cached_metadata_with_deps()` which runs `cargo metadata` without setting `current_dir` to `root`. Because metadata is cached globally, the audit can analyze the wrong workspace.

### Issue Context
`analyze_features` already takes a `root: &Path`, so it should use that consistently for both parsing Cargo.toml and running cargo metadata.

### Fix Focus Areas
- src/features.rs[56-86]
- src/utils.rs[31-38]

### Suggested fix
- Replace `get_cached_metadata_with_deps()` usage with a `cargo_metadata::MetadataCommand::new().current_dir(root).exec()?`.
- If caching is desired, cache by root path (keyed map) rather than a single global `OnceLock`.
- Add a test that uses a temp Cargo.toml with a dependency and verifies the metadata lookup is done relative to that temp root (or refactor to inject metadata for tests).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/timings.rs
Comment on lines +28 to +36
impl TimingStore {
pub fn load(path: &Path) -> Result<Self> {
if path.exists() {
let content = fs::read_to_string(path)?;
Ok(serde_json::from_str(&content).unwrap_or_default())
} else {
Ok(Self::default())
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. Timings load drops history 🐞 Bug ☼ Reliability

TimingStore::load() uses serde_json::from_str(...).unwrap_or_default(), silently replacing
corrupted or schema-incompatible timing files with an empty store. This can erase all historical
timing data without any warning to the user.
Agent Prompt
### Issue description
`TimingStore::load()` silently falls back to a default (empty) store on parse errors, losing history.

### Issue Context
Timings are used for trend/regression/dashboard features; silent data loss makes these features unreliable.

### Fix Focus Areas
- src/timings.rs[28-36]

### Suggested fix
- On parse failure, return an error with context (preferred), or at least print a warning and preserve the original file (e.g., rename to `timings.json.bak`).
- Add `#[serde(default)]` to new/optional fields (e.g., `next_id`) so old files remain readable.
- Consider recomputing `next_id` as `max(id)+1` when loading if the stored value is missing/zero.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/tracer.rs
Comment on lines +131 to +152
fn collect_per_crate_timings(root: &Path) -> Result<Vec<PerCrateTiming>> {
// Run cargo build with --timings=json to get per-crate breakdown
let timings_dir = root.join("target").join("cargo-timings");
// Clean previous timings so we only parse the new one
if timings_dir.exists() {
let _ = fs::remove_dir_all(&timings_dir);
}

let status = Command::new("cargo")
.args(["build", "--timings=json"])
.current_dir(root)
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.context("Failed to run cargo build --timings=json")?;

if !status.success() {
return Ok(Vec::new());
}

parse_timings_json_dir(&timings_dir)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

4. Trace runs extra build 🐞 Bug ➹ Performance

When --collect-timings is enabled, trace runs an additional cargo build --timings=json after
already running cargo build during phase measurement, significantly increasing runtime and
mutating build artifacts. It also deletes target/cargo-timings on each run, which can disrupt
other tooling that relies on those files.
Agent Prompt
### Issue description
`trace --collect-timings` runs a second cargo build solely to collect timings and deletes `target/cargo-timings` beforehand. This is expensive and introduces side effects.

### Issue Context
`measure_phases()` already executes `cargo build` (plus test/clippy). The per-crate timings collection should avoid duplicating that work where possible.

### Fix Focus Areas
- src/tracer.rs[37-57]
- src/tracer.rs[131-152]
- src/tracer.rs[210-239]

### Suggested fix
- Run a single `cargo build --timings=json` when per-crate timings are requested, and reuse that run for the phase timing (or skip the separate build phase).
- Avoid deleting `target/cargo-timings`; instead, parse the newest timings file or write to a dedicated/unique directory.
- If a second build is unavoidable, clearly warn the user that it will rebuild and mutate artifacts.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/tracer.rs
Comment on lines +154 to +183
fn parse_timings_json_dir(dir: &Path) -> Result<Vec<PerCrateTiming>> {
if !dir.exists() {
return Ok(Vec::new());
}
let mut results = Vec::new();
let entries = fs::read_dir(dir)?;
for entry in entries {
let entry = entry?;
let path = entry.path();
if path.extension().and_then(|s| s.to_str()) == Some("json") {
let content = fs::read_to_string(&path)?;
for line in content.lines() {
if line.trim().is_empty() {
continue;
}
if let Ok(val) = serde_json::from_str::<serde_json::Value>(line) {
if val.get("event").and_then(|v| v.as_str()) == Some("compiler_artifact") {
if let (Some(crate_name), Some(dur)) = (
val.get("crate_name").and_then(|v| v.as_str()),
val.get("duration").and_then(|v| v.as_f64()),
) {
results.push(PerCrateTiming {
crate_name: crate_name.to_string(),
duration_ms: dur as u64,
});
}
}
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

5. Per-crate json parsing fragile 🐞 Bug ≡ Correctness

parse_timings_json_dir() parses each timings file line-by-line and attempts to deserialize each
line as a standalone JSON value, ignoring parse errors. If the timings output is a normal JSON
document (not JSONL), per-crate timing data will be missing and the dashboard will be incorrect.
Agent Prompt
### Issue description
The per-crate timings parser assumes line-delimited JSON and ignores parse failures. This is brittle and can yield empty/incomplete results.

### Issue Context
The dashboard relies on `per_crate_data`; if parsing fails, users will see a fallback chart or incorrect breakdown.

### Fix Focus Areas
- src/tracer.rs[154-199]

### Suggested fix
- Parse the entire file content as JSON once (e.g., `serde_json::from_str(&content)`), then traverse the expected structure to extract crate durations.
- If multiple formats are possible, detect JSONL vs JSON document and support both.
- On parse failure, surface a warning that includes the file name and a short error summary so users know why per-crate data is missing.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/build_audit.rs
Comment on lines 210 to 224
None => {
println!(" ✔ codegen-units not set (defaults to 256 in dev)");
score += 1;
let default_cu = 256i64;
if default_cu > overhead_threshold {
println!(
" ℹ codegen-units defaults to 256 — {} CPU cores detected, suggest reducing to {} (4× {} CPUs) to avoid overhead",
cpus, overhead_threshold, cpus
);
} else {
println!(
" ✔ codegen-units defaults to 256 (well-matched to {} CPU cores)",
cpus
);
score += 1;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

6. Parallel audit zero silently 🐞 Bug ☼ Reliability

When codegen-units is unset and the default is deemed too high, check_parallel_build() prints
only an informational message but returns score = 0 without adding an issue, so the audit summary
can report fewer passed checks with no actionable reason. This makes the audit results misleading
and hard to interpret, especially when used in CI gating.
Agent Prompt
### Issue description
`check_parallel_build()` can return 0 in a scenario where it only prints ℹ output and adds no issue. The audit summary uses the numeric score as "checks passed", so this yields confusing results.

### Issue Context
`build_audit::run()` increments `passed` by the returned score and prints `issues` separately.

### Fix Focus Areas
- src/build_audit.rs[28-71]
- src/build_audit.rs[210-241]

### Suggested fix
- Decide whether the ℹ case is a pass or a fail:
  - If it’s informational, increment `score` (treat as pass).
  - If it’s a problem, push an issue explaining what to change.
- Alternatively, return a richer result type (pass/warn/fail) instead of overloading an integer score.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/regression.rs (1)

46-74: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Record timings when no baseline exists too.

The new store is only saved through compare_with_baseline; a first regression --save or any no-baseline regression run measures stats but never writes those timings to the unified store.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/regression.rs` around lines 46 - 74, Record the measured timings in the
unified store even when there is no baseline to compare against. In `run` within
`regression.rs`, after `measure_current_builds` and any budget reporting, make
sure the `TimingStore` is updated and saved for the no-baseline path as well,
not only through `compare_with_baseline`; use the existing `store` and
`store_path` flow so `--save` and first-run regressions persist `stats`
consistently.
🟡 Minor comments (10)
src/ci.rs-252-266 (1)

252-266: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Don’t claim budget-only CI will fail.

build_workflow(false, Some(_)) keeps continue-on-error: true, but the summary always says “CI will fail on timeout” whenever a budget is set.

Proposed fix
         if let Some(budget) = opts.budget {
             println!(
-                "  {} Regression budget set to {}s — CI will fail on timeout",
+                "  {} Regression budget set to {}s — {}",
                 "✓".green(),
-                budget.to_string().cyan()
+                budget.to_string().cyan(),
+                if opts.enforce_policy {
+                    "CI will fail on timeout"
+                } else {
+                    "CI will report regressions without failing"
+                }
             );
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ci.rs` around lines 252 - 266, The CI summary in
print_enforcement_summary is overclaiming failure behavior when only a budget is
set. Update the budget message to distinguish between opts.enforce_policy and
budget-only runs, so “CI will fail on timeout” is shown only when policy
enforcement is enabled; otherwise describe the budget as reporting/recording
timeouts without failing. Use the existing CiOptions fields and the
print_enforcement_summary function to gate the wording appropriately.
src/cache.rs-489-520 (1)

489-520: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Serialize and restore the SCCACHE_* env mutations in these tests. They mutate process-wide state and then remove it unconditionally, which can race with parallel tests or clobber pre-existing values. Use a shared test lock/serial helper and restore the previous values with RAII.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cache.rs` around lines 489 - 520, These tests mutate process-wide
SCCACHE_* environment state in test_validate_remote_cache_with_env_vars and
test_validate_remote_cache_without_dist, then unconditionally remove values,
which can interfere with parallel tests or overwrite existing settings. Guard
the tests with a shared serial/test lock and use RAII to save the prior values
before set_var, then restore each variable’s original state after
validate_remote_cache() completes.
src/cli.rs-51-53 (1)

51-53: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject non-positive or non-finite CI budgets.

--budget represents seconds, but the CLI currently accepts values like 0, negative numbers, or non-finite floats, which can generate unusable enforcement settings.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli.rs` around lines 51 - 53, The CLI budget option in the `budget` field
currently accepts invalid seconds values, including zero, negatives, and
non-finite floats. Add validation in `src/cli.rs` for the `budget: Option<f64>`
argument (or a dedicated parser/helper used by the CLI) so only positive, finite
values are accepted, and reject invalid inputs with a clear error before they
reach downstream enforcement logic.
src/timings.rs-120-142 (1)

120-142: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Treat failed git commands as unknown.

When git rev-parse exits non-zero, output() still returns Some, so non-git workspaces can store an empty branch/commit instead of unknown.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/timings.rs` around lines 120 - 142, Treat failed git lookups as unknown
in get_git_branch and get_git_commit_hash: right now Command::output().ok() only
handles process launch failures, so non-zero exits from git rev-parse can still
produce empty strings. Update the logic in these functions to inspect the
Command output status and only return the trimmed stdout when the command
succeeds; otherwise fall back to "unknown" for both branch and commit hash.
src/tracer.rs-51-54 (1)

51-54: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Surface per-crate collection failures when explicitly requested.

unwrap_or_default() hides I/O/toolchain failures, so users get an empty fallback chart with no explanation after passing --collect-timings.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tracer.rs` around lines 51 - 54, The per-crate timing collection in
tracer::trace currently swallows failures with unwrap_or_default(), which hides
errors when collect_per_crate is enabled. Update the collect_per_crate branch to
handle the result from collect_per_crate_timings(&root) explicitly, surfacing
any I/O or toolchain error to the caller instead of silently falling back, and
keep the existing default-only behavior for the non-collection path.
src/tracer.rs-445-445 (1)

445-445: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix the invalid command in the empty-trend hint.

benchmark --save is not defined in the provided CLI; this message sends users to a command that will fail. Use cargo accelerate benchmark or cargo accelerate trend.

Proposed fix
-    document.getElementById('trend').innerHTML = '<p class="note">No historical timing data found. Run `cargo accelerate benchmark --save` or `cargo accelerate trend` to start collecting.</p>';
+    document.getElementById('trend').innerHTML = '<p class="note">No historical timing data found. Run `cargo accelerate benchmark` or `cargo accelerate trend` to start collecting.</p>';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tracer.rs` at line 445, The empty-trend hint in the tracer UI points
users to an invalid command, so update the message in the trend rendering path
to reference only supported commands. In the code that sets the `trend`
element’s `innerHTML`, replace the `cargo accelerate benchmark --save`
suggestion with a valid `cargo accelerate benchmark` or `cargo accelerate trend`
invocation, keeping the rest of the hint text unchanged.
src/utils.rs-81-82 (1)

81-82: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove the machine-size upper bound from the test.

Large CI or build hosts can legitimately expose 1024+ CPUs/threads, making this test fail despite available_cpus() working correctly.

Proposed fix
     fn test_available_cpus_returns_positive() {
         let cpus = available_cpus();
         assert!(cpus >= 1);
-        // Sanity check: unlikely to have more than 1024 CPUs
-        assert!(cpus < 1024);
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils.rs` around lines 81 - 82, The test in available_cpus() currently
hard-codes an upper-bound sanity check that asserts cpus is below 1024, which
can fail on large CI/build hosts. Remove that machine-size limit from the test
and keep only the assertions that validate the actual behavior of
available_cpus(), using the available_cpus() test block or its surrounding
assertion logic to locate it.
src/timings.rs-88-99 (1)

88-99: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Return the true median for even sample counts.

For an even number of timings, this returns the upper middle value instead of averaging the two middle values.

Proposed fix
         }
         times.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
-        Some(times[times.len() / 2])
+        let mid = times.len() / 2;
+        if times.len() % 2 == 0 {
+            Some((times[mid - 1] + times[mid]) / 2.0)
+        } else {
+            Some(times[mid])
+        }
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/timings.rs` around lines 88 - 99, The median_duration_ms method in
Timings currently returns the upper middle value for even-sized samples instead
of the true median. Update the median calculation logic after sorting the
filtered times so that when the count is even, it averages the two middle
values; keep the existing None behavior for empty input. Use the
median_duration_ms function and its times vector as the place to make the
change.
plan.md-115-134 (1)

115-134: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Gap analysis describes issues this same PR already resolves.

This section (and the technical-debt table entry at line 329) states timings.rs is empty/missing persistent storage as a current gap, but this PR stack implements the timing store elsewhere (src/timings.rs). If this document is meant as a forward-looking roadmap rather than a historical snapshot, consider adding a note clarifying which items are already implemented by this PR to avoid confusing future readers.

Also applies to: 329-329

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plan.md` around lines 115 - 134, Clarify that the “Missing Performance Data
Collection Layer” gap is already addressed by this PR so the roadmap does not
contradict the codebase. Update the relevant plan section and the technical-debt
table entry to mark the `timings.rs`/`src/timings.rs` storage work as
implemented or add an explicit note that the item is historical/outdated,
referencing the `timings.rs` and `regression.rs` items so future readers
understand what remains versus what this PR already delivers.
plan.md-1-1 (1)

1-1: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove leftover AI-assistant preamble from committed doc.

Line 1 reads as raw assistant chat output ("I'll help you analyze the repository...Now let me explore...") rather than document content. Trim it before merging as project documentation.

✏️ Proposed fix
-I'll help you analyze the repository and create an improvement plan for a high-performance build system for Rust codebases. Let me start by gathering comprehensive information about the repository.Now let me explore the source directory structure and key files:Now I have a comprehensive view of the repository. Let me create a detailed improvement plan document.
-
 ---
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plan.md` at line 1, The document in plan.md contains leftover AI-assistant
preamble instead of the intended plan content. Remove the conversational intro
text from the start of the document and keep only the actual repository
improvement plan, ensuring the final committed text reads like normal
documentation.
🧹 Nitpick comments (6)
src/features.rs (1)

25-28: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use deterministic ordering for persisted suggestions.

HashMap serialization can reorder features.toml between runs, causing noisy diffs. BTreeMap keeps the generated config stable with a small local change.

Proposed refactor
-use std::collections::HashMap;
+use std::collections::{BTreeMap, HashMap};
...
 pub struct FeaturesConfig {
-    pub suggestions: HashMap<String, Vec<String>>,
+    pub suggestions: BTreeMap<String, Vec<String>>,
 }
...
     let mut config = FeaturesConfig {
-        suggestions: HashMap::new(),
+        suggestions: BTreeMap::new(),
     };

Also applies to: 169-181

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features.rs` around lines 25 - 28, Persisted suggestions use HashMap,
which can serialize in non-deterministic order and churn the generated config.
Update FeaturesConfig and the other matching suggestions type at the referenced
struct declaration to use BTreeMap instead, keeping serialization stable while
preserving the same data shape. Make the change in the relevant features config
types and adjust any construction sites or imports that currently assume
HashMap.
src/graph.rs (1)

394-430: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Keep the workspace package reference instead of re-looking it up by name.

find_workspace_member_dirs already filters exact workspace packages, but Line 426 re-searches all metadata packages by name. Package names are not as safe as package identity across a full metadata graph, so this can associate the directory with the wrong package data when names collide.

Suggested refactor
 fn find_workspace_member_dirs<'a>(
     metadata: &'a cargo_metadata::Metadata,
-) -> Vec<(&'a str, &'a Path)> {
+) -> Vec<(&'a cargo_metadata::Package, &'a Path)> {
     metadata
         .packages
         .iter()
         .filter(|p| metadata.workspace_members.contains(&p.id))
         .filter_map(|p| {
             let manifest = Path::new(&p.manifest_path);
             let dir = manifest.parent()?;
-            Some((p.name.as_str(), dir))
+            Some((p, dir))
         })
         .collect()
 }
 
@@
-    for (name, dir) in &member_dirs {
+    for (package, dir) in member_dirs {
+        let name = package.name.as_str();
         let loc = crate::workspace::count_rust_loc(dir).unwrap_or(0);
-        let package = metadata
-            .packages
-            .iter()
-            .find(|p| p.name.as_str() == *name)
-            .unwrap();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/graph.rs` around lines 394 - 430, The workspace member lookup in
suggest_crate_splits is re-finding a package by name even though
find_workspace_member_dirs already selected the exact workspace package, which
can mismatch metadata when names collide. Update the flow to carry the package
identity through from find_workspace_member_dirs and reuse that package
reference directly in suggest_crate_splits instead of calling iter().find(...)
on metadata.packages. Keep the fix localized around find_workspace_member_dirs
and suggest_crate_splits so the directory is always paired with the correct
package data.
src/profile.rs (1)

1-1: 🚀 Performance & Scalability | 🔵 Trivial

CPU detection may be inaccurate inside containers/CI runners.

available_cpus() relies on std::thread::available_parallelism(), which per Rust's docs can overcount available parallelism in VMs/containers with CPU limits, and cgroup-based quota support has known gaps (e.g., cgroup v1 environments). Since this value now directly drives codegen-units written into Cargo.toml for Dev/Test profiles via apply_profile, a containerized CI runner reporting the host's full core count rather than its actual quota could produce an oversized codegen-units recommendation.

Worth keeping in mind if this heuristic is later extended to CI-generated profiles (Scenario::Ci).

Also applies to: 38-51

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/profile.rs` at line 1, The CPU-count heuristic used by apply_profile via
available_cpus() can overestimate cores in containers/CI and lead to an
oversized codegen-units value. Update the profile logic in profile.rs so
apply_profile does not rely solely on available_parallelism-derived counts for
Dev/Test; instead add a container/CI-aware fallback or cap based on
quota-limited environments, and keep the behavior localized around
available_cpus and apply_profile so future Scenario::Ci support can reuse the
safer detection.
src/cli.rs (1)

92-106: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add parser coverage for the new timing flags.

The new Timings command and the positive trace --collect-timings path are not asserted in the parsing tests, so regressions in those CLI contracts could slip through.

Also applies to: 490-517, 598-619

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli.rs` around lines 92 - 106, Add parser test coverage for the new CLI
contracts by extending the existing argument parsing tests around the
Cli/Commands enum to assert the Timings subcommand parses with its command and
last flags, and that the trace command accepts the positive --collect-timings
path. Use the Cli parser entrypoint and the Timings and trace/collect_timings
symbols so the new behavior is locked in and future regressions are caught.
scripts/install_rust (2)

19-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate install/source logic between the two branches.

Lines 20-28 and 30-38 are identical except for the log message. Extract into a shared function to avoid drift if one branch is updated without the other.

♻️ Proposed refactor
+install_via_rustup() {
+  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh $CI_FLAGS
+  CARGO_ENV_FILE="$HOME/.cargo/env"
+  if [[ -f "$CARGO_ENV_FILE" ]]; then
+    source "$CARGO_ENV_FILE"
+  else
+    echo -e "⚠️  ${red}Please start a new terminal session so that cargo is in your PATH.${reset}"
+    exit 1
+  fi
+}
+
 if ! command -v cargo; then
   echo "⬇️  Installing rust..."
-  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh $CI_FLAGS
-  CARGO_ENV_FILE="$HOME/.cargo/env"
-  if [[ -f "$CARGO_ENV_FILE" ]]; then
-    source "$CARGO_ENV_FILE"
-  else
-    echo -e "⚠️  ${red}Please start a new terminal session so that cargo is in your PATH.${reset}"
-    exit 1
-  fi
+  install_via_rustup
 elif [[ ! -f "$HOME/.cargo/bin/cargo" ]]; then
   echo "⬇️  Cargo binary not found, reinstalling Rust..."
-  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh $CI_FLAGS
-  CARGO_ENV_FILE="$HOME/.cargo/env"
-  if [[ -f "$CARGO_ENV_FILE" ]]; then
-    source "$CARGO_ENV_FILE"
-  else
-    echo -e "⚠️  ${red}Please start a new terminal session so that cargo is in your PATH.${reset}"
-    exit 1
-  fi
+  install_via_rustup
 fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/install_rust` around lines 19 - 39, The Rust install script has
duplicated install-and-source logic in the `if ! command -v cargo` and `elif [[
! -f "$HOME/.cargo/bin/cargo" ]]` branches, which can drift over time. Extract
the shared `curl`/`rustup` install, `CARGO_ENV_FILE` sourcing, and failure
handling into a single helper/function in `scripts/install_rust`, then have both
branches call it while keeping their specific log messages.

7-7: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider set -o pipefail alongside set -e.

Without pipefail, a failed curl in the curl | sh pipelines (lines 21, 31) won't necessarily trigger set -e since only sh's exit status is checked.

🔧 Proposed fix
-set -e
+set -eo pipefail
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/install_rust` at line 7, The script currently relies on set -e in
install_rust, but the curl | sh pipelines can still hide curl failures because
pipe exit status is not fully checked. Update the shell options near the top of
the script to include pipefail alongside set -e so failures in the curl steps
are propagated correctly; the relevant locations are the script’s top-level
setup and the pipeline invocations in install_rust.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cache.rs`:
- Around line 190-212: The remote cache status check in the connectivity summary
is treating a failed `sccache --dist-status` as only a warning, so the final
“configuration looks complete” message can still appear. Update the logic around
the `out.status.success()` branch in the cache status function so a non-zero
status records connectivity failure and prevents the overall summary from
reporting success; use the existing remote-cache status handling path (the same
block that prints reachable/unreachable) to propagate failure into the final
result, including the related summary path mentioned by the duplicate section.
- Around line 176-180: The sccache remote probe in the cache validation path can
block indefinitely when the scheduler is unreachable. Update the logic around
the `sccache --dist-status` call in the cache module to run with a timeout, and
handle timeout or process-hang cases gracefully by treating the probe as failed
instead of waiting forever. Use the existing endpoint check and the
`Command::new("sccache")` probe location to bound the execution and keep
`validate-remote` from hanging.

In `@src/ci.rs`:
- Around line 104-105: The audit workflow/templates are invoking a `--fail-fast`
flag that the audit CLI does not currently support, so update the generated
`Validate Build Policy` command and related hook/test references to stop passing
that option unless `main.rs`/audit routing actually implements it. Locate the
`audit` command handling in `src/main.rs` and the template generation in
`src/ci.rs`, then either add real `--fail-fast` support end-to-end or remove the
flag consistently from all generated workflow and pre-commit outputs.
- Around line 146-159: `run` is passing `CiOptions.budget` straight into
`build_workflow`, so invalid values can generate broken CI commands. Add
validation in `run` before the workflow is built: require `budget` to be finite
and greater than zero, and reject `0`, negative, `NaN`, or infinite inputs with
an error. If the same budget formatting is used elsewhere, apply the same guard
at the other `build_workflow` call site too so all workflow generation paths are
protected.

In `@src/features.rs`:
- Around line 56-78: The analyze_features path only reads the root Cargo.toml
and inspects its [dependencies], so workspace member manifests are missed and
workspaces can incorrectly report no dependencies. Update analyze_features to
use the metadata from get_cached_metadata_with_deps and iterate workspace member
manifest paths from metadata.workspace_members (or otherwise include
[workspace.dependencies]) so dependency collection is done from member
Cargo.toml files, while keeping the existing analyze_features and
known_feature_suggestions flow intact.
- Around line 229-235: The optimization logic in features.rs currently
overwrites any existing explicit features on table and inline-table dependencies
instead of preserving them. Update the dependency rewrite path that handles
dep.as_table_mut() and dep.as_inline_table_mut() to merge the current features
list with suggestion.recommended_features, de-duplicating the combined set, or
leave dependencies unchanged when features are already explicitly declared. Keep
the existing default-features handling, and make the change in the feature
optimization flow so --optimize does not drop user-specified features.

In `@src/graph.rs`:
- Line 425: The LoC scan in graph::build_split_candidates currently swallows
failures by using unwrap_or(0), which can write an incorrect splits.toml with
missing candidates. Update the count_rust_loc call site to propagate the error
instead of defaulting to zero, and add context that makes clear the failure
happened while scanning the workspace directory. Keep the fix localized around
the loc calculation in the split-candidate generation flow so the caller can
handle the error properly.

In `@src/timings.rs`:
- Around line 48-50: The public Timings::record method adds an externally
created BuildRun but does not advance next_id, so later
Timings::record_build_run calls can reuse an existing ID. Update record to
inspect the incoming run’s id and keep next_id in sync by setting it to one past
the highest recorded id, matching the behavior used by record_build_run and
preserving unique IDs for all future runs.
- Around line 29-32: The load logic in timings::load currently hides serde_json
parse failures by falling back to an empty store, which can overwrite existing
timings; change it to return the parse error with context instead of using
unwrap_or_default(), and after a successful deserialize, validate or recompute
the TimingStore next_id before returning so the loaded state stays consistent.
- Around line 220-222: The branch truncation in the timing logic uses byte
slicing, which can panic on UTF-8 boundaries. Update the branch handling in the
`timings.rs` logic around the `branch` assignment to truncate by characters
instead of bytes, using the existing `run.branch` value safely. Keep the same
behavior for short branch names, but for long ones derive the shortened string
from `chars()` so the `branch` variable is always valid UTF-8.

In `@src/tracer.rs`:
- Around line 564-566: Serialize the trend trace in tracer.rs instead of
interpolating cmd directly into the JSON string, since the current format string
in the trace-building code can inject unescaped command names into the dashboard
script. Update the trace creation logic around the scatter plot builder to
construct the payload with serde_json, following the same pattern used by the
other chart helpers, and ensure cmd is serialized as a JSON string rather than
concatenated into raw JavaScript.
- Around line 139-151: The timing collection in `parse_timings_json_dir` is
using `cargo build --timings=json`, which is no longer supported and won’t
produce the expected artifacts. Update the `Command::new("cargo")` invocation to
use a supported timing source such as `--timings` or `-Zbuild-analysis`, and
make sure failures are surfaced instead of silently returning `Ok(Vec::new())`
so the caller can see the error when `status.success()` is false.

In `@src/trend.rs`:
- Around line 97-104: The build trend recording in trend currently saves timings
even when cargo check or cargo build exits non-zero, because measure_cmd returns
a duration on failure. Update measure_cmd to return an error when the command
status is unsuccessful, and let the callers in trend skip
timings::record_build_run and store.save unless both measurements succeed. Use
the measure_cmd function and the build/check calls in trend as the fix points.

---

Outside diff comments:
In `@src/regression.rs`:
- Around line 46-74: Record the measured timings in the unified store even when
there is no baseline to compare against. In `run` within `regression.rs`, after
`measure_current_builds` and any budget reporting, make sure the `TimingStore`
is updated and saved for the no-baseline path as well, not only through
`compare_with_baseline`; use the existing `store` and `store_path` flow so
`--save` and first-run regressions persist `stats` consistently.

---

Minor comments:
In `@plan.md`:
- Around line 115-134: Clarify that the “Missing Performance Data Collection
Layer” gap is already addressed by this PR so the roadmap does not contradict
the codebase. Update the relevant plan section and the technical-debt table
entry to mark the `timings.rs`/`src/timings.rs` storage work as implemented or
add an explicit note that the item is historical/outdated, referencing the
`timings.rs` and `regression.rs` items so future readers understand what remains
versus what this PR already delivers.
- Line 1: The document in plan.md contains leftover AI-assistant preamble
instead of the intended plan content. Remove the conversational intro text from
the start of the document and keep only the actual repository improvement plan,
ensuring the final committed text reads like normal documentation.

In `@src/cache.rs`:
- Around line 489-520: These tests mutate process-wide SCCACHE_* environment
state in test_validate_remote_cache_with_env_vars and
test_validate_remote_cache_without_dist, then unconditionally remove values,
which can interfere with parallel tests or overwrite existing settings. Guard
the tests with a shared serial/test lock and use RAII to save the prior values
before set_var, then restore each variable’s original state after
validate_remote_cache() completes.

In `@src/ci.rs`:
- Around line 252-266: The CI summary in print_enforcement_summary is
overclaiming failure behavior when only a budget is set. Update the budget
message to distinguish between opts.enforce_policy and budget-only runs, so “CI
will fail on timeout” is shown only when policy enforcement is enabled;
otherwise describe the budget as reporting/recording timeouts without failing.
Use the existing CiOptions fields and the print_enforcement_summary function to
gate the wording appropriately.

In `@src/cli.rs`:
- Around line 51-53: The CLI budget option in the `budget` field currently
accepts invalid seconds values, including zero, negatives, and non-finite
floats. Add validation in `src/cli.rs` for the `budget: Option<f64>` argument
(or a dedicated parser/helper used by the CLI) so only positive, finite values
are accepted, and reject invalid inputs with a clear error before they reach
downstream enforcement logic.

In `@src/timings.rs`:
- Around line 120-142: Treat failed git lookups as unknown in get_git_branch and
get_git_commit_hash: right now Command::output().ok() only handles process
launch failures, so non-zero exits from git rev-parse can still produce empty
strings. Update the logic in these functions to inspect the Command output
status and only return the trimmed stdout when the command succeeds; otherwise
fall back to "unknown" for both branch and commit hash.
- Around line 88-99: The median_duration_ms method in Timings currently returns
the upper middle value for even-sized samples instead of the true median. Update
the median calculation logic after sorting the filtered times so that when the
count is even, it averages the two middle values; keep the existing None
behavior for empty input. Use the median_duration_ms function and its times
vector as the place to make the change.

In `@src/tracer.rs`:
- Around line 51-54: The per-crate timing collection in tracer::trace currently
swallows failures with unwrap_or_default(), which hides errors when
collect_per_crate is enabled. Update the collect_per_crate branch to handle the
result from collect_per_crate_timings(&root) explicitly, surfacing any I/O or
toolchain error to the caller instead of silently falling back, and keep the
existing default-only behavior for the non-collection path.
- Line 445: The empty-trend hint in the tracer UI points users to an invalid
command, so update the message in the trend rendering path to reference only
supported commands. In the code that sets the `trend` element’s `innerHTML`,
replace the `cargo accelerate benchmark --save` suggestion with a valid `cargo
accelerate benchmark` or `cargo accelerate trend` invocation, keeping the rest
of the hint text unchanged.

In `@src/utils.rs`:
- Around line 81-82: The test in available_cpus() currently hard-codes an
upper-bound sanity check that asserts cpus is below 1024, which can fail on
large CI/build hosts. Remove that machine-size limit from the test and keep only
the assertions that validate the actual behavior of available_cpus(), using the
available_cpus() test block or its surrounding assertion logic to locate it.

---

Nitpick comments:
In `@scripts/install_rust`:
- Around line 19-39: The Rust install script has duplicated install-and-source
logic in the `if ! command -v cargo` and `elif [[ ! -f "$HOME/.cargo/bin/cargo"
]]` branches, which can drift over time. Extract the shared `curl`/`rustup`
install, `CARGO_ENV_FILE` sourcing, and failure handling into a single
helper/function in `scripts/install_rust`, then have both branches call it while
keeping their specific log messages.
- Line 7: The script currently relies on set -e in install_rust, but the curl |
sh pipelines can still hide curl failures because pipe exit status is not fully
checked. Update the shell options near the top of the script to include pipefail
alongside set -e so failures in the curl steps are propagated correctly; the
relevant locations are the script’s top-level setup and the pipeline invocations
in install_rust.

In `@src/cli.rs`:
- Around line 92-106: Add parser test coverage for the new CLI contracts by
extending the existing argument parsing tests around the Cli/Commands enum to
assert the Timings subcommand parses with its command and last flags, and that
the trace command accepts the positive --collect-timings path. Use the Cli
parser entrypoint and the Timings and trace/collect_timings symbols so the new
behavior is locked in and future regressions are caught.

In `@src/features.rs`:
- Around line 25-28: Persisted suggestions use HashMap, which can serialize in
non-deterministic order and churn the generated config. Update FeaturesConfig
and the other matching suggestions type at the referenced struct declaration to
use BTreeMap instead, keeping serialization stable while preserving the same
data shape. Make the change in the relevant features config types and adjust any
construction sites or imports that currently assume HashMap.

In `@src/graph.rs`:
- Around line 394-430: The workspace member lookup in suggest_crate_splits is
re-finding a package by name even though find_workspace_member_dirs already
selected the exact workspace package, which can mismatch metadata when names
collide. Update the flow to carry the package identity through from
find_workspace_member_dirs and reuse that package reference directly in
suggest_crate_splits instead of calling iter().find(...) on metadata.packages.
Keep the fix localized around find_workspace_member_dirs and
suggest_crate_splits so the directory is always paired with the correct package
data.

In `@src/profile.rs`:
- Line 1: The CPU-count heuristic used by apply_profile via available_cpus() can
overestimate cores in containers/CI and lead to an oversized codegen-units
value. Update the profile logic in profile.rs so apply_profile does not rely
solely on available_parallelism-derived counts for Dev/Test; instead add a
container/CI-aware fallback or cap based on quota-limited environments, and keep
the behavior localized around available_cpus and apply_profile so future
Scenario::Ci support can reuse the safer detection.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cfdfcd11-c81b-4895-a5b9-ec1418e85d3b

📥 Commits

Reviewing files that changed from the base of the PR and between 09841ed and 290e066.

📒 Files selected for processing (20)
  • README.md
  • plan.md
  • scripts/install_rust
  • src/benchmark.rs
  • src/build_audit.rs
  • src/cache.rs
  • src/ci.rs
  • src/cli.rs
  • src/doctor.rs
  • src/features.rs
  • src/graph.rs
  • src/main.rs
  • src/optimizer.rs
  • src/profile.rs
  • src/regression.rs
  • src/timings.rs
  • src/tracer.rs
  • src/trend.rs
  • src/utils.rs
  • src/workspace.rs

Comment thread src/cache.rs
Comment on lines +176 to +180
if endpoint.is_some() {
let start = std::time::Instant::now();
let output = std::process::Command::new("sccache")
.args(["--dist-status"])
.output();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Bound the sccache --dist-status probe with a timeout.

When SCCACHE_ENDPOINT is set, this external command can block indefinitely on an unreachable scheduler, hanging cargo accelerate cache validate-remote or CI automation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cache.rs` around lines 176 - 180, The sccache remote probe in the cache
validation path can block indefinitely when the scheduler is unreachable. Update
the logic around the `sccache --dist-status` call in the cache module to run
with a timeout, and handle timeout or process-hang cases gracefully by treating
the probe as failed instead of waiting forever. Use the existing endpoint check
and the `Command::new("sccache")` probe location to bound the execution and keep
`validate-remote` from hanging.

Comment thread src/cache.rs
Comment on lines +190 to +212
if out.status.success() {
if combined.to_lowercase().contains("connected")
|| combined.to_lowercase().contains("ok")
|| combined.to_lowercase().contains("available")
{
println!(
" ✓ Remote cache {} (latency: {}ms)",
"reachable".green(),
latency_ms.to_string().cyan()
);
} else {
println!(
" ⚠ Remote cache responded but status unclear (latency: {}ms)",
latency_ms.to_string().cyan()
);
}
} else {
println!(
" ✗ Remote cache {} (latency: {}ms)",
"unreachable".red(),
latency_ms.to_string().cyan()
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Include failed connectivity in the final summary.

If sccache --dist-status exits non-zero, the function prints “unreachable” but can still print “Remote cache configuration looks complete” when the env vars are set.

Proposed fix
     println!("\n  Connectivity test:");
+    let mut remote_reachable = None;
     if endpoint.is_some() {
         let start = std::time::Instant::now();
         let output = std::process::Command::new("sccache")
@@
                 if out.status.success() {
+                    remote_reachable = Some(true);
                     if combined.to_lowercase().contains("connected")
@@
                 } else {
+                    remote_reachable = Some(false);
                     println!(
@@
             Err(e) => {
+                remote_reachable = Some(false);
                 println!(
@@
     let all_set = sccache_available
         && endpoint.is_some()
         && dist_enabled
             .as_deref()
             .map(|v| v == "true" || v == "1")
-            .unwrap_or(false);
+            .unwrap_or(false)
+        && remote_reachable != Some(false);

Also applies to: 238-245

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cache.rs` around lines 190 - 212, The remote cache status check in the
connectivity summary is treating a failed `sccache --dist-status` as only a
warning, so the final “configuration looks complete” message can still appear.
Update the logic around the `out.status.success()` branch in the cache status
function so a non-zero status records connectivity failure and prevents the
overall summary from reporting success; use the existing remote-cache status
handling path (the same block that prints reachable/unreachable) to propagate
failure into the final result, including the related summary path mentioned by
the duplicate section.

Comment thread src/ci.rs
Comment on lines +104 to +105
- name: Validate Build Policy
run: cargo accelerate audit --fail-fast

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Don’t generate --fail-fast until the audit CLI supports it.

The generated workflow and hook call cargo accelerate audit --fail-fast, but the provided src/main.rs audit routing only handles skip_size, skip_rustflags, skip_features, and skip_parallel. As generated, policy CI/pre-commit can fail before the audit runs; either wire a real --fail-fast audit option or remove the flag from the templates/tests.

Also applies to: 138-139, 378-378, 388-388, 393-393

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ci.rs` around lines 104 - 105, The audit workflow/templates are invoking
a `--fail-fast` flag that the audit CLI does not currently support, so update
the generated `Validate Build Policy` command and related hook/test references
to stop passing that option unless `main.rs`/audit routing actually implements
it. Locate the `audit` command handling in `src/main.rs` and the template
generation in `src/ci.rs`, then either add real `--fail-fast` support end-to-end
or remove the flag consistently from all generated workflow and pre-commit
outputs.

Comment thread src/ci.rs
Comment on lines +146 to 159
pub fn run(opts: CiOptions) -> Result<()> {
println!(
"{}",
"Generating Optimized CI Configurations...".bold().cyan()
);

let root = get_project_root().context("Could not find project root")?;

// 1. Create GitHub Actions workflow
// 1. Create GitHub Actions workflow with conditional enforcement
let github_dir = root.join(".github").join("workflows");
fs::create_dir_all(&github_dir)?;

let workflow = build_workflow(opts.enforce_policy, opts.budget);
let workflow_path = github_dir.join("build.yml");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate budget before writing the workflow.

budget comes from CLI as Option<f64> and is interpolated directly, so 0, negative, NaN, or infinite values can produce nonsensical CI commands.

Proposed fix
 pub fn run(opts: CiOptions) -> Result<()> {
+    if let Some(budget) = opts.budget {
+        anyhow::ensure!(
+            budget.is_finite() && budget > 0.0,
+            "--budget must be a positive finite number of seconds"
+        );
+    }
+
     println!(

Also applies to: 226-233

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ci.rs` around lines 146 - 159, `run` is passing `CiOptions.budget`
straight into `build_workflow`, so invalid values can generate broken CI
commands. Add validation in `run` before the workflow is built: require `budget`
to be finite and greater than zero, and reject `0`, negative, `NaN`, or infinite
inputs with an error. If the same budget formatting is used elsewhere, apply the
same guard at the other `build_workflow` call site too so all workflow
generation paths are protected.

Comment thread src/features.rs
Comment on lines +56 to +78
pub fn analyze_features(root: &Path) -> Result<FeatureAudit> {
let cargo_toml = get_cargo_toml_path(root);
if !cargo_toml.exists() {
return Ok(FeatureAudit::default());
}

let content = fs::read_to_string(&cargo_toml)?;
let parsed: toml::Value = toml::from_str(&content)?;

let metadata = get_cached_metadata_with_deps()?;
let known = known_feature_suggestions();

let mut suggestions = Vec::new();

let direct_deps = parsed
.get("dependencies")
.and_then(|d| d.as_table())
.map(|t| {
t.iter()
.map(|(k, _)| k.clone())
.collect::<Vec<_>>()
})
.unwrap_or_default();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Analyze workspace member manifests, not only the workspace root.

run() passes get_project_root(), and that resolves to metadata.workspace_root; for typical workspaces, member dependencies live in member Cargo.toml files, so a root manifest with only [workspace] reports “No dependencies found to analyze.” Iterate metadata.workspace_members/manifest paths or include [workspace.dependencies] instead of only root [dependencies].

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features.rs` around lines 56 - 78, The analyze_features path only reads
the root Cargo.toml and inspects its [dependencies], so workspace member
manifests are missed and workspaces can incorrectly report no dependencies.
Update analyze_features to use the metadata from get_cached_metadata_with_deps
and iterate workspace member manifest paths from metadata.workspace_members (or
otherwise include [workspace.dependencies]) so dependency collection is done
from member Cargo.toml files, while keeping the existing analyze_features and
known_feature_suggestions flow intact.

Comment thread src/timings.rs
Comment thread src/timings.rs
Comment on lines +220 to +222
let branch = if run.branch.len() > 10 {
&run.branch[..10]
} else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Avoid byte slicing branch names.

&run.branch[..10] can panic if a UTF-8 branch name crosses a character boundary. Truncate by chars() instead.

Proposed fix
-        let branch = if run.branch.len() > 10 {
-            &run.branch[..10]
-        } else {
-            &run.branch
-        };
+        let branch = run.branch.chars().take(10).collect::<String>();
         println!(
             "{:<4} {:<20} {:<10} {:<12} {:<12} {:<10} {:<10}",
             run.id, ts, run.command, duration, run.profile, branch, label
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let branch = if run.branch.len() > 10 {
&run.branch[..10]
} else {
let branch = run.branch.chars().take(10).collect::<String>();
println!(
"{:<4} {:<20} {:<10} {:<12} {:<12} {:<10} {:<10}",
run.id, ts, run.command, duration, run.profile, branch, label
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/timings.rs` around lines 220 - 222, The branch truncation in the timing
logic uses byte slicing, which can panic on UTF-8 boundaries. Update the branch
handling in the `timings.rs` logic around the `branch` assignment to truncate by
characters instead of bytes, using the existing `run.branch` value safely. Keep
the same behavior for short branch names, but for long ones derive the shortened
string from `chars()` so the `branch` variable is always valid UTF-8.

Comment thread src/tracer.rs
Comment on lines +139 to +151
let status = Command::new("cargo")
.args(["build", "--timings=json"])
.current_dir(root)
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.context("Failed to run cargo build --timings=json")?;

if !status.success() {
return Ok(Vec::new());
}

parse_timings_json_dir(&timings_dir)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

git ls-files src/tracer.rs src | sed -n '1,120p'

Repository: khulnasoft/cargo-accelerate

Length of output: 516


🏁 Script executed:

ast-grep outline src/tracer.rs --view expanded

Repository: khulnasoft/cargo-accelerate

Length of output: 2400


🏁 Script executed:

rg -n "timings|collect_per_crate|benchmark --save|--timings=json|cargo build" src -S

Repository: khulnasoft/cargo-accelerate

Length of output: 6702


🌐 Web query:

Cargo --timings=json output stdout path docs

💡 Result:

As of July 2026, the --timings=json option in Cargo has been removed and is no longer supported [1]. Previously, this was an unstable feature that required the -Zunstable-options flag [2][3]. When it was available, it emitted JSON-formatted messages directly to stdout [1][3]. It did not output to a file, unlike the standard --timings flag, which writes an HTML report to the target/cargo-timings/ directory [4][5][6]. If you are looking for machine-readable build timing information, current documentation recommends using -Zbuild-analysis instead [1].

Citations:


🏁 Script executed:

sed -n '131,170p' src/tracer.rs

Repository: khulnasoft/cargo-accelerate

Length of output: 1640


🏁 Script executed:

sed -n '80,100p' src/cli.rs

Repository: khulnasoft/cargo-accelerate

Length of output: 894


🏁 Script executed:

sed -n '420,455p' src/tracer.rs

Repository: khulnasoft/cargo-accelerate

Length of output: 1608


Replace --timings=json with a supported timing source
cargo build --timings=json is no longer supported on current Cargo, and the old JSON mode emitted data on stdout rather than target/cargo-timings/. This path now falls back to an empty dashboard on failure; surface the error and switch to a supported source (--timings/-Zbuild-analysis) instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tracer.rs` around lines 139 - 151, The timing collection in
`parse_timings_json_dir` is using `cargo build --timings=json`, which is no
longer supported and won’t produce the expected artifacts. Update the
`Command::new("cargo")` invocation to use a supported timing source such as
`--timings` or `-Zbuild-analysis`, and make sure failures are surfaced instead
of silently returning `Ok(Vec::new())` so the caller can see the error when
`status.success()` is false.

Comment thread src/tracer.rs Outdated
Comment thread src/trend.rs
Comment on lines 97 to +104
println!(" Measuring current build times...");
let check_time = measure_cmd(&root, "check")?;
let build_time = measure_cmd(&root, "build")?;

// Record in unified timings store
timings::record_build_run(&mut store, "check", check_time, "trend", Some("trend-check"));
timings::record_build_run(&mut store, "build", build_time, "trend", Some("trend-build"));
store.save(&store_path)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Don’t persist failed cargo measurements as valid trend data.

measure_cmd returns elapsed time even if cargo check or cargo build exits non-zero, and these lines now save that duration into the unified timing history. Make measure_cmd fail on non-success before recording.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/trend.rs` around lines 97 - 104, The build trend recording in trend
currently saves timings even when cargo check or cargo build exits non-zero,
because measure_cmd returns a duration on failure. Update measure_cmd to return
an error when the command status is unsuccessful, and let the callers in trend
skip timings::record_build_run and store.save unless both measurements succeed.
Use the measure_cmd function and the build/check calls in trend as the fix
points.

ctx-eng and others added 2 commits July 1, 2026 09:27
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: ctx-eng <drlizabhola@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: ctx-eng <drlizabhola@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant