## ADDED Requirements ### Requirement: ExecutionMode enum includes Undecided variant `ExecutionMode` enum SHALL include an `Undecided` variant as the default for newly created tasks. #### Scenario: Task created via Forgejo webhook - **WHEN** a Forgejo Issue webhook creates a task - **THEN** `execution_mode` SHALL be `Undecided` - **AND** the task SHALL be eligible for both ssh_cli dispatch and http_pull dequeue #### Scenario: Task created via API - **WHEN** a task is created via direct API call without specifying execution_mode - **THEN** `execution_mode` SHALL default to `Undecided` ### Requirement: Two-phase dispatch loop The dispatch loop SHALL use a two-phase approach to handle `Undecided` tasks. #### Scenario: Undecided task with matching ssh_cli host - **GIVEN** an `Undecided` task with labels `["agent:code"]` - **AND** a registered ssh_cli host with agent capabilities matching `["agent:code"]` - **WHEN** the dispatch loop runs - **THEN** the task SHALL be assigned `execution_mode = SshCli` - **AND** the task SHALL be dispatched via SSH for execution #### Scenario: Undecided task with no matching ssh_cli host - **GIVEN** an `Undecided` task with labels `["agent:review", "agent:document"]` - **AND** no registered ssh_cli host with matching capabilities - **WHEN** the dispatch loop runs - **THEN** the task SHALL be assigned `execution_mode = HttpPull` - **AND** the task SHALL become available for http_pull dequeue #### Scenario: Undecided task with matching ssh_cli host but agent offline - **GIVEN** an `Undecided` task with matching ssh_cli host - **AND** the ssh_cli host is unreachable or agent is offline - **WHEN** the dispatch loop runs - **THEN** the task SHALL remain `Undecided` (retry next cycle) - **AND** the task SHALL also be available for http_pull dequeue (fallback) ### Requirement: Coordinator explicit assignment The API SHALL provide an endpoint for coordinators to explicitly assign tasks to specific agents. #### Scenario: Coordinator assigns task to specific agent - **GIVEN** a task in `Created` or `Undecided` status - **WHEN** coordinator calls `POST /api/v1/tasks/{id}/assign` with `{"agent_id": "hermes-worker-01"}` - **THEN** the task SHALL be assigned to the specified agent - **AND** execution_mode SHALL be auto-detected from the agent's registration type (http_pull for registered agents, ssh_cli for configured hosts) - **AND** the task status SHALL transition to `Assigned` #### Scenario: Coordinator assigns to non-existent agent - **WHEN** coordinator calls assign with an unknown agent_id - **THEN** the API SHALL return 404 Not Found #### Scenario: Coordinator assigns already-running task - **WHEN** coordinator calls assign on a task in `Running` or `Completed` status - **THEN** the API SHALL return 400 Bad Request ### Requirement: Dequeue accepts Undecided tasks The dequeue endpoint SHALL return tasks with `execution_mode` of either `HttpPull` or `Undecided`. #### Scenario: Agent dequeues Undecided task - **GIVEN** an `Undecided` task matching the agent's capabilities - **WHEN** an http_pull agent calls dequeue - **THEN** the task SHALL be returned - **AND** `execution_mode` SHALL be atomically updated to `HttpPull` - **AND** the task SHALL be assigned to the dequeuing agent #### Scenario: No race condition between dispatch and dequeue - **GIVEN** an `Undecided` task - **WHEN** both ssh_cli dispatch and http_pull dequeue attempt to claim it simultaneously - **THEN** exactly one SHALL succeed (atomic claim via DB transaction) - **AND** the other SHALL get no task / skip the task ### Requirement: Backward compatibility Existing tasks with `execution_mode = SshCli` or `HttpPull` SHALL continue to work without changes. #### Scenario: Pre-existing SshCli task - **WHEN** a task already has `execution_mode = SshCli` - **THEN** the dispatch loop SHALL process it as before (no change) #### Scenario: Pre-existing HttpPull task - **WHEN** a task already has `execution_mode = HttpPull` - **THEN** the dequeue endpoint SHALL return it as before (no change)