create-principles-disciple 1.145.34 → 1.145.36

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 (95) hide show
  1. package/_release/product-identity.json +2 -2
  2. package/console/dist/server/models/ApprovalsConsoleModel.d.ts +22 -2
  3. package/console/dist/server/models/ApprovalsConsoleModel.js +56 -16
  4. package/console/dist/server/models/ApprovalsGroupedConsoleModel.d.ts +8 -0
  5. package/console/dist/server/models/ApprovalsGroupedConsoleModel.js +3 -2
  6. package/console/dist/server/models/approval-review-material.d.ts +15 -0
  7. package/console/dist/server/models/approval-review-material.js +32 -0
  8. package/console/dist/server/routes/approvals.js +32 -7
  9. package/console/dist/ui/api.d.ts +8 -2
  10. package/console/dist/ui/api.js +8 -4
  11. package/console/dist/ui/i18n/en.json +98 -7
  12. package/console/dist/ui/i18n/zh-CN.json +98 -7
  13. package/console/dist/ui/pages/focus/ApprovalSubjectReading.d.ts +24 -0
  14. package/console/dist/ui/pages/focus/ApprovalSubjectReading.js +133 -0
  15. package/console/dist/ui/pages/focus/FocusPage.d.ts +5 -26
  16. package/console/dist/ui/pages/focus/FocusPage.js +166 -459
  17. package/console/dist/ui/pages/focus/OwnerWorkbench.d.ts +19 -0
  18. package/console/dist/ui/pages/focus/OwnerWorkbench.js +75 -0
  19. package/console/dist/ui/pages/focus/RuleCandidateBindingPanel.d.ts +4 -1
  20. package/console/dist/ui/pages/focus/RuleCandidateBindingPanel.js +7 -3
  21. package/console/dist/ui/pages/focus/focus-validation.js +31 -0
  22. package/console/dist/ui/pages/principles/PrincipleDetailPage.js +110 -86
  23. package/console/dist/ui/pages/principles/PrinciplesPage.js +39 -30
  24. package/console/dist/ui/utils/approval-review.d.ts +30 -0
  25. package/console/dist/ui/utils/approval-review.js +50 -0
  26. package/console/dist/ui/utils/reading-layout.d.ts +1 -0
  27. package/console/dist/ui/utils/reading-layout.js +1 -1
  28. package/console/dist/ui/utils/validators.d.ts +4 -0
  29. package/console/dist/ui/utils/validators.js +10 -2
  30. package/console/dist/web/assets/app.css +119 -11
  31. package/console/dist/web/assets/app.js +40 -30
  32. package/core/dist/runtime-v2/activation/activation-types.d.ts +12 -2
  33. package/core/dist/runtime-v2/activation/activation-types.d.ts.map +1 -1
  34. package/core/dist/runtime-v2/activation/activation-types.js.map +1 -1
  35. package/core/dist/runtime-v2/activation/approval-queue.d.ts +3 -2
  36. package/core/dist/runtime-v2/activation/approval-queue.d.ts.map +1 -1
  37. package/core/dist/runtime-v2/activation/approval-queue.js +6 -4
  38. package/core/dist/runtime-v2/activation/approval-queue.js.map +1 -1
  39. package/core/dist/runtime-v2/activation/approval-review-guard.d.ts +26 -0
  40. package/core/dist/runtime-v2/activation/approval-review-guard.d.ts.map +1 -0
  41. package/core/dist/runtime-v2/activation/approval-review-guard.js +25 -0
  42. package/core/dist/runtime-v2/activation/approval-review-guard.js.map +1 -0
  43. package/core/dist/runtime-v2/activation/memory-approval-store.d.ts +6 -2
  44. package/core/dist/runtime-v2/activation/memory-approval-store.d.ts.map +1 -1
  45. package/core/dist/runtime-v2/activation/memory-approval-store.js +26 -2
  46. package/core/dist/runtime-v2/activation/memory-approval-store.js.map +1 -1
  47. package/core/dist/runtime-v2/activation/sqlite-approval-store.d.ts +6 -2
  48. package/core/dist/runtime-v2/activation/sqlite-approval-store.d.ts.map +1 -1
  49. package/core/dist/runtime-v2/activation/sqlite-approval-store.js +59 -2
  50. package/core/dist/runtime-v2/activation/sqlite-approval-store.js.map +1 -1
  51. package/core/dist/runtime-v2/diagnostician-association-shadow.d.ts +24 -0
  52. package/core/dist/runtime-v2/diagnostician-association-shadow.d.ts.map +1 -0
  53. package/core/dist/runtime-v2/diagnostician-association-shadow.js +84 -0
  54. package/core/dist/runtime-v2/diagnostician-association-shadow.js.map +1 -0
  55. package/core/dist/runtime-v2/diagnostician-association-validation.d.ts +18 -0
  56. package/core/dist/runtime-v2/diagnostician-association-validation.d.ts.map +1 -0
  57. package/core/dist/runtime-v2/diagnostician-association-validation.js +47 -0
  58. package/core/dist/runtime-v2/diagnostician-association-validation.js.map +1 -0
  59. package/core/dist/runtime-v2/diagnostician-output.d.ts +123 -0
  60. package/core/dist/runtime-v2/diagnostician-output.d.ts.map +1 -1
  61. package/core/dist/runtime-v2/diagnostician-output.js +41 -0
  62. package/core/dist/runtime-v2/diagnostician-output.js.map +1 -1
  63. package/core/dist/runtime-v2/index.d.ts +2 -0
  64. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  65. package/core/dist/runtime-v2/index.js +1 -0
  66. package/core/dist/runtime-v2/index.js.map +1 -1
  67. package/core/dist/runtime-v2/internalization/diag-router-runner.d.ts +12 -1
  68. package/core/dist/runtime-v2/internalization/diag-router-runner.d.ts.map +1 -1
  69. package/core/dist/runtime-v2/internalization/diag-router-runner.js +50 -2
  70. package/core/dist/runtime-v2/internalization/diag-router-runner.js.map +1 -1
  71. package/core/dist/runtime-v2/internalization/router-context-evidence.d.ts +45 -0
  72. package/core/dist/runtime-v2/internalization/router-context-evidence.d.ts.map +1 -0
  73. package/core/dist/runtime-v2/internalization/router-context-evidence.js +64 -0
  74. package/core/dist/runtime-v2/internalization/router-context-evidence.js.map +1 -0
  75. package/core/dist/runtime-v2/signal-collector/types.d.ts +8 -0
  76. package/core/dist/runtime-v2/signal-collector/types.d.ts.map +1 -1
  77. package/core/dist/runtime-v2/signal-collector/types.js.map +1 -1
  78. package/core/package.json +1 -1
  79. package/package.json +2 -2
  80. package/pd-cli/dist/commands/config-doctor.js +1 -1
  81. package/pd-cli/dist/commands/config-doctor.js.map +1 -1
  82. package/pd-cli/dist/services/config-doctor.d.ts +2 -0
  83. package/pd-cli/dist/services/config-doctor.d.ts.map +1 -1
  84. package/pd-cli/dist/services/config-doctor.js +1 -0
  85. package/pd-cli/dist/services/config-doctor.js.map +1 -1
  86. package/pd-cli/package.json +1 -1
  87. package/plugin/dist/bundle.js +462 -462
  88. package/plugin/dist/core/signal-collector-host.d.ts +9 -0
  89. package/plugin/dist/core/signal-health.d.ts +6 -0
  90. package/plugin/dist/core/trajectory.d.ts +8 -0
  91. package/plugin/dist/openclaw.plugin.json +1 -1
  92. package/plugin/dist/rulehost-evidence.js +6 -6
  93. package/plugin/openclaw.plugin.json +1 -1
  94. package/plugin/package.json +1 -1
  95. package/release-manager/package.json +2 -2
@@ -1,18 +1,19 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect, useCallback } from "react";
3
- import { useParams, useNavigate, Link } from "react-router-dom";
2
+ import { useState, useEffect, useCallback, useRef } from "react";
3
+ import { useParams, useNavigate, useLocation, Link } from "react-router-dom";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import { toast } from "sonner";
6
6
  import { PageShell } from "../../components/layout/page-shell.js";
7
7
  import { PageLoading } from "../../components/layout/page-loading.js";
8
8
  import { SectionTitle } from "../../components/layout/section-title.js";
9
9
  import { Button } from "../../components/ui/button.js";
10
- import { fetchPrincipleDetail, fetchApprovalsGrouped, fetchLifecycleMetrics, fetchPrincipleTrajectory, fetchPrincipleGovernance, fetchPrincipleReceipts, fetchEvidenceAudit, fetchOwnerDecisionView, approveApproval, rejectApproval, editApproval, disableActivation, } from "../../api.js";
10
+ import { fetchPrincipleDetail, fetchApprovalsGrouped, fetchLifecycleMetrics, fetchPrincipleTrajectory, fetchPrincipleGovernance, fetchPrincipleReceipts, fetchEvidenceAudit, fetchOwnerDecisionView, disableActivation, } from "../../api.js";
11
+ import { ApprovalSubjectReading } from "../focus/ApprovalSubjectReading.js";
11
12
  import { ReceiptCoverageDisclosure, getReceiptSourceStatusLabelKey } from "../../components/receipts/ReceiptCoverageDisclosure.js";
