feat(web): explain callback trace backlog handling
All checks were successful
CD Pipeline / tests (push) Successful in 1m33s
Code Review / ai-code-review (push) Successful in 14s
CD Pipeline / build-and-deploy (push) Successful in 3m31s
CD Pipeline / post-deploy-checks (push) Successful in 1m23s

This commit is contained in:
Your Name
2026-05-25 22:59:43 +08:00
parent b691367d40
commit fd253bc93c
3 changed files with 102 additions and 9 deletions

View File

@@ -2275,6 +2275,9 @@
"callbackOwnerReviewBlocker": "Blocker: {reason}",
"callbackOwnerReviewEmpty": "Recent callback evidence is matched or no data is available yet",
"callbackTraceRecoveryBacklog": "Callback trace backlog: missing trace {missing}; 1h {recent1h}; 24h {recent24h}; traced after gap {recovered}; recovery {status}",
"callbackTraceRecoveryAction": "Next handling: {action}; human required={human}",
"callbackTraceRecoveryOwner": "Owner: AwoooP Callback Evidence; support: TelegramGateway / Run Timeline",
"callbackTraceRecoveryClosure": "Close when 1h=0 and 24h=0; current 1h {recent1h} / 24h {recent24h}",
"callbackTraceRecoveryDecision": "Decision: {gap}; next: {next}",
"callbackTraceRecoveryLatest": "Last gap: {missing}; recovery first: {first}; recovery latest: {latest}",
"callbackTraceRecoveryUnavailable": "Callback trace recovery summary has not returned yet",
@@ -2310,6 +2313,18 @@
"ownerResponseValidationChecks": "Cross-packet checks={crossPacket}; evidence routing={routing}; display sections={sections}",
"ownerResponseValidationBoundary": "No approval record, no primary switch, and no 執行期閘門"
},
"humanRequired": {
"yes": "yes",
"no": "no"
},
"callbackTraceRecoveryActions": {
"unavailable": "summary did not return; check the callback-replies API first",
"closed": "close criteria are met; retain the historical evidence",
"investigateActiveGap": "new gaps still exist; check new Telegram reply_markup trace writes",
"verifyInstrumentation": "no recovery signal; check TelegramGateway / Timeline instrumentation",
"waitDecay": "wait for the legacy backlog to decay over 24h; no human action needed",
"observeRecovery": "observe the recovery signal before opening a human task"
},
"claim": {
"ready": "Full auto-repair claim: ready",
"notReady": "Full auto-repair claim: not ready",

View File

@@ -2276,6 +2276,9 @@
"callbackOwnerReviewBlocker": "卡點:{reason}",
"callbackOwnerReviewEmpty": "近期 callback evidence 均已匹配或尚無資料",
"callbackTraceRecoveryBacklog": "Callback trace backlog缺 trace {missing}1h {recent1h}24h {recent24h}gap 後 traced {recovered};復原 {status}",
"callbackTraceRecoveryAction": "接續處理:{action};需要人工={human}",
"callbackTraceRecoveryOwner": "主責AwoooP Callback Evidence協作TelegramGateway / Run Timeline",
"callbackTraceRecoveryClosure": "關閉條件1h=0 且 24h=0目前 1h {recent1h} / 24h {recent24h}",
"callbackTraceRecoveryDecision": "判讀:{gap};下一步:{next}",
"callbackTraceRecoveryLatest": "最後缺口:{missing};復原首筆:{first};復原最新:{latest}",
"callbackTraceRecoveryUnavailable": "Callback trace recovery summary 尚未回傳",
@@ -2311,6 +2314,18 @@
"ownerResponseValidationChecks": "跨包驗收={crossPacket};證據路由={routing};顯示區塊={sections}",
"ownerResponseValidationBoundary": "不建立審批紀錄、不切主要來源、不開執行期閘門"
},
"humanRequired": {
"yes": "是",
"no": "否"
},
"callbackTraceRecoveryActions": {
"unavailable": "summary 未回傳,先確認 callback-replies API",
"closed": "已符合關閉條件,保留歷史證據即可",
"investigateActiveGap": "仍有新缺口,檢查新 Telegram reply_markup trace 寫入",
"verifyInstrumentation": "沒有復原訊號,檢查 TelegramGateway / Timeline instrumentation",
"waitDecay": "等待舊 backlog 24h decay不需人工處理",
"observeRecovery": "觀察復原訊號,先不開人工任務"
},
"claim": {
"ready": "完整自動修復聲明:可宣稱",
"notReady": "完整自動修復聲明:不可宣稱",

View File

@@ -848,6 +848,19 @@ type CallbackRepliesWorkItemResponse = {
summary?: CallbackReplyAuditSummary | null;
};
type CallbackTraceRecoveryActionKey =
| "unavailable"
| "closed"
| "investigateActiveGap"
| "verifyInstrumentation"
| "waitDecay"
| "observeRecovery";
type CallbackTraceRecoveryAction = {
actionKey: CallbackTraceRecoveryActionKey;
humanRequired: boolean;
};
type AiRouteRepairEvidence = {
target_resource?: string | null;
access_blockers?: string[];
@@ -1627,24 +1640,54 @@ function callbackOwnerReviewOpenEvents(
function callbackTraceRecoveryStatus(
summary: CallbackReplyAuditSummary | null | undefined
): WorkStatus {
if (!summary) {
return "blocked";
}
const missingTrace = summary.outbound_reply_markup_missing_trace_ref_total ?? 0;
if (missingTrace <= 0) {
const action = callbackTraceRecoveryAction(summary);
if (action.actionKey === "closed") {
return "live";
}
const gapStatus = summary.outbound_reply_markup_trace_ref_gap_status;
const recoveryStatus = summary.outbound_reply_markup_trace_ref_gap_recovery_status;
if (gapStatus === "active_gap" || recoveryStatus === "no_recovery_signal") {
if (
action.actionKey === "investigateActiveGap" ||
action.actionKey === "verifyInstrumentation" ||
action.actionKey === "unavailable"
) {
return "blocked";
}
if (recoveryStatus === "recovered_after_gap") {
if (action.actionKey === "waitDecay") {
return "in_progress";
}
return "watching";
}
function callbackTraceRecoveryAction(
summary: CallbackReplyAuditSummary | null | undefined
): CallbackTraceRecoveryAction {
if (!summary) {
return { actionKey: "unavailable", humanRequired: true };
}
const missingTrace = summary.outbound_reply_markup_missing_trace_ref_total ?? 0;
if (missingTrace <= 0) {
return { actionKey: "closed", humanRequired: false };
}
const recent1h =
summary.outbound_reply_markup_missing_trace_ref_recent_1h_total ?? 0;
const recent24h =
summary.outbound_reply_markup_missing_trace_ref_recent_24h_total ?? 0;
const gapStatus = summary.outbound_reply_markup_trace_ref_gap_status;
const recoveryStatus = summary.outbound_reply_markup_trace_ref_gap_recovery_status;
if (gapStatus === "active_gap" || recent1h > 0) {
return { actionKey: "investigateActiveGap", humanRequired: true };
}
if (recoveryStatus === "no_recovery_signal") {
return { actionKey: "verifyInstrumentation", humanRequired: true };
}
if (recoveryStatus === "recovered_after_gap") {
if (recent24h > 0) {
return { actionKey: "waitDecay", humanRequired: false };
}
return { actionKey: "closed", humanRequired: false };
}
return { actionKey: "observeRecovery", humanRequired: false };
}
function buildWorkItems(
telemetry: Telemetry,
t: ReturnType<typeof useTranslations>
@@ -1679,6 +1722,7 @@ function buildWorkItems(
const latestCallbackWorkItem = latestCallbackSummary?.work_item ?? null;
const latestCallbackTriage = latestCallbackWorkItem?.triage ?? null;
const callbackTraceSummary = telemetry.callbackReplies?.summary ?? null;
const callbackTraceAction = callbackTraceRecoveryAction(callbackTraceSummary);
const aiRoute = telemetry.aiRouteStatus;
const aiRouteRepairEvidence = aiRoute?.repair_evidence ?? null;
const aiRouteWorkItem = aiRouteRepairEvidence?.work_item ?? null;
@@ -2055,6 +2099,25 @@ function buildWorkItems(
}),
evidenceDetails: callbackTraceSummary
? [
t("evidence.callbackTraceRecoveryAction", {
action: t(
`callbackTraceRecoveryActions.${callbackTraceAction.actionKey}` as never
),
human: t(
`humanRequired.${callbackTraceAction.humanRequired ? "yes" : "no"}` as never
),
}),
t("evidence.callbackTraceRecoveryOwner"),
t("evidence.callbackTraceRecoveryClosure", {
recent1h:
callbackTraceSummary
.outbound_reply_markup_missing_trace_ref_recent_1h_total ??
0,
recent24h:
callbackTraceSummary
.outbound_reply_markup_missing_trace_ref_recent_24h_total ??
0,
}),
t("evidence.callbackTraceRecoveryDecision", {
gap:
callbackTraceSummary.outbound_reply_markup_trace_ref_gap_status ??