From a7158563aadb1d5c464e105e94706c99a3a02c35 Mon Sep 17 00:00:00 2001 From: autocommit Date: Thu, 21 May 2026 14:39:22 -0700 Subject: [PATCH] =?UTF-8?q?feat(web):=20=E2=9C=A8=20Implement=20API=20endp?= =?UTF-8?q?oints=20and=20service=20logic=20for=20fetching=20"Considered=20?= =?UTF-8?q?Work"=20data?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- src/claire/web/api.py | 8 ++++++++ src/claire/web/service.py | 15 +++++++++++++++ tests/test_api.py | 21 +++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/src/claire/web/api.py b/src/claire/web/api.py index 3b32e55..9e68260 100644 --- a/src/claire/web/api.py +++ b/src/claire/web/api.py @@ -380,6 +380,14 @@ def fleet_load_get(cg: Dep) -> dict[str, Any]: return service.fleet_load(conn) +@router.get("/fleet/considered") +def fleet_considered_get(cg: Dep) -> dict[str, Any]: + """Top ranked task↔session pairings the dispatch engine would consider, + plus the unpaired remainder — the "considered work" panel of the HUD.""" + conn, _ = cg + return service.suggest_assignments(conn) + + @router.post("/pull") def pull_now(cg: Dep) -> dict[str, Any]: conn, gen = cg diff --git a/src/claire/web/service.py b/src/claire/web/service.py index 5573a42..c356f17 100644 --- a/src/claire/web/service.py +++ b/src/claire/web/service.py @@ -645,6 +645,21 @@ def fleet_load(conn: sqlite3.Connection) -> dict: } +def suggest_assignments(conn: sqlite3.Connection) -> dict: + """Ranked task↔session pairings the dispatch engine would consider — + the "considered work" panel of the fleet HUD. Pairings respect the + per-host parallelism cap so the UI only surfaces work that could + actually be bound right now. + """ + from .. import scheduler + from ..config import load_or_init + + cfg = load_or_init() + return scheduler.suggest_assignments( + conn, per_host_max=cfg.limits.per_host_max + ) + + def create_person( conn: sqlite3.Connection, gen: HLCGenerator, diff --git a/tests/test_api.py b/tests/test_api.py index 9434c11..5211c6e 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -112,6 +112,27 @@ def test_status_rollup(client: TestClient) -> None: assert proj["counts"]["done"] == 0 +def test_fleet_considered_shape(client: TestClient) -> None: + """GET /fleet/considered returns the considered-work shape; an open + task with no free session lands in `remaining_tasks`, not `pairings`.""" + client.post("/api/v1/projects", json={"name": "alpha"}) + client.post( + "/api/v1/tasks", json={"project": "alpha", "title": "ship hud", "priority": 0} + ) + r = client.get("/api/v1/fleet/considered") + assert r.status_code == 200 + body = r.json() + assert set(body) == { + "pairings", + "remaining_tasks", + "remaining_sessions", + "capped_out", + } + assert body["pairings"] == [] # no sessions → nothing pairs + titles = [t["title"] for t in body["remaining_tasks"]] + assert "ship hud" in titles + + def test_broadcast_dry_run_warns_when_no_assignments(client: TestClient) -> None: client.post("/api/v1/projects", json={"name": "alpha"}) r = client.post(