Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 39s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
1529 lines
60 KiB
TypeScript
1529 lines
60 KiB
TypeScript
"use client";
|
|
|
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
import { useLocale, useTranslations } from "next-intl";
|
|
import {
|
|
Activity,
|
|
ArrowRight,
|
|
Bell,
|
|
Bot,
|
|
BookOpenCheck,
|
|
CheckCircle2,
|
|
Database,
|
|
Gauge,
|
|
ListChecks,
|
|
RefreshCw,
|
|
Rocket,
|
|
Send,
|
|
ShieldCheck,
|
|
SlidersHorizontal,
|
|
TriangleAlert,
|
|
Wrench,
|
|
} from "lucide-react";
|
|
|
|
import { getRuntimeApiBaseUrl } from "@/lib/runtime-api-base";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
type RuntimeReceiptReadback = {
|
|
db_read_status?: string | null;
|
|
ansible_apply_executed?: {
|
|
total?: number | null;
|
|
recent?: number | null;
|
|
} | null;
|
|
auto_repair_execution_receipt?: {
|
|
total?: number | null;
|
|
recent?: number | null;
|
|
} | null;
|
|
post_apply_verifier?: {
|
|
total?: number | null;
|
|
recent?: number | null;
|
|
} | null;
|
|
km_writeback?: {
|
|
total?: number | null;
|
|
recent?: number | null;
|
|
} | null;
|
|
telegram_receipt?: {
|
|
total?: number | null;
|
|
recent?: number | null;
|
|
} | null;
|
|
mcp_context?: {
|
|
total?: number | null;
|
|
recent?: number | null;
|
|
} | null;
|
|
service_log_evidence?: {
|
|
total?: number | null;
|
|
recent?: number | null;
|
|
} | null;
|
|
executor_log_projection?: {
|
|
total?: number | null;
|
|
recent?: number | null;
|
|
} | null;
|
|
playbook_trust?: {
|
|
total?: number | null;
|
|
recent?: number | null;
|
|
} | null;
|
|
trace_ledger?: {
|
|
stage_count?: number | null;
|
|
recorded_stage_count?: number | null;
|
|
missing_required_stage_ids?: string[] | null;
|
|
learning_source_stage_ids?: string[] | null;
|
|
public_safety?: {
|
|
reads_raw_sessions?: boolean | null;
|
|
stores_secret_values?: boolean | null;
|
|
stores_unredacted_telegram_payload?: boolean | null;
|
|
stores_internal_reasoning?: boolean | null;
|
|
} | null;
|
|
stages?: Array<{
|
|
stage_id?: string | null;
|
|
display_name?: string | null;
|
|
recorded?: boolean | null;
|
|
total?: number | null;
|
|
recent?: number | null;
|
|
required_for_closed_loop?: boolean | null;
|
|
feeds_learning?: boolean | null;
|
|
next_action_if_missing?: string | null;
|
|
}> | null;
|
|
} | null;
|
|
log_integration_taxonomy?: {
|
|
label_dimensions?: string[] | null;
|
|
rollups?: {
|
|
source_family_count?: number | null;
|
|
active_source_family_count?: number | null;
|
|
label_dimension_count?: number | null;
|
|
classified_event_total?: number | null;
|
|
recent_classified_event_total?: number | null;
|
|
learning_source_family_count?: number | null;
|
|
} | null;
|
|
} | null;
|
|
multi_product_taxonomy?: {
|
|
status?: string | null;
|
|
missing_product_scope_ids?: string[] | null;
|
|
rollups?: {
|
|
product_scope_count?: number | null;
|
|
contract_ready_product_scope_count?: number | null;
|
|
runtime_adapter_active_count?: number | null;
|
|
missing_required_dimension_count?: number | null;
|
|
} | null;
|
|
} | null;
|
|
agent_decision_wiring?: {
|
|
status?: string | null;
|
|
missing_required_stage_ids?: string[] | null;
|
|
rollups?: {
|
|
stage_count?: number | null;
|
|
required_stage_present_count?: number | null;
|
|
required_stage_missing_count?: number | null;
|
|
} | null;
|
|
} | null;
|
|
learning_loop?: {
|
|
status?: string | null;
|
|
missing_required_stage_ids?: string[] | null;
|
|
rollups?: {
|
|
stage_count?: number | null;
|
|
required_stage_present_count?: number | null;
|
|
required_stage_missing_count?: number | null;
|
|
similar_case_source_total?: number | null;
|
|
} | null;
|
|
} | null;
|
|
alert_noise_reduction?: {
|
|
status?: string | null;
|
|
missing_required_stage_ids?: string[] | null;
|
|
rollups?: {
|
|
stage_count?: number | null;
|
|
required_stage_present_count?: number | null;
|
|
required_stage_missing_count?: number | null;
|
|
suppressed_alert_total?: number | null;
|
|
controlled_route_total?: number | null;
|
|
} | null;
|
|
} | null;
|
|
work_item_progress?: {
|
|
ordered_items?: AutomationWorkItem[] | null;
|
|
source_family_items?: AutomationWorkItem[] | null;
|
|
rollups?: {
|
|
work_item_count?: number | null;
|
|
ordered_work_item_count?: number | null;
|
|
source_family_work_item_count?: number | null;
|
|
completed_count?: number | null;
|
|
in_progress_count?: number | null;
|
|
pending_count?: number | null;
|
|
blocked_count?: number | null;
|
|
not_started_count?: number | null;
|
|
} | null;
|
|
} | null;
|
|
latest_flow_closure?: {
|
|
apply_op_id?: string | null;
|
|
incident_id?: string | null;
|
|
has_post_apply_verifier?: boolean | null;
|
|
has_km_writeback?: boolean | null;
|
|
has_telegram_receipt?: boolean | null;
|
|
closed?: boolean | null;
|
|
missing?: string[] | null;
|
|
} | null;
|
|
autonomous_execution_loop_ledger?: {
|
|
execution_state?: string | null;
|
|
closed?: boolean | null;
|
|
missing_stage_ids?: string[] | null;
|
|
next_executor_action?: string | null;
|
|
operation_id?: string | null;
|
|
incident_id?: string | null;
|
|
catalog_id?: string | null;
|
|
} | null;
|
|
};
|
|
|
|
type RuntimeControlPayload = {
|
|
program_status?: {
|
|
implementation_completion_percent?: number | null;
|
|
deploy_readback_marker?: string | null;
|
|
} | null;
|
|
current_policy?: {
|
|
low_risk_controlled_apply_allowed?: boolean | null;
|
|
medium_risk_controlled_apply_allowed?: boolean | null;
|
|
high_risk_controlled_apply_allowed?: boolean | null;
|
|
critical_break_glass_required?: boolean | null;
|
|
} | null;
|
|
runtime_receipt_readback?: RuntimeReceiptReadback | null;
|
|
rollups?: Record<string, number | string | boolean | null | undefined> | null;
|
|
};
|
|
|
|
type PriorityWorkOrderPayload = {
|
|
status?: string | null;
|
|
summary?: {
|
|
latest_successful_deploy_marker?: string | null;
|
|
latest_successful_deployed_source_sha?: string | null;
|
|
latest_successful_deployed_source_short_sha?: string | null;
|
|
ai_loop_current_blocker_deploy_marker_readback_required?: boolean | null;
|
|
ai_loop_current_blocker_deploy_marker_resolved_by_production_readback?: boolean | null;
|
|
} | null;
|
|
mainline_execution_state?: {
|
|
current_main_cd_run_id?: string | null;
|
|
current_main_cd_run_status?: string | null;
|
|
current_main_latest_source_sha?: string | null;
|
|
} | null;
|
|
};
|
|
|
|
type LogConsumerReadbackPayload = {
|
|
status?: string | null;
|
|
active_blockers?: string[] | null;
|
|
controlled_consume?: {
|
|
controlled_consume_allowed?: boolean | null;
|
|
runtime_target_write_performed?: boolean | null;
|
|
} | null;
|
|
target_rollups?: Array<{
|
|
target?: string | null;
|
|
binding_count?: number | null;
|
|
ready_binding_count?: number | null;
|
|
target_write_performed?: boolean | null;
|
|
context_receipt_write_count?: number | null;
|
|
metadata_only?: boolean | null;
|
|
}> | null;
|
|
rollups?: {
|
|
dispatch_ledger_row_count?: number | null;
|
|
consumer_apply_receipt_row_count?: number | null;
|
|
consumer_binding_count?: number | null;
|
|
ready_consumer_binding_count?: number | null;
|
|
ready_target_count?: number | null;
|
|
metadata_only_receipt_count?: number | null;
|
|
post_apply_verifier_ref_count?: number | null;
|
|
target_context_receipt_write_count?: number | null;
|
|
controlled_consumer_readback_ready?: boolean | null;
|
|
runtime_target_write_performed?: boolean | null;
|
|
km_consumer_binding_count?: number | null;
|
|
rag_consumer_binding_count?: number | null;
|
|
playbook_consumer_binding_count?: number | null;
|
|
mcp_consumer_binding_count?: number | null;
|
|
verifier_consumer_binding_count?: number | null;
|
|
ai_agent_consumer_binding_count?: number | null;
|
|
km_context_receipt_write_count?: number | null;
|
|
rag_context_receipt_write_count?: number | null;
|
|
playbook_context_receipt_write_count?: number | null;
|
|
mcp_context_receipt_write_count?: number | null;
|
|
verifier_context_receipt_write_count?: number | null;
|
|
ai_agent_context_receipt_write_count?: number | null;
|
|
telegram_alert_learning_context_readback_ready?: boolean | null;
|
|
telegram_alert_learning_context_receipt_count?: number | null;
|
|
telegram_alert_learning_ai_agent_context_receipt_count?: number | null;
|
|
telegram_alert_learning_ready_target_count?: number | null;
|
|
telegram_alert_learning_target_count?: number | null;
|
|
} | null;
|
|
operation_boundaries?: {
|
|
runtime_target_write_performed?: boolean | null;
|
|
raw_log_payload_persisted?: boolean | null;
|
|
secret_value_collection_allowed?: boolean | null;
|
|
github_api_used?: boolean | null;
|
|
} | null;
|
|
};
|
|
|
|
type TelegramPostApplyVerifierPayload = {
|
|
status?: string | null;
|
|
active_blockers?: string[] | null;
|
|
rollups?: {
|
|
telegram_alert_learning_context_post_apply_verifier_ready?: boolean | null;
|
|
context_receipt_count?: number | null;
|
|
verified_context_receipt_count?: number | null;
|
|
verified_target_count?: number | null;
|
|
target_count?: number | null;
|
|
verified_ai_agent_context_receipt_count?: number | null;
|
|
post_apply_verifier_ref_count?: number | null;
|
|
metadata_only_receipt_count?: number | null;
|
|
raw_payload_included_count?: number | null;
|
|
secret_value_read_count?: number | null;
|
|
runtime_write_performed_count?: number | null;
|
|
telegram_send_performed_count?: number | null;
|
|
failed_context_receipt_count?: number | null;
|
|
verified_targets?: string[] | null;
|
|
} | null;
|
|
operation_boundaries?: {
|
|
raw_payload_included?: boolean | null;
|
|
secret_value_collection_allowed?: boolean | null;
|
|
runtime_target_write_performed?: boolean | null;
|
|
telegram_send_performed?: boolean | null;
|
|
github_api_used?: boolean | null;
|
|
} | null;
|
|
};
|
|
|
|
type PanelMode = "full" | "compact";
|
|
type Tone = "ok" | "warn" | "neutral";
|
|
type WorkFilter = "all" | "completed" | "active" | "pending" | "blocked";
|
|
type WorkItemStatus = "completed" | "in_progress" | "pending" | "blocked" | "not_started" | string;
|
|
|
|
type AutomationWorkItem = {
|
|
work_item_id?: string | null;
|
|
priority?: string | null;
|
|
title?: string | null;
|
|
status?: WorkItemStatus | null;
|
|
exit_criteria?: string | null;
|
|
source_family_id?: string | null;
|
|
next_controlled_action?: string | null;
|
|
};
|
|
|
|
const API_BASE = getRuntimeApiBaseUrl();
|
|
|
|
function numberValue(value: unknown): string {
|
|
const numeric = Number(value ?? 0);
|
|
if (!Number.isFinite(numeric)) return "0";
|
|
return new Intl.NumberFormat("zh-TW").format(numeric);
|
|
}
|
|
|
|
function toNumber(value: unknown): number {
|
|
const numeric = Number(value ?? 0);
|
|
return Number.isFinite(numeric) ? numeric : 0;
|
|
}
|
|
|
|
function readbackNumber(value: unknown, ready: boolean): string {
|
|
if (!ready) return "--";
|
|
return numberValue(value);
|
|
}
|
|
|
|
function readbackRatio(done: unknown, total: unknown, ready: boolean): string {
|
|
if (!ready) return "-- / --";
|
|
return `${numberValue(done)} / ${numberValue(total)}`;
|
|
}
|
|
|
|
function shortRef(value?: string | null): string {
|
|
if (!value) return "--";
|
|
return value.length > 12 ? `${value.slice(0, 8)}...` : value;
|
|
}
|
|
|
|
function toneClass(tone: Tone): string {
|
|
if (tone === "ok") return "border-[#9bc7a4] bg-[#f0faf2] text-[#17602a]";
|
|
if (tone === "warn") return "border-[#d9b36f] bg-[#fff7e8] text-[#8a5a08]";
|
|
return "border-[#d8d3c7] bg-white text-[#5f5b52]";
|
|
}
|
|
|
|
function statusToneClass(status?: WorkItemStatus | null): string {
|
|
if (status === "completed") return "border-[#9bc7a4] bg-[#f0faf2] text-[#17602a]";
|
|
if (status === "in_progress") return "border-[#9bb6d9] bg-[#eef5ff] text-[#1f5b9b]";
|
|
if (status === "pending" || status === "not_started") return "border-[#d8d3c7] bg-[#faf9f3] text-[#5f5b52]";
|
|
if (status === "blocked") return "border-[#e2a29b] bg-[#fff0ef] text-[#9f2f25]";
|
|
return "border-[#d8d3c7] bg-white text-[#5f5b52]";
|
|
}
|
|
|
|
function matchesWorkFilter(item: AutomationWorkItem, filter: WorkFilter): boolean {
|
|
const status = item.status ?? "pending";
|
|
if (filter === "all") return true;
|
|
if (filter === "active") return status === "in_progress" || status === "not_started";
|
|
return status === filter;
|
|
}
|
|
|
|
function formatTime(value: Date | null, locale: string): string {
|
|
if (!value) return "--";
|
|
return value.toLocaleTimeString(locale === "zh-TW" ? "zh-TW" : "en-US", {
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
second: "2-digit",
|
|
});
|
|
}
|
|
|
|
async function fetchRuntimeControl(): Promise<RuntimeControlPayload | null> {
|
|
const controller = new AbortController();
|
|
const timeout = window.setTimeout(() => controller.abort(), 12_000);
|
|
try {
|
|
const response = await fetch(`${API_BASE}/api/v1/agents/agent-autonomous-runtime-control`, {
|
|
cache: "no-store",
|
|
signal: controller.signal,
|
|
});
|
|
if (!response.ok) return null;
|
|
return (await response.json()) as RuntimeControlPayload;
|
|
} catch {
|
|
return null;
|
|
} finally {
|
|
window.clearTimeout(timeout);
|
|
}
|
|
}
|
|
|
|
async function fetchPriorityWorkOrder(): Promise<PriorityWorkOrderPayload | null> {
|
|
const controller = new AbortController();
|
|
const timeout = window.setTimeout(() => controller.abort(), 12_000);
|
|
try {
|
|
const response = await fetch(`${API_BASE}/api/v1/agents/awoooi-priority-work-order-readback`, {
|
|
cache: "no-store",
|
|
signal: controller.signal,
|
|
});
|
|
if (!response.ok) return null;
|
|
return (await response.json()) as PriorityWorkOrderPayload;
|
|
} catch {
|
|
return null;
|
|
} finally {
|
|
window.clearTimeout(timeout);
|
|
}
|
|
}
|
|
|
|
async function fetchLogConsumerReadback(): Promise<LogConsumerReadbackPayload | null> {
|
|
const controller = new AbortController();
|
|
const timeout = window.setTimeout(() => controller.abort(), 12_000);
|
|
try {
|
|
const response = await fetch(`${API_BASE}/api/v1/agents/agent-log-controlled-writeback-consumer-readback`, {
|
|
cache: "no-store",
|
|
signal: controller.signal,
|
|
});
|
|
if (!response.ok) return null;
|
|
return (await response.json()) as LogConsumerReadbackPayload;
|
|
} catch {
|
|
return null;
|
|
} finally {
|
|
window.clearTimeout(timeout);
|
|
}
|
|
}
|
|
|
|
async function fetchTelegramPostApplyVerifier(): Promise<TelegramPostApplyVerifierPayload | null> {
|
|
const controller = new AbortController();
|
|
const timeout = window.setTimeout(() => controller.abort(), 12_000);
|
|
try {
|
|
const response = await fetch(`${API_BASE}/api/v1/agents/telegram-alert-learning-context-post-apply-verifier`, {
|
|
cache: "no-store",
|
|
signal: controller.signal,
|
|
});
|
|
if (!response.ok) return null;
|
|
return (await response.json()) as TelegramPostApplyVerifierPayload;
|
|
} catch {
|
|
return null;
|
|
} finally {
|
|
window.clearTimeout(timeout);
|
|
}
|
|
}
|
|
|
|
export function AutonomousRuntimeReceiptPanel({
|
|
mode = "full",
|
|
}: {
|
|
mode?: PanelMode;
|
|
}) {
|
|
const t = useTranslations("awooop.autonomousRuntime");
|
|
const locale = useLocale();
|
|
const [payload, setPayload] = useState<RuntimeControlPayload | null>(null);
|
|
const [priorityPayload, setPriorityPayload] = useState<PriorityWorkOrderPayload | null>(null);
|
|
const [consumerPayload, setConsumerPayload] = useState<LogConsumerReadbackPayload | null>(null);
|
|
const [telegramVerifierPayload, setTelegramVerifierPayload] = useState<TelegramPostApplyVerifierPayload | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState(false);
|
|
const [updatedAt, setUpdatedAt] = useState<Date | null>(null);
|
|
const [workFilter, setWorkFilter] = useState<WorkFilter>("all");
|
|
|
|
const refresh = useCallback(async () => {
|
|
setLoading(true);
|
|
const [next, priority, consumer, telegramVerifier] = await Promise.all([
|
|
fetchRuntimeControl(),
|
|
fetchPriorityWorkOrder(),
|
|
fetchLogConsumerReadback(),
|
|
fetchTelegramPostApplyVerifier(),
|
|
]);
|
|
setPayload(next);
|
|
setPriorityPayload(priority);
|
|
setConsumerPayload(consumer);
|
|
setTelegramVerifierPayload(telegramVerifier);
|
|
setError(next === null);
|
|
setUpdatedAt(next ? new Date() : null);
|
|
setLoading(false);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
refresh();
|
|
const timer = window.setInterval(refresh, 30_000);
|
|
return () => window.clearInterval(timer);
|
|
}, [refresh]);
|
|
|
|
const hasRuntimeReadback = payload !== null;
|
|
const hasPriorityReadback = priorityPayload !== null;
|
|
const hasConsumerReadback = consumerPayload !== null;
|
|
const hasTelegramVerifierReadback = telegramVerifierPayload !== null;
|
|
const readback = payload?.runtime_receipt_readback;
|
|
const ledger = readback?.autonomous_execution_loop_ledger;
|
|
const traceLedger = readback?.trace_ledger;
|
|
const logTaxonomy = readback?.log_integration_taxonomy;
|
|
const logRollups = logTaxonomy?.rollups ?? {};
|
|
const multiProductRollups = readback?.multi_product_taxonomy?.rollups ?? {};
|
|
const decisionRollups = readback?.agent_decision_wiring?.rollups ?? {};
|
|
const decisionMissing = readback?.agent_decision_wiring?.missing_required_stage_ids ?? [];
|
|
const learningRollups = readback?.learning_loop?.rollups ?? {};
|
|
const learningMissing = readback?.learning_loop?.missing_required_stage_ids ?? [];
|
|
const alertNoiseRollups = readback?.alert_noise_reduction?.rollups ?? {};
|
|
const alertNoiseMissing = readback?.alert_noise_reduction?.missing_required_stage_ids ?? [];
|
|
const workItemRollups = readback?.work_item_progress?.rollups ?? {};
|
|
const orderedWorkItems = readback?.work_item_progress?.ordered_items ?? [];
|
|
const sourceFamilyItems = readback?.work_item_progress?.source_family_items ?? [];
|
|
const latestFlow = readback?.latest_flow_closure;
|
|
const rollups = payload?.rollups ?? {};
|
|
const consumerRollups = consumerPayload?.rollups ?? {};
|
|
const consumerBlockers = consumerPayload?.active_blockers ?? [];
|
|
const telegramVerifierRollups = telegramVerifierPayload?.rollups ?? {};
|
|
const telegramVerifierBlockers = telegramVerifierPayload?.active_blockers ?? [];
|
|
const consumerReady = consumerRollups.controlled_consumer_readback_ready === true
|
|
|| consumerPayload?.status === "controlled_writeback_consumer_readback_ready";
|
|
const telegramPostApplyVerifierReady =
|
|
telegramVerifierRollups.telegram_alert_learning_context_post_apply_verifier_ready === true
|
|
|| telegramVerifierPayload?.status === "telegram_alert_learning_context_post_apply_verified";
|
|
const runtimeTargetWritePerformed = consumerRollups.runtime_target_write_performed === true
|
|
|| consumerPayload?.controlled_consume?.runtime_target_write_performed === true
|
|
|| consumerPayload?.operation_boundaries?.runtime_target_write_performed === true
|
|
|| rollups.live_log_controlled_writeback_runtime_target_write_count === 1;
|
|
const closed = ledger?.closed === true || latestFlow?.closed === true;
|
|
const dbOk = readback?.db_read_status === "ok";
|
|
const missingStages = traceLedger?.missing_required_stage_ids
|
|
?? ledger?.missing_stage_ids
|
|
?? latestFlow?.missing
|
|
?? [];
|
|
const initialRuntimeReadInFlight = loading && !hasRuntimeReadback && !error;
|
|
const tone: Tone = initialRuntimeReadInFlight ? "neutral" : error || !dbOk ? "warn" : closed ? "ok" : "neutral";
|
|
const stateLabel = initialRuntimeReadInFlight
|
|
? t("states.loading")
|
|
: closed
|
|
? t("states.closed")
|
|
: error
|
|
? t("states.unavailable")
|
|
: dbOk
|
|
? t("states.open")
|
|
: t("states.degraded");
|
|
|
|
const metrics = useMemo(
|
|
() => [
|
|
{
|
|
key: "trace",
|
|
label: t("metrics.trace"),
|
|
value: toNumber(rollups.live_trace_recorded_stage_count ?? traceLedger?.recorded_stage_count),
|
|
recent: toNumber(traceLedger?.stage_count),
|
|
icon: CheckCircle2,
|
|
caption: t("traceCaption", {
|
|
count: numberValue(traceLedger?.stage_count ?? 0),
|
|
missing: numberValue(missingStages.length),
|
|
}),
|
|
},
|
|
{
|
|
key: "mcp",
|
|
label: t("metrics.mcp"),
|
|
value: toNumber(rollups.live_mcp_context_count ?? readback?.mcp_context?.total),
|
|
recent: toNumber(readback?.mcp_context?.recent),
|
|
icon: Bot,
|
|
},
|
|
{
|
|
key: "logs",
|
|
label: t("metrics.logs"),
|
|
value: toNumber(
|
|
rollups.live_log_classified_event_total
|
|
?? logRollups.classified_event_total
|
|
?? (
|
|
toNumber(rollups.live_service_log_evidence_count ?? readback?.service_log_evidence?.total)
|
|
+ toNumber(rollups.live_executor_log_projection_count ?? readback?.executor_log_projection?.total)
|
|
)
|
|
),
|
|
recent: toNumber(readback?.service_log_evidence?.recent)
|
|
+ toNumber(readback?.executor_log_projection?.recent),
|
|
icon: Activity,
|
|
},
|
|
{
|
|
key: "decision",
|
|
label: t("metrics.decision"),
|
|
value: toNumber(
|
|
rollups.live_agent_decision_wiring_required_present_count
|
|
?? decisionRollups.required_stage_present_count
|
|
),
|
|
recent: toNumber(
|
|
rollups.live_agent_decision_wiring_stage_count
|
|
?? decisionRollups.stage_count
|
|
),
|
|
icon: Bot,
|
|
caption: t("traceCaption", {
|
|
count: numberValue(
|
|
rollups.live_agent_decision_wiring_stage_count
|
|
?? decisionRollups.stage_count
|
|
?? 0
|
|
),
|
|
missing: numberValue(
|
|
rollups.live_agent_decision_wiring_required_missing_count
|
|
?? decisionRollups.required_stage_missing_count
|
|
?? decisionMissing.length
|
|
),
|
|
}),
|
|
},
|
|
{
|
|
key: "learning",
|
|
label: t("metrics.learning"),
|
|
value: toNumber(
|
|
rollups.live_learning_loop_required_present_count
|
|
?? learningRollups.required_stage_present_count
|
|
),
|
|
recent: toNumber(
|
|
rollups.live_learning_loop_stage_count
|
|
?? learningRollups.stage_count
|
|
),
|
|
icon: BookOpenCheck,
|
|
caption: t("traceCaption", {
|
|
count: numberValue(
|
|
rollups.live_learning_loop_stage_count
|
|
?? learningRollups.stage_count
|
|
?? 0
|
|
),
|
|
missing: numberValue(
|
|
rollups.live_learning_loop_required_missing_count
|
|
?? learningRollups.required_stage_missing_count
|
|
?? learningMissing.length
|
|
),
|
|
}),
|
|
},
|
|
{
|
|
key: "alerts",
|
|
label: t("metrics.alerts"),
|
|
value: toNumber(
|
|
rollups.live_alert_noise_required_present_count
|
|
?? alertNoiseRollups.required_stage_present_count
|
|
),
|
|
recent: toNumber(
|
|
rollups.live_alert_noise_stage_count
|
|
?? alertNoiseRollups.stage_count
|
|
),
|
|
icon: Bell,
|
|
caption: t("traceCaption", {
|
|
count: numberValue(
|
|
rollups.live_alert_noise_stage_count
|
|
?? alertNoiseRollups.stage_count
|
|
?? 0
|
|
),
|
|
missing: numberValue(
|
|
rollups.live_alert_noise_required_missing_count
|
|
?? alertNoiseRollups.required_stage_missing_count
|
|
?? alertNoiseMissing.length
|
|
),
|
|
}),
|
|
},
|
|
{
|
|
key: "apply",
|
|
label: t("metrics.apply"),
|
|
value: toNumber(rollups.live_ansible_apply_executed_count ?? readback?.ansible_apply_executed?.total),
|
|
recent: toNumber(readback?.ansible_apply_executed?.recent),
|
|
icon: Wrench,
|
|
},
|
|
{
|
|
key: "receipt",
|
|
label: t("metrics.receipt"),
|
|
value: toNumber(rollups.live_auto_repair_execution_receipt_count ?? readback?.auto_repair_execution_receipt?.total),
|
|
recent: toNumber(readback?.auto_repair_execution_receipt?.recent),
|
|
icon: Activity,
|
|
},
|
|
{
|
|
key: "verifier",
|
|
label: t("metrics.verifier"),
|
|
value: toNumber(rollups.live_post_apply_verifier_count ?? readback?.post_apply_verifier?.total),
|
|
recent: toNumber(readback?.post_apply_verifier?.recent),
|
|
icon: ShieldCheck,
|
|
},
|
|
{
|
|
key: "km",
|
|
label: t("metrics.km"),
|
|
value: toNumber(rollups.live_km_writeback_count ?? readback?.km_writeback?.total),
|
|
recent: toNumber(readback?.km_writeback?.recent),
|
|
icon: BookOpenCheck,
|
|
},
|
|
{
|
|
key: "playbook",
|
|
label: t("metrics.playbook"),
|
|
value: toNumber(rollups.live_playbook_trust_signal_count ?? readback?.playbook_trust?.total),
|
|
recent: toNumber(readback?.playbook_trust?.recent),
|
|
icon: ShieldCheck,
|
|
},
|
|
{
|
|
key: "telegram",
|
|
label: t("metrics.telegram"),
|
|
value: toNumber(rollups.live_telegram_receipt_count ?? readback?.telegram_receipt?.total),
|
|
recent: toNumber(readback?.telegram_receipt?.recent),
|
|
icon: Send,
|
|
},
|
|
],
|
|
[
|
|
decisionMissing.length,
|
|
decisionRollups.required_stage_missing_count,
|
|
decisionRollups.required_stage_present_count,
|
|
decisionRollups.stage_count,
|
|
learningMissing.length,
|
|
alertNoiseMissing.length,
|
|
alertNoiseRollups.required_stage_missing_count,
|
|
alertNoiseRollups.required_stage_present_count,
|
|
alertNoiseRollups.stage_count,
|
|
learningRollups.required_stage_missing_count,
|
|
learningRollups.required_stage_present_count,
|
|
learningRollups.stage_count,
|
|
logRollups.classified_event_total,
|
|
missingStages.length,
|
|
readback,
|
|
rollups,
|
|
t,
|
|
traceLedger,
|
|
]
|
|
);
|
|
|
|
const policy = payload?.current_policy;
|
|
const riskText = [
|
|
policy?.low_risk_controlled_apply_allowed ? t("risk.low") : null,
|
|
policy?.medium_risk_controlled_apply_allowed ? t("risk.medium") : null,
|
|
policy?.high_risk_controlled_apply_allowed ? t("risk.high") : null,
|
|
].filter(Boolean).join(" / ");
|
|
const workTotal = toNumber(rollups.live_work_item_count ?? workItemRollups.work_item_count);
|
|
const workCompleted = toNumber(rollups.live_work_item_completed_count ?? workItemRollups.completed_count);
|
|
const orderedWorkTotal = toNumber(workItemRollups.ordered_work_item_count ?? orderedWorkItems.length);
|
|
const sourceFamilyTotal = toNumber(workItemRollups.source_family_work_item_count ?? sourceFamilyItems.length);
|
|
const workCompletionPercent = workTotal > 0
|
|
? Math.min(100, Math.round((workCompleted / workTotal) * 100))
|
|
: 0;
|
|
const prioritySummary = priorityPayload?.summary;
|
|
const mainlineState = priorityPayload?.mainline_execution_state;
|
|
const deployedSourceSha = prioritySummary?.latest_successful_deployed_source_sha
|
|
?? mainlineState?.current_main_latest_source_sha
|
|
?? null;
|
|
const deployedSourceShortSha = prioritySummary?.latest_successful_deployed_source_short_sha
|
|
?? (deployedSourceSha ? deployedSourceSha.slice(0, 10) : null);
|
|
const deployReadbackResolved = prioritySummary?.ai_loop_current_blocker_deploy_marker_resolved_by_production_readback === true;
|
|
const deployCardTone: Tone = !hasPriorityReadback ? "neutral" : deployReadbackResolved ? "ok" : "warn";
|
|
const runtimeCardTone: Tone = !hasRuntimeReadback ? "neutral" : dbOk ? "ok" : "warn";
|
|
const workCardTone: Tone = !hasRuntimeReadback ? "neutral" : workTotal > 0 && workCompleted === workTotal ? "ok" : "warn";
|
|
const sourceCardTone: Tone = !hasRuntimeReadback
|
|
? "neutral"
|
|
: toNumber(rollups.live_log_active_source_family_count ?? logRollups.active_source_family_count) > 0
|
|
? "ok"
|
|
: "warn";
|
|
const eventCardTone: Tone = !hasRuntimeReadback
|
|
? "neutral"
|
|
: toNumber(rollups.live_log_classified_event_total ?? logRollups.classified_event_total) > 0
|
|
? "ok"
|
|
: "neutral";
|
|
const consumerCardTone: Tone = !hasConsumerReadback ? "neutral" : consumerReady ? "ok" : "warn";
|
|
const proofCards = [
|
|
{
|
|
key: "deploy",
|
|
label: t("proof.deploy"),
|
|
value: deployedSourceShortSha ?? "--",
|
|
detail: t("proof.deployDetail", {
|
|
status: hasPriorityReadback
|
|
? mainlineState?.current_main_cd_run_status ?? priorityPayload?.status ?? "--"
|
|
: t("states.loading"),
|
|
}),
|
|
icon: Rocket,
|
|
tone: deployCardTone,
|
|
},
|
|
{
|
|
key: "runtime",
|
|
label: t("proof.runtime"),
|
|
value: !hasRuntimeReadback ? t("states.loading") : dbOk ? t("proof.ok") : t("proof.degraded"),
|
|
detail: t("proof.runtimeDetail", {
|
|
marker: shortRef(payload?.program_status?.deploy_readback_marker),
|
|
}),
|
|
icon: Database,
|
|
tone: runtimeCardTone,
|
|
},
|
|
{
|
|
key: "work",
|
|
label: t("proof.workItems"),
|
|
value: readbackRatio(workCompleted, workTotal, hasRuntimeReadback),
|
|
detail: t("proof.workItemsDetail", {
|
|
percent: readbackNumber(workCompletionPercent, hasRuntimeReadback),
|
|
}),
|
|
icon: ListChecks,
|
|
tone: workCardTone,
|
|
},
|
|
{
|
|
key: "sources",
|
|
label: t("proof.sources"),
|
|
value: readbackRatio(
|
|
rollups.live_log_active_source_family_count ?? logRollups.active_source_family_count,
|
|
rollups.live_log_source_family_count ?? logRollups.source_family_count,
|
|
hasRuntimeReadback
|
|
),
|
|
detail: t("proof.sourcesDetail"),
|
|
icon: Bot,
|
|
tone: sourceCardTone,
|
|
},
|
|
{
|
|
key: "events",
|
|
label: t("proof.events"),
|
|
value: readbackNumber(
|
|
rollups.live_log_classified_event_total ?? logRollups.classified_event_total,
|
|
hasRuntimeReadback
|
|
),
|
|
detail: t("proof.eventsDetail", {
|
|
recent: readbackNumber(
|
|
rollups.live_log_recent_classified_event_total ?? logRollups.recent_classified_event_total,
|
|
hasRuntimeReadback
|
|
),
|
|
}),
|
|
icon: Activity,
|
|
tone: eventCardTone,
|
|
},
|
|
{
|
|
key: "consumer",
|
|
label: t("proof.consumer"),
|
|
value: readbackRatio(
|
|
rollups.live_log_controlled_writeback_consumer_apply_receipt_count
|
|
?? consumerRollups.consumer_apply_receipt_row_count,
|
|
rollups.live_log_controlled_writeback_consumer_dispatch_ledger_count
|
|
?? consumerRollups.dispatch_ledger_row_count,
|
|
hasConsumerReadback || hasRuntimeReadback
|
|
),
|
|
detail: t("proof.consumerDetail", {
|
|
targets: readbackNumber(consumerRollups.ready_target_count, hasConsumerReadback),
|
|
}),
|
|
icon: Database,
|
|
tone: consumerCardTone,
|
|
},
|
|
];
|
|
const writebackCards = [
|
|
{
|
|
key: "dispatch",
|
|
label: t("writeback.dispatch"),
|
|
value: readbackNumber(
|
|
rollups.live_log_controlled_writeback_consumer_dispatch_ledger_count
|
|
?? consumerRollups.dispatch_ledger_row_count,
|
|
hasConsumerReadback || hasRuntimeReadback
|
|
),
|
|
detail: t("writeback.dispatchDetail"),
|
|
icon: Send,
|
|
tone: consumerCardTone,
|
|
},
|
|
{
|
|
key: "apply",
|
|
label: t("writeback.apply"),
|
|
value: readbackNumber(
|
|
rollups.live_log_controlled_writeback_consumer_apply_receipt_count
|
|
?? consumerRollups.consumer_apply_receipt_row_count,
|
|
hasConsumerReadback || hasRuntimeReadback
|
|
),
|
|
detail: t("writeback.applyDetail"),
|
|
icon: CheckCircle2,
|
|
tone: !hasConsumerReadback && !hasRuntimeReadback ? "neutral" as Tone : runtimeTargetWritePerformed ? "ok" as Tone : "neutral" as Tone,
|
|
},
|
|
{
|
|
key: "bindings",
|
|
label: t("writeback.bindings"),
|
|
value: readbackRatio(
|
|
consumerRollups.ready_consumer_binding_count,
|
|
consumerRollups.consumer_binding_count,
|
|
hasConsumerReadback
|
|
),
|
|
detail: t("writeback.bindingsDetail"),
|
|
icon: Bot,
|
|
tone: !hasConsumerReadback
|
|
? "neutral" as Tone
|
|
: toNumber(consumerRollups.ready_consumer_binding_count) === toNumber(consumerRollups.consumer_binding_count)
|
|
&& toNumber(consumerRollups.consumer_binding_count) > 0
|
|
? "ok" as Tone
|
|
: "warn" as Tone,
|
|
},
|
|
{
|
|
key: "targets",
|
|
label: t("writeback.targets"),
|
|
value: readbackNumber(consumerRollups.ready_target_count, hasConsumerReadback),
|
|
detail: t("writeback.targetsDetail"),
|
|
icon: ListChecks,
|
|
tone: !hasConsumerReadback
|
|
? "neutral" as Tone
|
|
: toNumber(consumerRollups.ready_target_count) >= 6 ? "ok" as Tone : "warn" as Tone,
|
|
},
|
|
{
|
|
key: "context",
|
|
label: t("writeback.contextWrites"),
|
|
value: readbackNumber(consumerRollups.target_context_receipt_write_count, hasConsumerReadback),
|
|
detail: t("writeback.contextWritesDetail"),
|
|
icon: BookOpenCheck,
|
|
tone: !hasConsumerReadback
|
|
? "neutral" as Tone
|
|
: runtimeTargetWritePerformed ? "ok" as Tone : "neutral" as Tone,
|
|
},
|
|
{
|
|
key: "telegramContext",
|
|
label: t("writeback.telegramContext"),
|
|
value: readbackRatio(
|
|
consumerRollups.telegram_alert_learning_ai_agent_context_receipt_count,
|
|
consumerRollups.telegram_alert_learning_context_receipt_count,
|
|
hasConsumerReadback
|
|
),
|
|
detail: t("writeback.telegramContextDetail", {
|
|
targets: readbackRatio(
|
|
consumerRollups.telegram_alert_learning_ready_target_count,
|
|
consumerRollups.telegram_alert_learning_target_count,
|
|
hasConsumerReadback
|
|
),
|
|
}),
|
|
icon: Rocket,
|
|
tone: !hasConsumerReadback
|
|
? "neutral" as Tone
|
|
: consumerRollups.telegram_alert_learning_context_readback_ready === true
|
|
? "ok" as Tone
|
|
: "warn" as Tone,
|
|
},
|
|
{
|
|
key: "blockers",
|
|
label: t("writeback.blockers"),
|
|
value: readbackNumber(consumerBlockers.length, hasConsumerReadback),
|
|
detail: !hasConsumerReadback
|
|
? t("states.loading")
|
|
: consumerBlockers.length > 0 ? consumerBlockers[0] : t("writeback.noBlockers"),
|
|
icon: TriangleAlert,
|
|
tone: !hasConsumerReadback
|
|
? "neutral" as Tone
|
|
: consumerBlockers.length > 0 ? "warn" as Tone : "ok" as Tone,
|
|
},
|
|
];
|
|
const targetWritebackCards = [
|
|
{
|
|
key: "km",
|
|
label: t("writeback.targetsMap.km"),
|
|
binding: consumerRollups.km_consumer_binding_count,
|
|
writes: consumerRollups.km_context_receipt_write_count,
|
|
icon: BookOpenCheck,
|
|
},
|
|
{
|
|
key: "rag",
|
|
label: t("writeback.targetsMap.rag"),
|
|
binding: consumerRollups.rag_consumer_binding_count,
|
|
writes: consumerRollups.rag_context_receipt_write_count,
|
|
icon: Database,
|
|
},
|
|
{
|
|
key: "playbook",
|
|
label: t("writeback.targetsMap.playbook"),
|
|
binding: consumerRollups.playbook_consumer_binding_count,
|
|
writes: consumerRollups.playbook_context_receipt_write_count,
|
|
icon: ShieldCheck,
|
|
},
|
|
{
|
|
key: "mcp",
|
|
label: t("writeback.targetsMap.mcp"),
|
|
binding: consumerRollups.mcp_consumer_binding_count,
|
|
writes: consumerRollups.mcp_context_receipt_write_count,
|
|
icon: Bot,
|
|
},
|
|
{
|
|
key: "verifier",
|
|
label: t("writeback.targetsMap.verifier"),
|
|
binding: consumerRollups.verifier_consumer_binding_count,
|
|
writes: consumerRollups.verifier_context_receipt_write_count,
|
|
icon: Gauge,
|
|
},
|
|
{
|
|
key: "aiAgent",
|
|
label: t("writeback.targetsMap.aiAgent"),
|
|
binding: consumerRollups.ai_agent_consumer_binding_count,
|
|
writes: consumerRollups.ai_agent_context_receipt_write_count,
|
|
icon: Rocket,
|
|
},
|
|
];
|
|
const telegramVerifierCards = [
|
|
{
|
|
key: "status",
|
|
label: t("postApplyVerifier.status"),
|
|
value: !hasTelegramVerifierReadback
|
|
? t("states.loading")
|
|
: telegramPostApplyVerifierReady
|
|
? t("states.closed")
|
|
: t("states.open"),
|
|
detail: t("postApplyVerifier.statusDetail"),
|
|
icon: ShieldCheck,
|
|
tone: !hasTelegramVerifierReadback
|
|
? "neutral" as Tone
|
|
: telegramPostApplyVerifierReady ? "ok" as Tone : "warn" as Tone,
|
|
},
|
|
{
|
|
key: "contexts",
|
|
label: t("postApplyVerifier.contexts"),
|
|
value: readbackRatio(
|
|
telegramVerifierRollups.verified_context_receipt_count,
|
|
telegramVerifierRollups.context_receipt_count,
|
|
hasTelegramVerifierReadback
|
|
),
|
|
detail: t("postApplyVerifier.contextsDetail"),
|
|
icon: ListChecks,
|
|
tone: !hasTelegramVerifierReadback
|
|
? "neutral" as Tone
|
|
: toNumber(telegramVerifierRollups.failed_context_receipt_count) === 0
|
|
&& toNumber(telegramVerifierRollups.verified_context_receipt_count) > 0
|
|
? "ok" as Tone
|
|
: "warn" as Tone,
|
|
},
|
|
{
|
|
key: "targets",
|
|
label: t("postApplyVerifier.targets"),
|
|
value: readbackRatio(
|
|
telegramVerifierRollups.verified_target_count,
|
|
telegramVerifierRollups.target_count,
|
|
hasTelegramVerifierReadback
|
|
),
|
|
detail: t("postApplyVerifier.targetsDetail"),
|
|
icon: Database,
|
|
tone: !hasTelegramVerifierReadback
|
|
? "neutral" as Tone
|
|
: toNumber(telegramVerifierRollups.verified_target_count) === toNumber(telegramVerifierRollups.target_count)
|
|
&& toNumber(telegramVerifierRollups.target_count) > 0
|
|
? "ok" as Tone
|
|
: "warn" as Tone,
|
|
},
|
|
{
|
|
key: "aiAgent",
|
|
label: t("postApplyVerifier.aiAgent"),
|
|
value: readbackNumber(
|
|
telegramVerifierRollups.verified_ai_agent_context_receipt_count,
|
|
hasTelegramVerifierReadback
|
|
),
|
|
detail: t("postApplyVerifier.aiAgentDetail"),
|
|
icon: Rocket,
|
|
tone: !hasTelegramVerifierReadback
|
|
? "neutral" as Tone
|
|
: toNumber(telegramVerifierRollups.verified_ai_agent_context_receipt_count) > 0
|
|
? "ok" as Tone
|
|
: "warn" as Tone,
|
|
},
|
|
{
|
|
key: "refs",
|
|
label: t("postApplyVerifier.refs"),
|
|
value: readbackNumber(
|
|
telegramVerifierRollups.post_apply_verifier_ref_count,
|
|
hasTelegramVerifierReadback
|
|
),
|
|
detail: t("postApplyVerifier.refsDetail"),
|
|
icon: Gauge,
|
|
tone: !hasTelegramVerifierReadback
|
|
? "neutral" as Tone
|
|
: toNumber(telegramVerifierRollups.post_apply_verifier_ref_count) > 0
|
|
? "ok" as Tone
|
|
: "warn" as Tone,
|
|
},
|
|
{
|
|
key: "boundaries",
|
|
label: t("postApplyVerifier.boundaries"),
|
|
value: readbackRatio(
|
|
telegramVerifierRollups.raw_payload_included_count,
|
|
telegramVerifierRollups.secret_value_read_count,
|
|
hasTelegramVerifierReadback
|
|
),
|
|
detail: t("postApplyVerifier.boundariesDetail", {
|
|
runtime: readbackNumber(telegramVerifierRollups.runtime_write_performed_count, hasTelegramVerifierReadback),
|
|
telegram: readbackNumber(telegramVerifierRollups.telegram_send_performed_count, hasTelegramVerifierReadback),
|
|
}),
|
|
icon: TriangleAlert,
|
|
tone: !hasTelegramVerifierReadback
|
|
? "neutral" as Tone
|
|
: toNumber(telegramVerifierRollups.raw_payload_included_count) === 0
|
|
&& toNumber(telegramVerifierRollups.secret_value_read_count) === 0
|
|
&& telegramVerifierPayload?.operation_boundaries?.github_api_used !== true
|
|
? "ok" as Tone
|
|
: "warn" as Tone,
|
|
},
|
|
{
|
|
key: "blockers",
|
|
label: t("postApplyVerifier.blockers"),
|
|
value: readbackNumber(telegramVerifierBlockers.length, hasTelegramVerifierReadback),
|
|
detail: !hasTelegramVerifierReadback
|
|
? t("states.loading")
|
|
: telegramVerifierBlockers.length > 0
|
|
? telegramVerifierBlockers[0]
|
|
: t("postApplyVerifier.noBlockers"),
|
|
icon: TriangleAlert,
|
|
tone: !hasTelegramVerifierReadback
|
|
? "neutral" as Tone
|
|
: telegramVerifierBlockers.length > 0 ? "warn" as Tone : "ok" as Tone,
|
|
},
|
|
];
|
|
const visibleWorkItems = orderedWorkItems.filter((item) => matchesWorkFilter(item, workFilter));
|
|
const orderedCompleted = orderedWorkItems.filter((item) => item.status === "completed").length;
|
|
const orderedActive = orderedWorkItems.filter((item) => (
|
|
item.status === "in_progress" || item.status === "not_started"
|
|
)).length;
|
|
const orderedPending = orderedWorkItems.filter((item) => item.status === "pending").length;
|
|
const orderedBlocked = orderedWorkItems.filter((item) => item.status === "blocked").length;
|
|
const workFilters: Array<{
|
|
key: WorkFilter;
|
|
count: number;
|
|
icon: typeof ListChecks;
|
|
}> = [
|
|
{ key: "all", count: orderedWorkTotal, icon: ListChecks },
|
|
{ key: "completed", count: orderedCompleted, icon: CheckCircle2 },
|
|
{ key: "active", count: orderedActive, icon: Gauge },
|
|
{ key: "pending", count: orderedPending, icon: ArrowRight },
|
|
{ key: "blocked", count: orderedBlocked, icon: TriangleAlert },
|
|
];
|
|
|
|
return (
|
|
<section className="border border-[#e0ddd4] bg-white">
|
|
<div className="flex flex-wrap items-start justify-between gap-4 border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-3">
|
|
<div className="flex min-w-0 items-start gap-3">
|
|
<span className={cn("flex h-9 w-9 shrink-0 items-center justify-center border", toneClass(tone))}>
|
|
<Bot className="h-4 w-4" aria-hidden="true" />
|
|
</span>
|
|
<div className="min-w-0">
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<h3 className="text-sm font-semibold text-[#141413]">{t("title")}</h3>
|
|
<span className={cn("inline-flex border px-2 py-0.5 text-xs font-semibold", toneClass(tone))}>
|
|
{stateLabel}
|
|
</span>
|
|
<span className="font-mono text-xs text-[#77736a]">
|
|
{hasRuntimeReadback
|
|
? t("completion", {
|
|
percent: numberValue(payload?.program_status?.implementation_completion_percent ?? 0),
|
|
})
|
|
: t("completionLoading")}
|
|
</span>
|
|
</div>
|
|
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
|
{t("detail", {
|
|
incident: ledger?.incident_id ?? latestFlow?.incident_id ?? "--",
|
|
op: shortRef(ledger?.operation_id ?? latestFlow?.apply_op_id),
|
|
catalog: ledger?.catalog_id ?? "--",
|
|
})}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<span className="font-mono text-xs text-[#77736a]">
|
|
{formatTime(updatedAt, locale)}
|
|
</span>
|
|
<button
|
|
type="button"
|
|
onClick={refresh}
|
|
disabled={loading}
|
|
className="inline-flex items-center gap-2 border border-[#d8d3c7] bg-white px-3 py-2 text-xs font-semibold text-[#141413] hover:border-[#d97757] disabled:opacity-60"
|
|
aria-label={t("refresh")}
|
|
>
|
|
<RefreshCw className={cn("h-4 w-4", loading && "animate-spin")} aria-hidden="true" />
|
|
{t("refresh")}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
data-testid="ai-automation-production-proof"
|
|
className="grid gap-px border-b border-[#e0ddd4] bg-[#e0ddd4] md:grid-cols-3 xl:grid-cols-6"
|
|
>
|
|
{proofCards.map((card) => {
|
|
const Icon = card.icon;
|
|
return (
|
|
<div key={card.key} className="bg-white px-4 py-4">
|
|
<div className="flex items-start justify-between gap-3">
|
|
<div className="min-w-0">
|
|
<p className="text-xs font-semibold text-[#77736a]">{card.label}</p>
|
|
<p className="mt-2 truncate font-mono text-xl font-semibold text-[#141413]">
|
|
{card.value}
|
|
</p>
|
|
</div>
|
|
<span className={cn("flex h-8 w-8 shrink-0 items-center justify-center border", toneClass(card.tone))}>
|
|
<Icon className="h-4 w-4" aria-hidden="true" />
|
|
</span>
|
|
</div>
|
|
<p className="mt-2 line-clamp-2 text-xs leading-5 text-[#5f5b52]">
|
|
{card.detail}
|
|
</p>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<div
|
|
data-testid="ai-loop-consumer-writeback-readback"
|
|
className="border-b border-[#e0ddd4] bg-white"
|
|
>
|
|
<div className="grid gap-px bg-[#e0ddd4] md:grid-cols-3 xl:grid-cols-6">
|
|
{writebackCards.map((card) => {
|
|
const Icon = card.icon;
|
|
return (
|
|
<div key={card.key} className="bg-white px-4 py-3">
|
|
<div className="flex items-start justify-between gap-3">
|
|
<div className="min-w-0">
|
|
<p className="text-xs font-semibold text-[#77736a]">{card.label}</p>
|
|
<p className="mt-2 truncate font-mono text-lg font-semibold text-[#141413]">
|
|
{card.value}
|
|
</p>
|
|
</div>
|
|
<span className={cn("flex h-8 w-8 shrink-0 items-center justify-center border", toneClass(card.tone))}>
|
|
<Icon className="h-4 w-4" aria-hidden="true" />
|
|
</span>
|
|
</div>
|
|
<p className="mt-1 line-clamp-2 text-xs leading-5 text-[#5f5b52]">
|
|
{card.detail}
|
|
</p>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
<div className="grid gap-px border-t border-[#e0ddd4] bg-[#e0ddd4] md:grid-cols-3 xl:grid-cols-6">
|
|
{targetWritebackCards.map((card) => {
|
|
const Icon = card.icon;
|
|
const bindingCount = toNumber(card.binding);
|
|
const writeCount = toNumber(card.writes);
|
|
return (
|
|
<div key={card.key} className="bg-white px-4 py-3">
|
|
<div className="flex items-start justify-between gap-3">
|
|
<div>
|
|
<p className="text-xs font-semibold text-[#77736a]">{card.label}</p>
|
|
<p className="mt-2 font-mono text-lg font-semibold text-[#141413]">
|
|
{readbackNumber(writeCount, hasConsumerReadback)}
|
|
{" / "}
|
|
{readbackNumber(bindingCount, hasConsumerReadback)}
|
|
</p>
|
|
</div>
|
|
<Icon className="h-4 w-4 text-[#87867f]" aria-hidden="true" />
|
|
</div>
|
|
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
|
{t("writeback.targetDetail")}
|
|
</p>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
<div
|
|
data-testid="telegram-alert-post-apply-verifier-readback"
|
|
className="border-t border-[#e0ddd4] bg-white"
|
|
>
|
|
<div className="flex flex-wrap items-start justify-between gap-3 px-4 py-3">
|
|
<div className="min-w-0">
|
|
<div className="flex items-center gap-2">
|
|
<ShieldCheck className="h-4 w-4 text-[#87867f]" aria-hidden="true" />
|
|
<h4 className="text-sm font-semibold text-[#141413]">{t("postApplyVerifier.title")}</h4>
|
|
</div>
|
|
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
|
{t("postApplyVerifier.subtitle")}
|
|
</p>
|
|
</div>
|
|
<span className={cn("inline-flex border px-2 py-0.5 text-xs font-semibold", toneClass(
|
|
!hasTelegramVerifierReadback
|
|
? "neutral"
|
|
: telegramPostApplyVerifierReady ? "ok" : "warn"
|
|
))}>
|
|
{!hasTelegramVerifierReadback
|
|
? t("states.loading")
|
|
: telegramVerifierPayload?.status ?? "--"}
|
|
</span>
|
|
</div>
|
|
<div className="grid gap-px border-t border-[#e0ddd4] bg-[#e0ddd4] md:grid-cols-3 xl:grid-cols-7">
|
|
{telegramVerifierCards.map((card) => {
|
|
const Icon = card.icon;
|
|
return (
|
|
<div key={card.key} className="bg-white px-4 py-3">
|
|
<div className="flex items-start justify-between gap-3">
|
|
<div className="min-w-0">
|
|
<p className="text-xs font-semibold text-[#77736a]">{card.label}</p>
|
|
<p className="mt-2 truncate font-mono text-lg font-semibold text-[#141413]">
|
|
{card.value}
|
|
</p>
|
|
</div>
|
|
<span className={cn("flex h-8 w-8 shrink-0 items-center justify-center border", toneClass(card.tone))}>
|
|
<Icon className="h-4 w-4" aria-hidden="true" />
|
|
</span>
|
|
</div>
|
|
<p className="mt-1 line-clamp-2 text-xs leading-5 text-[#5f5b52]">
|
|
{card.detail}
|
|
</p>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-px bg-[#e0ddd4] md:grid-cols-5 xl:grid-cols-12">
|
|
<div className="bg-white px-4 py-3">
|
|
<p className="text-xs font-semibold text-[#77736a]">{t("metrics.loop")}</p>
|
|
<div className="mt-2 flex items-center gap-2">
|
|
{!hasRuntimeReadback ? (
|
|
<RefreshCw className="h-4 w-4 animate-spin text-[#87867f]" aria-hidden="true" />
|
|
) : closed ? (
|
|
<CheckCircle2 className="h-4 w-4 text-[#17602a]" aria-hidden="true" />
|
|
) : (
|
|
<TriangleAlert className="h-4 w-4 text-[#8a5a08]" aria-hidden="true" />
|
|
)}
|
|
<span className="font-mono text-lg font-semibold text-[#141413]">
|
|
{!hasRuntimeReadback ? "--" : closed ? "1" : "0"}
|
|
</span>
|
|
</div>
|
|
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
|
{!hasRuntimeReadback
|
|
? t("states.loading")
|
|
: missingStages.length > 0
|
|
? t("missing", { count: missingStages.length })
|
|
: t("closedDetail")}
|
|
</p>
|
|
</div>
|
|
{metrics.map((metric) => {
|
|
const Icon = metric.icon;
|
|
return (
|
|
<div key={metric.key} className="bg-white px-4 py-3">
|
|
<div className="flex items-start justify-between gap-3">
|
|
<div>
|
|
<p className="text-xs font-semibold text-[#77736a]">{metric.label}</p>
|
|
<div className="mt-2 font-mono text-lg font-semibold text-[#141413]">
|
|
{readbackNumber(metric.value, hasRuntimeReadback)}
|
|
</div>
|
|
</div>
|
|
<Icon className="h-4 w-4 text-[#87867f]" aria-hidden="true" />
|
|
</div>
|
|
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
|
{!hasRuntimeReadback
|
|
? t("states.loading")
|
|
: "caption" in metric && metric.caption
|
|
? metric.caption
|
|
: t("recent", { count: numberValue(metric.recent) })}
|
|
</p>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<div className="grid gap-px border-t border-[#e0ddd4] bg-[#e0ddd4] md:grid-cols-2 xl:grid-cols-6">
|
|
<div className="bg-white px-4 py-3">
|
|
<p className="text-xs font-semibold text-[#77736a]">{t("taxonomy.sources")}</p>
|
|
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
|
{readbackNumber(
|
|
rollups.live_log_active_source_family_count ?? logRollups.active_source_family_count,
|
|
hasRuntimeReadback
|
|
)}
|
|
{" / "}
|
|
{readbackNumber(
|
|
rollups.live_log_source_family_count ?? logRollups.source_family_count,
|
|
hasRuntimeReadback
|
|
)}
|
|
</p>
|
|
</div>
|
|
<div className="bg-white px-4 py-3">
|
|
<p className="text-xs font-semibold text-[#77736a]">{t("taxonomy.products")}</p>
|
|
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
|
{readbackNumber(
|
|
rollups.live_multi_product_taxonomy_contract_ready_count
|
|
?? multiProductRollups.contract_ready_product_scope_count,
|
|
hasRuntimeReadback
|
|
)}
|
|
{" / "}
|
|
{readbackNumber(
|
|
rollups.live_multi_product_taxonomy_product_scope_count
|
|
?? multiProductRollups.product_scope_count,
|
|
hasRuntimeReadback
|
|
)}
|
|
</p>
|
|
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
|
{t("taxonomy.productsDetail", {
|
|
active: readbackNumber(
|
|
rollups.live_multi_product_taxonomy_runtime_adapter_active_count
|
|
?? multiProductRollups.runtime_adapter_active_count,
|
|
hasRuntimeReadback
|
|
),
|
|
missing: readbackNumber(
|
|
rollups.live_multi_product_taxonomy_missing_dimension_count
|
|
?? multiProductRollups.missing_required_dimension_count,
|
|
hasRuntimeReadback
|
|
),
|
|
})}
|
|
</p>
|
|
</div>
|
|
<div className="bg-white px-4 py-3">
|
|
<p className="text-xs font-semibold text-[#77736a]">{t("taxonomy.labels")}</p>
|
|
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
|
{readbackNumber(
|
|
rollups.live_log_label_dimension_count ?? logRollups.label_dimension_count,
|
|
hasRuntimeReadback
|
|
)}
|
|
</p>
|
|
</div>
|
|
<div className="bg-white px-4 py-3">
|
|
<p className="text-xs font-semibold text-[#77736a]">{t("taxonomy.events")}</p>
|
|
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
|
{readbackNumber(
|
|
rollups.live_log_classified_event_total ?? logRollups.classified_event_total,
|
|
hasRuntimeReadback
|
|
)}
|
|
</p>
|
|
</div>
|
|
<div className="bg-white px-4 py-3">
|
|
<p className="text-xs font-semibold text-[#77736a]">{t("taxonomy.learning")}</p>
|
|
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
|
{readbackNumber(logRollups.learning_source_family_count, hasRuntimeReadback)}
|
|
</p>
|
|
</div>
|
|
<div className="bg-white px-4 py-3">
|
|
<p className="text-xs font-semibold text-[#77736a]">{t("taxonomy.workItems")}</p>
|
|
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
|
{readbackNumber(
|
|
rollups.live_work_item_completed_count ?? workItemRollups.completed_count,
|
|
hasRuntimeReadback
|
|
)}
|
|
{" / "}
|
|
{readbackNumber(
|
|
rollups.live_work_item_count ?? workItemRollups.work_item_count,
|
|
hasRuntimeReadback
|
|
)}
|
|
</p>
|
|
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
|
{t("taxonomy.workItemsDetail", {
|
|
active: readbackNumber(
|
|
rollups.live_work_item_in_progress_count ?? workItemRollups.in_progress_count,
|
|
hasRuntimeReadback
|
|
),
|
|
pending: readbackNumber(
|
|
rollups.live_work_item_pending_count ?? workItemRollups.pending_count,
|
|
hasRuntimeReadback
|
|
),
|
|
blocked: readbackNumber(
|
|
rollups.live_work_item_blocked_count ?? workItemRollups.blocked_count,
|
|
hasRuntimeReadback
|
|
),
|
|
})}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{mode === "full" ? (
|
|
<>
|
|
<div className="grid gap-px border-t border-[#e0ddd4] bg-[#e0ddd4] md:grid-cols-3">
|
|
<div className="bg-white px-4 py-3">
|
|
<p className="text-xs font-semibold text-[#77736a]">{t("policy.label")}</p>
|
|
<p className="mt-1 text-sm font-semibold text-[#141413]">{riskText || "--"}</p>
|
|
</div>
|
|
<div className="bg-white px-4 py-3">
|
|
<p className="text-xs font-semibold text-[#77736a]">{t("policy.critical")}</p>
|
|
<p className="mt-1 text-sm font-semibold text-[#141413]">
|
|
{policy?.critical_break_glass_required ? t("policy.breakGlass") : "--"}
|
|
</p>
|
|
</div>
|
|
<div className="bg-white px-4 py-3">
|
|
<p className="text-xs font-semibold text-[#77736a]">{t("nextAction")}</p>
|
|
<p className="mt-1 truncate text-sm font-semibold text-[#141413]">
|
|
{ledger?.next_executor_action ?? "--"}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div id="ai-automation-priority-work-board" className="border-t border-[#e0ddd4] bg-white">
|
|
<div className="grid gap-px bg-[#e0ddd4] lg:grid-cols-[1fr_220px]">
|
|
<div className="bg-white px-4 py-3">
|
|
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
<div className="min-w-0">
|
|
<div className="flex items-center gap-2">
|
|
<SlidersHorizontal className="h-4 w-4 text-[#87867f]" aria-hidden="true" />
|
|
<h4 className="text-sm font-semibold text-[#141413]">{t("workBoard.title")}</h4>
|
|
</div>
|
|
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
|
{t("workBoard.subtitle", {
|
|
ordered: numberValue(orderedWorkTotal),
|
|
sources: numberValue(sourceFamilyTotal),
|
|
})}
|
|
</p>
|
|
</div>
|
|
<div className="min-w-[180px]">
|
|
<div className="flex items-center justify-between gap-3 text-xs font-semibold text-[#5f5b52]">
|
|
<span>{t("workBoard.completedOfTotal", {
|
|
completed: readbackNumber(workCompleted, hasRuntimeReadback),
|
|
total: readbackNumber(workTotal, hasRuntimeReadback),
|
|
})}</span>
|
|
<span className="font-mono text-[#141413]">
|
|
{hasRuntimeReadback ? `${workCompletionPercent}%` : "--"}
|
|
</span>
|
|
</div>
|
|
<div className="mt-2 h-2 border border-[#d8d3c7] bg-[#faf9f3]">
|
|
<div
|
|
className="h-full bg-[#17602a]"
|
|
style={{ width: hasRuntimeReadback ? `${workCompletionPercent}%` : "0%" }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="mt-3 flex flex-wrap gap-2">
|
|
{workFilters.map((filter) => {
|
|
const Icon = filter.icon;
|
|
const selected = workFilter === filter.key;
|
|
return (
|
|
<button
|
|
key={filter.key}
|
|
type="button"
|
|
onClick={() => setWorkFilter(filter.key)}
|
|
className={cn(
|
|
"inline-flex items-center gap-2 border px-3 py-1.5 text-xs font-semibold",
|
|
selected
|
|
? "border-[#141413] bg-[#141413] text-white"
|
|
: "border-[#d8d3c7] bg-white text-[#5f5b52] hover:border-[#d97757] hover:text-[#141413]"
|
|
)}
|
|
aria-pressed={selected}
|
|
>
|
|
<Icon className="h-3.5 w-3.5" aria-hidden="true" />
|
|
<span>{t(`workBoard.filters.${filter.key}` as never)}</span>
|
|
<span className="font-mono">{readbackNumber(filter.count, hasRuntimeReadback)}</span>
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
<div className="bg-white px-4 py-3">
|
|
<p className="text-xs font-semibold text-[#77736a]">{t("workBoard.sourceCoverage")}</p>
|
|
<p className="mt-2 font-mono text-lg font-semibold text-[#141413]">
|
|
{readbackNumber(sourceFamilyTotal, hasRuntimeReadback)}
|
|
</p>
|
|
<p className="mt-1 text-xs leading-5 text-[#5f5b52]">
|
|
{t("workBoard.sourceCoverageDetail")}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="grid gap-px bg-[#e0ddd4]">
|
|
{visibleWorkItems.length > 0 ? visibleWorkItems.map((item) => (
|
|
<div
|
|
key={item.work_item_id ?? item.priority ?? item.title}
|
|
className="grid min-w-0 gap-3 bg-white px-4 py-3 md:grid-cols-[72px_minmax(0,1fr)_148px]"
|
|
>
|
|
<div className="flex items-center gap-2">
|
|
<span className={cn("h-2.5 w-2.5 border", statusToneClass(item.status))} aria-hidden="true" />
|
|
<span className="font-mono text-xs font-semibold text-[#141413]">{item.priority ?? "--"}</span>
|
|
</div>
|
|
<div className="min-w-0">
|
|
<div className="truncate text-sm font-semibold text-[#141413]">{item.title ?? item.work_item_id ?? "--"}</div>
|
|
<div className="mt-1 truncate text-xs text-[#5f5b52]">
|
|
{item.exit_criteria ?? item.next_controlled_action ?? item.work_item_id ?? "--"}
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-wrap items-center justify-start gap-2 md:justify-end">
|
|
<span className={cn("inline-flex border px-2 py-0.5 text-xs font-semibold", statusToneClass(item.status))}>
|
|
{t(`workBoard.statuses.${item.status ?? "unknown"}` as never)}
|
|
</span>
|
|
<span className="font-mono text-xs text-[#77736a]">
|
|
{shortRef(item.work_item_id)}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
)) : (
|
|
<div className="bg-white px-4 py-6 text-sm font-semibold text-[#5f5b52]">
|
|
{hasRuntimeReadback ? t("workBoard.empty") : t("states.loading")}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</>
|
|
) : null}
|
|
</section>
|
|
);
|
|
}
|