mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
docs(release): prepare 0.27.0 — curated changelog, rag/map sweep, concat rebuild script (#662)
This commit is contained in:
@@ -106,6 +106,15 @@ The AgentOrchestrator is the runtime brain of RoboCo: it owns the per-agent Dock
|
||||
| AgentOrchestrator._run_telegram_poll_cycle | method | roboco/runtime/orchestrator.py:8476 | One Telegram poll pass: `get_telegram_inbound_engine(db).run_cycle()` + commit; testable without the sleep. |
|
||||
| AgentOrchestrator._pending_claim_blocked | method | roboco/runtime/orchestrator.py:11586 | Dispatch-time probe reusing `TaskService.is_pending_claim_blocked` (the exact claim-gate predicate — dependency OR sequence) so `_route_unassigned_pm_task` (called from `_dispatch_pm_work` per PENDING coordination-root task) can filter a doomed later-wave/sequence-held task before attempting the raw claim, instead of one failed claim per tick. Fails open (False) on any lookup error — the claim attempt itself is the safety net. |
|
||||
| AgentOrchestrator._pm_respawn_should_gate | method | roboco/runtime/orchestrator.py:8915 | Per-(slug,task) respawn circuit breaker; tracing_gap rule-following resets (bounded) + durable persist; CEO notify once when tripped. |
|
||||
| AgentOrchestrator._notification_spawn_cooled | method | roboco/runtime/orchestrator.py:4738 | Cross-tick cooldown for notification-triggered spawns (escalation/approval/audit/a2a): one spawn per (agent, notification) per `notification_spawn_cooldown_seconds`; `0` disables (legacy every-tick respawn). |
|
||||
| AgentOrchestrator._notification_spawn_over_cap | method | roboco/runtime/orchestrator.py:4780 | Hard per-(agent, notification) attempt cap (`notification_spawn_max_attempts`, default 5) — the notification-driven analogue of the PM respawn breaker; these dispatchers carry no `task_id` so that breaker never sees them. Past the cap, stop respawning and log once; the count is id-scoped and survives map pruning. |
|
||||
| AgentOrchestrator._prune_notification_spawn_maps | method | roboco/runtime/orchestrator.py:4811 | Evict `_notification_spawn_at` entries older than a cutoff so the in-memory cooldown map doesn't grow unbounded. |
|
||||
| AgentOrchestrator._notification_has_live_work | coroutine | roboco/runtime/orchestrator.py:4848 | Live-work check before spawning a notification's recipient: skip when the notification has expired, is stale past `notification_spawn_max_age_seconds` (default 6h — wedged or reloaded from before a restart), or its related task is already terminal. |
|
||||
| AgentOrchestrator._fetch_budget_status | coroutine | roboco/runtime/orchestrator.py:8021 | `ROBOCO_TASK_BUDGETS_ENABLED` sweep helper: live-priced spend snapshot for one active task (closed sessions' `estimated_cost_usd` + open sessions priced from token snapshots). |
|
||||
| AgentOrchestrator._task_budget_breach | coroutine | roboco/runtime/orchestrator.py:8053 | `(spend, cap)` tuple when a task's own spend exceeds its `budget_usd` (falling back to the `TaskType` default via `effective_task_budget_usd`), else `None`. |
|
||||
| AgentOrchestrator._handle_task_budget_breach | coroutine | roboco/runtime/orchestrator.py:8090 | BLOCKs a breaching task (HUMAN resolver, a budget marker) BEFORE the graceful stop so the ensuing unclaim no-ops and the dispatcher never respawns onto it; notifies the CEO naming both recovery steps (raise the cap or `unblock`). |
|
||||
| AgentOrchestrator._sweep_budget_exceeded | coroutine | roboco/runtime/orchestrator.py:8152 | Iterates active agents past `_check_budget_for_agent`; gated entirely by `ROBOCO_TASK_BUDGETS_ENABLED` — off, neither cap is ever consulted. |
|
||||
| AgentOrchestrator._check_budget_for_agent | coroutine | roboco/runtime/orchestrator.py:8187 | Per-agent budget check called from the sweep; resolves the active task, checks breach, and calls `_handle_task_budget_breach`. |
|
||||
| AgentOrchestrator._handle_pm_assigned_task | method | roboco/runtime/orchestrator.py:9084 | Spawn/respawn the PM for an assigned coordination root subject to the respawn gate. |
|
||||
| AgentOrchestrator._AUTO_SUBMIT_VERB_BY_ROLE | ClassVar[dict] | roboco/runtime/orchestrator.py:10650 | Wave-1 PR-gate turn cut: maps cell_pm -> (cell_pm, submit_up) and main_pm -> (main_pm, submit_root), the flow route+verb that assembles the parent's PR for each coordinator role. |
|
||||
| AgentOrchestrator._auto_submit_target | method | roboco/runtime/orchestrator.py:10655 | Resolve (role, route, verb, pm_uuid) for an auto-submittable parent; None when the parent is branchless coordination (no PR to assemble), the role has no submit verb, or no PM identity resolves. Unconditional otherwise — no flag (the `pr_gate_auto_submit_enabled` kill-switch was removed post-0.19.0). |
|
||||
@@ -221,6 +230,7 @@ stateDiagram-v2
|
||||
- No flag — the PR-gate turn cut is unconditional: when every child of an assembled parent is terminal, `_try_auto_submit` always runs the owning PM's submit_up/submit_root gate system-side instead of spawning the PM for that turn; a gate rejection (freshness/integrity/AC-coverage/race) falls back to the classic PM closure spawn (the sole safety net), with the reason threaded into the PM's closure prompt. The `pr_gate_auto_submit_enabled` kill-switch that gated this through 0.19.0 has been removed.
|
||||
- `ROBOCO_OBSIDIAN_VAULT_ENABLED` (default off; both compose files set `true`) — gates `_dispatch_vault_curation_work` (the vault-curation Auditor-spawn trigger), `_vault_intake_loop`'s outer check, and (V2) `_vault_janitor_loop`'s sole gate. `ROBOCO_VAULT_INTAKE_ENABLED` (default off; both compose files set `true`) — the `_vault_intake_loop`'s own switch, consulted only when the vault master switch is also on. V2: `ROBOCO_VAULT_ARCHIVE_DAYS` (default 30) / `ROBOCO_VAULT_REPORT_ENABLED` (default true) tune the janitor's archival pass and weekly report, both folded into `_vault_janitor_loop` with no separate loop. `ROBOCO_VAULT_KB_ENABLED` (+ `_KB_DIRS` default `RoboCo/Notes` / `_KB_INTERVAL_SECONDS` default 900, default off; NAS compose sets it `true`, registry compose leaves it `false`) — the second, independent switch `_vault_kb_loop` checks alongside the vault master switch.
|
||||
- No flag — `_pending_claim_blocked` (the dependency/sequence claim-gate prefilter) is unconditional, mirroring `TaskService.claim`'s own always-on sequence gate; it is a pure dispatch-time optimization (fails open on lookup error) with no behavior change vs. attempting and failing the claim.
|
||||
- `ROBOCO_TASK_BUDGETS_ENABLED` (default off) — arms `_sweep_budget_exceeded`; off = the sweep never runs and neither `tasks.budget_usd` nor `projects.monthly_budget_usd` is ever consulted regardless of field values. `ROBOCO_NOTIFICATION_SPAWN_COOLDOWN_SECONDS` / `_MAX_ATTEMPTS` (default 5) / `_MAX_AGE_SECONDS` (default 21600/6h) — the notification-driven-respawn breaker (`_notification_spawn_cooled`/`_over_cap`/`_notification_has_live_work`), independent of `ROBOCO_TASK_BUDGETS_ENABLED` and always on (`0` on any one of the three tunables disables just that guard).
|
||||
- `ROBOCO_TELEGRAM_ENABLED` (default off) — V1 master switch; `telegram_inbound_enabled` is a sub-switch on top of it, so both plus stored credentials are required before `_telegram_poll_loop` does anything. `ROBOCO_TELEGRAM_INBOUND_ENABLED` (default off, NAS compose arms it `true`) — gates `_telegram_poll_loop`; also makes escalation DMs (not completion DMs) carry an actionable Approve/Reject/Open keyboard. `ROBOCO_TELEGRAM_POLL_INTERVAL_SECONDS` (5.0) / `_POLL_TIMEOUT_SECONDS` (25) / `_MAX_UPDATES_PER_CYCLE` (50) / `_PENDING_REPLY_TTL_SECONDS` (300) tune the poll cadence and the force_reply prompt lifetime.
|
||||
|
||||
## Gotchas
|
||||
@@ -234,6 +244,8 @@ stateDiagram-v2
|
||||
- Budget-kill (`_enforce_grok_cost_budget`) finalizes the spawn session BEFORE popping the instance so captured usage/cost isn't lost; the reaper then releases the freed claim.
|
||||
- `_should_skip_live_reap` short-circuits like the original `and`: when not live, none of the three kill checks is awaited. The three kill paths are: `_maybe_kill_wedged_grok` (grok idle TTL), `_maybe_kill_stuck_claude` (non-GROK agent stuck past `claude_stuck_kill_seconds`, default 3600s), and `_maybe_recover_broken_gateway`. A Claude agent stuck in a genuine verb loop (still firing gateway verbs, so heartbeat advances) remains spared — the stuck-claude TTL only catches heartbeat-stale containers.
|
||||
- Tests/helpers that construct `AgentOrchestrator` via `AgentOrchestrator.__new__(AgentOrchestrator)` to bypass `__init__` rely on `__new__` pre-initializing `_instances`, `_last_audit_spawn_at`, and `_notification_spawn_at`. Any refactor that moves those initializations out of `__new__` or adds new instance attributes read by `_dispatch_audit_work`/`_is_agent_active`/notification-cooldown paths without also pre-initializing them will re-break those helpers. `__init__` must continue to re-initialize `_instances` so normal construction is unaffected.
|
||||
- The escalation/approval/audit/a2a dispatchers spawn a notification's recipient every cooldown window for as long as it stays pending, and these spawns carry no `task_id` — the PM respawn breaker (`_pm_respawn_should_gate`) never sees them, so before `_notification_spawn_over_cap`/`_notification_has_live_work` existed a single wedged alert whose recipient never resolved it respawned that recipient forever (observed live: 6+ hours of a ~2-3min respawn cycle). Both guards gate AFTER the existing cooldown, not instead of it.
|
||||
- `_handle_task_budget_breach` blocks the task (HUMAN resolver) BEFORE the graceful stop specifically so the unclaim that follows is a no-op onto an already-`blocked` task — ordering it the other way would let the dispatcher immediately respawn onto the freshly-unclaimed, still-over-budget task. `unblock` on a budget-blocked task re-checks live spend and refuses while still over, closing the silent re-breach loop that ordering alone doesn't.
|
||||
- `_auto_submit_target` requires BOTH `branch_name` and `project_id` on the parent — a MegaTask umbrella (branchless coordination) always fails this check and falls through to the classic PM closure spawn, which is correct (an umbrella assembles no PR) but means the turn cut never applies to the top of a MegaTask tree, only its root-subtasks.
|
||||
|
||||
## Drift from CLAUDE.md
|
||||
@@ -255,6 +267,8 @@ stateDiagram-v2
|
||||
> - `49b93248` (PR #504, 2026-07-13): Extended `AgentOrchestrator.__new__` to also pre-initialize `_last_audit_spawn_at` and `_notification_spawn_at`. Hardens the `__init__`-bypass construction path against `AttributeError` when the auditor-dispatch and notification-cooldown paths read those attributes; the existing `_fresh_orchestrator` helper's explicit initialization is now defensive rather than required. `__init__` still re-initializes the registries for normal construction.
|
||||
> - `fd621f0d` (PR #544, 2026-07-17): adds `_is_video_authoring_spawn` (a fail-closed role/team/task-source probe) and threads a new `task_id` param through `_generate_mcp_config` so `_append_role_scoped_mcp_servers` can register the `playwright` MCP for a ux-dev spawned onto a `source=video` task, alongside its existing fe-qa/ux-qa grant — see `docs/map/video-engine.md` for the composition-authoring side of this wire.
|
||||
> - `3b9fd0e0` (PR #551, Telegram V2, 2026-07-17): adds `_telegram_poll_task` + `_telegram_poll_loop`/`_run_telegram_poll_cycle` (mirrors the `_x_mentions_poll_loop` shape: gated on BOTH `telegram_enabled` AND `telegram_inbound_enabled`, started in `start()`, cancelled in `stop()`) driving the new `TelegramInboundEngine` (`roboco/services/telegram_inbound.py`) — long-polls Telegram `getUpdates` and dispatches `/status` `/queue` `/task` commands plus Approve/Reject button callbacks to the SAME CEO-gated service methods the HTTP routes call.
|
||||
> - `b91229f4` (#643, "break the notification-driven respawn loop"): adds `_notification_spawn_cooled` (line 4738), `_notification_spawn_over_cap` (line 4780), `_prune_notification_spawn_maps` (line 4811), and `_notification_has_live_work` (line 4848) — both new guards gate AFTER the existing cross-tick cooldown. `_instances.__init__`/`__new__` gain `_notification_spawn_at: dict[tuple[str, str], float]` (existing cooldown map) plus a companion hard-cap counter; every notification-triggered spawn dispatcher (escalation/approval/audit/a2a) is threaded through both new checks.
|
||||
> - `7c8453e2` (#654, "per-task and per-project cost budgets"): adds `_fetch_budget_status`/`_task_budget_breach`/`_handle_task_budget_breach`/`_sweep_budget_exceeded`/`_check_budget_for_agent` (lines 8021-8214) gated by `ROBOCO_TASK_BUDGETS_ENABLED`. The claim-time project-month-spend guard (`project_budget_exceeded_guard`) lives in `docs/map/gateway-support.md`; this is the sweep-side task-budget half. The same PR bundles `1d5a8e84` (#652's re-escalation backoff, see `docs/map/notification.md`) as a prerequisite commit in its branch history.
|
||||
|
||||
## Regression Risks
|
||||
|
||||
|
||||
Reference in New Issue
Block a user