fix(monitor): clarify workbench read-model root causes

This commit is contained in:
Codex
2026-06-27 05:40:17 +00:00
parent 8d4565448e
commit c833294ab0
6 changed files with 33 additions and 17 deletions
@@ -1527,10 +1527,10 @@ function buildSessionInvariantFindings(control, manifest = {}) {
const traceIds = arrayStrings(messageOrder.traceIds).slice(0, 12);
const findingId = stringOrNull(detail.findingId) ?? "workbench-message-order-user-clustered-after-navigation";
const severity = stringOrNull(detail.severity) ?? "amber";
const rootCause = "workbench-message-order-projection-drops-terminal-cards-after-navigation";
const rootCauseStatus = "confirmed-from-controlled-refresh-dom;otel-read-model-comparison-required";
const rootCause = "session_message_role_clustered";
const rootCauseStatus = "confirmed-from-controlled-refresh-dom;check-otel-session_messages_read-role-sequence";
const rootCauseConfidence = "medium";
const nextAction = "Use OTel session_messages_read/session detail for the same canarySessionId and traceIds. If the read model is interleaved but DOM is clustered, fix Workbench renderer/hydration ordering; if the read model is already clustered, fix session message projection/read-model ordering.";
const nextAction = "Use OTel session_messages_read/session detail for the same canarySessionId and traceIds. Compare roleSequencePrefix and adjacentSameRoleCount; if the read model is already clustered, fix Workbench projection/read-model timeline ordering before changing renderer code.";
findings.push({
id: findingId,
severity,
@@ -2373,10 +2373,10 @@ function buildFindings(samples, control, network, errors, sampleMetrics, promptN
id: "session-rail-title-fallback-root-cause",
severity: "red",
summary: "INV-02 root cause visible: session rail is rendering fallback Session ses_* titles, so list projection/read model or rail binding is missing stable title/preview data before DOM render",
rootCause: "session-list-title-projection-missing-or-not-bound",
rootCause: "session_title_fallback_from_facts",
rootCauseStatus: "confirmed-from-dom-session-rail",
rootCauseConfidence: "high",
nextAction: "Check OTel session_list_read fallbackTitleCount/fallbackTitleRatio for the same run; fix session list projection/read model title/firstUserMessagePreview before changing DOM fallback text.",
nextAction: "Check OTel session_list_read fallbackTitleCount/fallbackTitleRatio and emptyPreviewCount for the same run; fix session list projection/read model title/preview before changing DOM fallback text.",
count: sessionRailTitleSummary.overThresholdSampleCount ?? sessionRailTitleSummary.majorityFallbackSampleCount,
thresholdRatio: alertThresholds.sessionRailFallbackRatio,
maxFallbackRatio: sessionRailTitleSummary.maxFallbackRatio,
@@ -2398,7 +2398,7 @@ function buildFindings(samples, control, network, errors, sampleMetrics, promptN
id: "trace-events-page-read-404-root-cause",
severity: "red",
summary: "INV-07 root cause visible: /v1/workbench/traces/:traceId/events returned HTTP 404 for a trace event page read, so the failure is in the trace-events API paging/read-model contract before DOM rendering",
rootCause: "trace-events-api-page-read-returned-404",
rootCause: "trace_events_paging_contract_mismatch",
rootCauseStatus: "confirmed-from-browser-network",
rootCauseConfidence: "high",
nextAction: "Use OTel trace_events_read for the same trace to compare sinceSeq/afterProjectedSeq, returnedEvents, range, totalEvents, hasMore and fullTraceLoaded; fix backend paging contract or add missing instrumentation before changing renderer behavior.",
@@ -1636,10 +1636,10 @@ def root_cause_candidates(http_summary, agentrun, read_model, lag_summary, error
})
if lag_summary.get("status") == "confirmed":
candidates.append({
"code": "hwlab_projection_stale",
"label": "HWLAB projection stale",
"code": "projection_read_model_stale",
"label": "projection/read-model stale",
"confidence": 0.94,
"summary": "HWLAB projection stale: read model sequence is behind the caller/requested event window.",
"summary": "Projection/read-model stale: read model sequence is behind the caller/requested event window.",
"evidence": {
"sourceEventCount": read_model.get("sourceEventCount"),
"requestedSinceSeq": read_model.get("requestedSinceSeq"),
@@ -1649,10 +1649,10 @@ def root_cause_candidates(http_summary, agentrun, read_model, lag_summary, error
})
elif lag_summary.get("status") == "suspected":
candidates.append({
"code": "hwlab_projection_lag_suspected",
"label": "HWLAB projection stale",
"code": "projection_read_model_lag_suspected",
"label": "projection/read-model stale",
"confidence": 0.64,
"summary": "HWLAB projection stale is suspected because AgentRun is terminal but HWLAB read-model evidence is incomplete.",
"summary": "Projection/read-model stale is suspected because AgentRun is terminal but HWLAB read-model evidence is incomplete.",
"evidence": lag_summary.get("reasons", []),
})
failure_kind = str(agentrun.get("failureKind") or "")
@@ -1976,7 +1976,7 @@ if terminal_status in ("failed", "error", "timeout", "blocked", "cancelled"):
if terminal_status == "completed":
facts.append("AgentRun completed")
if lag.get("status") in ("confirmed", "suspected"):
facts.append("HWLAB projection stale")
facts.append("projection/read-model stale")
if idle_warning_spans and terminal_status in (None, ""):
facts.append("AgentRun runner idle warnings active")
if not facts: