mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
517bee7d285fdfc996f68099db5f8db79dbf057b
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
517bee7d28 |
[chore] panel: prettier reformat across the codebase
Apply `pnpm format` (prettier 3.8.5, 80-col / double-quote / semi /
trailing-comma-all) to the 223 pre-existing panel files that predated the
prettier infra added in
|
||
|
|
c09cf80b40 |
Feature/observability gateway health (#247)
* feat(observability): revision_count + audit_log query index (migration 045)
Adds tasks.revision_count (the O(1) rework counter — forward-only, existing
rows default 0) and the composite index audit_log(target_id, event_type,
timestamp) that powers the cycle-time and rework reconstruction queries.
Verified the real upgrade/downgrade/upgrade chain on a throwaway pgvector PG.
First task of the 0.10.0 observability dashboards.
* feat(observability): count reworks + attribute qa_fail/pr_fail to the rejector
Every transition into needs_revision increments tasks.revision_count at the
single audit chokepoint (exactly once per bounce, across all paths incl. pr_fail
and ceo_reject), so the rework rate is an O(1) read. A QA or PR-review bounce
also emits a named task.qa_fail / task.pr_fail audit event carrying the
rejector's agent_id, so the per-agent rework scorecard charges the rejection to
the reviewer who made it, not the developer who owns the task.
* feat(observability): cycle-time, bottleneck, rework, and scorecard metrics
MetricsService gains four read methods on the audit_log + tasks data: per-stage
cycle time reconstructed from the transition journey (excluding the named
qa_fail/pr_fail events), bottleneck distribution (cumulative dwell + live parked
counts), rework rate (overall/by-team/by-agent with rejector attribution + cost
via spawn-session task_id), and a fused per-agent/per-cell scorecard. Dataclass
models with to_dict(). Verified against a real Postgres journey.
* feat(observability): cycle-time/bottleneck/rework/scorecard read endpoints
Thin read-only routes on the dashboard router delegating to MetricsService:
/metrics/cycle-time, /metrics/bottlenecks, /metrics/rework, and
/metrics/scorecard/{agent,team}. 404 when an agent scorecard target is absent.
5 route tests (200 + shape + the agent-404 case).
* feat(panel): Delivery observability tab (cycle-time, bottlenecks, rework, scorecards)
A third Metrics tab built on the observability endpoints: a per-stage
cycle-time bar chart, a bottleneck panel (worst stage + cumulative dwell +
live parked counts), a rework panel (rate + by-team + by-agent attribution +
cost), and per-cell scorecards. Reuses Recharts + Card/Badge/Skeleton and the
React-Query hook pattern; observabilityApi mirrors usageApi with mock-mode
fallbacks. tsc + eslint clean; 113 panel tests pass.
* docs(observability): changelog + CLAUDE.md for the delivery dashboards
* feat(gateway-health): recover a broken-but-alive agent instead of protecting it
The verb-heartbeat cannot tell a quiet-healthy agent from one whose MCP gateway
is broken (a corrupted /app/.venv firing no verb) yet whose container is up — the
reaper's live-skip would shield it forever. The reaper now probes the gateway
out-of-band (docker exec: does the gateway venv import its deps?) and, once it
has been broken past gateway_health_grace_seconds (tolerating a transient probe
miss), kills + evicts the container so it falls through to release + respawn.
Probe-inconclusive or healthy spares the container. Gated by
gateway_health_enabled (default-on reliability fix; in the panel Feature Flags).
Defers the optional agent-side self-check + full registry re-adoption — the
reaper's docker-liveness fallback already recovers a broken-after-restart agent.
* docs(gateway-health): changelog + CLAUDE.md for broken-but-alive recovery
* docs(observability): user-facing docs for the Delivery dashboards + gateway-health
Documents the new Metrics -> Delivery tab (cycle-time, bottlenecks, rework with
rejector attribution, cell scorecards) in the panel guide and the operations
health-and-metrics guide, and adds the gateway-health env vars + an agent-gateway
recovery note. Published MkDocs site only; settings.md's default-off flag table
intentionally omits the default-on gateway-health flag (same as overload-break).
* chore(release): cut 0.10.0 (changelog section + version refs)
* fix(gateway): exempt PM coordinators from single-task claim guards
A Main/Cell PM plans and delegates many root tasks in parallel; the work
then runs in the delegated cells, not in the PM's own hands. But the
claim-time concurrency guards meant for developers — already_active and
paused (the latter firing after i_am_idle auto-pauses the PM's own
umbrella) — were applied to the PM too, so once it held one root it could
never plan a second: it thrashed between its claimed roots and respawned
forever, burning tokens for zero progress.
_run_claim_guards now skips already_active/paused for the coordinator PM
roles (_COORDINATOR_ROLES = {main_pm, cell_pm}); only unmet_dependency — a
real upstream sequence constraint, which parks the root back to pending —
still gates a PM. paused_tasks_guard also excludes the target task itself,
so a PM re-entering its own paused umbrella never self-blocks.
Tests: a coordinator plans a second root with one in_progress + one paused
sibling (full path + claimed-recovery path), the paused target exclusion,
and the developer guards still fire. Repurposed the pre-fix test that
asserted the now-removed PM block.
* fix(metrics): coerce SQL avg/extract hours aggregates to float (panel toFixed crash)
EXTRACT(epoch ...) returns numeric on PostgreSQL 14+, which asyncpg surfaces
as a Decimal; a Decimal serializes to a quoted JSON string, so the panel's
avg_cycle_hours.toFixed(1) (and the other hours fields) threw 'toFixed is not
a function' and blanked the Delivery tab.
A single _as_hours helper now rounds every SQL-averaged hours field to a real
float — avg_cycle_hours on the new scorecards plus the pre-existing
avg_completion_hours / avg_blocked_hours / longest_blocked_hours. Token and
cost fields were already float()-cast and are unaffected.
Regression test asserts _as_hours coerces Decimal -> float and preserves the
None/zero behavior.
* feat(panel): edit a task's sequence from the details page
A task's sequence (order within siblings, lower runs first) was display-only
with no way to change it from the UI, and TaskUpdate didn't carry the field
so PATCH couldn't set it either. The details page's Dependencies tab now has
an inline sequence editor mirroring the parent / dependency editors, and
PATCH /tasks/{id} accepts a sequence field (owner or privileged role) through
the existing generic update path.
* fix(mypy): green the full make-quality type gate
make quality runs 'mypy roboco/ tests/', which the per-module checks on the
0.10.0 branch never exercised. Two issues surfaced:
- The coordinator-exemption change added role_str to
Choreographer._run_claim_guards but not to the ChoreographerHelpers
protocol base, so the composed Choreographer had incompatible base-class
signatures. Sync the protocol signature.
- The gateway-health / stale-reaper tests stubbed methods by direct
assignment (orch._m = AsyncMock()) and typed their duck-typed task doubles
as object, tripping method-assign / assignment / attr-defined. Switch to
monkeypatch.setattr (keeping a local mock ref for the assertions) and type
the doubles as Any — no type: ignore.
Full mypy roboco/ tests/ clean (785 files); the 21 runtime tests pass.
* fix(metrics): static cycle-time SQL — clear bandit B608 (CI gate)
The cycle-time query interpolated an optional team clause into the text() SQL
via an f-string, which bandit flags as B608 (hardcoded SQL) and turned the
merge gate red. The team value was always a bound parameter, so it was a false
positive — but the f-string is the trigger. Rebuilt as one static query with
(CAST(:team AS text) IS NULL OR a.details->>'team' = :team) and an always-bound
team param (CAST, not ::text — SQLAlchemy's :param parser collides with
PostgreSQL's :: cast operator, which broke the query as a stray param).
Full make quality green vs a real pgvector PG (all 21 gate steps).
---------
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
|
||
|
|
818f2ac7a6 |
[21e195cd] Panel-wide UI standardization and usability pass (#194)
* [4c179e3a] Add git pull, fetch, and rebase backend endpoints (#190) * [f966f772] feat(git): add pull, fetch, and rebase endpoints with integration tests (#185) - Add GitPullRequest/Response, GitFetchRequest/Response, GitRebaseRequest/Response schemas - Add GitService.pull(), fetch(), and rebase() methods using _network_git_timeout() - Add POST /api/git/pull, /api/git/fetch, /api/git/rebase route handlers - Rebase detects conflicts via git diff --name-only --diff-filter=U and aborts cleanly - Integration tests cover success path and GitCommandError→500 for all three endpoints - Rebase conflict test verifies conflict=True with populated conflicted_files list Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev> * [26e2b7af] test(git): add AsyncMock unit tests for rebase_onto_base conflict-state handling (#186) New test_git_rebase.py covers three branches of rebase_onto_base: - success path: rebase exits 0, returns rebased status, abort never called - conflict path: non-zero exit → diff → abort → returns conflict+files - resilience: both rebase and abort exit non-zero, still returns conflict dict without exception All tests use AsyncMock with side_effect sequences to mock _run_git at the service-method level. Co-authored-by: Backend Developer 2 <be-dev-2@agents.roboco.dev> --------- Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev> Co-authored-by: Backend Developer 2 <be-dev-2@agents.roboco.dev> * [551b1dbf] Panel-wide frontend UI standardization and page fixes (#193) * [1ec787b2] feat(panel): design-system sweep — full-width layouts, scrollbar fix, Secretary button, component audit (#188) - Settings page: remove max-w-3xl, wrap cards in grid-cols-1 lg:grid-cols-2 two-column layout - AI Providers page: remove max-w-5xl so AIRoutingCard fills available width - Journals AgentList: replace ScrollArea with overflow-y-auto div to eliminate nested scrollbar - Secretary chat input: add items-stretch to flex row so Send/Start button matches Textarea height - Component audit: replace all raw <button>/<input>/hand-rolled badge spans outside components/ui/ with canonical Button, Checkbox, Badge variants across 15 files: - ai-routing-card.tsx: ModeButton → Button, checkbox → Checkbox, badge spans → Badge - self-hosted-section.tsx: eye-toggle → Button ghost icon-sm, badge spans → Badge - journals/agent-item.tsx, communications/channel-item.tsx → Button ghost - kb-search-bar.tsx, kb-filters.tsx → Button ghost - kb-category-nav.tsx, git-log-panel.tsx → Button ghost - communications/page.tsx (channel + group lists) → Button ghost - projects/project-table.tsx, products/product-table.tsx → Button link - git-branch-panel.tsx (local + remote lists) → Button ghost - tasks/dependency-selector.tsx: Button ghost + Checkbox for visual indicator - tasks/task-table.tsx: sortable header + expand toggle → Button ghost - business/goals-tab.tsx: hidden button → Button Co-authored-by: Frontend Developer 1 <fe-dev-1@agents.roboco.dev> * [435b37b4] feat(metrics,notifications): URL-persisted tab state, semantic chart colors, humanized counts (#187) - Notifications page: replace useState with useSearchParams/useRouter for ?tab= URL parameter (all/unread/pending, default: unread); Suspense wrapper with skeleton fallback for SSR compatibility. - Metrics page: split into Performance tab (Velocity + Task Status + Agent Status + Team Health) and Token Usage tab (TokenUsageCostsSection) with ?tab= URL parameter (default: performance); Suspense wrapper; Refresh button moved inside PerformanceTabContent; humanizeCount() helper applies K/M suffixes to all MetricCard numeric values >= 1000. - Chart components (usage-time-series, agent-usage, team-usage, model-donut): replace var(--chart-N) CSS vars with explicit semantic hex colors — #3b82f6 blue for informational, #f59e0b amber for warning/pending, #22c55e green for success/healthy, #ef4444 red for error/blocked, #a855f7 purple for supplemental. pnpm lint and pnpm typecheck pass with zero new errors. Co-authored-by: Frontend Developer 2 <fe-dev-2@agents.roboco.dev> * [ccd256f4] Kanban mobile viewport: 375px layout, column navigation, 44px touch targets (#191) * [ccd256f4] feat(kanban): mobile 375px layout with column navigator and 44px touch targets - KanbanBoard: add activeColumnIndex state + mobile prev/next column navigator (lg:hidden); existing horizontal-scroll layout hidden on mobile (hidden lg:flex). Desktop DnD behavior unchanged. - KanbanColumn: add optional className prop (cn-based) so mobile view can pass w-full/sm:w-full to fill the viewport. - KanbanCard: bump all action buttons to min-h-11 (44px) touch targets (Assign, Pass, Fail, Move-forward). * [ccd256f4] fix(kanban): change breakpoint from lg to sm for mobile/desktop layout switch AC3 requires >=640px viewport to show multi-column layout (sm: breakpoint). Previous impl used lg: (1024px), leaving 640-1023px in single-column mode. Change: - Mobile navigator div: lg:hidden → sm:hidden - Desktop multi-column div: hidden lg:flex → hidden sm:flex At <640px: single-column with prev/next navigator (375px mobile use case). At >=640px: full horizontal-scroll multi-column layout (per AC3). DnD behavior and all other layout unchanged. --------- Co-authored-by: Frontend Developer 1 <fe-dev-1@agents.roboco.dev> * [23f02af4] Agents page On-Demand section + Board composition; Overview Quick Actions visibility + Team Health Intake/Secretary (#189) * [23f02af4] feat(agents,overview): On-Demand section, Board composition fix, Intake/Secretary in Quick Actions + Team Health - agent-definitions.ts: remove AgentRole.MAIN_PM from getBoardAgents (Main PM has its own dedicated section; including it there was redundant). Add getOnDemandAgents() that catches agents not in any standard team (board/main_pm/backend/frontend/ux_ui/marketing) and not a standard cell role — surfaces prompter/intake agents that the API may return. - agents/page.tsx: import getOnDemandAgents; add a conditional 'On-Demand Agents' AgentGrid section (only rendered when the API returns at least one matching agent, e.g. the Intake interviewer). - quick-actions-bar.tsx: add 'Task Intake' button (→/prompter, Sparkles icon) and 'Secretary' button (→/business?tab=secretary, Bot icon) alongside existing quick actions so operators can reach on-demand agents from the Overview in one click. - team-health-cards.tsx: add OnDemandAgentCard sub-component (link card with On-Demand badge) and render static cards for 'Task Intake' and 'Secretary' appended after the API-driven TeamHealthCard list, giving them equal visual presence in the Team Health section. pnpm lint and pnpm typecheck pass with zero new errors. * [23f02af4] fix(agents,overview): QA revision — enum entries, QuickActions placement, On-Demand title, Board PR_REVIEWER AC3: types/index.ts AgentRole enum adds PR_REVIEWER, PROMPTER, SECRETARY. agent-selector.tsx ROLE_LABELS exhaustive Record updated accordingly. AC4: command-center.tsx QuickActionsBar moved to after Team Health section, before CEO Approval Queue and data-heavy grid rows — visible without scrolling on a 900px viewport. AC1: agents/page.tsx On-Demand AgentGrid title fixed to 'On-Demand' (was 'On-Demand Agents' in prior commit). AC2: agent-definitions.ts getBoardAgents adds explicit PR_REVIEWER inclusion and uses inclusion-based getOnDemandAgents (PROMPTER|SECRETARY roles). AC5: team-health-cards.tsx static OnDemandAgentCard implementation refined with correct fallback rendering when no API team data. AC6: pnpm lint and pnpm typecheck (src only) pass with zero new errors. --------- Co-authored-by: Frontend Developer 2 <fe-dev-2@agents.roboco.dev> Co-authored-by: Frontend Developer 1 <fe-dev-1@agents.roboco.dev> * [b1c59206] Git page: Pull, Fetch, Rebase buttons wired to backend; Rebase destructive confirmation dialog (#192) * [b1c59206] feat(git): add Pull, Fetch, Rebase operations to Git page with destructive confirmation dialog for Rebase - Add GitPullRequest/Response, GitFetchRequest/Response, GitRebaseRequest/Response types - Add gitApi.pull(), gitApi.fetch(), gitApi.rebase() with mock stubs for /git/pull, /git/fetch, /git/rebase - Add useGitPull, useGitFetch, useGitRebase mutation hooks with cache invalidation; exported via useGitOperations - Add Pull (Download icon), Fetch (RefreshCcw icon), Rebase (GitGraph icon) buttons to GitActionsPanel - Rebase button triggers AlertDialog with destructive confirmation before calling API - Wire handlePull, handleFetch, handleRebase handlers in git-browser.tsx with toast feedback * [b1c59206] fix(git): add destructive styling and branch name to Rebase AlertDialog - Add className='border-destructive bg-destructive/5' to AlertDialogContent so the dialog container has the required red-tinted styling (AC3) - Update AlertDialogDescription to interpolate status?.current_branch so the dialog body explicitly names the branch being rebased (AC3) --------- Co-authored-by: Frontend Developer 2 <fe-dev-2@agents.roboco.dev> --------- Co-authored-by: Frontend Developer 1 <fe-dev-1@agents.roboco.dev> Co-authored-by: Frontend Developer 2 <fe-dev-2@agents.roboco.dev> * [3f305ed9] Frontend: Fix git control contract, complete Secretary restyling, and apply polish (CEO revision) (#199) * [72de8a65] fix(git): correct Pull/Fetch/Rebase types, API mocks, request fields, and toast handlers (#197) - types/git.ts: GitPullResponse and GitFetchResponse now have current_branch, has_changes, staged_files, unstaged_files, untracked_files, ahead, behind (matching backend GitStatusResponse); removed nonexistent commits_received/ refs_updated/remote fields - types/git.ts: GitRebaseRequest now uses target_branch: string (not onto?: string); GitRebaseResponse now has conflict: boolean and conflicted_files: string[] (removed branch/onto/commits_rebased); task_id made optional on all three request types - lib/api/git.ts: Updated mock returns for pull/fetch/rebase to match new types - git-actions-panel.tsx: onRebase prop now (targetBranch: string) => void; Rebase AlertDialog now contains an Input for target_branch; AlertDialogAction disabled when targetBranch empty and passes the value to onRebase - git-browser.tsx: handlePull and handleFetch toast references result.current_branch; handleRebase accepts targetBranch, sends target_branch in payload, toasts result.conflict and result.conflicted_files; no 'manual' task_id for any pull/fetch/rebase operation Co-authored-by: Frontend Developer 1 <fe-dev-1@agents.roboco.dev> * [be6a17fc] feat(ui): design-system polish — chart tokens, KB aria-label, Kanban touch targets (#196) - kb-search-bar.tsx: add aria-label="Clear search" to the clear (X) button - model-usage-donut.tsx: replace hex CHART_COLORS with var(--chart-1)…var(--chart-5) - usage-time-series-chart.tsx: replace hex stopColor/stroke with var(--chart-1)/var(--chart-2) - agent-usage-chart.tsx: Bar fill hex → var(--chart-1) - team-usage-chart.tsx: Bar fill hex → var(--chart-1) - kanban-card.tsx: min-h-11 → max-sm:min-h-11 (44px touch target mobile-only, 3 buttons) - secretary-tab.tsx: already compliant (Button + design-system tokens), no change needed Co-authored-by: Frontend Developer 2 <fe-dev-2@agents.roboco.dev> --------- Co-authored-by: Frontend Developer 1 <fe-dev-1@agents.roboco.dev> Co-authored-by: Frontend Developer 2 <fe-dev-2@agents.roboco.dev> * [d62036bd] Backend: Fix git endpoint schemas, add safety gates, and unit tests (CEO revision) (#200) * [d0593fe3] feat(git): remove agent_id from schemas and add service-layer safety gates (#195) - Remove agent_id field from all 9 git request schemas (GitCreateBranchRequest, GitCheckoutRequest, GitCommitRequest, GitPushRequest, GitCreatePRRequest, GitMergePRRequest, GitPullRequest, GitFetchRequest, GitRebaseRequest); agent identity comes from JWT auth context - Make task_id Optional[UUID]=None in GitPullRequest, GitFetchRequest, GitRebaseRequest - Add field_validator to GitRebaseRequest rejecting target_branch starting with '-' or equal to 'master'/'main' - Add lightweight PullRequest, FetchRequest, RebaseRequest schemas for gateway layer - Add dirty-workspace check to GitService.pull() (raises ValidationError if porcelain output) - Switch GitService.pull() to --ff-only; raises ValidationError with diverged-branch message on non-zero exit - Add master/main guard to GitService.rebase() for both head_branch and target_branch - Update callers: routes/tasks.py (2x), services/task.py, tests/unit/services/test_git.py (2x) Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev> * [a2f96961] Add role-gated rebase endpoint and unit tests (test_git_rebase.py) (#198) * [a2f96961] feat(git): add role-gated rebase endpoint and unit tests Add role-gate to POST /rebase restricting access to DEVELOPER and CELL_PM roles; add master/main protected-branch guard to GitService.rebase() before any git subprocess runs; add 4 unit tests in tests/unit/services/test_git_rebase.py covering both target-branch and head-branch REBASE_FORBIDDEN cases * [a2f96961] fix(git): invert rebase role gate, add ownership check, schema validator, and missing tests - _REBASE_ALLOWED_ROLES changed from {DEVELOPER, CELL_PM} to {CEO, CELL_PM, MAIN_PM} so developers correctly receive 403 per AC1/AC2 - rebase_branch() now verifies task ownership for non-CEO PM callers: if task_id is provided and the task is not assigned to the calling agent, returns 403/404 - GitRebaseRequest.target_branch gets a @field_validator rejecting '-' prefix names and protected branch names (main, master, develop) - GitService.pull() gains pre-flight safety gates: raises ValidationError DIRTY_TREE when staged/unstaged changes exist, DIVERGED_BRANCH when ahead > 0 and behind > 0 - test_git_rebase.py adds 9 new tests: pull() dirty-tree ValidationError, pull() diverged-branch ValidationError, pull() success path, schema validator for '-' prefix and protected names, and route-level tests confirming HTTP 403 for DEVELOPER and HTTP 200 for CELL_PM on POST /rebase * [a2f96961] fix(tests): add type annotations for tuple variables in test_git_rebase.py mypy needs explicit tuple type annotations when assigning bare tuples to variables used as mock side_effect return values — fixes var-annotated error caught by the server-side quality gate --------- Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev> Co-authored-by: Renn F <rennf93@users.noreply.github.com> --------- Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev> Co-authored-by: Renn F <rennf93@users.noreply.github.com> * [94015c6d] Frontend R3: Fix legacy git taskId coercion + rebase placeholder + phantom fields (#204) * [401ddb40] fix(git): remove phantom fields from GitPullRequest/GitFetchRequest and make task_id optional in write request interfaces; use taskId || undefined in git-browser.tsx handlers to avoid 422 errors when no task context is active (#201) Co-authored-by: Frontend Developer 1 <fe-dev-1@agents.roboco.dev> * [cca8d0c0] fix(git): fix rebase placeholder and surface backend error in toast (#202) git-actions-panel.tsx: change rebase target_branch Input placeholder from "e.g. main or origin/main" to "Remote ref (e.g. origin/HEAD)" so no default branch name (main/master/develop) is suggested. git-browser.tsx: import getErrorMessage from @/lib/api/client and use it in handleRebase catch block instead of the hardcoded string "Failed to rebase". getErrorMessage extracts the real detail from AxiosError.response.data.detail and falls back to a non-empty generic message, satisfying both the detail-surfacing and fallback criteria. Co-authored-by: Frontend Developer 2 <fe-dev-2@agents.roboco.dev> --------- Co-authored-by: Frontend Developer 1 <fe-dev-1@agents.roboco.dev> Co-authored-by: Frontend Developer 2 <fe-dev-2@agents.roboco.dev> * [1ea0fbcb] Backend R3: Relax legacy git schemas + fix integration tests (#206) * [219c539b] Make task_id Optional in git request schemas and update service methods (#205) * [219c539b] feat(git): make task_id Optional in git schemas and add None-guards in service methods - GitCommitRequest, GitPushRequest, GitCreatePRRequest, GitMergePRRequest now have task_id: UUID | None = None - commit_for_task, push_for_task, create_pr_for_task, merge_pr_for_task skip ownership/state checks when task_id is None and proceed to the git operation - Added 16 unit tests in tests/unit/api/routes/test_git_optional_task_id.py covering schema validation and HTTP endpoint responses - Added 4 integration tests in tests/integration/test_git_routes.py for no-422 behaviour - All quality gates pass: ruff format, ruff check, mypy, pytest * [219c539b] fix(tests): remove unused type-ignore comments, redundant cast, and invalid agent_id kwarg in git_optional_task_id unit tests --------- Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev> * [de95ce94] test(git): fix 3 rebase integration tests to use non-protected target_branch (#203) - Add pm_git_client fixture (CELL_PM role) needed for the role-gated rebase endpoint - Change target_branch from 'main' to 'develop' in test_rebase_success, test_rebase_conflict, and test_rebase_git_command_error - Remove task_id from request bodies (optional field; random UUIDs trigger 404) - Switch all 3 rebase tests to use pm_git_client instead of git_client Co-authored-by: Backend Developer 2 <be-dev-2@agents.roboco.dev> --------- Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev> Co-authored-by: Backend Developer 2 <be-dev-2@agents.roboco.dev> * chore: ruff format test_agent_image_registry.py (unblock quality gate) --------- Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev> Co-authored-by: Backend Developer 2 <be-dev-2@agents.roboco.dev> Co-authored-by: Frontend Developer 1 <fe-dev-1@agents.roboco.dev> Co-authored-by: Frontend Developer 2 <fe-dev-2@agents.roboco.dev> Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
bb9d4ff12a |
[87c7f3ec] Responsive grids: xl/2xl breakpoints + mobile overflow fix across all pages (#158) (#162) (#163)
* [87c7f3ec] feat(responsive): add xl/2xl breakpoint classes to dashboard grid layouts Adds xl: and 2xl: Tailwind breakpoint classes to all grid layouts in command-center.tsx, auditor-dashboard.tsx, team-health-cards.tsx, agent-grid.tsx, and metrics/page.tsx so content can expand denser beyond the current lg cap at ultrawide (2560px) viewports. Key changes: - team-health-cards.tsx: xl:grid-cols-4 2xl:grid-cols-6 (up to 6 teams) - metrics/page.tsx Team Health: xl:grid-cols-5 2xl:grid-cols-6 - agent-grid.tsx: xl/2xl classes for all 3 column variants - TokenUsageCostsSection: 2xl:grid-cols-6 added to row 1 (already had xl) - Fixed-size grids (2-4 items): xl matches lg, 2xl same as xl * [87c7f3ec] fix(mobile): stack grid-cols-12 layouts on mobile and fix git-browser header overflow communications/page.tsx: change col-span-3/6 to col-span-12 lg:col-span-3/6 so the three panels stack vertically on 375px viewports instead of being squished to 25%/50% widths. Gate the viewport-height constraint (h-[calc(100vh-7rem)]) and flex-1/min-h-0 to lg: so mobile can scroll naturally. Also fixes the Suspense fallback skeleton with the same responsive col-spans. git-browser.tsx: header flex row now goes flex-col on mobile and sm:flex-row on sm+ (640px), eliminating the overflow from the w-64 SelectTrigger plus Refresh button (346px combined) at 375px (327px content width). SelectTrigger is w-full on mobile and sm:w-64 on sm+. journals/page.tsx and git-browser.tsx grids already use col-span-12 lg:col-span-X so no grid changes needed there. --------- Co-authored-by: Frontend Developer 2 <fe-dev-2@agents.roboco.dev> |
||
|
|
b3057628b0 |
[499f9eb1] Token Usage & Cost Analytics — Full-Stack Instrumentation, Persistence, and Visualization (#90)
* [cd2bf666] feat(usage): add token usage types, API client, hooks, and UI components (#87) (#88) - Append 5 TypeScript interfaces to src/types/index.ts: TokenUsageSnapshot, AgentUsageRow, UsageSession, UsageTimePoint, ModelUsageSlice - Create src/lib/api/usage.ts: Axios singleton + isMockMode guards for getUsageSnapshot, getUsageTimeSeries, getAgentUsage, getUsageSessions, getModelUsage - Create src/hooks/use-usage.ts: usageKeys factory + useUsageSnapshot, useUsageTimeSeries, useAgentUsage, useUsageSessions, useModelUsage hooks - Create UsageOverviewPanel (dashboard/usage-overview-panel.tsx): 6 metric rows with Skeleton loading state; week-over-week trend arrow for cost - Update CommandCenter: Metrics+Alerts row expanded from 2-col to 3-col grid adding UsageOverviewPanel - Create src/components/metrics/ folder: UsageTimeSeriesChart (recharts stacked AreaChart with var(--chart-1/2/3)), ModelUsageDonut (PieChart), AgentUsageChart and TeamUsageChart (BarChart), SessionsTable (sortable columns + 10-row Prev/Next pagination) - Update Metrics page: Token Usage & Costs section with 5 rows (summary cards, time series+donut, agent+team bar charts, projection+cache efficiency, sessions table) - Add usage mini-bar to AgentCard: token count + cost + progress bar; AgentGrid and Agents page pass agentUsageMap through - Install recharts 3.8.1 - Export all new symbols through their barrel index.ts files Co-authored-by: Frontend Developer 1 <fe-dev-1@agents.roboco.dev> * [10372f0f] Implement full token usage instrumentation: DB migration, SDK endpoints, orchestrator hooks, analytics API, WebSocket events, dashboard integration (#86) (#89) * [10372f0f] feat(token-usage): add Alembic migration 026 for token usage tables Create agent_spawn_sessions, token_usage_snapshots, and daily_usage_rollups tables with correct BIGINT columns, indexes, and unique constraint. Chain: 025_agentrole_prompter → 026_token_usage_tables. * [10372f0f] feat(token-usage): add ORM table classes for token usage instrumentation Add AgentSpawnSessionTable, TokenUsageSnapshotTable, DailyUsageRollupTable to db/tables.py. Import BigInteger and Date from SQLAlchemy. All columns match the migration schema with BIGINT token counts and proper indexes. * [10372f0f] feat(billing): add pricing module with calculate_cost() function Create roboco/billing/__init__.py and roboco/billing/pricing.py with calculate_cost() supporting Claude opus/sonnet/haiku models with input/output/cache pricing. Unknown models return 0.0 without raising. * [10372f0f] feat(sdk): add POST /usage/report and GET /usage/status endpoints to agent SDK Extend _SessionState with token counters. Add TokenReportRequest and TokenUsageStatus models. POST /usage/report additively accumulates token counts; GET /usage/status returns current session totals for sweeper polling. * [10372f0f] feat(orchestrator): add token usage instrumentation hooks - _launch_spawn() calls _record_spawn_session() after successful container spawn - stop_agent() calls _finalize_spawn_session() before container removal - _run_sweep() calls _sweep_token_snapshots() and _sweep_daily_rollup() each tick - New methods: _record_spawn_session, _finalize_spawn_session, _sweep_token_snapshots, _sweep_daily_rollup in TOKEN USAGE section * [10372f0f] feat(api): add token usage analytics API with 7 endpoints Create roboco/services/usage.py (UsageService) and roboco/api/routes/usage.py. Endpoints: GET /api/usage/summary, /time-series, /by-agent, /by-team, /by-model, /projection, /cache-efficiency. Register in app.py. * [10372f0f] feat(dashboard): add usage_summary field to CEO dashboard Add UsageSummary schema (tokens_today, cost_today_usd) to dashboard schemas. Add usage_summary: UsageSummary | None to CEOOverview. Update get_ceo_overview() to populate usage_summary from daily_usage_rollups. * [10372f0f] fix(billing/tests): remove dead except block in _sweep_daily_rollup, add unit tests for pricing.py and services/usage.py - Remove unreachable `except Exception as e` block in orchestrator.py _sweep_daily_rollup() (lines 3376-3381) which referenced undefined `agent_id` and was copy-pasted from _sweep_token_snapshots by mistake - Add tests/unit/billing/test_pricing.py: 31 tests covering opus/sonnet/ haiku tiers with all 4 token types, unknown model → 0.0, empty string → 0.0, and substring-match priority (longer fragment wins) - Add tests/unit/services/test_usage.py: 25 tests covering get_summary trend_pct edge cases (prev=0, both=0, prev>0), get_by_agent/team/model pct_of_total summing to 100%, get_projection formula (avg_daily×30), and get_cache_efficiency hit-rate and cost_saved arithmetic - pricing.py: 100% coverage; services/usage.py: 83% coverage (>80% target) * [10372f0f] fix(usage): include cache tokens in time-series total_tokens to fix AC9 consistency violation get_time_series() previously computed total_tokens as tokens_input + tokens_output only. get_summary() includes all 4 token types (input + output + cache_read + cache_write). AC9 requires both endpoints to agree on their totals for the same period. Fix: add tokens_cache_read and tokens_cache_write to the SELECT query in get_time_series() and include them in the total_tokens calculation. Also adds 4 new unit tests in TestGetTimeSeries covering: - total_tokens includes cache_read and cache_write (the AC9 guard) - zero cache tokens still produces correct total - empty result returns empty list - required fields are present in each point * [10372f0f] fix(usage): remove unused imports and include cache tokens in breakdown totals (AC10) - Remove import math (F401 — never used) - Remove text from sqlalchemy import (F401 — never used) - Remove unused local calculate_cost import inside get_cache_efficiency (F401) - Add tokens_cache_read and tokens_cache_write to SELECT in get_by_agent, get_by_team, and get_by_model; update grand_total and per-item total to include all 4 token types so totals match get_summary() (AC10 fix) - Update test mock rows to include explicit tokens_cache_read=0 and tokens_cache_write=0 so they work with the fixed code - Add new test cases: test_cache_tokens_included_in_total_tokens and test_pct_of_total_sums_to_100_with_cache_tokens for each breakdown class --------- Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev> * [44b9eb1f] feat(usage): align frontend API client, TS types, and chart components to real backend contract (#92) (#94) Update all usage-related frontend code to match the actual FastAPI backend response shapes and endpoint paths: - panel/src/lib/api/usage.ts: rewrite all 7 API functions to use correct endpoint paths (/usage/summary, /usage/by-agent, /usage/by-model, /usage/by-team, /usage/time-series, /usage/projection, /usage/cache-efficiency); send period query param (24h/7d/30d not hours); mock generators produce data matching real backend shapes exactly; getUsageSessions returns [] in prod (no /usage/sessions endpoint exists) - panel/src/types/index.ts: replace TokenUsageSnapshot with UsageSummary (tokens_input/tokens_output/total_cost_usd/trend_pct); update AgentUsageRow to use agent_slug/total_tokens/cost_usd/pct_of_total; add TeamUsageRow, UsageProjection, CacheEfficiencyResponse; update UsageTimePoint to use bucket field; update UsageSession to use agent_slug - panel/src/hooks/use-usage.ts: rewrite all hooks to match new API and types; add useTeamUsage, useUsageProjection, useCacheEfficiency hooks - panel/src/components/metrics/usage-time-series-chart.tsx: use bucket field (not timestamp) for axis labels - panel/src/components/metrics/agent-usage-chart.tsx: use agent_slug and total_tokens (not agent_name/tokens_today) - panel/src/components/metrics/team-usage-chart.tsx: rewrite to accept TeamUsageRow[] from API directly - panel/src/components/metrics/model-usage-donut.tsx: use total_tokens, cost_usd, pct_of_total (not tokens/cost/percentage) - panel/src/components/metrics/sessions-table.tsx: use agent_slug, sort keys updated - panel/src/components/dashboard/usage-overview-panel.tsx: use useUsageSummary with tokens_input/tokens_output/total_cost_usd/trend_pct - panel/src/app/(dashboard)/metrics/page.tsx: wire all new hooks, add TeamUsageChart, ProjectionCard, CacheEfficiencyCard with correct types - panel/src/app/(dashboard)/agents/page.tsx: key agentUsageMap by agent_slug - panel/src/components/agents/agent-card.tsx: use total_tokens and cost_usd Co-authored-by: Frontend Developer 1 <fe-dev-1@agents.roboco.dev> * [2161b832] fix: SDK_PORT constant, stop_agent lock refactor, usage_session_id binding, rollup 7-day window (#93) (#95) - Add SDK_PORT = 9000 module-level constant to orchestrator.py; replace hardcoded 9000 in _sweep_budget_exceeded URL with SDK_PORT - Add UUID to TYPE_CHECKING imports to satisfy ruff F821 - Refactor stop_agent: call _finalize_spawn_session BEFORE acquiring self._lock so the SDK HTTP round-trip does not hold the lock - Add usage_session_id: UUID | None field to AgentInstance dataclass - Change _record_spawn_session to return UUID | None; wire return value back to instance.usage_session_id in _launch_spawn - Update _finalize_spawn_session to use WHERE id=usage_session_id for direct session row lookup when usage_session_id is not None - Add started_at >= (now_utc - 7 days) filter to _sweep_daily_rollup aggregate query to avoid re-aggregating all-time history each sweep Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev> * [2e0759e1] fix: pricing accuracy, import ordering, session-id binding, rollup cleanup, write-hook tests (#97) (#98) - pricing.py: correct claude-opus-4 prices (5/25/0.50/6.25 not 15/75/1.5/3.75) and haiku family prices (1/5/0.10/1.25 not 0.8/4/0.08/0.20); add Ollama zero-cost early-return; add structlog warning for unmatched model names - app.py: move usage_router import before routes.v1 block (ruff isort fix) - orchestrator.py _sweep_daily_rollup: remove unused calculate_cost import; add blank line between stdlib (uuid4) and third-party (sqlalchemy) imports - orchestrator.py _sweep_token_snapshots: prefer direct lookup by instance.usage_session_id; fall back to agent_slug heuristic only when None - tests: add test_sweep_daily_rollup_inserts_new_row and test_stop_agent_finalizes_before_lock to test_orchestrator_write_hooks.py - usage.py, routes/usage.py, stream_bus.py, test files: ruff format/lint fixes Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev> * Mypy compliance * fix(migrations,tests): linearize forked migration chain + correct ceo_reject coordination-root expectation The master merge brought in 026_completed_dependency_ids alongside the rework's 026_token_usage_tables — both off 025, forking the alembic head and breaking the enum-parity test. Rebase token-usage onto 026_completed_dependency_ids (linear chain, single head). Also: test_ceo_reject_routes_coordination_task_to_main_pm asserted the old NEEDS_REVISION behavior; the lifecycle fix correctly routes a coordination root to PENDING (Main PM's claim source). Update the assertion. --------- Co-authored-by: Frontend Developer 1 <fe-dev-1@agents.roboco.dev> Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev> Co-authored-by: Renn F <rennf93@users.noreply.github.com> |
||
|
|
8e201901c0 | I mean, it's at a good place rn... |