Phase 16A: Scheduler Evolution Foundation

Date: 2025-11-23 Phase: 16A - Resource Profiles & Matching Status: Complete ✅ Duration: 1 session (~4 hours)

Overview

Implemented the foundation for ICN's evolution from reactive task claiming (Phase 15) to intelligent, trust-governed distributed scheduling. Phase 16A introduces concrete resource requirements, capacity tracking, and a pluggable placement policy framework.

This is the first of five phases transforming ICN compute into a multi-tier cooperative fabric supporting edge/community/regional workloads with actor migration and per-coop policies.

Motivation

Current State (Phase 15):

  • Tasks broadcast via gossip, first executor with spare capacity claims
  • Only fuel limits specified, no CPU/RAM/GPU requirements
  • No awareness of data locality or network topology
  • Stateless execution (CCL runs once, returns result)

Gap for Vision: ICN's long-term compute architecture requires:

  • Multi-tier fabric: Unified edge/community/regional scheduling
  • Resource awareness: Match tasks to appropriate executors (GPU for ML, etc.)
  • Locality optimization: Minimize data transfer for batch workloads
  • Actor migration: Long-running stateful programs that survive failures
  • Cooperative policies: Per-coop rules enforced at runtime

Phase 16A provides the foundation types for this evolution.

Implementation

1. Scheduler Module (icn-compute/src/scheduler.rs - 700+ lines)

Core Types

ResourceProfile: Concrete task requirements

pub struct ResourceProfile {
    pub cpu_cores: Option<f64>,      // 0.5 = half a core
    pub memory_mb: Option<u64>,
    pub storage_mb: Option<u64>,
    pub network_mbps: Option<f64>,
    pub gpu_spec: Option<GpuSpec>,
    pub duration_estimate: Option<Duration>,
}

// Convenience constructors
ResourceProfile::minimal()                    // 0.1 CPU, 128 MB
ResourceProfile::compute_heavy(4.0, 8192)     // 4 cores, 8 GB
ResourceProfile::gpu(24, "sm_70".into())      // 24 GB GPU

NodeCapacity: Track and reserve resources

pub struct NodeCapacity {
    pub cpu_cores_available: f64,
    pub memory_mb_available: u64,
    pub storage_mb_available: u64,
    pub network_mbps: f64,
    pub gpu_devices: Vec<GpuDevice>,
    pub updated_at: u64,
}

impl NodeCapacity {
    pub fn can_fit(&self, profile: &ResourceProfile) -> bool;
    pub fn reserve(&mut self, profile: &ResourceProfile) -> Result<()>;
    pub fn release(&mut self, profile: &ResourceProfile);
    pub fn available_ratio(&self) -> f64;  // 0.0 = full, 1.0 = empty
}

GpuSpec/GpuDevice: GPU-specific matching

pub struct GpuSpec {
    pub memory_gb: u64,
    pub compute_capability: String,  // "sm_70", "sm_80", etc.
    pub device_count: usize,
}

pub struct GpuDevice {
    pub device_id: String,
    pub memory_gb: u64,
    pub compute_capability: String,
    pub device_name: String,           // "NVIDIA A100"
    pub available: bool,
}

GPU matching compares compute capabilities lexicographically (sm_80 >= sm_70).

Placement Policy Framework

PlacementPolicy Trait: Pluggable scoring algorithms

pub trait PlacementPolicy: Send + Sync {
    fn score_task(
        &self,
        task_hash: &[u8; 32],
        profile: &ResourceProfile,
        submitter: &str,
        node_state: &NodeState,
        trust_score: f64,
    ) -> Option<PlacementOffer>;
}

DefaultPlacementPolicy: Multi-factor scoring

impl PlacementPolicy for DefaultPlacementPolicy {
    fn score_task(...) -> Option<PlacementOffer> {
        // 1. Trust gate (MIN_TRUST_EXECUTE = 0.3)
        if trust_score < self.min_trust { return None; }

        // 2. Capacity check
        if !node_state.capacity.can_fit(profile) { return None; }

        // 3. Compute score (0.0 - 1.0)
        let mut score = 0.0;
        score += (trust_score * 0.4).min(0.4);          // Trust (0.4)
        score += node_state.capacity.available_ratio() * 0.3;  // Capacity (0.3)
        score += (1.0 - queue_penalty) * 0.2;          // Queue (0.2)
        score += rand::thread_rng().gen::<f64>() * 0.1; // Jitter (0.1)

        Some(PlacementOffer { executor, score, cost, estimated_start })
    }
}

