create-principles-disciple 1.121.9 → 1.122.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/console/dist/server/index.js +17 -0
  2. package/console/dist/server/models/OwnerDecisionConsoleModel.d.ts +39 -0
  3. package/console/dist/server/models/OwnerDecisionConsoleModel.js +233 -0
  4. package/console/dist/server/models/PrincipleClassifier.d.ts +3 -3
  5. package/console/dist/server/models/PrincipleClassifier.js +12 -5
  6. package/console/dist/server/models/PrinciplesConsoleModel.d.ts +1 -1
  7. package/console/dist/server/models/PrinciplesConsoleModel.js +2 -2
  8. package/console/dist/server/routes/failed-tasks.js +40 -2
  9. package/console/dist/server/routes/owner-decisions.d.ts +25 -0
  10. package/console/dist/server/routes/owner-decisions.js +186 -0
  11. package/console/dist/server/routes/principles.js +15 -7
  12. package/console/dist/server/routes/update.js +82 -14
  13. package/console/dist/server/utils/update-links.d.ts +38 -0
  14. package/console/dist/server/utils/update-links.js +71 -0
  15. package/console/dist/ui/api.d.ts +12 -1
  16. package/console/dist/ui/api.js +9 -2
  17. package/console/dist/ui/components/notifications/NotificationProvider.js +8 -2
  18. package/console/dist/ui/i18n/en.json +33 -1
  19. package/console/dist/ui/i18n/zh-CN.json +33 -1
  20. package/console/dist/ui/pages/failed-tasks/FailedTasksPage.js +5 -1
  21. package/console/dist/ui/pages/focus/FocusPage.js +19 -2
  22. package/console/dist/ui/pages/focus/OwnerDecisionCard.d.ts +6 -0
  23. package/console/dist/ui/pages/focus/OwnerDecisionCard.js +86 -0
  24. package/console/dist/ui/pages/principles/PrinciplesPage.js +11 -5
  25. package/console/dist/ui/utils/validators.d.ts +37 -0
  26. package/console/dist/ui/utils/validators.js +123 -0
  27. package/console/dist/web/assets/app.css +11 -0
  28. package/console/dist/web/assets/app.js +2740 -2350
  29. package/core/dist/runtime-v2/__tests__/evaluator-repair-loop.test.js +20 -0
  30. package/core/dist/runtime-v2/__tests__/evaluator-repair-loop.test.js.map +1 -1
  31. package/core/dist/runtime-v2/__tests__/rollout-reviewer-verdict-paths.test.js +26 -5
  32. package/core/dist/runtime-v2/__tests__/rollout-reviewer-verdict-paths.test.js.map +1 -1
  33. package/core/dist/runtime-v2/index.d.ts +7 -1
  34. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  35. package/core/dist/runtime-v2/index.js +4 -0
  36. package/core/dist/runtime-v2/index.js.map +1 -1
  37. package/core/dist/runtime-v2/internalization/__tests__/evaluator-prompt-builder.test.js +1 -1
  38. package/core/dist/runtime-v2/internalization/__tests__/internalization-transition-decision.test.js +15 -14
  39. package/core/dist/runtime-v2/internalization/__tests__/internalization-transition-decision.test.js.map +1 -1
  40. package/core/dist/runtime-v2/internalization/__tests__/owner-decision-architecture.test.d.ts +2 -0
  41. package/core/dist/runtime-v2/internalization/__tests__/owner-decision-architecture.test.d.ts.map +1 -0
  42. package/core/dist/runtime-v2/internalization/__tests__/owner-decision-architecture.test.js +56 -0
  43. package/core/dist/runtime-v2/internalization/__tests__/owner-decision-architecture.test.js.map +1 -0
  44. package/core/dist/runtime-v2/internalization/__tests__/owner-decision.test.d.ts +2 -0
  45. package/core/dist/runtime-v2/internalization/__tests__/owner-decision.test.d.ts.map +1 -0
  46. package/core/dist/runtime-v2/internalization/__tests__/owner-decision.test.js +883 -0
  47. package/core/dist/runtime-v2/internalization/__tests__/owner-decision.test.js.map +1 -0
  48. package/core/dist/runtime-v2/internalization/__tests__/owner-override-resume.test.d.ts +2 -0
  49. package/core/dist/runtime-v2/internalization/__tests__/owner-override-resume.test.d.ts.map +1 -0
  50. package/core/dist/runtime-v2/internalization/__tests__/owner-override-resume.test.js +328 -0
  51. package/core/dist/runtime-v2/internalization/__tests__/owner-override-resume.test.js.map +1 -0
  52. package/core/dist/runtime-v2/internalization/evaluator-output.d.ts +63 -2
  53. package/core/dist/runtime-v2/internalization/evaluator-output.d.ts.map +1 -1
  54. package/core/dist/runtime-v2/internalization/evaluator-output.js +139 -2
  55. package/core/dist/runtime-v2/internalization/evaluator-output.js.map +1 -1
  56. package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.d.ts +54 -2
  57. package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.d.ts.map +1 -1
  58. package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.js +49 -2
  59. package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.js.map +1 -1
  60. package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts +34 -0
  61. package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
  62. package/core/dist/runtime-v2/internalization/evaluator-runner.js +295 -12
  63. package/core/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
  64. package/core/dist/runtime-v2/internalization/internalization-orchestrator.d.ts.map +1 -1
  65. package/core/dist/runtime-v2/internalization/internalization-orchestrator.js +10 -54
  66. package/core/dist/runtime-v2/internalization/internalization-orchestrator.js.map +1 -1
  67. package/core/dist/runtime-v2/internalization/internalization-transition-decision.d.ts +7 -1
  68. package/core/dist/runtime-v2/internalization/internalization-transition-decision.d.ts.map +1 -1
  69. package/core/dist/runtime-v2/internalization/internalization-transition-decision.js +9 -2
  70. package/core/dist/runtime-v2/internalization/internalization-transition-decision.js.map +1 -1
  71. package/core/dist/runtime-v2/internalization/owner-resolution-service.d.ts +89 -0
  72. package/core/dist/runtime-v2/internalization/owner-resolution-service.d.ts.map +1 -0
  73. package/core/dist/runtime-v2/internalization/owner-resolution-service.js +272 -0
  74. package/core/dist/runtime-v2/internalization/owner-resolution-service.js.map +1 -0
  75. package/core/dist/runtime-v2/internalization/owner-retry.d.ts +12 -0
  76. package/core/dist/runtime-v2/internalization/owner-retry.d.ts.map +1 -1
  77. package/core/dist/runtime-v2/internalization/owner-retry.js +23 -0
  78. package/core/dist/runtime-v2/internalization/owner-retry.js.map +1 -1
  79. package/core/dist/runtime-v2/internalization/owner-review.d.ts +195 -0
  80. package/core/dist/runtime-v2/internalization/owner-review.d.ts.map +1 -0
  81. package/core/dist/runtime-v2/internalization/owner-review.js +470 -0
  82. package/core/dist/runtime-v2/internalization/owner-review.js.map +1 -0
  83. package/core/dist/runtime-v2/internalization/peer-runner-contracts.d.ts +5 -1
  84. package/core/dist/runtime-v2/internalization/peer-runner-contracts.d.ts.map +1 -1
  85. package/core/dist/runtime-v2/internalization/peer-runner-contracts.js.map +1 -1
  86. package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts +68 -0
  87. package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts.map +1 -1
  88. package/core/dist/runtime-v2/internalization/pitask-metadata.js +104 -0
  89. package/core/dist/runtime-v2/internalization/pitask-metadata.js.map +1 -1
  90. package/core/dist/runtime-v2/internalization/revision-reopen.d.ts +56 -0
  91. package/core/dist/runtime-v2/internalization/revision-reopen.d.ts.map +1 -0
  92. package/core/dist/runtime-v2/internalization/revision-reopen.js +144 -0
  93. package/core/dist/runtime-v2/internalization/revision-reopen.js.map +1 -0
  94. package/core/dist/runtime-v2/internalization/rollout-reviewer-runner.d.ts +12 -0
  95. package/core/dist/runtime-v2/internalization/rollout-reviewer-runner.d.ts.map +1 -1
  96. package/core/dist/runtime-v2/internalization/rollout-reviewer-runner.js +145 -14
  97. package/core/dist/runtime-v2/internalization/rollout-reviewer-runner.js.map +1 -1
  98. package/core/dist/runtime-v2/store/context/sqlite-context-assembler.test.js +1 -0
  99. package/core/dist/runtime-v2/store/context/sqlite-context-assembler.test.js.map +1 -1
  100. package/core/dist/runtime-v2/store/runtime-state-manager.d.ts +6 -0
  101. package/core/dist/runtime-v2/store/runtime-state-manager.d.ts.map +1 -1
  102. package/core/dist/runtime-v2/store/runtime-state-manager.js +9 -0
  103. package/core/dist/runtime-v2/store/runtime-state-manager.js.map +1 -1
  104. package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store-cas.test.d.ts +2 -0
  105. package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store-cas.test.d.ts.map +1 -0
  106. package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store-cas.test.js +78 -0
  107. package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store-cas.test.js.map +1 -0
  108. package/core/dist/runtime-v2/store/task/memory-task-store.d.ts +1 -0
  109. package/core/dist/runtime-v2/store/task/memory-task-store.d.ts.map +1 -1
  110. package/core/dist/runtime-v2/store/task/memory-task-store.js +8 -0
  111. package/core/dist/runtime-v2/store/task/memory-task-store.js.map +1 -1
  112. package/core/dist/runtime-v2/store/task/sqlite-task-store.d.ts +1 -0
  113. package/core/dist/runtime-v2/store/task/sqlite-task-store.d.ts.map +1 -1
  114. package/core/dist/runtime-v2/store/task/sqlite-task-store.js +52 -0
  115. package/core/dist/runtime-v2/store/task/sqlite-task-store.js.map +1 -1
  116. package/core/dist/runtime-v2/store/task/task-store.d.ts +9 -0
  117. package/core/dist/runtime-v2/store/task/task-store.d.ts.map +1 -1
  118. package/core/dist/runtime-v2/store/workspace-isolation.test.js +1 -0
  119. package/core/dist/runtime-v2/store/workspace-isolation.test.js.map +1 -1
  120. package/core/package.json +1 -1
  121. package/host-runtime/package.json +1 -1
  122. package/install-layout/package.json +3 -7
  123. package/package.json +2 -2
  124. package/pd-cli/dist/commands/runtime-internalization-retry.d.ts.map +1 -1
  125. package/pd-cli/dist/commands/runtime-internalization-retry.js +14 -0
  126. package/pd-cli/dist/commands/runtime-internalization-retry.js.map +1 -1
  127. package/pd-cli/package.json +1 -1
  128. package/plugin/dist/bundle.js +580 -569
  129. package/plugin/dist/governance-audit.js +153 -153
  130. package/plugin/dist/openclaw.plugin.json +1 -1
  131. package/plugin/dist/rulehost-evidence.js +180 -180
  132. package/plugin/openclaw.plugin.json +1 -1
  133. package/plugin/package.json +1 -1
@@ -260,7 +260,36 @@
260
260
  },
261
261
  "zeroStateHealthy": "No items need your judgment right now. PD has checked behavior evidence, principle review queue, and system signals.",
262
262
  "zeroStateDbMissing": "PD has not run in this workspace yet. Once the state database is initialized, governance data will appear here.",
263
- "evidenceInProgress": "{{count}} behavior evidence item(s) recorded, being diagnosed and processed."
263
+ "evidenceInProgress": "{{count}} behavior evidence item(s) recorded, being diagnosed and processed.",
264
+ "ownerDecision": {
265
+ "sectionTitle": "Needs your decision",
266
+ "empty": "Nothing needs your decision right now. Problems the machine can solve on its own will not disturb you.",
267
+ "unavailable": "(unavailable)",
268
+ "loadError": "The decision list is temporarily unavailable — the governance summary is still shown.",
269
+ "kindEvaluator": "Evaluator review",
270
+ "kindRollout": "Rollout review",
271
+ "kindApproval": "Deployment approval",
272
+ "kindRulecode": "RuleCode decision",
273
+ "legacyBadge": "Inferred from history",
274
+ "machineRecommendationLabel": "Machine recommendation",
275
+ "rolloutSafetyNote": "Accept this review and continue. High-risk rules still require an independent deployment approval.",
276
+ "acceptCurrent": "Accept current version",
277
+ "reviseOnce": "Revise once more",
278
+ "rejectCurrent": "Reject",
279
+ "instructionLabel": "Revision guidance (optional, one sentence)",
280
+ "instructionPlaceholder": "e.g. Do not add new tool-naming requirements; only address the unresolved items from the last round.",
281
+ "instructionRequired": "Fill in the revision guidance, or collapse the input and submit directly.",
282
+ "actionConsequence": "Accept = continue with the current version (the machine verdict is preserved permanently); Revise once = authorize one extra revision round (automatic budget unchanged); Reject = terminate this evolution.",
283
+ "advanced": "Advanced diagnostics",
284
+ "resolved": "Resolution recorded.",
285
+ "staleError": "The facts of this item changed (a new evaluation may exist). Your decision was NOT applied — refresh and decide again.",
286
+ "alreadyResolved": "This decision was already handled; no repeat action needed.",
287
+ "actionFailed": "Action failed, please retry later.",
288
+ "approvalHint": "The deployment approval for this principle is still waiting in the approval queue.",
289
+ "rulecodeHint": "This rule is in shadow activation and needs a decision in activation management.",
290
+ "goApprovalsCta": "Go to deployment approvals",
291
+ "goActivationCta": "Go to activation management"
292
+ }
264
293
  },
265
294
  "pain": {
266
295
  "eyebrow": "Behavior Evidence",
@@ -477,6 +506,7 @@
477
506
  "statusApproved": "Approved",
478
507
  "statusRejected": "Rejected",
479
508
  "statusParked": "Parked",
509
+ "statusCandidate": "Internalizing",
480
510
  "emptyTitle": "No principles to review",
481
511
  "emptyDescription": "When PD captures behavior deviation signals, principle candidates will appear here for your review.",
482
512
  "emptyActionable": "No owner-actionable principles at this time. When PD captures behavior deviation signals, principle candidates will appear here for your review. You can check the Behavior Evidence page to see if PD is actively collecting signals.",
@@ -1576,6 +1606,8 @@
1576
1606
  "recoverConfirmButton": "Recover",
1577
1607
  "recoverSuccess": "Recovery accepted — the task is pending again",
1578
1608
  "recoverFailed": "Recovery failed",
1609
+ "awaitingOwnerDecision": "Awaiting owner decision",
1610
+ "goGovernanceFocus": "Go to governance focus",
1579
1611
  "taskId": "Task ID",
1580
1612
  "painId": "Pain ID",
1581
1613
  "kind": "Kind",
@@ -260,7 +260,36 @@
260
260
  },
