feat: show run counts in wf status
This commit is contained in:
@@ -27,7 +27,8 @@ MCP entrypoint and compatibility surface.
|
|||||||
The platform is usable enough to test as a product. Next work should focus on
|
The platform is usable enough to test as a product. Next work should focus on
|
||||||
clear operator feedback before adding more architecture.
|
clear operator feedback before adding more architecture.
|
||||||
|
|
||||||
- Completed: `wf status` is a compact read-only target/server status command.
|
- Completed: `wf status` is a compact read-only target/server status command,
|
||||||
|
including durable run counts and the latest run summary when available.
|
||||||
- Completed: a real CLI smoke pass against `wf-rpc-server --config wf.config.json`
|
- Completed: a real CLI smoke pass against `wf-rpc-server --config wf.config.json`
|
||||||
is captured in
|
is captured in
|
||||||
[`2026-06-09 product smoke RPC CLI`](superpowers/research/2026-06-09-product-smoke-rpc-cli.md).
|
[`2026-06-09 product smoke RPC CLI`](superpowers/research/2026-06-09-product-smoke-rpc-cli.md).
|
||||||
|
|||||||
+3
-2
@@ -104,8 +104,9 @@ wf --url http://127.0.0.1:8765/rpc status
|
|||||||
```
|
```
|
||||||
|
|
||||||
`status` is read-only. It reports the selected target, capability/source
|
`status` is read-only. It reports the selected target, capability/source
|
||||||
availability, admin counts, auth record count, and desired registry count when
|
availability, durable run counts/latest run, admin counts, auth record count,
|
||||||
the target exposes those admin surfaces. It does not return auth payload values.
|
and desired registry count when the target exposes those surfaces. It does not
|
||||||
|
return auth payload values, trace entries, or checkpoint state.
|
||||||
|
|
||||||
## Output Policy
|
## Output Policy
|
||||||
|
|
||||||
|
|||||||
@@ -47,11 +47,13 @@ async def _fetch_status_data(context: CliContext) -> dict[str, Any]:
|
|||||||
}
|
}
|
||||||
|
|
||||||
sources = await _fetch_sources(context)
|
sources = await _fetch_sources(context)
|
||||||
|
runs = await _fetch_runs(context)
|
||||||
admin = await _fetch_admin(context)
|
admin = await _fetch_admin(context)
|
||||||
registry = await _fetch_registry(context)
|
registry = await _fetch_registry(context)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"workflow": workflow,
|
"workflow": workflow,
|
||||||
|
"runs": runs,
|
||||||
"sources": sources,
|
"sources": sources,
|
||||||
"admin": admin,
|
"admin": admin,
|
||||||
"registry": registry,
|
"registry": registry,
|
||||||
@@ -77,6 +79,41 @@ async def _fetch_sources(context: CliContext) -> dict[str, Any]:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def _fetch_runs(context: CliContext) -> dict[str, Any]:
|
||||||
|
# Intentionally broad: older/partial targets may not expose run listing yet.
|
||||||
|
try:
|
||||||
|
all_runs = await context.handlers.list_runs(limit=1)
|
||||||
|
except Exception as exc:
|
||||||
|
return _unavailable(exc)
|
||||||
|
|
||||||
|
latest = None
|
||||||
|
runs = all_runs.get("runs", [])
|
||||||
|
if runs and isinstance(runs[0], dict):
|
||||||
|
latest = {
|
||||||
|
"run_id": runs[0].get("run_id"),
|
||||||
|
"status": runs[0].get("status"),
|
||||||
|
"updated_at": runs[0].get("updated_at"),
|
||||||
|
}
|
||||||
|
|
||||||
|
counts: dict[str, int] = {}
|
||||||
|
for status in ("completed", "failed", "interrupted"):
|
||||||
|
try:
|
||||||
|
payload = await context.handlers.list_runs(status=status, limit=1)
|
||||||
|
except Exception:
|
||||||
|
counts[status] = 0
|
||||||
|
continue
|
||||||
|
counts[status] = _payload_count(payload, "runs")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"available": True,
|
||||||
|
"total": _payload_count(all_runs, "runs"),
|
||||||
|
"completed": counts["completed"],
|
||||||
|
"failed": counts["failed"],
|
||||||
|
"interrupted": counts["interrupted"],
|
||||||
|
"latest": latest,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def _fetch_admin(context: CliContext) -> dict[str, Any]:
|
async def _fetch_admin(context: CliContext) -> dict[str, Any]:
|
||||||
# Intentionally broad: graceful degradation when admin surfaces are unavailable
|
# Intentionally broad: graceful degradation when admin surfaces are unavailable
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -678,6 +678,32 @@ def test_wf_remote_run_resume_interrupted_deployment(monkeypatch, tmp_path) -> N
|
|||||||
|
|
||||||
def test_wf_status_uses_rpc_url_override(monkeypatch, tmp_path) -> None:
|
def test_wf_status_uses_rpc_url_override(monkeypatch, tmp_path) -> None:
|
||||||
server = build_local_static_workflow_server(tmp_path / "store")
|
server = build_local_static_workflow_server(tmp_path / "store")
|
||||||
|
asyncio.run(
|
||||||
|
server.api.create_artifact_from_plan(
|
||||||
|
artifact_id="status_constant",
|
||||||
|
version=1,
|
||||||
|
title="Status Constant",
|
||||||
|
plan=_constant_plan(),
|
||||||
|
outcomes=("ok",),
|
||||||
|
source_bindings={"wf.std": "wf.std"},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
asyncio.run(
|
||||||
|
server.api.save_deployment(
|
||||||
|
{
|
||||||
|
"id": "status_constant.default",
|
||||||
|
"artifact_id": "status_constant",
|
||||||
|
"artifact_version": 1,
|
||||||
|
"bindings": [{"logical_source": "wf.std", "concrete_source": "wf.std"}],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
started = asyncio.run(
|
||||||
|
server.api.run_deployment(
|
||||||
|
deployment_id="status_constant.default",
|
||||||
|
workflow_input={},
|
||||||
|
)
|
||||||
|
)
|
||||||
_patch_rpc_client_to_server(monkeypatch, server)
|
_patch_rpc_client_to_server(monkeypatch, server)
|
||||||
config_path = tmp_path / "wf.json"
|
config_path = tmp_path / "wf.json"
|
||||||
config_path.write_text('{"version": 1}', encoding="utf-8")
|
config_path.write_text('{"version": 1}', encoding="utf-8")
|
||||||
@@ -698,6 +724,13 @@ def test_wf_status_uses_rpc_url_override(monkeypatch, tmp_path) -> None:
|
|||||||
assert payload["target"]["mode"] == "remote"
|
assert payload["target"]["mode"] == "remote"
|
||||||
assert payload["target"]["url"] == "http://test/rpc"
|
assert payload["target"]["url"] == "http://test/rpc"
|
||||||
assert payload["workflow"]["capability_count"] >= 1
|
assert payload["workflow"]["capability_count"] >= 1
|
||||||
|
assert payload["runs"]["available"] is True
|
||||||
|
assert payload["runs"]["total"] == 1
|
||||||
|
assert payload["runs"]["completed"] == 1
|
||||||
|
assert payload["runs"]["failed"] == 0
|
||||||
|
assert payload["runs"]["interrupted"] == 0
|
||||||
|
assert payload["runs"]["latest"]["run_id"] == started["run_id"]
|
||||||
|
assert payload["runs"]["latest"]["status"] == "completed"
|
||||||
assert payload["sources"]["available"] is True
|
assert payload["sources"]["available"] is True
|
||||||
assert payload["admin"]["available"] is True
|
assert payload["admin"]["available"] is True
|
||||||
assert payload["registry"]["available"] is False
|
assert payload["registry"]["available"] is False
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ def test_wf_status_local_static_target(tmp_path) -> None:
|
|||||||
assert payload["target"]["url"] is None
|
assert payload["target"]["url"] is None
|
||||||
assert payload["workflow"]["capability_count"] >= 1
|
assert payload["workflow"]["capability_count"] >= 1
|
||||||
assert "wf.std.constant" in payload["workflow"]["sample_capabilities"]
|
assert "wf.std.constant" in payload["workflow"]["sample_capabilities"]
|
||||||
|
assert payload["runs"]["available"] is True
|
||||||
|
assert payload["runs"]["total"] == 0
|
||||||
|
assert payload["runs"]["latest"] is None
|
||||||
assert payload["sources"]["available"] is True
|
assert payload["sources"]["available"] is True
|
||||||
assert payload["sources"]["source_count"] >= 1
|
assert payload["sources"]["source_count"] >= 1
|
||||||
assert payload["admin"]["available"] is True
|
assert payload["admin"]["available"] is True
|
||||||
|
|||||||
Reference in New Issue
Block a user