create-principles-disciple 1.133.10 → 1.133.12

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 (96) hide show
  1. package/codex-adapter/package.json +2 -2
  2. package/console/dist/ui/i18n/en.json +13 -1
  3. package/console/dist/ui/i18n/zh-CN.json +13 -1
  4. package/console/dist/ui/pages/focus/OwnerDecisionCard.js +1 -1
  5. package/console/dist/ui/utils/validators.d.ts +9 -0
  6. package/console/dist/ui/utils/validators.js +31 -0
  7. package/console/dist/web/assets/app.css +3 -0
  8. package/console/dist/web/assets/app.js +60 -3
  9. package/console/package.json +1 -1
  10. package/core/dist/runtime-v2/internalization/__tests__/artifact-summary.property.test.js +1 -1
  11. package/core/dist/runtime-v2/internalization/__tests__/artifact-summary.property.test.js.map +1 -1
  12. package/core/dist/runtime-v2/internalization/__tests__/artificer-prompt-builder.test.js +6 -4
  13. package/core/dist/runtime-v2/internalization/__tests__/artificer-prompt-builder.test.js.map +1 -1
  14. package/core/dist/runtime-v2/internalization/__tests__/evaluator-out-of-scope-governance.test.d.ts +2 -0
  15. package/core/dist/runtime-v2/internalization/__tests__/evaluator-out-of-scope-governance.test.d.ts.map +1 -0
  16. package/core/dist/runtime-v2/internalization/__tests__/evaluator-out-of-scope-governance.test.js +307 -0
  17. package/core/dist/runtime-v2/internalization/__tests__/evaluator-out-of-scope-governance.test.js.map +1 -0
  18. package/core/dist/runtime-v2/internalization/__tests__/evaluator-prompt-builder.test.js +2 -2
  19. package/core/dist/runtime-v2/internalization/__tests__/evaluator-prompt-builder.test.js.map +1 -1
  20. package/core/dist/runtime-v2/internalization/__tests__/evolution-alignment-contract.test.d.ts +18 -0
  21. package/core/dist/runtime-v2/internalization/__tests__/evolution-alignment-contract.test.d.ts.map +1 -0
  22. package/core/dist/runtime-v2/internalization/__tests__/evolution-alignment-contract.test.js +457 -0
  23. package/core/dist/runtime-v2/internalization/__tests__/evolution-alignment-contract.test.js.map +1 -0
  24. package/core/dist/runtime-v2/internalization/__tests__/owner-decision-review.test.js +88 -0
  25. package/core/dist/runtime-v2/internalization/__tests__/owner-decision-review.test.js.map +1 -1
  26. package/core/dist/runtime-v2/internalization/artifact-summary.d.ts.map +1 -1
  27. package/core/dist/runtime-v2/internalization/artifact-summary.js +8 -0
  28. package/core/dist/runtime-v2/internalization/artifact-summary.js.map +1 -1
  29. package/core/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts +37 -2
  30. package/core/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts.map +1 -1
  31. package/core/dist/runtime-v2/internalization/artificer-prompt-builder.js +31 -1
  32. package/core/dist/runtime-v2/internalization/artificer-prompt-builder.js.map +1 -1
  33. package/core/dist/runtime-v2/internalization/artificer-runner.d.ts +18 -1
  34. package/core/dist/runtime-v2/internalization/artificer-runner.d.ts.map +1 -1
  35. package/core/dist/runtime-v2/internalization/artificer-runner.js +60 -2
  36. package/core/dist/runtime-v2/internalization/artificer-runner.js.map +1 -1
  37. package/core/dist/runtime-v2/internalization/context-manifests.d.ts.map +1 -1
  38. package/core/dist/runtime-v2/internalization/context-manifests.js +35 -2
  39. package/core/dist/runtime-v2/internalization/context-manifests.js.map +1 -1
  40. package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.d.ts +15 -2
  41. package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.d.ts.map +1 -1
  42. package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.js +10 -2
  43. package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.js.map +1 -1
  44. package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts +46 -0
  45. package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
  46. package/core/dist/runtime-v2/internalization/evaluator-runner.js +352 -21
  47. package/core/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
  48. package/core/dist/runtime-v2/internalization/index.d.ts +4 -2
  49. package/core/dist/runtime-v2/internalization/index.d.ts.map +1 -1
  50. package/core/dist/runtime-v2/internalization/index.js +2 -1
  51. package/core/dist/runtime-v2/internalization/index.js.map +1 -1
  52. package/core/dist/runtime-v2/internalization/intent-contract.d.ts +59 -0
  53. package/core/dist/runtime-v2/internalization/intent-contract.d.ts.map +1 -0
  54. package/core/dist/runtime-v2/internalization/intent-contract.js +61 -0
  55. package/core/dist/runtime-v2/internalization/intent-contract.js.map +1 -0
  56. package/core/dist/runtime-v2/internalization/owner-decision-review.d.ts +28 -0
  57. package/core/dist/runtime-v2/internalization/owner-decision-review.d.ts.map +1 -1
  58. package/core/dist/runtime-v2/internalization/owner-decision-review.js +76 -0
  59. package/core/dist/runtime-v2/internalization/owner-decision-review.js.map +1 -1
  60. package/core/dist/runtime-v2/internalization/owner-review.d.ts +8 -0
  61. package/core/dist/runtime-v2/internalization/owner-review.d.ts.map +1 -1
  62. package/core/dist/runtime-v2/internalization/owner-review.js +10 -0
  63. package/core/dist/runtime-v2/internalization/owner-review.js.map +1 -1
  64. package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts +76 -0
  65. package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts.map +1 -1
  66. package/core/dist/runtime-v2/internalization/pitask-metadata.js +116 -3
  67. package/core/dist/runtime-v2/internalization/pitask-metadata.js.map +1 -1
  68. package/core/dist/runtime-v2/internalization/rule-reliability-validation.d.ts +141 -1
  69. package/core/dist/runtime-v2/internalization/rule-reliability-validation.d.ts.map +1 -1
  70. package/core/dist/runtime-v2/internalization/rule-reliability-validation.js +140 -0
  71. package/core/dist/runtime-v2/internalization/rule-reliability-validation.js.map +1 -1
  72. package/core/dist/runtime-v2/internalization/scribe-output.d.ts +11 -0
  73. package/core/dist/runtime-v2/internalization/scribe-output.d.ts.map +1 -1
  74. package/core/dist/runtime-v2/internalization/scribe-output.js +13 -0
  75. package/core/dist/runtime-v2/internalization/scribe-output.js.map +1 -1
  76. package/core/dist/runtime-v2/internalization/scribe-prompt-builder.d.ts +8 -1
  77. package/core/dist/runtime-v2/internalization/scribe-prompt-builder.d.ts.map +1 -1
  78. package/core/dist/runtime-v2/internalization/scribe-prompt-builder.js +25 -1
  79. package/core/dist/runtime-v2/internalization/scribe-prompt-builder.js.map +1 -1
  80. package/core/dist/runtime-v2/runner/__tests__/base-peer-runner-failure-details.test.js +16 -1
  81. package/core/dist/runtime-v2/runner/__tests__/base-peer-runner-failure-details.test.js.map +1 -1
  82. package/core/dist/runtime-v2/runner/base-peer-runner.d.ts +9 -1
  83. package/core/dist/runtime-v2/runner/base-peer-runner.d.ts.map +1 -1
  84. package/core/dist/runtime-v2/runner/base-peer-runner.js +32 -3
  85. package/core/dist/runtime-v2/runner/base-peer-runner.js.map +1 -1
  86. package/core/package.json +2 -2
  87. package/host-runtime/package.json +2 -2
  88. package/install-layout/package.json +2 -2
  89. package/package.json +3 -3
  90. package/pd-cli/package.json +2 -2
  91. package/plugin/dist/bundle.js +764 -724
  92. package/plugin/dist/governance-audit.js +76 -76
  93. package/plugin/dist/rulehost-evidence.js +116 -116
  94. package/plugin/openclaw.plugin.json +1 -1
  95. package/plugin/package.json +2 -2
  96. package/release-manager/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principles/codex-adapter",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "Codex CLI host adapter for Principles Disciple — implements HostAdapter interface for OpenAI Codex CLI's stdin/stdout JSON hook model (ADR-0020).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -35,7 +35,7 @@