261
261
  "zeroStateHealthy": "当前没有需要你判断的事项。PD 已检查行为证据、原则审查队列和系统信号。",
262
262
  "zeroStateDbMissing": "PD 尚未在此工作空间中运行。状态数据库初始化后,治理数据将在这里呈现。",
263
- "evidenceInProgress": "{{count}} 条行为证据已记录,正在诊断和处理中。"
263
+ "evidenceInProgress": "{{count}} 条行为证据已记录,正在诊断和处理中。",
264
+ "ownerDecision": {
265
+ "sectionTitle": "需要你决定",
266
+ "empty": "现在没有需要你决定的事项。机器能自己解决的问题不会打扰你。",
267
+ "unavailable": "(暂不可用)",
268
+ "loadError": "决策列表暂时不可用——治理摘要仍可查看。",
269
+ "kindEvaluator": "Evaluator 评审",
270
+ "kindRollout": "Rollout 评审",
271
+ "kindApproval": "部署审批",
272
+ "kindRulecode": "RuleCode 决策",
273
+ "legacyBadge": "历史数据推断",
274
+ "machineRecommendationLabel": "机器建议",
275
+ "rolloutSafetyNote": "接受当前评审并继续。高风险规则仍需经过独立部署审批。",
276
+ "acceptCurrent": "接受当前版本",
277
+ "reviseOnce": "再修改一次",
278
+ "rejectCurrent": "拒绝",
279
+ "instructionLabel": "修订指导(可选,一句话)",
280
+ "instructionPlaceholder": "例如:不要增加新的工具命名要求,只处理上一轮未解决问题。",
281
+ "instructionRequired": "请填写修订指导,或收起输入后直接提交。",
282
+ "actionConsequence": "接受 = 按当前版本继续(机器原判定永久保留);再修改一次 = 授权额外一轮修订(自动预算不变);拒绝 = 终止本条演化。",
283
+ "advanced": "高级诊断",
284
+ "resolved": "裁决已记录。",
285
+ "staleError": "该事项的事实已变化(可能有新的评估结果)。未执行你的决定,请刷新后重新裁决。",
286
+ "alreadyResolved": "该决策已被处理过,无需重复操作。",
287
+ "actionFailed": "操作失败,请稍后重试。",
288
+ "approvalHint": "该原则的部署审批仍在审批队列中等待处理。",
289
+ "rulecodeHint": "该规则处于影子激活期,需要在激活管理中裁决。",
290
+ "goApprovalsCta": "前往部署审批",
291
+ "goActivationCta": "前往激活管理"
292
+ }
264
293
  },
265
294
  "pain": {
266
295
  "eyebrow": "行为证据",
@@ -477,6 +506,7 @@
477
506
  "statusApproved": "已批准",
478
507
  "statusRejected": "已拒绝",
479
508
  "statusParked": "已暂存",
509
+ "statusCandidate": "内化中",
480
510
  "emptyTitle": "还没有可审查原则",
481
511
  "emptyDescription": "当 PD 捕获到行为偏差信号时,会在这里生成原则候选,等待你审查。",
482
512
  "emptyActionable": "当前没有待决策的原则。当 PD 捕获到行为偏差信号时,原则候选会出现在这里。你可以前往行为证据页查看 PD 是否正在收集信号。",
@@ -1576,6 +1606,8 @@
1576
1606
  "recoverConfirmButton": "恢复",
1577
1607
  "recoverSuccess": "恢复已接受——任务已重新进入待处理状态",
1578
1608
  "recoverFailed": "恢复失败",
1609
+ "awaitingOwnerDecision": "等待拥有者决策",
1610
+ "goGovernanceFocus": "前往治理焦点",
1579
1611
  "taskId": "任务 ID",
1580
1612
  "painId": "Pain ID",
1581
1613
  "kind": "类型",
@@ -88,6 +88,9 @@ function validateTask(v) {
88
88
  const painId = readNullableString(v, "painId");
89
89
  const lastError = readNullableString(v, "lastError");
90
90
  const lastAttemptAt = readNullableString(v, "lastAttemptAt");
91
+ const ownerDecisionRequired = Object.hasOwn(v, "ownerDecisionRequired")
92
+ ? v.ownerDecisionRequired === true
93
+ : undefined;
91
94
  return {
92
95
  taskId,
93
96
  taskKind,
@@ -98,6 +101,7 @@ function validateTask(v) {
98
101
  maxAttempts,
99
102
  createdAt,
100
103
  lastAttemptAt,
104
+ ...(ownerDecisionRequired !== undefined ? { ownerDecisionRequired } : {}),
101
105
  };
102
106
  }
103
107
  function validateFailedTasksData(v) {
@@ -318,5 +322,5 @@ function LoadedContent({ data, onCreateDraft, onRecover, t }) {
318
322
  .replace("{total}", String(data.total)) }))] })] }));
319
323
  }
