diff --git a/apps/decodex/src/orchestrator/operator_dashboard.html b/apps/decodex/src/orchestrator/operator_dashboard.html index 8bbf844..920071e 100644 --- a/apps/decodex/src/orchestrator/operator_dashboard.html +++ b/apps/decodex/src/orchestrator/operator_dashboard.html @@ -3550,6 +3550,30 @@

Run History

.replace(/\b\w/g, (character) => character.toUpperCase()); } + function sentenceToken(value) { + return humanizeToken(value).toLowerCase(); + } + + function normalizedDisplayText(value) { + return String(value || "") + .toLowerCase() + .replace(/[^a-z0-9]+/g, " ") + .trim(); + } + + function displayTextRepeats(left, right) { + const normalizedLeft = normalizedDisplayText(left); + const normalizedRight = normalizedDisplayText(right); + + return Boolean( + normalizedLeft && + normalizedRight && + (normalizedLeft === normalizedRight || + normalizedLeft.includes(normalizedRight) || + normalizedRight.includes(normalizedLeft)), + ); + } + function compactStateToken(value) { if (!value) { return "none"; @@ -4022,6 +4046,14 @@

Run History

return humanizeToken(lane.classification); } + function postReviewBlockerStatus(lane, blockerScope) { + if (lane.review_decision && blockerScope === "Review") { + return `review ${compactStateToken(lane.review_decision)}`; + } + + return "needs attention"; + } + function toneForQueuedCandidate(candidate) { if (candidate.display_classification === "owned_active") { return "tone-run"; @@ -4129,28 +4161,28 @@

Run History

function queuedCandidateReasonText(candidate) { if (candidate.display_classification === "owned_active") { - return "Running Lane Claim"; + return "running lane claim"; } if ( candidate.attention?.worktree_has_tracked_changes && candidate.attention?.retry_budget_attempt_count != null ) { - return "Partial Patch Retained"; + return "partial patch retained"; } if (candidate.attention?.thread_status === "systemError") { - return "App-Server Error"; + return "app-server error"; } if (candidate.attention?.last_event_type === "item/tool/call") { - return "Tool Call Stalled"; + return "tool call stalled"; } if (candidate.attention?.attention_error_class) { - return humanizeToken(candidate.attention.attention_error_class); + return sentenceToken(candidate.attention.attention_error_class); } if (candidate.reason === "issue_needs_attention") { - return "Needs Attention"; + return "needs attention"; } if (candidate.attention?.retry_budget_attempt_count != null) { - return "Auto Retry Paused"; + return "auto retry paused"; } if (candidate.reason === "global_concurrency_exhausted") { return ""; @@ -4159,7 +4191,32 @@

Run History

return ""; } - return humanizeToken(candidate.reason); + return sentenceToken(candidate.reason); + } + + function queuedCandidateInlineReason(candidate) { + const reason = queuedCandidateReasonText(candidate); + if (!reason) { + return ""; + } + + if ( + candidate.attention?.attention_error_class && + displayTextRepeats(reason, sentenceToken(candidate.attention.attention_error_class)) + ) { + return ""; + } + if ( + candidate.attention?.worktree_has_tracked_changes && + displayTextRepeats(reason, "patch retained") + ) { + return ""; + } + if (displayTextRepeats(candidate.attention?.summary, reason)) { + return ""; + } + + return reason; } function queuedCandidateNeedsAttention(candidate) { @@ -4573,7 +4630,7 @@

Run History

facts.push(["Auto retry", autoRetryBlockedReasonText(attention.auto_retry_blocked_reason)]); } if (attention.attention_error_class) { - facts.push(["Cause", humanizeToken(attention.attention_error_class)]); + facts.push(["Cause", sentenceToken(attention.attention_error_class)]); } if (attention.worktree_has_tracked_changes) { facts.push(["Patch", "retained"]); @@ -4609,7 +4666,7 @@

Run History

return "needs-attention label set"; } - return `blocked by ${humanizeToken(reason)}`; + return `blocked by ${sentenceToken(reason)}`; } function statusLabel(label, tone) { @@ -5061,7 +5118,10 @@

Run History

const bits = [statusLabel(humanizeToken(run.status), tone)]; if (run.wait_reason) { - bits.push(inlineStatusFact("Wait", humanizeToken(run.wait_reason))); + const waitReason = sentenceToken(run.wait_reason); + if (!displayTextRepeats(recentRunSummary(run, lane), waitReason)) { + bits.push(inlineStatusFact("Wait", waitReason)); + } } if (run.continuation_pending) { bits.push(inlineStatusFact("Continuation", "Pending")); @@ -6747,7 +6807,6 @@

Run History

return facts; } - facts.push(["History", humanizeToken(outcome.ledger_status)]); if (outcome.pr_url) { facts.push(["PR", outcome.pr_url]); } @@ -6757,9 +6816,6 @@

Run History

if (outcome.branch) { facts.push(["Branch", outcome.branch]); } - if (outcome.closeout_status) { - facts.push(["Closeout", humanizeToken(outcome.closeout_status)]); - } if (outcome.needs_attention_reason) { facts.push(["Attention", outcome.needs_attention_reason]); } @@ -7186,7 +7242,7 @@

Run History

summary: run.next_retry_at ? `Retry scheduled for ${formatTimestamp(run.next_retry_at)}.` : `Waiting on ${humanizeToken(run.wait_reason || run.phase).toLowerCase()}.`, - status: run.wait_reason ? `wait ${humanizeToken(run.wait_reason)}` : `phase ${humanizeToken(run.phase)}`, + status: "waiting", facts: [ ["Codex thread", runThreadSummary(run)], ["Thread flags", runThreadFlagSummary(run)], @@ -7234,7 +7290,7 @@

Run History

issue: issueKey, title: postReviewBlockerTitle(lane), summary: "", - status: lane.review_decision && blockerScope === "Review" ? `review ${compactStateToken(lane.review_decision)}` : humanizeToken(lane.classification), + status: postReviewBlockerStatus(lane, blockerScope), facts: [ ["Checks", compactStateToken(lane.check_state)], ["Threads", lane.unresolved_review_threads == null ? "none" : String(lane.unresolved_review_threads)], @@ -7910,7 +7966,7 @@

Run History

? candidate.blocker_identifiers.join(", ") : "NONE"; const summary = summarizeQueuedCandidate(candidate); - const reason = queuedCandidateReasonText(candidate); + const reason = queuedCandidateInlineReason(candidate); return `
@@ -8044,14 +8100,18 @@

${escapeHtml(item.title)}

const summary = activeRunSummary(run); if (run.wait_reason && !runWaitReasonShowsExecutionProgress(run)) { - statusBits.push(inlineStatusFact("Wait", humanizeToken(run.wait_reason))); + const waitReason = sentenceToken(run.wait_reason); + if (!displayTextRepeats(summary, waitReason)) { + statusBits.push(inlineStatusFact("Wait", waitReason)); + } } if (runTelemetryMissing(run)) { - statusBits.push( - runHasChildAgentActivity(run) - ? inlineStatusFact("Metadata", "Pending") - : inlineStatusFact("Telemetry", "Missing"), - ); + const telemetryFact = runHasChildAgentActivity(run) + ? ["Metadata", "Pending"] + : ["Telemetry", "Missing"]; + if (!displayTextRepeats(summary, telemetryFact.join(" "))) { + statusBits.push(inlineStatusFact(telemetryFact[0], telemetryFact[1])); + } } if ( !runStoppedProcessNeedsAttention(run) && @@ -8060,10 +8120,14 @@

${escapeHtml(item.title)}

statusBits.push(inlineStatusFact("Agent", "Done")); } if (run.interactive_requested && !runStoppedProcessNeedsAttention(run)) { - statusBits.push(inlineStatusFact("Operator", "Input")); + if (!displayTextRepeats(summary, "operator input")) { + statusBits.push(inlineStatusFact("Operator", "Input")); + } } if (run.continuation_pending) { - statusBits.push(inlineStatusFact("Continuation", "Pending")); + if (!displayTextRepeats(summary, "continuation pending")) { + statusBits.push(inlineStatusFact("Continuation", "Pending")); + } } const attemptNumber = attemptNumberFromRun(run); const stopControl = renderRunStopControl(run); diff --git a/apps/decodex/src/orchestrator/tests/operator/status/dashboard.rs b/apps/decodex/src/orchestrator/tests/operator/status/dashboard.rs index 756c86d..f806d45 100644 --- a/apps/decodex/src/orchestrator/tests/operator/status/dashboard.rs +++ b/apps/decodex/src/orchestrator/tests/operator/status/dashboard.rs @@ -345,7 +345,7 @@ fn operator_dashboard_child_bucket_rows_split_time_bars_from_event_diagnostics() assert!(!response.contains("Queue ownership")); assert!(response.contains("attention.worktree_path")); assert!(response.contains("candidate.attention?.attention_error_class")); - assert!(response.contains("facts.push([\"Cause\", humanizeToken(attention.attention_error_class)]);")); + assert!(response.contains("facts.push([\"Cause\", sentenceToken(attention.attention_error_class)]);")); assert!(response.contains("queued attention")); assert!(response.contains("worktree.ownership_reason")); assert!(response.contains("const hygiene = worktree.hygiene;")); @@ -387,6 +387,13 @@ fn operator_dashboard_active_run_status_copy_stays_concise() { assert!(response.contains("Stopped agent process")); assert!(response.contains("attention stopped")); assert!(response.contains("inlineStatusFact(\"Agent\", \"Done\")")); + assert!(response.contains("const waitReason = sentenceToken(run.wait_reason);")); + assert!(response.contains("if (!displayTextRepeats(summary, waitReason))")); + assert!(response.contains("displayTextRepeats(summary, \"operator input\")")); + assert!(response.contains("status: \"waiting\",")); + assert!(!response.contains( + "status: run.wait_reason ? `wait ${humanizeToken(run.wait_reason)}`" + )); assert!(!response.contains("Running through ${focus}")); assert!(!response.contains("Running through model execution.")); assert!(!response.contains("Time is going to ${focus}.")); @@ -941,10 +948,15 @@ fn operator_dashboard_projects_keep_status_summary_compact() { assert!(response.contains("return priority == null ? \"NONE\" : `P${priority}`;")); assert!(response.contains("function queuedCandidateSummaryIsNoise(summary)")); assert!(response.contains("normalized.includes(\"systemerror\")")); + assert!(response.contains("function sentenceToken(value)")); + assert!(response.contains("function displayTextRepeats(left, right)")); assert!(response.contains("function inlineStatusFact(label, value)")); assert!(response.contains("titleCaseLabel(label)")); assert!(response.contains("const summary = summarizeQueuedCandidate(candidate);")); - assert!(response.contains("const reason = queuedCandidateReasonText(candidate);")); + assert!(response.contains("const reason = queuedCandidateInlineReason(candidate);")); + assert!(response.contains("bits.push(inlineStatusFact(\"History\", humanizeToken(outcome.ledger_status)))")); + assert!(!response.contains("facts.push([\"History\", humanizeToken(outcome.ledger_status)])")); + assert!(!response.contains("facts.push([\"Closeout\", humanizeToken(outcome.closeout_status)])")); assert!(response.contains("
")); assert!(!response.contains("queue-facts")); assert!(response.contains("cardField(\"State\", formatDetailToken(candidate.state))")); @@ -1099,9 +1111,11 @@ fn operator_dashboard_review_cards_omit_static_summary_copy() { let response = dashboard_response(); assert!(response.contains("summary: \"\",\n\t\t\t\t\t\t\tstatus: `run ${humanizeToken(activeRun.phase)}`")); - assert!(response.contains("summary: \"\",\n\t\t\t\t\t\t\tstatus: lane.review_decision")); + assert!(response.contains("function postReviewBlockerStatus(lane, blockerScope)")); + assert!(response.contains("status: postReviewBlockerStatus(lane, blockerScope)")); assert!(response.contains("summary: \"\",\n\t\t\t\t\t\t\tstatus: lane.check_state")); assert!(response.contains("summary: \"\",\n\t\t\t\t\t\t\tstatus: lane.mergeable")); + assert!(!response.contains("status: lane.review_decision && blockerScope === \"Review\"")); assert!( response.contains("${item.summary ? `

${escapeHtml(item.summary)}

` : \"\"}") ); @@ -1207,7 +1221,7 @@ fn operator_dashboard_prioritizes_needs_attention_reason_over_retry_count() { .next() .expect("queued candidate reason function should have an end"); - assert!(reason_text.contains("return \"Needs Attention\";")); + assert!(reason_text.contains("return \"needs attention\";")); assert!( response.contains("facts.push([\"Attempt status\", humanizeToken(attention.attempt_status)]);") ); @@ -1218,7 +1232,10 @@ fn operator_dashboard_prioritizes_needs_attention_reason_over_retry_count() { "facts.push([\"Auto retry\", autoRetryBlockedReasonText(attention.auto_retry_blocked_reason)]);" )); assert!(response.contains("return \"needs-attention label set\";")); - assert!(reason_text.contains("return \"Auto Retry Paused\";")); + assert!(reason_text.contains("return \"auto retry paused\";")); + assert!(response.contains("function queuedCandidateInlineReason(candidate)")); + assert!(response.contains("displayTextRepeats(reason, sentenceToken(candidate.attention.attention_error_class))")); + assert!(response.contains("displayTextRepeats(reason, \"patch retained\")")); assert!(!response.contains("return \"blocked by needs-attention\";")); assert!(!reason_text.contains("return \"Retry budget held\";")); assert!(!response.contains( @@ -1226,10 +1243,10 @@ fn operator_dashboard_prioritizes_needs_attention_reason_over_retry_count() { )); assert!( reason_text - .find("return \"Needs Attention\";") + .find("return \"needs attention\";") .expect("needs-attention reason should exist") < reason_text - .find("return \"Auto Retry Paused\";") + .find("return \"auto retry paused\";") .expect("retry-budget reason should exist") ); }