Scoring factors:

  • Trust (40%): Higher trust = higher score (respects ICN's trust-first philosophy)
  • Capacity (30%): More available resources = higher score
  • Queue depth (20%): Shorter queue = higher score
  • Random jitter (10%): Break ties, prevent thundering herd

Future Protocol Types

PlacementRequest/PlacementOffer: Gossip-based negotiation (Phase 16B)

pub struct PlacementRequest {
    pub task_hash: [u8; 32],
    pub resource_profile: ResourceProfile,
    pub locality_hints: Vec<LocalityHint>,
    pub max_cost: Option<u64>,
    pub requested_at: u64,
}

pub struct PlacementOffer {
    pub executor: String,
    pub score: f64,              // 0.0 - 1.0
    pub cost: u64,               // Credits per 1000 fuel
    pub estimated_start: u64,
    pub offered_at: u64,
}

LocalityHint: Placement preferences (Phase 16C)

pub enum LocalityHint {
    PreferDid(String),              // Prefer specific executor
    PreferRegion(String),           // Geographic preference
    DataLocality(Vec<[u8; 32]>),   // Near data blobs
    AvoidDid(String),               // Blacklist
    ColocateWith([u8; 32]),         // Same node as another task
}

2. Integration

Module exported in icn-compute/src/lib.rs:

pub use scheduler::{
    DefaultPlacementPolicy, GpuDevice, GpuSpec, LocalityHint,
    NodeCapacity, NodeState, PlacementOffer, PlacementPolicy,
    PlacementRequest, ResourceProfile,
};

Backward Compatibility:

  • Existing Phase 15 tasks work unchanged
  • New tasks can optionally specify ResourceProfile
  • Executors without capacity tracking use legacy logic
  • Migration is opt-in, not forced

3. Working Example (examples/scheduler_demo.rs)

Demonstrates ML training job placement:

Scenario: GPU task (24GB, sm_70+) across 3 executors

Executors:

  • A: NVIDIA A100 (40GB, sm_80), trust 0.85, queue 5 (busy)
  • B: RTX 2080 Ti (24GB, sm_75), trust 0.65, queue 1 (available)
  • C: No GPU, trust 0.50, queue 0 (rejected)

Placement Outcome:

executor-a: score = 0.564 (high trust, but busy)
executor-b: score = 0.680 (balanced, available) ← WINNER
executor-c: REJECTED (no GPU)

The system correctly picks the available executor with adequate resources over the more powerful but busy one.

Run with:

cargo run --example scheduler_demo

Testing

7 new tests, all passing:

  1. test_resource_profile_minimal - Default profile construction
  2. test_resource_profile_validation - Input validation (CPU/RAM limits)
  3. test_node_capacity_can_fit - Capacity matching logic
  4. test_node_capacity_reserve_release - Reservation mechanics
  5. test_default_placement_policy - Scoring algorithm
  6. test_gpu_capacity_matching - GPU compute capability matching
  7. Integration with existing 40 Phase 15 tests

Total: 47 tests passing in icn-compute

Test Coverage:

  • Resource profile validation (bounds checking)
  • Capacity matching (CPU, RAM, storage, GPU)
  • Reservation/release (prevents double-allocation)
  • Scoring algorithm (trust gates, multi-factor)
  • GPU-specific allocation (compute capability comparison)

Documentation

Comprehensive Plan (docs/scheduler-evolution-plan.md - 8,800+ words):

  1. Vision Restatement: Trust-governed, multi-tier cooperative fabric
  2. 5-Phase Roadmap:
    • 16A: Resource profiles (COMPLETE)
    • 16B: Placement scoring with deliberation windows (2-3 weeks)
    • 16C: Locality awareness and topology (3-4 weeks)
    • 16D: Actor state and migration (4-6 weeks)
    • 16E: Cooperative scheduling policies (3-4 weeks)
  3. Integration Examples: End-to-end ML training job flow
  4. Testing Strategy: Per-phase test requirements
  5. Metrics & Observability: Prometheus metrics plan
  6. Open Questions: Technical, economic, social trade-offs

Updated Project Docs:

  • ROADMAP.md: Added Phase 16 with 5-phase breakdown
  • CHANGELOG.md: Added Phase 16A completion entry
  • This dev journal entry

Key Design Decisions

1. Incremental Evolution

Each phase builds on the previous without disruption. Phase 16A is 100% backward compatible—existing tasks continue to work.

Rationale: Respects ICN's pilot-driven philosophy. Scheduler evolution shouldn't block pilot deployment.

2. Trust-First Gating

Trust score remains the primary gate. Resource matching is a secondary filter.

Rationale: ICN is built for trust-first communities, not anonymous markets. Resource awareness shouldn't override trust-based access control.

3. Gossip-Based Negotiation

No central scheduler. Executors independently score tasks and claim highest-score wins.

Rationale: Avoids single point of failure, aligns with ICN's distributed architecture.

4. Multi-Factor Scoring

Balances trust (40%), capacity (30%), queue (20%), jitter (10%).

Rationale:

  • Trust dominates (ICN's core principle)
  • Capacity prevents overcommitment
  • Queue optimizes latency
  • Jitter prevents thundering herd

5. Optional GPU Support

GPU matching via compute capability (sm_70, sm_80, etc.).

Rationale: ML/batch workloads are a key use case for cooperative compute. GPU support enables ML training, rendering, scientific computing.

6. Pluggable Policies

PlacementPolicy trait allows custom scoring algorithms.

Rationale: Different cooperatives have different priorities (latency vs cost, local vs distributed, etc.). Trait enables experimentation without forking core.

Performance Characteristics

Overhead:

  • Capacity checking: O(1) per executor
  • Scoring: O(1) computation per executor
  • No network overhead yet (Phase 16B adds gossip messages)

Memory:

  • ResourceProfile: ~80 bytes
  • NodeCapacity: ~200 bytes + GPU devices
  • Per-executor overhead: ~1KB

Scalability:

  • Phase 16A adds no new gossip traffic
  • Scales with existing Phase 15 performance
  • Phase 16B adds PlacementRequest/PlacementOffer messages (estimated 500 bytes each)

Next Steps (Phase 16B - 2-3 weeks)

Implementation Tasks

  1. Gossip Message Types:

    • Add PlacementRequest and PlacementOffer to ComputeMessage enum
    • Implement serialization (bincode)
  2. Deliberation Window:

    • 500ms delay after receiving PlacementRequest
    • Collect competing offers, pick highest score
    • Prevent race conditions (multiple executors claiming)
  3. Actor Integration:

    • Extend ComputeActor with placement_policy: Box<dyn PlacementPolicy>
    • Add on_placement_request handler
    • Add on_placement_offer handler
  4. Metrics:

    • icn_compute_placement_offers_sent_total
    • icn_compute_placement_wins_total
    • icn_compute_placement_losses_total
    • icn_compute_placement_score (histogram)
  5. Integration Test:

    • Spawn 5 executors with different capacities/trust
    • Submit task with resource profile
    • Verify highest-score executor wins
    • Check no double-claims (deliberation prevents races)

Design Questions for Phase 16B

  1. Deliberation Duration: 500ms balance between latency and coordination?
  2. Offer Expiration: Should offers expire if not claimed within N seconds?
  3. Conflict Resolution: What if two executors have identical scores?
  4. Cost Adjustment: Should cost increase with queue depth? (current: yes, 1.5x multiplier)

Migration Path

Dual Protocol Support:

  • Phase 15 TaskSubmitted → instant claim (legacy)
  • Phase 16B PlacementRequest → deliberation → claim (new)

Submitters can choose protocol. After 6 months, deprecate TaskSubmitted.

Lessons Learned

What Went Well

  1. Clear Vision Document: Starting with comprehensive vision statement aligned implementation
  2. Incremental Design: 5-phase plan makes complexity manageable
  3. Backward Compatibility: No disruption to existing system
  4. Working Demo: scheduler_demo.rs validates design early
  5. GPU Support: Compute capability matching was straightforward

Challenges

  1. Trait Design: Took iterations to get PlacementPolicy trait signature right
  2. Scoring Weights: Arbitrary weights (0.4/0.3/0.2/0.1) need empirical validation
  3. Random Jitter: Using rand feels hacky, but necessary for tie-breaking
  4. GPU Enumeration: Real GPU discovery (CUDA/OpenCL) deferred to OS integration

Future Improvements

  1. Adaptive Scoring: Learn optimal weights from historical data
  2. Simulator: Benchmark scoring algorithms against synthetic workloads
  3. GPU Abstraction: Support AMD ROCm, Apple Metal, not just NVIDIA
  4. Capacity Discovery: Auto-detect system resources (sysinfo crate)

Impact Assessment

Substrate Readiness

Before Phase 16A:

  • ✅ Trust-gated task execution
  • ✅ Priority levels
  • ✅ Payment settlement
  • ❌ Resource awareness
  • ❌ Intelligent placement
  • ❌ Locality optimization

After Phase 16A:

  • ✅ Resource profiles (CPU/RAM/GPU/storage)
  • ✅ Capacity tracking and reservation
  • ✅ Pluggable placement policies
  • ✅ Foundation for intelligent scoring
  • ⏳ Gossip protocol (Phase 16B)
  • ⏳ Locality awareness (Phase 16C)

Path to Vision

Completed: 20% of scheduler evolution (Phase 16A)

Remaining:

  • Phase 16B: Placement scoring (15%)
  • Phase 16C: Locality awareness (20%)
  • Phase 16D: Actor migration (30%)
  • Phase 16E: Cooperative policies (15%)

Timeline: 3-6 months to complete vision (Phases 16B-E)

Pilot Implications

Can Deploy Now:

  • Phase 16A doesn't block pilot deployment
  • Backward compatible with Phase 15 tasks
  • Provides foundation for future optimizations

Pilot Feedback Loop:

  • Phase 16B-C: Deploy during pilot, measure impact
  • Phase 16D-E: Build only if actor use cases emerge

Philosophy: Let pilot reveal whether advanced scheduling matters in practice.

Conclusion

Phase 16A successfully establishes the foundation for ICN's scheduler evolution. The implementation is clean, well-tested, and backward compatible. The 5-phase roadmap provides a clear path from reactive claiming to intelligent, trust-governed distributed scheduling.

Key Achievement: Proved that ICN can evolve toward sophisticated scheduling without disrupting existing functionality. This incremental approach respects the pilot-driven development philosophy while laying groundwork for the long-term vision of a multi-tier cooperative fabric.

Next Milestone: Phase 16B (Placement Scoring) - 2-3 weeks to production-ready gossip-based task placement with deliberation windows.


Files Modified:

  • icn/crates/icn-compute/src/scheduler.rs (new, 700+ lines)
  • icn/crates/icn-compute/src/lib.rs (exports)
  • icn/crates/icn-compute/Cargo.toml (added rand dependency)
  • icn/crates/icn-compute/examples/scheduler_demo.rs (new demo)
  • docs/scheduler-evolution-plan.md (new, 8,800+ words)
  • ROADMAP.md (added Phase 16, updated last modified)
  • CHANGELOG.md (added Phase 16A entry)
  • docs/dev-journal/2025-11-23-phase-16a-scheduler-foundation.md (this file)

Test Results:

$ cargo test -p icn-compute
test result: ok. 47 passed; 0 failed; 0 ignored

Commits Recommended:

git add icn/crates/icn-compute/
git add docs/scheduler-evolution-plan.md
git add ROADMAP.md CHANGELOG.md
git add docs/dev-journal/2025-11-23-phase-16a-scheduler-foundation.md
git commit -m "feat(compute): Phase 16A - scheduler evolution foundation

- Add ResourceProfile type for concrete resource requirements
- Implement NodeCapacity tracking and reservation system
- Create PlacementPolicy trait for pluggable scoring
- Add DefaultPlacementPolicy with multi-factor scoring
- Support GPU matching via compute capability
- 7 new tests, all passing (47 total)
- Comprehensive design doc (8,800+ words)
- Working demo: scheduler_demo.rs
- Backward compatible with Phase 15

Phase 16A establishes foundation for intelligent, trust-governed
distributed scheduling. First of 5 phases evolving ICN compute into
multi-tier cooperative fabric (edge/community/regional) with actor
migration and per-coop policies.

Next: Phase 16B (Placement Scoring) - 2-3 weeks

🤖 Generated with Claude Code"