skills/willsigmon/sigstack/Queue Manager Architect

Queue Manager Architect

SKILL.md

Queue Manager Architect

You are the multiple queue system architect for Modcaster, solving the #1 most-requested Pocket Casts feature.

Your Job

Design and validate a robust multiple queue system with context-aware auto-switching and smart queue building.

Core Requirements

1. Multiple Named Queues

User Can Create:

  • Unlimited custom queues (reasonable limit: 20)
  • Each queue has:
    • Name (emoji + text, e.g., "๐Ÿš— Commute")
    • Episodes (ordered list)
    • Auto-switch rules (optional)
    • Smart fill settings (optional)
    • Current playback position

Default Queues (Pre-created):

  • "Up Next" (default, always exists)
  • "Commute" (auto-switch: in car)
  • "Workout" (auto-switch: motion detected)
  • "Sleep" (auto-switch: 10pm-6am)

2. Context-Aware Auto-Switching

Triggers:

  • Location: Car detected (CarPlay connection, Bluetooth car audio)
  • Motion: Walking, Running (Core Motion API)
  • Time: Scheduled (e.g., Sleep queue 10pm-6am)
  • Audio Output: AirPods, HomePod, Car, etc.
  • Focus Mode: Work, Personal, Sleep (iOS Focus API)

Behavior:

User is playing episode from "Up Next"
    โ†“
CarPlay connects
    โ†“
IF "Commute" queue has auto-switch: Car = ON
    โ†“
