Skip to content

ci: add GitHub Actions workflow (fmt + clippy + test + doc)#31

Merged
maxine-at-forecast merged 1 commit into
mainfrom
feature/add-ci-workflow
May 24, 2026
Merged

ci: add GitHub Actions workflow (fmt + clippy + test + doc)#31
maxine-at-forecast merged 1 commit into
mainfrom
feature/add-ci-workflow

Conversation

@maxine-at-forecast
Copy link
Copy Markdown
Collaborator

Summary

ferrolearn had no PR CI before this — only Dependabot at the org level. This PR adds a strict, parallel-jobs GitHub Actions workflow + the fmt/clippy cleanup needed to land it green from day one.

New workflow (.github/workflows/ci.yml)

Four parallel jobs on every push to main + every PR targeting main:

job command gate
fmt cargo fmt --check strict rustfmt parity
clippy cargo clippy --workspace --all-targets -- -D warnings strict lints
test cargo test --workspace --release --lib --tests full suite, release mode (faster for math-heavy paths)
doc cargo doc --workspace --no-deps --document-private-items catches syntax-level doc breaks; not strict on warnings yet (see follow-up below)

Architectural choices:

  • Independent jobs — fmt / clippy / test / doc all run in parallel so one failure doesn't gate the others; contributors see the full picture in one CI run.
  • Concurrency controlcancel-in-progress on the same ref so a fix-up push kills the stale run.
  • Permissions hardeningcontents: read only. Workflow doesn't push, comment, or deploy.
  • CachingSwatinem/rust-cache@v2 keyed per-job so each artifact pool stays isolated.
  • Stable toolchain — no MSRV matrix yet; the workspace declares rust-version = "1.85" but enforcement can come as a separate matrix job if MSRV regressions become a practical concern.

Pre-CI cleanup so it lands green

change impact
cargo fmt applied across the workspace 66 files touched, ~1500-line diff, pure whitespace. Brings the tree to a rustfmt-clean baseline so future drift gets caught immediately.
clippy::needless_range_loop fixed with scoped #[allow] Math-style matrix index loops (per-class score rows, Laplace smoothing, k-means++ candidate walk) where range-by-index is the natural form. The allow is explicit + per-function so adjacent new code still gets linted. Files: categorical.rs, gmm.rs, lda.rs, gradient_boosting.rs, hist_gradient_boosting.rs, cluster/tests/conformance_sklearn.rs.
clippy::approximate_constant (false positive) 3.14 in mlp.rs::test_activate_identity was a placeholder for an Identity-activation passthrough check, not π. Changed to 1.25 with a comment.
clippy::unused_imports Transform not used in ferrolearn-neural/tests/conformance_wave4.rs.
cargo clippy --fix auto-applied ~10 files touched across ferrolearn-preprocess, ferrolearn-tree, ferrolearn-linear, ferrolearn-numerical, ferrolearn-model-selclippy::redundant_closure, clippy::derefed_type_is_same_as_origin, clippy::manual_range_patterns, clippy::length_comparison_to_one.

Verification

cargo fmt --check                                                    # clean
cargo clippy --workspace --all-targets -- -D warnings                # clean
cargo test --workspace --release --no-run                            # builds
cargo doc --workspace --no-deps --document-private-items             # builds (1 warning)

