Skip to content

fix: enhance disk space cleanup and remove duplicate build in docs deployment - #740

Merged
ooples merged 1 commit into
masterfrom
fix/docs-disk-space
Jan 21, 2026
Merged

ooples merged 1 commit into
masterfrom
fix/docs-disk-space

Conversation

@ooples

@ooples ooples commented Jan 21, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes the "No space left on device" error during documentation deployment by:

  1. Aggressive disk space cleanup (~20GB freed):

    • Old .NET versions (6.x, 7.x)
    • Android SDK (~10GB)
    • Language runtimes (Swift, Miniconda, Julia, GHC)
    • Toolchains (CodeQL, Python, Ruby, Go, Node)
    • Browsers and tools (Chromium, PowerShell, Boost)
    • Cloud and database tools (Azure CLI, PostgreSQL, MySQL)
    • Build tools (Gradle, SBT, Kotlin)
    • Docker images and apt cache
  2. Remove duplicate full solution build:

    • The docs job was building the entire solution twice (once in build-windows, once in build-docs)
    • Now only restore dependencies and let DocFX/Playground build what they need
    • DocFX extracts metadata from source code, not compiled binaries
    • Playground publish builds only the playground project
  3. Add intermediate cleanup before upload:

    • Remove _playground after copying to _site
    • Remove all bin/obj directories
    • Remove NuGet packages cache
    • Clear temp files

Test plan

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings January 21, 2026 15:51
@vercel

vercel Bot commented Jan 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
aidotnet-playground-api Ready Ready Preview, Comment Jan 21, 2026 6:58pm

@coderabbitai

coderabbitai Bot commented Jan 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

Release Notes

  • New Features
    • Added a new "Try It" navigation item in the documentation, providing quick access to an interactive playground experience.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

CI workflow optimization adds disk-cleanup steps to the sonarcloud workflow for managing build artifacts and freeing space before deployment phases. Documentation navigation enhanced with a new "Try It" playground entry positioned between Getting Started and Tutorials sections.

Changes

