diff --git a/cmd/agent-worker/main.go b/cmd/agent-worker/main.go index 59c3892..52c7711 100644 --- a/cmd/agent-worker/main.go +++ b/cmd/agent-worker/main.go @@ -49,6 +49,9 @@ func main() { os.Exit(1) } } else { + // The local evaluator keeps task-qualification work alive, but it is not + // an external Agent Execution Bridge and must never be reported as one. + localFallback = true executor = newTaskEvaluationExecutor(envOr("COGNITIVE_WORKER_URL", "http://cognitive-worker:8083"), envOr("WORK_GRAPH_RUNTIME_URL", "http://work-graph-runtime:8088"), &http.Client{Timeout: *leaseTTL}) fmt.Fprintln(os.Stderr, "protected agent execution bridge URL is not configured; task evaluations use the local durable evaluator, other work remains in fallback") } diff --git a/cmd/agent-worker/status_test.go b/cmd/agent-worker/status_test.go index 4922eac..88d9358 100644 --- a/cmd/agent-worker/status_test.go +++ b/cmd/agent-worker/status_test.go @@ -50,6 +50,18 @@ func TestWorkerStatusReportsLocalFallback(t *testing.T) { } } +func TestWorkerStatusDoesNotCallLocalFallbackAnExternalExecutor(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 value.ExecutorConfigured || value.Ready || !value.LocalFallback || value.Mode != "local-fallback" { + t.Fatalf("local fallback was presented as external execution: %+v", value) + } +} + func TestWorkerReadyzRequiresExecutor(t *testing.T) { response := httptest.NewRecorder() workerStatusHandler(false).ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/readyz", nil)) diff --git a/dev/ACTIVE_TASK.json b/dev/ACTIVE_TASK.json index 300181d..75836a6 100644 --- a/dev/ACTIVE_TASK.json +++ b/dev/ACTIVE_TASK.json @@ -1,5 +1,5 @@ { - "task_file": "dev/tasks/DEV-000215-governed-development-control-plane.json", - "task_id": "DEV-000215", + "task_file": "dev/tasks/DEV-000216-agent-worker-status-truth.json", + "task_id": "DEV-000216", "task_revision": 1 } diff --git a/dev/tasks/DEV-000216-agent-worker-status-truth.json b/dev/tasks/DEV-000216-agent-worker-status-truth.json new file mode 100644 index 0000000..aa42ee1 --- /dev/null +++ b/dev/tasks/DEV-000216-agent-worker-status-truth.json @@ -0,0 +1,23 @@ +{ + "task_id": "DEV-000216", + "task_revision": 1, + "architecture_revision": "ADR-0018", + "base_repo_revision": "62f0c529b3f8b3c92e4a69fcc6298d59b3015fde", + "risk_tier": "E", + "intent": "Keep agent-worker status truthful when the protected external execution bridge is absent while retaining local task-evaluation fallback.", + "requirement_ids": ["WP-301", "truthful degraded status", "local fallback"], + "allowed_change_scope": {"modules": ["agent-worker"], "paths": ["cmd/agent-worker/main.go", "cmd/agent-worker/status_test.go", "dev/ACTIVE_TASK.json", "dev/tasks/DEV-000216-agent-worker-status-truth.json"]}, + "forbidden_change_scope": {"paths": ["architecture/**", "database/**", "deploy/**", "security/**", "contracts/**", "modules/**", "LLM-local/**"]}, + "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": ["protected bridge file", "agent-worker status response", "local task-evaluation fallback"], "may_change": []}, + "semantic_owner": "work", + "canonical_state": ["existing worker status projection and durable dispatch lifecycle"], + "state_transitions": ["bridge absent -> local-fallback status", "bridge present -> execution status"], + "side_effects_and_privileges": ["no external mutation; no new credentials; no persistence change"], + "persistence_and_migrations": ["none"], + "failure_retry_restart": ["bridge absence remains explicit after restart; local evaluator remains available for bounded qualification work"], + "assumptions": ["task-evaluation fallback is not general external agent execution"], + "acceptance_scenarios": ["worker marks local_fallback when protected bridge URL is absent", "status never reports executor_configured=true for local fallback", "configured bridge path remains execution mode", "no secret value is exposed"], + "required_tests": ["go test ./cmd/agent-worker", "go vet ./cmd/agent-worker", "preflight", "check-diff", "check-architecture", "independent", "git diff --check", "CI", "production worker status"], + "terminal_gap_states": ["BLOCKED_BY_MISSING_CAPABILITY", "BLOCKED_BY_SPEC_GAP"] +}