From c5dcfe155c3d890ee4e51d99c561e04e8045cc2b Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Wed, 2 Sep 2026 20:57:13 -0700 Subject: [PATCH] refactor(kanban_db): AST-neutral packing of one-item-per-line signatures and call args --- hermes_cli/kanban_db.py | 398 ++++++++++------------------------------ 1 file changed, 94 insertions(+), 304 deletions(-) diff --git a/hermes_cli/kanban_db.py b/hermes_cli/kanban_db.py index cc7e4c8fb5..32facc56a4 100644 --- a/hermes_cli/kanban_db.py +++ b/hermes_cli/kanban_db.py @@ -177,11 +177,7 @@ def _kanban_observer_consumed(event: str) -> bool: def _fire_worker_spawned_hook( - conn: sqlite3.Connection, - task: "Task", - workspace_path: str, - pid: Optional[int], - *, + conn: sqlite3.Connection, task: "Task", workspace_path: str, pid: Optional[int], *, board: Optional[str] = None, ) -> None: """``on_kanban_worker_spawned`` AFTER the PID is durably persisted; best-effort.""" @@ -202,10 +198,7 @@ def _fire_worker_spawned_hook( def notify_task_updated( - conn: sqlite3.Connection, - task_id: str, - changed_fields: Iterable[str], - *, + conn: sqlite3.Connection, task_id: str, changed_fields: Iterable[str], *, board: Optional[str] = None, ) -> None: """``on_kanban_task_updated`` AFTER a non-lifecycle task mutation commits @@ -240,10 +233,7 @@ _TICK_ACTIVITY_FIELDS = ( def _fire_dispatch_tick_hook( - result: "DispatchResult", - *, - board: Optional[str] = None, - dry_run: bool = False, + result: "DispatchResult", *, board: Optional[str] = None, dry_run: bool = False, ) -> None: """``on_kanban_dispatch_tick`` — strictly AFTER ``_dispatch_tick_lock`` is released so a slow subscriber cannot stall a sibling dispatcher.""" @@ -572,15 +562,9 @@ def read_board_metadata(board: Optional[str] = None) -> dict: def write_board_metadata( - board: Optional[str], - *, - name: Optional[str] = None, - description: Optional[str] = None, - icon: Optional[str] = None, - color: Optional[str] = None, - archived: Optional[bool] = None, - default_workdir: Optional[str] = None, - project_id: Optional[str] = None, + board: Optional[str], *, name: Optional[str] = None, description: Optional[str] = None, + icon: Optional[str] = None, color: Optional[str] = None, archived: Optional[bool] = None, + default_workdir: Optional[str] = None, project_id: Optional[str] = None, ) -> dict: """Create/update ``board.json``; unmentioned fields are preserved, ``created_at`` set on first write. ``project_id``/``default_workdir``: ``None`` = unchanged, @@ -605,33 +589,22 @@ def write_board_metadata( path = board_metadata_path(slug) path.parent.mkdir(parents=True, exist_ok=True) path.write_text( - json.dumps(meta, indent=2, ensure_ascii=False) + "\n", - encoding="utf-8", + json.dumps(meta, indent=2, ensure_ascii=False) + "\n", encoding="utf-8", ) meta["db_path"] = str(kanban_db_path(slug)) return meta def create_board( - slug: str, - *, - name: Optional[str] = None, - description: Optional[str] = None, - icon: Optional[str] = None, - color: Optional[str] = None, - default_workdir: Optional[str] = None, + slug: str, *, name: Optional[str] = None, description: Optional[str] = None, + icon: Optional[str] = None, color: Optional[str] = None, default_workdir: Optional[str] = None, project_id: Optional[str] = None, ) -> dict: """Create board dir + DB + metadata (``mkdir -p`` semantics: existing board returns its metadata).""" normed = _require_slug(slug) meta = write_board_metadata( - normed, - name=name, - description=description, - icon=icon, - color=color, - default_workdir=default_workdir, - project_id=project_id, + normed, name=name, description=description, icon=icon, color=color, + default_workdir=default_workdir, project_id=project_id, ) # Touch the DB so list_boards() sees it immediately. init_db(board=normed) @@ -863,8 +836,7 @@ class Attachment: return cls( id=r["id"], task_id=r["task_id"], filename=r["filename"], stored_path=r["stored_path"], content_type=r["content_type"], - size=r["size"] or 0, uploaded_by=r["uploaded_by"], - created_at=r["created_at"], + size=r["size"] or 0, uploaded_by=r["uploaded_by"], created_at=r["created_at"], ) @@ -882,8 +854,7 @@ class Event: run_id = _row_get(row, "run_id") return cls( id=row["id"], task_id=row["task_id"], kind=row["kind"], - payload=_json_or(row["payload"]), created_at=row["created_at"], - run_id=_opt_int(run_id), + payload=_json_or(row["payload"]), created_at=row["created_at"], run_id=_opt_int(run_id), ) @@ -1133,11 +1104,8 @@ def _canonical_assignee(assignee: Optional[str]) -> Optional[str]: def _resolve_project_link( - conn: sqlite3.Connection, - project_id: Optional[str], - project_source_task_id: Optional[str], - workspace_kind: str, - workspace_path: Optional[str], + conn: sqlite3.Connection, project_id: Optional[str], project_source_task_id: Optional[str], + workspace_kind: str, workspace_path: Optional[str], ) -> tuple[Optional[str], Any, Optional[str], str]: """``(project_id, project_obj, project_repo, workspace_kind)`` for ``create_task``. @@ -1266,32 +1234,16 @@ def _normalize_task_skills(skills: Optional[Iterable[str]]) -> Optional[list[str def create_task( - conn: sqlite3.Connection, - *, - title: str, - body: Optional[str] = None, - assignee: Optional[str] = None, - created_by: Optional[str] = None, - workspace_kind: str = "scratch", - workspace_path: Optional[str] = None, - branch_name: Optional[str] = None, - tenant: Optional[str] = None, - priority: int = 0, - parents: Iterable[str] = (), - triage: bool = False, - idempotency_key: Optional[str] = None, - max_runtime_seconds: Optional[int] = None, - skills: Optional[Iterable[str]] = None, - max_retries: Optional[int] = None, - model_override: Optional[str] = None, - provider_override: Optional[str] = None, - reasoning_effort: Optional[str] = None, - goal_mode: bool = False, - goal_max_turns: Optional[int] = None, - initial_status: str = "running", - session_id: Optional[str] = None, - board: Optional[str] = None, - project_id: Optional[str] = None, + conn: sqlite3.Connection, *, title: str, body: Optional[str] = None, + assignee: Optional[str] = None, created_by: Optional[str] = None, + workspace_kind: str = "scratch", workspace_path: Optional[str] = None, + branch_name: Optional[str] = None, tenant: Optional[str] = None, priority: int = 0, + parents: Iterable[str] = (), triage: bool = False, idempotency_key: Optional[str] = None, + max_runtime_seconds: Optional[int] = None, skills: Optional[Iterable[str]] = None, + max_retries: Optional[int] = None, model_override: Optional[str] = None, + provider_override: Optional[str] = None, reasoning_effort: Optional[str] = None, + goal_mode: bool = False, goal_max_turns: Optional[int] = None, initial_status: str = "running", + session_id: Optional[str] = None, board: Optional[str] = None, project_id: Optional[str] = None, project_source_task_id: Optional[str] = None, ) -> str: """Create a task (optionally under ``parents``); returns its id. @@ -1391,8 +1343,7 @@ def create_task( branch_name, project_id, tenant, idempotency_key, _opt_int(max_runtime_seconds), json.dumps(skills_list) if skills_list is not None else None, - _opt_int(max_retries), model_override, provider_override, - reasoning_effort, + _opt_int(max_retries), model_override, provider_override, reasoning_effort, 1 if goal_mode else 0, _opt_int(goal_max_turns), session_id, ), ) @@ -1483,10 +1434,7 @@ def _missing_task_ids(conn: sqlite3.Connection, ids: Iterable[str]) -> list[str] def _inherit_notify_subs( - conn: sqlite3.Connection, - child_id: str, - parents: Iterable[str], - *, + conn: sqlite3.Connection, child_id: str, parents: Iterable[str], *, created_at: Optional[int] = None, ) -> None: """Copy parents' notify subscriptions to a child, cursor caught up to the @@ -1541,17 +1489,10 @@ VALID_SORT_ORDERS: dict[str, str] = { def list_tasks( - conn: sqlite3.Connection, - *, - assignee: Optional[str] = None, - status: Optional[str] = None, - tenant: Optional[str] = None, - session_id: Optional[str] = None, - include_archived: bool = False, - limit: Optional[int] = None, - order_by: Optional[str] = None, - workflow_template_id: Optional[str] = None, - current_step_key: Optional[str] = None, + conn: sqlite3.Connection, *, assignee: Optional[str] = None, status: Optional[str] = None, + tenant: Optional[str] = None, session_id: Optional[str] = None, include_archived: bool = False, + limit: Optional[int] = None, order_by: Optional[str] = None, + workflow_template_id: Optional[str] = None, current_step_key: Optional[str] = None, ) -> list[Task]: if status is not None and status not in VALID_STATUSES: raise ValueError(f"status must be one of {sorted(VALID_STATUSES)}") @@ -1610,10 +1551,7 @@ def assign_task(conn: sqlite3.Connection, task_id: str, profile: Optional[str]) def set_model_override( - conn: sqlite3.Connection, - task_id: str, - model: Optional[str], - provider: Optional[str] = None, + conn: sqlite3.Connection, task_id: str, model: Optional[str], provider: Optional[str] = None, ) -> bool: """Set (empty ``model`` clears BOTH) the per-task model/provider override. Allowed while ``running``: it applies on the NEXT dispatch, which is the @@ -1677,8 +1615,7 @@ def link_tasks(conn: sqlite3.Connection, parent_id: str, child_id: str) -> None: (child_id,), ) _append_event( - conn, child_id, "linked", - {"parent": parent_id, "child": child_id}, + conn, child_id, "linked", {"parent": parent_id, "child": child_id}, ) _inherit_notify_subs(conn, child_id, (parent_id,)) @@ -1838,15 +1775,9 @@ def _collision_free_path(dest_dir: Path, safe_name: str) -> Path: def store_attachment_bytes( - conn: sqlite3.Connection, - task_id: str, - filename: str, - data: bytes, - *, - content_type: Optional[str] = None, - uploaded_by: Optional[str] = None, - board: Optional[str] = None, - max_bytes: Optional[int] = None, + conn: sqlite3.Connection, task_id: str, filename: str, data: bytes, *, + content_type: Optional[str] = None, uploaded_by: Optional[str] = None, + board: Optional[str] = None, max_bytes: Optional[int] = None, ) -> int: """Single attachment write path (dashboard, tools, CLI): size cap, safe basename, collision-free blob under :func:`task_attachments_dir`, then the @@ -1863,13 +1794,8 @@ def store_attachment_bytes( dest_path.write_bytes(data) try: return add_attachment( - conn, - task_id, - filename=dest_path.name, - stored_path=str(dest_path.resolve()), - content_type=content_type, - size=len(data), - uploaded_by=uploaded_by, + conn, task_id, filename=dest_path.name, stored_path=str(dest_path.resolve()), + content_type=content_type, size=len(data), uploaded_by=uploaded_by, ) except Exception: # Don't leave an orphan blob if the metadata insert fails (most @@ -1880,14 +1806,8 @@ def store_attachment_bytes( def add_attachment( - conn: sqlite3.Connection, - task_id: str, - *, - filename: str, - stored_path: str, - content_type: Optional[str] = None, - size: int = 0, - uploaded_by: Optional[str] = None, + conn: sqlite3.Connection, task_id: str, *, filename: str, stored_path: str, + content_type: Optional[str] = None, size: int = 0, uploaded_by: Optional[str] = None, ) -> int: """Record the metadata row (+ ``attached`` event) for a blob the caller already wrote.""" if not filename or not filename.strip(): @@ -1953,11 +1873,7 @@ def _insert_comment( def _append_event( - conn: sqlite3.Connection, - task_id: str, - kind: str, - payload: Optional[dict] = None, - *, + conn: sqlite3.Connection, task_id: str, kind: str, payload: Optional[dict] = None, *, run_id: Optional[int] = None, ) -> None: """Insert an event row inside the caller's txn; ``run_id`` groups it by attempt (NULL = task-scoped).""" @@ -1969,14 +1885,8 @@ def _append_event( def _end_run( - conn: sqlite3.Connection, - task_id: str, - *, - outcome: str, - summary: Optional[str] = None, - error: Optional[str] = None, - metadata: Optional[dict] = None, - status: Optional[str] = None, + conn: sqlite3.Connection, task_id: str, *, outcome: str, summary: Optional[str] = None, + error: Optional[str] = None, metadata: Optional[dict] = None, status: Optional[str] = None, ) -> Optional[int]: """Close the active run (``status`` defaults to ``outcome``) and clear ``current_run_id``; None when no run was active (never-claimed task).""" @@ -2045,13 +1955,8 @@ def _end_or_synthesize_run( def _synthesize_ended_run( - conn: sqlite3.Connection, - task_id: str, - *, - outcome: str, - summary: Optional[str] = None, - error: Optional[str] = None, - metadata: Optional[dict] = None, + conn: sqlite3.Connection, task_id: str, *, outcome: str, summary: Optional[str] = None, + error: Optional[str] = None, metadata: Optional[dict] = None, ) -> int: """Zero-duration closed run for a terminal transition on a never-claimed task, so the handoff fields aren't silently dropped (``_end_run`` is a @@ -2074,10 +1979,7 @@ def _synthesize_ended_run( ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( - task_id, profile, step_key, - outcome, outcome, - summary, error, - _json_or_null(metadata), + task_id, profile, step_key, outcome, outcome, summary, error, _json_or_null(metadata), now, now, ), ) @@ -2206,14 +2108,8 @@ def _parents_satisfied(conn: sqlite3.Connection, task_id: str) -> bool: def _claim_and_open_run( - conn: sqlite3.Connection, - task_id: str, - source_status: str, - lock: str, - expires: int, - now: int, - *, - event_extra: Optional[dict] = None, + conn: sqlite3.Connection, task_id: str, source_status: str, lock: str, expires: int, now: int, + *, event_extra: Optional[dict] = None, ) -> Optional[int]: """CAS ``source_status -> running``, open a run row, emit ``claimed``; None when the CAS lost. Caller holds the txn.""" @@ -2247,30 +2143,21 @@ def _claim_and_open_run( ) VALUES (?, ?, ?, 'running', ?, ?, ?, ?) """, ( - task_id, - trow["assignee"] if trow else None, - trow["current_step_key"] if trow else None, - lock, - expires, - trow["max_runtime_seconds"] if trow else None, - now, + task_id, trow["assignee"] if trow else None, trow["current_step_key"] if trow else None, + lock, expires, trow["max_runtime_seconds"] if trow else None, now, ), ) run_id = run_cur.lastrowid conn.execute("UPDATE tasks SET current_run_id = ? WHERE id = ?", (run_id, task_id)) _append_event( conn, task_id, "claimed", - {"lock": lock, "expires": expires, "run_id": run_id, **(event_extra or {})}, - run_id=run_id, + {"lock": lock, "expires": expires, "run_id": run_id, **(event_extra or {})}, run_id=run_id, ) return run_id def claim_task( - conn: sqlite3.Connection, - task_id: str, - *, - ttl_seconds: Optional[int] = None, + conn: sqlite3.Connection, task_id: str, *, ttl_seconds: Optional[int] = None, claimer: Optional[str] = None, ) -> Optional[Task]: """Atomically transition ``ready -> running``. @@ -2292,14 +2179,12 @@ def claim_task( (task_id,), ) _append_event( - conn, task_id, "claim_rejected", - {"reason": "parents_not_done"}, + conn, task_id, "claim_rejected", {"reason": "parents_not_done"}, ) return None # Close a leaked prior run so the CAS below doesn't strand it. _reclaim_dangling_run( - conn, task_id, statuses=("ready",), now=now, - note="invariant recovery on re-claim", + conn, task_id, statuses=("ready",), now=now, note="invariant recovery on re-claim", ) run_id = _claim_and_open_run(conn, task_id, "ready", lock, expires, now) if run_id is None: @@ -2310,10 +2195,7 @@ def claim_task( def claim_review_task( - conn: sqlite3.Connection, - task_id: str, - *, - ttl_seconds: Optional[int] = None, + conn: sqlite3.Connection, task_id: str, *, ttl_seconds: Optional[int] = None, claimer: Optional[str] = None, ) -> Optional[Task]: """Atomic ``review -> running`` (None when lost). Parents are re-checked @@ -2341,8 +2223,7 @@ def claim_review_task( ) return None run_id = _claim_and_open_run( - conn, task_id, "review", lock, expires, now, - event_extra={"source_status": "review"}, + conn, task_id, "review", lock, expires, now, event_extra={"source_status": "review"}, ) if run_id is None: return None @@ -2350,9 +2231,7 @@ def claim_review_task( def _retry_status_for_run( - conn: sqlite3.Connection, - task_id: str, - run_id: Optional[int] = None, + conn: sqlite3.Connection, task_id: str, run_id: Optional[int] = None, ) -> str: """``review`` when the run's ``claimed`` event says ``source_status=review``, else ``ready`` — one place, so crash/timeout/reclaim can't silently turn a @@ -2377,9 +2256,7 @@ _RUN_OUTCOME_TERMINAL_STATUS = { def goal_run_status( - conn: sqlite3.Connection, - task_id: str, - expected_run_id: Optional[int] = None, + conn: sqlite3.Connection, task_id: str, expected_run_id: Optional[int] = None, ) -> Optional[str]: """Lifecycle status as seen by ONE run: terminal handoffs bind to that run, any other ownership loss is ``superseded`` — otherwise an old goal loop @@ -2410,10 +2287,7 @@ def goal_run_status( def heartbeat_claim( - conn: sqlite3.Connection, - task_id: str, - *, - ttl_seconds: Optional[int] = None, + conn: sqlite3.Connection, task_id: str, *, ttl_seconds: Optional[int] = None, claimer: Optional[str] = None, ) -> bool: """Extend a running claim; True if we still own it.""" @@ -2565,11 +2439,7 @@ def _extend_live_stale_claim(conn: sqlite3.Connection, row: sqlite3.Row, now: in def reclaim_task( - conn: sqlite3.Connection, - task_id: str, - *, - reason: Optional[str] = None, - signal_fn=None, + conn: sqlite3.Connection, task_id: str, *, reason: Optional[str] = None, signal_fn=None, ) -> bool: """Operator reclaim regardless of TTL: release the claim, restore the source phase, reset the failure counter. False when not running.""" @@ -2606,11 +2476,7 @@ def reclaim_task( def reassign_task( - conn: sqlite3.Connection, - task_id: str, - profile: Optional[str], - *, - reclaim_first: bool = False, + conn: sqlite3.Connection, task_id: str, profile: Optional[str], *, reclaim_first: bool = False, reason: Optional[str] = None, ) -> bool: """Reassign (None unassigns); a running task is refused unless @@ -2628,9 +2494,7 @@ def reassign_task( def _verify_created_cards( - conn: sqlite3.Connection, - completing_task_id: str, - claimed_ids: Iterable[str], + conn: sqlite3.Connection, completing_task_id: str, claimed_ids: Iterable[str], ) -> tuple[list[str], list[str]]: """Partition ``claimed_ids`` into (verified, phantom). Verified = the row exists AND ``created_by`` is the completing task's assignee or id, OR the @@ -2707,14 +2571,9 @@ class ArtifactPreservationError(RuntimeError): def complete_task( - conn: sqlite3.Connection, - task_id: str, - *, - result: Optional[str] = None, - summary: Optional[str] = None, - metadata: Optional[dict] = None, - created_cards: Optional[Iterable[str]] = None, - expected_run_id: Optional[int] = None, + conn: sqlite3.Connection, task_id: str, *, result: Optional[str] = None, + summary: Optional[str] = None, metadata: Optional[dict] = None, + created_cards: Optional[Iterable[str]] = None, expected_run_id: Optional[int] = None, fire_lifecycle_hook: bool = True, ) -> bool: """``running|ready|blocked|review -> done``; records ``result``. @@ -2764,9 +2623,7 @@ def complete_task( if isinstance(metadata, dict): _stage_completion_artifacts(conn, task_id, metadata, now) run_id = _end_run( - conn, task_id, - outcome="completed", status="done", - summary=handoff_summary, + conn, task_id, outcome="completed", status="done", summary=handoff_summary, metadata=metadata, ) # Never-claimed task: synthesize a run so the handoff fields survive. @@ -2871,17 +2728,12 @@ def _flag_phantom_prose_refs( with write_txn(conn): _append_event( conn, task_id, "suspected_hallucinated_references", - {"phantom_refs": phantom_refs, "source": "completion_summary"}, - run_id=run_id, + {"phantom_refs": phantom_refs, "source": "completion_summary"}, run_id=run_id, ) def _merge_completion_prose_artifacts( - conn: sqlite3.Connection, - task_id: str, - metadata: Optional[dict], - *, - summary: Optional[str], + conn: sqlite3.Connection, task_id: str, metadata: Optional[dict], *, summary: Optional[str], result: Optional[str], ) -> Optional[dict]: """Legacy workers named deliverables only by absolute path in prose; add @@ -2917,9 +2769,7 @@ def _merge_completion_prose_artifacts( def _persist_scratch_completion_artifacts( - conn: sqlite3.Connection, - task_id: str, - metadata: dict, + conn: sqlite3.Connection, task_id: str, metadata: dict, ) -> None: """Copy scratch-workspace completion artifacts before cleanup removes them.""" raw_artifacts = metadata.get("artifacts") @@ -3013,12 +2863,7 @@ def _persist_scratch_completion_artifacts( def _insert_completion_attachment( - conn: sqlite3.Connection, - task_id: str, - *, - filename: str, - stored_path: str, - size: int, + conn: sqlite3.Connection, task_id: str, *, filename: str, stored_path: str, size: int, created_at: int, ) -> None: """Record a worker-produced artifact in the existing attachment table.""" @@ -3054,11 +2899,7 @@ def _unique_attachment_path(directory: Path, filename: str, used: set[Path]) -> def edit_completed_task_result( - conn: sqlite3.Connection, - task_id: str, - *, - result: str, - summary: Optional[str] = None, + conn: sqlite3.Connection, task_id: str, *, result: str, summary: Optional[str] = None, metadata: Optional[dict] = None, ) -> bool: """Backfill the user-visible result for an already completed task.""" @@ -3080,10 +2921,7 @@ def edit_completed_task_result( run_id = int(run["id"]) if run else None if run_id is None: run_id = _synthesize_ended_run( - conn, task_id, - outcome="completed", - summary=handoff_summary, - metadata=metadata, + conn, task_id, outcome="completed", summary=handoff_summary, metadata=metadata, ) else: conn.execute("UPDATE task_runs SET summary = ? WHERE id = ?", (handoff_summary, run_id)) @@ -3105,12 +2943,8 @@ def edit_completed_task_result( def block_task( - conn: sqlite3.Connection, - task_id: str, - *, - reason: Optional[str] = None, - kind: Optional[str] = None, - expected_run_id: Optional[int] = None, + conn: sqlite3.Connection, task_id: str, *, reason: Optional[str] = None, + kind: Optional[str] = None, expected_run_id: Optional[int] = None, ) -> bool: """``running``/``ready`` -> ``blocked`` (or ``todo`` / ``triage``, see :func:`_route_block`). ``transient`` still counts toward the loop breaker @@ -3130,8 +2964,7 @@ def block_task( else "ready" ) new_status, event_kind, set_sql, params, payload = _route_block( - kind, reason, source_status, - prev_kind=_row_get(cur_row, "block_kind"), + kind, reason, source_status, prev_kind=_row_get(cur_row, "block_kind"), prev_recurrences=int(_row_get(cur_row, "block_recurrences") or 0), ) sql = f""" @@ -3207,15 +3040,9 @@ def redact_review_value(value: Any) -> Any: def request_review( - conn: sqlite3.Connection, - task_id: str, - *, - summary: Optional[str] = None, - metadata: Optional[dict] = None, - reviewer: Optional[str] = None, - expected_run_id: Optional[int] = None, - force: bool = False, - with_reason: bool = False, + conn: sqlite3.Connection, task_id: str, *, summary: Optional[str] = None, + metadata: Optional[dict] = None, reviewer: Optional[str] = None, + expected_run_id: Optional[int] = None, force: bool = False, with_reason: bool = False, ): """``running``/``ready`` -> ``review``; never touches block recurrence accounting. @@ -3268,8 +3095,7 @@ def request_review( assignee_sql = ", assignee = ?" if reviewer is not None else "" run_guard = "" if expected_run_id is None else " AND current_run_id = ?" params: tuple[Any, ...] = ( - *(() if reviewer is None else (reviewer,)), - task_id, + *(() if reviewer is None else (reviewer,)), task_id, *(() if expected_run_id is None else (int(expected_run_id),)), ) cur = conn.execute( @@ -3331,11 +3157,7 @@ def _nonblank_str(value: Any) -> Optional[str]: def request_changes( - conn: sqlite3.Connection, - task_id: str, - *, - reason: str, - expected_run_id: Optional[int] = None, + conn: sqlite3.Connection, task_id: str, *, reason: str, expected_run_id: Optional[int] = None, ) -> tuple[bool, Optional[str]]: """Close an active reviewer run (claimed from ``review``) and hand the task back to the implementer from the latest ``review_requested`` event, parent @@ -3388,11 +3210,7 @@ def request_changes( if cur.rowcount != 1: return False, "task changed during review handoff" run_id = _end_run( - conn, - task_id, - outcome="changes_requested", - status=new_status, - summary=reason, + conn, task_id, outcome="changes_requested", status=new_status, summary=reason, ) _append_event( conn, @@ -3410,13 +3228,8 @@ def request_changes( def promote_task( - conn: sqlite3.Connection, - task_id: str, - *, - actor: str, - reason: Optional[str] = None, - force: bool = False, - dry_run: bool = False, + conn: sqlite3.Connection, task_id: str, *, actor: str, reason: Optional[str] = None, + force: bool = False, dry_run: bool = False, ) -> tuple[bool, Optional[str]]: """Operator promotion ``todo``/``blocked`` -> ``ready`` with an audit event. Refused while a parent is unfinished unless ``force``; ``dry_run`` only @@ -3581,10 +3394,7 @@ def reopen_review_task(conn: sqlite3.Connection, task_id: str) -> bool: def invalidate_descendants_for_parent_reopen( - conn: sqlite3.Connection, - task_id: str, - *, - author: str, + conn: sqlite3.Connection, task_id: str, *, author: str, ) -> dict[str, Any]: """THE done-reopen invalidation: every ``ready``/``review``/``running``/``done`` descendant of a reopened ancestor is demoted to ``todo`` and re-gated. @@ -3682,13 +3492,8 @@ def invalidate_descendants_for_parent_reopen( def specify_triage_task( - conn: sqlite3.Connection, - task_id: str, - *, - title: Optional[str] = None, - body: Optional[str] = None, - assignee: Optional[str] = None, - author: Optional[str] = None, + conn: sqlite3.Connection, task_id: str, *, title: Optional[str] = None, + body: Optional[str] = None, assignee: Optional[str] = None, author: Optional[str] = None, ) -> bool: """Update title/body/assignee (when given) and move ``triage -> todo`` in one txn; False when not in triage. Lands in ``todo`` (not ``ready``) so parent @@ -3783,13 +3588,8 @@ def _validate_children_graph(children: list) -> None: def decompose_triage_task( - conn: sqlite3.Connection, - task_id: str, - *, - root_assignee: Optional[str], - children: list[dict], - author: Optional[str] = None, - auto_promote: bool = True, + conn: sqlite3.Connection, task_id: str, *, root_assignee: Optional[str], children: list[dict], + author: Optional[str] = None, auto_promote: bool = True, ) -> Optional[list[str]]: """Fan a triage task out into children and move the root to ``todo``; the root waits on every child and wakes (``ready``) when all are done. @@ -3911,8 +3711,7 @@ def archive_task(conn: sqlite3.Connection, task_id: str) -> bool: return False # Archived mid-run (dashboard): close the run so history isn't orphaned. run_id = _end_run( - conn, task_id, - outcome="reclaimed", status="reclaimed", + conn, task_id, outcome="reclaimed", status="reclaimed", summary="task archived with run still active", ) _append_event(conn, task_id, "archived", None, run_id=run_id) @@ -3953,10 +3752,7 @@ def delete_task(conn: sqlite3.Connection, task_id: str) -> bool: def schedule_task( - conn: sqlite3.Connection, - task_id: str, - *, - reason: Optional[str] = None, + conn: sqlite3.Connection, task_id: str, *, reason: Optional[str] = None, expected_run_id: Optional[int] = None, ) -> bool: """Park in ``scheduled`` (waiting on time, not a human; not dispatchable) @@ -4054,8 +3850,7 @@ def _ctx_header(lines: list[str], task: Task) -> None: lines.append(f"Workspace: {task.workspace_kind} @ {task.workspace_path or '(unresolved)'}") if task.max_runtime_seconds is not None: terminal_timeout = _worker_terminal_timeout_env( - task.max_runtime_seconds, - os.environ.get("TERMINAL_TIMEOUT"), + task.max_runtime_seconds, os.environ.get("TERMINAL_TIMEOUT"), ) effective_terminal_timeout = terminal_timeout or os.environ.get("TERMINAL_TIMEOUT") lines.append(f"Max runtime: {task.max_runtime_seconds}s") @@ -4313,8 +4108,7 @@ def worker_log_path(task_id: str, *, board: Optional[str] = None) -> Path: def read_worker_log( - task_id: str, *, tail_bytes: Optional[int] = None, - board: Optional[str] = None, + task_id: str, *, tail_bytes: Optional[int] = None, board: Optional[str] = None, ) -> Optional[str]: """Worker log text (last ``tail_bytes`` when set); None when the file is missing.""" path = worker_log_path(task_id, board=board) @@ -4374,12 +4168,8 @@ def known_assignees(conn: sqlite3.Connection) -> list[dict]: # --- Runs (attempt history on a task) --- def list_runs( - conn: sqlite3.Connection, - task_id: str, - *, - include_active: bool = True, - state_type: Optional[str] = None, - state_name: Optional[str] = None, + conn: sqlite3.Connection, task_id: str, *, include_active: bool = True, + state_type: Optional[str] = None, state_name: Optional[str] = None, ) -> list[Run]: """Runs in start order; ``include_active=False`` = closed only; ``state_type`` (``status``/``outcome``) + ``state_name`` filter together."""