Cohort / File(s) Summary
CI Workflow Configuration
.github/workflows/sonarcloud.yml
Added extensive disk-cleanup steps removing SDK, language runtimes, caches, and Docker images; restructured "Restore and build" into dedicated "Restore dependencies" step; introduced cleanup sequences before upload/Pages deployment phases targeting build artifacts (_playground, bin, obj, tests/*/bin, api/.manifest, NuGet cache)
Navigation Structure
toc.yml
Added "Try It" navigation entry with playground reference (href: playground/, topicHref: playground/index.html) positioned between Getting Started and Tutorials

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Possibly related PRs

  • PR #735: Modifies disk-cleanup steps in sonarcloud.yml for the build-docs deployment phase.
  • PR #734: Alters build-docs and documentation deployment flow in sonarcloud.yml.
  • PR #730: Adds playground-related navigation item to toc.yml for interactive content access.

Poem

🐰 Hop! Hop! The workflows dance so free,
Disk space cleaned with jubilee,
Try It now—a playground gleams,
Between the docs, a rabbit's dreams! 🎯✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: aggressive disk cleanup and removal of duplicate build steps in docs deployment.
Description check ✅ Passed The description comprehensively explains the PR's purpose, detailing disk cleanup strategies, removal of duplicate builds, and intermediate cleanup steps.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/docs-disk-space

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

@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: 10

Caution

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

⚠️ Outside diff range comments (2)
src/Optimizers/ParticleSwarmOptimizer.cs (1)

98-130: Add guard against empty swarm before accessing swarm[0].
The code at line 116 accesses swarm[0] directly to initialize globalBest, but there is no validation ensuring SwarmSize > 0. Even though line 98 uses a guard pattern (swarm.Count > 0 ? swarm[0].ParameterCount : ...), this protection is absent at the point where firstStepData is created. If SwarmSize = 0, the initialization loop never executes and swarm[0] will throw an IndexOutOfRangeException. Add a validation check or guard to ensure the swarm is non-empty before line 116.

src/Regression/RegressionBase.cs (1)

523-557: Guard against empty parameter vectors when intercept is enabled.

With UseIntercept = true and parameters.Length == 0, coefficientCount becomes -1, leading to invalid vector allocation.

🛠️ Proposed fix
        if (coefficientCount == 0)
        {
+           if (Options.UseIntercept && parameters.Length == 0)
+           {
+               throw new ArgumentException("Parameters must include an intercept value.", nameof(parameters));
+           }
            // For untrained model, infer coefficient count from parameters
            // If UseIntercept: coeffCount = parameters.Length - 1
            // If not UseIntercept: coeffCount = parameters.Length
            coefficientCount = Options.UseIntercept ? parameters.Length - 1 : parameters.Length;
        }
🤖 Fix all issues with AI agents
In @.github/workflows/sonarcloud.yml:
- Around line 658-672: In the "Free up disk space before upload" step the
unconditional line sudo rm -rf /tmp/* is risky; remove that command or replace
it with a scoped, safer cleanup (for example, only remove build-related
temporary files or files owned by the current runner that match a known pattern
or age) to avoid breaking downstream actions; specifically update the step to
stop running sudo rm -rf /tmp/* (or swap it for a targeted cleanup strategy) so
actions/upload-pages-artifact and actions/deploy-pages aren’t impacted.

In `@src/Optimizers/AdaDeltaOptimizer.cs`:
- Around line 321-337: The CPU path in UpdateParameters multiplies
updateUnscaled by CurrentLearningRate but the GPU path (UpdateParametersGpu)
calls backend.AdadeltaUpdate with no LR, causing divergence when LR != 1; modify
either the GPU kernel signature (backend.AdadeltaUpdate) to accept a
learningRate parameter and use CurrentLearningRate inside the native update, or
pre-scale the update/parameters on the managed side before calling
backend.AdadeltaUpdate so the GPU receives the same scaledUpdate as the CPU;
update references to CurrentLearningRate, AdadeltaUpdate, UpdateParameters and
UpdateParametersGpu and ensure _accumulatedSquaredUpdates behavior remains
identical between paths.

In `@src/Optimizers/BayesianOptimizer.cs`:
- Around line 105-125: The code assumes _options.InitialSamples > 0 and writes
to _sampledPoints[0,*]; add a guard at the start of this initialization block to
validate _options.InitialSamples (check <= 0) and either throw a clear
ArgumentException or return/skip the sampling flow early; ensure you validate
before calling InitializeRandomSolution or allocating
_sampledPoints/_sampledValues so functions like InitializeRandomSolution,
EvaluateSolution and UpdateBestSolution are not invoked when InitialSamples is
non-positive.

In `@src/Optimizers/BFGSOptimizer.cs`:
- Around line 277-366: When reinitializing _inverseHessian in UpdateParameters
(the block checking "_inverseHessian is null || _inverseHessian.Rows !=
parameters.Length"), also reset _previousParameters and _previousGradient to
null to avoid size mismatches; locate the reset logic in the UpdateParameters
method and clear those fields immediately after creating the identity inverse
Hessian so future BFGS updates (s = parameters - _previousParameters, y =
clippedGradient - _previousGradient) don't use incompatible-sized vectors.

In `@src/Optimizers/DFPOptimizer.cs`:
- Around line 304-369: The optimizer stores previous state in
_previousParameters used by UpdateParameters but that field is not persisted
across checkpoints; update the DFPOptimizer's serialization and deserialization
logic (e.g., the class's SaveState/LoadState, GetObjectData/constructor for
ISerializable, or whatever checkpointing methods exist) to include
_previousParameters so it is restored on resume, or explicitly clear/reset
_previousParameters on deserialize if you intend to drop curvature; reference
the _previousParameters field and the UpdateParameters method when making the
change so curvature continuity is preserved or intentionally reset.

In `@src/Optimizers/FTRLOptimizer.cs`:
- Around line 130-182: UpdateParameters and UpdateSolution compute the FTRL
denominator differently (UpdateParameters uses lambda2 + (sqrt(n) + beta)/alpha
while UpdateSolution uses lambda2*(1+beta) + sqrt(n)/alpha) causing inconsistent
updates; pick the correct math and make both use the same expression by either
changing the denominator in UpdateParameters to match UpdateSolution (or vice
versa) and extracting the shared logic into a single helper (e.g.,
ComputeFtrlDenominator or GetDenominator) that takes sqrtN, alpha, beta, lambda2
and is called from UpdateParameters and UpdateSolution so both use the identical
formula.
- Around line 103-107: InitializeAdaptiveParameters currently sets _z and _n to
null which breaks Optimize/UpdateSolution that expect pre-allocated arrays;
instead, in InitializeAdaptiveParameters (called by Optimize), preserve existing
_z/_n if already allocated or reinitialize them to zero-sized arrays of the
correct length (or zero their contents) rather than nulling them; ensure
CurrentLearningRate and _t are still reset as shown, but remove the "_z = null;
_n = null;" behavior or replace it with logic that checks for non-null _z/_n and
zeroes or re-allocates them so UpdateSolution's dereferences of _z!/_n! remain
safe.

In `@src/Optimizers/RootMeanSquarePropagationOptimizer.cs`:
- Around line 244-248: UpdateSolution currently assumes _squaredGradient length
matches the incoming parameter/solution vectors which can cause exceptions after
Reset()/Deserialize() or model shape changes; mirror the guard used in
UpdateParameters by checking if (_squaredGradient.Length != parameters.Length)
(or the corresponding solution length) and reinitialize _squaredGradient = new
Vector<T>(parameters.Length) before performing vector ops so sizes are
consistent with UpdateParameters and safe across deserialization/reset flows.

In `@src/Optimizers/TrustRegionOptimizer.cs`:
- Around line 57-66: The checkpointing currently omits the trust‑region state so
resumed runs diverge: include _trustRegionPreviousParameters and
_trustRegionPreviousGradient in the optimizer's Serialize and Deserialize logic
by writing them into the checkpoint payload and restoring them on load (handle
nulls and add backwards-compatible versioning/optional fields so older
checkpoints still load); update the Serialize method to emit the two vectors and
the Deserialize method to read and assign them back to
_trustRegionPreviousParameters and _trustRegionPreviousGradient (ensure type T
and vector shape validation during restore).

In `@src/Regression/RegressionBase.cs`:
- Around line 655-683: In SetParameters, add the same empty-parameters guard to
avoid computing a negative coefficientCount when parameters.Length == 0 and
Options.UseIntercept is true: if parameters.Length == 0, set coefficientCount =
0, resize Coefficients = new Vector<T>(0) (or ensure Coefficients has length 0),
and set Intercept = default(T) only if Options.UseIntercept (or leave it
unchanged if intended), then skip the parameter copy/indexing and the
expectedCount check that assumes parameters exist; reference SetParameters,
Coefficients, Options.UseIntercept, Intercept, and parameters to locate where to
insert this guard.
🧹 Nitpick comments (8)
src/GaussianProcesses/StandardGaussianProcess.cs (1)

113-121: Consider making jitter magnitude configurable or scale-aware.

A fixed 1e-6 can be too small for large-kernel scales or too large for tightly normalized data. Exposing a configurable jitter (e.g., constructor optional parameter) or deriving it from the diagonal scale would make this more robust across datasets.

src/Optimizers/TrustRegionOptimizer.cs (1)

156-186: Consider applying radius adaptation before computing the step.

The radius update is based on the previous step’s outcome, but it executes after the new step is computed, so the current step still uses the old radius. If you want the latest success/failure to influence the current step, move this block before the Cauchy step (or document the intentional lag).

♻️ Proposed refactor (move adaptation block before step computation)
-        // Cauchy point computation:
+        // Adapt trust region radius based on gradient change (proxy for step success)
+        if (_trustRegionPreviousGradient is not null && _trustRegionPreviousParameters is not null)
+        {
+            // Compute the gradient difference to estimate curvature
+            var gradDiff = (Vector<T>)Engine.Subtract(gradient, _trustRegionPreviousGradient);
+            var paramDiff = (Vector<T>)Engine.Subtract(parameters, _trustRegionPreviousParameters);
+            var paramDiffNorm = paramDiff.Norm();
+
+            if (NumOps.GreaterThan(paramDiffNorm, NumOps.FromDouble(1e-10)))
+            {
+                // If gradient is decreasing in magnitude, step was likely successful
+                var prevGradNorm = _trustRegionPreviousGradient.Norm();
+
+                if (NumOps.LessThan(gradientNorm, prevGradNorm))
+                {
+                    // Successful step - expand trust region
+                    _trustRegionRadius = NumOps.Multiply(_trustRegionRadius, NumOps.FromDouble(_options.ExpansionFactor));
+                }
+                else
+                {
+                    // Unsuccessful step - contract trust region
+                    _trustRegionRadius = NumOps.Multiply(_trustRegionRadius, NumOps.FromDouble(_options.ContractionFactor));
+                }
+
+                // Clamp trust region radius
+                _trustRegionRadius = MathHelper.Clamp(
+                    _trustRegionRadius,
+                    NumOps.FromDouble(_options.MinTrustRegionRadius),
+                    NumOps.FromDouble(_options.MaxTrustRegionRadius));
+            }
+        }
+
+        // Cauchy point computation:
         // The optimal step along the steepest descent direction is:
         // alpha = min(trust_radius / ||g||, ||g||^2 / (g^T B g))
         // For gradient-only case (assuming B = I), this simplifies to:
         // alpha = min(trust_radius / ||g||, 1)
         // Then: step = -alpha * g
@@
-        // Adapt trust region radius based on gradient change (proxy for step success)
-        if (_trustRegionPreviousGradient is not null && _trustRegionPreviousParameters is not null)
-        {
-            // Compute the gradient difference to estimate curvature
-            var gradDiff = (Vector<T>)Engine.Subtract(gradient, _trustRegionPreviousGradient);
-            var paramDiff = (Vector<T>)Engine.Subtract(parameters, _trustRegionPreviousParameters);
-            var paramDiffNorm = paramDiff.Norm();
-
-            if (NumOps.GreaterThan(paramDiffNorm, NumOps.FromDouble(1e-10)))
-            {
-                // If gradient is decreasing in magnitude, step was likely successful
-                var prevGradNorm = _trustRegionPreviousGradient.Norm();
-
-                if (NumOps.LessThan(gradientNorm, prevGradNorm))
-                {
-                    // Successful step - expand trust region
-                    _trustRegionRadius = NumOps.Multiply(_trustRegionRadius, NumOps.FromDouble(_options.ExpansionFactor));
-                }
-                else
-                {
-                    // Unsuccessful step - contract trust region
-                    _trustRegionRadius = NumOps.Multiply(_trustRegionRadius, NumOps.FromDouble(_options.ContractionFactor));
-                }
-
-                // Clamp trust region radius
-                _trustRegionRadius = MathHelper.Clamp(
-                    _trustRegionRadius,
-                    NumOps.FromDouble(_options.MinTrustRegionRadius),
-                    NumOps.FromDouble(_options.MaxTrustRegionRadius));
-            }
-        }
src/Optimizers/OptimizerBase.cs (1)

1259-1262: Redundant empty matrix check.

This validation is redundant since lines 1226-1229 already throw ArgumentException if matrix.Rows == 0. The code at line 1263 (matrix[0, col]) is only reachable when matrix.Rows > 0.

♻️ Suggested removal
             for (int col = 0; col < features; col++)
             {
-                // Safe to access matrix[0, col] after validation above
-                if (matrix.Rows == 0)
-                {
-                    throw new ArgumentException("Matrix cannot be empty", nameof(matrix));
-                }
                 T initialValue = matrix[0, col];
src/Models/Options/LBFGSOptimizerOptions.cs (1)

98-101: Outdated documentation: still references "new" keyword.

The XML documentation on lines 98-99 states "This property uses the 'new' keyword" but the property now uses override. Update the documentation to reflect the change:

-    /// Note: This property uses the "new" keyword because it overrides the base class property with a
-    /// different default value that's more appropriate for L-BFGS.</para>
+    /// Note: This property overrides the base class property with a different default value
+    /// that's more appropriate for L-BFGS.</para>

The change from new to override is correct and enables proper polymorphic behavior.

src/Optimizers/AdagradOptimizer.cs (1)

483-499: Deserialization looks correct; minor naming nit.

The deserialization logic properly reconstructs the optimizer state. One small inconsistency: data_arr (line 489) uses snake_case while the codebase appears to use camelCase for local variables.

Optional naming fix
-                T[] data_arr = new T[length];
+                T[] dataArr = new T[length];
                 for (int i = 0; i < length; i++)
                 {
-                    data_arr[i] = NumOps.FromDouble(reader.ReadDouble());
+                    dataArr[i] = NumOps.FromDouble(reader.ReadDouble());
                 }
-                _accumulatedSquaredGradients = new Vector<T>(data_arr);
+                _accumulatedSquaredGradients = new Vector<T>(dataArr);
src/Optimizers/NadamOptimizer.cs (2)

513-519: Consider serializing _previousT for complete state restoration.

The time step _t is serialized (line 513), but _previousT (used by ReverseUpdate) is not. If ReverseUpdate is called after deserialization without first calling UpdateParameters, _previousT will have its default value (0), which may not match the restored _previousM/_previousV state.

Suggested fix
             writer.Write(_t);

+            writer.Write(_previousT);
+
             // Serialize state vectors
             SerializeVector(writer, _m);

And in Deserialize:

             _t = reader.ReadInt32();

+            _previousT = reader.ReadInt32();
+
             // Deserialize state vectors
             _m = DeserializeVector(reader);

525-553: Helper methods duplicate code from AMSGradOptimizer.

SerializeVector and DeserializeVector are identical to those in AMSGradOptimizer. Consider extracting these to a shared base class or utility class to reduce duplication.

tests/AiDotNet.Tests/IntegrationTests/Optimizers/MetaheuristicOptimizerIntegrationTests.cs (1)

10-22: Consider tagging these as integration tests for filtering.

There are many stochastic optimizers with non-trivial iteration counts. A category/trait would let CI split or filter if runtime becomes an issue.

Comment thread .github/workflows/sonarcloud.yml
Comment thread src/Optimizers/AdaDeltaOptimizer.cs
Comment thread src/Optimizers/BayesianOptimizer.cs
Comment thread src/Optimizers/BFGSOptimizer.cs
Comment thread src/Optimizers/DFPOptimizer.cs
Comment thread src/Optimizers/FTRLOptimizer.cs
Comment thread src/Optimizers/FTRLOptimizer.cs
Comment thread src/Optimizers/RootMeanSquarePropagationOptimizer.cs
Comment thread src/Optimizers/TrustRegionOptimizer.cs
Comment thread src/Regression/RegressionBase.cs

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Copilot AI 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.

Pull request overview

This PR fixes "No space left on device" errors during documentation deployment while also adding comprehensive optimizer integration tests and fixing several optimizer-related bugs.

Changes:

  • Enhanced disk space cleanup in CI/CD pipeline (~20GB freed through removal of unused tools and runtimes)
  • Removed duplicate solution build in docs job (DocFX extracts metadata from source, not binaries)
  • Added 5200+ lines of comprehensive integration tests for gradient-based and metaheuristic optimizers
  • Implemented missing UpdateParameters methods for several optimizers (BFGS, DFP, L-BFGS, TrustRegion, FTRL)
  • Fixed parameter dimension mismatches in optimizers (CMA-ES, Bayesian, Powell, ParticleSwarm, DifferentialEvolution, AntColony)
  • Enhanced serialization/deserialization for optimizer state vectors
  • Fixed untrained model parameter handling in RegressionBase

Reviewed changes

Copilot reviewed 42 out of 43 changed files in this pull request and generated no comments.

Show a summary per file
File Description
.github/workflows/sonarcloud.yml Enhanced disk cleanup (~20GB), removed duplicate build, added intermediate cleanup
toc.yml Added "Try It" playground navigation entry
MetaheuristicOptimizerIntegrationTests.cs New comprehensive tests for GA, PSO, DE, SA, ACO, Tabu, CMA-ES, Bayesian, Nelder-Mead, Powell, Normal optimizers
GradientBasedOptimizerIntegrationTests.cs New comprehensive tests for SGD, Momentum, Adam, RMSProp, Adagrad, AdaDelta, NAG, AdaMax, AMSGrad, Nadam, Lion, L-BFGS, Newton, AdamW, FTRL, LAMB, LARS, BFGS, DFP, ConjugateGradient, TrustRegion, Levenberg-Marquardt, etc.
RegressionBase.cs Fixed WithParameters/SetParameters to handle untrained models correctly
Multiple optimizer files Implemented missing UpdateParameters methods, fixed serialization, added state management
Multiple option files Changed new to override for InitialLearningRate property
StandardGeneticAlgorithm.cs Fixed parameter initialization for untrained models
GeneticBase.cs Added training input storage for proper dimension inference
StandardGaussianProcess.cs Added jitter term for numerical stability

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Enhance disk cleanup to free ~15GB (Android SDK, Haskell, language runtimes,
  docker images, apt cache)
- Remove duplicate full solution build - DocFX extracts metadata from source
  code, not compiled binaries, so only restore is needed
- Add intermediate cleanup before upload to free build artifacts
- Add "Try It" link to main navigation for the playground

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@ooples
ooples merged commit c868392 into master Jan 21, 2026
40 checks passed
@ooples
ooples deleted the fix/docs-disk-space branch January 21, 2026 21:23

This branch was successfully deployed

1 active deployment
Preview — e6789797 Deployed Jan 21, 2026 by vercel[bot]
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.

3 participants