35
35
  "@principles/host-runtime": "file:../host-runtime"
36
36
  },
37
37
  "devDependencies": {
38
- "@types/node": "^26.1.2",
38
+ "@types/node": "^26.4.1",
39
39
  "typescript": "^7.0.2",
40
40
  "vite": "^8.2.2",
41
41
  "vitest": "^5.0.0"
@@ -309,7 +309,19 @@
309
309
  "approvalHint": "The deployment approval for this principle is still waiting in the approval queue.",
310
310
  "rulecodeHint": "This rule is in shadow activation and needs a decision in activation management.",
311
311
  "goApprovalsCta": "Go to deployment approvals",
312
- "goActivationCta": "Go to activation management"
312
+ "goActivationCta": "Go to activation management",
313
+ "qualityChecklistLabel": "Quality checklist",
314
+ "qualityCheckStatus": {
315
+ "passed": "passed",
316
+ "failed": "failed"
317
+ },
318
+ "qualityCheck": {
319
+ "understandability": "Understandability",
320
+ "evidence": "Evidence",
321
+ "actionability": "Actionability",
322
+ "generalization": "Generalization",
323
+ "boundary": "Boundary"
324
+ }
313
325
  }
314
326
  },
315
327
  "pain": {
@@ -309,7 +309,19 @@
309
309
  "approvalHint": "该原则的部署审批仍在审批队列中等待处理。",
310
310
  "rulecodeHint": "该规则处于影子激活期,需要在激活管理中裁决。",
311
311
  "goApprovalsCta": "前往部署审批",
312
- "goActivationCta": "前往激活管理"
312
+ "goActivationCta": "前往激活管理",
313
+ "qualityChecklistLabel": "质量检查表",
314
+ "qualityCheckStatus": {
315
+ "passed": "已通过",
316
+ "failed": "未通过"
317
+ },
318
+ "qualityCheck": {
319
+ "understandability": "可理解性",
320
+ "evidence": "证据来源",
321
+ "actionability": "可执行性",
322
+ "generalization": "泛化度",
323
+ "boundary": "适用边界"
324
+ }
313
325
  }
