Skip to content

feat(arbiter): Implement Byzantine Swarm Protection - #705

Merged
fallofpheonix merged 1 commit into
mainfrom
feature/byzantine-swarm
May 21, 2026
Merged

fallofpheonix merged 1 commit into
mainfrom
feature/byzantine-swarm

Conversation

@fallofpheonix

@fallofpheonix fallofpheonix commented May 21, 2026

Copy link
Copy Markdown
Owner

Closes #673. Implements Proof-of-Authority, node reputation scoring, and weighted quorum consensus for swarm coordination.

Summary by Sourcery

Introduce reputation-weighted quorum calculation for arbiter-based swarm coordination.

New Features:

  • Add Node and Arbiter types to model authorized swarm participants with reputations and quorum thresholds.
  • Implement reputation-weighted quorum calculation that ignores unauthorized nodes.

Tests:

  • Replace minimax test with quorum calculation test cases covering different vote distributions and thresholds.

Copilot AI review requested due to automatic review settings May 21, 2026 13:53
@sourcery-ai

sourcery-ai Bot commented May 21, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a new Arbiter component to handle reputation-weighted quorum decisions and replaces the previous minimax test with tests for quorum calculation.

File-Level Changes

Change Details Files
Introduce Arbiter and Node types to support reputation-weighted quorum calculation with authorization filtering.
  • Define Node struct with ID, Reputation, and Authorized fields to represent swarm participants.
  • Define Arbiter struct containing a slice of Nodes and a QuorumThreshold parameter.
  • Implement CalculateQuorum to aggregate reputation of authorized nodes and compute whether positive votes meet the configured quorum threshold, safely handling zero-total reputations.
phoenix_os/arbiter/src/arbiter.go
Replace minimax game theory test with a unit test for reputation-weighted quorum behavior.
  • Remove TestMiniMax and associated payoff matrix usage from arbiter_test.go.
  • Add TestCalculateQuorum to validate quorum outcomes under different vote distributions and threshold conditions, including negative and positive quorum cases based on node reputations and authorization status.
phoenix_os/arbiter/src/arbiter_test.go

Possibly linked issues

  • [P2] [Phoenix Arbiter] Implement Byzantine Swarm Protection #673: PR implements the Proof-of-Authority, reputation scoring, and weighted quorum consensus requested in the issue.
  • #(unknown): PR introduces Arbiter, Node, and CalculateQuorum implementing weighted, reputation-based quorum as requested for Byzantine protection.
  • #[INTEGRATION] Arbiter: Reputation-Weighted Quorum Implementation: PR introduces Arbiter node reputation and CalculateQuorum, directly implementing reputation-weighted quorum from the issue.

Tips and commands

Interacting with Sourcery

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

Customizing Your Experience

Access your dashboard to:

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

Getting Help

@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@fallofpheonix has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 16 minutes and 3 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d6d79c43-5fea-41e6-9939-658e0a981166

📥 Commits

Reviewing files that changed from the base of the PR and between 2cac688 and 1ca1266.

📒 Files selected for processing (2)
  • phoenix_os/arbiter/src/arbiter.go
  • phoenix_os/arbiter/src/arbiter_test.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/byzantine-swarm

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

❤️ Share

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1ca1266ea5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if totalReputation == 0 {
return false
}
return (positiveReputation / totalReputation) >= a.QuorumThreshold

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Enforce a non-zero quorum threshold

CalculateQuorum fails open when QuorumThreshold is left at its Go zero value (0): with any authorized nodes present, positiveReputation/totalReputation can be 0, and 0 >= 0 returns true. That means a caller that forgets to initialize the threshold can approve quorum even when nobody voted yes, which defeats the safety property this arbiter is meant to enforce.

Useful? React with 👍 / 👎.

Comment on lines +36 to +38
totalReputation += node.Reputation
if vote, ok := votes[node.ID]; ok && vote {
positiveReputation += node.Reputation

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject negative reputation weights in quorum math

The quorum calculation sums raw Reputation values directly into both numerator and denominator without validating sign, so negative weights can distort the ratio (e.g., make it exceed 1, go negative, or let a single negative-weight vote force or block quorum). Since reputation is a free float64, this creates incorrect consensus outcomes whenever any authorized node’s score drops below zero.

Useful? React with 👍 / 👎.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • Consider validating or normalizing QuorumThreshold (e.g., ensuring it’s within [0,1]) when constructing or updating an Arbiter, so CalculateQuorum doesn’t silently accept out-of-range thresholds.
  • It may be worth documenting and/or asserting the behavior when totalReputation == 0 (no authorized nodes or all zero reputation), since always returning false in that case could mask configuration errors.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider validating or normalizing `QuorumThreshold` (e.g., ensuring it’s within [0,1]) when constructing or updating an `Arbiter`, so `CalculateQuorum` doesn’t silently accept out-of-range thresholds.
- It may be worth documenting and/or asserting the behavior when `totalReputation == 0` (no authorized nodes or all zero reputation), since always returning `false` in that case could mask configuration errors.

## Individual Comments

### Comment 1
<location path="phoenix_os/arbiter/src/arbiter.go" line_range="23-25" />
<code_context>
+}
+
+// Arbiter handles quorum and reputation
+type Arbiter struct {
+	Nodes           []Node
+	QuorumThreshold float64
+}
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Validate or constrain QuorumThreshold to avoid surprising behavior

If QuorumThreshold is set <= 0 or > 1, quorum checks could effectively always fail or always pass. Please either clamp this to [0,1] or enforce validation (e.g., in a constructor/setter) so invalid thresholds are rejected early.

Suggested implementation:

```golang
 // Arbiter handles quorum and reputation
type Arbiter struct {
	Nodes           []Node
	QuorumThreshold float64
}

// NewArbiter constructs an Arbiter with a validated quorum threshold.
// QuorumThreshold must be in the (0,1] range; values outside this range will
// cause NewArbiter to return an error.
func NewArbiter(nodes []Node, quorumThreshold float64) (*Arbiter, error) {
	if quorumThreshold <= 0 || quorumThreshold > 1 {
		return nil, fmt.Errorf("quorumThreshold must be in the range (0,1], got %f", quorumThreshold)
	}

	return &Arbiter{
		Nodes:           nodes,
		QuorumThreshold: quorumThreshold,
	}, nil
}

```

1. Ensure `fmt` is imported at the top of `phoenix_os/arbiter/src/arbiter.go`, e.g.:
   `import "fmt"`, or added to the existing import block.
2. Update any existing code that instantiates `Arbiter` via struct literals to instead call `NewArbiter` (or, if you must keep struct literals, make sure they always set a valid `QuorumThreshold`).
3. If there are other constructors or setters for `Arbiter` elsewhere in the file, align them with the same validation logic so `QuorumThreshold` is always constrained to `(0,1]`.
</issue_to_address>

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

Comment on lines +23 to +25
type Arbiter struct {
Nodes []Node
QuorumThreshold float64

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): Validate or constrain QuorumThreshold to avoid surprising behavior

If QuorumThreshold is set <= 0 or > 1, quorum checks could effectively always fail or always pass. Please either clamp this to [0,1] or enforce validation (e.g., in a constructor/setter) so invalid thresholds are rejected early.

Suggested implementation:

 // Arbiter handles quorum and reputation
type Arbiter struct {
	Nodes           []Node
	QuorumThreshold float64
}

// NewArbiter constructs an Arbiter with a validated quorum threshold.
// QuorumThreshold must be in the (0,1] range; values outside this range will
// cause NewArbiter to return an error.
func NewArbiter(nodes []Node, quorumThreshold float64) (*Arbiter, error) {
	if quorumThreshold <= 0 || quorumThreshold > 1 {
		return nil, fmt.Errorf("quorumThreshold must be in the range (0,1], got %f", quorumThreshold)
	}

	return &Arbiter{
		Nodes:           nodes,
		QuorumThreshold: quorumThreshold,
	}, nil
}
  1. Ensure fmt is imported at the top of phoenix_os/arbiter/src/arbiter.go, e.g.:
    import "fmt", or added to the existing import block.
  2. Update any existing code that instantiates Arbiter via struct literals to instead call NewArbiter (or, if you must keep struct literals, make sure they always set a valid QuorumThreshold).
  3. If there are other constructors or setters for Arbiter elsewhere in the file, align them with the same validation logic so QuorumThreshold is always constrained to (0,1].

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR aims to add Byzantine-resistance primitives to the Phoenix Arbiter by introducing node authorization and a reputation-weighted quorum check.

Changes:

  • Added Node and Arbiter types to represent swarm participants and quorum configuration.
  • Implemented Arbiter.CalculateQuorum to compute quorum using reputation-weighted votes from authorized nodes.
  • Replaced the existing minimax unit test with a new quorum unit test.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
phoenix_os/arbiter/src/arbiter.go Adds node/arbiter data structures and implements reputation-weighted quorum calculation.
phoenix_os/arbiter/src/arbiter_test.go Adds tests for the new quorum calculation logic and removes the previous minimax test.

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

Comment on lines +32 to +38
for _, node := range a.Nodes {
if !node.Authorized {
continue
}
totalReputation += node.Reputation
if vote, ok := votes[node.ID]; ok && vote {
positiveReputation += node.Reputation
Comment on lines +41 to +45
if totalReputation == 0 {
return false
}
return (positiveReputation / totalReputation) >= a.QuorumThreshold
}
Comment on lines +15 to +26
// Node represents a participant in the swarm
type Node struct {
ID string
Reputation float64
Authorized bool
}

// Arbiter handles quorum and reputation
type Arbiter struct {
Nodes []Node
QuorumThreshold float64
}
Comment on lines +7 to 15
func TestCalculateQuorum(t *testing.T) {
arbiter := Arbiter{
Nodes: []Node{
{"node1", 1.0, true},
{"node2", 2.0, true},
{"node3", 1.0, false},
},
QuorumThreshold: 0.6,
}
@fallofpheonix
fallofpheonix merged commit 0efada7 into main May 21, 2026
7 of 10 checks passed
@fallofpheonix
fallofpheonix deleted the feature/byzantine-swarm branch May 21, 2026 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P2] [Phoenix Arbiter] Implement Byzantine Swarm Protection

2 participants