## MODIFIED Requirements ### Requirement: Task submission enqueues a scheduled task The system SHALL allow a caller to submit a task (a goal string, or a reference to a `WorkflowDefinition`, plus optional device constraints: `driver_type`, required capability tags, and an explicit Host/Device target) and SHALL enqueue it as a `ScheduledTask` with status `queued`, returning a stable task id the caller can poll. A Device target MUST name its owning Host; an explicit target remains attached to the task for its entire lifecycle. #### Scenario: Successful submission - **WHEN** a caller submits a task with a goal and no constraints - **THEN** the scheduler creates a `ScheduledTask` with status `queued`, assigns it a unique id, and returns that id to the caller without blocking for a device to become available #### Scenario: Targeted submission - **WHEN** a caller submits a valid task targeted to a Host and one of its Devices - **THEN** the queued task retains that Host/Device target until it is assigned or reaches a terminal lifecycle state #### Scenario: Queue depth limit reached - **WHEN** a caller submits a task while the queue already holds `config.max_queue_depth` queued tasks - **THEN** the scheduler rejects the submission with a clear error rather than accepting an unbounded backlog ### Requirement: Assignment matches a queued task to an idle, constraint-matching device The system SHALL assign a queued `ScheduledTask` to an idle `PooledDevice` (as reported by the `device-pool` capability) whose explicit target, if any, `driver_type`, and capability tags satisfy the task's constraints, using a named, registrable `AssignmentStrategy`. #### Scenario: Matching idle device available - **WHEN** `assign()` runs and at least one idle `PooledDevice` matches the head-of-queue task's constraints - **THEN** the scheduler selects one such device via the configured `AssignmentStrategy`, transitions the task to status `assigned`, and records the chosen `device_id`/`host_id` #### Scenario: Targeted Device is unavailable - **WHEN** `assign()` runs and the only explicitly targeted Device is busy, stale, absent, or otherwise ineligible - **THEN** the task remains `queued` and the scheduler does not assign a different Device or Host #### Scenario: No matching device available - **WHEN** `assign()` runs and no idle `PooledDevice` matches the head-of-queue task's constraints - **THEN** the task remains `queued` (not failed), and `assign()` returns without error, ready to be retried on a later call #### Scenario: Unknown assignment strategy configured - **WHEN** `TaskScheduler` is configured with an `AssignmentStrategy` name that is not registered - **THEN** the scheduler raises a clear configuration error at startup/first- assign rather than silently falling back to a default strategy