320
324
  function TaskTable({ tasks, onCreateDraft, onRecover, t }) {
321
- return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_minmax(0,1fr)_auto_minmax(0,1fr)_auto] gap-3 pb-2 border-b border-line font-mono text-[10px] uppercase tracking-[0.08em] text-ink-4", children: [_jsx("span", { children: t("pages.failedTasks.taskId") }), _jsx("span", { children: t("pages.failedTasks.painId") }), _jsx("span", { children: t("pages.failedTasks.status") }), _jsx("span", { children: t("pages.failedTasks.lastError") }), _jsx("span", { children: t("pages.failedTasks.attempts") }), _jsx("span", { children: t("pages.failedTasks.lastAttempt") }), _jsx("span", { "aria-hidden": "true" })] }), tasks.map((task) => (_jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_minmax(0,1fr)_auto_minmax(0,1fr)_auto] gap-3 py-2 items-center text-[13px] border-b border-line/50 last:border-b-0", children: [_jsx("span", { className: "font-mono text-ink-2 truncate", title: task.taskId, children: truncateId(task.taskId) }), _jsx("span", { className: "font-mono text-ink-3 truncate", title: task.painId ?? "", children: task.painId ? truncateId(task.painId) : t("pages.failedTasks.noPainId") }), _jsx(Badge, { variant: statusToVariant(task.status), children: task.status }), _jsx("span", { className: "text-ink-3 truncate", title: task.lastError ?? "", children: task.lastError ?? "—" }), _jsx("span", { className: "font-mono text-ink-2 text-center", children: task.attemptCount }), _jsx("span", { className: "font-mono text-ink-3 text-[12px]", children: task.lastAttemptAt ? formatDate(task.lastAttemptAt) : "—" }), onRecover && (_jsx(Button, { variant: "default", size: "sm", onClick: () => onRecover(task), className: "whitespace-nowrap", children: t("pages.failedTasks.recover") })), _jsx(Button, { variant: "outline", size: "sm", onClick: () => onCreateDraft(task), className: "whitespace-nowrap", children: t("pages.failedTasks.createDraft") })] }, task.taskId)))] }));
325
+ return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_minmax(0,1fr)_auto_minmax(0,1fr)_auto] gap-3 pb-2 border-b border-line font-mono text-[10px] uppercase tracking-[0.08em] text-ink-4", children: [_jsx("span", { children: t("pages.failedTasks.taskId") }), _jsx("span", { children: t("pages.failedTasks.painId") }), _jsx("span", { children: t("pages.failedTasks.status") }), _jsx("span", { children: t("pages.failedTasks.lastError") }), _jsx("span", { children: t("pages.failedTasks.attempts") }), _jsx("span", { children: t("pages.failedTasks.lastAttempt") }), _jsx("span", { "aria-hidden": "true" })] }), tasks.map((task) => (_jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_minmax(0,1fr)_auto_minmax(0,1fr)_auto] gap-3 py-2 items-center text-[13px] border-b border-line/50 last:border-b-0", children: [_jsx("span", { className: "font-mono text-ink-2 truncate", title: task.taskId, children: truncateId(task.taskId) }), _jsx("span", { className: "font-mono text-ink-3 truncate", title: task.painId ?? "", children: task.painId ? truncateId(task.painId) : t("pages.failedTasks.noPainId") }), _jsx(Badge, { variant: statusToVariant(task.status), children: task.status }), _jsx("span", { className: "text-ink-3 truncate", title: task.lastError ?? "", children: task.lastError ?? "—" }), _jsx("span", { className: "font-mono text-ink-2 text-center", children: task.attemptCount }), _jsx("span", { className: "font-mono text-ink-3 text-[12px]", children: task.lastAttemptAt ? formatDate(task.lastAttemptAt) : "—" }), task.ownerDecisionRequired === true ? (_jsxs("span", { className: "whitespace-nowrap text-[12px]", children: [_jsx("span", { className: "text-amber", children: t("pages.failedTasks.awaitingOwnerDecision") }), " ", _jsx("a", { href: "#/focus", className: "text-gov underline underline-offset-2 hover:text-gov/80", "data-testid": `go-focus-${task.taskId}`, children: t("pages.failedTasks.goGovernanceFocus") })] })) : onRecover ? (_jsx(Button, { variant: "default", size: "sm", onClick: () => onRecover(task), className: "whitespace-nowrap", children: t("pages.failedTasks.recover") })) : null, _jsx(Button, { variant: "outline", size: "sm", onClick: () => onCreateDraft(task), className: "whitespace-nowrap", children: t("pages.failedTasks.createDraft") })] }, task.taskId)))] }));
322
326
  }
@@ -8,7 +8,8 @@ import { PageLoading } from "../../components/layout/page-loading.js";
8
8
  import { SectionTitle } from "../../components/layout/section-title.js";
9
9
  import { DailyThoughtCard } from "../../components/focus/daily-thought-card.js";
10
10
  import { ShinyText } from "../../components/ui/shiny-text.js";
11
- import { fetchGovernanceQueue, fetchApprovalsGrouped, approveApproval, rejectApproval, editApproval, fetchAllActivations, } from "../../api.js";
11
+ import { fetchGovernanceQueue, fetchApprovalsGrouped, approveApproval, rejectApproval, editApproval, fetchAllActivations, fetchOwnerDecisions, } from "../../api.js";
12
+ import { OwnerDecisionCard } from "./OwnerDecisionCard.js";
12
13
  import { fetchGovernanceExperience } from "../../api.js";
