Align Runtime Health with canonical envelope
This commit is contained in:
parent
3685710fe8
commit
114ffa4067
@ -45,8 +45,8 @@
|
||||
| `routes/cortex_os_extension.py:17` | `api.logger` | `log = api.logger("svrnty.routes.cortex_os_extension")` |
|
||||
| `routes/cortex_os_extension.py:21` | `api.inject_stylesheet` | `api.inject_stylesheet(stylesheet)` |
|
||||
| `routes/cortex_os_extension.py:22` | `api.inject_script` | `api.inject_script(script)` |
|
||||
| `routes/cortex_os_runtime_health.py:26` | `api.logger` | `log = api.logger("svrnty.routes.cortex_os_runtime_health")` |
|
||||
| `routes/cortex_os_runtime_health.py:27` | `api.register_route` | `api.register_route(ROUTE_PATH, ROUTE_METHOD, _handle_runtime_health)` |
|
||||
| `routes/cortex_os_runtime_health.py:30` | `api.logger` | `log = api.logger("svrnty.routes.cortex_os_runtime_health")` |
|
||||
| `routes/cortex_os_runtime_health.py:31` | `api.register_route` | `api.register_route(ROUTE_PATH, ROUTE_METHOD, _handle_runtime_health)` |
|
||||
| `routes/transcribe.py:37` | `api.logger` | `log = api.logger("svrnty.routes.transcribe")` |
|
||||
| `routes/transcribe.py:38` | `api.register_route` | `api.register_route("/api/transcribe", "POST", _handle_transcribe)` |
|
||||
| `routes/transcribe.py:39` | `api.register_audio_attachment_processor` | `api.register_audio_attachment_processor(_transcribe_audio_attachments)` |
|
||||
|
||||
@ -14,6 +14,10 @@ ROUTE_PATH = "/api/cortex-os/runtime-health"
|
||||
ROUTE_METHOD = "GET"
|
||||
CONTRACT_ID = "runtime-health/v0.1"
|
||||
CHECKED_AT = "2026-05-29T00:00:00Z"
|
||||
SCHEMA_VERSION = "0.1.0"
|
||||
HOST_RUNTIME_ID = "webui"
|
||||
HOST_ADAPTER_ID = "hermes"
|
||||
HOST_ADAPTER_KIND = "development_host"
|
||||
|
||||
_FORBIDDEN_TEXT = re.compile(
|
||||
r"(https?://|/home/|workspaces/|\b\d{2,5}\b|token|secret|cookie|traceback|exception|\.env)",
|
||||
@ -46,33 +50,77 @@ def runtime_health_payload(host_signals: dict[str, Any] | None = None) -> dict[s
|
||||
signals = _summarize_host_signals(host_signals or {})
|
||||
status = _derive_status(signals)
|
||||
return {
|
||||
"contract_id": CONTRACT_ID,
|
||||
"schema_version": SCHEMA_VERSION,
|
||||
"cortex_os_contract_id": CONTRACT_ID,
|
||||
"host_runtime_id": HOST_RUNTIME_ID,
|
||||
"host_adapter_id": HOST_ADAPTER_ID,
|
||||
"host_adapter_kind": HOST_ADAPTER_KIND,
|
||||
"checked_at": CHECKED_AT,
|
||||
"status": status,
|
||||
"readiness": "runtime_not_started",
|
||||
"summary": _summary_for(status),
|
||||
"readiness": "not_configured",
|
||||
"signals": signals,
|
||||
"display_summary": _display_summary_for(status),
|
||||
"redactions": [
|
||||
{"target_path": "signals", "reason_code": "no_raw_host_payload", "label": "raw host payloads omitted"},
|
||||
{"target_path": "signals.summary", "reason_code": "path_redacted", "label": "raw paths redacted"},
|
||||
{"target_path": "signals.summary", "reason_code": "secret_redacted", "label": "secrets redacted"},
|
||||
{
|
||||
"target_path": "source_trace",
|
||||
"reason_code": "request_response_redacted",
|
||||
"label": "request and response details omitted",
|
||||
},
|
||||
],
|
||||
"warnings": [
|
||||
{
|
||||
"code": "deterministic_host_surface_inputs_only",
|
||||
"message": "Runtime Health uses deterministic declared host-surface inputs only.",
|
||||
}
|
||||
],
|
||||
"errors": [],
|
||||
"source_trace": [
|
||||
{
|
||||
"source_id": "runtime-health-contract",
|
||||
"source_kind": "sot_document",
|
||||
"label": "Runtime Health Contract",
|
||||
},
|
||||
{
|
||||
"source_id": "hermes-host-adapter-contract",
|
||||
"source_kind": "host_adapter_contract",
|
||||
"label": "Hermes Host Adapter Contract",
|
||||
},
|
||||
{
|
||||
"source_id": "hermes-runtime-health-slice",
|
||||
"source_kind": "validator",
|
||||
"label": "Hermes Runtime Health Slice",
|
||||
},
|
||||
],
|
||||
"authority": {
|
||||
"read_only": True,
|
||||
"runtime_coding": False,
|
||||
"hermes_source_edits": False,
|
||||
"hermes_host_adapter_authority_map": False,
|
||||
"hermes_host_adapter_implementation": False,
|
||||
"webui_plugin_implementation": False,
|
||||
"local_json_api_route_files": False,
|
||||
"local_json_api_route_handlers": False,
|
||||
"browser_source": False,
|
||||
"host_runtime_start": False,
|
||||
"runtime_process_behavior": False,
|
||||
"runtime_state_mutation": False,
|
||||
"product_ui_implementation": False,
|
||||
"display_source": False,
|
||||
"tool_callable_authority": False,
|
||||
"mcp_exposure": False,
|
||||
"profile_exposure_change": False,
|
||||
"mcp_server_runtime_behavior": False,
|
||||
"mcp_tool_exposure": False,
|
||||
"profile_exposure_broadening": False,
|
||||
"memory_domain_access": False,
|
||||
"delegated_memory_grant": False,
|
||||
"delegated_memory_grants": False,
|
||||
"sharing": False,
|
||||
"installer_automation": False,
|
||||
"source_import": False,
|
||||
"forced_internal_upstream_dependency": False,
|
||||
"live_smoke_execution": False,
|
||||
"product_readiness_claim": False,
|
||||
},
|
||||
"signals": signals,
|
||||
"warnings": ["deterministic_host_surface_inputs_only"],
|
||||
"errors": [],
|
||||
"redactions": ["host_specific_values", "raw_paths", "raw_urls", "secrets", "raw_payloads"],
|
||||
"source_trace": {
|
||||
"host_adapter": "hermes",
|
||||
"host_surfaces": ["health", "agent_health", "dashboard_status"],
|
||||
"live_probe": False,
|
||||
"raw_payload_passthrough": False,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -80,21 +128,27 @@ def _summarize_host_signals(host_signals: dict[str, Any]) -> list[dict[str, str]
|
||||
names = ["health", "agent_health", "dashboard_status"]
|
||||
if not host_signals:
|
||||
return [
|
||||
{"name": name, "status": "unknown", "detail": "not_probed"}
|
||||
{"signal_id": name, "state": "unknown", "summary": "not configured", "redacted": False}
|
||||
for name in names
|
||||
]
|
||||
return [
|
||||
{
|
||||
"name": name,
|
||||
"status": _clean_status(host_signals.get(name, "unknown")),
|
||||
"detail": _bounded_text(host_signals.get(f"{name}_detail", "declared_surface")),
|
||||
}
|
||||
_summarize_signal(name, host_signals)
|
||||
for name in names
|
||||
]
|
||||
|
||||
|
||||
def _summarize_signal(name: str, host_signals: dict[str, Any]) -> dict[str, Any]:
|
||||
summary, redacted = _bounded_text(host_signals.get(f"{name}_detail", "declared surface"))
|
||||
return {
|
||||
"signal_id": name,
|
||||
"state": _clean_status(host_signals.get(name, "unknown")),
|
||||
"summary": summary,
|
||||
"redacted": redacted,
|
||||
}
|
||||
|
||||
|
||||
def _derive_status(signals: list[dict[str, str]]) -> str:
|
||||
statuses = {signal["status"] for signal in signals}
|
||||
statuses = {signal["state"] for signal in signals}
|
||||
if "unavailable" in statuses:
|
||||
return "unavailable"
|
||||
if "degraded" in statuses:
|
||||
@ -109,23 +163,39 @@ def _clean_status(value: Any) -> str:
|
||||
return text if text in {"healthy", "degraded", "unavailable", "unknown"} else "unknown"
|
||||
|
||||
|
||||
def _summary_for(status: str) -> str:
|
||||
def _display_summary_for(status: str) -> dict[str, str]:
|
||||
if status == "healthy":
|
||||
return "Runtime Health signals are healthy."
|
||||
return {
|
||||
"headline": "Runtime Health signals are healthy.",
|
||||
"detail": "Declared Runtime Health signals are healthy.",
|
||||
"severity": "ok",
|
||||
}
|
||||
if status == "degraded":
|
||||
return "Runtime Health signals are degraded."
|
||||
return {
|
||||
"headline": "Runtime Health signals are degraded.",
|
||||
"detail": "One or more declared Runtime Health signals are degraded.",
|
||||
"severity": "warning",
|
||||
}
|
||||
if status == "unavailable":
|
||||
return "Runtime Health signals are unavailable."
|
||||
return "Runtime Health has not been live-probed in this slice."
|
||||
return {
|
||||
"headline": "Runtime Health signals are unavailable.",
|
||||
"detail": "One or more declared Runtime Health signals are unavailable.",
|
||||
"severity": "error",
|
||||
}
|
||||
return {
|
||||
"headline": "Runtime Health is not configured.",
|
||||
"detail": "Runtime Health has not been live-probed in this slice.",
|
||||
"severity": "neutral",
|
||||
}
|
||||
|
||||
|
||||
def _bounded_text(value: Any) -> str:
|
||||
def _bounded_text(value: Any) -> tuple[str, bool]:
|
||||
text = str(value).strip().replace("\n", " ")
|
||||
if not text:
|
||||
return "redacted"
|
||||
return "redacted", True
|
||||
if _FORBIDDEN_TEXT.search(text):
|
||||
return "redacted"
|
||||
return text[:80]
|
||||
return "redacted", True
|
||||
return text[:160], False
|
||||
|
||||
|
||||
def _error_envelope(code: str, message: str) -> dict[str, Any]:
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
panel.setAttribute("data-state", "loading");
|
||||
|
||||
var title = document.createElement("h2");
|
||||
title.setAttribute("data-role", "headline");
|
||||
title.textContent = "Cortex OS Runtime Health";
|
||||
|
||||
var badge = document.createElement("span");
|
||||
@ -50,11 +51,12 @@
|
||||
return panel;
|
||||
}
|
||||
|
||||
function setState(panel, state, summary, signals) {
|
||||
function setState(panel, state, headline, detail, signals) {
|
||||
var nextState = states.indexOf(state) >= 0 ? state : "unknown";
|
||||
panel.setAttribute("data-state", nextState);
|
||||
panel.querySelector("[data-role='headline']").textContent = headline || "Runtime Health";
|
||||
panel.querySelector("[data-role='status']").textContent = nextState;
|
||||
panel.querySelector("[data-role='summary']").textContent = summary || "redacted";
|
||||
panel.querySelector("[data-role='summary']").textContent = detail || "redacted";
|
||||
renderSignals(panel.querySelector("[data-role='signals']"), signals || []);
|
||||
}
|
||||
|
||||
@ -63,8 +65,11 @@
|
||||
signals.slice(0, 3).forEach(function (signal) {
|
||||
var name = document.createElement("dt");
|
||||
var value = document.createElement("dd");
|
||||
name.textContent = signal.name || "redacted";
|
||||
value.textContent = signal.status || "unknown";
|
||||
name.textContent = signal.signal_id || "redacted";
|
||||
value.textContent = signal.state || "unknown";
|
||||
if (signal.summary) {
|
||||
value.setAttribute("title", signal.summary);
|
||||
}
|
||||
list.appendChild(name);
|
||||
list.appendChild(value);
|
||||
});
|
||||
@ -72,15 +77,22 @@
|
||||
|
||||
function renderPayload(panel, payload) {
|
||||
if (!payload || payload.ok !== true || !payload.result) {
|
||||
setState(panel, "error", "Runtime Health is unavailable.", []);
|
||||
setState(panel, "error", "Runtime Health is unavailable.", "Runtime Health is unavailable.", []);
|
||||
return;
|
||||
}
|
||||
setState(panel, payload.result.status, payload.result.summary, payload.result.signals);
|
||||
var displaySummary = payload.result.display_summary || {};
|
||||
setState(
|
||||
panel,
|
||||
payload.result.status,
|
||||
displaySummary.headline,
|
||||
displaySummary.detail,
|
||||
payload.result.signals,
|
||||
);
|
||||
}
|
||||
|
||||
function loadRuntimeHealth() {
|
||||
var panel = ensurePanel();
|
||||
setState(panel, "loading", "Checking Runtime Health.", []);
|
||||
setState(panel, "loading", "Cortex OS Runtime Health", "Checking Runtime Health.", []);
|
||||
|
||||
fetch(endpoint, {
|
||||
method: "GET",
|
||||
@ -98,7 +110,7 @@
|
||||
renderPayload(panel, payload);
|
||||
})
|
||||
.catch(function () {
|
||||
setState(panel, "error", "Runtime Health is unavailable.", []);
|
||||
setState(panel, "error", "Runtime Health is unavailable.", "Runtime Health is unavailable.", []);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -47,10 +47,42 @@ def test_get_returns_runtime_health_envelope():
|
||||
payload = handler.payload()
|
||||
assert handler.status_code == 200
|
||||
assert payload["ok"] is True
|
||||
assert payload["result"]["contract_id"] == "runtime-health/v0.1"
|
||||
assert payload["result"]["schema_version"] == "0.1.0"
|
||||
assert payload["result"]["cortex_os_contract_id"] == "runtime-health/v0.1"
|
||||
assert payload["result"]["host_runtime_id"] == "webui"
|
||||
assert payload["result"]["host_adapter_id"] == "hermes"
|
||||
assert payload["result"]["host_adapter_kind"] == "development_host"
|
||||
assert payload["result"]["checked_at"] == "2026-05-29T00:00:00Z"
|
||||
assert payload["result"]["status"] == "unknown"
|
||||
assert payload["result"]["source_trace"]["live_probe"] is False
|
||||
assert payload["result"]["readiness"] == "not_configured"
|
||||
assert "display_summary" in payload["result"]
|
||||
assert {signal["signal_id"] for signal in payload["result"]["signals"]} == {
|
||||
"health",
|
||||
"agent_health",
|
||||
"dashboard_status",
|
||||
}
|
||||
assert payload["result"]["authority"]["runtime_state_mutation"] is False
|
||||
assert all(value is False for value in payload["result"]["authority"].values())
|
||||
|
||||
|
||||
def test_runtime_health_envelope_rejects_old_shape_fields():
|
||||
result = route.runtime_health_payload()
|
||||
|
||||
forbidden_top_level = {"contract_id", "summary"}
|
||||
forbidden_authority = {
|
||||
"read_only",
|
||||
"mcp_exposure",
|
||||
"profile_exposure_change",
|
||||
"delegated_memory_grant",
|
||||
}
|
||||
|
||||
assert forbidden_top_level.isdisjoint(result)
|
||||
assert forbidden_authority.isdisjoint(result["authority"])
|
||||
assert isinstance(result["redactions"][0], dict)
|
||||
assert isinstance(result["warnings"][0], dict)
|
||||
assert isinstance(result["source_trace"], list)
|
||||
for signal in result["signals"]:
|
||||
assert {"signal_id", "state", "summary", "redacted"} == set(signal)
|
||||
|
||||
|
||||
def test_host_signal_mapping_is_closed_and_redacted():
|
||||
@ -66,11 +98,12 @@ def test_host_signal_mapping_is_closed_and_redacted():
|
||||
)
|
||||
|
||||
assert payload["status"] == "unavailable"
|
||||
assert {signal["detail"] for signal in payload["signals"]} == {"redacted"}
|
||||
assert payload["source_trace"]["host_surfaces"] == [
|
||||
"health",
|
||||
"agent_health",
|
||||
"dashboard_status",
|
||||
assert {signal["summary"] for signal in payload["signals"]} == {"redacted"}
|
||||
assert {signal["redacted"] for signal in payload["signals"]} == {True}
|
||||
assert [entry["source_id"] for entry in payload["source_trace"]] == [
|
||||
"runtime-health-contract",
|
||||
"hermes-host-adapter-contract",
|
||||
"hermes-runtime-health-slice",
|
||||
]
|
||||
|
||||
|
||||
|
||||
@ -34,6 +34,12 @@ def test_runtime_health_display_has_no_hidden_write_surface():
|
||||
"eval(",
|
||||
"new Function",
|
||||
"innerHTML",
|
||||
"insertAdjacentHTML",
|
||||
"outerHTML",
|
||||
"DOMParser",
|
||||
"template.innerHTML",
|
||||
"window.location",
|
||||
"createElement(\"script\"",
|
||||
"<form",
|
||||
".submit(",
|
||||
"POST",
|
||||
@ -67,3 +73,31 @@ def test_runtime_health_mounts_only_in_cortex_os_panel_context():
|
||||
assert 'document.addEventListener("DOMContentLoaded", loadRuntimeHealth' not in js
|
||||
assert "loadRuntimeHealth();" in js
|
||||
assert js.count("/api/cortex-os/runtime-health") == 1
|
||||
|
||||
|
||||
def test_runtime_health_display_consumes_canonical_envelope_only():
|
||||
js = JS.read_text(encoding="utf-8")
|
||||
|
||||
for snippet in [
|
||||
"payload.result.display_summary",
|
||||
"displaySummary.headline",
|
||||
"displaySummary.detail",
|
||||
"signal.signal_id",
|
||||
"signal.state",
|
||||
"signal.summary",
|
||||
]:
|
||||
assert snippet in js
|
||||
for forbidden in [
|
||||
"payload.result.summary",
|
||||
"signal.name",
|
||||
"signal.status",
|
||||
"signal.detail",
|
||||
"contract_id",
|
||||
"source_trace.live_probe",
|
||||
"source_trace.raw_payload_passthrough",
|
||||
"authority.read_only",
|
||||
"authority.mcp_exposure",
|
||||
"authority.profile_exposure_change",
|
||||
"authority.delegated_memory_grant",
|
||||
]:
|
||||
assert forbidden not in js
|
||||
|
||||
Loading…
Reference in New Issue
Block a user