Skip to content

feat: Federated Learning v3 comprehensive enhancements (#536) - #911

Merged
ooples merged 40 commits into
masterfrom
feat/federated-learning-v3
Mar 1, 2026
Merged

ooples merged 40 commits into
masterfrom
feat/federated-learning-v3

Conversation

@ooples

@ooples ooples commented Feb 27, 2026 •

Copy link
Copy Markdown
Owner

Summary

Comprehensive Federated Learning v3 implementation covering all 10 sub-issues of #536. Adds 55+ new production-ready classes across 10 FL research areas with paper-accurate defaults and full XML documentation. Includes a 27-task production-readiness audit fixing critical algorithmic gaps, security issues, and anti-patterns.

Issues Addressed

Production-Readiness Audit (27 tasks completed)

Critical fixes applied across all FL subsystems:

Aggregation (#32): Added local training methods (contrastive loss, NTD, logit calibration, decorrelation, alignment, SAM perturbation) to 6 FedAvg wrapper strategies

Byzantine Robustness (#33-35): DnC SVD-based spectral analysis, FLAME HDBSCAN clustering, BOBA Bayesian mixture model

Privacy (#36-37, #46, #54): ShuffleModelDP actual shuffling, ProxyZKP cryptographic commitments, DPFedLoRA correct sensitivity formula with Renyi DP accounting, OPSA cryptographic RNG for secret shares with power-of-2 validation

Adapters (#38-41, #52, #55): FedMeZO zeroth-order gradient estimation, HierFedLoRA two-tier aggregation, SparseLoRA top-k sparsification, FLoRA paper-accurate stacking, FedPETuning method-aware PEFT aggregation, adapter forward pass, PPO/GAE/DPO gradient computation, OpenFedLLM stage-aware pipeline

Compression (#42, #44, #53, #57): One-Shot ensemble distillation, FedDT value-based splits, FedKD server-side distillation, SignSGD error feedback + SIGNUM momentum, TopK sparse representation, FetchSGD 2-universal hash family

Decentralized (#43, #58): DeTAG neighbor tracker averaging, DFedBCA importance-based block selection with gradient magnitude tracking

Personalization (#56): All 8 strategies fixed — FedBABU head extraction/initialization, FedRoD balanced softmax, FedCP routing/load-balancing, kNN-Per cosine-similarity distance-weighted combined prediction, FedSelect STE mask learning, pFedGate loss-based gate updates, FedAGHN gradient similarity adaptive weights, FedPAC prototype computation and calibration loss

Continual Learning (#45, #58): DataFreeFCL synthetic data generation, FedAGC Fisher information approximation with adaptive per-parameter correction

Code Quality (#47-51): Fixed hardcoded double anti-pattern, deterministic seed reuse, string-based strategy params, missing interface implementations, strategy-specific hyperparameters in options classes

Key Design Decisions

  • All classes extend FederatedLearningComponentBase<T> for NumOps access
  • Aggregation strategies extend ParameterDictionaryAggregationStrategyBase<T>
  • Paper-accurate default hyperparameters with XML docs citing original papers
  • Every class has <b>For Beginners:</b> documentation sections
  • Multi-target compatible (net10.0 + net471)
  • Cryptographic RNG for privacy-critical operations (secret shares, DP noise)
  • 2-universal hash families for probabilistic data structures
  • Error feedback for all biased compressors (SignSGD, TopK, FetchSGD)

Test plan

  • Build succeeds on both net10.0 and net471 targets (0 errors)
  • All 27 production-readiness audit tasks verified with build after each change
  • Verify existing FL tests still pass
  • Add contract tests for new classes in future PR

Closes #900, Closes #901, Closes #902, Closes #903, Closes #904, Closes #905, Closes #906, Closes #907, Closes #908, Closes #909

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

New Features

  • Federated Adapters: Added LoRA variants (FLoRA, DPFedLoRA, HierarchicalFedLoRA, SparseLoRA), zeroth-order optimization (FedMeZO), and unified parameter-efficient fine-tuning framework.
  • Aggregation Strategies: Introduced 14 new robust aggregation methods including Byzantine-resistant (BOBA, FLAME, FLTrust), fairness-aware (FedAA, FedAlign), and adaptive strategies (OptiGradTrust, Moon, FedSAM).
  • Compression & Communication: Added knowledge distillation, sketching, sign-based, and tree-based compression techniques for bandwidth optimization.
  • LLM Alignment: Added Direct Preference Optimization (DPO) and Reinforcement Learning from Human Feedback (RLHF) with multi-stage pipeline support.
  • Continual Learning: New prototype-replay and data-free distillation strategies with importance-aware parameter updates.
  • Decentralized Learning: Added gossip protocols, time-varying topologies, and block-coordinate aggregation for edge deployments.
  • Fairness & Privacy: Incorporated fairness constraints, Shapley value approximations, shuffle-model DP, and cryptographic verification.

Lines Changed: ~14,000+

franklinic and others added 10 commits February 27, 2026 10:29
Replace string Strategy properties with type-safe enums in:
- FederatedPersonalizationOptions (FederatedPersonalizationStrategy enum)
- FederatedMetaLearningOptions (FederatedMetaLearningStrategy enum)
- FederatedCompressionOptions (FederatedCompressionStrategy enum)

Update all string comparisons in InMemoryFederatedTrainer and test files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add MOON, FedNTD, FedLC, FedDecorr, FedAlign, FedSAM, FedMA, and FedAA
aggregation strategies with paper-accurate defaults and comprehensive docs.
Expand FederatedAggregationStrategy enum with 13 new values (also covering #903).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add FLTrust, DnC, Bucketing, FLAME, BOBA, and OptiGradTrust with
paper-accurate implementations, trust scoring, spectral analysis,
and historical reputation tracking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add FedPETuning, FedAdapter, FLoRA, HierFedLoRA, SLoRA, DP-FedLoRA,
FedMeZO adapters and FederatedRLHF, FederatedDPO, OpenFedLLMPipeline
alignment modules with expanded FederatedAdapterType enum.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add FedBABU, FedRoD, FedCP, kNN-Per, FedSelect, pFedGate, FedAGHN,
and FedPAC with expanded FederatedPersonalizationStrategy enum.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nalytics (#904)

Add ShuffleModelDP for privacy amplification via shuffling, ProxyZKPVerifier
for lightweight computation verification, and OptimizedPrivateSetAnalytics
for count-min sketch based private analytics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…hSGD, FedKD (#905)

Add SignSGDCompressor for 1-bit gradient compression with majority vote,
TopKSparsificationCompressor with error feedback, FetchSGDCompressor using
count-sketch recovery, and FedKDCompressor for knowledge distillation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…p, FedBuff (#906)

Add DFedAvgMProtocol for decentralized averaging with momentum, DeTAGProtocol
for gradient tracking, SegmentedGossipProtocol for bandwidth-efficient gossip,
TimeVaryingTopology for dynamic network graphs, and BufferedAsyncFederatedTrainer
for buffered async aggregation (FedBuff).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…lay, FedCIL (#907)

Add FedAGCContinualLearning for adaptive gradient correction,
FederatedExperienceReplay with reservoir sampling buffer, and
FedCILContinualLearning for class-incremental learning with prototype
consolidation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ey, FedFair (#908)

Add AgnosticFairnessObjective for minimax fairness, QFairFederatedLearning
for parameterized q-fair optimization, TiltedERMFairness for smooth
avg/worst-case interpolation, LightweightShapleyEvaluator for O(n) Shapley
values, and FedFairOptimizer for multi-objective Pareto scalarization.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 27, 2026 16:12
@vercel

vercel Bot commented Feb 27, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
aidotnet-playground-api Ready Ready Preview, Comment Mar 1, 2026 4:55pm

@coderabbitai

coderabbitai Bot commented Feb 27, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds ~50 new federated‑learning components across adapters, aggregators, alignment, compression, continual learning, decentralization, fairness, personalization, privacy, trainers, PSI, options/enums, and tests; converts several string strategy fields to strongly‑typed enums.

Changes

Cohort / File(s) Summary
Adapters
src/FederatedLearning/Adapters/...
DPFedLoRA.cs, FLoRA.cs, FedMeZO.cs, FedPETuning.cs, FederatedAdapterTuning.cs, HierarchicalFedLoRA.cs, SparseLoRA.cs
Adds multiple PEFT/LoRA adapter strategies (including DP‑aware, stacking, hierarchical, sparse, ZO, unified PEFT). New Extract/Merge/Aggregate APIs, ctor validation, adapter metadata, and DP accounting in DPFedLoRA.
Aggregators
src/FederatedLearning/Aggregators/...
MoonAggregationStrategy.cs, FedNtdAggregationStrategy.cs, FedLcAggregationStrategy.cs, FedDecorrAggregationStrategy.cs, FedAlignAggregationStrategy.cs, FedSamAggregationStrategy.cs, FedMaAggregationStrategy.cs, FedAaAggregationStrategy.cs, FLTrustAggregationStrategy.cs, DivideAndConquerAggregationStrategy.cs, BucketingAggregationStrategy.cs, FlameAggregationStrategy.cs, BobaAggregationStrategy.cs, OptiGradTrustAggregationStrategy.cs
Adds many advanced and robust aggregation strategies (contrastive/distillation/regularization/SAM family/matching/attention/meta‑wrappers/EM/Bayesian reputation). Exposes config properties, GetStrategyName, and non‑trivial iterative/math logic.
Alignment / LLM Pipelines
src/FederatedLearning/Alignment/...
FederatedDPO.cs, FederatedRLHF.cs, OpenFedLLMPipeline.cs
Adds Federated DPO, RLHF utilities, and an OpenFedLLM pipeline with staged orchestration, aggregation entry points, and options classes.
Compression
src/FederatedLearning/Compression/...
FedKDCompressor.cs, FetchSGDCompressor.cs, SignSGDCompressor.cs, TopKSparsificationCompressor.cs, FedDTCompressor.cs
New compressors: KD‑based distillation compressor, FetchSGD sketch + top‑k, SignSGD (1‑bit) with error feedback/momentum, TopK sparsifier, and decision‑tree compressor with compress/decompress/merge APIs.
Continual Learning
src/FederatedLearning/ContinualLearning/...
FedAGCContinualLearning.cs, FedCILContinualLearning.cs, FederatedExperienceReplay.cs, DataFreeFCL.cs
Adds FedAGC, FedCIL, Experience Replay, and Data‑Free FCL strategies with importance estimation, projection, prototype management, and synthetic data utilities.
Decentralized & Async Protocols
src/FederatedLearning/Decentralized/..., src/FederatedLearning/Trainers/...
DFedAvgMProtocol.cs, DFedBCAProtocol.cs, DeTAGProtocol.cs, SegmentedGossipProtocol.cs, TimeVaryingTopology.cs, BufferedAsyncFederatedTrainer.cs, AsyncFedEDTrainer.cs, SemiAsyncFederatedTrainer.cs, OneShotFederatedTrainer.cs
Adds decentralized protocols (DFedAvgM, DFedBCA, DeTAG, segmented gossip, time‑varying topology) and several trainers (buffered async, entropy‑driven async, semi‑async, one‑shot) with buffering, staleness, block/segment handling, and selection logic.
Fairness & Contribution
src/FederatedLearning/Fairness/...
AgnosticFairnessObjective.cs, FedFairOptimizer.cs, LightweightShapleyEvaluator.cs, QFairFederatedLearning.cs, TiltedERMFairness.cs
Adds AFL/q‑FFL/TERM objectives, a FedFair multi‑objective weighting optimizer, and a lightweight Shapley‑style contribution evaluator with free‑rider detection.
Personalization
src/FederatedLearning/Personalization/...
FedAGHNPersonalization.cs, FedBABUPersonalization.cs, FedCPPersonalization.cs, FedPACPersonalization.cs, FedRoDPersonalization.cs, FedSelectPersonalization.cs, KNNPersonalization.cs, PFedGatePersonalization.cs
Adds eight personalization modules (shared projection, BABU, conditional policy, PAC prototypes, RoD dual‑head, learned masks, kNN inference, pFedGate) with parameter extraction/merge and config properties.
Privacy, Verification & PSI
src/FederatedLearning/Privacy/..., src/FederatedLearning/Verification/..., src/FederatedLearning/PSI/...
ShuffleModelDP.cs, ProxyZKPVerifier.cs, OptimizedPrivateSetAnalytics.cs
Adds shuffle‑model DP pipeline (local DP + shuffling + aggregation + central epsilon estimation), proxy ZKP verifier with certificate issuance, and OPSA (Count‑Min, HLL, secret shares, threshold queries).
Options / Enums & Tests
src/Models/Options/..., tests/AiDotNet.Tests/FederatedLearning/*
Converts many string strategy fields to enums and extends option enums (adapters, aggregation, compression, personalization, meta‑learning, async modes, decentralized topologies, continual learning, DP modes, fairness, advanced compressors, contribution methods); updates tests to use enums.
Trainer wiring
src/FederatedLearning/Trainers/InMemoryFederatedTrainer.cs
Refactors trainer routing from string‑based strategy checks to strongly‑typed enums; updates helper signatures and metadata handling.
Other utilities & options
src/Models/Options/...
Multiple new option properties and enum additions (AdvancedCompressionOptions, Decentralized options, Async options, ContinualLearning options, etc.).

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related issues

Possibly related PRs

Suggested labels

feature, roadmap

Fifty modules marched into the tree,
Enums hardened choices, now safe to be.
Adapters, aggregators, privacy and PSI—
Flag TODOs, numeric edges, crypto review high.
Merge when tests pass and audits agree. 🚀

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Federated Learning v3 comprehensive enhancements (#536)' accurately summarizes the main change: a large, comprehensive addition of 55+ production-ready classes across ten major federated learning domains.
Linked Issues check ✅ Passed The changeset comprehensively addresses all ten linked issues (#900–#909): implements advanced aggregators (MOON, FedSAM family, FedNTD, FedLC, FedMA, FedAA), foundation-model adapters (FedPETuning, FLoRA variants, DPFedLoRA, FedMeZO, FederatedRLHF, FederatedDPO, OpenFedLLM), personalization methods (FedBABU, FedRoD, FedCP, kNN-Per, FedSelect, pFedGate, FedAGHN, FedPAC), Byzantine defenses (FLTrust, Divide-and-Conquer, Bucketing, FLAME, BOBA, OptiGradTrust), privacy mechanisms (ShuffleModelDP, ProxyZKPVerifier, OptimizedPrivateSetAnalytics), communication efficiency (SignSGD, Top-k, FetchSGD, FedKD, FedDT, OneShot), async/decentralized protocols, continual learning strategies, fairness/incentive mechanisms, and string-to-enum conversions.
Out of Scope Changes check ✅ Passed All changes remain directly aligned with the linked issue objectives: new aggregation strategies, adapter implementations, personalization methods, Byzantine-robust mechanisms, privacy enhancements, compression techniques, async/decentralized protocols, continual learning, fairness mechanisms, and options enum migrations—exactly as specified in #900–#909. No unrelated or exploratory changes detected.
Docstring Coverage ✅ Passed Docstring coverage is 89.49% which is sufficient. The required threshold is 80.00%.

✏️ 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 feat/federated-learning-v3

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

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 implements Federated Learning v3 enhancements, adding 55+ production-ready classes across 10 research areas to address issues #900-#909. The changes convert string-based strategy parameters to type-safe enums and add comprehensive implementations for advanced aggregation, foundation model FL, personalization, Byzantine robustness, privacy enhancements, communication efficiency, async/decentralized protocols, continual learning, and fairness mechanisms.

Changes:

  • Converted FederatedCompressionStrategy, FederatedPersonalizationStrategy, and FederatedMetaLearningStrategy from strings to proper enums
  • Added 13 new aggregation strategy enum values (MOON, FedNTD, FedLC, FedDecorr, FedAlign, FedSAM, FedMA, FedAA, FLTrust, DivideAndConquer, Bucketing, Flame, Boba)
  • Added 7 new adapter type enum values for foundation model FL
  • Implemented 55+ new strategy classes with paper-accurate defaults and comprehensive XML documentation

Reviewed changes

Copilot reviewed 62 out of 64 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Test files (4 files) Updated tests to use enum values instead of strings for strategy selection
FederatedPersonalizationOptions.cs Converted Strategy property from string to FederatedPersonalizationStrategy enum with 14 values
FederatedMetaLearningOptions.cs Converted Strategy property from string to FederatedMetaLearningStrategy enum with 4 values
FederatedCompressionOptions.cs Converted Strategy property from string to FederatedCompressionStrategy enum with 7 values
FederatedAggregationStrategy.cs Added 13 new enum values for advanced aggregation strategies
FederatedAdapterOptions.cs Added 7 new enum values for foundation model adapters
New aggregation strategies (8 files) MOON, FedSAM, FedNTD, FedMA, FedLC, FedDecorr, FedAlign, FedAA
New Byzantine-robust strategies (5 files) FLTrust, Bucketing, Boba, OptiGradTrust
New personalization strategies (8 files) FedBABU, FedRoD, FedCP, KNNPer, FedSelect, pFedGate, FedAGHN, FedPAC
New adapter strategies (7 files) FedPETuning, FederatedAdapterTuning, FLoRA, HierarchicalFedLoRA, SparseLoRA, FedMeZO
New alignment strategies (2 files) FederatedRLHF, FederatedDPO
New privacy mechanisms (2 files) ShuffleModelDP, ProxyZKPVerifier, OptimizedPrivateSetAnalytics
New compression strategies (4 files) SignSGD, TopKSparsification, FetchSGD, FedKD
New decentralized protocols (5 files) DFedAvgM, DeTAG, SegmentedGossip, TimeVaryingTopology, BufferedAsync
New continual learning (3 files) FedAGC, FederatedExperienceReplay, FedCIL
New fairness implementations (5 files) AgnosticFairness, QFairFL, TiltedERM, LightweightShapley, FedFair

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

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

Caution

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

⚠️ Outside diff range comments (2)
src/FederatedLearning/Trainers/InMemoryFederatedTrainer.cs (1)

163-203: ⚠️ Potential issue | 🟠 Major

Add fail-fast enum validation for option strategies before use.

compressionOptions.Strategy, personalizationOptions.Strategy, and metaLearningOptions.Strategy are consumed without validating that the value is defined. Invalid numeric enum values can enter from config binding and produce inconsistent behavior instead of a clear configuration error.

🔧 Proposed fix
         var compressionOptions = ResolveCompressionOptions(flOptions);
+        if (compressionOptions != null &&
+            !Enum.IsDefined(typeof(FederatedCompressionStrategy), compressionOptions.Strategy))
+        {
+            throw new InvalidOperationException($"Unknown compression strategy '{compressionOptions.Strategy}'.");
+        }
         bool useCompression = compressionOptions != null &&
                               compressionOptions.Strategy != FederatedCompressionStrategy.None;
@@
         var personalizationOptions = ResolvePersonalizationOptions(flOptions);
+        if (personalizationOptions != null &&
+            !Enum.IsDefined(typeof(FederatedPersonalizationStrategy), personalizationOptions.Strategy))
+        {
+            throw new InvalidOperationException($"Unknown personalization strategy '{personalizationOptions.Strategy}'.");
+        }
         bool usePersonalization = personalizationOptions != null &&
                                   personalizationOptions.Enabled &&
                                   personalizationOptions.Strategy != FederatedPersonalizationStrategy.None;
@@
         var metaLearningOptions = flOptions?.MetaLearning;
+        if (metaLearningOptions != null &&
+            !Enum.IsDefined(typeof(FederatedMetaLearningStrategy), metaLearningOptions.Strategy))
+        {
+            throw new InvalidOperationException($"Unknown meta-learning strategy '{metaLearningOptions.Strategy}'.");
+        }
         bool useMetaLearning = metaLearningOptions != null &&
                                metaLearningOptions.Enabled &&
                                metaLearningOptions.Strategy != FederatedMetaLearningStrategy.None;

As per coding guidelines, production-ready code must avoid “missing validation of external inputs”.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/FederatedLearning/Trainers/InMemoryFederatedTrainer.cs` around lines 163
- 203, Validate enum values for compressionOptions.Strategy,
personalizationOptions.Strategy, and metaLearningOptions.Strategy immediately
after resolving each options object (e.g., after
ResolveCompressionOptions(flOptions), ResolvePersonalizationOptions(flOptions),
and flOptions?.MetaLearning). Use Enum.IsDefined (or equivalent) to fail-fast
and throw a clear ArgumentException/InvalidOperationException if the numeric
value is not a valid FederatedCompressionStrategy /
FederatedPersonalizationStrategy / FederatedMetaLearningStrategy; do this before
any use such as computing useCompression/usePersonalization/useMetaLearning or
assigning metadata fields so invalid config bindings produce a clear error
instead of undefined behavior.
src/Models/Options/FederatedCompressionOptions.cs (1)

74-75: 🧹 Nitpick | 🔵 Trivial

Use enum cref in XML docs instead of a string literal.

After the enum migration, reference the actual member to keep docs IDE-linkable and less error-prone.

📝 Suggested XML doc update
-    /// beyond what basic TopK/Quantization can achieve. Set <see cref="Strategy"/> to "Advanced"
+    /// beyond what basic TopK/Quantization can achieve. Set <see cref="Strategy"/> to
+    /// <see cref="FederatedCompressionStrategy.Advanced"/>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Models/Options/FederatedCompressionOptions.cs` around lines 74 - 75, The
XML doc in FederatedCompressionOptions refers to the Strategy value as the
string "Advanced"; update that to use a cref to the enum member instead (for
example <see cref="CompressionStrategy.Advanced"/>), so the docs are
IDE-linkable and robust. Edit the comment that mentions Strategy in the
FederatedCompressionOptions class (the XML docs near the Strategy property) and
replace the literal "Advanced" with a <see cref="..."/> reference to the actual
enum type and member used by the property (e.g., CompressionStrategy.Advanced or
the actual enum name in your codebase).

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d5ea443 and 893efaa.

⛔ Files ignored due to path filters (2)
  • src/Generated/AiDotNet.Generators/AiDotNet.Generators.YamlConfigSourceGenerator/YamlRegisteredTypeNames.g.cs is excluded by !**/generated/**
  • src/Generated/AiDotNet.Generators/AiDotNet.Generators.YamlConfigSourceGenerator/YamlTypeRegistry.g.cs is excluded by !**/generated/**
📒 Files selected for processing (62)
  • src/FederatedLearning/Adapters/DPFedLoRA.cs
  • src/FederatedLearning/Adapters/FLoRA.cs
  • src/FederatedLearning/Adapters/FedMeZO.cs
  • src/FederatedLearning/Adapters/FedPETuning.cs
  • src/FederatedLearning/Adapters/FederatedAdapterTuning.cs
  • src/FederatedLearning/Adapters/HierarchicalFedLoRA.cs
  • src/FederatedLearning/Adapters/SparseLoRA.cs
  • src/FederatedLearning/Aggregators/BobaAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/BucketingAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/DivideAndConquerAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FLTrustAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedAaAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedAlignAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedDecorrAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedLcAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedMaAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedNtdAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedSamAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FlameAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/MoonAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/OptiGradTrustAggregationStrategy.cs
  • src/FederatedLearning/Alignment/FederatedDPO.cs
  • src/FederatedLearning/Alignment/FederatedRLHF.cs
  • src/FederatedLearning/Alignment/OpenFedLLMPipeline.cs
  • src/FederatedLearning/Compression/FedKDCompressor.cs
  • src/FederatedLearning/Compression/FetchSGDCompressor.cs
  • src/FederatedLearning/Compression/SignSGDCompressor.cs
  • src/FederatedLearning/Compression/TopKSparsificationCompressor.cs
  • src/FederatedLearning/ContinualLearning/FedAGCContinualLearning.cs
  • src/FederatedLearning/ContinualLearning/FedCILContinualLearning.cs
  • src/FederatedLearning/ContinualLearning/FederatedExperienceReplay.cs
  • src/FederatedLearning/Decentralized/DFedAvgMProtocol.cs
  • src/FederatedLearning/Decentralized/DeTAGProtocol.cs
  • src/FederatedLearning/Decentralized/SegmentedGossipProtocol.cs
  • src/FederatedLearning/Decentralized/TimeVaryingTopology.cs
  • src/FederatedLearning/Fairness/AgnosticFairnessObjective.cs
  • src/FederatedLearning/Fairness/FedFairOptimizer.cs
  • src/FederatedLearning/Fairness/LightweightShapleyEvaluator.cs
  • src/FederatedLearning/Fairness/QFairFederatedLearning.cs
  • src/FederatedLearning/Fairness/TiltedERMFairness.cs
  • src/FederatedLearning/PSI/OptimizedPrivateSetAnalytics.cs
  • src/FederatedLearning/Personalization/FedAGHNPersonalization.cs
  • src/FederatedLearning/Personalization/FedBABUPersonalization.cs
  • src/FederatedLearning/Personalization/FedCPPersonalization.cs
  • src/FederatedLearning/Personalization/FedPACPersonalization.cs
  • src/FederatedLearning/Personalization/FedRoDPersonalization.cs
  • src/FederatedLearning/Personalization/FedSelectPersonalization.cs
  • src/FederatedLearning/Personalization/KNNPersonalization.cs
  • src/FederatedLearning/Personalization/PFedGatePersonalization.cs
  • src/FederatedLearning/Privacy/ShuffleModelDP.cs
  • src/FederatedLearning/Trainers/BufferedAsyncFederatedTrainer.cs
  • src/FederatedLearning/Trainers/InMemoryFederatedTrainer.cs
  • src/FederatedLearning/Verification/ProxyZKPVerifier.cs
  • src/Models/Options/FederatedAdapterOptions.cs
  • src/Models/Options/FederatedAggregationStrategy.cs
  • src/Models/Options/FederatedCompressionOptions.cs
  • src/Models/Options/FederatedMetaLearningOptions.cs
  • src/Models/Options/FederatedPersonalizationOptions.cs
  • tests/AiDotNet.Tests/FederatedLearning/FederatedLearningCompressionIntegrationTests.cs
  • tests/AiDotNet.Tests/FederatedLearning/FederatedLearningInvalidConfigurationTests.cs
  • tests/AiDotNet.Tests/FederatedLearning/FederatedLearningPersonalizationAndMetaLearningIntegrationTests.cs
  • tests/AiDotNet.Tests/FederatedLearning/InMemoryFederatedTrainerInternalHelperTests.cs

Comment thread src/FederatedLearning/Aggregators/OptiGradTrustAggregationStrategy.cs Outdated
Comment thread src/FederatedLearning/Aggregators/OptiGradTrustAggregationStrategy.cs Outdated
Comment thread src/FederatedLearning/Alignment/FederatedRLHF.cs
Comment thread src/FederatedLearning/Alignment/FederatedRLHF.cs
Comment thread src/FederatedLearning/Privacy/ShuffleModelDP.cs
Comment thread src/FederatedLearning/Trainers/BufferedAsyncFederatedTrainer.cs
Comment thread src/FederatedLearning/Trainers/BufferedAsyncFederatedTrainer.cs Outdated
Comment thread src/FederatedLearning/Trainers/BufferedAsyncFederatedTrainer.cs Outdated
Comment thread src/FederatedLearning/Verification/ProxyZKPVerifier.cs Outdated

@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.

Review continued from previous batch...

Comment thread src/FederatedLearning/Aggregators/FedAlignAggregationStrategy.cs
Comment thread src/FederatedLearning/Aggregators/FedMaAggregationStrategy.cs Outdated
Comment thread src/FederatedLearning/Aggregators/FedNtdAggregationStrategy.cs
Comment thread src/FederatedLearning/Aggregators/FedSamAggregationStrategy.cs
Comment thread src/FederatedLearning/Compression/SignSGDCompressor.cs Outdated
Comment thread src/FederatedLearning/PSI/OptimizedPrivateSetAnalytics.cs
Comment thread src/FederatedLearning/PSI/OptimizedPrivateSetAnalytics.cs
Comment thread src/FederatedLearning/PSI/OptimizedPrivateSetAnalytics.cs
Comment thread src/FederatedLearning/PSI/OptimizedPrivateSetAnalytics.cs Outdated

@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.

Review continued from previous batch...

Comment thread src/FederatedLearning/Adapters/DPFedLoRA.cs
Comment thread src/FederatedLearning/Adapters/DPFedLoRA.cs
Comment thread src/FederatedLearning/Adapters/DPFedLoRA.cs
Comment thread src/FederatedLearning/Adapters/FederatedAdapterTuning.cs
Comment thread src/FederatedLearning/Adapters/FederatedAdapterTuning.cs
Comment thread src/FederatedLearning/Personalization/FedCPPersonalization.cs
Comment thread src/FederatedLearning/Personalization/FedPACPersonalization.cs
Comment thread src/FederatedLearning/Personalization/FedPACPersonalization.cs
Comment thread src/FederatedLearning/Personalization/FedSelectPersonalization.cs
Comment thread src/FederatedLearning/Personalization/FedSelectPersonalization.cs
…coverage

Missing files added:
- FedDTCompressor.cs (#905) - decision-tree compression
- DataFreeFCL.cs (#907) - data-free continual learning
- DFedBCAProtocol.cs (#906) - block coordinate ascent
- AsyncFedEDTrainer.cs (#906) - entropy-driven scheduling
- OneShotFederatedTrainer.cs (#905) - single-round FL
- SemiAsyncFederatedTrainer.cs (#906) - hybrid sync/async

Enum/options updates:
- FederatedAggregationStrategy: add OptiGradTrust (#903)
- AdvancedCompressionStrategy: add SignSGD, FetchSGD, FedKD, FedDT (#905)
- DecentralizedTopologyType: add DFedAvgM, DFedBCA, DeTAG, SegmentedGossip, TimeVarying (#906)
- FederatedAsyncMode: add AsyncFedED, SemiAsync (#906)
- FederatedContinualLearningStrategy: add FedAGC, ExperienceReplay, DataFreeFCL, FedCIL (#907)
- FairnessConstraintType: add AgnosticFairness, QFairFL, TiltedERM, FedFair (#908)
- DifferentialPrivacyMode: add Shuffle (#904)

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

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

Caution

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

⚠️ Outside diff range comments (2)
src/Models/Options/DifferentialPrivacyMode.cs (1)

6-11: 🧹 Nitpick | 🔵 Trivial

Consider updating top-level remarks to mention Shuffle mode.

The <remarks> block explains Local, Central, and Both modes but omits the newly added Shuffle mode. For completeness and discoverability, consider adding a bullet point for Shuffle.

📝 Suggested documentation update
 /// <remarks>
 /// <b>For Beginners:</b> Differential privacy can be applied at different points:
 /// - Local DP: each client adds noise before sending updates (stronger protection vs server).
 /// - Central DP: the server adds noise after aggregation (simpler and often higher utility).
 /// - Both: apply local and central DP for defense-in-depth.
+/// - Shuffle DP: clients add local noise, then a shuffler permutes updates before the server
+///   sees them, achieving central-DP-level accuracy with local-DP trust assumptions.
 /// </remarks>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Models/Options/DifferentialPrivacyMode.cs` around lines 6 - 11, The
remarks for DifferentialPrivacyMode currently document Local, Central, and Both
but omit the Shuffle mode; update the XML <remarks> for the
DifferentialPrivacyMode enum to add a fourth bullet describing Shuffle (briefly
explain that a trusted shuffler anonymizes client contributions before
aggregation, offering a middle ground between local and central DP), referencing
the DifferentialPrivacyMode symbol so reviewers can find and verify the new doc
text matches the enum's Shuffle value.
src/Models/Options/FederatedContinualLearningOptions.cs (1)

33-61: ⚠️ Potential issue | 🔴 Critical

BLOCKING: Options class missing required Golden Pattern elements.

This Options class violates multiple BLOCKING requirements per the coding guidelines:

  1. Missing Copy Constructor — This is a silent data-loss bug. When users clone/copy options, properties won't transfer.
  2. Missing Explicit Default Constructor — Guidelines require public FederatedContinualLearningOptions() { }
  3. Missing <para><b>Reference:</b> in class remarks — Must cite the foundational research papers for federated continual learning (e.g., FedWEIT, FedCurv).
  4. Properties missing full XML docs — Each property requires <value>, and <remarks> with <para><b>For Beginners:</b> explaining what the property controls.
🔧 Proposed fix adding required constructors and documentation
 /// <summary>
 /// Configuration options for federated continual learning (preventing catastrophic forgetting in FL).
 /// </summary>
 /// <remarks>
 /// <para><b>For Beginners:</b> When federated models learn new tasks over time, they can forget what they
 /// learned before (catastrophic forgetting). These strategies identify which model parameters are important
 /// for previous tasks and protect them during future training rounds. Each client computes importance locally,
 /// and the server aggregates these importance estimates across all clients.</para>
+/// <para><b>Reference:</b> Foundational work includes Federated EWC (Kirkpatrick et al., PNAS 2017),
+/// FedCurv (Shoham et al., 2019), and FedCIL (Qi et al., CVPR 2023).</para>
 /// </remarks>
 public class FederatedContinualLearningOptions : ModelOptions
 {
+    /// <summary>
+    /// Initializes a new instance of the <see cref="FederatedContinualLearningOptions"/> class with default values.
+    /// </summary>
+    public FederatedContinualLearningOptions()
+    {
+    }
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="FederatedContinualLearningOptions"/> class
+    /// by copying values from another instance.
+    /// </summary>
+    /// <param name="other">The instance to copy.</param>
+    /// <exception cref="ArgumentNullException">Thrown when <paramref name="other"/> is null.</exception>
+    public FederatedContinualLearningOptions(FederatedContinualLearningOptions other)
+    {
+        ArgumentNullException.ThrowIfNull(other);
+        Strategy = other.Strategy;
+        RegularizationStrength = other.RegularizationStrength;
+        FisherSamples = other.FisherSamples;
+        ProjectionThreshold = other.ProjectionThreshold;
+    }
+
     /// <summary>
     /// Gets or sets the strategy. Default: None.
     /// </summary>
+    /// <value>The federated continual learning strategy to use.</value>
+    /// <remarks>
+    /// <para><b>For Beginners:</b> Choose which forgetting-prevention technique to apply.
+    /// Start with <see cref="FederatedContinualLearningStrategy.None"/> for standard FL,
+    /// then try <see cref="FederatedContinualLearningStrategy.FederatedEWC"/> for basic protection.</para>
+    /// </remarks>
     public FederatedContinualLearningStrategy Strategy { get; set; } = FederatedContinualLearningStrategy.None;

     /// <summary>
     /// Gets or sets the regularization strength for EWC penalty. Default: 400.0.
     /// </summary>
+    /// <value>The lambda coefficient for EWC regularization.</value>
     /// <remarks>
+    /// <para><b>For Beginners:</b> Higher values mean "remember old tasks more strongly" but learn new tasks
+    /// more slowly. Start with 400 and increase if you see forgetting, or decrease if new learning stalls.</para>
     /// Higher values provide stronger protection against forgetting but may slow learning of new tasks.
     /// Typical range: 100–5000.
     /// </remarks>
     public double RegularizationStrength { get; set; } = 400.0;

     /// <summary>
     /// Gets or sets the number of data samples for Fisher information estimation. Default: 200.
     /// </summary>
+    /// <value>Sample count for computing diagonal Fisher information matrix.</value>
+    /// <remarks>
+    /// <para><b>For Beginners:</b> More samples = more accurate importance estimates but slower computation.
+    /// 200 is a good balance; increase to 500+ for complex models.</para>
+    /// </remarks>
     public int FisherSamples { get; set; } = 200;

     /// <summary>
     /// Gets or sets the projection threshold for orthogonal projection. Default: 0.01.
     /// </summary>
+    /// <value>Importance threshold below which directions are not protected.</value>
     /// <remarks>
+    /// <para><b>For Beginners:</b> Lower values protect more gradient directions (stronger forgetting prevention
+    /// but slower new learning). Start at 0.01; raise to 0.05 if new tasks struggle to learn.</para>
     /// Directions with importance above this threshold are protected. Lower values protect more directions.
     /// </remarks>
     public double ProjectionThreshold { get; set; } = 0.01;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Models/Options/FederatedContinualLearningOptions.cs` around lines 33 -
61, Add the required Golden Pattern elements to
FederatedContinualLearningOptions: implement a public parameterless constructor
FederatedContinualLearningOptions() { } and a copy constructor
FederatedContinualLearningOptions(FederatedContinualLearningOptions other) that
throws ArgumentNullException if other is null and copies Strategy,
RegularizationStrength, FisherSamples, and ProjectionThreshold; update the class
XML <remarks> to include a <para><b>Reference:</b> entry citing foundational
federated continual learning papers (e.g., FedWEIT, FedCurv); and expand each
property’s XML docs (Strategy, RegularizationStrength, FisherSamples,
ProjectionThreshold) to include a <value> describing the property and a
<remarks> containing a <para><b>For Beginners:</b> explanation of what the
property controls.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/FederatedLearning/Compression/FedDTCompressor.cs`:
- Around line 243-262: The EstimateCompressionRatio method lacks a null check
for the CompressedTree parameter and doesn't document that it treats all stored
elements equally regardless of type; update EstimateCompressionRatio to validate
that the tree argument is not null (throw ArgumentNullException or return a
sensible default like 1.0 consistently), then proceed to sum lengths from
tree.LeafValues, tree.SplitPoints and tree.LeafCounts as before; also add a
brief inline comment inside EstimateCompressionRatio noting that the calculation
treats doubles and ints equally as an approximation so callers are aware.
- Around line 276-297: Validate constructor inputs for CompressedTree by
guarding against nulls and invalid contents: in the CompressedTree constructor
check that splitPoints, leafValues, and leafCounts are not null and throw
ArgumentNullException if any are; also validate that none of the dictionaries
contain null values (e.g., any value arrays are non-null) and throw
ArgumentException describing which parameter is invalid; ensure the property
assignments (SplitPoints, LeafValues, LeafCounts) only happen after these checks
so the instance cannot be created in an invalid state.
- Around line 71-98: The public method Compress should validate its input and
throw an ArgumentNullException when parameterDelta is null; add a null-check at
the start of the Compress method (in class FedDTCompressor) that throws new
ArgumentNullException(nameof(parameterDelta)) before any access to
parameterDelta (e.g., before the foreach) so callers get a clear error instead
of a NullReferenceException while preserving existing behavior that builds and
returns a CompressedTree.
- Around line 149-189: Add null validation at the start of the public method
Decompress(CompressedTree tree, Dictionary<string, T[]> templateDelta): check if
tree is null and if templateDelta is null and throw ArgumentNullException (or
appropriate) naming the offending parameter. Update any callers/tests if they
rely on null inputs; leave the existing logic for reconstructing layers intact
(references: Decompress, CompressedTree, templateDelta, tree).
- Around line 198-235: MergeTrees is doing Decompress inside the inner (layer ×
client) loop causing L×C decompressions and allocations; instead, decompress
once per client and reuse the result. Specifically, for each clientId in
clientTrees call Decompress(tree, templateDelta) once, cache the returned
Dictionary<string, T[]> (e.g., decompressedPerClient[clientId]) and then in the
outer loop over templateDelta look up layer values from that cached dictionary;
remove the per-iteration new Dictionary<string, T[]> allocation and keep
accumulation into merged using clientWeights as currently done, then convert to
T[] as before.
- Around line 127-141: The code computes a median split value but actually
partitions by index in BuildTree (using start/mid/end), so either implement
value-based partitioning or remove the dead split-value work; to minimize
changes, delete the median computation and splits.Add(splitVal) and update the
comment in BuildTree to state that partitioning is index-based (spatial split of
parameter vector), and ensure CompressedTree.SplitPoints is no longer
populated/relied upon (or documented as unused) so Decompress continues to rely
on leafCounts; keep references to BuildTree, CompressedTree.SplitPoints,
Decompress, leafValues and leafCounts in your edits.

In `@src/FederatedLearning/ContinualLearning/DataFreeFCL.cs`:
- Line 34: The private field _accumulatedImportance in DataFreeFCL is mutated by
ComputeImportance and needs thread-safety and a reset mechanism: protect all
reads/writes to _accumulatedImportance with a dedicated lock object (e.g., a
private readonly object _importanceLock) or use Interlocked operations when
replacing the Vector<T>, and add a public ResetImportance() method that acquires
the same lock and sets _accumulatedImportance to null (or a zeroed Vector) to
allow reuse between runs; also update the class summary/comments on DataFreeFCL
and the ComputeImportance method to document that importance is accumulated
stateful data that must be reset between experiments.
- Around line 76-127: The parameter taskData in ComputeImportance is never used
which is confusing; update the method to clearly document this by adding an XML
doc comment on ComputeImportance (and/or on the interface
IFederatedContinualLearningStrategy<T> signature) stating that this
implementation is data-free and intentionally ignores taskData, or add an inline
comment and a pragma to suppress unused-parameter warnings if needed; reference
ComputeImportance and taskData so reviewers can find and read the new
doc/comment and ensure callers understand the interface mismatch is intentional.

In `@src/FederatedLearning/Decentralized/DFedBCAProtocol.cs`:
- Around line 78-84: ExtractBlock currently uses fullParameters.Keys.ToList()
which yields non-deterministic ordering across peers; update ExtractBlock to
produce a deterministic, reproducible layer list (e.g., sort the keys via
layerNames = fullParameters.Keys.OrderBy(k => k).ToList()) and explicitly
validate blockIndex (throw or clamp if blockIndex < 0 or blockIndex >=
_numBlocks) before computing layersPerBlock, start, and end so every peer maps
the same blockIndex to the same layer subset; keep existing logic for
layersPerBlock and slicing but base it on the sorted layerNames and validated
blockIndex.
- Around line 57-67: The ImportanceBased branch in SelectBlock currently falls
back to cyclic selection; replace this placeholder with a proper implementation
or fail fast: either (A) implement importance-based selection inside SelectBlock
using the component that supplies importance scores (e.g., query the importance
score provider or array and pick the block with highest/weighted probability
among _numBlocks) and ensure you use _currentBlock and _numBlocks correctly, or
(B) if the importance-score plumbing is not yet available, throw a
NotImplementedException (or ArgumentException) for
BlockSelectionStrategy.ImportanceBased so the code fails fast rather than
silently using cyclic fallback; update any callers/tests as needed.
- Line 26: The SelectBlock implementation currently contains a placeholder for
the ImportanceBased strategy—replace the stub in SelectBlock with a real
importance-based selection algorithm (or remove the ImportanceBased branch
entirely) so it returns deterministic, meaningful block indices; in ExtractBlock
stop relying on dictionary enumeration order and instead produce a deterministic
layer ordering (e.g., sort layer keys or use an explicit layer index list)
before partitioning so all peers map layers to blocks the same way; in
AverageBlock fix the normalization so totalWeight sums only the mixing weights
of the actually participating neighbors/layers (the actual contributors
returned/used in the aggregation) rather than all possible weights to avoid
bias; and if DFedBCAProtocol<T> is not intended as part of the public API,
change its visibility from public to internal to limit surface area.
- Around line 129-153: The denominator totalWeight is computed from
mixingWeights.Values.Sum() and can include neighbors that are not present in
clientBlocks or that don't contribute the current layer, causing biased
normalization in the averaging loop inside the method that builds result from
template; fix by computing a per-layer effective weight sum (e.g.,
effectiveTotal or layerWeightSum) inside the foreach over template using only
neighbors that actually contributed to that layer (use clientBlocks iteration
and GetValueOrDefault/matching neighborId checks like where you compute w =
mixingWeights.GetValueOrDefault(neighborId, 0) and only add w to the per-layer
sum when block.TryGetValue(layerName, out var neighborLayer) is true), then
normalize averaged[i] by this per-layer sum (falling back to 0 if that per-layer
sum is zero) when creating averagedT so the normalization uses only
participating neighbors.

In `@src/FederatedLearning/Trainers/AsyncFedEDTrainer.cs`:
- Around line 30-32: The two shared mutable fields _clientEntropies and
_lastParticipationRound are accessed concurrently and need synchronization:
replace them with thread-safe collections (e.g.,
ConcurrentDictionary<int,double> and ConcurrentDictionary<int,int>) or wrap all
access in a dedicated lock object (e.g., a private readonly object _sync) and
use lock(...) around every read/write in AsyncFedEDTrainer methods that touch
these fields (refer to usages in the methods that perform reads/writes between
lines ~72–173). Ensure adds/updates use atomic operations (TryAdd/TryUpdate or
lock-protected indexers) and any read-modify-write sequences are protected to
avoid race conditions.
- Around line 72-73: Add production-grade input guards to public entry points
(starting with UpdateClientEntropy) that accept external data: validate that
classLosses is not null and has expected length, clientId is non-negative, and
currentRound is >= 0 (or >= last known round if staleness math assumes monotonic
rounds); if validation fails throw appropriate exceptions (ArgumentNullException
/ ArgumentException) or return early, and ensure any staleness calculations
clamp or check for negative results before using them. Locate
UpdateClientEntropy and the other public methods that accept currentRound and
apply the same checks and defensive clamping to prevent NREs and negative
staleness math.
- Around line 176-193: The aggregation uses the first client's layer set as
`template` and always normalizes by global `totalWeight`, which drops layers
present only in other clients and mis-normalizes layers missing from some
clients; instead, build the union of all layer names from `clientUpdates` (not
`template`), iterate that union when creating `merged`, and for each layer
compute a per-layer weight sum from `weights` only over clients that actually
provide that layer; then normalize `merged` by that per-layer weight (falling
back to equal weighting if per-layer weight is zero) and continue using
`NumOps.ToDouble` for conversions so layer coverage and normalization are
correct (apply same fix to the subsequent aggregation block in
AsyncFedEDTrainer.cs).

In `@src/FederatedLearning/Trainers/OneShotFederatedTrainer.cs`:
- Around line 82-88: When returning from the aggregation switch in
OneShotFederatedTrainer, ensure LastEnsembleDiversity is reset whenever
_aggregationMode is not OneShotAggregationMode.EnsembleDistillation to avoid
exposing stale diversity values; update the return branch that calls
AggregateWeightedAverage and AggregateUniform (and the default) to set
LastEnsembleDiversity to its default (null or 0 consistent with its type) before
returning, and apply the same reset at the other aggregation switch location
that calls AggregateEnsembleDistillation (the second occurrence mentioned) so
only the EnsembleDistillation path preserves a computed diversity value.
- Around line 143-147: EnsembleDistillation currently only computes a weighted
average via AggregateWeightedAverage and ignores
DistillationTemperature/DistillationSteps; replace the placeholder by injecting
and invoking a real distiller: define or accept an IDistiller (e.g.,
Distill(ensembleModels, unlabeledDataset, temperature, steps)) and call it from
EnsembleDistillation using the AggregateWeightedAverage result as initialization
and passing DistillationTemperature and DistillationSteps, then return the
distilled model and recorded diversity; if no distiller is available yet, fail
fast by throwing a clear NotImplementedException mentioning EnsembleDistillation
so the missing implementation is explicit.
- Around line 113-114: The loops that use Math.Min(clientLayer.Length,
merged.Length) silently truncate mismatched layer arrays; instead, validate that
clientLayer and merged have identical shapes before merging and reject the
client (or throw a clear exception) when they differ. Locate the loops that
iterate using Math.Min over clientLayer and merged (the one that indexes i and
accesses clientLayer[i] and merged[i]) and replace the truncation logic with an
explicit check (e.g., compare lengths and/or tensor dimensions) that raises an
informative InvalidOperationException or logs and skips the client with details
(client id, layer index, expected vs actual shape); apply the same change to the
second occurrence that currently uses Math.Min so no silent truncation occurs.
- Around line 73-76: Validate inputs at the start of Aggregate: ensure
clientModels and clientSampleCounts are not null and throw/return early if they
are; then build a filtered client list containing only client IDs that exist in
both dictionaries and whose sample count is > 0 (exclude clients missing from
clientSampleCounts rather than defaulting them into the numerator); compute
totalSamples as the sum of these included sample counts and throw/return if
totalSamples == 0; compute each client's weight as clientSampleCounts[id] /
totalSamples and use those weights to do the per-parameter weighted aggregation
over matching parameter arrays in clientModels (also validate matching array
lengths for a given parameter name across included clients and throw if
inconsistent).

In `@src/FederatedLearning/Trainers/SemiAsyncFederatedTrainer.cs`:
- Around line 77-80: ReceiveUpdate currently stores a null-prone reference to
the caller's Dictionary and arrays and captures clientId which ApplyAsyncUpdates
never reads; add a null-check at the start of ReceiveUpdate (throw
ArgumentNullException or handle per project convention) and create a defensive
deep copy of the incoming update: allocate a new Dictionary<string, T[]> and for
each kvp copy the key and clone each T[] (or create new arrays and copy
contents) before constructing PendingUpdate; finally either remove the unused
clientId from PendingUpdate/ReceiveUpdate or mark a TODO/use clientId inside
ApplyAsyncUpdates to avoid dead code (referencing ReceiveUpdate, PendingUpdate,
and ApplyAsyncUpdates).
- Around line 32-36: The _updateBuffer List<T> is not thread-safe; replace it
with a thread-safe collection (e.g.,
System.Collections.Concurrent.ConcurrentQueue<PendingUpdate> or
ConcurrentBag<PendingUpdate>) by changing the field declaration for
_updateBuffer, initializing it in the constructor, and updating ReceiveUpdate to
Enqueue/Add into that concurrent collection; then modify ApplyAsyncUpdates to
atomically drain the queue (e.g., TryDequeue in a loop or use
GetConsumingEnumerable pattern) so it processes all pending updates safely
without races.

---

Outside diff comments:
In `@src/Models/Options/DifferentialPrivacyMode.cs`:
- Around line 6-11: The remarks for DifferentialPrivacyMode currently document
Local, Central, and Both but omit the Shuffle mode; update the XML <remarks> for
the DifferentialPrivacyMode enum to add a fourth bullet describing Shuffle
(briefly explain that a trusted shuffler anonymizes client contributions before
aggregation, offering a middle ground between local and central DP), referencing
the DifferentialPrivacyMode symbol so reviewers can find and verify the new doc
text matches the enum's Shuffle value.

In `@src/Models/Options/FederatedContinualLearningOptions.cs`:
- Around line 33-61: Add the required Golden Pattern elements to
FederatedContinualLearningOptions: implement a public parameterless constructor
FederatedContinualLearningOptions() { } and a copy constructor
FederatedContinualLearningOptions(FederatedContinualLearningOptions other) that
throws ArgumentNullException if other is null and copies Strategy,
RegularizationStrength, FisherSamples, and ProjectionThreshold; update the class
XML <remarks> to include a <para><b>Reference:</b> entry citing foundational
federated continual learning papers (e.g., FedWEIT, FedCurv); and expand each
property’s XML docs (Strategy, RegularizationStrength, FisherSamples,
ProjectionThreshold) to include a <value> describing the property and a
<remarks> containing a <para><b>For Beginners:</b> explanation of what the
property controls.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 893efaa and 191dbea.

📒 Files selected for processing (13)
  • src/FederatedLearning/Compression/FedDTCompressor.cs
  • src/FederatedLearning/ContinualLearning/DataFreeFCL.cs
  • src/FederatedLearning/Decentralized/DFedBCAProtocol.cs
  • src/FederatedLearning/Trainers/AsyncFedEDTrainer.cs
  • src/FederatedLearning/Trainers/OneShotFederatedTrainer.cs
  • src/FederatedLearning/Trainers/SemiAsyncFederatedTrainer.cs
  • src/Models/Options/AdvancedCompressionStrategy.cs
  • src/Models/Options/DecentralizedFederatedOptions.cs
  • src/Models/Options/DifferentialPrivacyMode.cs
  • src/Models/Options/FairnessConstraintType.cs
  • src/Models/Options/FederatedAggregationStrategy.cs
  • src/Models/Options/FederatedAsyncMode.cs
  • src/Models/Options/FederatedContinualLearningOptions.cs

Comment thread src/FederatedLearning/Compression/FedDTCompressor.cs
Comment thread src/FederatedLearning/Compression/FedDTCompressor.cs Outdated
Comment thread src/FederatedLearning/Compression/FedDTCompressor.cs
Comment thread src/FederatedLearning/Compression/FedDTCompressor.cs
Comment thread src/FederatedLearning/Compression/FedDTCompressor.cs
Comment thread src/FederatedLearning/Trainers/OneShotFederatedTrainer.cs Outdated
Comment thread src/FederatedLearning/Trainers/OneShotFederatedTrainer.cs Outdated
Comment thread src/FederatedLearning/Trainers/SemiAsyncFederatedTrainer.cs
Comment thread src/FederatedLearning/Trainers/SemiAsyncFederatedTrainer.cs
Comment thread src/FederatedLearning/Trainers/SemiAsyncFederatedTrainer.cs
…orithms

- FedMA: Full Hungarian algorithm (Jonker-Volgenant) for neuron matching
  with cosine similarity cost matrix and multi-iteration refinement
- ProxyZKPVerifier: SHA-256 commitment verification with deterministic
  serialization, nonce generation, and hash recomputation
- OptimizedPrivateSetAnalytics: Full HyperLogLog with MurmurHash3 for
  cardinality estimation, threshold queries via secret-shared count-min
  sketches, and bias-corrected estimators
- DPFedLoRA: Per-layer noise calibration computing max gradient norm
  across clients per layer for sensitivity-proportional DP noise
- FLoRA: Stacking + truncated SVD re-decomposition via power iteration
  for lossless federated LoRA aggregation per the original paper

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

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

Copilot reviewed 74 out of 76 changed files in this pull request and generated 1 comment.


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

Comment thread src/FederatedLearning/Privacy/ShuffleModelDP.cs Outdated

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

♻️ Duplicate comments (8)
src/FederatedLearning/PSI/OptimizedPrivateSetAnalytics.cs (1)

69-83: ⚠️ Potential issue | 🔴 Critical

Blocking: add complete argument and shape guards on all public boundaries.

Line 69 onward accepts external inputs without consistent null/shape validation, which can throw nondeterministic runtime exceptions (e.g., null item strings, null collections, mismatched sketch/register dimensions). Line 177 also silently truncates mismatched HLL register arrays instead of rejecting invalid input.

Concrete guard pattern to apply
 public int[,] CreateSketch(IEnumerable<string> items)
 {
+    if (items is null) throw new ArgumentNullException(nameof(items));
     var sketch = new int[_sketchDepth, _sketchWidth];
     foreach (var item in items)
     {
+        if (string.IsNullOrWhiteSpace(item))
+            throw new ArgumentException("Items must not contain null/empty values.", nameof(items));
         int hash = GetStableHash(item);
@@
 public int EstimateFrequency(int[,] mergedSketch, string item)
 {
+    if (mergedSketch is null) throw new ArgumentNullException(nameof(mergedSketch));
+    if (mergedSketch.GetLength(0) != _sketchDepth || mergedSketch.GetLength(1) != _sketchWidth)
+        throw new ArgumentException("Merged sketch dimensions must match configured depth/width.", nameof(mergedSketch));
+    if (string.IsNullOrWhiteSpace(item))
+        throw new ArgumentException("Item must not be null or empty.", nameof(item));
@@
 public byte[] MergeHLLRegisters(IReadOnlyList<byte[]> registerSets)
 {
+    if (registerSets is null) throw new ArgumentNullException(nameof(registerSets));
     if (registerSets.Count == 0)
         throw new ArgumentException("No register sets to merge.", nameof(registerSets));
@@
     foreach (var registers in registerSets)
     {
-        for (int i = 0; i < Math.Min(registers.Length, _hllRegisterCount); i++)
+        if (registers is null || registers.Length != _hllRegisterCount)
+            throw new ArgumentException("All HLL register arrays must be non-null and match configured register count.", nameof(registerSets));
+        for (int i = 0; i < _hllRegisterCount; i++)
         {
             if (registers[i] > merged[i]) merged[i] = registers[i];
         }
     }
@@
 public double EstimateCardinality(byte[] registers)
 {
+    if (registers is null) throw new ArgumentNullException(nameof(registers));
+    if (registers.Length != _hllRegisterCount)
+        throw new ArgumentException("Register length must match configured register count.", nameof(registers));

As per coding guidelines: “missing validation of external inputs” is a blocking production-readiness issue.

Also applies to: 91-103, 110-130, 139-160, 167-187, 195-258, 269-312, 322-341

src/FederatedLearning/Adapters/DPFedLoRA.cs (3)

174-189: ⚠️ Potential issue | 🔴 Critical

Blocking: validate totalWeight before normalization.

Line 188 performs 1.0 / totalWeight without guarding zero/negative totals.

Proposed fix
         foreach (var (clientId, adapters) in clipped)
         {
             double w = clientWeights?.GetValueOrDefault(clientId, 1.0) ?? 1.0;
+            if (w < 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(clientWeights), "Client weights must be non-negative.");
+            }
             totalWeight += w;
@@
         }
+        if (totalWeight <= 0)
+        {
+            throw new ArgumentException("Total client weight must be positive.", nameof(clientWeights));
+        }

         var invTotal = NumOps.FromDouble(1.0 / totalWeight);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/FederatedLearning/Adapters/DPFedLoRA.cs` around lines 174 - 189, The code
computes invTotal using 1.0 / totalWeight without validating totalWeight; before
calling NumOps.FromDouble(1.0 / totalWeight) in the block that computes invTotal
and applies it to aggregated, add a guard that checks totalWeight (the variable
accumulated in the foreach) is > 0 (or otherwise non-zero) and handle the
zero/negative case (e.g., log/throw or skip normalization and leave aggregated
as-is) so you never call NumOps.FromDouble with an infinite/NaN divisor; update
the normalization loop that multiplies aggregated[i] by invTotal accordingly
(referencing totalWeight, invTotal, aggregated and NumOps.FromDouble).

196-235: ⚠️ Potential issue | 🔴 Critical

Blocking: DP noise is reseeded each call, repeating the same sequence.

Line 198 creates new Random(_seed) per aggregation call, which reproduces identical noise streams across calls for the same input path. Initialize RNG once per instance (or use a crypto RNG) and reuse it safely.

Proposed fix
-    private readonly int _seed;
+    private readonly int _seed;
+    private readonly Random _noiseRng;
+    private readonly object _noiseLock = new();
@@
         _seed = seed;
+        _noiseRng = new Random(_seed);
@@
-            var rng = new Random(_seed);
             int paramsPerLayer = adapterLen / Math.Max(_numAdaptedLayers, 1);
@@
-                    double u1 = 1.0 - rng.NextDouble();
-                    double u2 = 1.0 - rng.NextDouble();
+                    double u1, u2;
+                    lock (_noiseLock)
+                    {
+                        u1 = 1.0 - _noiseRng.NextDouble();
+                        u2 = 1.0 - _noiseRng.NextDouble();
+                    }
                     double noise = layerNoiseStd * Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Cos(2.0 * Math.PI * u2);
#!/bin/bash
# Verify deterministic per-call seeding and related guard gaps in adapter strategies.
rg -nP --type=cs -C2 'new Random\(_seed\)|start = totalParams - adapterCount|1\.0 / totalWeight|Values\.First\(\)\.Length'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/FederatedLearning/Adapters/DPFedLoRA.cs` around lines 196 - 235, The
aggregation routine currently instantiates new Random(_seed) inside the method
(see usage of new Random(_seed) where _noiseMultiplier is applied), which
reproduces the same Gaussian noise each call; change this to use a single,
long-lived RNG instance (e.g., add a private readonly Random _rng or use
System.Security.Cryptography.RandomNumberGenerator as a field in the DPFedLoRA
class) and reuse it when generating u1/u2 for the Box‑Muller transform instead
of creating Random(_seed) per call; ensure the chosen RNG is thread-safe (or
protect access with a lock) and keep the existing noise scaling logic that
computes layerNoiseStd and applies NumOps.Add to aggregated.

116-121: ⚠️ Potential issue | 🔴 Critical

Blocking: prevent negative start in merge.

Line 120 goes negative when aggregatedAdapters.Length > fullModelParameters.Length, causing invalid indexing at Line 132.

Proposed fix
     public Vector<T> MergeAdapterParameters(Vector<T> fullModelParameters, Vector<T> aggregatedAdapters)
     {
         int totalParams = fullModelParameters.Length;
         int adapterCount = aggregatedAdapters.Length;
+        if (adapterCount > totalParams)
+        {
+            throw new ArgumentException(
+                $"Adapter vector length ({adapterCount}) cannot exceed model parameter length ({totalParams}).",
+                nameof(aggregatedAdapters));
+        }
         int start = totalParams - adapterCount;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/FederatedLearning/Adapters/DPFedLoRA.cs` around lines 116 - 121,
MergeAdapterParameters currently computes start = totalParams - adapterCount
which can be negative when aggregatedAdapters.Length >
fullModelParameters.Length; add a guard in MergeAdapterParameters to validate
sizes before indexing: check that aggregatedAdapters.Length <=
fullModelParameters.Length (or clamp adapterCount to totalParams) and either
throw a clear ArgumentException (including both lengths) or adjust start to 0
and handle the mismatch explicitly, then proceed to copy/assign using start to
avoid invalid indexing where parameters are merged; reference symbols:
MergeAdapterParameters, fullModelParameters.Length, aggregatedAdapters.Length,
totalParams, adapterCount, and start.
src/FederatedLearning/Adapters/FLoRA.cs (2)

97-114: ⚠️ Potential issue | 🔴 Critical

Blocking: guard merge path against adapter/model length mismatch.

Line 101 can make start negative when aggregatedAdapters.Length > fullModelParameters.Length, causing invalid indexing at Line 113.

Proposed fix
     public Vector<T> MergeAdapterParameters(Vector<T> fullModelParameters, Vector<T> aggregatedAdapters)
     {
         int totalParams = fullModelParameters.Length;
         int adapterCount = aggregatedAdapters.Length;
+        if (adapterCount > totalParams)
+        {
+            throw new ArgumentException(
+                $"Adapter vector length ({adapterCount}) cannot exceed model parameter length ({totalParams}).",
+                nameof(aggregatedAdapters));
+        }
         int start = totalParams - adapterCount;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/FederatedLearning/Adapters/FLoRA.cs` around lines 97 - 114, In
MergeAdapterParameters validate that aggregatedAdapters.Length (adapterCount)
does not exceed fullModelParameters.Length (totalParams) before computing start;
if adapterCount > totalParams either throw an ArgumentException (with a clear
message) or handle by clamping/truncating adapters to totalParams, and
return/abort early to avoid start becoming negative and invalid indexing when
copying into merged; ensure you reference fullModelParameters,
aggregatedAdapters, start, adapterCount and totalParams in the guard so the
merge loop and subsequent NumOps.Multiply loop cannot run with a negative start.

50-77: ⚠️ Potential issue | 🟠 Major

Validate all constructor hyperparameters before deriving adapter geometry.

Line 53 accepts non-positive alpha, and Lines 54–56 accept non-positive layer topology values. That can produce invalid AdapterParameterCount and unstable downstream indexing behavior. Add explicit guards and checked arithmetic.

Proposed fix
     public FLoRA(
         int modelDim,
         int rank = 8,
         double alpha = 16.0,
         int numAdaptedLayers = 4,
         int layerInputDim = 768,
         int layerOutputDim = 768)
     {
@@
         if (rank <= 0)
         {
             throw new ArgumentOutOfRangeException(nameof(rank), "Rank must be positive.");
         }
+        if (alpha <= 0)
+        {
+            throw new ArgumentOutOfRangeException(nameof(alpha), "Alpha must be positive.");
+        }
+        if (numAdaptedLayers <= 0)
+        {
+            throw new ArgumentOutOfRangeException(nameof(numAdaptedLayers), "Number of adapted layers must be positive.");
+        }
+        if (layerInputDim <= 0)
+        {
+            throw new ArgumentOutOfRangeException(nameof(layerInputDim), "Layer input dimension must be positive.");
+        }
+        if (layerOutputDim <= 0)
+        {
+            throw new ArgumentOutOfRangeException(nameof(layerOutputDim), "Layer output dimension must be positive.");
+        }
@@
-        int paramsPerLayer = _layerOutputDim * _rank + _rank * _layerInputDim;
-        AdapterParameterCount = _numAdaptedLayers * paramsPerLayer;
+        int paramsPerLayer = checked(_layerOutputDim * _rank + _rank * _layerInputDim);
+        AdapterParameterCount = checked(_numAdaptedLayers * paramsPerLayer);
As per coding guidelines, production-ready code must validate external inputs at boundaries.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/FederatedLearning/Adapters/FLoRA.cs` around lines 50 - 77, Validate all
constructor hyperparameters at the start of the FLoRA constructor: ensure alpha
> 0, numAdaptedLayers > 0, layerInputDim > 0, and layerOutputDim > 0 and throw
ArgumentOutOfRangeException with the parameter name if any are invalid; then
compute paramsPerLayer and AdapterParameterCount using checked arithmetic (e.g.,
checked(...) or checked context) when calculating _layerOutputDim * _rank +
_rank * _layerInputDim and when multiplying by _numAdaptedLayers to prevent
overflow; finally compute CompressionRatio as (double)AdapterParameterCount /
_modelDim (after validating _modelDim > 0).
src/FederatedLearning/Verification/ProxyZKPVerifier.cs (2)

136-178: ⚠️ Potential issue | 🔴 Critical

BLOCKING: Nonce-less Verify can return success without cryptographic commitment verification.

This path performs only bounds checks and can return IsValid=true for any non-empty commitment. For a method named Verify, this is an incomplete security path and should not pass as verified.

Concrete fix
-    /// <summary>
-    /// Overload for backward compatibility — verifies without nonce (commitment-only check skipped
-    /// if nonce is unavailable, but norm/element checks still apply).
-    /// </summary>
-    public ProxyVerificationResult Verify(Dictionary<string, T[]> update, string commitment)
-    {
-        if (string.IsNullOrEmpty(commitment))
-        {
-            return new ProxyVerificationResult(false, "Missing commitment hash.");
-        }
-
-        double totalNorm2 = 0;
-        foreach (var kvp in update)
-        {
-            for (int i = 0; i < kvp.Value.Length; i++)
-            {
-                double v = NumOps.ToDouble(kvp.Value[i]);
-                ...
-            }
-        }
-
-        double norm = Math.Sqrt(totalNorm2);
-        if (norm > _maxNorm)
-        {
-            return new ProxyVerificationResult(false,
-                $"Update norm {norm:F4} exceeds limit {_maxNorm}.");
-        }
-
-        return new ProxyVerificationResult(true, "Verified (commitment not re-verified without nonce).", commitment, norm);
-    }
+    /// <summary>
+    /// Legacy overload retained for compatibility.
+    /// Commitment verification requires a nonce; use Verify(update, commitment, nonce).
+    /// </summary>
+    [Obsolete("Nonce-less verification cannot verify commitments. Use Verify(update, commitment, nonce).")]
+    public ProxyVerificationResult Verify(Dictionary<string, T[]> update, string commitment)
+    {
+        return new ProxyVerificationResult(false,
+            "Nonce is required for commitment verification. Use Verify(update, commitment, nonce).");
+    }

As per coding guidelines: "Incomplete features ... where some code paths work but others silently do nothing" are blocking.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/FederatedLearning/Verification/ProxyZKPVerifier.cs` around lines 136 -
178, The Verify overload in ProxyZKPVerifier.cs (method
Verify(Dictionary<string, T[]> update, string commitment)) currently only does
bounds checks and returns a successful ProxyVerificationResult even though it
does not perform cryptographic commitment/nonce verification; change this so
Verify does not report success when it cannot re-verify the commitment: either
(preferred) make this overload return a failing ProxyVerificationResult (e.g.,
false with a message like "Cannot verify commitment without nonce") whenever the
cryptographic commitment/nonce path cannot be executed, or have it call the full
Verify that accepts the nonce (or a helper that performs commitment
verification) and propagate its result; update any callers/tests accordingly so
no code path silently returns IsValid=true without actual commitment
verification.

60-63: ⚠️ Potential issue | 🔴 Critical

BLOCKING: Missing input-shape guards can crash verifier methods on malformed external input.

update/layer arrays are assumed non-null in multiple public entry points and in serialization. A null dictionary or null layer value can still throw at runtime instead of returning a deterministic validation result.

Concrete fix
+    private static string? ValidateUpdateShape(Dictionary<string, T[]>? update)
+    {
+        if (update is null || update.Count == 0)
+            return "Missing update.";
+
+        foreach (var kvp in update)
+        {
+            if (string.IsNullOrWhiteSpace(kvp.Key))
+                return "Layer name is required.";
+            if (kvp.Value is null)
+                return $"Layer '{kvp.Key}' parameter array is null.";
+        }
+
+        return null;
+    }

     public string ComputeCommitment(Dictionary<string, T[]> update, byte[] nonce)
     {
+        var updateError = ValidateUpdateShape(update);
+        if (updateError is not null)
+            throw new ArgumentException(updateError, nameof(update));
+        if (nonce is null || nonce.Length == 0)
+            throw new ArgumentException("Missing nonce.", nameof(nonce));
+
         byte[] updateBytes = SerializeUpdate(update);
         ...
     }

     public ProxyVerificationResult Verify(Dictionary<string, T[]> update, string commitment, byte[] nonce)
     {
+        var updateError = ValidateUpdateShape(update);
+        if (updateError is not null)
+            return new ProxyVerificationResult(false, updateError);
+
         // Check 1: Commitment must be present.
         ...
     }

As per coding guidelines: production-ready code must avoid "missing validation of external inputs."

Also applies to: 80-81, 103-106, 140-150, 193-201

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/FederatedLearning/Verification/ProxyZKPVerifier.cs` around lines 60 - 63,
Add explicit null/shape validation at the start of all public verifier entry
points that accept the update dictionary or layer arrays (e.g.,
ComputeCommitment and SerializeUpdate) so malformed external input cannot cause
a runtime crash: check that the update Dictionary itself is non-null, that it
contains no null keys or null value arrays, and that each layer array has
expected length/shape; return a deterministic validation result (e.g., throw an
ArgumentException/ArgumentNullException or return a defined error string/status)
rather than letting subsequent code dereference nulls. Apply the same guards to
the other public methods that consume update/layer arrays (the methods covering
the ranges noted in the review) so all callers get consistent, safe failure
behavior on bad input.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/FederatedLearning/Adapters/DPFedLoRA.cs`:
- Around line 146-167: The code assumes all client adapter vectors have the same
length (adapterLen) but only reads it from the first entry; before
clipping/aggregation (i.e., at the start of the loop over clientAdapters in
DPFedLoRA), validate that each adapters.Length equals adapterLen and throw a
clear ArgumentException (or return an error) if any mismatch is found, so you
won't index out of bounds when creating clippedAdapter and multiplying elements;
alternatively, if heterogenous lengths are acceptable, allocate clippedAdapter
using adapters.Length for each client and adjust subsequent aggregation logic to
handle variable-length vectors consistently.
- Around line 53-97: The DPFedLoRA constructor must validate alpha,
numAdaptedLayers, layerInputDim, and layerOutputDim and use checked arithmetic
for derived counts: add ArgumentOutOfRangeException guards ensuring alpha > 0,
numAdaptedLayers > 0, layerInputDim > 0 and layerOutputDim > 0 (using nameof for
each), then compute paramsPerLayer and AdapterParameterCount inside a checked
context (or using checked(...) expressions) to surface overflow issues when
calculating paramsPerLayer = _layerOutputDim * _rank + _rank * _layerInputDim
and AdapterParameterCount = _numAdaptedLayers * paramsPerLayer; leave
CompressionRatio logic but ensure it uses the validated values.

In `@src/FederatedLearning/Adapters/FLoRA.cs`:
- Around line 127-170: The code assumes all client adapter arrays match the
first client's length and divides by totalWeight without guarding zero; update
the aggregation in AggregateAdapters (use clientAdapters, adapterLen,
totalWeight, normalizedW, layerOffset, paramsPerLayer) to: first validate every
client's adapter length matches adapterLen and throw or skip mismatched clients;
compute totalWeight only over validated clients and if totalWeight <= 0
return/throw early; when iterating use each client's actual adapter array (not
assuming first length) and guard indexing by checking layerOffset +
paramsPerLayer <= adapters.Length before accessing B/A values so you never index
out of range; finally recompute normalizedW = w / totalWeight using the
validated totalWeight.

In `@src/FederatedLearning/Aggregators/FedMaAggregationStrategy.cs`:
- Around line 229-260: EstimateNeuronCount incorrectly treats all tensors as
[out×in] dense weight matrices (so biases and conv/attention tensors are
misclassified); update the function to handle layer-type hints or naming
conventions: detect tensor role by key/name suffixes like ".bias" and skip or
return 1 for biases, treat convolution and attention parameter names (e.g.,
containing "conv", "conv2d", "weight" with rank>2, "query", "key", "value",
"proj") differently (either skip heuristic or use configurable per-layer neuron
counts), and add an optional parameter or config map (e.g., layerTypeHints or
neuronCountOverrides) that FedMaAggregationStrategy can consult; modify
EstimateNeuronCount, its callers, and the code that builds model layer entries
to pass the hint/override so biases and non-dense tensors are not
misinterpreted.
- Around line 359-361: GetStrategyName currently embeds a non-ASCII character
(τ) which can cause encoding/logging issues; change the formatted string in
GetStrategyName to use an ASCII-safe label such as "thresh" or "t" (e.g.
$"FedMA(iters={_matchingIterations},thresh={_matchingThreshold})") so references
to _matchingIterations and _matchingThreshold remain but the output is
ASCII-safe.
- Around line 60-63: The single-client fast path in FedMaAggregationStrategy
returns clientModels.First().Value directly, exposing the original model to
mutation; change this to return a defensive copy instead (e.g., var model =
clientModels.First().Value; return model.Clone();), or if no Clone() exists
implement/call the model's copy constructor or a deep-copy helper (serialization
or utility method) to produce and return a new instance; update the code path
where clientModels.Count == 1 to use that clone/deep-copy so callers cannot
mutate the original client model.
- Around line 155-167: The current per-neuron threshold fallback breaks the
bijection by overriding srcNeuron inside the loop (see variables neuronCount,
assignment, costMatrix, _matchingThreshold, clientParams, permutedParams,
neuronSize in FedMaAggregationStrategy), so instead evaluate all similarities
first and if any sim < _matchingThreshold for any i then abandon the permutation
for this layer and perform an identity copy of the whole layer (copy
clientParams into permutedParams unchanged) to preserve bijection; otherwise
proceed to apply the assignment mapping exactly as returned by the Hungarian
algorithm.
- Around line 211-227: The CosineSimilarity method repeatedly calls
MathHelper.GetNumericOperations<T>(), causing heavy redundant lookups; change
the design so MatchAndPermute (or the caller building costMatrix) calls
MathHelper.GetNumericOperations<T>() once and passes the resulting
INumericOperations<T> (or cached value) into CosineSimilarity (e.g., add a
parameter like numOps or numericOps) or store it at class level, then update
CosineSimilarity to use that passed/cached numOps instead of calling
GetNumericOperations<T>() inside the loop and adjust all call sites (e.g., where
costMatrix[i,j] is set) to supply the pre-fetched numOps.

In `@src/FederatedLearning/PSI/OptimizedPrivateSetAnalytics.cs`:
- Around line 40-43: Constructor currently accepts any positive sketchWidth but
ComputeBucketIndex uses bitmasking with _sketchWidth-1, which requires a
power-of-two width; update the OptimizedPrivateSetAnalytics constructor to
validate that sketchWidth is a power of two (e.g., check (sketchWidth &
(sketchWidth - 1)) == 0) and throw an
ArgumentException/ArgumentOutOfRangeException with a clear message if it is not,
referencing the parameter name sketchWidth and the private field _sketchWidth so
callers cannot instantiate the class with a non-power-of-two width that would
break ComputeBucketIndex.

In `@src/FederatedLearning/Verification/ProxyZKPVerifier.cs`:
- Around line 185-190: The GenerateNonce method currently allocates a byte array
without validating the length parameter; add an explicit guard at the start of
GenerateNonce(int length = 32) that checks if length <= 0 and throws an
ArgumentOutOfRangeException (mentioning the parameter name "length") to prevent
invalid array sizes, then proceed with the existing
RandomNumberGenerator.Create() usage and nonce population; ensure the thrown
exception type is ArgumentOutOfRangeException and include a clear message or use
the constructor that takes the parameter name.
- Around line 197-201: The variable totalParams and its pre-pass loop over
sortedKeys in ProxyZKPVerifier.cs are dead code; either remove the totalParams
declaration and the foreach loop entirely, or if the intent was to validate the
update size, use totalParams to assert/validate against the expected parameter
count (e.g., compare totalParams to an expectedModelSize or throw/return an
error) inside the same method in class ProxyZKPVerifier (the block referencing
sortedKeys and update). Make the change consistently: delete the unused variable
and loop if not needed, or wire totalParams into the verification logic to
enforce a size check.

---

Duplicate comments:
In `@src/FederatedLearning/Adapters/DPFedLoRA.cs`:
- Around line 174-189: The code computes invTotal using 1.0 / totalWeight
without validating totalWeight; before calling NumOps.FromDouble(1.0 /
totalWeight) in the block that computes invTotal and applies it to aggregated,
add a guard that checks totalWeight (the variable accumulated in the foreach) is
> 0 (or otherwise non-zero) and handle the zero/negative case (e.g., log/throw
or skip normalization and leave aggregated as-is) so you never call
NumOps.FromDouble with an infinite/NaN divisor; update the normalization loop
that multiplies aggregated[i] by invTotal accordingly (referencing totalWeight,
invTotal, aggregated and NumOps.FromDouble).
- Around line 196-235: The aggregation routine currently instantiates new
Random(_seed) inside the method (see usage of new Random(_seed) where
_noiseMultiplier is applied), which reproduces the same Gaussian noise each
call; change this to use a single, long-lived RNG instance (e.g., add a private
readonly Random _rng or use System.Security.Cryptography.RandomNumberGenerator
as a field in the DPFedLoRA class) and reuse it when generating u1/u2 for the
Box‑Muller transform instead of creating Random(_seed) per call; ensure the
chosen RNG is thread-safe (or protect access with a lock) and keep the existing
noise scaling logic that computes layerNoiseStd and applies NumOps.Add to
aggregated.
- Around line 116-121: MergeAdapterParameters currently computes start =
totalParams - adapterCount which can be negative when aggregatedAdapters.Length
> fullModelParameters.Length; add a guard in MergeAdapterParameters to validate
sizes before indexing: check that aggregatedAdapters.Length <=
fullModelParameters.Length (or clamp adapterCount to totalParams) and either
throw a clear ArgumentException (including both lengths) or adjust start to 0
and handle the mismatch explicitly, then proceed to copy/assign using start to
avoid invalid indexing where parameters are merged; reference symbols:
MergeAdapterParameters, fullModelParameters.Length, aggregatedAdapters.Length,
totalParams, adapterCount, and start.

In `@src/FederatedLearning/Adapters/FLoRA.cs`:
- Around line 97-114: In MergeAdapterParameters validate that
aggregatedAdapters.Length (adapterCount) does not exceed
fullModelParameters.Length (totalParams) before computing start; if adapterCount
> totalParams either throw an ArgumentException (with a clear message) or handle
by clamping/truncating adapters to totalParams, and return/abort early to avoid
start becoming negative and invalid indexing when copying into merged; ensure
you reference fullModelParameters, aggregatedAdapters, start, adapterCount and
totalParams in the guard so the merge loop and subsequent NumOps.Multiply loop
cannot run with a negative start.
- Around line 50-77: Validate all constructor hyperparameters at the start of
the FLoRA constructor: ensure alpha > 0, numAdaptedLayers > 0, layerInputDim >
0, and layerOutputDim > 0 and throw ArgumentOutOfRangeException with the
parameter name if any are invalid; then compute paramsPerLayer and
AdapterParameterCount using checked arithmetic (e.g., checked(...) or checked
context) when calculating _layerOutputDim * _rank + _rank * _layerInputDim and
when multiplying by _numAdaptedLayers to prevent overflow; finally compute
CompressionRatio as (double)AdapterParameterCount / _modelDim (after validating
_modelDim > 0).

In `@src/FederatedLearning/Verification/ProxyZKPVerifier.cs`:
- Around line 136-178: The Verify overload in ProxyZKPVerifier.cs (method
Verify(Dictionary<string, T[]> update, string commitment)) currently only does
bounds checks and returns a successful ProxyVerificationResult even though it
does not perform cryptographic commitment/nonce verification; change this so
Verify does not report success when it cannot re-verify the commitment: either
(preferred) make this overload return a failing ProxyVerificationResult (e.g.,
false with a message like "Cannot verify commitment without nonce") whenever the
cryptographic commitment/nonce path cannot be executed, or have it call the full
Verify that accepts the nonce (or a helper that performs commitment
verification) and propagate its result; update any callers/tests accordingly so
no code path silently returns IsValid=true without actual commitment
verification.
- Around line 60-63: Add explicit null/shape validation at the start of all
public verifier entry points that accept the update dictionary or layer arrays
(e.g., ComputeCommitment and SerializeUpdate) so malformed external input cannot
cause a runtime crash: check that the update Dictionary itself is non-null, that
it contains no null keys or null value arrays, and that each layer array has
expected length/shape; return a deterministic validation result (e.g., throw an
ArgumentException/ArgumentNullException or return a defined error string/status)
rather than letting subsequent code dereference nulls. Apply the same guards to
the other public methods that consume update/layer arrays (the methods covering
the ranges noted in the review) so all callers get consistent, safe failure
behavior on bad input.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 191dbea and 8529282.

📒 Files selected for processing (5)
  • src/FederatedLearning/Adapters/DPFedLoRA.cs
  • src/FederatedLearning/Adapters/FLoRA.cs
  • src/FederatedLearning/Aggregators/FedMaAggregationStrategy.cs
  • src/FederatedLearning/PSI/OptimizedPrivateSetAnalytics.cs
  • src/FederatedLearning/Verification/ProxyZKPVerifier.cs

Comment thread src/FederatedLearning/Adapters/DPFedLoRA.cs
Comment thread src/FederatedLearning/Adapters/DPFedLoRA.cs
Comment thread src/FederatedLearning/Adapters/FLoRA.cs
Comment thread src/FederatedLearning/Aggregators/FedMaAggregationStrategy.cs
Comment thread src/FederatedLearning/Aggregators/FedMaAggregationStrategy.cs
Comment thread src/FederatedLearning/Aggregators/FedMaAggregationStrategy.cs
Comment thread src/FederatedLearning/Aggregators/FedMaAggregationStrategy.cs
Comment thread src/FederatedLearning/PSI/OptimizedPrivateSetAnalytics.cs
Comment thread src/FederatedLearning/Verification/ProxyZKPVerifier.cs
Comment thread src/FederatedLearning/Verification/ProxyZKPVerifier.cs Outdated
franklinic and others added 2 commits February 27, 2026 13:00
… strategies

- MOON: contrastive loss with cosine similarity, temperature scaling,
  previous representation tracking per client, numerically stable log-sum-exp
- FedNTD: not-true distillation loss masking out true class before KL
  divergence, temperature-scaled softmax, batch processing support
- FedLC: logit calibration with class distribution tracking, batch
  calibration, helper to compute distributions from labels
- FedDecorr: decorrelation loss computing correlation matrix C = X^T*X/N
  and squared Frobenius norm ||C - I||_F^2, diagnostic correlation method
- FedAlign: feature alignment with L2, CKA, and MMD distance metrics,
  anchor input management, median bandwidth for RBF kernel
- FedSAM: full SAM perturbation with all 5 variants (Base, FedSMOO,
  FedSpeed, FedLESAM, FedSCAM), gradient history for approximation,
  variant-specific hyperparameters

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d BOBA

DnC: orthogonal projection via Gram-Schmidt, top singular vector via
power iteration on A^T*A, iterative one-at-a-time outlier removal with
recomputed spectral analysis each round.

FLAME: HDBSCAN-inspired clustering using pairwise cosine distances,
core distances, mutual reachability distances, Prim's MST, and
largest-gap cluster extraction instead of static threshold.

BOBA: two-class Bayesian mixture model (honest vs Byzantine) with
full EM algorithm, cross-round belief propagation, numerically stable
log-space posteriors, and proper variance estimation.

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

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

Copilot reviewed 79 out of 81 changed files in this pull request and generated 5 comments.


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

Comment thread src/FederatedLearning/Personalization/PersonalizedFederatedLearning.cs Outdated
Comment thread src/FederatedLearning/Trainers/BufferedAsyncFederatedTrainer.cs
Comment thread src/FederatedLearning/Decentralized/TimeVaryingTopology.cs Outdated
Comment thread src/FederatedLearning/Fairness/FedFairOptimizer.cs
Comment thread src/FederatedLearning/Personalization/PersonalizedFederatedLearning.cs Outdated
…ent, options, tests)

DataFreeFCL: thread-safe _accumulatedImportance with lock, doc unused taskData param,
guard zero totalWeight in AggregateImportance.

OpenFedLLMPipeline: defensive copy for LastCheckpoint property, fix totalWeight to
include default weights for missing clients and guard divide-by-zero.

FederatedRLHF: Guard.NotNull + array-length validation on ComputePPOLoss and
ComputeRewardsWithKLPenalty.

AdvancedCompressionOptions, AsyncFederatedLearningOptions, DecentralizedFederatedOptions,
FederatedPersonalizationOptions: add <value> and <remarks> with For Beginners sections
to new properties.

InMemoryFederatedTrainer: handle FederatedCompressionStrategy.Advanced in CompressDelta
by falling back to TopK.

Tests: restore unknown compression strategy test (C# enums can hold undeclared values),
fix PersonalizedFederatedLearningTests to use enum values instead of strings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nalization)

PersonalizedFederatedLearning: use deterministic ordinal sort instead of unreliable
dictionary enumeration order for LastN layer selection; update enum doc to match.

TimeVaryingTopology: cache topology per round so GetMixingWeight uses same neighbor
set as GetPeers; eliminate non-atomic _roundCounter-- race condition.

BufferedAsyncFederatedTrainer: guard totalWeight <= 0 from staleness discount underflow,
fall back to uniform weights.

FedFairOptimizer: compute totalSamples from clientIds with same GetValueOrDefault(id,1)
logic so default weights for missing clients are properly counted.

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

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

Copilot reviewed 80 out of 82 changed files in this pull request and generated 8 comments.


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

Comment thread src/FederatedLearning/Personalization/KNNPersonalization.cs
Comment thread src/FederatedLearning/Personalization/FedRoDPersonalization.cs Outdated
Comment thread src/FederatedLearning/Personalization/FedBABUPersonalization.cs Outdated
Comment thread src/FederatedLearning/Personalization/FedCPPersonalization.cs Outdated
Comment thread src/FederatedLearning/ContinualLearning/FedCILContinualLearning.cs
Comment thread src/FederatedLearning/Trainers/BufferedAsyncFederatedTrainer.cs
Comment thread src/FederatedLearning/Trainers/BufferedAsyncFederatedTrainer.cs

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

Caution

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

⚠️ Outside diff range comments (2)
src/Models/Options/DecentralizedFederatedOptions.cs (2)

6-22: 🧹 Nitpick | 🔵 Trivial

Minor: Consider adding explicit integer values to DecentralizedTopologyType for serialization stability.

The new enum members extend DecentralizedTopologyType, but unlike BlockSelectionMode, they don't have explicit integer values. If these values are ever serialized/persisted, adding explicit values prevents breaking changes if members are reordered.

💡 Optional: Add explicit values for serialization stability
 public enum DecentralizedTopologyType
 {
     /// <summary>Gossip — randomized peer selection each round.</summary>
-    Gossip,
+    Gossip = 0,
     /// <summary>Ring AllReduce — bandwidth-optimal ring-based averaging.</summary>
-    RingAllReduce,
+    RingAllReduce = 1,
     /// <summary>DFedAvgM — decentralized averaging with momentum for faster convergence. (Sun et al., TMLR 2023)</summary>
-    DFedAvgM,
+    DFedAvgM = 2,
     /// <summary>DFedBCA — block coordinate ascent with partial model sharing per round. (2024)</summary>
-    DFedBCA,
+    DFedBCA = 3,
     /// <summary>DeTAG — gradient tracking for exact convergence in decentralized non-convex optimization. (Li et al., 2023)</summary>
-    DeTAG,
+    DeTAG = 4,
     /// <summary>Segmented gossip — exchange only model segments per round for bandwidth efficiency. (Bellet et al., 2024)</summary>
-    SegmentedGossip,
+    SegmentedGossip = 5,
     /// <summary>Time-varying topology — dynamic graph that changes each round for better mixing. (2024)</summary>
-    TimeVarying
+    TimeVarying = 6
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Models/Options/DecentralizedFederatedOptions.cs` around lines 6 - 22, The
enum DecentralizedTopologyType lacks explicit integer values which can break
serialized/persisted representations if members are reordered; update the
DecentralizedTopologyType declaration to assign explicit integer values to each
member (e.g., start from 0 and increment consistently for Gossip, RingAllReduce,
DFedAvgM, DFedBCA, DeTAG, SegmentedGossip, TimeVarying) preserving the current
ordering so existing serialized data remains stable and mirror the approach used
in BlockSelectionMode.

32-55: ⚠️ Potential issue | 🔴 Critical

BLOCKING: Missing required default and copy constructors per Golden Pattern.

The DecentralizedFederatedOptions class is missing both the required parameterless default constructor and the copy constructor. Per the coding guidelines, every Options class MUST have:

  1. A parameterless constructor: public DecentralizedFederatedOptions() { }
  2. A copy constructor that copies ALL properties and throws ArgumentNullException if other is null

Additionally, the older properties (Enabled, Topology, GossipFanout, MixingRoundsPerTrainingRound) are missing the required <value> tag and <remarks> with <para><b>For Beginners:</b> sections. The class <remarks> should also include a <para><b>Reference:</b> citing the relevant research papers.

🔧 Proposed fix: Add constructors and complete documentation
 /// <summary>
 /// Configuration options for decentralized (serverless) federated learning.
 /// </summary>
 /// <remarks>
 /// <para><b>For Beginners:</b> Standard FL uses a central server to aggregate models. Decentralized FL
 /// removes this server — nodes communicate directly with each other using peer-to-peer protocols.
 /// This eliminates single point of failure and can be more robust in edge/IoT deployments.</para>
+/// <para><b>Reference:</b> See Sun et al. (TMLR 2023) for DFedAvgM, Li et al. (2023) for DeTAG,
+/// and Bellet et al. (2024) for Segmented Gossip.</para>
 /// </remarks>
 public class DecentralizedFederatedOptions : ModelOptions
 {
+    /// <summary>
+    /// Initializes a new instance of the <see cref="DecentralizedFederatedOptions"/> class with default values.
+    /// </summary>
+    public DecentralizedFederatedOptions()
+    {
+    }
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="DecentralizedFederatedOptions"/> class by copying another instance.
+    /// </summary>
+    /// <param name="other">The instance to copy.</param>
+    /// <exception cref="ArgumentNullException">Thrown when <paramref name="other"/> is null.</exception>
+    public DecentralizedFederatedOptions(DecentralizedFederatedOptions other)
+    {
+        ArgumentNullException.ThrowIfNull(other);
+        Enabled = other.Enabled;
+        Topology = other.Topology;
+        GossipFanout = other.GossipFanout;
+        MixingRoundsPerTrainingRound = other.MixingRoundsPerTrainingRound;
+        DFedAvgMMomentum = other.DFedAvgMMomentum;
+        DFedBCANumBlocks = other.DFedBCANumBlocks;
+        DFedBCASelectionStrategy = other.DFedBCASelectionStrategy;
+        DeTAGLearningRate = other.DeTAGLearningRate;
+        SegmentedGossipNumSegments = other.SegmentedGossipNumSegments;
+        TimeVaryingSeed = other.TimeVaryingSeed;
+    }
+
     /// <summary>
     /// Gets or sets whether decentralized mode is enabled. Default: false.
     /// </summary>
+    /// <value>True to enable decentralized (peer-to-peer) mode; false to use centralized aggregation.</value>
+    /// <remarks>
+    /// <para><b>For Beginners:</b> When enabled, clients communicate directly with each other
+    /// instead of through a central server. This is useful in edge computing scenarios where
+    /// a central server may be unavailable or undesirable.</para>
+    /// </remarks>
     public bool Enabled { get; set; } = false;

     /// <summary>
     /// Gets or sets the topology type. Default: Gossip.
     /// </summary>
+    /// <value>The communication topology used for peer-to-peer model exchange.</value>
+    /// <remarks>
+    /// <para><b>For Beginners:</b> The topology determines how nodes discover and communicate
+    /// with each other. Gossip is simple and robust; RingAllReduce is bandwidth-optimal;
+    /// newer methods like DFedAvgM and DeTAG offer better convergence guarantees.</para>
+    /// </remarks>
     public DecentralizedTopologyType Topology { get; set; } = DecentralizedTopologyType.Gossip;

     /// <summary>
     /// Gets or sets the gossip fanout (number of random peers per round). Default: 2.
     /// </summary>
+    /// <value>Number of peers each node contacts per gossip round. Must be positive.</value>
+    /// <remarks>
+    /// <para><b>For Beginners:</b> Higher fanout means faster information spread but more
+    /// bandwidth usage. A fanout of 2 is a common default that balances speed and efficiency.</para>
+    /// </remarks>
     public int GossipFanout { get; set; } = 2;

     /// <summary>
     /// Gets or sets the number of mixing rounds per training round. Default: 3.
     /// </summary>
+    /// <value>Number of communication rounds between local training steps.</value>
     /// <remarks>
+    /// <para><b>For Beginners:</b> After each local training step, nodes average their models
+    /// with peers multiple times. More mixing improves convergence (models become more similar)
+    /// but increases communication cost.</para>
-    /// More mixing rounds improve convergence but increase communication cost.
     /// </remarks>
     public int MixingRoundsPerTrainingRound { get; set; } = 3;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Models/Options/DecentralizedFederatedOptions.cs` around lines 32 - 55,
Add a parameterless default constructor and a copy constructor on
DecentralizedFederatedOptions (e.g., public DecentralizedFederatedOptions() { }
and public DecentralizedFederatedOptions(DecentralizedFederatedOptions other) {
if (other == null) throw new ArgumentNullException(nameof(other)); Enabled =
other.Enabled; Topology = other.Topology; GossipFanout = other.GossipFanout;
MixingRoundsPerTrainingRound = other.MixingRoundsPerTrainingRound; }) and update
the XML documentation for each property (Enabled, Topology, GossipFanout,
MixingRoundsPerTrainingRound) to include a <value> tag and a <remarks> section
with a <para><b>For Beginners:</b>...</para> plus add a class-level <remarks>
that includes a <para><b>Reference:</b> citing the relevant papers; ensure all
property names used match the class members exactly.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a95360 and 5e73977.

📒 Files selected for processing (66)
  • src/FederatedLearning/Adapters/DPFedLoRA.cs
  • src/FederatedLearning/Adapters/FLoRA.cs
  • src/FederatedLearning/Adapters/FedMeZO.cs
  • src/FederatedLearning/Adapters/FedPETuning.cs
  • src/FederatedLearning/Adapters/FederatedAdapterTuning.cs
  • src/FederatedLearning/Adapters/HierarchicalFedLoRA.cs
  • src/FederatedLearning/Adapters/SparseLoRA.cs
  • src/FederatedLearning/Aggregators/BobaAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/BucketingAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/DivideAndConquerAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FLTrustAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedAaAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedAlignAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedDecorrAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedLcAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedMaAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedNtdAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FedSamAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/FlameAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/MoonAggregationStrategy.cs
  • src/FederatedLearning/Aggregators/OptiGradTrustAggregationStrategy.cs
  • src/FederatedLearning/Alignment/FederatedDPO.cs
  • src/FederatedLearning/Alignment/FederatedRLHF.cs
  • src/FederatedLearning/Alignment/OpenFedLLMPipeline.cs
  • src/FederatedLearning/Compression/FedDTCompressor.cs
  • src/FederatedLearning/Compression/FedKDCompressor.cs
  • src/FederatedLearning/Compression/FetchSGDCompressor.cs
  • src/FederatedLearning/Compression/SignSGDCompressor.cs
  • src/FederatedLearning/Compression/TopKSparsificationCompressor.cs
  • src/FederatedLearning/ContinualLearning/DataFreeFCL.cs
  • src/FederatedLearning/ContinualLearning/FedAGCContinualLearning.cs
  • src/FederatedLearning/ContinualLearning/FedCILContinualLearning.cs
  • src/FederatedLearning/ContinualLearning/FederatedExperienceReplay.cs
  • src/FederatedLearning/Decentralized/DFedAvgMProtocol.cs
  • src/FederatedLearning/Decentralized/DFedBCAProtocol.cs
  • src/FederatedLearning/Decentralized/DeTAGProtocol.cs
  • src/FederatedLearning/Decentralized/SegmentedGossipProtocol.cs
  • src/FederatedLearning/Decentralized/TimeVaryingTopology.cs
  • src/FederatedLearning/Fairness/AgnosticFairnessObjective.cs
  • src/FederatedLearning/Fairness/FedFairOptimizer.cs
  • src/FederatedLearning/Fairness/LightweightShapleyEvaluator.cs
  • src/FederatedLearning/Fairness/QFairFederatedLearning.cs
  • src/FederatedLearning/Fairness/TiltedERMFairness.cs
  • src/FederatedLearning/PSI/OptimizedPrivateSetAnalytics.cs
  • src/FederatedLearning/Personalization/FedAGHNPersonalization.cs
  • src/FederatedLearning/Personalization/FedBABUPersonalization.cs
  • src/FederatedLearning/Personalization/FedCPPersonalization.cs
  • src/FederatedLearning/Personalization/FedPACPersonalization.cs
  • src/FederatedLearning/Personalization/FedRoDPersonalization.cs
  • src/FederatedLearning/Personalization/FedSelectPersonalization.cs
  • src/FederatedLearning/Personalization/KNNPersonalization.cs
  • src/FederatedLearning/Personalization/PFedGatePersonalization.cs
  • src/FederatedLearning/Personalization/PersonalizedFederatedLearning.cs
  • src/FederatedLearning/Privacy/ShuffleModelDP.cs
  • src/FederatedLearning/Trainers/AsyncFedEDTrainer.cs
  • src/FederatedLearning/Trainers/BufferedAsyncFederatedTrainer.cs
  • src/FederatedLearning/Trainers/InMemoryFederatedTrainer.cs
  • src/FederatedLearning/Trainers/OneShotFederatedTrainer.cs
  • src/FederatedLearning/Trainers/SemiAsyncFederatedTrainer.cs
  • src/FederatedLearning/Verification/ProxyZKPVerifier.cs
  • src/Models/Options/AdvancedCompressionOptions.cs
  • src/Models/Options/AsyncFederatedLearningOptions.cs
  • src/Models/Options/DecentralizedFederatedOptions.cs
  • src/Models/Options/FederatedPersonalizationOptions.cs
  • tests/AiDotNet.Tests/FederatedLearning/FederatedLearningInvalidConfigurationTests.cs
  • tests/AiDotNet.Tests/FederatedLearning/PersonalizedFederatedLearningTests.cs

Comment thread src/FederatedLearning/Aggregators/BucketingAggregationStrategy.cs
Comment thread src/FederatedLearning/Aggregators/FedAlignAggregationStrategy.cs
Comment thread src/FederatedLearning/Aggregators/FedDecorrAggregationStrategy.cs
Comment thread src/FederatedLearning/Aggregators/FedLcAggregationStrategy.cs
Comment thread src/FederatedLearning/Aggregators/FedMaAggregationStrategy.cs Outdated
Comment thread src/FederatedLearning/Trainers/OneShotFederatedTrainer.cs
Comment thread src/FederatedLearning/Trainers/OneShotFederatedTrainer.cs
Comment thread src/FederatedLearning/Verification/ProxyZKPVerifier.cs
Comment thread src/FederatedLearning/Verification/ProxyZKPVerifier.cs
Comment thread src/FederatedLearning/Verification/ProxyZKPVerifier.cs

@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.

Review continued from previous batch...

Comment thread src/FederatedLearning/Adapters/DPFedLoRA.cs
Comment thread src/FederatedLearning/Adapters/FedMeZO.cs
Comment thread src/FederatedLearning/Adapters/FedPETuning.cs Outdated
Comment thread src/FederatedLearning/Adapters/FedPETuning.cs
Comment thread src/FederatedLearning/Adapters/HierarchicalFedLoRA.cs
Comment thread src/FederatedLearning/Personalization/FedPACPersonalization.cs
Comment thread src/FederatedLearning/Personalization/FedPACPersonalization.cs Outdated
Comment thread src/FederatedLearning/Personalization/KNNPersonalization.cs
Comment thread src/FederatedLearning/Trainers/InMemoryFederatedTrainer.cs
Comment thread src/FederatedLearning/Trainers/SemiAsyncFederatedTrainer.cs Outdated
- Aggregators: null guards, defensive copies, deep copy for single-client,
  deterministic iteration, non-finite weight validation, threshold consistency
- Compression: error feedback residual fix, shape validation, null guards,
  layer delta validation
- Adapters: model dim validation, checked arithmetic for overflow, adapter
  length validation, crypto RNG documentation
- Privacy: clip-norm noise calibration, strict aggregation validation,
  Laplace fallback for delta=0
- Alignment: client model structure validation, DPO layer validation
- Personalization: gradient length strict checks, weight renormalization,
  deterministic ordering, prototype validation, defensive copies
- Trainers: throw NotSupportedException for unsupported compression,
  defensive copy on buffer submit, weighted barrier aggregation,
  enum/array validation
- Continual Learning: null guards, synthetic param validation,
  NumOps.Zero initialization
- Fairness: non-finite rejection, Shapley zero-norm handling, proper
  tilt anchor
- Verification: commitment validation, certificate constructor guards

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 1, 2026 13:38

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

Copilot reviewed 80 out of 82 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (7)

src/FederatedLearning/Personalization/FedBABUPersonalization.cs:1

  • The head/body split in MaskHeadGradients depends on Dictionary key enumeration order (gradients.Keys.ToArray()), which is not stable across runtimes/targets and can cause the wrong layers to be frozen. Sort the layer names deterministically (e.g., ordinal sort like other personalization utilities in this PR) before computing headStart and applying the mask.
    src/FederatedLearning/Trainers/BufferedAsyncFederatedTrainer.cs:1
  • _currentGlobalRound is written via Interlocked.Increment in AggregateBuffer, but read here without an atomic/volatile read and outside the lock; this can compute inconsistent staleness under concurrency. Read the round using Volatile.Read(ref _currentGlobalRound) (or move the staleness computation inside the same lock that protects the buffer, or use a dedicated atomic access pattern) to make the staleness calculation thread-safe.
    src/FederatedLearning/Trainers/BufferedAsyncFederatedTrainer.cs:1
  • AggregateBuffer derives layerNames and layer lengths solely from snapshot[0]. If later buffered updates contain extra layers (or snapshot[0] is missing a layer), those layers are silently dropped from the aggregation output. Consider validating that all buffered updates have the same layer set/lengths at SubmitUpdate, or compute the union of layer names (and enforce consistent lengths) when aggregating.
    src/FederatedLearning/Decentralized/DFedAvgMProtocol.cs:1
  • neighborModel[layerName] can throw KeyNotFoundException when a neighbor model is missing a layer present in currentModel. Use TryGetValue(layerName, out var np) with a clear exception (or an explicit skip/validation step) to avoid runtime crashes and make layer-schema mismatches diagnosable.
    src/FederatedLearning/Trainers/InMemoryFederatedTrainer.cs:1
  • The NotSupportedException guidance mentions strategy names that don’t match the enum (RandomSparsification, Quantization). This is misleading for users debugging config. Update the message to reference the actual enum values (e.g., RandomK, UniformQuantization, StochasticQuantization) and/or point to AdvancedCompressionStrategy/AdvancedCompressionOptions if that’s the intended configuration surface.
    src/FederatedLearning/Decentralized/TimeVaryingTopology.cs:1
  • GetOrGenerateTopologyForRound mutates _roundCounter, _cachedTopology, and _lastQueriedRound without synchronization. If GetPeers/GetMixingWeight are called concurrently (or re-entrantly), this can produce inconsistent topologies and mixing weights. Consider avoiding mutation by refactoring GenerateTopology to accept an explicit round parameter (no shared state), or guard this block (and cache reads) with a lock.
    src/FederatedLearning/Personalization/FedSelectPersonalization.cs:1
  • The sigmoid computation 1 / (1 + exp(-x)) can overflow/underflow for large-magnitude logits (which can occur after many UpdateMask steps), leading to mask becoming 0/1 unexpectedly or exp overflow. Use a numerically stable sigmoid implementation (branching on sign of logits[i], or clamping logits to a safe range) in all places where sigmoid is computed.

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

Comment thread src/FederatedLearning/Compression/FetchSGDCompressor.cs
Regenerated YAML source generator output after merging master to include
all type registrations from both branches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ooples
ooples merged commit 66f726e into master Mar 1, 2026
34 of 39 checks passed
@ooples
ooples deleted the feat/federated-learning-v3 branch March 1, 2026 20:49
@henry-f

henry-f commented Mar 21, 2026

Copy link
Copy Markdown

are we sure this still works in light of recent events?

This branch was successfully deployed

1 active deployment
Preview — 80aeb56a Deployed Mar 1, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment