Skip to content

Full Codex stability, flume restart, and kill-switch mesh fix - #230

Open
keeper337 wants to merge 3 commits into
mainfrom
feature/full-codex-agent-stability
Open

Full Codex stability, flume restart, and kill-switch mesh fix#230
keeper337 wants to merge 3 commits into
mainfrom
feature/full-codex-agent-stability

Conversation

@keeper337

@keeper337 keeper337 commented Apr 21, 2026

Copy link
Copy Markdown
Collaborator

Overview

This branch hardens full Codex worker routing and auth, adds a flume restart command, and fixes kill-switch / resume-all so Elasticsearch task state matches what the worker mesh shows after Stop all.


1. Stabilize full-Codex worker execution and auth (a7155f82)

Goal: Reduce agent loops and make PM/implementer runs reliable when using Codex end-to-end (OAuth, routing, tokens).

CLI (cmd/flume/)

  • codex_oauth.go — large addition for Codex/OpenAI OAuth flows (cache repair, device flow, token handling).
  • config.go, start.go, upgrade.go — wiring and behavior tweaks for Codex-related config and lifecycle.
  • ui/interactive.go, model_suggestions.go, validate.go — interactive/config UX aligned with Codex usage.

Dashboard (src/dashboard/)

  • codex_app_server_bridge.py — bridge behavior updates for Codex app-server integration.
  • codex_app_server_client.py — client simplification/refactor for planner/worker calls.
  • llm_settings.py — settings surface for Codex/LLM configuration.
  • server.py — planner and API paths updated for Codex stability (in addition to the kill-switch fix in commit 3).

Workers (src/worker-manager/)

  • agent_runner.py — execution path hardening for Codex-backed runs.
  • manager.py, worker_handlers.py — coordination and handler fixes for reliable task execution.

Other

  • src/github_tokens_store.py — token resolution fixes for GitHub access.
  • src/utils/git_host_client.py — small client adjustments.
  • src/agents/pm-dispatcher/SYSTEM_PROMPT.md — PM prompt tweak for the stabilized flows.

2. CLI: flume restart (a624eeea)

  • cmd/flume/commands/restart.go (new) — recreate containers and reload environment.
  • cmd/flume/main.go — register the restart subcommand.

3. Dashboard: kill-switch clears mesh claims (2563e97a)

Problem: The mesh marks workers busy from queue_state: active and active_worker (src/worker-manager/manager.py). Halt previously only set blocked / ast_sync_status: halted, so the UI could still show agents as claimed after stop. review tasks were also easy to miss in the halt query.

Changes in ElasticsearchClient (src/dashboard/server.py):

  • update_tasks_to_halted: Match ready / running / review, or any doc with queue_state: active; set queue_state to idle and clear active_worker in the Painless script.
  • update_tasks_to_ready: Align with worker-manager PAINLESS_RESUME_SCRIPT: tester/reviewer return to review, others to ready; clear claim fields.

Files changed (vs main)

19 files changed, ~1900 insertions, ~413 deletions — see the Files changed tab on this PR for the full diff.


Testing

  • Automated: not run in the authoring environment for this PR.
  • Manual: exercise full Codex OAuth + worker runs, flume restart, and Stop all / Resume all against Elasticsearch-backed tasks to confirm mesh and task docs stay consistent.

Made with Cursor

Harden Codex worker routing, OAuth cache repair, and GitHub token resolution so PM/implementer agents stop looping and can execute tasks reliably under full Codex operation.

Made-with: Cursor
Stop-all now clears queue_state and active_worker in Elasticsearch, expands
the halt query to review and active-queue docs, and aligns resume-all with
tester/reviewer pipeline stages so the mesh no longer shows workers as
claimed after halt.

Made-with: Cursor

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meta-Critic Agent Triggered

The following standards violations were detected in your code diff:

Zero-LLM Linter Checks Failed:

Ruff Python Linter Violations:

F841 Local variable `cutoff_iso` is assigned to but never used
   --> src/dashboard/autonomy_sweeps.py:409:5
    |
408 |     cutoff_ts = time.time() - idle_min * 60
409 |     cutoff_iso = datetime.fromtimestamp(cutoff_ts, tz=timezone.utc).isoformat().replace('+00:00', 'Z')
    |     ^^^^^^^^^^
