From 381e4d52e8309bf55da7e78112bbcf0794ff169c Mon Sep 17 00:00:00 2001 From: Mikhail Date: Mon, 24 Aug 2026 00:08:18 +0300 Subject: [PATCH] fix(agent-worker): report local capability readiness --- cmd/agent-worker/status.go | 3 ++- cmd/agent-worker/status_test.go | 13 +++++++---- dev/ACTIVE_TASK.json | 4 ++-- ...pability-aware-agent-worker-readiness.json | 23 +++++++++++++++++++ 4 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 dev/tasks/DEV-000264-capability-aware-agent-worker-readiness.json diff --git a/cmd/agent-worker/status.go b/cmd/agent-worker/status.go index a8176fd..223cb7d 100644 --- a/cmd/agent-worker/status.go +++ b/cmd/agent-worker/status.go @@ -94,7 +94,8 @@ func workerStatusHandler(executorConfigured bool, localFallback ...interface{}) } if local { baseStatus.Mode = "local-executor" - baseStatus.Reason = "bounded local task-evaluation executor is active; unsupported work remains durably waiting" + baseStatus.Ready = true + baseStatus.Reason = "bounded local task-evaluation capability is ready; unsupported work remains durably waiting" baseStatus.Capabilities = []string{"task-evaluation"} } if executorConfigured { diff --git a/cmd/agent-worker/status_test.go b/cmd/agent-worker/status_test.go index 84bb185..5a2dab1 100644 --- a/cmd/agent-worker/status_test.go +++ b/cmd/agent-worker/status_test.go @@ -39,14 +39,14 @@ func TestWorkerStatusReportsRecoveryOnlyWithoutExecutor(t *testing.T) { } } -func TestWorkerStatusReportsLocalExecutor(t *testing.T) { +func TestWorkerStatusReportsLocalExecutorCapabilityReady(t *testing.T) { response := httptest.NewRecorder() workerStatusHandler(false, true).ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/status", nil)) var value workerStatusResponse if err := json.NewDecoder(response.Body).Decode(&value); err != nil { t.Fatal(err) } - if response.Code != http.StatusOK || value.Ready || value.Mode != "local-executor" || !value.LocalFallback || !value.LocalExecutor { + if response.Code != http.StatusOK || !value.Ready || value.Mode != "local-executor" || !value.LocalFallback || !value.LocalExecutor { t.Fatalf("unexpected status: code=%d value=%+v", response.Code, value) } if len(value.Capabilities) != 1 || value.Capabilities[0] != "task-evaluation" { @@ -61,18 +61,23 @@ func TestWorkerStatusDoesNotCallLocalFallbackAnExternalExecutor(t *testing.T) { if err := json.NewDecoder(response.Body).Decode(&value); err != nil { t.Fatal(err) } - if value.ExecutorConfigured || value.Ready || !value.LocalFallback || !value.LocalExecutor || value.Mode != "local-executor" { + if value.ExecutorConfigured || !value.Ready || !value.LocalFallback || !value.LocalExecutor || value.Mode != "local-executor" { t.Fatalf("local fallback was presented as external execution: %+v", value) } } -func TestWorkerReadyzRequiresExecutor(t *testing.T) { +func TestWorkerReadyzRequiresAnAdvertisedCapability(t *testing.T) { response := httptest.NewRecorder() workerStatusHandler(false).ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/readyz", nil)) if response.Code != http.StatusServiceUnavailable { t.Fatalf("readyz status=%d", response.Code) } response = httptest.NewRecorder() + workerStatusHandler(false, true).ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/readyz", nil)) + if response.Code != http.StatusOK { + t.Fatalf("local capability readyz status=%d", response.Code) + } + response = httptest.NewRecorder() workerStatusHandler(true).ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/readyz", nil)) if response.Code != http.StatusOK { t.Fatalf("configured readyz status=%d", response.Code) diff --git a/dev/ACTIVE_TASK.json b/dev/ACTIVE_TASK.json index 88e4857..058883c 100644 --- a/dev/ACTIVE_TASK.json +++ b/dev/ACTIVE_TASK.json @@ -1,5 +1,5 @@ { - "task_file": "dev/tasks/DEV-000263-gpu-qualification-runtime-evidence.json", - "task_id": "DEV-000263", + "task_file": "dev/tasks/DEV-000264-capability-aware-agent-worker-readiness.json", + "task_id": "DEV-000264", "task_revision": 1 } diff --git a/dev/tasks/DEV-000264-capability-aware-agent-worker-readiness.json b/dev/tasks/DEV-000264-capability-aware-agent-worker-readiness.json new file mode 100644 index 0000000..eda6ba2 --- /dev/null +++ b/dev/tasks/DEV-000264-capability-aware-agent-worker-readiness.json @@ -0,0 +1,23 @@ +{ + "task_id": "DEV-000264", + "task_revision": 1, + "architecture_revision": "ADR-0018", + "base_repo_revision": "c8dc9ed", + "risk_tier": "E", + "intent": "Report agent-worker readiness for the bounded local capability while keeping unsupported work durably waiting and external bridge state explicit.", + "requirement_ids": ["Agent Execution runtime and recovery", "local-first fallback", "truthful operational readiness"], + "allowed_change_scope": {"modules": ["agent-worker"], "paths": ["cmd/agent-worker/status.go", "cmd/agent-worker/status_test.go", "dev/ACTIVE_TASK.json", "dev/tasks/DEV-000264-capability-aware-agent-worker-readiness.json"]}, + "forbidden_change_scope": {"paths": ["architecture/**", "security/**", "database/**", "deploy/**", "contracts/**", "LLM-local/**", "modules/**", "adapters/**"]}, + "allowed_architecture_delta": {"new_cross_module_dependencies": 0, "new_canonical_owners": 0, "new_privileges": 0, "new_third_party_dependencies": 0, "new_database_owner_roles": 0}, + "contracts": {"consume": ["agent-worker status response", "local task-evaluation capability"], "may_change": ["readiness semantics only"]}, + "semantic_owner": "Agent worker operational status", + "canonical_state": ["none"], + "state_transitions": ["local capability unavailable -> recovery-only; local task-evaluation capability available -> capability-ready; external bridge configured -> execution-ready"], + "side_effects_and_privileges": ["status/readiness response only"], + "persistence_and_migrations": ["none"], + "failure_retry_restart": ["unsupported work remains WAITING; stale claims remain recoverable"], + "assumptions": ["ready means at least one advertised capability can accept work, not that every arbitrary agent operation is supported"], + "acceptance_scenarios": ["recovery-only remains not ready", "local task-evaluation reports ready without claiming external bridge", "configured bridge remains ready", "local capability and unsupported-work distinction is explicit"], + "required_tests": ["go test ./cmd/agent-worker/...", "go vet ./cmd/agent-worker/...", "go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json", "go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json", "go run ./cmd/devctl check-architecture", "independent evidence review", "git diff --check", "CI", "production health smoke"], + "terminal_gap_states": ["BLOCKED_BY_MISSING_CAPABILITY", "BLOCKED_BY_SPEC_GAP"] +} -- 2.54.0