314
326
  },
315
327
  "pain": {
@@ -79,7 +79,7 @@ export function OwnerDecisionCard({ item, onResolved, governanceReady = true })
79
79
  : item.kind === "rulecode_decision"
80
80
  ? t("pages.focus.ownerDecision.kindRulecode")
81
81
  : t("pages.focus.ownerDecision.kindEvaluator");
82
- 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.review?.brief.kind === "evaluator" && (_jsxs("div", { className: "mb-3 grid gap-2 text-[12.5px] leading-relaxed", children: [item.review.brief.principle?.statement && (_jsxs("p", { children: [_jsx("span", { className: "font-medium text-ink", children: t("pages.focus.ownerDecision.principleLabel") }), " ", item.review.brief.principle.statement] })), item.review.brief.implementation?.summary && (_jsxs("p", { children: [_jsx("span", { className: "font-medium text-ink", children: t("pages.focus.ownerDecision.implementationLabel") }), " ", item.review.brief.implementation.summary] })), (item.review.brief.concerns?.length ?? 0) > 0 && (_jsxs("p", { className: "text-amber", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.ownerDecision.concernLabel") }), " ", item.review.brief.concerns?.[0]] }))] })), item.review?.brief.kind === "rollout" && item.review.brief.summary && (_jsx("p", { className: "mb-3 text-[12.5px] text-ink-2", children: item.review.brief.summary })), item.review && (_jsxs("div", { className: "mb-2 flex flex-wrap gap-2 text-[10.5px] font-mono uppercase tracking-[0.06em]", children: [_jsx("span", { className: "rounded-[2px] border border-line px-2 py-1 text-ink-3", children: t(`pages.focus.ownerDecision.evidence.${item.review.evidence.completeness}`) }), item.review.evidence.deterministicChecks.map(check => (_jsxs("span", { className: "rounded-[2px] border border-line px-2 py-1 text-ink-3", children: [check.check, ": ", check.status] }, check.check)))] })), 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") })), evidenceUnavailable ? (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 p-3", children: [_jsx("p", { className: "text-ink-2 text-[12.5px] leading-relaxed", children: t("pages.focus.ownerDecision.evidenceUnavailable") }), _jsx(Link, { to: "/failed", "data-testid": `owner-evidence-recover-${item.taskId}`, className: "mt-2 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", children: t("pages.focus.ownerDecision.goRecoverCta") })] })) : 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" })] })), requiresPartialAcknowledgement && (_jsxs("label", { className: "mt-2 mb-1 flex items-start gap-2 text-[12px] text-ink-3", children: [_jsx("input", { type: "checkbox", checked: partialEvidenceAcknowledged, onChange: (event) => setPartialEvidenceAcknowledged(event.target.checked), "data-testid": `owner-partial-evidence-ack-${item.taskId}`, className: "mt-0.5" }), _jsx("span", { children: t("pages.focus.ownerDecision.partialEvidenceAcknowledgement") })] })), _jsxs("div", { className: "flex flex-wrap gap-2 mt-3", children: [canAccept && (_jsx("button", { type: "button", onClick: () => handleAction("accept_current"), disabled: !governanceReady || actionLoading !== null || (requiresPartialAcknowledgement && !partialEvidenceAcknowledged), "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: () => {
82
+ 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.review?.brief.kind === "evaluator" && (_jsxs("div", { className: "mb-3 grid gap-2 text-[12.5px] leading-relaxed", children: [item.review.brief.principle?.statement && (_jsxs("p", { children: [_jsx("span", { className: "font-medium text-ink", children: t("pages.focus.ownerDecision.principleLabel") }), " ", item.review.brief.principle.statement] })), item.review.brief.implementation?.summary && (_jsxs("p", { children: [_jsx("span", { className: "font-medium text-ink", children: t("pages.focus.ownerDecision.implementationLabel") }), " ", item.review.brief.implementation.summary] })), (item.review.brief.concerns?.length ?? 0) > 0 && (_jsxs("p", { className: "text-amber", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.ownerDecision.concernLabel") }), " ", item.review.brief.concerns?.[0]] })), (item.review.brief.qualityChecklist?.items?.length ?? 0) > 0 && (_jsxs("div", { className: "mt-1 rounded-[3px] border border-line bg-surface-2 p-2", "data-testid": `owner-quality-checklist-${item.taskId}`, children: [_jsx("div", { className: "font-mono text-[10.5px] uppercase tracking-[0.06em] text-ink-3 mb-1", children: t("pages.focus.ownerDecision.qualityChecklistLabel") }), _jsx("ul", { className: "grid gap-0.5", children: item.review.brief.qualityChecklist?.items.map((qItem) => (_jsxs("li", { className: "flex items-start gap-1.5 text-[12px]", children: [_jsx("span", { className: qItem.pass ? "text-emerald" : "text-amber", "aria-hidden": "true", children: qItem.pass ? "✓" : "!" }), _jsx("span", { className: "sr-only", children: qItem.pass ? t("pages.focus.ownerDecision.qualityCheckStatus.passed") : t("pages.focus.ownerDecision.qualityCheckStatus.failed") }), _jsxs("span", { className: "text-ink-2", children: [_jsx("span", { className: "font-medium", children: t(`pages.focus.ownerDecision.qualityCheck.${qItem.id}`) }), " ", qItem.note] })] }, qItem.id))) })] }))] })), item.review?.brief.kind === "rollout" && item.review.brief.summary && (_jsx("p", { className: "mb-3 text-[12.5px] text-ink-2", children: item.review.brief.summary })), item.review && (_jsxs("div", { className: "mb-2 flex flex-wrap gap-2 text-[10.5px] font-mono uppercase tracking-[0.06em]", children: [_jsx("span", { className: "rounded-[2px] border border-line px-2 py-1 text-ink-3", children: t(`pages.focus.ownerDecision.evidence.${item.review.evidence.completeness}`) }), item.review.evidence.deterministicChecks.map(check => (_jsxs("span", { className: "rounded-[2px] border border-line px-2 py-1 text-ink-3", children: [check.check, ": ", check.status] }, check.check)))] })), 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") })), evidenceUnavailable ? (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 p-3", children: [_jsx("p", { className: "text-ink-2 text-[12.5px] leading-relaxed", children: t("pages.focus.ownerDecision.evidenceUnavailable") }), _jsx(Link, { to: "/failed", "data-testid": `owner-evidence-recover-${item.taskId}`, className: "mt-2 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", children: t("pages.focus.ownerDecision.goRecoverCta") })] })) : 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" })] })), requiresPartialAcknowledgement && (_jsxs("label", { className: "mt-2 mb-1 flex items-start gap-2 text-[12px] text-ink-3", children: [_jsx("input", { type: "checkbox", checked: partialEvidenceAcknowledged, onChange: (event) => setPartialEvidenceAcknowledged(event.target.checked), "data-testid": `owner-partial-evidence-ack-${item.taskId}`, className: "mt-0.5" }), _jsx("span", { children: t("pages.focus.ownerDecision.partialEvidenceAcknowledgement") })] })), _jsxs("div", { className: "flex flex-wrap gap-2 mt-3", children: [canAccept && (_jsx("button", { type: "button", onClick: () => handleAction("accept_current"), disabled: !governanceReady || actionLoading !== null || (requiresPartialAcknowledgement && !partialEvidenceAcknowledged), "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: () => {
83
83
  if (!showInstruction) {
84
84
  setShowInstruction(true);
85
85
  return;
@@ -866,6 +866,15 @@ export interface OwnerDecisionReviewData {
866
866
  requiredChanges: string[];
867
867
  risks?: string[];
868
868
  score?: number;
869
+ /** PRI-704 / PRI-703 Phase 4: 5-item deterministic quality checklist (evaluator briefs only). */
870
+ qualityChecklist?: {
871
+ schemaVersion: number;
872
+ items: {
873
+ id: string;
874
+ pass: boolean;
875
+ note: string;
876
+ }[];
877
+ };
869
878
  };
870
879
  evidence: {
871
880
  completeness: 'complete' | 'partial' | 'insufficient';
@@ -2415,6 +2415,37 @@ function validateOwnerDecisionReview(value) {
2415
2415
  return null;
2416
2416
  if (isNumber(brief.score))
2417
2417
  parsedBrief.score = brief.score;
2418
+ // PRI-704 / PRI-703 Phase 4 (评审修正): optional quality checklist —
2419
+ // strict five-item contract: schemaVersion must be exactly 1 and the five
2420
+ // known item ids must each appear EXACTLY once (the UI builds i18n keys
2421
+ // from the id; an unknown id would render an untranslated label, a
2422
+ // missing id an incomplete checklist). Anything else → omit the whole
2423
+ // checklist (older snapshots legitimately lack it; a partial one must
2424
+ // not masquerade as a review aid).
2425
+ if (brief.qualityChecklist !== undefined) {
2426
+ const KNOWN_IDS = ['understandability', 'evidence', 'actionability', 'generalization', 'boundary'];
2427
+ const qc = brief.qualityChecklist;
2428
+ if (isObject(qc) && qc.schemaVersion === 1 && Array.isArray(qc.items)) {
2429
+ const validItems = [];
2430
+ let shapeValid = true;
2431
+ const seen = new Set();
2432
+ for (const entry of qc.items) {
2433
+ if (!isObject(entry) || !isString(entry.id)
2434
+ || typeof entry.pass !== 'boolean' || !isString(entry.note)) {
2435
+ shapeValid = false;
2436
+ break;
2437
+ }
2438
+ seen.add(entry.id);
2439
+ validItems.push({ id: entry.id, pass: entry.pass, note: entry.note });
2440
+ }
2441
+ const allKnownOnce = shapeValid
2442
+ && validItems.length === KNOWN_IDS.length
2443
+ && KNOWN_IDS.every((id) => seen.has(id));
2444
+ if (allKnownOnce) {
2445
+ parsedBrief.qualityChecklist = { schemaVersion: 1, items: validItems };
2446
+ }
2447
+ }
2448
+ }
2418
2449
  }
2419
2450
  else {
2420
2451
  const risks = readOwnerStringArray(brief.risks);
@@ -993,6 +993,9 @@
993
993
  .justify-end {
994
994
  justify-content: flex-end;
995
995
  }
996
+ .gap-0\.5 {
997
+ gap: calc(var(--spacing) * 0.5);
998
+ }
996
999
  .gap-1 {
997
1000
  gap: var(--spacing);
998
1001
  }