mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
chore(release): 0.14.0
This commit is contained in:
@@ -6,10 +6,34 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.14.0] - 2026-06-29
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Multi-level MegaTask sequencing — a batch now runs in the right order, structurally, not by luck.** A MegaTask that spans several cells (and may mix per-cell projects from different products or OSS libraries) can now be routed per-cell without standing up a Product for it: each root-subtask carries an ad-hoc per-cell project map (`task_cell_projects`, migration 052, with a panel per-cell project picker), then cuts `feature/main_pm/{root}` and opens a root→master PR per repo exactly like a Product fan-out. On top of that map the dependency graph now carries the sequencing edges that collision and migration ordering need, enforced in the DAG rather than hoped for in the prompt: a dev task declares its collision surface (`intends_to_touch` globs, `adds_migration`, `touches_shared`, migration 046) on `delegate`; file-overlap serializes (more-important first), migration-adders chain serially, and a shared-surface edit runs after each non-shared task it overlaps — independent tasks still run in parallel — with cell-task wave chains and a by-osmosis edge completing the multi-level chain. Two new gate-level verbs close the "agent started out of order / drifted behind base" hole that no amount of prompting fixed: `sync_branch` (a dev gate verb that rebases the task branch onto its base and force-pushes, through the gate — raw git stays denied), and an `i_am_done` behind-base submit gate that structurally refuses to submit a task whose branch has fallen behind its base. Single-task intake is byte-for-byte unchanged.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- **A whole-codebase logic-gap audit — roughly 140 concurrency, scoping, signal, and lifecycle gaps fixed.** The dominant body of this release. The categories: **cross-repo PR scoping** — `pr_number` and `branch_name` are per-repo but were stored and looked up unscoped, so two tasks on different repos sharing a PR number could merge the wrong repo's PR or skip the org's own in-flight integration PR; every PR-merge and branch-ownership lookup is now `project_id`-scoped, and `close_pull_request` / `pr_target` make `project_id` mandatory. **Advisory locks closing TOCTOU races** — per-agent on claim, per-parent on `delegate`, per-task on `open_pr` (preventing a milestone double-emit), plus an atomic server-side Redis probe-failure counter and a single-transaction `replace_chunks` (delete+insert) closing a reindex race. **Audit-row transactionality** — status-transition audit rows and the rework counter are written in-session in the caller's transaction (the old fire-and-forget path is gone), so the audit trail can't diverge from the state change. **Signal gaps** — `pr_fail` now pushes the reviewer's issues to the owning cell PM (the re-submit loop where a PM respawned into `needs_revision` blind and re-submitted the same PR is closed), and `fail_qa` routes a `needs_revision` dev task back to the dev, never the pool. **Asyncio cleanup** — `OptimalService.close()` cancels its startup indexing task before the periodic task and the plugin clear, so it can't write against closed plugins. **Conventions standard** — the validator now times out and reaps on hang, and the gate fails closed on resolution errors (a broken standard can no longer silently disable the gate). **WebSocket** — fan-out is non-blocking with finally-disconnect, idle-timeout, and dead-socket reaping on send error. **Orchestrator runtime** — it drains its fire-and-forget background set on shutdown and stops in lifespan shutdown before closing the DB; the probe-resume loop actually revives parked agents; the grok auth token is refreshed before expiry and parked (not crash-retried) when missing. **Release executor** — every subprocess (git/make/gh/clone) is deadline-bounded and it fails closed on a git add/commit before push. Dozens more across org-memory (private-leak closures, playbook index/unindex as a post-commit step so the RAG corpus never leads the status transaction), the reaper, the provider-park/overload break, and the live-chat bridges. The full categorized tracker lives in `docs/internal` (gitignored).
|
||||||
|
|
||||||
|
- **The 2026-06-27 live-run meltdown cluster — root-caused and closed.** A run hit several compounding wedges at once, each TDD-fixed and verified green: a `main_pm` assigned a `code`-typed task is a structural impossibility (a coordinator PM does no coding) and is now hard-rejected at the gate; `cell_pm_complete` resolved a merge by global `pr_number` and merged the wrong repo's PR (closed by the cross-repo `project_id` scoping above); `submit_root` re-submitted an unchanged PR into an infinite `pr_fail` loop (now hard-gated); `fail_qa` bounced a dev task to the pool instead of back to the dev; a `note(scope='handoff')` with an empty section crashed the note path and tripped a PM respawn loop; the MegaTask four-layer hierarchy (umbrella → root → cell → dev) hit a depth cap sized for three layers; and the durable respawn counter's persist raced under fire-and-forget (an atomic upsert closes it).
|
||||||
|
|
||||||
|
- **The CEO, prompter, and secretary can no longer be spawned as agent containers.** These are human-only roles (the CEO is the human; the prompter is the on-demand intake interviewer; the secretary is the on-demand chief-of-staff) with no delivery lifecycle, yet a `_dispatch_a2a_work` path that spawned any notification target — plus an `_is_agent_active('ceo')` that always returned false — could nonetheless launch them and burn a container on a role that has no work to do. A chokepoint in `spawn_agent` plus a dispatcher skip on human-only assignees closes it at both the spawn and the dispatch layer.
|
||||||
|
|
||||||
- **The PM-respawn loop breaker now survives an orchestrator restart.** The circuit breaker that stops RoboCo from respawning the same PM on the same wedged task forever (`_pm_respawn_tracker`) lived only in memory, so a deploy/crash/OOM reset a task's strike count to 1 and re-burned the whole threshold — four full agent spawns × container cost — against the still-broken task before the gate fired again. The counter is now write-through-persisted to a new `respawn_tracker` table (migration 051) on every mutation and restored at startup, validated against live tasks so a stale counter can't resurrect against a fixed one. Best-effort and inert when empty (a DB hiccup degrades to exactly the prior in-memory behaviour); it can only ever suppress a spawn, never manufacture one.
|
- **The PM-respawn loop breaker now survives an orchestrator restart.** The circuit breaker that stops RoboCo from respawning the same PM on the same wedged task forever (`_pm_respawn_tracker`) lived only in memory, so a deploy/crash/OOM reset a task's strike count to 1 and re-burned the whole threshold — four full agent spawns × container cost — against the still-broken task before the gate fired again. The counter is now write-through-persisted to a new `respawn_tracker` table (migration 051) on every mutation and restored at startup, validated against live tasks so a stale counter can't resurrect against a fixed one. Best-effort and inert when empty (a DB hiccup degrades to exactly the prior in-memory behaviour); it can only ever suppress a spawn, never manufacture one.
|
||||||
|
|
||||||
|
- **The `mypy` / `ruff` quality gate is green again, with no `type: ignore` suppressions in `tests/`.** A round of pre-existing type errors in the test suite (ORM `<row>.id` passed where `uuid.UUID` was expected, missing annotations, `None`-attribute accesses) and every remaining `# type: ignore` in `tests/` are cleared, so `make quality` passes cleanly and the no-suppression convention holds.
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- **Phase 5 — the live-chat bridges now enforce the CEO-signed panel token.** The intake (`prompter_live`) and secretary (`secretary_live`) panel-facing endpoints were the only API surface that ran unauthenticated at the route layer — their SSE stream (`GET /stream`) carried no identity at all (browser `EventSource` cannot set headers), and the start / status / messages / stop endpoints took no auth dependency. They now require the existing CEO-signed HMAC panel token (`require_panel_token`, the HTTP sibling of the WS `_require_panel_token`): nginx already injects `X-Agent-Token` on `/api/` in prod, so the browser never holds the secret and no panel/nginx change was needed; in dev a missing token is allowed but a forged one is still rejected. This closes the last ungated panel-facing surface using the existing scheme verbatim — no new auth, no client changes.
|
||||||
|
|
||||||
|
- **Agent-token gates and secret-scrubbing hardened across the API.** The HMAC agent-token gate is now enforced on the `do` content routes and the WebSocket streams (not just the a2a message routes); the orchestrator signs its own `X-Agent-Token` on self-API calls; 422 error logs are scrubbed of secrets; the a2a / dashboard / orchestrator routes are gated; and SSE runs one session per query. With the Phase 5 bridge gate above, no panel-facing or inter-agent HTTP surface is now unauthenticated when auth is required.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **The local LLM was bumped to `glm-5.2` and the Ollama fleet defaults swapped off minimax.** The in-house RAG / hybrid-retrieval model and the default fleet model assignment move to `glm-5.2:cloud`; a stale minimax default that no longer matched the running fleet is cleared.
|
||||||
|
|
||||||
## [0.13.0] - 2026-06-26
|
## [0.13.0] - 2026-06-26
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ Choose the registry and version with two env vars (defaults shown):
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
ROBOCO_REGISTRY=ghcr.io/rennf93 # or docker.io/renzof93
|
ROBOCO_REGISTRY=ghcr.io/rennf93 # or docker.io/renzof93
|
||||||
ROBOCO_VERSION=latest # or a pinned release, e.g. 0.13.0
|
ROBOCO_VERSION=latest # or a pinned release, e.g. 0.14.0
|
||||||
```
|
```
|
||||||
|
|
||||||
The orchestrator spawns the matching pre-built agent images on demand — no build toolchain or source compile on your host.
|
The orchestrator spawns the matching pre-built agent images on demand — no build toolchain or source compile on your host.
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ Two variables choose what you pull (defaults shown):
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
ROBOCO_REGISTRY=ghcr.io/rennf93 # or docker.io/renzof93
|
ROBOCO_REGISTRY=ghcr.io/rennf93 # or docker.io/renzof93
|
||||||
ROBOCO_VERSION=latest # or a pinned release, e.g. 0.13.0
|
ROBOCO_VERSION=latest # or a pinned release, e.g. 0.14.0
|
||||||
```
|
```
|
||||||
|
|
||||||
The orchestrator then spawns the **matching** pre-built agent images on demand (it reads `ROBOCO_AGENT_IMAGE_REGISTRY` / `ROBOCO_AGENT_IMAGE_TAG`, which the registry compose wires to the same registry and version). Pin `ROBOCO_VERSION` to a release tag in production so an upstream `latest` push can't silently change your fleet.
|
The orchestrator then spawns the **matching** pre-built agent images on demand (it reads `ROBOCO_AGENT_IMAGE_REGISTRY` / `ROBOCO_AGENT_IMAGE_TAG`, which the registry compose wires to the same registry and version). Pin `ROBOCO_VERSION` to a release tag in production so an upstream `latest` push can't silently change your fleet.
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "roboco-panel",
|
"name": "roboco-panel",
|
||||||
"version": "0.13.0",
|
"version": "0.14.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "pnpm@10.25.0",
|
"packageManager": "pnpm@10.25.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "roboco"
|
name = "roboco"
|
||||||
version = "0.13.0"
|
version = "0.14.0"
|
||||||
description = "AI Agents Company - A virtual organization of AI agents functioning as a software development workforce"
|
description = "AI Agents Company - A virtual organization of AI agents functioning as a software development workforce"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "Renzo Franceschini", email = "rennf93@users.noreply.github.com"}
|
{name = "Renzo Franceschini", email = "rennf93@users.noreply.github.com"}
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ A virtual organization of 25 AI agents + 1 human CEO,
|
|||||||
designed to operate as a complete software development workforce.
|
designed to operate as a complete software development workforce.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "0.13.0"
|
__version__ = "0.14.0"
|
||||||
|
|
||||||
# Core exports
|
# Core exports
|
||||||
from roboco.config import settings
|
from roboco.config import settings
|
||||||
|
|||||||
+2
-2
@@ -28,7 +28,7 @@ class Settings(BaseSettings):
|
|||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
# Application
|
# Application
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
app_version: str = "0.13.0"
|
app_version: str = "0.14.0"
|
||||||
debug: bool = False
|
debug: bool = False
|
||||||
environment: str = Field(
|
environment: str = Field(
|
||||||
default="development", pattern="^(development|staging|production)$"
|
default="development", pattern="^(development|staging|production)$"
|
||||||
@@ -668,7 +668,7 @@ class Settings(BaseSettings):
|
|||||||
agent_image_tag: str = Field(
|
agent_image_tag: str = Field(
|
||||||
default="",
|
default="",
|
||||||
description=(
|
description=(
|
||||||
"Tag for pre-built agent images (e.g. 'latest' or '0.13.0'). Empty "
|
"Tag for pre-built agent images (e.g. 'latest' or '0.14.0'). Empty "
|
||||||
"leaves the tag implicit (':latest'); only meaningful with "
|
"leaves the tag implicit (':latest'); only meaningful with "
|
||||||
"agent_image_registry set."
|
"agent_image_registry set."
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user