feat(governance): bind km archive confirm to dry-run fingerprint
All checks were successful
Code Review / ai-code-review (push) Successful in 14s
Type Sync Check / check-type-sync (push) Successful in 31s
CD Pipeline / tests (push) Successful in 4m8s
CD Pipeline / build-and-deploy (push) Successful in 4m48s
CD Pipeline / post-deploy-checks (push) Successful in 2m13s
All checks were successful
Code Review / ai-code-review (push) Successful in 14s
Type Sync Check / check-type-sync (push) Successful in 31s
CD Pipeline / tests (push) Successful in 4m8s
CD Pipeline / build-and-deploy (push) Successful in 4m48s
CD Pipeline / post-deploy-checks (push) Successful in 2m13s
This commit is contained in:
@@ -1929,9 +1929,11 @@
|
||||
"failed": "Archive action failed; refresh and verify the latest dedupe plan.",
|
||||
"previewFailed": "Dry-run preview failed; refresh and verify the latest dedupe plan.",
|
||||
"confirmFailed": "Archive confirmation failed; the backend may have detected a changed dedupe plan.",
|
||||
"missingPreviewFingerprint": "Missing dry-run plan fingerprint; run the preview again first.",
|
||||
"requiresOwner": "Run the dry-run preview first, then owner-confirm the archive; the backend rechecks the latest plan.",
|
||||
"previewResult": "Dry run would archive {count}; writes KM: {writesKm}; writes audit: {writesAudit}",
|
||||
"previewNext": "Next: only after owner confirmation will duplicate KM be soft-archived and audit / stale-ratio recheck rows be written.",
|
||||
"planFingerprint": "Plan fingerprint: {fingerprint}",
|
||||
"result": "Archived {archived}; audit dispatch: {audit}",
|
||||
"recheck": "Stale-ratio recheck: {status}; dispatch: {dispatch}",
|
||||
"snapshot": "Current stale {stale} / total {total}; ratio {ratio}; threshold {threshold}",
|
||||
|
||||
@@ -1930,9 +1930,11 @@
|
||||
"failed": "封存動作失敗;請重新整理後確認最新 dedupe plan。",
|
||||
"previewFailed": "乾跑預覽失敗;請重新整理後確認最新 dedupe plan。",
|
||||
"confirmFailed": "確認封存失敗;後端可能偵測到 dedupe plan 已變更。",
|
||||
"missingPreviewFingerprint": "缺少乾跑 plan fingerprint;請先重新執行乾跑預覽。",
|
||||
"requiresOwner": "必須先乾跑預覽,再由 owner 確認封存;後端會重新比對最新 plan。",
|
||||
"previewResult": "乾跑將封存 {count} 份;寫 KM:{writesKm};寫稽核:{writesAudit}",
|
||||
"previewNext": "下一步:owner 確認後才會 soft archive duplicate KM 並寫入 audit / stale ratio 回測。",
|
||||
"planFingerprint": "Plan fingerprint:{fingerprint}",
|
||||
"result": "已封存 {archived} 份;稽核 dispatch:{audit}",
|
||||
"recheck": "Stale ratio 回測:{status};dispatch:{dispatch}",
|
||||
"snapshot": "目前 stale {stale} / total {total};ratio {ratio};門檻 {threshold}",
|
||||
|
||||
@@ -303,6 +303,7 @@ type KnowledgeReviewDraftArchiveResponse = {
|
||||
| "already_active"
|
||||
| "not_requested";
|
||||
stale_ratio_recheck_dispatch_id?: string | null;
|
||||
dry_run_plan_fingerprint?: string | null;
|
||||
next_action: string;
|
||||
generated_at?: string | null;
|
||||
};
|
||||
@@ -1558,6 +1559,22 @@ function KnowledgeGovernancePanel({
|
||||
}, [t]);
|
||||
|
||||
const confirmArchiveDuplicates = useCallback(async (group: KnowledgeReviewDraftDedupeGroup) => {
|
||||
const dryRunPlanFingerprint =
|
||||
archiveActions[group.governance_event_id]?.previewResult?.dry_run_plan_fingerprint;
|
||||
if (!dryRunPlanFingerprint) {
|
||||
setArchiveActions((current) => ({
|
||||
...current,
|
||||
[group.governance_event_id]: {
|
||||
previewLoading: false,
|
||||
confirmLoading: false,
|
||||
previewResult: current[group.governance_event_id]?.previewResult ?? null,
|
||||
result: null,
|
||||
error: t("archiveActions.missingPreviewFingerprint"),
|
||||
},
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
setArchiveActions((current) => ({
|
||||
...current,
|
||||
[group.governance_event_id]: {
|
||||
@@ -1576,6 +1593,7 @@ function KnowledgeGovernancePanel({
|
||||
owner: "operator_console",
|
||||
owner_approved: true,
|
||||
dry_run: false,
|
||||
dry_run_plan_fingerprint: dryRunPlanFingerprint,
|
||||
},
|
||||
15000
|
||||
);
|
||||
@@ -1592,7 +1610,7 @@ function KnowledgeGovernancePanel({
|
||||
if (result?.status === "archived" || result?.status === "noop_already_archived") {
|
||||
onArchived();
|
||||
}
|
||||
}, [onArchived, t]);
|
||||
}, [archiveActions, onArchived, t]);
|
||||
|
||||
return (
|
||||
<section className="border border-[#e0ddd4] bg-white">
|
||||
@@ -1723,7 +1741,10 @@ function KnowledgeGovernancePanel({
|
||||
const archiveAction = archiveActions[group.governance_event_id];
|
||||
const previewResult = archiveAction?.previewResult ?? null;
|
||||
const finalResult = archiveAction?.result ?? null;
|
||||
const previewReady = previewResult?.status === "dry_run";
|
||||
const previewReady = (
|
||||
previewResult?.status === "dry_run" &&
|
||||
Boolean(previewResult.dry_run_plan_fingerprint)
|
||||
);
|
||||
const previewKey = groupArchiveStatusKey(previewResult?.status);
|
||||
const finalResultKey = groupArchiveStatusKey(finalResult?.status);
|
||||
return (
|
||||
@@ -1824,6 +1845,11 @@ function KnowledgeGovernancePanel({
|
||||
<p className="mt-1 text-[#5f5b52]">
|
||||
{t("archiveActions.previewNext")}
|
||||
</p>
|
||||
<p className="mt-1 break-all font-mono text-[11px] text-[#5f5b52]">
|
||||
{t("archiveActions.planFingerprint", {
|
||||
fingerprint: previewResult.dry_run_plan_fingerprint ?? "--",
|
||||
})}
|
||||
</p>
|
||||
{previewResult.stale_ratio_snapshot ? (
|
||||
<p className="mt-1 text-[#5f5b52]">
|
||||
{t("archiveActions.snapshot", {
|
||||
|
||||
Reference in New Issue
Block a user