410 |
411 |     body = {
    |
help: Remove assignment to unused variable `cutoff_iso`

F841 Local variable `es_post` is assigned to but never used
   --> src/dashboard/autonomy_sweeps.py:573:5
    |
571 |     logger = deps['logger']
572 |     es_search = deps['es_search']
573 |     es_post = deps['es_post']
    |     ^^^^^^^
574 |     es_upsert = deps['es_upsert']
575 |     append_note = deps['append_note']
    |
help: Remove assignment to unused variable `es_post`

F841 Local variable `append_note` is assigned to but never used
   --> src/dashboard/autonomy_sweeps.py:575:5
    |
573 |     es_post = deps['es_post']
574 |     es_upsert = deps['es_upsert']
575 |     append_note = deps['append_note']
    |     ^^^^^^^^^^^
576 |     list_projects = deps.get('list_projects')
577 |     if list_projects is None:
    |
help: Remove assignment to unused variable `append_note`

F401 [*] `codex_app_server` imported but unused
  --> src/dashboard/codex_app_server_client.py:11:8
   |
 9 | from typing import Any
10 |
11 | import codex_app_server
   |        ^^^^^^^^^^^^^^^^
   |
help: Remove unused import: `codex_app_server`

F841 Local variable `pairs` is assigned to but never used
  --> src/dashboard/repo_settings.py:21:5
   |
19 |     gts.ensure_migrated_from_env(workspace_root)
20 |     ats.ensure_migrated_from_env(workspace_root)
21 |     pairs = load_effective_pairs(workspace_root)
   |     ^^^^^
22 |
23 |     active_gh = gts.get_active_token_plain(workspace_root)
   |
help: Remove assignment to unused variable `pairs`

E402 Module level import not at top of file
  --> src/dashboard/server.py:21:1
   |
19 |     pass
20 |
21 | import subprocess
   | ^^^^^^^^^^^^^^^^^
22 | import urllib.request
23 | import urllib.parse
   |

E402 Module level import not at top of file
  --> src/dashboard/server.py:22:1
   |
21 | import subprocess
22 | import urllib.request
   | ^^^^^^^^^^^^^^^^^^^^^
23 | import urllib.parse
24 | from urllib.parse import urlparse
   |

E402 Module level import not at top of file
  --> src/dashboard/server.py:23:1
   |
21 | import subprocess
22 | import urllib.request
23 | import urllib.parse
   | ^^^^^^^^^^^^^^^^^^^
24 | from urllib.parse import urlparse
25 | from contextlib import asynccontextmanager
   |

E402 Module level import not at top of file
  --> src/dashboard/server.py:24:1
   |
22 | import urllib.request
23 | import urllib.parse
24 | from urllib.parse import urlparse
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
25 | from contextlib import asynccontextmanager
26 | from datetime import datetime, timezone
   |

E402 Module level import not at top of file
  --> src/dashboard/server.py:25:1
   |
23 | import urllib.parse
24 | from urllib.parse import urlparse
25 | from contextlib import asynccontextmanager
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26 | from datetime import datetime, timezone
27 | from pydantic import BaseModel
   |

E402 Module level import not at top of file
  --> src/dashboard/server.py:26:1
   |
24 | from urllib.parse import urlparse
25 | from contextlib import asynccontextmanager
26 | from datetime import datetime, timezone
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27 | from pydantic import BaseModel
28 | import traceback
   |

E402 Module level import not at top of file
  --> src/dashboard/server.py:27:1
   |
25 | from contextlib import asynccontextmanager
26 | from datetime import datetime, timezone
27 | from pydantic import BaseModel
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
28 | import traceback
29 | from fastapi import BackgroundTasks
   |

E402 Module level import not at top of file
  --> src/dashboard/server.py:28:1
   |
26 | from datetime import datetime, timezone
27 | from pydantic import BaseModel
28 | import traceback
   | ^^^^^^^^^^^^^^^^
29 | from fastapi import BackgroundTasks
30 | from concurrent.futures import ThreadPoolExecutor
   |

E402 Module level import not at top of file
  --> src/dashboard/server.py:29:1
   |
27 | from pydantic import BaseModel
28 | import traceback
29 | from fastapi import BackgroundTasks
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30 | from concurrent.futures import ThreadPoolExecutor
   |

E402 Module level import not at top of file
  --> src/dashboard/server.py:30:1
   |
28 | import traceback
29 | from fastapi import BackgroundTasks
30 | from concurrent.futures import ThreadPoolExecutor
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31 |
32 | # Flume Bootstrap Logic
   |

E402 Module level import not at top of file
  --> src/dashboard/server.py:45:1
   |
43 |     sys.path.insert(0, str(BASE))
44 |
45 | from utils.logger import get_logger, set_global_log_level
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
46 | logger = get_logger(__name__)
   |

E402 Module level import not at top of file
  --> src/dashboard/server.py:59:1
   |
57 | # The dashboard only verifies indices exist at startup — it does NOT create them.
58 | # This eliminates the boot-race where workers hit 404s before the dashboard finishes bootstrapping.
59 | from utils.logger import get_logger as _get_startup_logger
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
60 | _startup_logger = _get_startup_logger('es_bootstrap')
61 | try:
   |

F841 Local variable `OS_ENV_ES_URL` is assigned to but never used
   --> src/dashboard/server.py:118:24
    |
116 |     # because we explicitly do NOT overwrite here — we only supply missing values.
117 |     try:
118 |         es_url_local = OS_ENV_ES_URL = os.environ.get('ES_URL', _DEFAULT_ES).rstrip('/')
    |                        ^^^^^^^^^^^^^
119 |         url = f'{es_url_local}/flume-llm-config/_update/singleton'
120 |         headers: dict = {'Content-Type': 'application/json'}
    |
help: Remove assignment to unused variable `OS_ENV_ES_URL`

E402 Module level import not at top of file
   --> src/dashboard/server.py:160:1
    |
158 | STATIC_ROOT = Path(__file__).resolve().parent.parent / 'frontend' / 'dist'
159 |
160 | from utils.workspace import resolve_safe_workspace, WorkspaceInitializationError
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
161 |
162 | # Module-level paths are bounded to block AppSec Path Traversals seamlessly isolating the host
    |

E402 Module level import not at top of file
   --> src/dashboard/server.py:164:1
    |
162 | # Module-level paths are bounded to block AppSec Path Traversals seamlessly isolating the host
163 | WORKSPACE_ROOT = resolve_safe_workspace()
164 | from config import AppConfig, get_settings  # type: ignore
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
165 |
166 | # AP-2 resolved: WORKER_STATE removed — worker lifecycle state belongs in ES (flume-workers index).
    |

F821 Undefined name `WORKER_MANAGER_SCRIPT`
    --> src/dashboard/server.py:2756:30
     |
2754 |     if not pids['manager']:
2755 |         proc = subprocess.Popen(
2756 |             [python_bin, str(WORKER_MANAGER_SCRIPT)],
     |                              ^^^^^^^^^^^^^^^^^^^^^
2757 |             env=env,
2758 |             stdout=subprocess.DEVNULL,
     |

F821 Undefined name `WORKER_HANDLERS_SCRIPT`
    --> src/dashboard/server.py:2766:30
     |
2764 |     if not pids['handlers']:
2765 |         proc = subprocess.Popen(
2766 |             [python_bin, str(WORKER_HANDLERS_SCRIPT)],
     |                              ^^^^^^^^^^^^^^^^^^^^^^
2767 |             env=env,
2768 |             cwd=str(_SRC_ROOT / 'worker-manager'),
     |

F821 Undefined name `shlex`
    --> src/dashboard/server.py:2799:19
     |
2797 |         script = flume_sh.name
2798 |         inner = (
2799 |             f'cd {shlex.quote(str(root))} && sleep 0.5 && exec bash {shlex.quote(script)} restart --all'
     |                   ^^^^^
2800 |         )
2801 |         try:
     |

F821 Undefined name `shlex`
    --> src/dashboard/server.py:2799:70
     |
2797 |         script = flume_sh.name
2798 |         inner = (
2799 |             f'cd {shlex.quote(str(root))} && sleep 0.5 && exec bash {shlex.quote(script)} restart --all'
     |                                                                      ^^^^^
2800 |         )
2801 |         try:
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:2896:1
     |
2896 | from fastapi import FastAPI, WebSocket, Request, Depends, HTTPException, Header, Query
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2897 | from fastapi.responses import JSONResponse
2898 | from fastapi.staticfiles import StaticFiles
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:2897:1
     |
2896 | from fastapi import FastAPI, WebSocket, Request, Depends, HTTPException, Header, Query
2897 | from fastapi.responses import JSONResponse
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2898 | from fastapi.staticfiles import StaticFiles
2899 | from fastapi.middleware.cors import CORSMiddleware
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:2898:1
     |
2896 | from fastapi import FastAPI, WebSocket, Request, Depends, HTTPException, Header, Query
2897 | from fastapi.responses import JSONResponse
2898 | from fastapi.staticfiles import StaticFiles
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2899 | from fastapi.middleware.cors import CORSMiddleware
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:2899:1
     |
2897 | from fastapi.responses import JSONResponse
2898 | from fastapi.staticfiles import StaticFiles
2899 | from fastapi.middleware.cors import CORSMiddleware
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2900 |
2901 | @asynccontextmanager
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:2999:1
     |
2997 | )
2998 |
2999 | from starlette.middleware.base import BaseHTTPMiddleware
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3000 |
3001 | class LoggingMiddleware(BaseHTTPMiddleware):
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:3149:1
     |
3149 | from urllib.parse import urlunparse
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3150 |
3151 | def _parse_float_env(key: str, default: float) -> float:
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:3185:1
     |
3183 | settings = AppSettings()
3184 |
3185 | import fastapi
     | ^^^^^^^^^^^^^^
3186 | def get_app_settings() -> AppSettings:
3187 |     return settings
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:3242:1
     |
3242 | import shutil
     | ^^^^^^^^^^^^^
3243 |
3244 | _flume_cli_checked: bool = False
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:3284:1
     |
3282 |         return JSONResponse(status_code=502, content={'error': str(e)[:300]})
3283 |
3284 | import asyncio
     | ^^^^^^^^^^^^^^
3285 | async def _check_ast_exists_natively(http_client: httpx.AsyncClient, repo_path: str) -> tuple[bool, str]:
3286 |     try:
     |

E701 Multiple statements on one line (colon)
    --> src/dashboard/server.py:3290:19
     |
3288 |         api_key = os.environ.get('ES_API_KEY', '')
3289 |         headers = {'Content-Type': 'application/json'}
3290 |         if api_key: headers['Authorization'] = f'ApiKey {api_key}'
     |                   ^
3291 |
3292 |         elastro_index = os.environ.get("FLUME_ELASTRO_INDEX", "flume-elastro-graph")
     |

F841 Local variable `flume_root` is assigned to but never used
    --> src/dashboard/server.py:3401:5
     |
3399 |         raise HTTPException(status_code=403, detail="Forbidden: System architectural mapping strictly enforced")
3400 |         
3401 |     flume_root = str(_SRC_ROOT.parent)
     |     ^^^^^^^^^^
3402 |     try:
3403 |         http_client = request.app.state.http_client
     |
help: Remove assignment to unused variable `flume_root`

F841 Local variable `http_client` is assigned to but never used
    --> src/dashboard/server.py:3403:9
     |
3401 |     flume_root = str(_SRC_ROOT.parent)
3402 |     try:
3403 |         http_client = request.app.state.http_client
     |         ^^^^^^^^^^^
3404 |         # Simply return success so orchestrator knows Dashboard is up seamlessly
3405 |         return {"success": True, "message": "Elastro RAG integration securely decoupled from built-in Flume architecture"}
     |
help: Remove assignment to unused variable `http_client`

E402 Module level import not at top of file
    --> src/dashboard/server.py:4570:1
     |
4570 | from fastapi import Depends, Request, Header
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4571 | import secrets
4572 | import httpx
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:4571:1
     |
4570 | from fastapi import Depends, Request, Header
4571 | import secrets
     | ^^^^^^^^^^^^^^
4572 | import httpx
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:4572:1
     |
4570 | from fastapi import Depends, Request, Header
4571 | import secrets
4572 | import httpx
     | ^^^^^^^^^^^^
4573 |
4574 | class KillSwitchDatabaseError(Exception): pass
     |

E701 Multiple statements on one line (colon)
    --> src/dashboard/server.py:4574:41
     |
4572 | import httpx
4573 |
4574 | class KillSwitchDatabaseError(Exception): pass
     |                                         ^
4575 | class KillSwitchProcessError(Exception): pass
     |

E701 Multiple statements on one line (colon)
    --> src/dashboard/server.py:4575:40
     |
4574 | class KillSwitchDatabaseError(Exception): pass
4575 | class KillSwitchProcessError(Exception): pass
     |                                        ^
4576 |
4577 | class AuthConfigurationError(Exception): pass
     |

E701 Multiple statements on one line (colon)
    --> src/dashboard/server.py:4577:40
     |
4575 | class KillSwitchProcessError(Exception): pass
4576 |
4577 | class AuthConfigurationError(Exception): pass
     |                                        ^
4578 | class InvalidCredentialsError(Exception): pass
     |

E701 Multiple statements on one line (colon)
    --> src/dashboard/server.py:4578:41
     |
4577 | class AuthConfigurationError(Exception): pass
4578 | class InvalidCredentialsError(Exception): pass
     |                                         ^
4579 |
4580 | class IndexError(Exception): pass
     |

E701 Multiple statements on one line (colon)
    --> src/dashboard/server.py:4580:28
     |
4578 | class InvalidCredentialsError(Exception): pass
4579 |
4580 | class IndexError(Exception): pass
     |                            ^
4581 | class ElasticsearchClient:
4582 |     def __init__(self, es_url: str, api_key: str, ca_certs: str):
     |

E701 Multiple statements on one line (colon)
    --> src/dashboard/server.py:4585:19
     |
4583 |         self.es_url = es_url.rstrip('/')
4584 |         self.headers = {'Content-Type': 'application/json'}
4585 |         if api_key: self.headers['Authorization'] = f'ApiKey {api_key}'
     |                   ^
4586 |         verify_ssl = ca_certs if ca_certs else False
4587 |         self.client = httpx.AsyncClient(headers=self.headers, verify=verify_ssl, timeout=10.0)
     |

F841 Local variable `size_and_path` is assigned to but never used
    --> src/dashboard/server.py:4930:15
     |
4928 |         if len(parts) < 2:
4929 |             continue
4930 |         meta, size_and_path = parts[0], parts[1] if len(parts) == 2 else parts[1]
     |               ^^^^^^^^^^^^^
4931 |         meta_parts = meta.split()
4932 |         if len(meta_parts) < 3:
     |
help: Remove assignment to unused variable `size_and_path`

E701 Multiple statements on one line (colon)
    --> src/dashboard/server.py:5527:9
     |
5525 | def get_vault_token():
5526 |     t = os.environ.get('VAULT_TOKEN')
5527 |     if t: return t
     |         ^
5528 |     
5529 |     role_id = os.environ.get('VAULT_ROLE_ID')
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:5709:1
     |
5707 |         return {"status": "error", "message": str(e)}
5708 |
5709 | from pydantic import BaseModel
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5710 | class TaskClaimRequest(BaseModel):
5711 |     worker_id: str
     |

E402 Module level import not at top of file
    --> src/dashboard/server.py:5729:1
     |
5728 | # Static Mount for Frontend
5729 | from fastapi.responses import FileResponse, HTMLResponse
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5730 |
5731 | _MISSING_UI_HTML = """<!DOCTYPE html>
     |

F841 Local variable `new_id` is assigned to but never used
   --> src/llm_credentials_store.py:447:13
    |
445 |             api_key = ""
446 |         try:
447 |             new_id = upsert_credential(workspace_root, cred_id, label, provider, api_key, base_url)
    |             ^^^^^^
448 |         except ValueError as e:
449 |             return False, str(e), None
    |
help: Remove assignment to unused variable `new_id`

E702 Multiple statements on one line (semicolon)
  --> src/memory/es/scripts/assign_model.py:20:37
   |
18 | ctx=None
19 | if not ES_VERIFY_TLS:
20 |     ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
   |                                     ^
21 | headers={'Content-Type':'application/json','Authorization':f'ApiKey {ES_API_KEY}'}
22 | body={'doc':{'preferred_model':preferred_model,'updated_at':now,'last_update':now}}
   |

E702 Multiple statements on one line (semicolon)
  --> src/memory/es/scripts/assign_model.py:20:63
   |
18 | ctx=None
19 | if not ES_VERIFY_TLS:
20 |     ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
   |                                                               ^
21 | headers={'Content-Type':'application/json','Authorization':f'ApiKey {ES_API_KEY}'}
22 | body={'doc':{'preferred_model':preferred_model,'updated_at':now,'last_update':now}}
   |

E702 Multiple statements on one line (semicolon)
  --> src/memory/es/scripts/claim_work_item.py:21:37
   |
19 | ctx=None
20 | if not ES_VERIFY_TLS:
21 |     ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
   |                                     ^
22 | headers={'Content-Type':'application/json','Authorization':f'ApiKey {ES_API_KEY}'}
23 | get_req=urllib.request.Request(f"{ES_URL}/{INDEX}/_doc/{item_id}", headers=headers, method='GET')
   |

E702 Multiple statements on one line (semicolon)
  --> src/memory/es/scripts/claim_work_item.py:21:63
   |
19 | ctx=None
20 | if not ES_VERIFY_TLS:
21 |     ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
   |                                                               ^
22 | headers={'Content-Type':'application/json','Authorization':f'ApiKey {ES_API_KEY}'}
23 | get_req=urllib.request.Request(f"{ES_URL}/{INDEX}/_doc/{item_id}", headers=headers, method='GET')
   |

E702 Multiple statements on one line (semicolon)
  --> src/memory/es/scripts/compute_ready.py:16:37
   |
14 | ctx=None
15 | if not ES_VERIFY_TLS:
16 |     ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
   |                                     ^
17 | headers={'Content-Type':'application/json','Authorization':f'ApiKey {ES_API_KEY}'}
18 | search_body={'size':500,'query':{'match_all':{}},'sort':[{'updated_at':{'order':'desc','unmapped_type':'date'}}]}
   |

E702 Multiple statements on one line (semicolon)
  --> src/memory/es/scripts/compute_ready.py:16:63
   |
14 | ctx=None
15 | if not ES_VERIFY_TLS:
16 |     ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
   |                                                               ^
17 | headers={'Content-Type':'application/json','Authorization':f'ApiKey {ES_API_KEY}'}
18 | search_body={'size':500,'query':{'match_all':{}},'sort':[{'updated_at':{'order':'desc','unmapped_type':'date'}}]}
   |

E702 Multiple statements on one line (semicolon)
  --> src/memory/es/scripts/create_work_item.py:34:39
   |
32 | ctx = None
33 | if not ES_VERIFY_TLS:
34 |     ctx = ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
   |                                       ^
35 | req = urllib.request.Request(f"{ES_URL}/{INDEX}/_doc/{doc_id}", data=json.dumps(payload).encode(), headers={'Content-Type':'applicatio…
36 | with urllib.request.urlopen(req, context=ctx) as resp:
   |

E702 Multiple statements on one line (semicolon)
  --> src/memory/es/scripts/create_work_item.py:34:65
   |
32 | ctx = None
33 | if not ES_VERIFY_TLS:
34 |     ctx = ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
   |                                                                 ^
35 | req = urllib.request.Request(f"{ES_URL}/{INDEX}/_doc/{doc_id}", data=json.dumps(payload).encode(), headers={'Content-Type':'applicatio…
36 | with urllib.request.urlopen(req, context=ctx) as resp:
   |

E702 Multiple statements on one line (semicolon)
  --> src/memory/es/scripts/generate_work_tree.py:22:37
   |
20 | ctx=None
21 | if not ES_VERIFY_TLS:
22 |     ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
   |                                     ^
23 | headers={'Content-Type':'application/json','Authorization':f'ApiKey {ES_API_KEY}'}
24 | created=[]
   |

E702 Multiple statements on one line (semicolon)
  --> src/memory/es/scripts/generate_work_tree.py:22:63
   |
20 | ctx=None
21 | if not ES_VERIFY_TLS:
22 |     ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
   |                                                               ^
23 | headers={'Content-Type':'application/json','Authorization':f'ApiKey {ES_API_KEY}'}
24 | created=[]
   |

E702 Multiple statements on one line (semicolon)
  --> src/memory/es/scripts/ready_work_items.py:14:37
   |
12 | ctx=None
13 | if not ES_VERIFY_TLS:
14 |     ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
   |                                     ^
15 | body={
16 |   'size': 100,
   |

E702 Multiple statements on one line (semicolon)
  --> src/memory/es/scripts/ready_work_items.py:14:63
   |
12 | ctx=None
13 | if not ES_VERIFY_TLS:
14 |     ctx=ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
   |                                                               ^
15 | body={
16 |   'size': 100,
   |

F841 Local variable `data` is assigned to but never used
   --> src/utils/git_host_client.py:614:9
    |
612 |             branch = self.get_default_branch()
613 |         clean = "/" + path.lstrip("/")
614 |         data = self._get("items", {
    |         ^^^^
615 |             "path": clean,
616 |             "versionDescriptor.version": branch,
    |
help: Remove assignment to unused variable `data`

E402 Module level import not at top of file
   --> src/utils/llm_client_legacy.py:100:1
    |
100 | import time
    | ^^^^^^^^^^^
101 |
102 | # ---------------------------------------------------------------------------
    |

E701 Multiple statements on one line (colon)
   --> src/utils/llm_client_legacy.py:233:43
    |
231 |                     from utils.llm_client_fallback import resolve_fallback_model
232 |                     prov = "unknown"
233 |                     if "openai.com" in url: prov = "openai"
    |                                           ^
234 |                     elif "anthropic.com" in url: prov = "anthropic"
235 |                     elif "generativelanguage" in url: prov = "gemini"
    |

E701 Multiple statements on one line (colon)
   --> src/utils/llm_client_legacy.py:234:48
    |
232 |                     prov = "unknown"
233 |                     if "openai.com" in url: prov = "openai"
234 |                     elif "anthropic.com" in url: prov = "anthropic"
    |                                                ^
235 |                     elif "generativelanguage" in url: prov = "gemini"
236 |                     elif "/api/" in url or ":11434" in url: prov = "ollama"
    |

E701 Multiple statements on one line (colon)
   --> src/utils/llm_client_legacy.py:235:53
    |
233 |                     if "openai.com" in url: prov = "openai"
234 |                     elif "anthropic.com" in url: prov = "anthropic"
235 |                     elif "generativelanguage" in url: prov = "gemini"
    |                                                     ^
236 |                     elif "/api/" in url or ":11434" in url: prov = "ollama"
    |

E701 Multiple statements on one line (colon)
   --> src/utils/llm_client_legacy.py:236:59
    |
234 |                     elif "anthropic.com" in url: prov = "anthropic"
235 |                     elif "generativelanguage" in url: prov = "gemini"
236 |                     elif "/api/" in url or ":11434" in url: prov = "ollama"
    |                                                           ^
237 |                     
238 |                     b_url = url.split('/api')[0] if prov == "ollama" else ""
    |

E701 Multiple statements on one line (colon)
   --> src/utils/llm_client_legacy.py:270:43
    |
268 |                     from utils.llm_client_fallback import resolve_fallback_model
269 |                     prov = "unknown"
270 |                     if "openai.com" in url: prov = "openai"
    |                                           ^
271 |                     elif "anthropic.com" in url: prov = "anthropic"
272 |                     elif "generativelanguage" in url: prov = "gemini"
    |

E701 Multiple statements on one line (colon)
   --> src/utils/llm_client_legacy.py:271:48
    |
269 |                     prov = "unknown"
270 |                     if "openai.com" in url: prov = "openai"
271 |                     elif "anthropic.com" in url: prov = "anthropic"
    |                                                ^
272 |                     elif "generativelanguage" in url: prov = "gemini"
273 |                     elif "/api/" in url or ":11434" in url: prov = "ollama"
    |

E701 Multiple statements on one line (colon)
   --> src/utils/llm_client_legacy.py:272:53
    |
270 |                     if "openai.com" in url: prov = "openai"
271 |                     elif "anthropic.com" in url: prov = "anthropic"
272 |                     elif "generativelanguage" in url: prov = "gemini"
    |                                                     ^
273 |                     elif "/api/" in url or ":11434" in url: prov = "ollama"
    |

E701 Multiple statements on one line (colon)
   --> src/utils/llm_client_legacy.py:273:59
    |
271 |                     elif "anthropic.com" in url: prov = "anthropic"
272 |                     elif "generativelanguage" in url: prov = "gemini"
273 |                     elif "/api/" in url or ":11434" in url: prov = "ollama"
    |                                                           ^
274 |                     
275 |                     b_url = url.split('/api')[0] if prov == "ollama" else ""
    |

F841 [*] Local variable `de` is assigned to but never used
   --> src/worker-manager/agent_runner.py:276:40
    |
274 |                 val = inner.strip()
275 |             return json.loads(val)
276 |         except json.JSONDecodeError as de:
    |                                        ^^
277 |             logger.warning(f'[agent_runner] LLM JSON parse failed — raw response (first 2000 chars): {content[:2000]}')
278 |             return None
    |
help: Remove assignment to unused variable `de`

F841 Local variable `target_path` is assigned to but never used
   --> src/worker-manager/agent_runner.py:484:5
    |
482 | def _exec_elastro_query_ast(args: dict, repo_path: Optional[str]) -> str:
483 |     query = args.get('query', '')
484 |     target_path = _resolve_path(args.get('target_path', repo_path or '.'), repo_path)
    |     ^^^^^^^^^^^
485 |     try:
486 |         es_url = os.environ.get('ES_URL', 'http://elasticsearch:9200').rstrip('/')
    |
help: Remove assignment to unused variable `target_path`

F841 Local variable `task_title` is assigned to but never used
    --> src/worker-manager/agent_runner.py:1649:5
     |
1647 |     # Prevent the PM from re-decomposing tasks that the planner already scoped.
1648 |     item_type = (task or {}).get('item_type', 'task')
1649 |     task_title = (task or {}).get('title', '')
     |     ^^^^^^^^^^
1650 |
1651 |     instruction = (
     |
help: Remove assignment to unused variable `task_title`

F541 [*] f-string without any placeholders
  --> src/worker-manager/manager.py:81:26
   |
79 |     node_caps = {}
80 |     try:
81 |         res = es_request(f'/flume-node-registry/_search', {'size': 100}, method='GET')
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
82 |         nodes = res.get('hits', {}).get('hits', []) if res else []
83 |         for n in nodes:
   |
help: Remove extraneous `f` prefix

F841 Local variable `hits` is assigned to but never used
   --> src/worker-manager/manager.py:360:9
    |
358 |         }
359 |         res = es_request(f'/{TASK_INDEX}/_search', body, method='GET')
360 |         hits = res.get('hits', {}).get('hits', []) if res.get('hits', {}).get('total', {}).get('value', 0) > 0 else []
    |         ^^^^
361 |         # Full scan: fetch titles of active tasks and compare normalized
362 |         if res.get('hits', {}).get('total', {}).get('value', 0) > 0:
    |
help: Remove assignment to unused variable `hits`

F401 [*] `utils.git_host_client.GitHostError` imported but unused
   --> src/worker-manager/manager.py:403:81
    |
401 |         return
402 |     try:
403 |         from utils.git_host_client import get_git_client, GitHostNotFoundError, GitHostError  # noqa: PLC0415
    |                                                                                 ^^^^^^^^^^^^
404 |         client = get_git_client(src)
405 |         client.delete_remote_branch(branch)
    |
help: Remove unused import: `utils.git_host_client.GitHostError`

E402 Module level import not at top of file
    --> src/worker-manager/manager.py:1271:1
     |
1271 | import time
     | ^^^^^^^^^^^
1272 | import random
     |

F811 [*] Redefinition of unused `time` from line 6
    --> src/worker-manager/manager.py:1271:8
     |
1271 | import time
     |        ^^^^ `time` redefined here
1272 | import random
     |
    ::: src/worker-manager/manager.py:6:8
     |
   4 | import ssl
   5 | import sys
   6 | import time
     |        ---- previous definition of `time` here
   7 | # AST injected by Swarm Agent 3
   8 | import socket
     |
help: Remove definition: `time`

E402 Module level import not at top of file
    --> src/worker-manager/manager.py:1272:1
     |
1271 | import time
1272 | import random
     | ^^^^^^^^^^^^^
1273 |
1274 | last_resume_timestamp = 0
     |

F821 Undefined name `active_mesh_count`
    --> src/worker-manager/manager.py:1463:17
     |
1461 |         if claimed_task:
1462 |             if check_prov not in cloud_providers:
1463 |                 active_mesh_count += 1
     |                 ^^^^^^^^^^^^^^^^^
1464 |             src = claimed_task.get('_source', {})
1465 |             snapshot['status'] = 'claimed'
     |

F841 Local variable `active_mesh_count` is assigned to but never used
    --> src/worker-manager/manager.py:1463:17
     |
1461 |         if claimed_task:
1462 |             if check_prov not in cloud_providers:
1463 |                 active_mesh_count += 1
     |                 ^^^^^^^^^^^^^^^^^
1464 |             src = claimed_task.get('_source', {})
1465 |             snapshot['status'] = 'claimed'
     |
help: Remove assignment to unused variable `active_mesh_count`

F841 Local variable `gitflow` is assigned to but never used
    --> src/worker-manager/worker_handlers.py:1003:5
     |
1001 |     repo_id = task.get('repo')
1002 |     src     = _get_project_source(repo_id) or {}
1003 |     gitflow = load_project_gitflow(repo_id)
     |     ^^^^^^^
1004 |     target_branch = resolve_pr_base_branch(repo_id)
     |
help: Remove assignment to unused variable `gitflow`

E402 Module level import not at top of file
  --> test_clone_auth.py:17:1
   |
15 |     sys.path.insert(0, str(_DB))
16 |
17 | from flume_secrets import apply_runtime_config
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18 | apply_runtime_config(_WS)
   |

E402 Module level import not at top of file
  --> test_clone_auth.py:20:1
   |
18 | apply_runtime_config(_WS)
19 |
20 | import worker_handlers
   | ^^^^^^^^^^^^^^^^^^^^^^
21 |
22 | import urllib.request
   |

E402 Module level import not at top of file
  --> test_clone_auth.py:22:1
   |
20 | import worker_handlers
21 |
22 | import urllib.request
   | ^^^^^^^^^^^^^^^^^^^^^
23 | import json
24 | req = urllib.request.Request("http://elasticsearch:9200/flume-projects/_doc/proj-5bc17450")
   |

E402 Module level import not at top of file
  --> test_clone_auth.py:23:1
   |
22 | import urllib.request
23 | import json
   | ^^^^^^^^^^^
24 | req = urllib.request.Request("http://elasticsearch:9200/flume-projects/_doc/proj-5bc17450")
25 | res = urllib.request.urlopen(req).read()
   |

E402 Module level import not at top of file
  --> test_llm.py:11:1
   |
 9 |     sys.path.insert(0, str(_SRC))
10 |
11 | from flume_secrets import apply_runtime_config
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12 | apply_runtime_config(_WS)
   |

E402 Module level import not at top of file
  --> test_llm.py:14:1
   |
12 | apply_runtime_config(_WS)
13 |
14 | from utils import llm_client
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15 |
16 | try:
   |

E402 Module level import not at top of file
 --> test_llm_tools.py:7:1
  |
5 | from flume_secrets import apply_runtime_config
6 | apply_runtime_config(Path("/app"))
7 | from utils import llm_client
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 | try:
9 |     messages = [{"role": "user", "content": "Hello"}]
  |

F401 [*] `pytest` imported but unused
 --> tests/test_manager.py:1:8
  |
1 | import pytest
  |        ^^^^^^
2 | from unittest.mock import patch, MagicMock
3 | import time
  |
help: Remove unused import: `pytest`

F401 [*] `unittest.mock.MagicMock` imported but unused
 --> tests/test_manager.py:2:34
  |
1 | import pytest
2 | from unittest.mock import patch, MagicMock
  |                                  ^^^^^^^^^
3 | import time
  |
help: Remove unused import: `unittest.mock.MagicMock`

Found 93 errors.
[*] 7 fixable with the `--fix` option (14 hidden fixes can be enabled with the `--unsafe-fixes` option).

@keeper337 keeper337 changed the title fix(dashboard): clear task claims on kill-switch halt Full Codex stability, flume restart, and kill-switch mesh fix Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant