Skip to content

Conversation

@squadgazzz
Copy link
Contributor

@squadgazzz squadgazzz commented Dec 24, 2025

Description

One of the prerequisites for integrating the Pod network[more details] is to extract the winner selection logic into a separate crate since the following flow is expected in the future: autopilot sends an auction to all the drivers to solve -> drivers send their solutions to the pod network -> once competition deadline is reached, each driver fetches all submitted solutions from the pod network -> each driver decides whether its solutions are among winning ones. Both driver and autopilot should use the same logic, so a separate crate is introduced in this PR.

Changes

The PR is huge since it mostly moves the code. In any case, I made it as a POC before trying to split it into smaller parts, since this turned out to be non-trivial. I am open to any ideas on how to do this, if ever needed.

  • All the winning selection logic is now extracted to a separate crate, which tries to operate with minimal required data. That is useful for the future integration into the driver. The driver crate should already contain all the required competition data previously sent from autopilot to assess the solutions.
  • Autopilot now uses the new create. I tried to avoid many back-and-forth type conversions, but still, autopilot requires different extended data structures.
  • Winning selection includes a lot of stuff, such as protocol fees computation. Probably, in the future, it will make sense to create a separate crate for protocol fees.
  • The ranking traits are generalized, so the winner-selection crate uses its implementation with its own types, while autopilot continues using the Participant crate.

How to test

Existing tests

@squadgazzz squadgazzz force-pushed the winner-selection-crate branch from 1c8a399 to decca80 Compare December 25, 2025 14:40
@squadgazzz squadgazzz mentioned this pull request Dec 26, 2025
3 tasks
# Conflicts:
#	crates/autopilot/src/domain/competition/participant.rs
#	crates/autopilot/src/domain/competition/winner_selection.rs
@squadgazzz squadgazzz changed the base branch from main to refactor-participant-scores December 26, 2025 15:25
@squadgazzz squadgazzz changed the title Winner selection crate [POC] Winner selection crate Dec 26, 2025
@squadgazzz squadgazzz marked this pull request as ready for review December 26, 2025 18:18
@squadgazzz squadgazzz requested a review from a team as a code owner December 26, 2025 18:18
Copilot AI review requested due to automatic review settings December 26, 2025 18:18
Copy link
Contributor

Copilot AI left a comment

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 extracts winner selection logic into a new standalone winner-selection crate to prepare for Pod network integration. The crate contains minimal data structures and algorithms needed to run winner selection, allowing both autopilot and drivers to use the same logic for determining winning solutions.

Key changes:

  • New winner-selection crate with minimal solution/order data structures optimized for serialization
  • Generalized ranking traits using state markers (Unscored, Scored, Ranked)
  • Autopilot refactored to use the new crate with conversion functions between domain types

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
crates/winner-selection/Cargo.toml Defines new crate with dependencies for winner selection
crates/winner-selection/src/lib.rs Module organization and re-exports for the new crate
crates/winner-selection/src/primitives.rs Core primitive types (OrderUid, Side, FeePolicy, Quote)
crates/winner-selection/src/util.rs Mathematical utility functions for U256 operations
crates/winner-selection/src/state.rs Generic state markers and traits for scoring/ranking
crates/winner-selection/src/solution.rs Minimal solution and order data structures
crates/winner-selection/src/auction.rs Auction context with fee policies and native prices
crates/winner-selection/src/arbitrator.rs Core winner selection algorithm implementation
crates/autopilot/src/domain/competition/winner_selection.rs Refactored to wrap and delegate to new winner-selection crate
crates/autopilot/src/domain/competition/participant.rs Uses generalized state traits from winner-selection
crates/autopilot/src/domain/settlement/trade/mod.rs Removes score computation now handled by winner-selection
crates/autopilot/src/domain/settlement/trade/math.rs Removes score computation logic
crates/autopilot/src/domain/settlement/mod.rs Adds test helpers to verify winner-selection integration
crates/autopilot/src/shadow.rs Updates to use new Arbitrator constructor
crates/autopilot/src/run_loop.rs Updates to use new Arbitrator constructor
crates/autopilot/src/infra/persistence/mod.rs Imports RankedItem trait from winner-selection
crates/autopilot/Cargo.toml Adds winner-selection dependency
Cargo.toml Adds winner-selection workspace member
Cargo.lock Registers new winner-selection crate

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

Comment on lines +28 to +29
let multiplied = self.checked_mul(Self::from(factor * CONVERSION_FACTOR))?
/ Self::from(CONVERSION_FACTOR);
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

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

The conversion factor calculation may lose precision due to floating-point limitations. The value factor * CONVERSION_FACTOR is computed as a floating-point multiplication before being cast to U256. If factor is very small or very large, this could result in precision loss or overflow in floating-point arithmetic before the conversion. Consider checking for edge cases or documenting the valid range of factor values.

Suggested change
let multiplied = self.checked_mul(Self::from(factor * CONVERSION_FACTOR))?
/ Self::from(CONVERSION_FACTOR);
const U256_CONVERSION_FACTOR: U256 = U256::from(1_000_000_000_000_000_000u128);
// Scale the factor in floating point space, but guard against
// non-finite and out-of-range values before converting to U256.
let scaled = factor * CONVERSION_FACTOR;
if !scaled.is_finite() || scaled < 0.0 || scaled > u128::MAX as f64 {
return None;
}
// Round to the nearest integer to preserve as much precision as possible
// when converting from f64 to an integer type.
let scaled_int = scaled.round() as u128;
let multiplied = self.checked_mul(Self::from(scaled_int))? / U256_CONVERSION_FACTOR;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants