Command center API core endpoints
## Epic 11717 — Executive AI command center
Original requirement (verbatim):
> Implement Something like this. Share code with Operator Dashboard.
> 10. Executive AI command center — Major differentiator
> Create one dashboard where a founder or CTO can see: All active projects. All AI employees. Development progress. Project health. Bugs and risks. Development expenses. Deployment status. Productivity and quality metrics.
> The owner should be able to ask: "What's happening with my company today?" and receive an accurate answer.
Settled inputs: the BA PRD (task 11718, R1–R14, OD-1..OD-12, A-1..A-8) and the Architecture (task 11719, §2.1 is this child's spec; §4 risks 1–3, 5). Read both artifacts on the epic before building.
## This child (Architecture C2, minus `/deployments` and the CI health factor)
New package `apps/api/app/exec_dashboard/` — a tenant-plane twin of the operator engine. Router `APIRouter(prefix="/api/exec/dashboard")`, every handler `@org_admin(Tenancy.CALLER_PLANE)` + `Depends(require_user)` (as `routes/org_siem.py:126-130`) + `parse_query` (`frame.py:163`). It composes `operator_dashboard` builders (`sections.usage/efficiency/results`, `derived.autonomy/funnel/anomalies`, `quality.quality`, `cost.*`, `derived._factor/health_of`, `frame.metric/grouped/envelope/cached`); `operator_dashboard` never imports `exec_dashboard`.
- Query: `org` dimension refused with **403** "org filter is operator-only"; a `project` id the caller cannot read → 404.
- **Cache-key fix (shared engine):** `frame.cached` key becomes `(section, query, knobs, seam.current_scope(), org_filter)`; operator behaviour unchanged. Mandatory two-org back-to-back test with the same query.
- **`frame.metric` gains optional `previous`**, emitted only when passed (operator payloads byte-identical).
- Endpoints (envelope shape with `as_of`): `/overview` (active_projects, tasks_in_flight, failed_or_stuck, spend_usd, worst_health), `/projects` (ProjectRow; health from non-CI factors for now), `/personas` (PersonaRow, labels from `PERSONA_LABELS`), `/progress`, `/risks` (RiskItem incl. `broken_session` via new `runner_breaks.broken_task_id`, plus anomalies), `/expenses`, `/productivity` (each KPI with `previous`). Shapes exactly as Architecture §2.1.
- Board-linked counts use `board_row_clauses` + `scoped_task_select` (`routes/tasks/listing.py:193-268`), window `window.start <= updated_at <= window.end` inclusive; never `sections._state_now_chart`. `board_link(state?, project?, persona?, window)` → `/tasks?state=&project=&persona=&after=<iso>&before=<iso>`. Write a JSON fixture of `board_link` samples (shared-fixture pattern, like `supportLinks.fixture.json`) with a Python test; the page child adds the TS round-trip test over it.
- Raw-SQL reads in reused builders get an explicit `org_id = seam.bound_org()` clause. Exec builders PICK metric keys by an allow-list per endpoint — never forward a whole operator envelope (no fleet quota/node/worktree charts).
- Missing data carries a `NULL_STATUSES` status with a reason, never 0/$0.00; unpriced tokens follow `sections._cost_metric`.
- Project-health knobs in `operator_settings/catalog_ops.py`, new `_Section("Dashboard", "Project health")`, `tier="operator"`, `feature="operator_dashboard"`: `dashboard_project_failed_amber`=1/`_red`=3, `dashboard_project_stuck_hours`=24, `dashboard_project_stuck_amber`=1/`_red`=5, `dashboard_project_merge_fail_amber`=1/`_red`=3, `dashboard_project_idle_days`=7. All-null factors → health `null`.
- `exec_dashboard.WIDGET_KEYS` tuple = `('overview','projects','personas','progress','risks','spend','spend_by_project','spend_by_persona','spend_by_model','deployments','productivity')` mirrored in a shared JSON fixture with a Python test (TS side added by the page child).
- Edition: create-or-append `[feature.exec_dashboard]` (cloud-only) in `packages/editions/features.toml` with `apps/api/app/exec_dashboard/**` and route prefix `/api/exec/dashboard` (the forge-CI child creates the row if it merges first); regenerate both `edition_features.py`.
- Docs: router row "Command center" in `CLAUDE.md` pointing to the `exec_dashboard/__init__.py` docstring as single home.
- Tests: `tests/exec_dashboard_contract.py` org-scoped twin of `operator_dashboard_contract` for every endpoint; cross-org isolation (pattern `test_cross_org_isolation.py`) with two orgs and overlapping windows; Member 403; operator routes unchanged; each empty state.
Requirements this child owns (verbatim from the PRD):
- **AC1.3 States.** (a) An org with zero projects shows an empty state with one action toward creating or onboarding a project. It never shows a grid of zeros or a blank panel. (b) A metric with no data renders the shared "missing" mark (`MissingValue`) with a hover reason, never `0` or `$0.00`. Verify both on dev with a fresh org and with an org that has projects but no runs. — API half.
- **AC2.2** The API computes metrics through the operator dashboard's existing window, metric and pricing code (`operator_dashboard/frame.py`, `facts.py`, `cost.py`, `derived.py`, `anomaly.py`) parameterised by org, not through a second implementation. Verify: code review of the PR. The operator-dashboard contract helper (`apps/api/tests/operator_dashboard_contract.py`) or its org-scoped twin passes for every new endpoint.
- **AC3.1** It is ON by default on dev for every cloud tenant on every plan (trial included), with no flag, plan or setting to turn on. Verify: on dev, a trial org's Owner opens `/` and sees it. — API: no plan or flag gate.
- **AC3.2** A Member seat opening `/` lands on `/tasks` as today. Calling the command center API directly as a Member returns 403. Verify: as a Member on dev, open `/`, then call the endpoint from devtools and observe 403. — API half.
- **AC3.3** Org isolation: every number and row belongs to the signed-in org only. Verify: on dev, with two orgs A and B, A's Owner sees none of B's project names, personas' counts or spend. An API call with another org's id in any parameter returns 403/404, never data. Also verify with a cross-org isolation API test (`apps/api/tests/test_cross_org_isolation.py` pattern).
- **AC3.4** The community edition has neither the page nor the API route. Verify: the community-edition build and check (`tools/community_edition/README.md`) pass with the feature listed as cloud-only in `packages/editions/features.toml`.
- **AC3.5** The operator plane is unaffected (A-7). See AC2.3.
- **AC4.1** It lists every project of the org: active ones first (A-1), inactive below and marked. Each row shows name, health RAG (R7), open tasks, tasks done in window, spend in window, and last merge time. Clicking a row opens that project's console page. Verify: on dev, compare the list against the org's Projects page. The counts match and every project appears exactly once.
- **AC4.2** States: a project with no repo or no tasks shows "—" with a reason, never an error. Verify on dev.
- **AC5.1** One row per persona that has at least one task in the org in the window, plus every persona with an in-flight task. Labels come from the persona registry's display labels (e.g. "Analyze", "Coder"), never raw slugs such as `business_analysis`. Columns: in flight now, done in window, success rate, spend in window. Verify: on dev, for one persona, count that persona's tasks on the Tasks board filtered to the same window. The numbers match.
- **AC5.2** A persona with zero activity in the window is not listed, and an empty list shows an empty state. Verify on an org with one persona used.
- **AC6.1** It shows tasks by state now, across the seven lifecycle states with their console labels, plus tasks created vs done per bucket in the window, and open epics with their pipeline stage (Analyze → Design → Plan → Coder → Merged). Verify: the state counts equal the Tasks board's counts for the org (`/api/tasks/counts`).
- **AC7.1** Each project carries green, amber or red, equal to its worst factor (A-3). Hovering or tapping shows each factor's value and colour in words ("2 failed tasks — red"). Verify: on dev, make a project with a `system_failed` task above the red threshold and observe red, with that factor named. A project with no factor over threshold shows green. — non-CI factors.
- **AC7.2** A project whose factors are all missing (no tasks, no repo) shows "no data", not green. Verify on dev.
- **AC7.3** The thresholds are operator knobs with defaults, editable in operator Settings. Verify: change one on dev and observe the RAG change after refresh.
- **AC8.1** It lists the org's failed and stuck work: tasks in `system_failed`, tasks waiting on a human (`awaiting_response`) or `paused` beyond a threshold, merge-lane failures, and broken sessions. Each row shows project, task title (untruncated to 24+ characters), reason and age, and links to the task. Verify: on dev, every `system_failed` task of the org in the window appears, and a `done` task does not.
- **AC8.2** It shows org-scoped anomaly flags (cost spike, success-rate drop against the trailing baseline), from the operator dashboard's detector applied to the org's own series. Each flag names the metric, the observed value and the baseline. Verify: the anomaly unit tests on fixtures pass for org-scoped input, and on dev the section renders either the flags or a "no anomalies" state.
- **AC8.3** No forge or Jira issues appear (OD-12). Verify: code review.
- **AC9.1** It shows total AI spend in dollars for the window, a per-bucket trend, and a breakdown by project, persona and model. Verify: on dev, the total equals the sum of the org's per-task run-metric dollars for tasks in the window (`/api/tasks/{id}/run-metrics` on a sample), within rounding of $0.01.
- **AC9.2** Unpriced usage (a model with no `model_prices` row) is shown as "unpriced" with the token count, never counted as $0. Verify with a fixture test.
- **AC9.3** No subscription, invoice or node cost is shown (OD-4). Verify: code review.
- **AC11.1** KPI tiles for the window: tasks done, success rate, zero-touch rate, median cycle time, cost per merged task, and AI quality review score (missing mark when the org has none). Each has a trend against the previous window. Verify: on dev, compare tasks done and success rate with the Tasks board for the same window.
- **AC14.1** `./dc check full` is green on the merge lane. New API endpoints have tests for org scoping, role refusal (Member 403, operator unchanged) and each empty state. The web side has unit tests for each section's states and one e2e for the Owner flow. Verify: the merge lane's gate output. — API half.
Credentials & reach:
- Every dev.jaah.ai browser oracle (AC1.1–13.4 "Verify on dev") — dev.jaah.ai from h5-3-gmind: DNS resolves 10.60.x, HTTPS and browser time out — **deferred**: operator answer AD-5. Local `./dc` e2e + API tests are the oracles. The dev re-check is done by a node with dev reach in the Finish stage.
- Owner / Member / org-B seats for dev oracles — `org/console/dev-login`, `org/console/dev-tpl-member-login`, `org/console/dev-tpl-viewer-login`, `org/console/dev-orgb-login`, `me/jaah/debug/main/operator-login` — **verified** (credential_get OK). Their use on dev is **deferred** with the reach (AD-5, AD-6).
- Local gates (`./dc check quick/full`, pytest, vitest, Playwright local e2e) — worktree only — **verified**.
Out of scope: Do NOT build `/deployments` or the CI health factor (child "Deployments endpoint and CI health"), any web UI, or Jarvis tools. MUST NOT change the Operator dashboard's behaviour, tabs, routes or data for the operator (`apps/web/src/pages/dashboard/OperatorDashboard.tsx`, `/api/operator/dashboard/*`). Moving shared code is allowed, but behaviour must stay identical. Do NOT rename `operator_dashboard`. MUST NOT expose the command center or its API to tenant Members, or to the community edition. MUST NOT show cross-org data anywhere. MUST NOT ingest forge issues or Jira bugs (OD-12). MUST NOT add billing/subscription, cloud/node/AWS cost or budget-vs-actual to expenses (OD-4). MUST NOT add an "AI employee" entity or table (OD-2). MUST NOT add a plan gate or an enablement flag (OD-10).
Done means (dev browser oracles deferred — AD-5; the local API test named is the oracle; a poor-but-literal result FAILS: a 0/$0.00 where data is missing, a raw slug label, or a fleet chart in a tenant payload fails):
- AC1.3 (API) — test: zero-project org returns an explicit empty state; projects-without-runs metrics carry a `NULL_STATUSES` status with a reason, never 0.
- AC2.2 — `tests/exec_dashboard_contract.py` passes for every endpoint; code review shows only builder composition, no second metric/cost implementation.
- AC3.1 (API) — no plan/flag gate on the routes (test as a trial-plan Owner).
- AC3.2 (API) — Member gets 403 on every endpoint (test).
- AC3.3 — two-org cross-org test: every count/row/spend equals org A's own; `org` param → 403; foreign `project` id → 404; two-org back-to-back cache test shows no leak.
- AC3.4 — community-edition tree build/check passes with `exec_dashboard` cloud-only.
- AC3.5 — operator dashboard tests and contract unchanged and green; operator payloads byte-identical (no `previous`).
- AC4.1/4.2 — projects test: every project exactly once, active first then severity then name, counts equal board predicate, no-repo/no-task → "—" with reason.
- AC5.1/5.2 — personas test: counts equal `/api/tasks/counts` with persona + window; labels from `PERSONA_LABELS`; idle persona absent; empty list explicit.
- AC6.1 — progress state counts equal `GET /api/tasks/counts` with the same params, seeded with hidden tasks and tasks without runs, incl. a task updated exactly at `window.end`.
- AC7.1/7.2/7.3 — health test per factor and threshold; all-null → `null`; changing a knob changes the colour (cache key includes knobs).
- AC8.1/8.2/8.3 — risks test: every `system_failed` in window present, `done` absent, stuck beyond `dashboard_project_stuck_hours`, merge failures, broken session resolved via `broken_task_id` (unit test incl. missing marker fallback), org B's incident absent; anomaly fixtures for org-scoped input; no forge/Jira source.
- AC9.1/9.2/9.3 — expenses total equals the sum of per-task run-metric dollars within $0.01 (fixture); unpriced shown with token count; no billing/node cost.
- AC11.1 — productivity KPIs each carry `previous`; tasks done and success rate equal the board for the same window.
- AC14.1 (API) — `./dc check quick` green locally; merge lane `./dc check full` green.
Outcome
Command center API (/api/exec/dashboard: overview, projects+health, personas, progress, risks, expenses, productivity) on the operator engine; scope- and viewer-keyed cache. Quick gate green, 40 tests pass; PR #7472 queued. Draft #11774 filed (develop CE check). Memory: none applied.
Artifacts
Activity
- Draft
- Ready
- Runner started
- Runner ended (done)