12
13
  import { formatDate } from "../../utils/format-date.js";
13
14
  import { localizeAggregatedBlocker } from "../../utils/blocker-localization.js";
14
15
  import { groupByReasonCode, formatGroupedReasonLine } from "../../utils/attention-presentation.js";
15
- import { splitReadingTitleBody } from "../../utils/reading-layout.js";
16
+ import { splitReadingTitleBody, truncateByCodePoints } from "../../utils/reading-layout.js";
16
17
  // ── Runtime validation (H section) ──────────────────────────────────────────
17
18
  function isString(v) {
18
19
  return typeof v === "string";
@@ -217,8 +218,13 @@ export function PrincipleDetailPage() {
217
218
  const { t, i18n } = useTranslation("pages");
218
219
  const { id } = useParams();
219
220
  const navigate = useNavigate();
221
+ const location = useLocation();
222
+ const navigationState = location.state;
223
+ const requestedReturn = navigationState !== null && typeof navigationState === 'object' && Object.hasOwn(navigationState, 'returnTo') ? Reflect.get(navigationState, 'returnTo') : null;
224
+ const returnTo = typeof requestedReturn === 'string' && (requestedReturn === '/principles' || requestedReturn.startsWith('/principles?') || requestedReturn === '/focus' || requestedReturn.startsWith('/focus?')) ? requestedReturn : '/principles';
220
225
  const [principle, setPrinciple] = useState(null);
221
226
  const [approvalGroup, setApprovalGroup] = useState(null);
227
+ const [approvalGroupUnavailable, setApprovalGroupUnavailable] = useState(false);
222
228
  const [lifecycle, setLifecycle] = useState(null);
223
229
  const [trajectory, setTrajectory] = useState(null);
224
230
  const [governance, setGovernance] = useState(null);
@@ -232,6 +238,7 @@ export function PrincipleDetailPage() {
232
238
  const [loadingEvidenceKind, setLoadingEvidenceKind] = useState(null);
233
239
  const [loading, setLoading] = useState(true);
234
240
  const [error, setError] = useState(null);
241
+ const detailEpoch = useRef(0);
235
242
  // Decision action state — driven by backend available_actions only.
236
243
  const [pendingAction, setPendingAction] = useState(null);
237
244
  const [rejectReason, setRejectReason] = useState("");
@@ -245,9 +252,12 @@ export function PrincipleDetailPage() {
245
252
  const loadData = useCallback(async () => {
246
253
  if (!id)
247
254
  return;
255
+ const epoch = ++detailEpoch.current;
248
256
  setLoading(true);
257
+ setLoadingEvidenceKind(null);
249
258
  setError(null);
250
259
  setApprovalGroup(null); // Clear previous approval group to prevent stale actionability (P1)
260
+ setApprovalGroupUnavailable(false);
251
261
  setGovernance(null);
252
262
  setGovernanceUnavailable(null);
253
263
  setOwnerDecision(null);
@@ -265,6 +275,8 @@ export function PrincipleDetailPage() {
265
275
  fetchPrincipleReceipts(id),
266
276
  fetchEvidenceAudit('principle', id),
267
277
  ]);
278
+ if (epoch !== detailEpoch.current)
279
+ return;
268
280
  if (!pResult.success) {
269
281
  setError(pResult.error ?? "Failed to load principle");
270
282
  return;
@@ -282,6 +294,9 @@ export function PrincipleDetailPage() {
282
294
  }
283
295
  else {
284
296
  setApprovalGroup(null);
297
+ // The grouped list is the only source of pending approval records here;
298
+ // swallowing the failure would hide the decision surface without a word.
299
+ setApprovalGroupUnavailable(true);
285
300
  }
286
301
  const lData = lResult.success ? validateLifecycleMetrics(lResult.data) : null;
287
302
  setLifecycle(lData);
@@ -322,15 +337,25 @@ export function PrincipleDetailPage() {
322
337
  }
323
338
  }
324
339
  catch (err) {
340
+ if (epoch !== detailEpoch.current)
341
+ return;
325
342
  setError(err instanceof Error ? err.message : "Unknown error");
326
343
  setApprovalGroup(null);
344
+ setApprovalGroupUnavailable(true);
327
345
  }
328
346
  finally {
329
- setLoading(false);
347
+ if (epoch === detailEpoch.current)
348
+ setLoading(false);
330
349
  }
331
350
  }, [id]);
332
351
  useEffect(() => {
333
- loadData();
352
+ setPendingAction(null);
353
+ setRejectReason('');
354
+ setNewArtifactId('');
355
+ setApproveNote('');
356
+ setActionLoading(false);
357
+ void loadData();
358
+ return () => { detailEpoch.current++; };
334
359
  }, [loadData]);
335
360
  const loadOlderEvidence = async (kind) => {
336
361
  if (!id || !evidenceAudit || loadingEvidenceKind)
@@ -339,8 +364,11 @@ export function PrincipleDetailPage() {
339
364
  if (!page.hasMore || !page.nextCursor)
340
365
  return;
341
366
  setLoadingEvidenceKind(kind);
367
+ const epoch = detailEpoch.current;
342
368
  try {
343
369
  const result = await fetchEvidenceAudit('principle', id, { kind, after: page.nextCursor });
370
+ if (epoch !== detailEpoch.current)
371
+ return;
344
372
  if (!result.success || !result.data)
345
373
  return;
346
374
  if (result.data.status !== 'ok') {
@@ -360,20 +388,26 @@ export function PrincipleDetailPage() {
360
388
  }));
361
389
  }
362
390
  catch (err) {
391
+ if (epoch !== detailEpoch.current)
392
+ return;
363
393
  toast.error(err instanceof Error ? err.message : '读取更早的干预证据失败');
364
394
  }
365
395
  finally {
366
- setLoadingEvidenceKind(null);
396
+ if (epoch === detailEpoch.current)
397
+ setLoadingEvidenceKind(null);
367
398
  }
368
399
  };
369
400
  // ── Owner decision actions (SPEC §8.4: mutation service is the authority) ─
370
401
  // The view's actions are advisory; every submission goes through the real
371
402
  // mutation service. On failure: show the service reason, invalidate stale
372
403
  // actions, re-GET the view. Never auto-retry a mutation.
373
- const submitOwnerAction = async (action, reason, note) => {
404
+ const submitOwnerAction = async (action) => {
374
405
  if (actionLoading)
375
406
  return;
407
+ if (action.semantic !== 'disable')
408
+ return;
376
409
  setActionLoading(true);
410
+ const epoch = detailEpoch.current;
377
411
  try {
378
412
  let failed = false;
379
413
  let failureDetail = '';
@@ -383,37 +417,7 @@ export function PrincipleDetailPage() {
383
417
  failureDetail = `${result.error ?? ''}${result.nextAction ? ` ${result.nextAction}` : ''}`.trim();
384
418
  }
385
419
  };
386
- if (action.semantic === 'approve') {
387
- const approvalId = actionTargetId(action, 'approval');
388
- if (approvalId === null) {
389
- toast.error(t("principles.detail.ownerDecision.invalidTarget", { defaultValue: "动作目标缺失,无法提交。" }));
390
- return;
391
- }
392
- const approveResult = await approveApproval(approvalId, note);
393
- settle(approveResult);
394
- // PRI-890: non-fatal server warnings (e.g. prompt injection budget
395
- // exclusion) must reach the Owner on this path too, not vanish.
396
- if (approveResult.success && typeof approveResult.data?.warning === 'string') {
397
- toast.warning(approveResult.data.warning, { duration: 15000 });
398
- }
399
- }
400
- else if (action.semantic === 'reject') {
401
- const approvalId = actionTargetId(action, 'approval');
402
- if (approvalId === null) {
403
- toast.error(t("principles.detail.ownerDecision.invalidTarget", { defaultValue: "动作目标缺失,无法提交。" }));
404
- return;
405
- }
406
- settle(await rejectApproval(approvalId, reason ?? ""));
407
- }
408
- else if (action.semantic === 'edit_approval') {
409
- const approvalId = actionTargetId(action, 'approval');
410
- if (approvalId === null || reason === undefined || newArtifactId.trim() === '') {
411
- toast.error(t("principles.detail.ownerDecision.invalidTarget", { defaultValue: "动作目标缺失,无法提交。" }));
412
- return;
413
- }
414
- settle(await editApproval(approvalId, newArtifactId.trim(), reason));
415
- }
416
- else if (action.semantic === 'disable') {
420
+ if (action.semantic === 'disable') {
417
421
  const activationId = actionTargetId(action, 'activation');
418
422
  if (activationId === null) {
419
423
  toast.error(t("principles.detail.ownerDecision.invalidTarget", { defaultValue: "动作目标缺失,无法提交。" }));
@@ -424,6 +428,8 @@ export function PrincipleDetailPage() {
424
428
  else {
425
429
  return; // unknown semantics are never rendered; belt-and-suspenders
426
430
  }
431
+ if (epoch !== detailEpoch.current)
432
+ return;
427
433
  if (!failed) {
428
434
  toast.success(t("principles.detail.ownerDecision.actionDone", { defaultValue: "操作已提交。" }));
429
435
  }
@@ -437,16 +443,20 @@ export function PrincipleDetailPage() {
437
443
  }
438
444
  }
439
445
  catch (err) {
446
+ if (epoch !== detailEpoch.current)
447
+ return;
440
448
  toast.error(err instanceof Error ? err.message : String(err));
441
449
  }
442
450
  finally {
443
- setActionLoading(false);
444
- setPendingAction(null);
445
- setRejectReason("");
446
- setNewArtifactId("");
447
- setApproveNote("");
448
- // Invalidate the stale action list and re-derive from a fresh GET.
449
- await loadData();
451
+ if (epoch === detailEpoch.current) {
452
+ setActionLoading(false);
453
+ setPendingAction(null);
454
+ setRejectReason("");
455
+ setNewArtifactId("");
456
+ setApproveNote("");
457
+ // Invalidate the stale action list and re-derive from a fresh GET.
458
+ await loadData();
459
+ }
450
460
  }
451
461
  };
452
462
  // ── Render ──────────────────────────────────────────────────────────────
@@ -454,7 +464,7 @@ export function PrincipleDetailPage() {
454
464
  return (_jsx(PageShell, { children: _jsx(PageLoading, { cardCount: 1, label: t("principles.loading", { defaultValue: "Loading…" }) }) }));
455
465
  }
456
466
  if (error || !principle) {
457
- return (_jsxs(PageShell, { children: [_jsxs(Button, { variant: "ghost", onClick: () => navigate("/principles"), className: "mb-4", children: ["\u2190 ", t("principles.detail.backToList")] }), _jsxs("div", { className: "border border-danger/30 rounded-[var(--radius-md)] p-4", children: [_jsx("p", { className: "text-danger text-sm", children: error ?? t("principles.notFound") }), _jsx(Button, { variant: "outline", size: "sm", onClick: loadData, className: "mt-2", children: t("principles.retry", { defaultValue: "Retry" }) })] })] }));
467
+ return (_jsxs(PageShell, { children: [_jsxs(Button, { variant: "ghost", onClick: () => navigate(returnTo), className: "mb-4", children: ["\u2190 ", t("principles.detail.backToList")] }), _jsxs("div", { className: "border border-danger/30 rounded-[var(--radius-md)] p-4", children: [_jsx("p", { className: "text-danger text-sm", children: error ?? t("principles.notFound") }), _jsx(Button, { variant: "outline", size: "sm", onClick: loadData, className: "mt-2", children: t("principles.retry", { defaultValue: "Retry" }) })] })] }));
458
468
  }
459
469
  const hasRules = principle.rules.length > 0;
460
470
  const receiptPresentation = receipts?.status === 'ok'
@@ -466,30 +476,36 @@ export function PrincipleDetailPage() {
466
476
  ? ownerDecision.learnedPrinciple.value.text
467
477
  : undefined;
468
478
  const learnedKnown = learnedText !== undefined;
479
+ const learnedPreview = learnedText === undefined ? undefined : truncateByCodePoints(learnedText, 240);
480
+ const learnedTruncated = learnedPreview !== learnedText;
469
481
  const headlineLayout = splitReadingTitleBody(learnedText ?? principle.text);
470
- return (_jsx(PageShell, { children: _jsxs("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: [_jsxs(Button, { variant: "ghost", onClick: () => navigate("/principles"), className: "mb-4 -ml-2", children: ["\u2190 ", t("principles.detail.backToList")] }), _jsxs("section", { className: "mb-8", children: [_jsx(SectionTitle, { children: t("principles.detail.conclusion") }), _jsx("h1", { className: "text-[22px] font-semibold text-ink leading-snug mb-3", "data-testid": "principle-detail-title", children: headlineLayout.title }), headlineLayout.body !== null && !learnedKnown && (_jsx("div", { className: "mb-3 text-[15px] leading-relaxed text-ink whitespace-pre-wrap break-words", "data-testid": "principle-detail-body", children: headlineLayout.body })), ownerDecision !== null && ownerDecision.learnedPrinciple.status !== 'known' && (_jsx("p", { className: "text-amber text-[13px] leading-relaxed mb-3", "data-testid": "owner-decision-technical-note", children: t("principles.detail.ownerDecision.technicalOriginalNote", {
482
+ return (_jsx(PageShell, { children: _jsxs("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: [_jsxs(Button, { variant: "ghost", onClick: () => navigate(returnTo), className: "mb-4 -ml-2", children: ["\u2190 ", t("principles.detail.backToList")] }), _jsxs("section", { className: "mb-8", children: [_jsx(SectionTitle, { children: t("principles.detail.conclusion") }), _jsx("h1", { className: "text-[22px] font-semibold text-ink leading-snug mb-3", "data-testid": "principle-detail-title", children: headlineLayout.title }), headlineLayout.body !== null && !learnedKnown && (_jsx("div", { className: "mb-3 text-[15px] leading-relaxed text-ink whitespace-pre-wrap break-words", "data-testid": "principle-detail-body", children: headlineLayout.body })), ownerDecision !== null && ownerDecision.learnedPrinciple.status !== 'known' && (_jsx("p", { className: "text-amber text-[13px] leading-relaxed mb-3", "data-testid": "owner-decision-technical-note", children: t("principles.detail.ownerDecision.technicalOriginalNote", {
471
483
  defaultValue: "以上为原始技术建议文本;可读的行为准则暂缺(保留原文以保证可追溯)。",
472
- }) })), _jsx("p", { className: "text-ink-3 text-[14px] leading-relaxed mb-3", children: t("principles.detail.policyNote") }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Button, { variant: "outline", size: "sm", disabled: true, children: t("principles.detail.modifyWording") }), _jsx("span", { className: "text-ink-4 text-[13px]", children: t("principles.detail.modifyWordingNote") }), _jsx(Button, { variant: "ghost", size: "sm", className: "ml-auto", "data-testid": "principle-feedback", onClick: () => {
484
+ }) })), _jsx("p", { className: "text-ink-3 text-[14px] leading-relaxed mb-3", children: t("principles.detail.policyNote") }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-ink-4 text-[13px]", children: t("principles.detail.modifyWordingNote") }), _jsx(Button, { variant: "ghost", size: "sm", className: "ml-auto", "data-testid": "principle-feedback", onClick: () => {
473
485
  const params = new URLSearchParams({ source: "principle_page", principleId: id ?? "" });
474
486
  navigate(`/report-problem?${params.toString()}`);
475
487
  }, children: t("reportProblem.entryFeedback") })] })] }), ownerDecision !== null && (_jsxs("section", { className: "mb-8", "aria-labelledby": "owner-decision-title", "data-testid": "owner-decision-view", children: [_jsx(SectionTitle, { children: t("principles.detail.ownerDecision.title", { defaultValue: "这条原则的决策视图" }) }), _jsxs("div", { className: "rounded-[var(--radius-md)] border border-gov/25 bg-gov/5 p-4", children: [_jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between", children: [_jsxs("div", { children: [_jsx("h2", { id: "owner-decision-title", className: "text-[18px] font-semibold text-ink", children: t(DECISION_STATE_LABEL_KEY[ownerDecision.decisionState]) }), _jsx("p", { className: "mt-1 text-[13px] leading-relaxed text-ink-2", children: localizeNextAction(ownerDecision.nextAction.code, ownerDecision.nextAction.ownerText, t) })] }), _jsx("span", { "data-testid": "owner-decision-state", className: "w-fit rounded-full border border-line px-2 py-1 font-mono text-[11px] text-ink-3", children: ownerDecision.sourceReadStatus === 'complete'
476
488
  ? t("principles.detail.ownerDecision.readsComplete", { defaultValue: "本次所需数据已读取" })
477
- : t("principles.detail.ownerDecision.readsPartial", { defaultValue: "部分数据源读取失败" }) })] }), _jsx(OwnerNarrativeBlock, { testId: "owner-decision-incident", label: t("principles.detail.ownerDecision.incident", { defaultValue: "发生了什么" }), field: ownerDecision.incidentSummary }), _jsxs("div", { className: "mt-4", "data-testid": "owner-decision-learned", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.learned", { defaultValue: "Agent 学到的行为准则" }) }), ownerDecision.learnedPrinciple.status === 'known' ? (_jsxs(_Fragment, { children: [_jsx("p", { className: "mt-1 text-ink-2 text-[15px] leading-relaxed whitespace-pre-wrap break-words", children: learnedText }), _jsx("p", { className: "mt-1 text-ink-4 text-[12px]", children: t("principles.detail.ownerDecision.sourceTierLabel", {
489
+ : t("principles.detail.ownerDecision.readsPartial", { defaultValue: "部分数据源读取失败" }) })] }), _jsxs("div", { className: "mt-4", "data-testid": "owner-decision-learned", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.learned", { defaultValue: "Agent 学到的行为准则" }) }), ownerDecision.learnedPrinciple.status === 'known' ? (_jsxs(_Fragment, { children: [_jsx("p", { className: "mt-1 text-ink-2 text-[15px] leading-relaxed whitespace-pre-wrap break-words", children: learnedPreview }), learnedTruncated && _jsxs("details", { className: "mt-3 text-sm text-ink-2", children: [_jsx("summary", { className: "cursor-pointer text-gov", children: t('principles.detail.fullRule') }), _jsx("p", { className: "mt-3 whitespace-pre-wrap break-words leading-relaxed", children: learnedText })] }), _jsx("p", { className: "mt-1 text-ink-4 text-[12px]", children: t("principles.detail.ownerDecision.sourceTierLabel", {
478
490
  defaultValue: "来源:{{tier}}(未经改写)",
479
491
  tier: t(`principles.detail.ownerDecision.tier.${ownerDecision.learnedPrinciple.value.sourceTier}`, { defaultValue: ownerDecision.learnedPrinciple.value.sourceTier }),
480
- }) })] })) : (_jsx("p", { className: "mt-1 text-amber text-[13px] leading-relaxed", children: ownerDecision.learnedPrinciple.reason.ownerText }))] }), _jsx(OwnerNarrativeBlock, { testId: "owner-decision-rationale", label: t("principles.detail.ownerDecision.rationale", { defaultValue: "为什么这么判断" }), field: ownerDecision.rationale }), _jsx(OwnerNarrativeBlock, { testId: "owner-decision-applicability", label: t("principles.detail.ownerDecision.applicability", { defaultValue: "什么时候适用" }), field: ownerDecision.applicability }), _jsx(OwnerNarrativeBlock, { testId: "owner-decision-expected", label: t("principles.detail.ownerDecision.expected", { defaultValue: "批准后会怎样(拟议行为,未部署)" }), field: ownerDecision.expectedBehavior }), ownerDecision.currentEnforcement.status === 'known' && (_jsxs("div", { className: "mt-4", "data-testid": "owner-decision-enforcement", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.enforcementLabel", { defaultValue: "当前实际执行" }) }), _jsx("p", { className: "mt-1 text-ink-2 text-[14px] leading-relaxed", children: ownerDecision.currentEnforcement.value?.state === 'active'
481
- ? t("principles.detail.ownerDecision.enforcement.active", { defaultValue: "当前有正在执行的生效方式(见下方明细)。" })
482
- : ownerDecision.currentEnforcement.value?.state === 'deactivated'
483
- ? t("principles.detail.ownerDecision.enforcement.deactivated", { defaultValue: "此前的执行方式已停用;当前没有正在执行的生效方式。" })
484
- : ownerDecision.currentEnforcement.value?.state === 'partially_active'
485
- ? t("principles.detail.ownerDecision.enforcement.partial", { defaultValue: "部分执行方式仍在运行(见下方明细)。" })
486
- : t("principles.detail.ownerDecision.enforcement.none", { defaultValue: "这条原则当前没有生效中的执行方式。" }) }), ownerDecision.currentEnforcement.value?.items.map((item) => (_jsxs("p", { className: "mt-1 text-ink-3 text-[12px]", children: [item.mode.status === 'known' ? item.mode.value : item.channel, " · ", item.active
487
- ? t("principles.detail.ownerDecision.enforcement.since", { defaultValue: "生效中(自 {{since}})", since: item.since.status === 'known' ? item.since.value.slice(0, 10) : '?' })
488
- : t("principles.detail.ownerDecision.enforcement.stopped", { defaultValue: "已停用" })] }, item.activationRef.id)))] })), ownerDecision.currentEnforcement.status === 'unknown' && (_jsx("p", { className: "mt-4 text-amber text-[13px]", "data-testid": "owner-decision-enforcement-unknown", children: ownerDecision.currentEnforcement.reason?.ownerText })), ownerDecision.evidenceSummary.status === 'known' && (_jsxs("div", { className: "mt-4", "data-testid": "owner-decision-evidence", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.evidence", { defaultValue: "行为证据" }) }), _jsx("p", { className: "mt-1 text-ink-2 text-[13px] leading-relaxed", children: ownerDecision.evidenceSummary.value?.ownerExplanation })] })), _jsxs("div", { className: "mt-4", "data-testid": "owner-decision-uncertainty", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.uncertainty", { defaultValue: "风险与不确定性" }) }), ownerDecision.risk.status === 'known' && (ownerDecision.risk.value?.items.length ?? 0) > 0 && (_jsx("ul", { className: "mt-1 space-y-1 text-[13px] text-ink-2", children: ownerDecision.risk.value?.items.map((item, index) => (_jsx("li", { children: item.text }, `risk-${index}`))) })), ownerDecision.risk.status === 'known' && (ownerDecision.risk.value?.items.length ?? 0) === 0 && (_jsx("p", { className: "mt-1 text-ink-3 text-[13px]", children: t("principles.detail.ownerDecision.riskNotAssessed", { defaultValue: "尚未做过风险评估;这不代表没有风险。" }) })), ownerDecision.risk.status === 'unknown' && (_jsx("p", { className: "mt-1 text-ink-3 text-[13px]", children: ownerDecision.risk.reason?.ownerText })), ownerDecision.uncertainty.status === 'known' && ownerDecision.uncertainty.value.length > 0 && (_jsx("ul", { className: "mt-2 space-y-1 text-[12px] text-ink-3", children: ownerDecision.uncertainty.value.map((item, index) => (_jsx("li", { children: item.text }, `unc-${index}`))) }))] }), _jsxs("div", { className: "mt-4", "data-testid": "owner-decision-rollback", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.rollback", { defaultValue: "如何停止影响" }) }), ownerDecision.rollback.status === 'known' && (_jsxs(_Fragment, { children: [_jsx("p", { className: "mt-1 text-ink-2 text-[13px] leading-relaxed", children: ownerDecision.rollback.value?.ownerText }), ownerDecision.rollback.value?.stopFuture.status === 'known' && (_jsx("ul", { className: "mt-1 space-y-1 text-[12px] text-ink-3", children: ownerDecision.rollback.value.stopFuture.value.map((item, index) => (_jsx("li", { children: item.text }, `rb-${index}`))) })), ownerDecision.rollback.value?.stopFuture.status === 'not_applicable' && (_jsx("p", { className: "mt-1 text-ink-3 text-[12px]", children: ownerDecision.rollback.value.stopFuture.reason.ownerText }))] })), ownerDecision.rollback.status === 'unknown' && (_jsx("p", { className: "mt-1 text-amber text-[13px]", children: ownerDecision.rollback.reason?.ownerText }))] }), ownerDecision.decisionSubjects.some((subject) => subject.state !== 'pending') && (_jsxs("div", { className: "mt-3", "data-testid": "owner-decision-history", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.history", { defaultValue: "决定历史" }) }), _jsx("ul", { className: "mt-1 space-y-1 text-[13px] text-ink-2", children: ownerDecision.decisionSubjects.filter((subject) => subject.state !== 'pending').map((subject) => {
492
+ }) })] })) : (_jsx("p", { className: "mt-1 text-amber text-[13px] leading-relaxed", children: ownerDecision.learnedPrinciple.reason.ownerText }))] }), ownerDecision.decisionSubjects.some((subject) => subject.state !== 'pending') && (_jsxs("div", { className: "mt-3", "data-testid": "owner-decision-history", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.history", { defaultValue: "决定历史" }) }), _jsx("ul", { className: "mt-1 space-y-1 text-[13px] text-ink-2", children: ownerDecision.decisionSubjects.filter((subject) => subject.state !== 'pending').map((subject) => {
489
493
  const decidedAt = subject.targetRefs.find((target) => target.kind === 'approval')?.recordedAt;
490
494
  const stateKey = `principles.detail.ownerDecision.historyState.${subject.state}`;
491
495
  return (_jsxs("li", { children: [t(stateKey, { defaultValue: subject.state }), decidedAt !== undefined ? ` · ${decidedAt.slice(0, 10)}` : '', ' · ', t(`principles.detail.ownerDecision.channel.${subject.channel}`, { defaultValue: subject.channel })] }, `hist-${subject.key}`));
492
- }) })] })), _jsxs("div", { className: "mt-5 border-t border-line pt-4", "data-testid": "owner-decision-actions", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.decision", { defaultValue: "你的决定" }) }), ownerDecision.availableActions.length === 0 && (_jsx("p", { className: "mt-1 text-ink-3 text-[13px]", children: t("principles.detail.ownerDecision.noActions", { defaultValue: "当前没有可以执行的操作。" }) })), ownerDecision.decisionSubjects.filter((subject) => subject.state === 'pending').length > 0 && (_jsx("div", { className: "mt-3 space-y-3", "data-testid": "owner-decision-subject-materials", children: ownerDecision.decisionSubjects.filter((subject) => subject.state === 'pending').map((subject) => (_jsxs("div", { className: "rounded-[var(--radius-sm)] border border-line p-3", "data-subject-key": subject.key, children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.subjectMaterial", { defaultValue: "这项决定的材料" }) }), subject.decisionMaterial.learnedPrinciple.status === 'known' ? (subject.decisionMaterial.learnedPrinciple.value.map((item, index) => (_jsx("p", { className: "mt-1 text-ink-2 text-[13px] leading-relaxed", children: item.text }, `sm-${index}`)))) : (_jsx("p", { className: "mt-1 text-amber text-[13px]", children: subject.decisionMaterial.learnedPrinciple.reason.ownerText })), subject.decisionMaterial.consequence.status === 'known' && (_jsx("p", { className: "mt-1 text-ink-3 text-[12px] leading-relaxed", children: subject.decisionMaterial.consequence.value.map((item) => item.text).join(' ') }))] }, subject.key))) })), _jsx("div", { className: "mt-2 flex flex-wrap gap-3", children: ownerDecision.availableActions.map((action) => (_jsx(Button, { variant: action.semantic === 'reject' ? 'destructive' : action.semantic === 'disable' ? 'outline' : 'default', size: "sm", disabled: actionLoading, "data-action-semantic": action.semantic, onClick: () => {
496
+ }) })] })), _jsxs("div", { className: "mt-5 border-t border-line pt-4", "data-testid": "owner-decision-actions", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.decision", { defaultValue: "你的决定" }) }), ownerDecision.availableActions.length === 0 && (_jsx("p", { className: "mt-1 text-ink-3 text-[13px]", children: t("principles.detail.ownerDecision.noActions", { defaultValue: "当前没有可以执行的操作。" }) })), approvalGroupUnavailable && ownerDecision.availableActions.length > 0 && (_jsxs("div", { role: "alert", className: "mt-2 text-[13px] leading-relaxed text-amber", "data-testid": "detail-approvals-unavailable", children: [_jsx("p", { children: t('focus.workbench.approvalsUnavailable') }), _jsx("button", { type: "button", onClick: () => { void loadData(); }, className: "mt-1 text-gov underline", children: t('focus.workbench.retry') })] })), approvalGroup?.records.filter(record => record.status === 'pending').map(record => {
497
+ const allowedActions = ownerDecision.availableActions
498
+ .filter(action => actionTargetId(action, 'approval') === record.id)
499
+ .map(action => action.semantic)
500
+ .filter((semantic) => semantic === 'approve' || semantic === 'reject' || semantic === 'edit_approval');
501
+ // A sibling's broken revision review must not block this record;
502
+ // without any per-record defect the group flag still covers the
503
+ // "multiple versions pending" ambiguity.
504
+ const revisionReviewUnavailable = record.revisionReviewUnavailable
505
+ ?? (approvalGroup.records.some(entry => entry.status === 'pending' && entry.revisionReviewUnavailable === true)
506
+ ? false : approvalGroup.revisionReviewUnavailable);
507
+ return _jsxs("details", { className: "mt-4 rounded border border-line p-4", "data-testid": "detail-approval-review", children: [_jsxs("summary", { className: "cursor-pointer text-sm text-gov", children: [t('focus.workbench.proposal'), " \u00B7 ", t(`principles.detail.ownerDecision.channel.${record.channel}`, { defaultValue: record.channel })] }), _jsx("div", { className: "mt-5", children: _jsx(ApprovalSubjectReading, { principleId: principle.id, approvalId: record.id, artifactId: record.artifactId, channel: record.channel, showPrincipleLink: false, revisionReview: new Set(approvalGroup.records.filter(entry => entry.status === 'pending').map(entry => entry.artifactId)).size === 1 ? approvalGroup.revisionReview : undefined, revisionReviewUnavailable: revisionReviewUnavailable, allowedActions: allowedActions, lockedReason: ownerDecision.availableActions.some(action => actionTargetId(action, 'approval') === record.id) ? undefined : t('focus.workbench.permissionsUnknown'), onResolved: message => { toast.success(message); void loadData(); } }) })] }, record.id);
508
+ }), _jsx("div", { className: "mt-2 flex flex-wrap gap-3", children: ownerDecision.availableActions.filter(action => action.semantic === 'disable').map((action) => (_jsx(Button, { variant: action.semantic === 'reject' ? 'destructive' : action.semantic === 'disable' ? 'outline' : 'default', size: "sm", disabled: actionLoading, "data-action-semantic": action.semantic, onClick: () => {
493
509
  setRejectReason("");
494
510
  setApproveNote("");
495
511
  setPendingAction(action);
@@ -498,8 +514,16 @@ export function PrincipleDetailPage() {
498
514
  || (pendingAction.requirements.some((req) => req.name === 'reason') && !rejectReason.trim())
499
515
  || (pendingAction.requirements.some((req) => req.name === 'newArtifactId') && !newArtifactId.trim()), onClick: () => {
500
516
  const action = pendingAction;
501
- void submitOwnerAction(action, rejectReason.trim() === '' ? undefined : rejectReason.trim(), approveNote.trim() === '' ? undefined : approveNote.trim());
502
- }, children: t("principles.detail.confirm", { defaultValue: "确认" }) }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => { setPendingAction(null); setRejectReason(""); setNewArtifactId(""); setApproveNote(""); }, children: t("principles.detail.cancel") })] })] })] }))] })] })] })), ownerDecision === null && ownerDecisionUnavailable !== null && (_jsxs("section", { className: "mb-8", "data-testid": "owner-decision-unavailable", children: [_jsx(SectionTitle, { children: t("principles.detail.ownerDecision.title", { defaultValue: "这条原则的决策视图" }) }), _jsxs("div", { className: "rounded-[var(--radius-md)] border border-amber/30 bg-amber/5 p-4", role: "status", children: [_jsx("p", { className: "text-ink-2 text-[13px]", children: t("principles.detail.ownerDecision.unavailable", { defaultValue: "决策视图暂时不可用,无法据此做决定。" }) }), _jsx("p", { className: "mt-1 text-ink-4 text-[12px] font-mono", children: ownerDecisionUnavailable.reason })] })] })), (governance !== null || governanceUnavailable !== null) && (_jsxs("section", { className: "mb-8", "aria-labelledby": "governance-summary-title", children: [_jsx(SectionTitle, { children: t('principles.detail.governance.title') }), governance !== null ? (_jsxs("div", { "data-testid": "governance-summary", className: `rounded-[var(--radius-md)] border p-4 ${governance.dataQuality.degraded ? 'border-amber/30 bg-amber/5' : 'border-gov/25 bg-gov/5'}`, children: [_jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between", children: [_jsxs("div", { children: [_jsx("h2", { id: "governance-summary-title", className: "text-[18px] font-semibold text-ink", children: t(`principles.detail.${governance.summary.headlineCode}`, { defaultValue: governance.summary.headlineCode }) }), _jsx("p", { className: "mt-1 text-[13px] leading-relaxed text-ink-2", children: t(`principles.detail.${governance.summary.reasonCode}`, { defaultValue: governance.summary.reasonCode }) })] }), _jsx("span", { className: "w-fit rounded-full border border-line px-2 py-1 font-mono text-[11px] text-ink-3", children: t(`principles.detail.governance.confidence.${governance.dataQuality.degraded ? 'degraded' : 'strong'}`) })] }), _jsxs("dl", { className: "mt-4 grid grid-cols-1 gap-3 sm:grid-cols-3", children: [_jsxs("div", { children: [_jsx("dt", { className: "font-mono text-[11px] text-ink-4", children: t('principles.detail.governance.principleState') }), _jsx("dd", { className: "text-[13px] text-ink-2", children: t(`principles.detail.governance.state.${governance.principleState.value}`) })] }), _jsxs("div", { children: [_jsx("dt", { className: "font-mono text-[11px] text-ink-4", children: t('principles.detail.governance.process') }), _jsx("dd", { className: "text-[13px] text-ink-2", children: governance.process.stage === undefined ? t('principles.detail.governance.none') : t(`principles.detail.governance.stage.${governance.process.stage}`) })] }), _jsxs("div", { children: [_jsx("dt", { className: "font-mono text-[11px] text-ink-4", children: t('principles.detail.governance.automation') }), _jsx("dd", { className: "text-[13px] text-ink-2", children: t(`principles.detail.governance.automationState.${governance.automation.state}`) })] })] }), _jsxs("div", { "data-testid": "governance-next-action", className: "mt-4 border-l-2 border-l-gov pl-3", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t('principles.detail.governance.nextAction') }), _jsx("p", { className: "text-[13px] text-ink-2", children: t(`principles.detail.${governance.summary.nextActionCode}`, { defaultValue: governance.summary.nextActionCode }) })] }), governance.attention.items.length > 0 && (_jsxs("div", { className: "mt-4", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t('principles.detail.governance.blockers') }), _jsx("ul", { className: "mt-1 space-y-1 text-[13px] text-ink-2", children: groupByReasonCode(governance.attention.items).map(group => _jsx("li", { children: formatGroupedReasonLine(t, 'principles.detail.governance.attention', group) }, group.reasonCode)) })] })), governance.dataQuality.degraded && (_jsxs("div", { "data-testid": "governance-data-quality", className: "mt-4 rounded-[var(--radius-sm)] border border-amber/20 p-3", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-amber", children: t('principles.detail.governance.uncertainty') }), _jsx("ul", { className: "mt-1 space-y-1 text-[12px] text-ink-3", children: groupByReasonCode(governance.dataQuality.issues).map(group => _jsx("li", { children: formatGroupedReasonLine(t, 'principles.detail.governance.issue', group) }, group.reasonCode)) })] }))] })) : (_jsxs("div", { "data-testid": "governance-data-quality", className: "rounded-[var(--radius-md)] border border-amber/30 bg-amber/5 p-4", role: "status", children: [_jsx("h2", { id: "governance-summary-title", className: "text-[16px] font-semibold text-ink", children: t('principles.detail.governance.unavailable') }), _jsx("p", { className: "mt-1 text-[13px] text-ink-2", children: t('principles.detail.governance.unavailableReason') }), _jsx("p", { className: "mt-2 text-[12px] text-ink-3", children: t('principles.detail.governance.unavailableNextAction') })] }))] })), receipts !== null && (_jsxs("section", { className: "mb-8", "aria-labelledby": "receipt-history-title", children: [_jsx(SectionTitle, { children: t('principles.detail.receipts.title') }), receipts.status === 'ok' ? (_jsxs("div", { "data-testid": "receipt-history", className: "rounded-[var(--radius-md)] border border-line p-4", children: [_jsxs("div", { className: "flex flex-wrap items-baseline justify-between gap-2", children: [_jsx("h2", { id: "receipt-history-title", className: "text-[15px] font-semibold text-ink", children: receiptPresentation?.headlineKey === 'principles.detail.receipts.headline'
517
+ void submitOwnerAction(action);
518
+ }, children: t("principles.detail.confirm", { defaultValue: "确认" }) }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => { setPendingAction(null); setRejectReason(""); setNewArtifactId(""); setApproveNote(""); }, children: t("principles.detail.cancel") })] })] })] }))] }), _jsxs("details", { className: "mt-5 border-t border-line pt-4", "data-testid": "principle-formation-disclosure", children: [_jsx("summary", { className: "cursor-pointer text-sm text-gov", children: t('principles.detail.formationDisclosure') }), _jsxs("div", { className: "mt-4", children: [_jsx(OwnerNarrativeBlock, { testId: "owner-decision-incident", label: t("principles.detail.ownerDecision.incident", { defaultValue: "发生了什么" }), field: ownerDecision.incidentSummary }), _jsx(OwnerNarrativeBlock, { testId: "owner-decision-rationale", label: t("principles.detail.ownerDecision.rationale", { defaultValue: "为什么这么判断" }), field: ownerDecision.rationale })] })] }), _jsx(OwnerNarrativeBlock, { testId: "owner-decision-applicability", label: t("principles.detail.ownerDecision.applicability", { defaultValue: "什么时候适用" }), field: ownerDecision.applicability }), _jsx(OwnerNarrativeBlock, { testId: "owner-decision-expected", label: t("principles.detail.ownerDecision.expected", { defaultValue: "批准后会怎样(拟议行为,未部署)" }), field: ownerDecision.expectedBehavior }), ownerDecision.currentEnforcement.status === 'known' && (_jsxs("div", { className: "mt-4", "data-testid": "owner-decision-enforcement", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.enforcementLabel", { defaultValue: "当前实际执行" }) }), _jsx("p", { className: "mt-1 text-ink-2 text-[14px] leading-relaxed", children: ownerDecision.currentEnforcement.value?.state === 'active'
519
+ ? t("principles.detail.ownerDecision.enforcement.active", { defaultValue: "当前有正在执行的生效方式(见下方明细)。" })
520
+ : ownerDecision.currentEnforcement.value?.state === 'deactivated'
521
+ ? t("principles.detail.ownerDecision.enforcement.deactivated", { defaultValue: "此前的执行方式已停用;当前没有正在执行的生效方式。" })
522
+ : ownerDecision.currentEnforcement.value?.state === 'partially_active'
523
+ ? t("principles.detail.ownerDecision.enforcement.partial", { defaultValue: "部分执行方式仍在运行(见下方明细)。" })
524
+ : t("principles.detail.ownerDecision.enforcement.none", { defaultValue: "这条原则当前没有生效中的执行方式。" }) }), ownerDecision.currentEnforcement.value?.items.map((item) => (_jsxs("p", { className: "mt-1 text-ink-3 text-[12px]", children: [item.mode.status === 'known' ? item.mode.value : item.channel, " · ", item.active
525
+ ? t("principles.detail.ownerDecision.enforcement.since", { defaultValue: "生效中(自 {{since}})", since: item.since.status === 'known' ? item.since.value.slice(0, 10) : '?' })
526
+ : t("principles.detail.ownerDecision.enforcement.stopped", { defaultValue: "已停用" })] }, item.activationRef.id)))] })), ownerDecision.currentEnforcement.status === 'unknown' && (_jsx("p", { className: "mt-4 text-amber text-[13px]", "data-testid": "owner-decision-enforcement-unknown", children: ownerDecision.currentEnforcement.reason?.ownerText })), ownerDecision.evidenceSummary.status === 'known' && (_jsxs("div", { className: "mt-4", "data-testid": "owner-decision-evidence", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.evidence", { defaultValue: "行为证据" }) }), _jsx("p", { className: "mt-1 text-ink-2 text-[13px] leading-relaxed", children: ownerDecision.evidenceSummary.value?.ownerExplanation })] })), _jsxs("div", { className: "mt-4", "data-testid": "owner-decision-uncertainty", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.uncertainty", { defaultValue: "风险与不确定性" }) }), ownerDecision.risk.status === 'known' && (ownerDecision.risk.value?.items.length ?? 0) > 0 && (_jsx("ul", { className: "mt-1 space-y-1 text-[13px] text-ink-2", children: ownerDecision.risk.value?.items.map((item, index) => (_jsx("li", { children: item.text }, `risk-${index}`))) })), ownerDecision.risk.status === 'known' && (ownerDecision.risk.value?.items.length ?? 0) === 0 && (_jsx("p", { className: "mt-1 text-ink-3 text-[13px]", children: t("principles.detail.ownerDecision.riskNotAssessed", { defaultValue: "尚未做过风险评估;这不代表没有风险。" }) })), ownerDecision.risk.status === 'unknown' && (_jsx("p", { className: "mt-1 text-ink-3 text-[13px]", children: ownerDecision.risk.reason?.ownerText })), ownerDecision.uncertainty.status === 'known' && ownerDecision.uncertainty.value.length > 0 && (_jsx("ul", { className: "mt-2 space-y-1 text-[12px] text-ink-3", children: ownerDecision.uncertainty.value.map((item, index) => (_jsx("li", { children: item.text }, `unc-${index}`))) }))] }), _jsxs("div", { className: "mt-4", "data-testid": "owner-decision-rollback", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t("principles.detail.ownerDecision.rollback", { defaultValue: "如何停止影响" }) }), ownerDecision.rollback.status === 'known' && (_jsxs(_Fragment, { children: [_jsx("p", { className: "mt-1 text-ink-2 text-[13px] leading-relaxed", children: ownerDecision.rollback.value?.ownerText }), ownerDecision.rollback.value?.stopFuture.status === 'known' && (_jsx("ul", { className: "mt-1 space-y-1 text-[12px] text-ink-3", children: ownerDecision.rollback.value.stopFuture.value.map((item, index) => (_jsx("li", { children: item.text }, `rb-${index}`))) })), ownerDecision.rollback.value?.stopFuture.status === 'not_applicable' && (_jsx("p", { className: "mt-1 text-ink-3 text-[12px]", children: ownerDecision.rollback.value.stopFuture.reason.ownerText }))] })), ownerDecision.rollback.status === 'unknown' && (_jsx("p", { className: "mt-1 text-amber text-[13px]", children: ownerDecision.rollback.reason?.ownerText }))] })] })] })), ownerDecision === null && ownerDecisionUnavailable !== null && (_jsxs("section", { className: "mb-8", "data-testid": "owner-decision-unavailable", children: [_jsx(SectionTitle, { children: t("principles.detail.ownerDecision.title", { defaultValue: "这条原则的决策视图" }) }), _jsxs("div", { className: "rounded-[var(--radius-md)] border border-amber/30 bg-amber/5 p-4", role: "status", children: [_jsx("p", { className: "text-ink-2 text-[13px]", children: t("principles.detail.ownerDecision.unavailable", { defaultValue: "决策视图暂时不可用,无法据此做决定。" }) }), _jsx("p", { className: "mt-1 text-ink-4 text-[12px] font-mono", children: ownerDecisionUnavailable.reason })] })] })), (governance !== null || governanceUnavailable !== null) && (_jsxs("section", { className: "mb-8", "aria-labelledby": "governance-summary-title", children: [_jsx(SectionTitle, { children: t('principles.detail.governance.title') }), governance !== null ? (_jsxs("div", { "data-testid": "governance-summary", className: `rounded-[var(--radius-md)] border p-4 ${governance.dataQuality.degraded ? 'border-amber/30 bg-amber/5' : 'border-gov/25 bg-gov/5'}`, children: [_jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between", children: [_jsxs("div", { children: [_jsx("h2", { id: "governance-summary-title", className: "text-[18px] font-semibold text-ink", children: t(`principles.detail.${governance.summary.headlineCode}`, { defaultValue: governance.summary.headlineCode }) }), _jsx("p", { className: "mt-1 text-[13px] leading-relaxed text-ink-2", children: t(`principles.detail.${governance.summary.reasonCode}`, { defaultValue: governance.summary.reasonCode }) })] }), _jsx("span", { className: "w-fit rounded-full border border-line px-2 py-1 font-mono text-[11px] text-ink-3", children: t(`principles.detail.governance.confidence.${governance.dataQuality.degraded ? 'degraded' : 'strong'}`) })] }), _jsxs("dl", { className: "mt-4 grid grid-cols-1 gap-3 sm:grid-cols-3", children: [_jsxs("div", { children: [_jsx("dt", { className: "font-mono text-[11px] text-ink-4", children: t('principles.detail.governance.principleState') }), _jsx("dd", { className: "text-[13px] text-ink-2", children: t(`principles.detail.governance.state.${governance.principleState.value}`) })] }), _jsxs("div", { children: [_jsx("dt", { className: "font-mono text-[11px] text-ink-4", children: t('principles.detail.governance.process') }), _jsx("dd", { className: "text-[13px] text-ink-2", children: governance.process.stage === undefined ? t('principles.detail.governance.none') : t(`principles.detail.governance.stage.${governance.process.stage}`) })] }), _jsxs("div", { children: [_jsx("dt", { className: "font-mono text-[11px] text-ink-4", children: t('principles.detail.governance.automation') }), _jsx("dd", { className: "text-[13px] text-ink-2", children: t(`principles.detail.governance.automationState.${governance.automation.state}`) })] })] }), _jsxs("div", { "data-testid": "governance-next-action", className: "mt-4 border-l-2 border-l-gov pl-3", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t('principles.detail.governance.nextAction') }), _jsx("p", { className: "text-[13px] text-ink-2", children: t(`principles.detail.${governance.summary.nextActionCode}`, { defaultValue: governance.summary.nextActionCode }) })] }), governance.attention.items.length > 0 && (_jsxs("div", { className: "mt-4", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t('principles.detail.governance.blockers') }), _jsx("ul", { className: "mt-1 space-y-1 text-[13px] text-ink-2", children: groupByReasonCode(governance.attention.items).map(group => _jsx("li", { children: formatGroupedReasonLine(t, 'principles.detail.governance.attention', group) }, group.reasonCode)) })] })), governance.dataQuality.degraded && (_jsxs("div", { "data-testid": "governance-data-quality", className: "mt-4 rounded-[var(--radius-sm)] border border-amber/20 p-3", children: [_jsx("p", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-amber", children: t('principles.detail.governance.uncertainty') }), _jsx("ul", { className: "mt-1 space-y-1 text-[12px] text-ink-3", children: groupByReasonCode(governance.dataQuality.issues).map(group => _jsx("li", { children: formatGroupedReasonLine(t, 'principles.detail.governance.issue', group) }, group.reasonCode)) })] }))] })) : (_jsxs("div", { "data-testid": "governance-data-quality", className: "rounded-[var(--radius-md)] border border-amber/30 bg-amber/5 p-4", role: "status", children: [_jsx("h2", { id: "governance-summary-title", className: "text-[16px] font-semibold text-ink", children: t('principles.detail.governance.unavailable') }), _jsx("p", { className: "mt-1 text-[13px] text-ink-2", children: t('principles.detail.governance.unavailableReason') }), _jsx("p", { className: "mt-2 text-[12px] text-ink-3", children: t('principles.detail.governance.unavailableNextAction') })] }))] })), receipts !== null && (_jsxs("section", { className: "mb-8", "aria-labelledby": "receipt-history-title", children: [_jsx(SectionTitle, { children: t('principles.detail.receipts.title') }), receipts.status === 'ok' ? (_jsxs("div", { "data-testid": "receipt-history", className: "rounded-[var(--radius-md)] border border-line p-4", children: [_jsxs("div", { className: "flex flex-wrap items-baseline justify-between gap-2", children: [_jsx("h2", { id: "receipt-history-title", className: "text-[15px] font-semibold text-ink", children: receiptPresentation?.headlineKey === 'principles.detail.receipts.headline'
503
527
  ? t(receiptPresentation.headlineKey, {
504
528
  defaultValue: '',
505
529
  effectCount: receipts.effectCount,
@@ -538,30 +562,30 @@ export function PrincipleDetailPage() {
538
562
  activationId: record.activationReference.activationId,
539
563
  activatedAt: record.activationReference.activatedAt ? ` · ${record.activationReference.activatedAt}` : '',
540
564
  snapshotDigest: ` · ${t('principles.detail.evidenceAudit.snapshotDigestLabel')}: ${record.activationReference.sourceSnapshotDigest}`,
541
- })] })), record.nativeLineage.length > 0 && _jsxs(_Fragment, { children: [" \u00B7 ", t('principles.detail.evidenceAudit.nativeLineage', { lineage: record.nativeLineage.join(' · ') })] })] }, record.evidenceId)))) })] }), _jsx("p", { className: "mt-3 text-[11px] leading-relaxed text-ink-4", children: t('principles.detail.evidenceAudit.note') })] })) : (_jsxs("div", { "data-testid": "evidence-audit-degraded", className: "rounded-[var(--radius-md)] border border-amber/30 bg-amber/5 p-4", role: "status", children: [_jsx("h3", { className: "text-[13px] font-semibold text-ink", children: t('principles.detail.evidenceAudit.unavailable') }), _jsx("p", { className: "mt-1 text-[13px] text-ink-2", children: evidenceAudit.reason ?? '—' }), evidenceAudit.nextAction && _jsx("p", { className: "mt-1 text-[12px] text-ink-3", children: evidenceAudit.nextAction })] }))] })), _jsxs("section", { className: "mb-8", children: [_jsx(SectionTitle, { children: t("principles.detail.whyExists") }), _jsxs("div", { className: "space-y-3 mb-6", children: [_jsxs("div", { children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("principles.detail.applicable", { defaultValue: "适用场景(原始触发配置)" }) }), _jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed font-mono break-all", children: principle.triggerPattern || t("principles.detail.notSpecified", { defaultValue: "未指定" }) })] }), _jsxs("div", { children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("principles.detail.expectedBehavior", { defaultValue: "预期行为(原始建议)" }) }), _jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed", children: principle.action || t("principles.detail.notSpecified", { defaultValue: "未指定" }) })] })] }), principle.derivedFromPainIds.length > 0 && (_jsxs("div", { children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("principles.detail.evidence") }), _jsxs("div", { className: "mt-2 flex items-center gap-3 flex-wrap", children: [_jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed", children: t("principles.detail.evidenceCount", {
542
- defaultValue: "已关联 {{count}} 条证据记录",
543
- count: principle.derivedFromPainIds.length,
544
- }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: async () => {
545
- try {
546
- const summary = principle.derivedFromPainIds
547
- .map((pid, i) => `pain_${i + 1}_id: ${pid}`)
548
- .join("\n");
549
- await navigator.clipboard.writeText(summary);
550
- setEvidenceCopied(true);
551
- setTimeout(() => setEvidenceCopied(false), 2000);
552
- }
553
- catch (error) {
554
- // clipboard unavailable — expand as fallback
555
- console.warn("Evidence ID copy failed; expanding technical details.", error);
556
- if (!evidenceExpanded)
557
- setEvidenceExpanded(true);
558
- }
559
- }, className: "font-mono text-[11px] h-7", children: evidenceCopied
560
- ? t("principles.detail.evidenceCopied", { defaultValue: "已复制" })
561
- : t("principles.detail.copyEvidenceId", { defaultValue: "复制证据 ID" }) }), _jsx("button", { type: "button", onClick: () => setEvidenceExpanded((v) => !v), className: "font-mono text-[11px] text-ink-4 hover:text-ink-3 transition-colors underline-offset-2 hover:underline", children: t("principles.detail.expandTechDetails", { defaultValue: "展开技术细节" }) }), _jsx(Link, { to: "/pain", className: "font-mono text-[11px] text-gov hover:underline transition-colors", children: t("principles.detail.viewEvidenceChain", { defaultValue: "在证据链页查看 →" }) })] }), evidenceExpanded && (_jsx("div", { className: "mt-3 p-3 bg-paper-2 border border-line rounded-[var(--radius-sm)]", children: _jsx("div", { className: "grid grid-cols-[auto 1fr] gap-x-4 gap-y-2 text-[13px]", children: principle.derivedFromPainIds.map((painId, idx) => (_jsxs("div", { className: "contents", children: [_jsx("span", { className: "font-mono text-ink-4", children: t("principles.detail.evidenceIdLabel", {
562
- defaultValue: "证据 {{n}} ID",
563
- n: idx + 1,
564
- }) }), _jsx("span", { className: "font-mono text-ink-2 break-all", children: painId })] }, `${painId}-${idx}`))) }) }))] }))] }), _jsxs("section", { className: "mb-8 border-t border-line pt-6", children: [_jsx(SectionTitle, { children: t("principles.detail.ownerReflection") }), _jsxs("div", { className: "space-y-3", children: [_jsx("div", { className: "border-l-2 border-l-gov pl-3 text-ink-2 text-[13px] leading-relaxed", children: t("principles.detail.reflectionQ1") }), _jsx("div", { className: "border-l-2 border-l-gov pl-3 text-ink-2 text-[13px] leading-relaxed", children: t("principles.detail.reflectionQ2") }), _jsx("div", { className: "border-l-2 border-l-gov pl-3 text-ink-2 text-[13px] leading-relaxed", children: t("principles.detail.reflectionQ3") })] })] }), _jsxs("details", { className: "mb-8 border border-line rounded-[var(--radius-md)]", children: [_jsx("summary", { className: "px-4 py-3 cursor-pointer font-mono text-[11px] uppercase tracking-[0.1em] text-ink-3 hover:text-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov", children: t("principles.detail.trajectory") }), _jsxs("div", { className: "px-4 pb-4 border-t border-line pt-4", children: [governance !== null && (_jsxs("section", { className: "mb-6", "data-testid": "governance-timeline", children: [_jsx(SectionTitle, { children: t('principles.detail.governance.timeline') }), governance.timeline.length === 0 ? _jsx("p", { className: "text-[13px] text-ink-4", children: t('principles.detail.governance.timelineEmpty') }) : (_jsx("ol", { className: "space-y-3 border-l border-line pl-4", children: governance.timeline.map((event, index) => {
565
+ })] })), record.nativeLineage.length > 0 && _jsxs(_Fragment, { children: [" \u00B7 ", t('principles.detail.evidenceAudit.nativeLineage', { lineage: record.nativeLineage.join(' · ') })] })] }, record.evidenceId)))) })] }), _jsx("p", { className: "mt-3 text-[11px] leading-relaxed text-ink-4", children: t('principles.detail.evidenceAudit.note') })] })) : (_jsxs("div", { "data-testid": "evidence-audit-degraded", className: "rounded-[var(--radius-md)] border border-amber/30 bg-amber/5 p-4", role: "status", children: [_jsx("h3", { className: "text-[13px] font-semibold text-ink", children: t('principles.detail.evidenceAudit.unavailable') }), _jsx("p", { className: "mt-1 text-[13px] text-ink-2", children: evidenceAudit.reason ?? '—' }), evidenceAudit.nextAction && _jsx("p", { className: "mt-1 text-[12px] text-ink-3", children: evidenceAudit.nextAction })] }))] })), _jsxs("details", { className: "mb-8 border-t border-line pt-4", "data-testid": "principle-extra-context", children: [_jsx("summary", { className: "cursor-pointer text-sm text-gov", children: t('principles.detail.extraContext') }), _jsxs("div", { className: "mt-5", children: [_jsxs("section", { className: "mb-8", children: [_jsx(SectionTitle, { children: t("principles.detail.whyExists") }), _jsxs("div", { className: "space-y-3 mb-6", children: [_jsxs("div", { children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("principles.detail.applicable", { defaultValue: "适用场景(原始触发配置)" }) }), _jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed font-mono break-all", children: principle.triggerPattern || t("principles.detail.notSpecified", { defaultValue: "未指定" }) })] }), _jsxs("div", { children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("principles.detail.expectedBehavior", { defaultValue: "预期行为(原始建议)" }) }), _jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed", children: principle.action || t("principles.detail.notSpecified", { defaultValue: "未指定" }) })] })] }), principle.derivedFromPainIds.length > 0 && (_jsxs("div", { children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("principles.detail.evidence") }), _jsxs("div", { className: "mt-2 flex items-center gap-3 flex-wrap", children: [_jsx("p", { className: "text-ink-2 text-[14px] leading-relaxed", children: t("principles.detail.evidenceCount", {
566
+ defaultValue: "已关联 {{count}} 条证据记录",
567
+ count: principle.derivedFromPainIds.length,
568
+ }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: async () => {
569
+ try {
570
+ const summary = principle.derivedFromPainIds
571
+ .map((pid, i) => `pain_${i + 1}_id: ${pid}`)
572
+ .join("\n");
573
+ await navigator.clipboard.writeText(summary);
574
+ setEvidenceCopied(true);
575
+ setTimeout(() => setEvidenceCopied(false), 2000);
576
+ }
577
+ catch (error) {
578
+ // clipboard unavailable — expand as fallback
579
+ console.warn("Evidence ID copy failed; expanding technical details.", error);
580
+ if (!evidenceExpanded)
581
+ setEvidenceExpanded(true);
582
+ }
583
+ }, className: "font-mono text-[11px] h-7", children: evidenceCopied
584
+ ? t("principles.detail.evidenceCopied", { defaultValue: "已复制" })
585
+ : t("principles.detail.copyEvidenceId", { defaultValue: "复制证据 ID" }) }), _jsx("button", { type: "button", onClick: () => setEvidenceExpanded((v) => !v), className: "font-mono text-[11px] text-ink-4 hover:text-ink-3 transition-colors underline-offset-2 hover:underline", children: t("principles.detail.expandTechDetails", { defaultValue: "展开技术细节" }) }), _jsx(Link, { to: "/pain", className: "font-mono text-[11px] text-gov hover:underline transition-colors", children: t("principles.detail.viewEvidenceChain", { defaultValue: "在证据链页查看 →" }) })] }), evidenceExpanded && (_jsx("div", { className: "mt-3 p-3 bg-paper-2 border border-line rounded-[var(--radius-sm)]", children: _jsx("div", { className: "grid grid-cols-[auto 1fr] gap-x-4 gap-y-2 text-[13px]", children: principle.derivedFromPainIds.map((painId, idx) => (_jsxs("div", { className: "contents", children: [_jsx("span", { className: "font-mono text-ink-4", children: t("principles.detail.evidenceIdLabel", {
586
+ defaultValue: "证据 {{n}} ID",
587
+ n: idx + 1,
588
+ }) }), _jsx("span", { className: "font-mono text-ink-2 break-all", children: painId })] }, `${painId}-${idx}`))) }) }))] }))] }), _jsxs("section", { className: "mb-8 border-t border-line pt-6", children: [_jsx(SectionTitle, { children: t("principles.detail.ownerReflection") }), _jsxs("div", { className: "space-y-3", children: [_jsx("div", { className: "border-l-2 border-l-gov pl-3 text-ink-2 text-[13px] leading-relaxed", children: t("principles.detail.reflectionQ1") }), _jsx("div", { className: "border-l-2 border-l-gov pl-3 text-ink-2 text-[13px] leading-relaxed", children: t("principles.detail.reflectionQ2") }), _jsx("div", { className: "border-l-2 border-l-gov pl-3 text-ink-2 text-[13px] leading-relaxed", children: t("principles.detail.reflectionQ3") })] })] })] })] }), _jsxs("details", { className: "mb-8 border border-line rounded-[var(--radius-md)]", children: [_jsx("summary", { className: "px-4 py-3 cursor-pointer font-mono text-[11px] uppercase tracking-[0.1em] text-ink-3 hover:text-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov", children: t("principles.detail.trajectory") }), _jsxs("div", { className: "px-4 pb-4 border-t border-line pt-4", children: [governance !== null && (_jsxs("section", { className: "mb-6", "data-testid": "governance-timeline", children: [_jsx(SectionTitle, { children: t('principles.detail.governance.timeline') }), governance.timeline.length === 0 ? _jsx("p", { className: "text-[13px] text-ink-4", children: t('principles.detail.governance.timelineEmpty') }) : (_jsx("ol", { className: "space-y-3 border-l border-line pl-4", children: governance.timeline.map((event, index) => {
565
589
  const derived = event.code === 'revision_requested' || event.code === 'revision_reopened';
566
590
  return _jsxs("li", { children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-[13px] text-ink-2", children: t(`principles.detail.governance.timelineCode.${event.code}`, { defaultValue: event.code }) }), _jsx("span", { className: "rounded border border-line px-1.5 py-0.5 font-mono text-[10px] text-ink-4", children: t(`principles.detail.governance.${derived ? 'derived' : 'fact'}`) })] }), _jsx("p", { className: "mt-0.5 font-mono text-[11px] text-ink-4", children: event.occurredAt ?? event.recordedAt })] }, `${event.sourceRef.type}-${event.sourceRef.id}-${event.code}-${index}`);
567
591
  }) }))] })), trajectory?.degraded && (_jsxs("div", { className: "mb-4 p-3 bg-amber/5 border border-amber/20 rounded-[var(--radius-sm)]", children: [_jsx("p", { className: "text-amber text-[12px] font-mono", children: trajectory.degraded.reason }), _jsx("p", { className: "text-ink-4 text-[11px] mt-1", children: trajectory.degraded.nextAction })] })), _jsx("div", { className: "space-y-4", children: (trajectory?.stages ?? []).length > 0 ? (trajectory.stages.map((stage) => (_jsxs("div", { className: "flex gap-4", children: [_jsx("span", { className: "font-mono text-[12px] text-ink-3 min-w-[80px]", children: t(STAGE_LABEL_KEYS[stage.key] ?? `principles.detail.stage${stage.key}`, { defaultValue: stage.key }) }), _jsx("div", { className: "flex-1", children: stage.status === 'available' ? (_jsxs(_Fragment, { children: [_jsx("p", { className: "text-ink-2 text-[13px]", children: stage.summary }), stage.detail && (_jsx("p", { className: "text-ink-3 text-[12px] mt-0.5", children: stage.detail })), stage.timestamp && (_jsx("p", { className: "text-ink-4 text-[11px] mt-0.5 font-mono", children: stage.timestamp }))] })) : (_jsxs("p", { className: "text-ink-4 text-[13px]", children: [stage.unavailableReason ?? '—', stage.nextAction && (_jsx("span", { className: "block text-ink-4 text-[11px] mt-0.5", children: stage.nextAction }))] })) })] }, stage.key)))) : (