From da75ad88e0bba892f8b495ca38ad7edf872fbd27 Mon Sep 17 00:00:00 2001 From: huangruiteng <14976749+huangruiteng@users.noreply.github.com> Date: Thu, 17 Sep 2026 17:06:43 +0800 Subject: [PATCH] fix(diagnostics): expose route health scope across status and doctor Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> --- .../hot-path-interface-budget-smoke.py | 4 ++- ...h-state-shared-runtime-projection-smoke.py | 28 +++++++++++++++++-- ...hared-runtime-material-projection-smoke.py | 4 ++- .../runtime/runtime_projection_route.py | 7 +++++ loopx/control_plane/status/collection.py | 4 ++- loopx/doctor.py | 9 +++++- .../presentation/renderers/status_markdown.py | 10 +++++-- 7 files changed, 58 insertions(+), 8 deletions(-) diff --git a/examples/control_plane/hot-path-interface-budget-smoke.py b/examples/control_plane/hot-path-interface-budget-smoke.py index b06c1e22a3..1ee80ecfeb 100644 --- a/examples/control_plane/hot-path-interface-budget-smoke.py +++ b/examples/control_plane/hot-path-interface-budget-smoke.py @@ -387,7 +387,9 @@ def main() -> int: status_items = status_payload["attention_queue"]["items"] assert status_items, status_payload assert "task_graph_projection" not in status_items[0], status_items[0] - assert status_payload["runtime_projection_routes"] == {"healthy": True} + route_health = status_payload["runtime_projection_routes"] + assert route_health["healthy"] is True, route_health + assert route_health["goal_count"] >= 1, route_health quota_payload = build_quota_should_run( status_payload, goal_id=GOAL_ID, diff --git a/examples/control_plane/refresh-state-shared-runtime-projection-smoke.py b/examples/control_plane/refresh-state-shared-runtime-projection-smoke.py index 38a3f73313..ebf25cf3ca 100644 --- a/examples/control_plane/refresh-state-shared-runtime-projection-smoke.py +++ b/examples/control_plane/refresh-state-shared-runtime-projection-smoke.py @@ -25,6 +25,7 @@ resolve_runtime_projection_route, ) from loopx import doctor as doctor_module # noqa: E402 +from loopx.paths import global_registry_path # noqa: E402 from loopx.presentation.renderers.status_markdown import ( # noqa: E402 render_status_markdown, ) @@ -387,8 +388,10 @@ def main() -> None: shared_runtime=shared_runtime, ) route_diagnostics = status["runtime_projection_routes"] - assert route_diagnostics == {"healthy": True}, route_diagnostics + assert route_diagnostics["healthy"] is True, route_diagnostics + assert route_diagnostics["goal_count"] == 1, route_diagnostics assert "runtime_projection_routes: healthy=True" in render_status_markdown(status) + assert "goals=1" in render_status_markdown(status), render_status_markdown(status) source_index = project_runtime / "goals" / GOAL_ID / "runs" / "index.jsonl" source_rows = [ @@ -420,7 +423,8 @@ def main() -> None: shared_runtime=shared_runtime, ) lagging_routes = lagging_status["runtime_projection_routes"] - assert lagging_routes == {"healthy": False}, lagging_routes + assert lagging_routes["healthy"] is False, lagging_routes + assert lagging_routes["goal_count"] == 1, lagging_routes lagging_markdown = render_status_markdown(lagging_status) assert "runtime_projection_routes: healthy=False" in lagging_markdown assert "details=loopx doctor" in lagging_markdown @@ -437,6 +441,26 @@ def main() -> None: item.get("goal_id") == GOAL_ID and item.get("status") == "lagging" for item in doctor_routes["items"] ), doctor_routes + # Same selected routes yield the same health even through different registries. + assert doctor_routes["healthy"] is lagging_routes["healthy"] + assert doctor_routes["goal_count"] == lagging_routes["goal_count"] == 1 + assert doctor_routes["registry"] == str(global_registry_path(shared_runtime).resolve()) + assert lagging_status["registry"] == str(source_registry) + assert doctor_routes["registry"] != lagging_status["registry"] + doctor_markdown = doctor_module.render_doctor_markdown(doctor) + assert f"registry=`{doctor_routes['registry']}`" in doctor_markdown + assert f"registry: `{source_registry}`" in lagging_markdown + assert f"goal_filter: `{GOAL_ID}`" in lagging_markdown + assert "global details=loopx doctor" in lagging_markdown + + # A healthy unrelated registry can have the same count as the lagging one. + other_project, other_runtime, other_registry, other_global = write_fixture(Path(tmp) / "other") + other_status = run_cli("--registry", str(other_registry), "status", "--goal-id", GOAL_ID, + cwd=other_project, shared_runtime=other_global.parent) + assert other_status["runtime_projection_routes"]["goal_count"] == doctor_routes["goal_count"] + assert other_status["runtime_projection_routes"]["healthy"] is True + assert other_status["registry"] != doctor_routes["registry"] + assert f"registry: `{other_registry}`" in render_status_markdown(other_status) single_runtime = Path(tmp) / "single-runtime" single_registry, single_goal = write_route_source( diff --git a/examples/control_plane/shared-runtime-material-projection-smoke.py b/examples/control_plane/shared-runtime-material-projection-smoke.py index f214e9f348..c68313a060 100644 --- a/examples/control_plane/shared-runtime-material-projection-smoke.py +++ b/examples/control_plane/shared-runtime-material-projection-smoke.py @@ -264,7 +264,9 @@ def exercise_split_runtime(root: Path) -> None: assert dream_status["run_history"]["goals"][0]["latest_status_run"][ "classification" ] == "dreaming_proposal_deferred" - assert dream_status["runtime_projection_routes"] == {"healthy": True} + route_health = dream_status["runtime_projection_routes"] + assert route_health["healthy"] is True, route_health + assert route_health["goal_count"] >= 1, route_health source_row = read_rows(source_runtime)[-1] replay_record, replay_index = build_shared_runtime_material_projection( diff --git a/loopx/control_plane/runtime/runtime_projection_route.py b/loopx/control_plane/runtime/runtime_projection_route.py index bfbd73362f..54fab5dbcc 100644 --- a/loopx/control_plane/runtime/runtime_projection_route.py +++ b/loopx/control_plane/runtime/runtime_projection_route.py @@ -694,6 +694,13 @@ def collect_runtime_projection_route_diagnostics( } return { "schema_version": RUNTIME_PROJECTION_ROUTE_DIAGNOSTICS_SCHEMA_VERSION, + "registry": str(registry_path.resolve()), + "runtime_root": str(runtime_root.resolve()), + "goal_filter": goal_id, + "activation_state_filter": ( + normalize_goal_activation_state(activation_state_filter).value + if activation_state_filter is not None else None + ), "available": bool(items), "goal_count": len(items), "healthy": not any( diff --git a/loopx/control_plane/status/collection.py b/loopx/control_plane/status/collection.py index 9be3e93fba..5900e1cb58 100644 --- a/loopx/control_plane/status/collection.py +++ b/loopx/control_plane/status/collection.py @@ -159,7 +159,9 @@ def collect_status( bool(runtime_projection_routes.get("healthy")) if runtime_projection_routes.get("available") else None - ) + ), + # Registry, Goal and activation scope already live in the status envelope. + "goal_count": int(runtime_projection_routes.get("goal_count") or 0), } contract_projection = { "ok": contract.get("ok"), diff --git a/loopx/doctor.py b/loopx/doctor.py index 8727fde8f5..ee888da392 100644 --- a/loopx/doctor.py +++ b/loopx/doctor.py @@ -891,6 +891,10 @@ def collect_doctor( if default_global_registry.exists() else { "schema_version": "runtime_projection_route_diagnostics_v0", + "registry": str(default_global_registry.resolve()), + "runtime_root": str(DEFAULT_RUNTIME_ROOT.resolve()), + "goal_filter": None, + "activation_state_filter": None, "available": False, "goal_count": 0, "healthy": True, @@ -1186,7 +1190,10 @@ def render_doctor_markdown(payload: dict[str, Any]) -> str: f"- skill_delivery_mode: `{(payload.get('skill_delivery') or {}).get('mode')}`", f"- skill_delivery_status: `{(payload.get('skill_delivery') or {}).get('status')}`", f"- global_registry_writable: `{(payload.get('global_registry_writability') or {}).get('ok')}`", - f"- runtime_projection_routes_healthy: `{(payload.get('runtime_projection_routes') or {}).get('healthy')}`", + f"- runtime_projection_routes_healthy: `{(payload.get('runtime_projection_routes') or {}).get('healthy')}`" + f" (registry=`{(payload.get('runtime_projection_routes') or {}).get('registry')}`," + f" goals=`{(payload.get('runtime_projection_routes') or {}).get('goal_count')}`," + f" counts=`{json.dumps((payload.get('runtime_projection_routes') or {}).get('counts') or {}, sort_keys=True)}`)", f"- user_local_bin_on_path: `{(payload.get('path') or {}).get('user_local_bin_on_path')}`", f"- python: `{(payload.get('python') or {}).get('executable')}`", f"- typescript_control_plane: `{typescript_control_plane.get('status')}`", diff --git a/loopx/presentation/renderers/status_markdown.py b/loopx/presentation/renderers/status_markdown.py index e21d22af90..46ace4b4aa 100644 --- a/loopx/presentation/renderers/status_markdown.py +++ b/loopx/presentation/renderers/status_markdown.py @@ -75,6 +75,10 @@ def append_status_overview_markdown( if payload.get("goal_filter"): lines.append(f"- goal_filter: `{payload.get('goal_filter')}`") + projection_scope = as_dict(payload.get("goal_projection")).get("scope") + if projection_scope: + lines.append(f"- activation_filter: `{projection_scope}`") + contract = as_dict(payload.get("contract")) summary = as_dict(contract.get("summary")) lines.append( @@ -138,8 +142,10 @@ def append_runtime_projection_routes_markdown( healthy = diagnostics.get("healthy") if healthy is None: return - suffix = "" if healthy else ", details=loopx doctor" - lines.append(f"- runtime_projection_routes: healthy={healthy}{suffix}") + count = diagnostics.get("goal_count") + scope = f" (goals={count})" if isinstance(count, int) else "" + suffix = "" if healthy else ", global details=loopx doctor" + lines.append(f"- runtime_projection_routes: healthy={healthy}{scope}{suffix}") def append_global_registry_findings_markdown(