13
14
  export function summarizeDecisionResults(results) {
14
15
  const failures = results.filter((result) => !result.success);
@@ -458,6 +459,9 @@ export function FocusPage({ featureFlags }) {
458
459
  const [groupedErrorReason, setGroupedErrorReason] = useState(null);
459
460
  const [ruleCodeItems, setRuleCodeItems] = useState([]);
460
461
  const [ruleCodeErrorReason, setRuleCodeErrorReason] = useState(null);
462
+ // PRI-629: 统一 Owner Inbox — 两种模式都加载 (决策与治理摘要模式正交)
463
+ const [ownerDecisionItems, setOwnerDecisionItems] = useState([]);
464
+ const [ownerDecisionError, setOwnerDecisionError] = useState(null);
461
465
  const loadData = useCallback(async () => {
462
466
  setLoadingState("loading");
463
467
  setErrorMessage(null);
@@ -507,6 +511,17 @@ export function FocusPage({ featureFlags }) {
507
511
  setRuleCodeItems([]);
508
512
  setRuleCodeErrorReason(activationsResult.error);
509
513
  }
514
+ // PRI-629: 统一 Owner Inbox (decision-capable NHR + approvals + rulecode)。
515
+ // 投影失败不阻塞页面 (rc-9 降级 — 显示原因,治理摘要仍可用)。
516
+ const decisionsResult = await fetchOwnerDecisions();
517
+ if (decisionsResult.success) {
518
+ setOwnerDecisionItems(decisionsResult.data.items);
519
+ setOwnerDecisionError(null);
520
+ }
521
+ else {
522
+ setOwnerDecisionItems([]);
523
+ setOwnerDecisionError(decisionsResult.error ?? "Owner decisions unavailable");
524
+ }
510
525
  setLoadingState("loaded");
511
526
  }, [experienceMode, t]);
512
527
  useEffect(() => {
@@ -551,7 +566,9 @@ export function FocusPage({ featureFlags }) {
551
566
  ? "bg-amber/10 text-amber border border-amber/20"
552
567
  : governanceState === "in_progress"
553
568
  ? "bg-green/10 text-green border border-green/20"
554
- : "text-ink-4 border border-line bg-surface/80"}`, role: "status", children: t(`pages.focus.stateLabel.${governanceState}`) }) }), _jsx("div", { className: "text-ink-2 text-[13px] leading-relaxed mt-1", children: stateReason }), _jsxs("div", { className: "text-ink-4 text-[13px] leading-relaxed mt-1", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.nextActionLabel") }), " ", nextAction] })] })) : null, !experienceMode && (_jsxs(_Fragment, { children: [_jsx(ProseSummary, { pendingCount: pendingCount, deviationCount: deviationCount, stagnationCount: stagnationCount, evidenceCount: evidenceCount }), _jsx(FeedbackStratification, { gateBlocksToday: gateBlocksToday, inProgressCount: evidenceCount, pendingCount: pendingCount }), !experienceMode && governanceState === "none" && pendingCount === 0 && deviationCount === 0 && stagnationCount === 0 && (stateReasonCode === "state_db_missing" ? (_jsx(ZeroStateDbMissing, {})) : (_jsxs(_Fragment, { children: [_jsx(ZeroStateHealthy, {}), _jsx("div", { className: "mt-4", children: _jsx(OnboardingGuide, {}) })] }))), governanceState === "in_progress" && inProgressSummary && (_jsx(InProgressGuide, { summary: inProgressSummary })), degradedSignals && degradedSignals.length > 0 && (_jsx(DegradedSummary, { signals: degradedSignals }))] })), _jsx(DailyThoughtCard, {}), experienceMode && experienceData !== null && experienceData.summary.primaryAttention === "all_clear" && pendingGroups.length === 0 && (_jsx("div", { className: "mt-4", children: _jsx(OnboardingGuide, {}) })), (ruleCodeErrorReason || ruleCodePending.length > 0 || ruleCodeAlerts.length > 0) && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-rulecode-owner", children: [_jsx(SectionTitle, { id: "section-rulecode-owner", children: t("pages.focus.ruleCodeOwnerQueue") }), ruleCodeErrorReason && (_jsxs("div", { className: "mb-3 rounded border border-amber/30 bg-panel p-4 text-[12px] text-ink-3", children: [_jsx("div", { className: "font-medium text-amber", children: t("pages.focus.ruleCodeUnavailable") }), _jsx("div", { className: "mt-1 font-mono", children: ruleCodeErrorReason }), _jsx("div", { className: "mt-1", children: t("pages.focus.ruleCodeUnavailableNextAction") })] })), _jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [ruleCodePending.length > 0 && (_jsxs(Link, { to: "/activation", className: "rounded border border-gov/30 bg-panel p-4 hover:border-gov", children: [_jsx("div", { className: "font-medium text-ink", children: t("pages.focus.ruleCodePending") }), _jsx("div", { className: "mt-1 text-[12px] text-ink-3", children: t("pages.focus.ruleCodePendingCount", { count: ruleCodePending.length }) })] })), ruleCodeAlerts.length > 0 && (_jsxs(Link, { to: "/activation", className: "rounded border border-danger/30 bg-panel p-4 hover:border-danger", children: [_jsx("div", { className: "font-medium text-danger", children: t("pages.focus.ruleCodeAlerts") }), _jsx("div", { className: "mt-1 text-[12px] text-ink-3", children: t("pages.focus.ruleCodeAlertCount", { count: ruleCodeAlerts.length }) })] }))] })] })), _jsxs("section", { className: "mt-8", "aria-labelledby": "section-pending", children: [_jsx(SectionTitle, { id: "section-pending", children: t("pages.focus.sectionPending") }), pendingGroups.length > 0 ? (_jsx("div", { className: "space-y-[14px]", children: pendingGroups.map((group) => (_jsx(PendingReviewCard, { group: group, onDecisionApplied: loadData }, group.principleId))) })) : (_jsx("div", { className: "text-ink-3 text-[13px] leading-relaxed py-3", children: approvalDataUnavailable
569
+ : "text-ink-4 border border-line bg-surface/80"}`, role: "status", children: t(`pages.focus.stateLabel.${governanceState}`) }) }), _jsx("div", { className: "text-ink-2 text-[13px] leading-relaxed mt-1", children: stateReason }), _jsxs("div", { className: "text-ink-4 text-[13px] leading-relaxed mt-1", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.nextActionLabel") }), " ", nextAction] })] })) : null, _jsxs("section", { "aria-label": t("pages.focus.ownerDecision.sectionTitle"), className: "mb-7", "data-testid": "owner-decisions-section", children: [_jsxs("div", { className: "flex items-baseline gap-2 mb-3", children: [_jsx(SectionTitle, { children: t("pages.focus.ownerDecision.sectionTitle") }), _jsx("span", { className: "font-mono text-ink-4 text-[12px]", children: ownerDecisionError !== null
570
+ ? t("pages.focus.ownerDecision.unavailable")
571
+ : `· ${ownerDecisionItems.length}` })] }), ownerDecisionError !== null && (_jsx("p", { className: "text-ink-4 text-[12.5px]", children: t("pages.focus.ownerDecision.loadError") })), ownerDecisionError === null && ownerDecisionItems.length === 0 && (_jsx("p", { className: "text-ink-4 text-[13px]", children: t("pages.focus.ownerDecision.empty") })), ownerDecisionItems.map((item) => (_jsx(OwnerDecisionCard, { item: item, onResolved: () => { void loadData(); } }, item.reviewKey)))] }), !experienceMode && (_jsxs(_Fragment, { children: [_jsx(ProseSummary, { pendingCount: pendingCount, deviationCount: deviationCount, stagnationCount: stagnationCount, evidenceCount: evidenceCount }), _jsx(FeedbackStratification, { gateBlocksToday: gateBlocksToday, inProgressCount: evidenceCount, pendingCount: pendingCount }), !experienceMode && governanceState === "none" && pendingCount === 0 && deviationCount === 0 && stagnationCount === 0 && (stateReasonCode === "state_db_missing" ? (_jsx(ZeroStateDbMissing, {})) : (_jsxs(_Fragment, { children: [_jsx(ZeroStateHealthy, {}), _jsx("div", { className: "mt-4", children: _jsx(OnboardingGuide, {}) })] }))), governanceState === "in_progress" && inProgressSummary && (_jsx(InProgressGuide, { summary: inProgressSummary })), degradedSignals && degradedSignals.length > 0 && (_jsx(DegradedSummary, { signals: degradedSignals }))] })), _jsx(DailyThoughtCard, {}), experienceMode && experienceData !== null && experienceData.summary.primaryAttention === "all_clear" && pendingGroups.length === 0 && (_jsx("div", { className: "mt-4", children: _jsx(OnboardingGuide, {}) })), (ruleCodeErrorReason || ruleCodePending.length > 0 || ruleCodeAlerts.length > 0) && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-rulecode-owner", children: [_jsx(SectionTitle, { id: "section-rulecode-owner", children: t("pages.focus.ruleCodeOwnerQueue") }), ruleCodeErrorReason && (_jsxs("div", { className: "mb-3 rounded border border-amber/30 bg-panel p-4 text-[12px] text-ink-3", children: [_jsx("div", { className: "font-medium text-amber", children: t("pages.focus.ruleCodeUnavailable") }), _jsx("div", { className: "mt-1 font-mono", children: ruleCodeErrorReason }), _jsx("div", { className: "mt-1", children: t("pages.focus.ruleCodeUnavailableNextAction") })] })), _jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [ruleCodePending.length > 0 && (_jsxs(Link, { to: "/activation", className: "rounded border border-gov/30 bg-panel p-4 hover:border-gov", children: [_jsx("div", { className: "font-medium text-ink", children: t("pages.focus.ruleCodePending") }), _jsx("div", { className: "mt-1 text-[12px] text-ink-3", children: t("pages.focus.ruleCodePendingCount", { count: ruleCodePending.length }) })] })), ruleCodeAlerts.length > 0 && (_jsxs(Link, { to: "/activation", className: "rounded border border-danger/30 bg-panel p-4 hover:border-danger", children: [_jsx("div", { className: "font-medium text-danger", children: t("pages.focus.ruleCodeAlerts") }), _jsx("div", { className: "mt-1 text-[12px] text-ink-3", children: t("pages.focus.ruleCodeAlertCount", { count: ruleCodeAlerts.length }) })] }))] })] })), _jsxs("section", { id: "approval-queue-section", className: "mt-8", "aria-labelledby": "section-pending", children: [_jsx(SectionTitle, { id: "section-pending", children: t("pages.focus.sectionPending") }), pendingGroups.length > 0 ? (_jsx("div", { className: "space-y-[14px]", children: pendingGroups.map((group) => (_jsx(PendingReviewCard, { group: group, onDecisionApplied: loadData }, group.principleId))) })) : (_jsx("div", { className: "text-ink-3 text-[13px] leading-relaxed py-3", children: approvalDataUnavailable
555
572
  ? (groupedErrorReason
556
573
  ? `${t("pages.focus.loadError")} (${groupedErrorReason})`
557
574
  : t("pages.focus.loadError"))
