- ExecutionMode enum adds Undecided variant (default for new tasks)
- Webhook creates tasks as Undecided instead of hardcoded SshCli
- Dispatch loop: Phase 1 matches ssh_cli hosts, Phase 2 marks remaining as HttpPull
- Dequeue now returns http_pull AND undecided tasks (atomic claim)
- New endpoint: POST /api/v1/tasks/{id}/assign for coordinator explicit assignment
- Backward compatible: existing SshCli/HttpPull tasks unaffected
- 37 tests passing (6 new)
4 KiB
4 KiB
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_modeSHALL beUndecided - 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_modeSHALL default toUndecided
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
Undecidedtask 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
Undecidedtask 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
Undecidedtask 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
CreatedorUndecidedstatus - WHEN coordinator calls
POST /api/v1/tasks/{id}/assignwith{"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
RunningorCompletedstatus - 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
Undecidedtask matching the agent's capabilities - WHEN an http_pull agent calls dequeue
- THEN the task SHALL be returned
- AND
execution_modeSHALL be atomically updated toHttpPull - AND the task SHALL be assigned to the dequeuing agent
Scenario: No race condition between dispatch and dequeue
- GIVEN an
Undecidedtask - 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)