Known follow-ups (out of scope)

  1. Doc-link cleanup: ~10 broken intra-doc links in ferrolearn-io + ferrolearn-bayes (FerroError::Variant paths that don't resolve). Tighten the doc job to RUSTDOCFLAGS=-D warnings once those land.
  2. MSRV enforcement: add a cargo +1.85 check matrix job if MSRV regressions become a practical concern.
  3. Coverage / further hardening: deferred.

Diff shape

.github/workflows/ci.yml         | new file (~110 lines)
+
~66 files                        | fmt-only churn (whitespace)
+
~16 files                        | targeted clippy fixes (#[allow] annotations + auto-fixes)

Total: 79 files changed (+1605 / −791), most of it the mechanical fmt churn.

🤖 Generated with Claude Code

…p debt

ferrolearn had no PR CI before this — only Dependabot at the org level.
This adds a strict, parallel-jobs GitHub Actions workflow plus the fmt
+ clippy cleanup needed to land it green from day one.

## New workflow (.github/workflows/ci.yml)

Four parallel jobs on every push to main + every PR targeting main:

- `cargo fmt --check`           — strict rustfmt parity with main
- `cargo clippy -D warnings`    — strict lints across `--workspace --all-targets`
- `cargo test --release`        — full workspace test suite in release
- `cargo doc --no-deps`         — docs build (no `-D warnings` yet; see below)

Architectural choices:

- **Independent jobs**: fmt / clippy / test / doc all run in parallel so
  one failure doesn't gate the others — contributors see the full picture
  in a single CI run.
- **Concurrency control**: `cancel-in-progress` on the same ref so a
  fix-up push kills the stale run.
- **Permissions hardening**: `contents: read` only — workflow doesn't
  push, comment, or deploy.
- **Caching**: `Swatinem/rust-cache@v2` keyed per-job so each artifact
  pool stays isolated (clippy vs test vs doc).
- **Stable only**: no MSRV matrix yet — workspace declares `rust-version
  = "1.85"` but enforcement can come as a separate matrix job if MSRV
  regressions become a practical concern.
- **Doc job is advisory**: `RUSTDOCFLAGS=-D warnings` would be ideal but
  the workspace currently has multiple broken intra-doc links
  (`FerroError::*` variants in `ferrolearn-io`, etc.). Job catches
  syntax-level doc errors that would break the docs.rs build; lint
  tightening tracked as follow-up.

## Pre-CI cleanup so it lands green

- **`cargo fmt` applied across the workspace** (66 files, ~1500 line
  diff, all whitespace). Pure mechanical churn; brings the tree to a
  rustfmt-clean baseline so future drift gets caught immediately.

- **9 clippy violations fixed** to clear `-D warnings`:
  - 8× `clippy::needless_range_loop` (6 files: `categorical.rs`,
    `gmm.rs`, `lda.rs`, `gradient_boosting.rs`, `hist_gradient_boosting.rs`,
    `cluster/tests/conformance_sklearn.rs`). Each fixed with a
    scoped `#[allow(clippy::needless_range_loop)]` on the enclosing
    function — these are math-style matrix index loops (per-class score
    rows, smoothing, k-means++ candidate search) where range-by-index
    is the natural form; rewriting to `.iter().enumerate()` would
    obscure the intent. The allow is explicit and per-function so
    new loops in adjacent code still get linted.
  - 1× `clippy::approximate_constant` — false positive in
    `ferrolearn-neural/src/mlp.rs` test: `3.14` was a placeholder for
    the Identity activation passthrough test, not an approximation of
    π. Changed to `1.25` with a comment.
  - 1× `clippy::unused_imports` — `Transform` not used in
    `ferrolearn-neural/tests/conformance_wave4.rs`.

- **Auto-fixed by `cargo clippy --fix`**: several `clippy::redundant_closure`
  / `clippy::derefed_type_is_same_as_origin` / `clippy::manual_range_patterns`
  / `clippy::length_comparison_to_one` issues across
  `ferrolearn-preprocess`, `ferrolearn-tree`, `ferrolearn-linear`,
  `ferrolearn-numerical`, `ferrolearn-model-sel`. ~10 files touched.

## Verification

```
cargo fmt --check                                                    # clean
cargo clippy --workspace --all-targets -- -D warnings                # clean
cargo test --workspace --release --no-run                            # builds
cargo doc --workspace --no-deps --document-private-items             # builds (1 warning)
```

## Known follow-ups (out of scope here)

1. Doc-link cleanup: ~10 broken intra-doc links in `ferrolearn-io` +
   `ferrolearn-bayes` that prevent tightening to `RUSTDOCFLAGS=-D warnings`.
2. MSRV enforcement: add a `cargo +1.85 check` matrix job if MSRV
   regressions show up.
3. Coverage / dependabot review: not added; can come later.

Refs forecast-bio/decode#3 (upstream contributions backlog).
@maxine-at-forecast maxine-at-forecast force-pushed the feature/add-ci-workflow branch from 5b2da1f to 474a95e Compare May 24, 2026 16:27
@maxine-at-forecast maxine-at-forecast merged commit 176de12 into main May 24, 2026
4 checks passed
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