@@ -0,0 +1,6 @@
1
+ import type { OwnerDecisionItemData } from "../../utils/validators.js";
2
+ export interface OwnerDecisionCardProps {
3
+ item: OwnerDecisionItemData;
4
+ onResolved: () => void;
5
+ }
6
+ export declare function OwnerDecisionCard({ item, onResolved }: OwnerDecisionCardProps): import("react").JSX.Element;
@@ -0,0 +1,86 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * OwnerDecisionCard — PRI-629 统一 Owner Inbox 的决策卡(evaluator/rollout)。
4
+ *
5
+ * 第一层只回答 Owner 关心的问题 (SPEC §26): 发生了什么 / 为什么找我 /
6
+ * 机器建议 / 可执行动作与后果。taskId / repairIteration / reasonCode 等
7
+ * 实现细节收纳在折叠的高级诊断里。动作经 resolveOwnerDecision 服务端重读
8
+ * durable facts — stale → 409,由本组件以可理解文案呈现并触发刷新。
9
+ */
10
+ import { useState } from "react";
11
+ import { Link } from "react-router-dom";
12
+ import { useTranslation } from "react-i18next";
13
+ import { toast } from "sonner";
14
+ import { resolveOwnerDecision } from "../../api.js";
15
+ export function OwnerDecisionCard({ item, onResolved }) {
16
+ const { t } = useTranslation();
17
+ const [actionLoading, setActionLoading] = useState(null);
18
+ const [instruction, setInstruction] = useState("");
19
+ const [showInstruction, setShowInstruction] = useState(false);
20
+ const [showAdvanced, setShowAdvanced] = useState(false);
21
+ const isTaskDecision = item.kind === "evaluator_review" || item.kind === "rollout_review";
22
+ const canAccept = item.allowedActions.includes("accept_current");
23
+ const canRevise = item.allowedActions.includes("revise_once");
24
+ const canReject = item.allowedActions.includes("reject_current");
25
+ async function handleAction(action) {
26
+ if (action === "revise_once" && showInstruction && instruction.trim().length === 0) {
27
+ // 指导为空也可以提交 — instruction 是可选的;这里仅在展开输入后要求非空确认
28
+ // (避免误提交空指导),Owner 可收起输入直接提交。
29
+ toast.error(t("pages.focus.ownerDecision.instructionRequired"));
30
+ return;
31
+ }
32
+ setActionLoading(action);
33
+ try {
34
+ const response = await resolveOwnerDecision(item.taskId, {
35
+ action,
36
+ reviewKey: item.reviewKey,
37
+ expectedRevisionEpoch: item.expectedRevisionEpoch,
38
+ expectedSourceRunId: item.expectedSourceRunId,
39
+ expectedSourceArtifactId: item.expectedSourceArtifactId,
40
+ expectedSourceArtifactHash: item.expectedSourceArtifactHash,
41
+ ...(action === "revise_once" && instruction.trim().length > 0
42
+ ? { ownerInstruction: instruction.trim() }
43
+ : { ownerInstruction: null }),
44
+ });
45
+ if (!response.success) {
46
+ if (response.error === "stale_owner_decision") {
47
+ toast.error(t("pages.focus.ownerDecision.staleError"));
48
+ }
49
+ else if (response.error === "already_resolved") {
50
+ toast.info(t("pages.focus.ownerDecision.alreadyResolved"));
51
+ }
52
+ else {
53
+ toast.error(response.error ?? t("pages.focus.ownerDecision.actionFailed"));
54
+ }
55
+ onResolved();
56
+ return;
57
+ }
58
+ toast.success(t("pages.focus.ownerDecision.resolved"));
59
+ onResolved();
60
+ }
61
+ catch {
62
+ toast.error(t("pages.focus.ownerDecision.actionFailed"));
63
+ }
64
+ finally {
65
+ setActionLoading(null);
66
+ }
67
+ }
68
+ const kindLabel = item.kind === "rollout_review"
69
+ ? t("pages.focus.ownerDecision.kindRollout")
70
+ : item.kind === "activation_approval"
71
+ ? t("pages.focus.ownerDecision.kindApproval")
72
+ : item.kind === "rulecode_decision"
73
+ ? t("pages.focus.ownerDecision.kindRulecode")
74
+ : t("pages.focus.ownerDecision.kindEvaluator");
75
+ return (_jsxs("article", { className: "bg-panel border border-line rounded-[6px] p-4 mb-3", "data-testid": `owner-decision-${item.taskId}`, children: [_jsxs("div", { className: "flex items-start justify-between gap-3 mb-2", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-ink text-[14px] font-medium leading-snug", children: item.title }), _jsx("div", { className: "mt-1 text-ink-4 text-[11px] font-mono uppercase tracking-[0.08em]", children: kindLabel })] }), item.legacy && (_jsx("span", { className: "shrink-0 text-ink-4 border border-line rounded-[2px] px-[7px] py-[3px] text-[10.5px] font-mono", children: t("pages.focus.ownerDecision.legacyBadge") }))] }), _jsx("p", { className: "text-ink-2 text-[13px] leading-relaxed mb-2", children: item.summary }), item.machineRecommendation && (_jsxs("p", { className: "text-ink-3 text-[12.5px] mb-1", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.ownerDecision.machineRecommendationLabel") }), " ", item.machineRecommendation, item.score !== undefined && _jsx("span", { className: "font-mono ml-1", children: item.score.toFixed(2) })] })), item.kind === "rollout_review" && (_jsx("p", { className: "text-ink-4 text-[12px] mb-1", children: t("pages.focus.ownerDecision.rolloutSafetyNote") })), isTaskDecision ? (_jsxs(_Fragment, { children: [showInstruction && (_jsxs("div", { className: "mt-2 mb-2", children: [_jsx("label", { className: "block font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 mb-2", children: t("pages.focus.ownerDecision.instructionLabel") }), _jsx("textarea", { value: instruction, onChange: (e) => setInstruction(e.target.value.slice(0, 500)), "data-testid": `owner-instruction-${item.taskId}`, placeholder: t("pages.focus.ownerDecision.instructionPlaceholder"), className: "w-full border border-line rounded-[var(--radius-md)] bg-surface text-ink px-3 py-2 text-[13px] min-h-[64px] resize-y focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov" })] })), _jsxs("div", { className: "flex flex-wrap gap-2 mt-3", children: [canAccept && (_jsx("button", { type: "button", onClick: () => handleAction("accept_current"), disabled: actionLoading !== null, "data-testid": `owner-accept-${item.taskId}`, className: "inline-flex items-center border border-gov text-gov bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-gov/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", children: actionLoading === "accept_current" ? t("common.loading") : t("pages.focus.ownerDecision.acceptCurrent") })), canRevise && (_jsx("button", { type: "button", onClick: () => {
76
+ if (!showInstruction) {
77
+ setShowInstruction(true);
78
+ return;
79
+ }
80
+ void handleAction("revise_once");
81
+ }, disabled: actionLoading !== null, "data-testid": `owner-revise-${item.taskId}`, className: "inline-flex items-center border border-line text-ink bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", children: actionLoading === "revise_once" ? t("common.loading") : t("pages.focus.ownerDecision.reviseOnce") })), canReject && (_jsx("button", { type: "button", onClick: () => handleAction("reject_current"), disabled: actionLoading !== null, "data-testid": `owner-reject-${item.taskId}`, className: "inline-flex items-center border border-danger text-danger bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-danger/5 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", children: actionLoading === "reject_current" ? t("common.loading") : t("pages.focus.ownerDecision.rejectCurrent") }))] }), _jsx("div", { className: "mt-2 text-ink-4 text-[11.5px] leading-relaxed", children: t("pages.focus.ownerDecision.actionConsequence") }), _jsxs("button", { type: "button", onClick: () => setShowAdvanced(!showAdvanced), className: "mt-2 text-ink-4 text-[11px] font-mono uppercase tracking-[0.08em] hover:text-ink-3", "data-testid": `owner-advanced-toggle-${item.taskId}`, children: [showAdvanced ? "▾" : "▸", " ", t("pages.focus.ownerDecision.advanced")] }), showAdvanced && (_jsxs("dl", { className: "mt-2 grid gap-1 text-[11.5px] font-mono text-ink-4", children: [_jsxs("div", { children: ["taskId: ", item.taskId] }), _jsxs("div", { children: ["reasonCode: ", item.reasonCode] }), _jsxs("div", { children: ["reviewKey: ", item.reviewKey.slice(0, 24), "\u2026"] }), _jsxs("div", { children: ["epoch: ", item.expectedRevisionEpoch] })] }))] })) : (_jsxs("div", { className: "mt-2", children: [_jsx("p", { className: "text-ink-4 text-[12px] mb-2", children: item.kind === "activation_approval"
82
+ ? t("pages.focus.ownerDecision.approvalHint")
83
+ : t("pages.focus.ownerDecision.rulecodeHint") }), item.kind === "activation_approval" ? (_jsx("button", { type: "button", onClick: () => {
84
+ document.getElementById("approval-queue-section")?.scrollIntoView({ behavior: "smooth", block: "start" });
85
+ }, "data-testid": `go-approvals-${item.taskId}`, className: "inline-flex items-center border border-gov text-gov bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-gov/5 transition-colors", children: t("pages.focus.ownerDecision.goApprovalsCta") })) : (_jsx(Link, { to: "/activation", "data-testid": `go-activation-${item.taskId}`, className: "inline-flex items-center border border-gov text-gov bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-gov/5 transition-colors", children: t("pages.focus.ownerDecision.goActivationCta") }))] }))] }));
86
+ }
@@ -22,19 +22,21 @@ function toReviewStatus(principleStatus, approvalStatus) {
22
22
  return "parked";
23
23
  if (principleStatus === "deprecated")
24
24
  return "rejected";
25
- if (principleStatus === "probation")
26
- return "pending";
27
- return "pending";
25
+ // PRI-629 INV-02: candidate/probation 是生命周期(内化进行中),不是"待你
26
+ // 审查"。真实 Owner 决策只在治理焦点 Owner Inbox 呈现。
27
+ return "candidate";
28
28
  }
