Deployments endpoint and CI health
## 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: PRD (task 11718, R7, R10) and Architecture (task 11719, §2.1 `/deployments`, `DeployRow`, `CiRun`, health table CI row; §2.2; §4 risk 4). Builds on the merged "Forge CI reader for four forges" (`forge_ci.latest_run`) and "Command center API core endpoints" (`exec_dashboard/`).
## This child (Architecture C2 remainder)
- `GET /api/exec/dashboard/deployments` → `{rows:[DeployRow]}`, `DeployRow = {project_id, project_name, merges: [{state: "merged"|"failed"|"queued"|"testing", pr_number, pr_url, at}] (last 5), ci: CiRun}`; `CiRun = {status, workflow, branch, at, url, reason}` with `reason` always set when `unknown`. Merge rows from `MergeLaneRow` (org-scoped by the seam). Same `@org_admin(Tenancy.CALLER_PLANE)` guard and contract tests as the core endpoints.
- Add the CI factor to project health: latest run on the integration branch — failure → red, success → green, unknown → null (ignored). Pass the viewer into the `projects` builder; `/projects` and `/deployments` call `forge_ci` through its bounded batch (pool 8, 8s total cap) and never wait beyond the cap. `worst_health` on `/overview` reflects it.
- Forge results are NOT put into the shared `frame.cached` entry keyed only by scope — the CI read is per viewer credential (forge_ci's own TTL cache governs it).
- Update the core child's health and `worst_health` tests for the CI factor; add `/deployments` to the org-scoped contract and cross-org tests.
Requirements this child owns (verbatim):
- **AC10.1** For each project it shows the last merges to the integration branch (merged / failed / queued, with time) from the merge lane, and the forge's latest CI/deploy workflow run on the integration branch (status, workflow name, time, link). Verify: on dev, for one project, compare with the forge's Actions page for that branch. The status and time match. — merge half + API composition.
- **AC10.2** States: a project with no repo, no forge credential, a forge error or rate limiting shows "unknown" with the reason in words. The page never errors or blanks. A project with no merge lane shows only CI. Verify on dev with a project that has no repo. — API half.
- **AC10.3** No deploy history is stored (OD-7). Verify: the PR adds no table or column for deploy runs.
- **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. — CI factor.
Credentials & reach:
- AC10.1 GitHub CI live — `me/GitHub (ruzhukov)` against api.github.com (reachable: app.jaah.ai and GitHub egress OK), repo `jaah-ai/jaah` branch `develop` — **verified**: credential_get OK. The coder compares `forge_ci.latest_run` with `GET /repos/jaah-ai/jaah/actions/runs?branch=develop&per_page=1`.
- AC10.1 GitLab / Bitbucket CI — `me/GitLab (rzhukov)`, `me/Bitbucket (Roman Zhukov)` — **deferred**: AD-7, fixtures are the oracle. Azure DevOps — none on the roster — **deferred**: AD-7, fixture only.
- Every dev.jaah.ai browser oracle — **deferred**: AD-5; local API tests are the oracle; Finish stage re-checks on dev.
- Local gates — worktree only — **verified**.
Out of scope: Do NOT add a deploy/CI history table or persist CI runs (OD-7). Do NOT change `forge_ci`'s pinned `CiRun`/`latest_run` shape. Do NOT build UI. MUST NOT change the Operator dashboard's behaviour, tabs, routes or data. MUST NOT show cross-org data. MUST NOT expose the API to Members or the community edition. Do NOT ingest forge issues or Jira bugs (OD-12).
Done means (dev oracles deferred — AD-5):
- AC10.1 — API test: `/deployments` returns each project's last 5 merge-lane rows with state/pr/time and the `CiRun` from `forge_ci` (fixture-backed); a live GitHub check of one project's `ci` against `GET /repos/jaah-ai/jaah/actions/runs?branch=develop&per_page=1` matches status and time (cite output).
- AC10.2 — tests: no repo, no credential, forge error, 429 and a slow forge each yield `unknown` with a reason a tenant Owner can act on; `/projects` and `/deployments` return within the 8s cap with a stubbed hanging forge; a project with no merge-lane rows returns `merges: []` and its CI.
- AC10.3 — no migration, table or column.
- AC7.1 (CI) — health test: failing CI → red with the factor named in words; success → contributes green; unknown → ignored (all-null still `null`); `worst_health` updated.
- Org isolation and Member 403 tests cover `/deployments`; operator dashboard tests unchanged.
- `./dc check quick` green; merge lane `./dc check full` green.
Outcome
Artifacts
Activity
- Draft
- Ready
- Runner started
- Runner ended (done)
- Run
- Runner started
- Runner ended (done)
- Run
- Runner started