Skip to content

feat(xtask): add ci plan subcommand (Rust-native PR planner)#3758

Draft
EffortlessSteven wants to merge 1 commit intomainfrom
claude/improve-bitnet-ci-AkGLc-K-xtask-ci-plan
Draft

feat(xtask): add ci plan subcommand (Rust-native PR planner)#3758
EffortlessSteven wants to merge 1 commit intomainfrom
claude/improve-bitnet-ci-AkGLc-K-xtask-ci-plan

Conversation

@EffortlessSteven
Copy link
Copy Markdown
Member

Summary

Replaces the inline Python planner in .github/workflows/pr-plan.yml (added in #3742) with a Rust-native, unit-testable xtask ci plan subcommand. This is PR K in the multi-PR CI roadmap (A–H merged; I, J, K open).

cargo run --locked -p xtask -- ci plan \
  --base "$BASE_SHA" \
  --head "$HEAD_SHA" \
  --labels-json '["full-ci"]' \
  --json-out ci-plan.json \
  --github-summary "$GITHUB_STEP_SUMMARY"

Why

The inline Python version was the right first move (#3742 shipped fast and exercised the LEM model end-to-end) but it could not be tested without a CI run. A YAML-embedded planner drifts; a Rust planner can be tested with fixtures and held to the same review bar as the rest of the codebase. This is the foundation for everything that follows: PR L (policy files), PR N (actuals), PR O (budget warnings), and PR P (ripr promotion rules) all consume ci-plan.json.

Implementation

  • xtask/src/ci_plan.rs — pure plan_for(changed, labels) -> Plan function + git_changed_files(...) wrapper + run(...) entry point. Same touched-area buckets and lane logic as the Python version, plus the ripr lane (rust_production, ripr label).
  • xtask/src/main.rs — new Cmd::Ci { command: CiCmd } subcommand and CiCmd::Plan variant.
  • .github/workflows/pr-plan.yml — drops ~120 lines of inline Python in favor of a single cargo run invocation. Adds a small Rust toolchain install + Swatinem/rust-cache for the xtask compile.

Schema

Two additions vs the inline Python version:

Field Type Purpose
lane.blocking bool Whether this lane blocks merges today (placeholder for budget enforcement).
lane.stage "required" | "default" | "label" | "advisory" Lane-class taxonomy for PR P (ripr promotion).

The rest of the schema (posture, touched, labels, lanes[].name/lem/reason, estimated_lem, band) is unchanged from #3742.

Tests (10/10 passing)

Test Asserts
empty PR 0 lanes, pennies band
docs-only PR guards lane only, posture=docs-only
rust crate change Core / Feature Matrix PR / MSRV / ripr / guards (54 LEM, elevated band)
GPU kernel change native compile fires; Docker does not without label
full-ci label all label-gated lanes fire
ripr-eligible PR advisory lane fires
test-only Rust diff ripr advisory does not fire (tests/ ≠ rust_production)
ripr label on docs-only PR ripr advisory still fires
full-ci on kernel change >125 LEM, over-hard-ceiling band
parse_git_output strips blank lines
cargo test --locked --no-default-features -p xtask --bin xtask ci_plan
# test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured

Smoke output

$ cargo run -q -p xtask -- ci plan --dry-run --labels-json '["full-ci"]'
{
  "posture": "empty",
  "touched": { ... },
  "labels": ["full-ci"],
  "lanes": [
    { "name": "BDD Grid Check", "lem": 4, "stage": "label", "blocking": false, ... },
    { "name": "Clippy (macOS ARM64)", "lem": 150, "stage": "label", ... },
    { "name": "Compatibility (ABI/FFI)", "lem": 8, ... },
    { "name": "Compatibility (tokenizer)", "lem": 6, ... },
    { "name": "Property Tests (smoke)", "lem": 4, ... },
    { "name": "ripr static exposure (advisory)", "lem": 4, "stage": "advisory", ... }
  ],
  "estimated_lem": 176,
  "band": "🚨 over hard ceiling (> 125 LEM)"
}

Test plan

  • CI Core green on the new xtask code (clippy + tests).
  • PR Plan workflow runs the new Rust planner on this PR and posts the same shape of step summary.
  • ci-plan.json artifact uploaded with new schema.
  • No behavior change for downstream consumers — all existing fields preserved.

Out of scope (future PRs)

  • PR L: hoist hard-coded LEM estimates and lane definitions into policy/ci-budget.toml, policy/ci-lanes.toml, policy/ci-risk-packs.toml.
  • PR M: nextest profile + JUnit upload + per-test duration history.
  • PR N: actual LEM collection (ci-actuals.json).
  • PR O: soft budget warnings (warn at 35 / 75 LEM; hard at 125 without full-ci).
  • PR P: ripr promotion rules using lane.stage taxonomy added here.

https://claude.ai/code/session_01S2yTnEYJcA3G2CyZn9bY4v


Generated by Claude Code

Replaces the inline Python planner that previously lived in
.github/workflows/pr-plan.yml. The Rust version is unit-testable with
fixtures and emits a stable ci-plan.json schema for downstream tooling
(budget warnings, label-aware gating, future learned-budget calibration).

  cargo run --locked -p xtask -- ci plan \
    --base "$BASE_SHA" \
    --head "$HEAD_SHA" \
    --labels-json '["full-ci"]' \
    --json-out ci-plan.json \
    --github-summary "$GITHUB_STEP_SUMMARY"

Implementation:
  - xtask/src/ci_plan.rs: pure planner (plan_for) + git-diff wrapper
    (git_changed_files) + JSON / step-summary entry point (run).
  - xtask/src/main.rs: new `Cmd::Ci { command: CiCmd }` subcommand and
    `CiCmd::Plan` variant.
  - .github/workflows/pr-plan.yml: replace ~120 lines of inline Python
    with a single cargo run invocation.

Tests (10/10 passing):
  - empty PR → 0 lanes, pennies band
  - docs-only PR → guards lane only
  - rust crate change → Core / Feature Matrix PR / MSRV / ripr / guards
  - GPU kernel change → native compile lane (no Docker without label)
  - full-ci label → all label-gated lanes fire
  - ripr-eligible PR → advisory lane fires
  - test-only Rust diff → ripr advisory does NOT fire
  - ripr label on docs-only PR → ripr advisory still fires
  - high-LEM full-ci on kernel change → over-hard-ceiling band
  - parse_git_output strips blank lines

Schema additions vs the inline Python version:
  - lane.blocking: bool (whether this lane blocks merges today)
  - lane.stage: "required" | "default" | "label" | "advisory"
  These are placeholders for future budget enforcement (PR O) and ripr
  promotion rules (PR P).

Out of scope (future PRs):
  - Hoist hard-coded LEM estimates into policy/ci-budget.toml,
    policy/ci-lanes.toml, policy/ci-risk-packs.toml (PR L).
  - actual LEM collection / ci-actuals.json (PR N).
  - soft budget warnings + hard ceiling at 125 LEM without full-ci (PR O).
@gemini-code-assist
Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b105101d-57c2-4afb-bd56-7c2e21939af7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/improve-bitnet-ci-AkGLc-K-xtask-ci-plan

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 and usage tips.

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.

2 participants