29
29
  // ── Status visual mapping ───────────────────────────────────────────────────
30
30
  const STATUS_BORDER = {
31
31
  pending: "border-l-gov",
32
+ candidate: "border-l-ink-3",
32
33
  approved: "border-l-green",
33
34
  rejected: "border-l-danger",
34
35
  parked: "border-l-ink-3",
35
36
  };
36
37
  const STATUS_TEXT = {
37
38
  pending: "text-gov",
39
+ candidate: "text-ink-3",
38
40
  approved: "text-green",
39
41
  rejected: "text-danger",
40
42
  parked: "text-ink-3",
@@ -47,6 +49,7 @@ const CHANNEL_LABELS = {
47
49
  // ── PRI-558: timeline node fill + status-driven copy (theme tokens, dark-mode safe) ──
48
50
  const STATUS_DOT_BG = {
49
51
  pending: "bg-gov",
52
+ candidate: "bg-ink-3",
50
53
  approved: "bg-green",
51
54
  rejected: "bg-danger",
52
55
  parked: "bg-ink-3",
@@ -56,12 +59,14 @@ const STATUS_DOT_BG = {
56
59
  const GOV_DECISION = {
57
60
  approved: { glyph: "✓", labelKey: "principles.govApproved" },
58
61
  pending: { glyph: "⏳", labelKey: "principles.govPending" },
62
+ candidate: { glyph: "○", labelKey: "principles.statusCandidate" },
59
63
  rejected: { glyph: "✗", labelKey: "principles.statusRejected" },
60
64
  parked: { glyph: "⏸", labelKey: "principles.statusParked" },
61
65
  };
62
66
  const BLOCK_IMPACT_KEY = {
63
67
  approved: "principles.blockImpactActive",
64
68
  pending: "principles.blockImpactPending",
69
+ candidate: "principles.blockImpactPending",
65
70
  rejected: "principles.blockImpactRejected",
66
71
  parked: "principles.blockImpactParked",
67
72
  };
@@ -145,8 +150,9 @@ export function PrinciplesPage() {
145
150
  const [search, setSearch] = useState("");
146
151
  const [statusFilter, setStatusFilter] = useState("all");
147
152
  const [sortBy, setSortBy] = useState("updatedAt");
148
- // PRI-330: Default to actionable filter
149
- const [filterMode, setFilterMode] = useState('actionable');
153
+ // PRI-629 (INV-02): 默认展示全部 — candidate 是生命周期而非待办,
154
+ // "只看待决策"不再作为默认视图 (真实决策在治理焦点)。
155
+ const [filterMode, setFilterMode] = useState('all');
150
156
  const [categories, setCategories] = useState();
151
157
  // Fetch data
152
158
  const loadData = useCallback(async () => {
@@ -810,3 +810,40 @@ export interface OwnerIdentityUnregisterData {
810
810
  governance: OwnerGovernanceReadinessData;
811
811
  }
812
812
  export declare function validateOwnerIdentityUnregister(v: unknown): OwnerIdentityUnregisterData | null;
813
+ export interface OwnerDecisionItemData {
814
+ reviewKey: string;
815
+ kind: string;
816
+ taskId: string;
817
+ title: string;
818
+ summary: string;
819
+ reasonCode: string;
820
+ legacy: boolean;
821
+ allowedActions: string[];
822
+ expectedRevisionEpoch: number;
823
+ expectedSourceRunId: string;
824
+ expectedSourceArtifactId: string;
825
+ expectedSourceArtifactHash: string;
826
+ createdAt: string;
827
+ machineRecommendation?: string;
828
+ score?: number;
829
+ principleId?: string;
830
+ }
831
+ export interface OwnerDecisionsData {
832
+ items: OwnerDecisionItemData[];
833
+ total: number;
834
+ generatedAt: string;
835
+ }
836
+ export declare function validateOwnerDecisionItem(v: unknown): OwnerDecisionItemData | null;
837
+ export declare function validateOwnerDecisionsData(v: unknown): OwnerDecisionsData | null;
838
+ export interface OwnerResolutionResultData {
839
+ status: 'resolved';
840
+ resolutionId: string;
841
+ reviewKey: string;
842
+ action: string;
843
+ applied: boolean;
844
+ runnerWillApply: boolean;
845
+ effectiveDecision?: string;
846
+ targetTaskId?: string;
847
+ nextAction?: string;
848
+ }
849
+ export declare function validateOwnerResolutionResult(v: unknown): OwnerResolutionResultData | null;
@@ -2326,3 +2326,126 @@ export function validateOwnerIdentityUnregister(v) {
2326
2326
  return null;
2327
2327
  return { ok: true, source: 'none', governance };
2328
2328
  }
2329
+ // ── PRI-629: unified Owner Decision inbox (owner-decisions API) ──────────────
2330
+ const OWNER_DECISION_KINDS = new Set(['evaluator_review', 'rollout_review', 'activation_approval', 'rulecode_decision']);
2331
+ const OWNER_DECISION_ACTIONS = new Set(['accept_current', 'revise_once', 'reject_current', 'approve', 'reject', 'promote', 'reject_after_shadow']);
2332
+ export function validateOwnerDecisionItem(v) {
2333
+ if (!isObject(v))
2334
+ return null;
2335
+ const { reviewKey } = v;
2336
+ const { kind } = v;
2337
+ const { taskId } = v;
2338
+ const { title } = v;
2339
+ const { summary } = v;
2340
+ const { reasonCode } = v;
2341
+ const { createdAt } = v;
2342
+ if (!isString(reviewKey) || !isString(kind) || !isString(taskId) || !isString(title)
2343
+ || !isString(summary) || !isString(reasonCode) || !isString(createdAt))
2344
+ return null;
2345
+ if (!OWNER_DECISION_KINDS.has(kind))
2346
+ return null;
2347
+ if (!Object.hasOwn(v, 'legacy') || !isBoolean(v.legacy))
2348
+ return null;
2349
+ if (!Object.hasOwn(v, 'allowedActions') || !Array.isArray(v.allowedActions))
2350
+ return null;
2351
+ for (const action of v.allowedActions) {
2352
+ if (typeof action !== 'string' || !OWNER_DECISION_ACTIONS.has(action))
2353
+ return null;
2354
+ }
2355
+ if (!Object.hasOwn(v, 'expectedRevisionEpoch') || !isNumber(v.expectedRevisionEpoch))
2356
+ return null;
2357
+ const { expectedRevisionEpoch } = v;
2358
+ const { expectedSourceRunId } = v;
2359
+ const { expectedSourceArtifactId } = v;
2360
+ const { expectedSourceArtifactHash } = v;
2361
+ if (!isString(expectedSourceRunId) || !isString(expectedSourceArtifactId) || !isString(expectedSourceArtifactHash))
2362
+ return null;
2363
+ const item = {
2364
+ reviewKey,
2365
+ kind,
2366
+ taskId,
2367
+ title,
2368
+ summary,
2369
+ reasonCode,
2370
+ legacy: v.legacy,
2371
+ allowedActions: v.allowedActions,
2372
+ expectedRevisionEpoch,
2373
+ expectedSourceRunId,
2374
+ expectedSourceArtifactId,
2375
+ expectedSourceArtifactHash,
2376
+ createdAt,
2377
+ };
2378
+ if (Object.hasOwn(v, 'machineRecommendation')) {
2379
+ if (!isString(v.machineRecommendation))
2380
+ return null;
2381
+ item.machineRecommendation = v.machineRecommendation;
2382
+ }
2383
+ if (Object.hasOwn(v, 'score')) {
2384
+ if (!isNumber(v.score))
2385
+ return null;
2386
+ item.score = v.score;
2387
+ }
2388
+ if (Object.hasOwn(v, 'principleId')) {
2389
+ if (!isString(v.principleId))
2390
+ return null;
2391
+ item.principleId = v.principleId;
2392
+ }
2393
+ return item;
2394
+ }
2395
+ export function validateOwnerDecisionsData(v) {
2396
+ if (!isObject(v))
2397
+ return null;
2398
+ if (!Object.hasOwn(v, 'items') || !Array.isArray(v.items))
2399
+ return null;
2400
+ const items = [];
2401
+ for (const entry of v.items) {
2402
+ const item = validateOwnerDecisionItem(entry);
2403
+ if (item === null)
2404
+ return null;
2405
+ items.push(item);
2406
+ }
2407
+ if (!Object.hasOwn(v, 'total') || !isNumber(v.total))
2408
+ return null;
2409
+ if (!Object.hasOwn(v, 'generatedAt') || !isString(v.generatedAt))
2410
+ return null;
2411
+ return { items, total: v.total, generatedAt: v.generatedAt };
2412
+ }
2413
+ export function validateOwnerResolutionResult(v) {
2414
+ if (!isObject(v))
2415
+ return null;
2416
+ if (!Object.hasOwn(v, 'status') || v.status !== 'resolved')
2417
+ return null;
2418
+ const { resolutionId } = v;
2419
+ const { reviewKey } = v;
2420
+ const { action } = v;
2421
+ if (!isString(resolutionId) || !isString(reviewKey) || !isString(action))
2422
+ return null;
2423
+ if (!Object.hasOwn(v, 'applied') || !isBoolean(v.applied))
2424
+ return null;
2425
+ if (!Object.hasOwn(v, 'runnerWillApply') || !isBoolean(v.runnerWillApply))
2426
+ return null;
2427
+ const result = {
2428
+ status: 'resolved',
2429
+ resolutionId,
2430
+ reviewKey,
2431
+ action,
2432
+ applied: v.applied,
2433
+ runnerWillApply: v.runnerWillApply,
2434
+ };
2435
+ if (Object.hasOwn(v, 'effectiveDecision')) {
2436
+ if (!isString(v.effectiveDecision))
2437
+ return null;
2438
+ result.effectiveDecision = v.effectiveDecision;
2439
+ }
2440
+ if (Object.hasOwn(v, 'targetTaskId')) {
2441
+ if (!isString(v.targetTaskId))
2442
+ return null;
2443
+ result.targetTaskId = v.targetTaskId;
2444
+ }
2445
+ if (Object.hasOwn(v, 'nextAction')) {
2446
+ if (!isString(v.nextAction))
2447
+ return null;
2448
+ result.nextAction = v.nextAction;
2449
+ }
2450
+ return result;
2451
+ }
@@ -667,6 +667,9 @@
667
667
  .min-h-0 {
668
668
  min-height: 0px;
669
669
  }
670
+ .min-h-\[64px\] {
671
+ min-height: 64px;
672
+ }
670
673
  .min-h-\[80px\] {
671
674
  min-height: 80px;
672
675
  }
@@ -2550,6 +2553,14 @@
2550
2553
  .hover\:text-gov-2:hover {
2551
2554
  color: var(--color-gov-2);
2552
2555
  }
2556
+ .hover\:text-gov\/80:hover {
2557
+ color: color-mix(in srgb, #1e3a5f 80%, transparent);
2558
+ }
2559
+ @supports (color: color-mix(in lab, red, red)) {
2560
+ .hover\:text-gov\/80:hover {
2561
+ color: color-mix(in oklab, var(--color-gov) 80%, transparent);
2562
+ }
2563
+ }
2553
2564
  .hover\:text-green:hover {
2554
2565
  color: var(--color-green);
2555
2566
  }