create-principles-disciple 1.146.3 → 1.146.6
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.
- package/_release/product-identity.json +1 -1
- package/console/dist/web/assets/app.js +26 -26
- package/console/package.json +1 -1
- package/package.json +3 -3
- package/pd-cli/package.json +1 -1
- package/release-manager/package.json +3 -3
- package/console/dist/ui/App.d.ts +0 -1
- package/console/dist/ui/App.js +0 -172
- package/console/dist/ui/api.d.ts +0 -611
- package/console/dist/ui/api.js +0 -1094
- package/console/dist/ui/components/auth/login-form.d.ts +0 -4
- package/console/dist/ui/components/auth/login-form.js +0 -142
- package/console/dist/ui/components/auth/splash-screen.d.ts +0 -9
- package/console/dist/ui/components/auth/splash-screen.js +0 -22
- package/console/dist/ui/components/error-boundary.d.ts +0 -15
- package/console/dist/ui/components/error-boundary.js +0 -30
- package/console/dist/ui/components/focus/daily-thought-card.d.ts +0 -1
- package/console/dist/ui/components/focus/daily-thought-card.js +0 -41
- package/console/dist/ui/components/language-switcher.d.ts +0 -2
- package/console/dist/ui/components/language-switcher.js +0 -17
- package/console/dist/ui/components/layout/app-sidebar.d.ts +0 -27
- package/console/dist/ui/components/layout/app-sidebar.js +0 -128
- package/console/dist/ui/components/layout/page-loading.d.ts +0 -13
- package/console/dist/ui/components/layout/page-loading.js +0 -14
- package/console/dist/ui/components/layout/page-shell.d.ts +0 -12
- package/console/dist/ui/components/layout/page-shell.js +0 -11
- package/console/dist/ui/components/layout/section-title.d.ts +0 -10
- package/console/dist/ui/components/layout/section-title.js +0 -9
- package/console/dist/ui/components/notifications/NotificationProvider.d.ts +0 -14
- package/console/dist/ui/components/notifications/NotificationProvider.js +0 -136
- package/console/dist/ui/components/notifications/favicon-badge.d.ts +0 -3
- package/console/dist/ui/components/notifications/favicon-badge.js +0 -68
- package/console/dist/ui/components/notifications/notification-reducer.d.ts +0 -9
- package/console/dist/ui/components/notifications/notification-reducer.js +0 -9
- package/console/dist/ui/components/notifications/sound-storage.d.ts +0 -3
- package/console/dist/ui/components/notifications/sound-storage.js +0 -37
- package/console/dist/ui/components/notifications/useNotifications.d.ts +0 -1
- package/console/dist/ui/components/notifications/useNotifications.js +0 -9
- package/console/dist/ui/components/onboarding/CircuitDiagram.d.ts +0 -8
- package/console/dist/ui/components/onboarding/CircuitDiagram.js +0 -18
- package/console/dist/ui/components/onboarding/DemoResultView.d.ts +0 -22
- package/console/dist/ui/components/onboarding/DemoResultView.js +0 -33
- package/console/dist/ui/components/onboarding/SlashCommandsCard.d.ts +0 -16
- package/console/dist/ui/components/onboarding/SlashCommandsCard.js +0 -20
- package/console/dist/ui/components/onboarding/slashCommands.d.ts +0 -20
- package/console/dist/ui/components/onboarding/slashCommands.js +0 -22
- package/console/dist/ui/components/receipts/ReceiptCoverageDisclosure.d.ts +0 -6
- package/console/dist/ui/components/receipts/ReceiptCoverageDisclosure.js +0 -66
- package/console/dist/ui/components/theme-provider.d.ts +0 -14
- package/console/dist/ui/components/theme-provider.js +0 -40
- package/console/dist/ui/components/theme-toggle.d.ts +0 -2
- package/console/dist/ui/components/theme-toggle.js +0 -11
- package/console/dist/ui/components/ui/alert-dialog.d.ts +0 -20
- package/console/dist/ui/components/ui/alert-dialog.js +0 -26
- package/console/dist/ui/components/ui/badge.d.ts +0 -9
- package/console/dist/ui/components/ui/badge.js +0 -22
- package/console/dist/ui/components/ui/button.d.ts +0 -11
- package/console/dist/ui/components/ui/button.js +0 -34
- package/console/dist/ui/components/ui/card.d.ts +0 -8
- package/console/dist/ui/components/ui/card.js +0 -16
- package/console/dist/ui/components/ui/charts.d.ts +0 -51
- package/console/dist/ui/components/ui/charts.js +0 -72
- package/console/dist/ui/components/ui/dialog.d.ts +0 -19
- package/console/dist/ui/components/ui/dialog.js +0 -22
- package/console/dist/ui/components/ui/input.d.ts +0 -3
- package/console/dist/ui/components/ui/input.js +0 -8
- package/console/dist/ui/components/ui/markdown.d.ts +0 -24
- package/console/dist/ui/components/ui/markdown.js +0 -119
- package/console/dist/ui/components/ui/progress-bar.d.ts +0 -20
- package/console/dist/ui/components/ui/progress-bar.js +0 -38
- package/console/dist/ui/components/ui/select.d.ts +0 -13
- package/console/dist/ui/components/ui/select.js +0 -26
- package/console/dist/ui/components/ui/separator.d.ts +0 -3
- package/console/dist/ui/components/ui/separator.js +0 -6
- package/console/dist/ui/components/ui/sheet.d.ts +0 -25
- package/console/dist/ui/components/ui/sheet.js +0 -37
- package/console/dist/ui/components/ui/shiny-text.d.ts +0 -28
- package/console/dist/ui/components/ui/shiny-text.js +0 -46
- package/console/dist/ui/components/ui/skeleton.d.ts +0 -3
- package/console/dist/ui/components/ui/skeleton.js +0 -6
- package/console/dist/ui/components/ui/sonner.d.ts +0 -3
- package/console/dist/ui/components/ui/sonner.js +0 -13
- package/console/dist/ui/components/ui/tooltip.d.ts +0 -7
- package/console/dist/ui/components/ui/tooltip.js +0 -10
- package/console/dist/ui/data/daily-thoughts.d.ts +0 -15
- package/console/dist/ui/data/daily-thoughts.js +0 -164
- package/console/dist/ui/hooks/useNotificationSound.d.ts +0 -12
- package/console/dist/ui/hooks/useNotificationSound.js +0 -74
- package/console/dist/ui/i18n/en.json +0 -2399
- package/console/dist/ui/i18n/index.d.ts +0 -2
- package/console/dist/ui/i18n/index.js +0 -32
- package/console/dist/ui/i18n/zh-CN.json +0 -2399
- package/console/dist/ui/main.d.ts +0 -1
- package/console/dist/ui/main.js +0 -9
- package/console/dist/ui/pages/ReportProblemValidators.d.ts +0 -144
- package/console/dist/ui/pages/ReportProblemValidators.js +0 -418
- package/console/dist/ui/pages/activation/ActivationPage.d.ts +0 -1
- package/console/dist/ui/pages/activation/ActivationPage.js +0 -512
- package/console/dist/ui/pages/activation/ActivationValidators.d.ts +0 -20
- package/console/dist/ui/pages/activation/ActivationValidators.js +0 -160
- package/console/dist/ui/pages/control-center/AgentCard.d.ts +0 -31
- package/console/dist/ui/pages/control-center/AgentCard.js +0 -212
- package/console/dist/ui/pages/control-center/AgentGroup.d.ts +0 -26
- package/console/dist/ui/pages/control-center/AgentGroup.js +0 -38
- package/console/dist/ui/pages/control-center/ControlCenterPage.d.ts +0 -1
- package/console/dist/ui/pages/control-center/ControlCenterPage.js +0 -509
- package/console/dist/ui/pages/control-center/DesignGatePanel.d.ts +0 -1
- package/console/dist/ui/pages/control-center/DesignGatePanel.js +0 -137
- package/console/dist/ui/pages/control-center/RuntimeProfileManager.d.ts +0 -31
- package/console/dist/ui/pages/control-center/RuntimeProfileManager.js +0 -199
- package/console/dist/ui/pages/control-center/WorkflowDiagram.d.ts +0 -17
- package/console/dist/ui/pages/control-center/WorkflowDiagram.js +0 -55
- package/console/dist/ui/pages/debt/DebtPage.d.ts +0 -2
- package/console/dist/ui/pages/debt/DebtPage.js +0 -222
- package/console/dist/ui/pages/design-system/DesignSystemPage.d.ts +0 -2
- package/console/dist/ui/pages/design-system/DesignSystemPage.js +0 -30
- package/console/dist/ui/pages/examiner/ExaminerPage.d.ts +0 -15
- package/console/dist/ui/pages/examiner/ExaminerPage.js +0 -158
- package/console/dist/ui/pages/failed-tasks/FailedTasksPage.d.ts +0 -1
- package/console/dist/ui/pages/failed-tasks/FailedTasksPage.js +0 -421
- package/console/dist/ui/pages/focus/ApprovalSubjectReading.d.ts +0 -24
- package/console/dist/ui/pages/focus/ApprovalSubjectReading.js +0 -133
- package/console/dist/ui/pages/focus/FocusPage.d.ts +0 -123
- package/console/dist/ui/pages/focus/FocusPage.js +0 -567
- package/console/dist/ui/pages/focus/OwnerDecisionCard.d.ts +0 -9
- package/console/dist/ui/pages/focus/OwnerDecisionCard.js +0 -111
- package/console/dist/ui/pages/focus/OwnerWorkbench.d.ts +0 -19
- package/console/dist/ui/pages/focus/OwnerWorkbench.js +0 -75
- package/console/dist/ui/pages/focus/RuleCandidateBindingPanel.d.ts +0 -34
- package/console/dist/ui/pages/focus/RuleCandidateBindingPanel.js +0 -298
- package/console/dist/ui/pages/focus/focus-validation.d.ts +0 -40
- package/console/dist/ui/pages/focus/focus-validation.js +0 -211
- package/console/dist/ui/pages/intent/IntentOnboarding.d.ts +0 -67
- package/console/dist/ui/pages/intent/IntentOnboarding.js +0 -289
- package/console/dist/ui/pages/intent/IntentPage.d.ts +0 -1
- package/console/dist/ui/pages/intent/IntentPage.js +0 -252
- package/console/dist/ui/pages/pain/PainEvidenceValidators.d.ts +0 -59
- package/console/dist/ui/pages/pain/PainEvidenceValidators.js +0 -125
- package/console/dist/ui/pages/pain/PainPage.d.ts +0 -1
- package/console/dist/ui/pages/pain/PainPage.js +0 -420
- package/console/dist/ui/pages/pain/pain-card-helpers.d.ts +0 -175
- package/console/dist/ui/pages/pain/pain-card-helpers.js +0 -181
- package/console/dist/ui/pages/principles/CorePrinciplesPage.d.ts +0 -10
- package/console/dist/ui/pages/principles/CorePrinciplesPage.js +0 -59
- package/console/dist/ui/pages/principles/PrincipleDetailPage.d.ts +0 -60
- package/console/dist/ui/pages/principles/PrincipleDetailPage.js +0 -602
- package/console/dist/ui/pages/principles/PrinciplesPage.d.ts +0 -1
- package/console/dist/ui/pages/principles/PrinciplesPage.js +0 -327
- package/console/dist/ui/pages/principles/PrinciplesViewNav.d.ts +0 -8
- package/console/dist/ui/pages/principles/PrinciplesViewNav.js +0 -15
- package/console/dist/ui/pages/report-problem/ReportProblemPage.d.ts +0 -1
- package/console/dist/ui/pages/report-problem/ReportProblemPage.js +0 -467
- package/console/dist/ui/pages/settings/SettingsPage.d.ts +0 -4
- package/console/dist/ui/pages/settings/SettingsPage.js +0 -457
- package/console/dist/ui/pages/settings/UpdatePage.d.ts +0 -1
- package/console/dist/ui/pages/settings/UpdatePage.js +0 -215
- package/console/dist/ui/pages/welcome/WelcomePage.d.ts +0 -5
- package/console/dist/ui/pages/welcome/WelcomePage.js +0 -187
- package/console/dist/ui/utils/agent-metadata.d.ts +0 -71
- package/console/dist/ui/utils/agent-metadata.js +0 -284
- package/console/dist/ui/utils/approval-review.d.ts +0 -30
- package/console/dist/ui/utils/approval-review.js +0 -50
- package/console/dist/ui/utils/approval-warning-localization.d.ts +0 -34
- package/console/dist/ui/utils/approval-warning-localization.js +0 -148
- package/console/dist/ui/utils/attention-presentation.d.ts +0 -35
- package/console/dist/ui/utils/attention-presentation.js +0 -46
- package/console/dist/ui/utils/blocker-localization.d.ts +0 -23
- package/console/dist/ui/utils/blocker-localization.js +0 -36
- package/console/dist/ui/utils/control-center-helpers.d.ts +0 -79
- package/console/dist/ui/utils/control-center-helpers.js +0 -189
- package/console/dist/ui/utils/enum-labels.d.ts +0 -50
- package/console/dist/ui/utils/enum-labels.js +0 -171
- package/console/dist/ui/utils/format-date.d.ts +0 -11
- package/console/dist/ui/utils/format-date.js +0 -17
- package/console/dist/ui/utils/onboarding-state.d.ts +0 -25
- package/console/dist/ui/utils/onboarding-state.js +0 -77
- package/console/dist/ui/utils/reading-layout.d.ts +0 -20
- package/console/dist/ui/utils/reading-layout.js +0 -46
- package/console/dist/ui/utils/rule-binding-validators.d.ts +0 -13
- package/console/dist/ui/utils/rule-binding-validators.js +0 -188
- package/console/dist/ui/utils/runtime-mode.d.ts +0 -11
- package/console/dist/ui/utils/runtime-mode.js +0 -11
- package/console/dist/ui/utils/token-storage.d.ts +0 -22
- package/console/dist/ui/utils/token-storage.js +0 -47
- package/console/dist/ui/utils/validators.d.ts +0 -1178
- package/console/dist/ui/utils/validators.js +0 -3297
- package/release-manager/dist/bootstrap-entry.d.ts +0 -2
- package/release-manager/dist/bootstrap-entry.d.ts.map +0 -1
- package/release-manager/dist/bootstrap-entry.js.map +0 -1
- package/release-manager/dist/i18n.d.ts +0 -6
- package/release-manager/dist/i18n.d.ts.map +0 -1
- package/release-manager/dist/i18n.js.map +0 -1
- package/release-manager/dist/index.d.ts +0 -7
- package/release-manager/dist/index.d.ts.map +0 -1
- package/release-manager/dist/index.js +0 -656
- package/release-manager/dist/index.js.map +0 -1
- package/release-manager/dist/installer.d.ts +0 -629
- package/release-manager/dist/installer.d.ts.map +0 -1
- package/release-manager/dist/installer.js.map +0 -1
- package/release-manager/dist/installers/codex-host-installer.d.ts +0 -39
- package/release-manager/dist/installers/codex-host-installer.d.ts.map +0 -1
- package/release-manager/dist/installers/codex-host-installer.js.map +0 -1
- package/release-manager/dist/installers/index.d.ts +0 -51
- package/release-manager/dist/installers/index.d.ts.map +0 -1
- package/release-manager/dist/installers/index.js.map +0 -1
- package/release-manager/dist/installers/openclaw-host-installer.d.ts +0 -14
- package/release-manager/dist/installers/openclaw-host-installer.d.ts.map +0 -1
- package/release-manager/dist/installers/openclaw-host-installer.js.map +0 -1
- package/release-manager/dist/installers/workbuddy-host-installer.d.ts +0 -335
- package/release-manager/dist/installers/workbuddy-host-installer.d.ts.map +0 -1
- package/release-manager/dist/installers/workbuddy-host-installer.js.map +0 -1
- package/release-manager/dist/mvp-config.d.ts +0 -233
- package/release-manager/dist/mvp-config.d.ts.map +0 -1
- package/release-manager/dist/mvp-config.js.map +0 -1
- package/release-manager/dist/prompts.d.ts +0 -43
- package/release-manager/dist/prompts.d.ts.map +0 -1
- package/release-manager/dist/prompts.js +0 -268
- package/release-manager/dist/prompts.js.map +0 -1
- package/release-manager/dist/skill-language.d.ts +0 -32
- package/release-manager/dist/skill-language.d.ts.map +0 -1
- package/release-manager/dist/skill-language.js.map +0 -1
- package/release-manager/dist/uninstaller.d.ts +0 -68
- package/release-manager/dist/uninstaller.d.ts.map +0 -1
- package/release-manager/dist/uninstaller.js +0 -746
- package/release-manager/dist/uninstaller.js.map +0 -1
- package/release-manager/dist/update/apply-payload.d.ts +0 -143
- package/release-manager/dist/update/apply-payload.d.ts.map +0 -1
- package/release-manager/dist/update/apply-payload.js.map +0 -1
- package/release-manager/dist/update/atomic-file.d.ts +0 -35
- package/release-manager/dist/update/atomic-file.d.ts.map +0 -1
- package/release-manager/dist/update/atomic-file.js.map +0 -1
- package/release-manager/dist/update/bootstrap-executor.d.ts +0 -21
- package/release-manager/dist/update/bootstrap-executor.d.ts.map +0 -1
- package/release-manager/dist/update/bootstrap-executor.js.map +0 -1
- package/release-manager/dist/update/bootstrap-protocol.d.ts +0 -56
- package/release-manager/dist/update/bootstrap-protocol.d.ts.map +0 -1
- package/release-manager/dist/update/bootstrap-protocol.js.map +0 -1
- package/release-manager/dist/update/channel-metadata.d.ts +0 -28
- package/release-manager/dist/update/channel-metadata.d.ts.map +0 -1
- package/release-manager/dist/update/channel-metadata.js.map +0 -1
- package/release-manager/dist/update/channel-promotion.d.ts +0 -39
- package/release-manager/dist/update/channel-promotion.d.ts.map +0 -1
- package/release-manager/dist/update/channel-promotion.js +0 -55
- package/release-manager/dist/update/channel-promotion.js.map +0 -1
- package/release-manager/dist/update/console-surface.d.ts +0 -19
- package/release-manager/dist/update/console-surface.d.ts.map +0 -1
- package/release-manager/dist/update/console-surface.js.map +0 -1
- package/release-manager/dist/update/data-compatibility.d.ts +0 -35
- package/release-manager/dist/update/data-compatibility.d.ts.map +0 -1
- package/release-manager/dist/update/data-compatibility.js +0 -45
- package/release-manager/dist/update/data-compatibility.js.map +0 -1
- package/release-manager/dist/update/install-layout.d.ts +0 -105
- package/release-manager/dist/update/install-layout.d.ts.map +0 -1
- package/release-manager/dist/update/install-layout.js.map +0 -1
- package/release-manager/dist/update/product-identity.d.ts +0 -70
- package/release-manager/dist/update/product-identity.d.ts.map +0 -1
- package/release-manager/dist/update/product-identity.js.map +0 -1
- package/release-manager/dist/update/release-asset-manifest.d.ts +0 -31
- package/release-manager/dist/update/release-asset-manifest.d.ts.map +0 -1
- package/release-manager/dist/update/release-asset-manifest.js.map +0 -1
- package/release-manager/dist/update/release-identity.d.ts +0 -33
- package/release-manager/dist/update/release-identity.d.ts.map +0 -1
- package/release-manager/dist/update/release-identity.js.map +0 -1
- package/release-manager/dist/update/release-manager-authority.d.ts +0 -39
- package/release-manager/dist/update/release-manager-authority.d.ts.map +0 -1
- package/release-manager/dist/update/release-manager-authority.js.map +0 -1
- package/release-manager/dist/update/release-manager.d.ts +0 -156
- package/release-manager/dist/update/release-manager.d.ts.map +0 -1
- package/release-manager/dist/update/release-manager.js.map +0 -1
- package/release-manager/dist/update/release-metadata-publisher.d.ts +0 -199
- package/release-manager/dist/update/release-metadata-publisher.d.ts.map +0 -1
- package/release-manager/dist/update/release-metadata-publisher.js +0 -478
- package/release-manager/dist/update/release-metadata-publisher.js.map +0 -1
- package/release-manager/dist/update/release-metadata-source.d.ts +0 -85
- package/release-manager/dist/update/release-metadata-source.d.ts.map +0 -1
- package/release-manager/dist/update/release-metadata-source.js.map +0 -1
- package/release-manager/dist/update/release-metadata.d.ts +0 -60
- package/release-manager/dist/update/release-metadata.d.ts.map +0 -1
- package/release-manager/dist/update/release-metadata.js.map +0 -1
- package/release-manager/dist/update/release-policy.d.ts +0 -51
- package/release-manager/dist/update/release-policy.d.ts.map +0 -1
- package/release-manager/dist/update/release-policy.js.map +0 -1
- package/release-manager/dist/update/rollback-policy.d.ts +0 -56
- package/release-manager/dist/update/rollback-policy.d.ts.map +0 -1
- package/release-manager/dist/update/rollback-policy.js +0 -61
- package/release-manager/dist/update/rollback-policy.js.map +0 -1
- package/release-manager/dist/update/transaction-journal.d.ts +0 -212
- package/release-manager/dist/update/transaction-journal.d.ts.map +0 -1
- package/release-manager/dist/update/transaction-journal.js.map +0 -1
- package/release-manager/dist/update/trust-metadata.d.ts +0 -55
- package/release-manager/dist/update/trust-metadata.d.ts.map +0 -1
- package/release-manager/dist/update/trust-metadata.js.map +0 -1
- package/release-manager/dist/update/trust-root-provisioning.d.ts +0 -99
- package/release-manager/dist/update/trust-root-provisioning.d.ts.map +0 -1
- package/release-manager/dist/update/trust-root-provisioning.js.map +0 -1
- package/release-manager/dist/update/update-history.d.ts +0 -46
- package/release-manager/dist/update/update-history.d.ts.map +0 -1
- package/release-manager/dist/update/update-history.js +0 -123
- package/release-manager/dist/update/update-history.js.map +0 -1
- package/release-manager/dist/utils/config-file-io.d.ts +0 -34
- package/release-manager/dist/utils/config-file-io.d.ts.map +0 -1
- package/release-manager/dist/utils/config-file-io.js.map +0 -1
- package/release-manager/dist/utils/env.d.ts +0 -94
- package/release-manager/dist/utils/env.d.ts.map +0 -1
- package/release-manager/dist/utils/env.js.map +0 -1
- package/release-manager/dist/utils/logger.d.ts +0 -15
- package/release-manager/dist/utils/logger.d.ts.map +0 -1
- package/release-manager/dist/utils/logger.js.map +0 -1
- package/release-manager/dist/utils/workspace-divergence.d.ts +0 -36
- package/release-manager/dist/utils/workspace-divergence.d.ts.map +0 -1
- package/release-manager/dist/utils/workspace-divergence.js.map +0 -1
|
@@ -1,111 +0,0 @@
|
|
|
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, governanceReady = true, actionsLockedReason, }) {
|
|
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 [partialEvidenceAcknowledged, setPartialEvidenceAcknowledged] = useState(false);
|
|
22
|
-
const isTaskDecision = item.kind === "evaluator_review" || item.kind === "rollout_review";
|
|
23
|
-
const canAccept = item.allowedActions.includes("accept_current");
|
|
24
|
-
const canRevise = item.allowedActions.includes("revise_once");
|
|
25
|
-
const canReject = item.allowedActions.includes("reject_current");
|
|
26
|
-
const requiresPartialAcknowledgement = item.review?.capability.acceptRequirement.kind === "acknowledge_partial_evidence";
|
|
27
|
-
const evidenceUnavailable = item.evidenceUnavailableReason !== undefined;
|
|
28
|
-
// PRI-798 P1-2: when accept is unavailable the copy must name the actual
|
|
29
|
-
// reason — the adversarial hard gate, a missing activation candidate, or
|
|
30
|
-
// insufficient review evidence are different situations with different next
|
|
31
|
-
// actions. Discriminate on the structured reason codes, never on !canAccept.
|
|
32
|
-
const acceptBlockedCopy = (() => {
|
|
33
|
-
const acceptRequirement = item.review?.capability.acceptRequirement;
|
|
34
|
-
if (acceptRequirement?.kind === "forbidden" &&
|
|
35
|
-
(acceptRequirement.reasonCode === "adversarial_hard_gate_failed" ||
|
|
36
|
-
acceptRequirement.reasonCode === "adversarial_hard_gate_not_passed")) {
|
|
37
|
-
return t("pages.focus.ownerDecision.acceptBlockedHardGate");
|
|
38
|
-
}
|
|
39
|
-
if (item.reasonCode === "rollout_activation_candidate_unresolved") {
|
|
40
|
-
return t("pages.focus.ownerDecision.acceptBlockedNoCandidate");
|
|
41
|
-
}
|
|
42
|
-
return t("pages.focus.ownerDecision.acceptBlockedGeneric");
|
|
43
|
-
})();
|
|
44
|
-
async function handleAction(action) {
|
|
45
|
-
if (action === "revise_once" && showInstruction && instruction.trim().length === 0) {
|
|
46
|
-
// 指导为空也可以提交 — instruction 是可选的;这里仅在展开输入后要求非空确认
|
|
47
|
-
// (避免误提交空指导),Owner 可收起输入直接提交。
|
|
48
|
-
toast.error(t("pages.focus.ownerDecision.instructionRequired"));
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
setActionLoading(action);
|
|
52
|
-
try {
|
|
53
|
-
const response = await resolveOwnerDecision(item.taskId, {
|
|
54
|
-
action,
|
|
55
|
-
reviewKey: item.reviewKey,
|
|
56
|
-
expectedRevisionEpoch: item.expectedRevisionEpoch,
|
|
57
|
-
expectedSourceRunId: item.expectedSourceRunId,
|
|
58
|
-
expectedSourceArtifactId: item.expectedSourceArtifactId,
|
|
59
|
-
expectedSourceArtifactHash: item.expectedSourceArtifactHash,
|
|
60
|
-
expectedEvidenceDigest: item.expectedEvidenceDigest ?? "",
|
|
61
|
-
...(action === "accept_current" && requiresPartialAcknowledgement && partialEvidenceAcknowledged
|
|
62
|
-
? { acknowledgement: { kind: "partial_evidence", acknowledged: true } }
|
|
63
|
-
: {}),
|
|
64
|
-
...(action === "revise_once" && instruction.trim().length > 0
|
|
65
|
-
? { ownerInstruction: instruction.trim() }
|
|
66
|
-
: { ownerInstruction: null }),
|
|
67
|
-
});
|
|
68
|
-
if (!response.success) {
|
|
69
|
-
if (response.error === "stale_owner_decision") {
|
|
70
|
-
toast.error(t("pages.focus.ownerDecision.staleError"));
|
|
71
|
-
}
|
|
72
|
-
else if (response.error === "already_resolved") {
|
|
73
|
-
toast.info(t("pages.focus.ownerDecision.alreadyResolved"));
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
toast.error(response.error ?? t("pages.focus.ownerDecision.actionFailed"));
|
|
77
|
-
}
|
|
78
|
-
onResolved();
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
toast.success(t("pages.focus.ownerDecision.resolved"));
|
|
82
|
-
onResolved();
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
toast.error(t("pages.focus.ownerDecision.actionFailed"));
|
|
86
|
-
}
|
|
87
|
-
finally {
|
|
88
|
-
setActionLoading(null);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
const kindLabel = item.kind === "rollout_review"
|
|
92
|
-
? t("pages.focus.ownerDecision.kindRollout")
|
|
93
|
-
: item.kind === "activation_approval"
|
|
94
|
-
? t("pages.focus.ownerDecision.kindApproval")
|
|
95
|
-
: item.kind === "rulecode_decision"
|
|
96
|
-
? t("pages.focus.ownerDecision.kindRulecode")
|
|
97
|
-
: t("pages.focus.ownerDecision.kindEvaluator");
|
|
98
|
-
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.formationEvidence && (_jsxs("div", { className: "mt-1 rounded-[3px] border border-line bg-surface-2 p-2", "data-testid": `owner-formation-evidence-${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.formationLabel") }), item.review.brief.formationEvidence.sourcePainId ? (_jsxs("p", { className: "text-ink-2", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.ownerDecision.formationPainLabel") }), " ", _jsx("span", { className: "font-mono text-[11.5px]", children: item.review.brief.formationEvidence.sourcePainId })] })) : null, item.review.brief.formationEvidence.diagnosis?.summary && (_jsxs("p", { className: "text-ink-2", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.ownerDecision.formationDiagnosisLabel") }), " ", item.review.brief.formationEvidence.diagnosis.summary] })), item.review.brief.formationEvidence.diagnosis?.rootCause && (_jsxs("p", { className: "text-ink-2", children: [_jsx("span", { className: "font-medium", children: t("pages.focus.ownerDecision.formationRootCauseLabel") }), " ", item.review.brief.formationEvidence.diagnosis.rootCause] })), (item.review.brief.formationEvidence.diagnosis?.evidence.length ?? 0) > 0 && (_jsxs("div", { children: [_jsx("span", { className: "font-medium text-ink-2", children: t("pages.focus.ownerDecision.formationEvidenceLabel") }), _jsx("ul", { className: "mt-0.5 grid gap-0.5 text-[12px] text-ink-3", children: item.review.brief.formationEvidence.diagnosis?.evidence.slice(0, 3).map((row, index) => (_jsxs("li", { children: [_jsx("span", { className: "font-mono text-[11px]", children: row.sourceRef }), " ", row.note] }, `${row.sourceRef}-${index}`))) })] })), !item.review.brief.formationEvidence.diagnosis && (_jsx("p", { className: "text-ink-3", children: t("pages.focus.ownerDecision.formationUnavailableNote") }))] }))] })), item.review && (_jsxs("div", { className: "mb-2 flex flex-wrap items-center 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}`) }), _jsxs("details", { "data-testid": `owner-checks-${item.taskId}`, children: [_jsx("summary", { className: "cursor-pointer text-ink-4 hover:text-ink-3", children: t("pages.focus.ownerDecision.checksDisclosure") }), _jsx("div", { className: "mt-1 flex flex-wrap gap-2", children: 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-tasks?taskId=${encodeURIComponent(item.taskId)}`, "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") })] })), !governanceReady && actionsLockedReason && (_jsxs("div", { className: "mt-3 rounded-[3px] border border-amber/40 bg-amber/5 p-3", "data-testid": `owner-actions-locked-${item.taskId}`, children: [_jsx("p", { className: "text-ink-2 text-[12.5px] leading-relaxed", children: actionsLockedReason }), _jsx(Link, { to: "/settings", "data-testid": `owner-actions-locked-settings-${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.goSettingsCta") })] })), _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: () => {
|
|
99
|
-
if (!showInstruction) {
|
|
100
|
-
setShowInstruction(true);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
void handleAction("revise_once");
|
|
104
|
-
}, disabled: !governanceReady || 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: !governanceReady || 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: canAccept
|
|
105
|
-
? t("pages.focus.ownerDecision.actionConsequence")
|
|
106
|
-
: acceptBlockedCopy }), _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] }), item.review?.brief.requiredChanges.map((change, index) => (_jsxs("div", { children: ["requiredChange: ", change] }, `${change}-${index}`))), item.review?.evidence.items.map((evidence, index) => (_jsxs("div", { children: [evidence.evidenceClass, "/", evidence.label, ": ", evidence.value] }, `${evidence.label}-${index}`))), item.review?.brief.kind === "evaluator" && item.review.brief.formationEvidence && (_jsxs(_Fragment, { children: [_jsxs("div", { children: ["dreamerArtifact: ", item.review.brief.formationEvidence.provenance.sourceDreamerArtifactId] }), item.review.brief.formationEvidence.provenance.sourceDiagnosisArtifactId && (_jsxs("div", { children: ["diagnosisArtifact: ", item.review.brief.formationEvidence.provenance.sourceDiagnosisArtifactId] })), item.review.brief.formationEvidence.notes.map((note, index) => (_jsxs("div", { children: ["formationNote: ", note] }, `${note}-${index}`)))] }))] }))] })) : (_jsxs("div", { className: "mt-2", children: [_jsx("p", { className: "text-ink-4 text-[12px] mb-2", children: item.kind === "activation_approval"
|
|
107
|
-
? t("pages.focus.ownerDecision.approvalHint")
|
|
108
|
-
: t("pages.focus.ownerDecision.rulecodeHint") }), item.kind === "activation_approval" ? (_jsx(Link, { to: item.principleId !== undefined
|
|
109
|
-
? `/principles/${encodeURIComponent(item.principleId)}`
|
|
110
|
-
: "/principles", "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?activationId=${encodeURIComponent(item.taskId)}`, "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") }))] }))] }));
|
|
111
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
2
|
-
export type OwnerWorkItemKind = 'prompt' | 'rule' | 'promotion' | 'revision' | 'validation' | 'binding' | 'archive' | 'approval' | 'unknown';
|
|
3
|
-
export interface OwnerWorkItem {
|
|
4
|
-
key: string;
|
|
5
|
-
title: string;
|
|
6
|
-
kind: OwnerWorkItemKind;
|
|
7
|
-
summary: string;
|
|
8
|
-
reference?: string;
|
|
9
|
-
content: ReactNode;
|
|
10
|
-
}
|
|
11
|
-
/** Presentation only: list grouping never changes an action's identity or authority. */
|
|
12
|
-
export declare function OwnerWorkbench({ items, completed, uncertain }: {
|
|
13
|
-
items: OwnerWorkItem[];
|
|
14
|
-
completed: {
|
|
15
|
-
key: string;
|
|
16
|
-
message: string;
|
|
17
|
-
} | null;
|
|
18
|
-
uncertain: boolean;
|
|
19
|
-
}): import("react").JSX.Element;
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useRef } from 'react';
|
|
3
|
-
import { useSearchParams } from 'react-router-dom';
|
|
4
|
-
import { useTranslation } from 'react-i18next';
|
|
5
|
-
import { Archive, CircleHelp, ClipboardCheck, Code2, FilePenLine, FlaskConical, Link2, MessageSquareText, ShieldCheck } from 'lucide-react';
|
|
6
|
-
// Type describes the decision, not an inferred urgency or permission.
|
|
7
|
-
const KIND_PRESENTATION = {
|
|
8
|
-
prompt: { icon: MessageSquareText, label: 'promptReview', style: 'border-gov/30 bg-gov/10 text-gov' },
|
|
9
|
-
rule: { icon: Code2, label: 'ruleReview', style: 'border-ink-3/30 bg-ink-3/10 text-ink-2' },
|
|
10
|
-
promotion: { icon: ShieldCheck, label: 'rulePromotion', style: 'border-amber/30 bg-amber/10 text-ink-2' },
|
|
11
|
-
revision: { icon: FilePenLine, label: 'revisionDecision', style: 'border-amber/30 text-ink-2' },
|
|
12
|
-
validation: { icon: FlaskConical, label: 'validationReview', style: 'border-gov/30 text-gov' },
|
|
13
|
-
binding: { icon: Link2, label: 'bindingReview', style: 'border-gov/30 text-gov' },
|
|
14
|
-
archive: { icon: Archive, label: 'archiveReview', style: 'border-line bg-surface text-ink-3' },
|
|
15
|
-
approval: { icon: ClipboardCheck, label: 'approvalMaterialReview', style: 'border-line text-ink-2' },
|
|
16
|
-
unknown: { icon: CircleHelp, label: 'unknownReview', style: 'border-line text-ink-3' },
|
|
17
|
-
};
|
|
18
|
-
function WorkItemType({ kind }) {
|
|
19
|
-
const { t } = useTranslation();
|
|
20
|
-
const { icon: Icon, label, style } = KIND_PRESENTATION[kind];
|
|
21
|
-
return _jsxs("span", { "data-testid": "owner-work-type", "data-kind": kind, className: `inline-flex max-w-full items-center gap-1.5 rounded-[4px] border px-2 py-1 text-[11px] font-medium leading-relaxed ${style}`, children: [_jsx(Icon, { "aria-hidden": "true", className: "h-3.5 w-3.5 shrink-0", strokeWidth: 1.75 }), t(`pages.focus.workbench.${label}`)] });
|
|
22
|
-
}
|
|
23
|
-
/** Presentation only: list grouping never changes an action's identity or authority. */
|
|
24
|
-
export function OwnerWorkbench({ items, completed, uncertain }) {
|
|
25
|
-
const { t } = useTranslation();
|
|
26
|
-
const [params, setParams] = useSearchParams();
|
|
27
|
-
const selectedKey = params.get('review') ?? '';
|
|
28
|
-
const selected = items.find(item => item.key === selectedKey);
|
|
29
|
-
const heading = useRef(null);
|
|
30
|
-
const list = useRef(null);
|
|
31
|
-
const lastSelected = useRef('');
|
|
32
|
-
const listScroll = useRef(0);
|
|
33
|
-
// A deep link can arrive before the items do. `focusKey` only becomes the
|
|
34
|
-
// selection once the item exists, so the effect re-runs when it appears
|
|
35
|
-
// without stealing focus on every data refresh.
|
|
36
|
-
const focusKey = selected ? selectedKey : '';
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
if (focusKey) {
|
|
39
|
-
heading.current?.focus({ preventScroll: true });
|
|
40
|
-
const reading = heading.current?.closest('[data-testid="owner-work-reading"]');
|
|
41
|
-
if (reading && (reading.getBoundingClientRect().top < 0 || reading.getBoundingClientRect().top > window.innerHeight - 100))
|
|
42
|
-
reading.scrollIntoView({ block: 'start' });
|
|
43
|
-
const current = list.current?.querySelector('[aria-current="true"]');
|
|
44
|
-
if (current && list.current && list.current.scrollHeight > list.current.clientHeight) {
|
|
45
|
-
list.current.scrollTop = Math.max(0, current.offsetTop - list.current.offsetTop - 24);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
else if (selectedKey) {
|
|
49
|
-
heading.current?.focus({ preventScroll: true });
|
|
50
|
-
}
|
|
51
|
-
else if (lastSelected.current && list.current) {
|
|
52
|
-
list.current.scrollTop = listScroll.current;
|
|
53
|
-
const previous = Array.from(list.current.querySelectorAll('[data-item-key]')).find(button => button.dataset.itemKey === lastSelected.current);
|
|
54
|
-
previous?.focus({ preventScroll: true });
|
|
55
|
-
if (previous && (previous.getBoundingClientRect().top < 0 || previous.getBoundingClientRect().bottom > window.innerHeight))
|
|
56
|
-
previous.scrollIntoView({ block: 'nearest' });
|
|
57
|
-
}
|
|
58
|
-
}, [focusKey, selectedKey]);
|
|
59
|
-
function choose(key) {
|
|
60
|
-
if (!key && selectedKey) {
|
|
61
|
-
lastSelected.current = selectedKey;
|
|
62
|
-
listScroll.current = list.current?.scrollTop ?? 0;
|
|
63
|
-
}
|
|
64
|
-
const next = new URLSearchParams(params);
|
|
65
|
-
if (key)
|
|
66
|
-
next.set('review', key);
|
|
67
|
-
else
|
|
68
|
-
next.delete('review');
|
|
69
|
-
setParams(next, { preventScrollReset: true });
|
|
70
|
-
}
|
|
71
|
-
const completedHere = completed?.key === selectedKey ? completed : null;
|
|
72
|
-
const selectedIndex = items.findIndex(item => item.key === selectedKey);
|
|
73
|
-
const nextItem = selectedIndex >= 0 ? items[selectedIndex + 1] : undefined;
|
|
74
|
-
return _jsxs("section", { className: "owner-workbench", "data-testid": "owner-workbench", children: [_jsxs("nav", { ref: list, tabIndex: -1, className: `owner-work-list ${selected ? 'owner-work-list-selected' : ''}`, "aria-label": t('pages.focus.workbench.list'), children: [_jsxs("div", { className: "mb-3 flex items-baseline justify-between gap-3", children: [_jsx("h2", { className: "text-[15px] font-medium text-ink", children: t('pages.focus.workbench.list') }), _jsx("span", { className: "text-[12px] text-ink-4", children: t('pages.focus.workbench.count', { count: items.length }) })] }), items.length === 0 && _jsx("p", { className: "text-sm leading-relaxed text-ink-3", children: t(uncertain ? 'pages.focus.workbench.uncertain' : 'pages.focus.workbench.empty') }), _jsx("ol", { className: "space-y-2", children: items.map(item => _jsx("li", { children: _jsxs("button", { type: "button", onClick: () => choose(item.key), "aria-current": selected?.key === item.key ? 'true' : undefined, "data-testid": "owner-work-item", "data-item-key": item.key, className: `w-full rounded-[6px] border px-4 py-4 text-left transition-colors focus-visible:outline-2 focus-visible:outline-gov ${selected?.key === item.key ? 'border-gov bg-gov/5' : 'border-line bg-panel hover:border-gov/50'}`, children: [_jsx("span", { className: "mb-3 block", children: _jsx(WorkItemType, { kind: item.kind }) }), _jsx("span", { className: "block text-[14px] font-medium leading-relaxed text-ink break-words", children: item.title }), _jsx("span", { className: "mt-2 block text-[12.5px] leading-relaxed text-ink-3 line-clamp-2", children: item.summary }), item.reference && items.some(other => other.key !== item.key && other.title === item.title && other.summary === item.summary) && _jsx("span", { className: "mt-2 block break-all font-mono text-[11px] text-ink-4", children: item.reference })] }) }, item.key)) })] }), _jsx("div", { className: "owner-work-reading min-w-0", "data-testid": "owner-work-reading", children: selected ? _jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "mb-5 text-[13px] text-gov underline underline-offset-4", onClick: () => choose(''), children: t('pages.focus.workbench.back') }), _jsx("div", { className: "mb-3", children: _jsx(WorkItemType, { kind: selected.kind }) }), _jsx("h2", { ref: heading, tabIndex: -1, className: "mb-6 text-[22px] font-semibold leading-snug text-ink break-words", children: selected.title }), _jsx("div", { children: selected.content }, selected.key), _jsxs("footer", { className: "mt-7 border-t border-line pt-5", children: [_jsx("p", { className: "mb-3 text-[12.5px] text-ink-3", children: t('pages.focus.workbench.readingEnd') }), nextItem && _jsx("button", { type: "button", className: "text-[13px] text-gov underline underline-offset-4", onClick: () => choose(nextItem.key), children: t('pages.focus.workbench.next') })] })] }) : _jsxs("div", { className: "py-10 text-ink-3", children: [_jsx("h2", { ref: heading, tabIndex: -1, className: "mb-3 text-[22px] font-medium text-ink", children: t(completedHere ? 'pages.focus.workbench.completed' : selectedKey ? 'pages.focus.workbench.notCurrent' : 'pages.focus.workbench.startTitle') }), _jsx("p", { role: completedHere ? 'status' : undefined, className: "max-w-[440px] text-[14px] leading-relaxed", children: completedHere?.message ?? t(selectedKey ? 'pages.focus.workbench.notCurrentBody' : 'pages.focus.workbench.startBody') }), items[0] && _jsx("button", { type: "button", className: "mt-6 rounded-[4px] border border-gov bg-gov px-4 py-2.5 text-sm text-paper", onClick: () => choose(items[0].key), children: t(completedHere ? 'pages.focus.workbench.next' : 'pages.focus.workbench.start') })] }) })] });
|
|
75
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { RuleBindingQueueItem } from '../../../shared/rule-candidate-binding-contract.js';
|
|
2
|
-
export type RuleBindingCardState = 'awaiting_owner' | 'bound_generating' | 'bound_blocked' | 'bound_advanced' | 'bound_not_built' | 'bound_ambiguous' | 'revoked' | 'attention';
|
|
3
|
-
/** ERR-106: exhaustive display map over the card state union — no default branch. */
|
|
4
|
-
export declare const RULE_BINDING_CARD_STATE_KEY: Record<RuleBindingCardState, string>;
|
|
5
|
-
export declare const RULE_BINDING_CARD_STATE_CLASS: Record<RuleBindingCardState, string>;
|
|
6
|
-
export declare function deriveRuleBindingCardState(item: RuleBindingQueueItem): RuleBindingCardState;
|
|
7
|
-
export interface RuleBindingPainGroup {
|
|
8
|
-
key: string;
|
|
9
|
-
pain: RuleBindingQueueItem['pain'];
|
|
10
|
-
items: RuleBindingQueueItem[];
|
|
11
|
-
}
|
|
12
|
-
/** Group by canonical pain id; a missing pain id gets its own per-candidate
|
|
13
|
-
* group so unattributable candidates never vanish into someone else's group. */
|
|
14
|
-
export declare function groupRuleBindingQueue(items: RuleBindingQueueItem[]): RuleBindingPainGroup[];
|
|
15
|
-
/** The resume action may only appear when the real backend says ready AND the
|
|
16
|
-
* chain is not currently running — a revision during an active run would be
|
|
17
|
-
* a fake retry, not the bounded source revision. */
|
|
18
|
-
export declare function canOfferRuleBindingResume(item: RuleBindingQueueItem): boolean;
|
|
19
|
-
/**
|
|
20
|
-
* PRI-1048 R6 #4: the source-correction entry applies when the bounded
|
|
21
|
-
* source-correction budget is available on a bound+blocked chain — the shape
|
|
22
|
-
* where the binding revision budget is typically already spent (the 52d
|
|
23
|
-
* production candidate). Real eligibility is resolved server-side
|
|
24
|
-
* (previewRuleSourceCorrection); click-time authority is reviseRuleSourceOnce.
|
|
25
|
-
*/
|
|
26
|
-
export declare function canOfferSourceCorrection(item: Pick<RuleBindingQueueItem, 'binding' | 'generation' | 'sourceCorrection'>): boolean;
|
|
27
|
-
/** Model-synthesized fallback sources must stay localized (CodeRabbit PRI-1048:
|
|
28
|
-
* `unknown` previously fell through to raw English in the zh-CN group header). */
|
|
29
|
-
export declare const PAIN_SOURCE_KEY: Record<string, string>;
|
|
30
|
-
/** Inline in Governance Focus; assignment, rule approval and live promotion remain separate. */
|
|
31
|
-
export declare function RuleCandidateBindingPanel({ candidateId, onChanged }?: {
|
|
32
|
-
candidateId?: string;
|
|
33
|
-
onChanged?: () => void;
|
|
34
|
-
}): import("react").JSX.Element | null;
|
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
3
|
-
import { useTranslation } from 'react-i18next';
|
|
4
|
-
import { Link } from 'react-router-dom';
|
|
5
|
-
import { fetchRuleBindingQueue, fetchRuleBindingReview, mutateRuleBinding, reviseRuleBindingOnce, correctRuleSource } from '../../api.js';
|
|
6
|
-
import { splitReadingTitleBody } from '../../utils/reading-layout.js';
|
|
7
|
-
/**
|
|
8
|
-
* PRI-1048 治理焦点「规则的正式原则归属」队列。
|
|
9
|
-
* 按痛苦信号分组的有界卡片列表;每张卡默认回答三问:
|
|
10
|
-
* 这是哪次反馈 / 现在卡在哪 / 我要做什么。技术 ID 与原始 JSON 只进「技术详情」。
|
|
11
|
-
* 归属、规则审批、激活三权分立不变(文案见 separate/declaration)。
|
|
12
|
-
*/
|
|
13
|
-
/** Collapsed first screen shows at most this many pain groups. */
|
|
14
|
-
const COLLAPSED_GROUP_LIMIT = 3;
|
|
15
|
-
/** ERR-106: exhaustive display map over the card state union — no default branch. */
|
|
16
|
-
export const RULE_BINDING_CARD_STATE_KEY = {
|
|
17
|
-
awaiting_owner: 'pages.focus.ruleBinding.stateAwaitingOwner',
|
|
18
|
-
bound_generating: 'pages.focus.ruleBinding.stateBoundGenerating',
|
|
19
|
-
bound_blocked: 'pages.focus.ruleBinding.stateBoundBlocked',
|
|
20
|
-
bound_advanced: 'pages.focus.ruleBinding.stateBoundAdvanced',
|
|
21
|
-
bound_not_built: 'pages.focus.ruleBinding.stateBoundNotBuilt',
|
|
22
|
-
bound_ambiguous: 'pages.focus.ruleBinding.stateBoundAmbiguous',
|
|
23
|
-
revoked: 'pages.focus.ruleBinding.stateRevoked',
|
|
24
|
-
attention: 'pages.focus.ruleBinding.stateAttention',
|
|
25
|
-
};
|
|
26
|
-
export const RULE_BINDING_CARD_STATE_CLASS = {
|
|
27
|
-
awaiting_owner: 'border-gov/40 text-gov',
|
|
28
|
-
bound_generating: 'border-green/40 text-green',
|
|
29
|
-
bound_blocked: 'border-amber/45 text-amber',
|
|
30
|
-
bound_advanced: 'border-green/40 text-green',
|
|
31
|
-
bound_not_built: 'border-line text-ink-3',
|
|
32
|
-
bound_ambiguous: 'border-amber/45 text-amber',
|
|
33
|
-
revoked: 'border-line text-ink-3',
|
|
34
|
-
attention: 'border-amber/45 text-amber',
|
|
35
|
-
};
|
|
36
|
-
export function deriveRuleBindingCardState(item) {
|
|
37
|
-
switch (item.binding.status) {
|
|
38
|
-
case 'unlinked': return 'awaiting_owner';
|
|
39
|
-
case 'binding_revoked': return 'revoked';
|
|
40
|
-
case 'attention': return 'attention';
|
|
41
|
-
case 'bound':
|
|
42
|
-
switch (item.generation?.stage) {
|
|
43
|
-
case null:
|
|
44
|
-
case undefined:
|
|
45
|
-
case 'not_built': return 'bound_not_built';
|
|
46
|
-
case 'in_progress': return 'bound_generating';
|
|
47
|
-
case 'blocked': return 'bound_blocked';
|
|
48
|
-
case 'advanced': return 'bound_advanced';
|
|
49
|
-
case 'ambiguous': return 'bound_ambiguous';
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
/** Group by canonical pain id; a missing pain id gets its own per-candidate
|
|
54
|
-
* group so unattributable candidates never vanish into someone else's group. */
|
|
55
|
-
export function groupRuleBindingQueue(items) {
|
|
56
|
-
const groups = new Map();
|
|
57
|
-
for (const item of items) {
|
|
58
|
-
const key = item.pain.painId === '' ? `candidate:${item.candidateId}` : item.pain.painId;
|
|
59
|
-
const group = groups.get(key) ?? { key, pain: item.pain, items: [] };
|
|
60
|
-
group.items.push(item);
|
|
61
|
-
groups.set(key, group);
|
|
62
|
-
}
|
|
63
|
-
return [...groups.values()];
|
|
64
|
-
}
|
|
65
|
-
/** The resume action may only appear when the real backend says ready AND the
|
|
66
|
-
* chain is not currently running — a revision during an active run would be
|
|
67
|
-
* a fake retry, not the bounded source revision. */
|
|
68
|
-
export function canOfferRuleBindingResume(item) {
|
|
69
|
-
return item.binding.status === 'bound'
|
|
70
|
-
&& item.resume?.status === 'ready'
|
|
71
|
-
&& item.generation?.stage !== 'in_progress'
|
|
72
|
-
&& item.generation?.stage !== 'ambiguous';
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* PRI-1048 R6 #4: the source-correction entry applies when the bounded
|
|
76
|
-
* source-correction budget is available on a bound+blocked chain — the shape
|
|
77
|
-
* where the binding revision budget is typically already spent (the 52d
|
|
78
|
-
* production candidate). Real eligibility is resolved server-side
|
|
79
|
-
* (previewRuleSourceCorrection); click-time authority is reviseRuleSourceOnce.
|
|
80
|
-
*/
|
|
81
|
-
export function canOfferSourceCorrection(item) {
|
|
82
|
-
return item.binding.status === 'bound'
|
|
83
|
-
&& item.generation?.stage === 'blocked'
|
|
84
|
-
&& item.sourceCorrection?.status === 'ready';
|
|
85
|
-
}
|
|
86
|
-
/** ERR-106: next-step copy and the left bar also use exhaustive maps. */
|
|
87
|
-
const RULE_BINDING_NEXT_STEP_KEY = {
|
|
88
|
-
awaiting_owner: 'pages.focus.ruleBinding.nextAwaitingOwner',
|
|
89
|
-
bound_generating: 'pages.focus.ruleBinding.nextBoundGenerating',
|
|
90
|
-
bound_blocked: 'pages.focus.ruleBinding.nextBoundBlocked',
|
|
91
|
-
bound_advanced: 'pages.focus.ruleBinding.nextBoundAdvanced',
|
|
92
|
-
bound_not_built: 'pages.focus.ruleBinding.nextBoundNotBuilt',
|
|
93
|
-
bound_ambiguous: 'pages.focus.ruleBinding.nextBoundAmbiguous',
|
|
94
|
-
revoked: 'pages.focus.ruleBinding.nextRevoked',
|
|
95
|
-
attention: 'pages.focus.ruleBinding.nextAttention',
|
|
96
|
-
};
|
|
97
|
-
const RULE_BINDING_CARD_STATE_BAR = {
|
|
98
|
-
awaiting_owner: 'bg-gov',
|
|
99
|
-
bound_generating: 'bg-green',
|
|
100
|
-
bound_blocked: 'bg-amber',
|
|
101
|
-
bound_advanced: 'bg-green',
|
|
102
|
-
bound_not_built: 'bg-line-2',
|
|
103
|
-
bound_ambiguous: 'bg-amber',
|
|
104
|
-
revoked: 'bg-line-2',
|
|
105
|
-
attention: 'bg-amber',
|
|
106
|
-
};
|
|
107
|
-
/** Model-synthesized fallback sources must stay localized (CodeRabbit PRI-1048:
|
|
108
|
-
* `unknown` previously fell through to raw English in the zh-CN group header). */
|
|
109
|
-
export const PAIN_SOURCE_KEY = {
|
|
110
|
-
unreadable: 'pages.focus.ruleBinding.sourceUnreadable',
|
|
111
|
-
unknown: 'pages.focus.ruleBinding.sourceUnknown',
|
|
112
|
-
manual: 'pages.focus.ruleBinding.sourceManual',
|
|
113
|
-
tool_failure: 'pages.focus.ruleBinding.sourceToolFailure',
|
|
114
|
-
};
|
|
115
|
-
const STAGE_KIND_KEY = {
|
|
116
|
-
dreamer: 'pages.focus.ruleBinding.stageDreamer',
|
|
117
|
-
philosopher: 'pages.focus.ruleBinding.stagePhilosopher',
|
|
118
|
-
scribe: 'pages.focus.ruleBinding.stageScribe',
|
|
119
|
-
artificer: 'pages.focus.ruleBinding.stageArtificer',
|
|
120
|
-
evaluator: 'pages.focus.ruleBinding.stageEvaluator',
|
|
121
|
-
rollout_reviewer: 'pages.focus.ruleBinding.stageRolloutReviewer',
|
|
122
|
-
};
|
|
123
|
-
/** i18n with graceful fallback to the raw server code (visible, not dropped). */
|
|
124
|
-
function codeText(t, prefix, code) {
|
|
125
|
-
if (!code)
|
|
126
|
-
return '';
|
|
127
|
-
const key = `${prefix}.${code}`;
|
|
128
|
-
const text = t(key);
|
|
129
|
-
return text === key ? code : text;
|
|
130
|
-
}
|
|
131
|
-
function painSourceLabel(t, source) {
|
|
132
|
-
const key = PAIN_SOURCE_KEY[source];
|
|
133
|
-
return key ? t(key) : source;
|
|
134
|
-
}
|
|
135
|
-
function stageKindLabel(t, stageKind) {
|
|
136
|
-
if (!stageKind)
|
|
137
|
-
return null;
|
|
138
|
-
const key = STAGE_KIND_KEY[stageKind];
|
|
139
|
-
return key ? t(key) : stageKind;
|
|
140
|
-
}
|
|
141
|
-
/** Inline in Governance Focus; assignment, rule approval and live promotion remain separate. */
|
|
142
|
-
export function RuleCandidateBindingPanel({ candidateId, onChanged } = {}) {
|
|
143
|
-
const { t } = useTranslation();
|
|
144
|
-
const [queue, setQueue] = useState(null);
|
|
145
|
-
const [review, setReview] = useState(null);
|
|
146
|
-
const [openCandidateId, setOpenCandidateId] = useState('');
|
|
147
|
-
const [search, setSearch] = useState('');
|
|
148
|
-
const [selectedId, setSelectedId] = useState('');
|
|
149
|
-
const [reason, setReason] = useState('');
|
|
150
|
-
const [busy, setBusy] = useState(false);
|
|
151
|
-
const [message, setMessage] = useState('');
|
|
152
|
-
const [error, setError] = useState('');
|
|
153
|
-
const [showAllGroups, setShowAllGroups] = useState(false);
|
|
154
|
-
useEffect(() => {
|
|
155
|
-
let active = true;
|
|
156
|
-
void fetchRuleBindingQueue().then(result => {
|
|
157
|
-
if (!active)
|
|
158
|
-
return;
|
|
159
|
-
if (result.success)
|
|
160
|
-
setQueue(result.data);
|
|
161
|
-
else
|
|
162
|
-
setError([result.error, result.nextAction].filter(Boolean).join(' ') || t('pages.focus.ruleBinding.unavailable'));
|
|
163
|
-
});
|
|
164
|
-
return () => { active = false; };
|
|
165
|
-
}, [t]);
|
|
166
|
-
async function load(candidateId, query = '') {
|
|
167
|
-
setBusy(true);
|
|
168
|
-
setError('');
|
|
169
|
-
const result = await fetchRuleBindingReview(candidateId, query);
|
|
170
|
-
if (result.success) {
|
|
171
|
-
setReview(result.data);
|
|
172
|
-
setOpenCandidateId(candidateId);
|
|
173
|
-
setSelectedId('');
|
|
174
|
-
}
|
|
175
|
-
else
|
|
176
|
-
setError([result.error, result.nextAction].filter(Boolean).join(' ') || t('pages.focus.ruleBinding.unavailable'));
|
|
177
|
-
setBusy(false);
|
|
178
|
-
}
|
|
179
|
-
useEffect(() => { if (candidateId)
|
|
180
|
-
void load(candidateId); }, [candidateId]);
|
|
181
|
-
function closeReview() { setOpenCandidateId(''); setReview(null); setSearch(''); setReason(''); }
|
|
182
|
-
async function refreshQueue() {
|
|
183
|
-
const result = await fetchRuleBindingQueue();
|
|
184
|
-
if (result.success) {
|
|
185
|
-
setQueue(result.data);
|
|
186
|
-
onChanged?.();
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
async function decide(action) {
|
|
190
|
-
if (!review)
|
|
191
|
-
return;
|
|
192
|
-
const target = review.eligibleTargets.find(p => p.principleId === selectedId);
|
|
193
|
-
if (action === 'bind' && !target)
|
|
194
|
-
return;
|
|
195
|
-
setBusy(true);
|
|
196
|
-
setError('');
|
|
197
|
-
setMessage('');
|
|
198
|
-
const requestId = crypto.randomUUID();
|
|
199
|
-
const common = { expectedRevision: review.currentRevision, reason, requestId };
|
|
200
|
-
const result = await mutateRuleBinding(review.candidateId, action === 'bind' && target
|
|
201
|
-
? { ...common, action: 'bind', resumeOnce: true, principleId: target.principleId, expectedCandidateDigest: review.candidateDigest, expectedPrincipleDigest: target.digest }
|
|
202
|
-
: { ...common, action: 'revoke', resumeOnce: false });
|
|
203
|
-
if (result.success) {
|
|
204
|
-
setMessage(action === 'revoke' ? t('pages.focus.ruleBinding.revoked')
|
|
205
|
-
: result.data.revisionStatus === 'refused' ? t('pages.focus.ruleBinding.resumeFailed') : t('pages.focus.ruleBinding.bound'));
|
|
206
|
-
await load(review.candidateId, search);
|
|
207
|
-
await refreshQueue();
|
|
208
|
-
}
|
|
209
|
-
else
|
|
210
|
-
setError([result.error, result.nextAction].filter(Boolean).join(' ') || t('pages.focus.ruleBinding.unavailable'));
|
|
211
|
-
setBusy(false);
|
|
212
|
-
}
|
|
213
|
-
/** Only reachable when the real resolver said ready (canOfferRuleBindingResume). */
|
|
214
|
-
async function revise() {
|
|
215
|
-
if (!review?.resume || review.resume.status !== 'ready' || review.resume.scribeTaskId === null || review.resume.taskRevisionEpoch === null)
|
|
216
|
-
return;
|
|
217
|
-
setBusy(true);
|
|
218
|
-
setError('');
|
|
219
|
-
setMessage('');
|
|
220
|
-
const result = await reviseRuleBindingOnce(review.candidateId, {
|
|
221
|
-
expectedBindingRevision: review.currentRevision,
|
|
222
|
-
expectedScribeTaskId: review.resume.scribeTaskId,
|
|
223
|
-
expectedTaskRevisionEpoch: review.resume.taskRevisionEpoch,
|
|
224
|
-
requestId: crypto.randomUUID(),
|
|
225
|
-
});
|
|
226
|
-
if (result.success) {
|
|
227
|
-
setMessage(result.data.status === 'revision_already_started'
|
|
228
|
-
? t('pages.focus.ruleBinding.reviseAlreadyStarted')
|
|
229
|
-
: t('pages.focus.ruleBinding.reviseStarted'));
|
|
230
|
-
await load(review.candidateId, search);
|
|
231
|
-
await refreshQueue();
|
|
232
|
-
}
|
|
233
|
-
else
|
|
234
|
-
setError([result.error, result.nextAction].filter(Boolean).join(' ') || t('pages.focus.ruleBinding.unavailable'));
|
|
235
|
-
setBusy(false);
|
|
236
|
-
}
|
|
237
|
-
/** PRI-1048 R6 #4: only reachable when the server preview said ready
|
|
238
|
-
* (canOfferSourceCorrection); the server re-validates every CAS input. */
|
|
239
|
-
async function correctSource() {
|
|
240
|
-
const preview = review?.sourceCorrection;
|
|
241
|
-
if (!review || !preview || preview.status !== 'ready'
|
|
242
|
-
|| preview.scribeTaskId === null || preview.artificerTaskId === null
|
|
243
|
-
|| preview.scribeArtifactDigest === null || preview.expectedBindingRevision === null)
|
|
244
|
-
return;
|
|
245
|
-
setBusy(true);
|
|
246
|
-
setError('');
|
|
247
|
-
setMessage('');
|
|
248
|
-
const result = await correctRuleSource(review.candidateId, {
|
|
249
|
-
expectedBindingRevision: preview.expectedBindingRevision,
|
|
250
|
-
expectedScribeTaskId: preview.scribeTaskId,
|
|
251
|
-
expectedArtificerTaskId: preview.artificerTaskId,
|
|
252
|
-
expectedScribeArtifactDigest: preview.scribeArtifactDigest,
|
|
253
|
-
reason,
|
|
254
|
-
requestId: crypto.randomUUID(),
|
|
255
|
-
});
|
|
256
|
-
if (result.success) {
|
|
257
|
-
setMessage(result.data.status === 'revision_already_started'
|
|
258
|
-
? t('pages.focus.ruleBinding.sourceCorrectionAlreadyStarted')
|
|
259
|
-
: t('pages.focus.ruleBinding.sourceCorrectionStarted'));
|
|
260
|
-
await load(review.candidateId, search);
|
|
261
|
-
await refreshQueue();
|
|
262
|
-
}
|
|
263
|
-
else
|
|
264
|
-
setError([result.error, result.nextAction].filter(Boolean).join(' ') || t('pages.focus.ruleBinding.unavailable'));
|
|
265
|
-
setBusy(false);
|
|
266
|
-
}
|
|
267
|
-
if ((queue === null || queue.items.length === 0) && !error)
|
|
268
|
-
return null;
|
|
269
|
-
const groups = groupRuleBindingQueue((queue?.items ?? []).filter(item => candidateId === undefined || item.candidateId === candidateId));
|
|
270
|
-
const visibleGroups = showAllGroups ? groups : groups.slice(0, COLLAPSED_GROUP_LIMIT);
|
|
271
|
-
const bound = review?.currentBinding?.action === 'bind';
|
|
272
|
-
return _jsxs("section", { className: "mb-7 rounded border border-line p-4", "data-testid": "rule-binding-panel", "aria-label": t('pages.focus.ruleBinding.title'), children: [_jsx("h2", { className: "text-sm font-medium", children: t('pages.focus.ruleBinding.title') }), _jsx("p", { className: "mt-2 text-sm text-ink-3", children: t('pages.focus.ruleBinding.separate') }), queue && _jsx("p", { className: "mt-2 text-[13px] text-ink-3", role: "status", "data-testid": "rule-binding-counts", children: t('pages.focus.ruleBinding.countsLine', { candidates: queue.summary.candidates, painGroups: queue.summary.painGroups, bound: queue.summary.bound, unlinked: queue.summary.unlinked, blocked: queue.summary.blocked }) }), queue?.truncated && _jsx("p", { className: "mt-1 text-[12.5px] text-amber", children: t('pages.focus.ruleBinding.truncatedNote', { count: queue.items.length }) }), error && _jsx("p", { role: "alert", className: "my-2 text-amber", children: error }), message && _jsx("p", { role: "status", className: "my-2", children: message }), visibleGroups.map(group => _jsxs("div", { className: "mt-4", "data-testid": "rule-binding-pain-group", children: [_jsxs("div", { className: "border-l-2 border-line pl-3", children: [_jsxs("div", { className: "text-[13px] text-ink-2 leading-relaxed", children: [_jsx("span", { className: "font-medium text-ink", children: t('pages.focus.ruleBinding.groupPrefix') }), ' ', group.pain.text
|
|
273
|
-
? splitReadingTitleBody(group.pain.text).title
|
|
274
|
-
: t('pages.focus.ruleBinding.painUnrecorded')] }), _jsxs("div", { className: "mt-0.5 text-[11.5px] text-ink-4", children: [painSourceLabel(t, group.pain.source), group.pain.createdAt ? ` · ${group.pain.createdAt.slice(0, 10)}` : '', ' · ', t('pages.focus.ruleBinding.groupCount', { count: group.items.length })] })] }), group.items.map(item => {
|
|
275
|
-
const cardState = deriveRuleBindingCardState(item);
|
|
276
|
-
const layout = splitReadingTitleBody(item.text);
|
|
277
|
-
const open = openCandidateId === item.candidateId;
|
|
278
|
-
return _jsxs("article", { className: "relative mt-3 pl-[22px] py-[14px] pr-[18px] bg-panel border border-line rounded-[6px]", "data-testid": `rule-binding-card-${item.candidateId}`, children: [_jsx("div", { className: `absolute left-0 top-0 bottom-0 w-[3px] rounded-l-[6px] ${RULE_BINDING_CARD_STATE_BAR[cardState]}` }), _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx("span", { className: `inline-flex items-center border rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase ${RULE_BINDING_CARD_STATE_CLASS[cardState]}`, children: t(RULE_BINDING_CARD_STATE_KEY[cardState]) }), (() => {
|
|
279
|
-
const stageLabel = stageKindLabel(t, item.generation?.stageKind ?? null);
|
|
280
|
-
return stageLabel
|
|
281
|
-
? _jsxs("span", { className: "text-[11.5px] text-ink-4", children: [t('pages.focus.ruleBinding.currentStage'), stageLabel] })
|
|
282
|
-
: null;
|
|
283
|
-
})()] }), _jsx("div", { className: "mt-[10px] mb-1 font-semibold text-ink leading-snug", "data-testid": `rule-binding-title-${item.candidateId}`, children: layout.title }), layout.body !== null && _jsx("div", { className: "mb-2 text-[14px] leading-relaxed text-ink-2 whitespace-pre-wrap break-words", children: layout.body }), item.binding.status === 'bound' && _jsxs("div", { className: "mt-2 px-3 py-2 bg-surface/60 border-l-2 border-gov text-[13px] leading-relaxed", children: [_jsx("span", { className: "text-ink-3", children: t('pages.focus.ruleBinding.boundTo') }), ' ', _jsx("span", { className: "text-ink", children: splitReadingTitleBody(item.binding.principle.text).title }), ' · ', _jsxs("span", { className: "text-ink-4", children: [t(`principles.status${item.binding.principle.status[0]?.toUpperCase()}${item.binding.principle.status.slice(1)}`, { defaultValue: item.binding.principle.status }), " \u00B7 ", t('pages.focus.ruleBinding.version'), " ", item.binding.principle.version] }), ' · ', _jsx(Link, { to: `/principles/${item.binding.principle.principleId}`, className: "text-gov underline", children: t('pages.focus.ruleBinding.viewPrinciple') })] }), cardState === 'bound_blocked' && item.generation && _jsxs("div", { className: "mt-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `rule-binding-blocked-${item.candidateId}`, children: [t('pages.focus.ruleBinding.blockedLine', {
|
|
284
|
-
stage: stageKindLabel(t, item.generation.stageKind) ?? '',
|
|
285
|
-
reason: codeText(t, 'pages.focus.ruleBinding.blockReason', item.generation.reasonCode) || t('pages.focus.ruleBinding.blockReasonUnknown'),
|
|
286
|
-
}), _jsx("div", { className: "mt-0.5 text-ink-3", children: t('pages.focus.ruleBinding.blockedNoOwnerApproval') }), item.generation.detail && _jsxs("details", { className: "mt-1 text-[11.5px]", children: [_jsx("summary", { className: "cursor-pointer select-none", children: t('pages.focus.ruleBinding.blockedDetail') }), _jsx("pre", { className: "mt-1 max-h-40 overflow-auto whitespace-pre-wrap break-words font-mono text-[11px]", children: item.generation.detail })] })] }), cardState === 'attention' && _jsx("div", { className: "mt-2 text-[12.5px] leading-relaxed text-amber", "data-testid": `rule-binding-attention-${item.candidateId}`, children: t('pages.focus.ruleBinding.attentionLine', { reason: item.binding.status === 'attention' ? item.binding.reason : '' }) }), _jsxs("div", { className: "mt-2 text-[12.5px] text-ink-3 leading-relaxed", "data-testid": `rule-binding-next-${item.candidateId}`, children: [_jsx("span", { className: "font-medium", children: t('pages.focus.ruleBinding.nextLabel') }), ' ', cardState === 'bound_blocked' && item.resume?.status === 'refused'
|
|
287
|
-
? t('pages.focus.ruleBinding.nextBoundBlockedNoResume', { reason: codeText(t, 'pages.focus.ruleBinding.resumeReason', item.resume.reason) })
|
|
288
|
-
: t(RULE_BINDING_NEXT_STEP_KEY[cardState])] }), _jsxs("details", { className: "mt-2 text-[11.5px] text-ink-4", children: [_jsx("summary", { className: "cursor-pointer select-none", children: t('pages.focus.ruleBinding.techDetails') }), _jsxs("dl", { className: "mt-1 font-mono text-[11px] break-all", children: [_jsxs("div", { children: ["candidateId: ", item.candidateId] }), _jsxs("div", { children: ["painId: ", item.pain.painId || '—'] }), item.binding.status === 'bound' && _jsxs("div", { children: ["bindingRevision: ", item.binding.principle.revision, " \u00B7 decidedAt: ", item.binding.principle.decidedAt || '—'] }), item.resume && _jsxs("div", { children: ["resume: ", item.resume.status, item.resume.reason ? ` (${item.resume.reason})` : '', item.resume.scribeTaskId ? ` · ${item.resume.scribeTaskId}` : ''] })] })] }), _jsx("button", { type: "button", className: "mt-3 inline-flex items-center border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed", disabled: busy, "aria-expanded": open, onClick: () => { if (open)
|
|
289
|
-
closeReview();
|
|
290
|
-
else {
|
|
291
|
-
setSearch('');
|
|
292
|
-
setReason('');
|
|
293
|
-
void load(item.candidateId);
|
|
294
|
-
} }, children: open ? t('pages.focus.ruleBinding.closeReview') : t('pages.focus.ruleBinding.openReview') }), open && review && review.candidateId === item.candidateId && _jsxs("div", { className: "mt-4 border-t border-line pt-3", children: [_jsx("h3", { className: "font-medium text-[13px]", children: t('pages.focus.ruleBinding.candidate') }), _jsx("p", { className: "mt-1 whitespace-pre-wrap text-sm", children: review.candidateText }), _jsxs("p", { className: "mt-2 text-sm", children: [t('pages.focus.ruleBinding.pain'), "\uFF1A", review.sourcePain.text ?? t('pages.focus.ruleBinding.painUnrecorded')] }), _jsxs("details", { className: "mt-2 text-sm", children: [_jsx("summary", { children: t('pages.focus.ruleBinding.evidence') }), _jsx("pre", { className: "whitespace-pre-wrap break-words", children: review.evidence })] }), bound && review.boundPrinciple && _jsxs(_Fragment, { children: [_jsxs("div", { className: "mt-3 px-3 py-2 bg-surface/60 border-l-2 border-gov text-[13px] leading-relaxed", children: [_jsx("div", { className: "whitespace-pre-wrap", children: review.boundPrinciple.text }), _jsxs("div", { className: "mt-1 text-ink-4", children: [t('pages.focus.ruleBinding.boundSince', { revision: review.boundPrinciple.revision, date: review.boundPrinciple.decidedAt.slice(0, 10) || '—' }), " \u00B7 ", _jsx(Link, { to: `/principles/${review.boundPrinciple.principleId}`, className: "text-gov underline", children: t('pages.focus.ruleBinding.viewPrinciple') })] })] }), canOfferRuleBindingResume({ ...item, resume: review.resume }) && _jsx("button", { type: "button", className: "mt-3 rounded border border-gov bg-gov text-paper px-3 py-2 text-sm disabled:opacity-50", disabled: busy, onClick: () => void revise(), children: t('pages.focus.ruleBinding.reviseCta') }), canOfferSourceCorrection({ ...item, sourceCorrection: review.sourceCorrection }) && _jsx("button", { type: "button", className: "mt-3 ml-2 rounded border border-gov bg-gov text-paper px-3 py-2 text-sm disabled:opacity-50", disabled: busy || !reason.trim(), "data-testid": "rule-binding-source-correct-cta", onClick: () => void correctSource(), children: t('pages.focus.ruleBinding.sourceCorrectionCta') }), review.resume?.status === 'refused' && _jsx("p", { className: "mt-3 text-[12.5px] text-ink-3 leading-relaxed", children: t('pages.focus.ruleBinding.resumeUnavailable', { reason: codeText(t, 'pages.focus.ruleBinding.resumeReason', review.resume.reason) }) }), review.generation?.stage === 'blocked' && review.sourceCorrection?.status === 'unavailable' && _jsx("p", { className: "mt-2 text-[12.5px] text-ink-4 leading-relaxed", children: t('pages.focus.ruleBinding.sourceCorrectionUnavailable', { reason: review.sourceCorrection.reason ?? '' }) }), review.generation?.stage === 'in_progress' && _jsx("p", { className: "mt-3 text-[12.5px] text-ink-3", children: t('pages.focus.ruleBinding.nextBoundGenerating') })] }), !bound && _jsxs(_Fragment, { children: [_jsx("p", { className: "mt-3 text-sm text-ink-3", children: t('pages.focus.ruleBinding.chooseTarget') }), _jsxs("form", { className: "mt-3 flex gap-2", onSubmit: event => { event.preventDefault(); void load(review.candidateId, search); }, children: [_jsx("input", { value: search, onChange: event => setSearch(event.target.value), maxLength: 200, "aria-label": t('pages.focus.ruleBinding.search'), className: "border border-line p-2 text-sm" }), _jsx("button", { disabled: busy, type: "submit", children: t('pages.focus.ruleBinding.search') })] }), review.eligibleTargets.length === 0 && _jsxs("p", { className: "mt-2 text-sm", children: [t('pages.focus.ruleBinding.noTarget'), " ", _jsx(Link, { to: "/principles", className: "underline", children: t('pages.focus.ruleBinding.formation') })] }), review.eligibleTargets.map(target => _jsxs("label", { className: "my-3 block border border-line p-3 text-sm", children: [_jsx("input", { type: "radio", name: "binding-target", value: target.principleId, checked: selectedId === target.principleId, onChange: () => setSelectedId(target.principleId) }), _jsxs("span", { className: "ml-2", children: [t(`principles.status${target.status[0]?.toUpperCase()}${target.status.slice(1)}`, { defaultValue: target.status }), " \u00B7 ", t('pages.focus.ruleBinding.version'), " ", target.version] }), _jsx("p", { className: "mt-2 whitespace-pre-wrap", children: target.text })] }, target.principleId)), _jsx("p", { className: "mt-3 text-sm text-ink-3", children: review.resumeNotice }), _jsx("p", { className: "mt-2 text-sm", children: t('pages.focus.ruleBinding.declaration') })] }), _jsxs("label", { className: "mt-3 block text-sm", children: [t('pages.focus.ruleBinding.reason'), _jsx("textarea", { className: "mt-1 block w-full border border-line p-2", maxLength: 2000, value: reason, onChange: event => setReason(event.target.value) })] }), _jsxs("div", { className: "mt-3 flex gap-2 flex-wrap", children: [!bound && _jsx("button", { type: "button", className: "rounded border border-gov px-3 py-2 text-sm disabled:opacity-50", disabled: busy || !reason.trim() || !selectedId, onClick: () => void decide('bind'), children: t('pages.focus.ruleBinding.bind') }), bound && _jsx("button", { type: "button", className: "rounded border border-line px-3 py-2 text-sm disabled:opacity-50", disabled: busy || !reason.trim(), onClick: () => void decide('revoke'), children: t('pages.focus.ruleBinding.revokeSecondary') })] }), _jsxs("p", { className: "mt-3 text-sm text-ink-3", children: [t('pages.focus.ruleBinding.revokeBoundary'), " ", _jsx(Link, { to: "/activation", className: "underline", children: t('pages.focus.ruleBinding.stop') })] })] })] }, item.candidateId);
|
|
295
|
-
})] }, group.key)), groups.length > COLLAPSED_GROUP_LIMIT && _jsx("button", { type: "button", className: "mt-3 text-[12.5px] text-gov underline", onClick: () => setShowAllGroups(value => !value), "aria-expanded": showAllGroups, "data-testid": "rule-binding-groups-toggle", children: showAllGroups
|
|
296
|
-
? t('pages.focus.ruleBinding.hideRemaining')
|
|
297
|
-
: t('pages.focus.ruleBinding.viewRemaining', { count: groups.length - COLLAPSED_GROUP_LIMIT }) })] });
|
|
298
|
-
}
|