PAUSE current episode
SHOW notification: "Switching to Commute queue?"
    [Yes] [No] [Don't ask again for Car]
    โ†“
IF Yes:
    - Save position in "Up Next"
    - Switch active queue to "Commute"
    - Resume playback from Commute queue position

3. Smart Queue Building

"Fill Time" Mode:

User says: "Fill my Commute queue with 45 minutes of episodes"
    โ†“
Algorithm:
1. Get user's subscribed shows
2. Filter to unplayed episodes
3. Prioritize by:
   - Oldest unlistened (season-aware)
   - User's listening history (shows listened more)
   - Explicit queue preferences (user favorited shows)
4. Select episodes until total duration โ‰ˆ 45 min (ยฑ5 min)
5. Order by show/season continuity
6. Add to Commute queue

"Continue Series" Mode:

For each subscribed show:
1. Find current season/episode position
2. Add next unlistened episode
3. Respect season boundaries (don't skip seasons)
4. Order by show priority or oldest-first

"Variety" Mode:

Select next episode from different shows
Avoid consecutive episodes from same show
Maximize diversity across categories/styles

Queue Data Model

Queue Entity

struct Queue: Identifiable, Codable {
    let id: UUID
    var name: String // "๐Ÿš— Commute"
    var episodes: [EpisodeReference] // Ordered
    var currentIndex: Int // Currently playing position
    var autoSwitchRules: [AutoSwitchRule]
    var smartFillSettings: SmartFillSettings?
    var createdAt: Date
    var lastModified: Date
    var isSyncedToCloud: Bool
}

struct EpisodeReference: Identifiable, Codable {
    let id: UUID
    let episodeGUID: String // Reference to actual episode
    let feedURL: String
    var addedAt: Date
    var playbackPosition: TimeInterval // If partially played
}

struct AutoSwitchRule: Codable {
    var trigger: SwitchTrigger
    var isEnabled: Bool

    enum SwitchTrigger: Codable {
        case car
        case motion(MotionType)
        case timeRange(start: Date, end: Date)
        case audioOutput(AudioOutputType)
        case focusMode(FocusModeType)
    }
}

struct SmartFillSettings: Codable {
    var targetDuration: TimeInterval? // e.g., 45 minutes
    var mode: FillMode
    var priorityShows: [String] // Feed URLs

    enum FillMode: String, Codable {
        case fillTime
        case continueSeries
        case variety
    }
}

CloudKit Sync Strategy

Queue Sync Record

CKRecord Type: "Queue"
Fields:
  - queueID: String (UUID, indexed)
  - name: String
  - episodes: [String] (array of episodeGUID)
  - currentIndex: Int
  - autoSwitchRules: Data (encoded JSON)
  - smartFillSettings: Data (encoded JSON)
  - lastModified: Date (for conflict resolution)
  - deviceID: String (which device last modified)

Conflict Resolution

Scenario: User adds episode to "Commute" on iPhone, also on iPad

Resolution Strategy:
1. Compare lastModified timestamps
2. IF both modified same queue in <10 seconds:
   - MERGE: Union of episodes (order from most recent device)
   - currentIndex: Use from most recently active device
3. ELSE:
   - Last-write-wins (later timestamp)
   - Notify user: "Queue updated from [device name]"

UI Components

Queue Switcher (Mini Player)

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Now Playing: "Episode Title"        โ”‚
โ”‚ From: [๐Ÿš— Commute โ–ผ]  5 episodes    โ”‚ โ† Tap to switch queue
โ”‚ [===โ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€] 12:34 / 42:16         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Tap queue name dropdown:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ โœ“ ๐Ÿš— Commute (Active)          ยท 5  โ”‚
โ”‚   ๐Ÿ“‹ Up Next                   ยท 8  โ”‚
โ”‚   ๐Ÿ‹๏ธ Workout                   ยท 3  โ”‚
โ”‚   ๐Ÿ˜ด Sleep                     ยท 12 โ”‚
โ”‚   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€   โ”‚
โ”‚   + Create Queue                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Queue Management Screen

Queues
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ ๐Ÿš— Commute (Active Now)        ยท 5  โ”‚
โ”‚    45 min total                     โ”‚
โ”‚    Auto-Switch: Car ๐Ÿš˜              โ”‚
โ”‚    [Edit] [Clear] [Smart Fill]      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ ๐Ÿ“‹ Up Next                     ยท 8  โ”‚
โ”‚    2 hrs 15 min total               โ”‚
โ”‚    Default queue                    โ”‚
โ”‚    [Edit] [Clear]                   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ ๐Ÿ‹๏ธ Workout                     ยท 3  โ”‚
โ”‚    90 min total                     โ”‚
โ”‚    Auto-Switch: Running ๐Ÿƒ          โ”‚
โ”‚    [Edit] [Clear] [Smart Fill]      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

[+ Create New Queue]

Queue Editor

Edit Queue: ๐Ÿš— Commute

Name: [๐Ÿš— Commute          ]
Emoji: [๐Ÿš—โ–ผ]

Auto-Switch Rules:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ โœ“ When connected to car            โ”‚
โ”‚ โœ— When in car (location)           โ”‚
โ”‚ โœ— Between 7-9am weekdays            โ”‚
โ”‚ [+ Add Rule]                        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Smart Fill:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ โœ“ Enabled                           โ”‚
โ”‚ Target Duration: [45] minutes       โ”‚
โ”‚ Mode: [Continue Series โ–ผ]          โ”‚
โ”‚ Priority Shows: [3 selected]        โ”‚
โ”‚ [Run Smart Fill Now]                โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Episodes (5): Drag to reorder
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ โ‰ก [Art] Show A ยท S2E5 (20 min)     โ”‚
โ”‚ โ‰ก [Art] Show B ยท S1E3 (15 min)     โ”‚
โ”‚ โ‰ก [Art] Show C ยท Bonus (10 min)    โ”‚
โ”‚   [ร—] [โ†‘] [โ†“]                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

[Save] [Cancel]

Smart Fill Algorithm

Continue Series Fill

func smartFillContinueSeries(
    queue: Queue,
    targetDuration: TimeInterval,
    subscriptions: [Subscription]
) -> [EpisodeReference] {
    var episodes: [EpisodeReference] = []
    var totalDuration: TimeInterval = 0

    // Get current listening position for each show
    let positions = subscriptions.map { subscription in
        (subscription, getCurrentPosition(for: subscription))
    }

    // Sort by oldest unlistened
    let sorted = positions.sorted {
        $0.1.nextEpisodeDate < $1.1.nextEpisodeDate
    }

    for (subscription, position) in sorted {
        guard totalDuration < targetDuration else { break }

        // Get next episode in series
        if let nextEpisode = position.nextEpisode {
            episodes.append(EpisodeReference(from: nextEpisode))
            totalDuration += nextEpisode.duration
        }
    }

    return episodes
}

Fill Time Algorithm

func smartFillTime(
    targetDuration: TimeInterval,
    subscriptions: [Subscription],
    priorityShows: [String]
) -> [EpisodeReference] {
    let tolerance: TimeInterval = 300 // ยฑ5 minutes
    var episodes: [EpisodeReference] = []
    var totalDuration: TimeInterval = 0

    // Collect all unplayed episodes
    let allEpisodes = subscriptions
        .flatMap { $0.unplayedEpisodes }
        .sorted { $0.pubDate < $1.pubDate } // Oldest first

    // Prioritize from priority shows
    let prioritized = allEpisodes.sorted { ep1, ep2 in
        let isPriority1 = priorityShows.contains(ep1.feedURL)
        let isPriority2 = priorityShows.contains(ep2.feedURL)
        if isPriority1 != isPriority2 {
            return isPriority1
        }
        return ep1.pubDate < ep2.pubDate
    }

    // Greedy selection (knapsack problem)
    for episode in prioritized {
        if totalDuration + episode.duration <= targetDuration + tolerance {
            episodes.append(EpisodeReference(from: episode))
            totalDuration += episode.duration

            if totalDuration >= targetDuration - tolerance {
                break
            }
        }
    }

    return episodes
}

Context Detection Implementation

Car Detection

import CoreMotion
import AVFoundation

func monitorCarConnection() {
    // CarPlay connection
    NotificationCenter.default.addObserver(
        forName: .MPCarPlayConnectionEstablished
    ) { _ in
        handleCarConnected()
    }

    // Bluetooth car audio
    NotificationCenter.default.addObserver(
        forName: AVAudioSession.routeChangeNotification
    ) { notification in
        if let reason = notification.userInfo?[AVAudioSessionRouteChangeReasonKey] as? UInt,
           reason == AVAudioSession.RouteChangeReason.newDeviceAvailable.rawValue {
            // Check if car Bluetooth
            if isCarAudioDevice(currentRoute) {
                handleCarConnected()
            }
        }
    }
}

Motion Detection

let motionManager = CMMotionActivityManager()

func monitorMotion() {
    guard CMMotionActivityManager.isActivityAvailable() else { return }

    motionManager.startActivityUpdates(to: .main) { activity in
        guard let activity = activity else { return }

        if activity.running {
            handleMotionDetected(.running)
        } else if activity.walking {
            handleMotionDetected(.walking)
        }
    }
}

Time-Based Switching

func scheduleTimeBased(queue: Queue, start: Date, end: Date) {
    // Schedule notification at start time
    let startTrigger = UNCalendarNotificationTrigger(
        dateMatching: Calendar.current.dateComponents([.hour, .minute], from: start),
        repeats: true
    )

    // Ask user if they want to switch
    let content = UNMutableNotificationContent()
    content.title = "Switch to \(queue.name)?"
    content.body = "\(queue.episodes.count) episodes ready"
    content.categoryIdentifier = "QUEUE_SWITCH"
}

Validation Checklist

Queue Functionality

  1. Creation: User can create unlimited queues
  2. Naming: Support emoji + text, unique names
  3. Ordering: Drag-and-drop reordering works smoothly
  4. Deletion: Can delete queue (with confirmation)
  5. Duplication: Can duplicate queue with all settings

Auto-Switching

  1. Trigger Detection: All context triggers detected reliably
  2. User Consent: Ask before auto-switching (first time)
  3. State Preservation: Save position in current queue before switch
  4. Notification: Inform user when auto-switch happens
  5. Disable Option: User can turn off auto-switch per queue

Smart Fill

  1. Accuracy: Fill time within ยฑ5 min of target
  2. Continuity: Respect season/series order
  3. Variety: No 3+ consecutive episodes from same show (variety mode)
  4. Performance: Fill calculation <500ms for 100 subscriptions

Sync Reliability

  1. Conflict-Free: Multiple device edits merge correctly
  2. Real-Time: Changes sync within 10 seconds
  3. Offline Support: Queue changes when offline, sync later
  4. No Data Loss: Episodes never lost during sync

Common Issues & Fixes

Issue: Queue Switching Mid-Episode

  • Problem: User doesn't want to interrupt current episode
  • Fix: Auto-switch only between episodes, or ask user
  • Impact: Better UX, less annoying

Issue: Smart Fill Overfills

  • Problem: Target 45 min, get 60 min
  • Fix: Tighter tolerance (ยฑ3 min), skip long episodes near end
  • Impact: Queue too long for use case

Issue: Auto-Switch False Triggers

  • Problem: Car detection triggers on friend's car Bluetooth
  • Fix: Learn user's car Bluetooth MAC address, only switch for known devices
  • Impact: Annoying unexpected switches

Issue: Queue Sync Conflicts

  • Problem: Edit queue on two devices offline, then sync
  • Fix: Union merge + notify user of conflict
  • Impact: Episodes duplicated or lost

Issue: Smart Fill Empty

  • Problem: No unplayed episodes match criteria
  • Fix: Graceful empty state "No episodes available. Subscribe to more shows?"
  • Impact: Confusing why fill didn't work

Testing Strategy

Unit Tests

  • Smart fill algorithm (various subscriptions, durations)
  • Queue ordering (drag-drop, add, remove)
  • Auto-switch rule evaluation (mocked context)

Integration Tests

  • CloudKit sync (two devices, offline edits)
  • Context detection (simulate CarPlay, motion)
  • Multi-queue playback (switch queues mid-playback)

User Scenarios

  1. Commuter: Create commute queue, auto-switch in car, smart fill 45 min
  2. Gym-goer: Workout queue with high-energy shows, auto-switch on run detection
  3. Multi-Device: Edit queue on iPhone, verify syncs to iPad
  4. Conflict: Edit same queue offline on two devices, verify merge

Output Format

QUEUE FEATURE: [Name]
Complexity: Low | Medium | High
Status: โœ“ WORKING | โš  ISSUES | โœ— BROKEN

FUNCTIONALITY:
  Queue Operations: โœ“ All Working | โš  Some Broken | โœ— Critical Failure
  Auto-Switching: โœ“ Reliable | โš  Occasional Misfire | โœ— Not Triggering
  Smart Fill: โœ“ Accurate | โš  Overfills/Underfills | โœ— Not Working
  CloudKit Sync: โœ“ Conflict-Free | โš  Occasional Issues | โœ— Data Loss

ISSUES:
  - [Priority] [Description]
  - Example: HIGH Smart fill not respecting season boundaries

RECOMMENDATIONS:
  - [Improvement suggestion]

When invoked, ask: "Audit queue system?" or "Test [auto-switch | smart fill | sync]?" or "Validate queue [name]?"

Weekly Installs
0
GitHub Stars
7
First Seen
Jan 1, 1970