create-principles-disciple 1.102.0 → 1.103.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/console/dist/server/config/pd-config-store.d.ts +50 -1
  2. package/console/dist/server/config/pd-config-store.js +364 -1
  3. package/console/dist/server/models/ActivationsConsoleModel.d.ts +7 -4
  4. package/console/dist/server/models/ActivationsConsoleModel.js +7 -6
  5. package/console/dist/server/routes/config.js +92 -2
  6. package/console/dist/ui/api.d.ts +44 -3
  7. package/console/dist/ui/api.js +58 -2
  8. package/console/dist/ui/components/onboarding/DemoResultView.js +19 -1
  9. package/console/dist/ui/i18n/en.json +63 -2
  10. package/console/dist/ui/i18n/zh-CN.json +63 -2
  11. package/console/dist/ui/pages/activation/ActivationPage.js +11 -11
  12. package/console/dist/ui/pages/activation/ActivationValidators.js +14 -13
  13. package/console/dist/ui/pages/control-center/AgentCard.js +56 -7
  14. package/console/dist/ui/pages/control-center/ControlCenterPage.js +2 -1
  15. package/console/dist/ui/pages/control-center/RuntimeProfileManager.d.ts +31 -0
  16. package/console/dist/ui/pages/control-center/RuntimeProfileManager.js +234 -0
  17. package/console/dist/ui/pages/debt/DebtPage.js +2 -2
  18. package/console/dist/ui/utils/validators.d.ts +26 -3
  19. package/console/dist/ui/utils/validators.js +23 -6
  20. package/console/dist/web/assets/app.css +41 -0
  21. package/console/dist/web/assets/app.js +1918 -1160
  22. package/core/dist/runtime-v2/__tests__/resolve-runtime-config-from-pd-config.test.js +8 -10
  23. package/core/dist/runtime-v2/__tests__/resolve-runtime-config-from-pd-config.test.js.map +1 -1
  24. package/core/dist/runtime-v2/adapter/__tests__/l2-resolve-model-compat.test.d.ts +2 -0
  25. package/core/dist/runtime-v2/adapter/__tests__/l2-resolve-model-compat.test.d.ts.map +1 -0
  26. package/core/dist/runtime-v2/adapter/__tests__/l2-resolve-model-compat.test.js +81 -0
  27. package/core/dist/runtime-v2/adapter/__tests__/l2-resolve-model-compat.test.js.map +1 -0
  28. package/core/dist/runtime-v2/adapter/__tests__/pi-ai-runtime-adapter.test.js +19 -0
  29. package/core/dist/runtime-v2/adapter/__tests__/pi-ai-runtime-adapter.test.js.map +1 -1
  30. package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts +8 -0
  31. package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts.map +1 -1
  32. package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js +4 -1
  33. package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js.map +1 -1
  34. package/core/dist/runtime-v2/candidate-intake-service.d.ts.map +1 -1
  35. package/core/dist/runtime-v2/candidate-intake-service.js +92 -6
  36. package/core/dist/runtime-v2/candidate-intake-service.js.map +1 -1
  37. package/core/dist/runtime-v2/candidate-intake.d.ts +38 -0
  38. package/core/dist/runtime-v2/candidate-intake.d.ts.map +1 -1
  39. package/core/dist/runtime-v2/candidate-intake.js +48 -0
  40. package/core/dist/runtime-v2/candidate-intake.js.map +1 -1
  41. package/core/dist/runtime-v2/config/__tests__/pd-config-agent-binding.test.js +26 -1
  42. package/core/dist/runtime-v2/config/__tests__/pd-config-agent-binding.test.js.map +1 -1
  43. package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js +9 -5
  44. package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js.map +1 -1
  45. package/core/dist/runtime-v2/config/__tests__/pd-config-validation-edge-cases.test.js +53 -33
  46. package/core/dist/runtime-v2/config/__tests__/pd-config-validation-edge-cases.test.js.map +1 -1
  47. package/core/dist/runtime-v2/config/pd-config-agent-binding.d.ts +2 -0
  48. package/core/dist/runtime-v2/config/pd-config-agent-binding.d.ts.map +1 -1
  49. package/core/dist/runtime-v2/config/pd-config-agent-binding.js +3 -0
  50. package/core/dist/runtime-v2/config/pd-config-agent-binding.js.map +1 -1
  51. package/core/dist/runtime-v2/config/pd-config-defaults.d.ts +7 -3
  52. package/core/dist/runtime-v2/config/pd-config-defaults.d.ts.map +1 -1
  53. package/core/dist/runtime-v2/config/pd-config-defaults.js +27 -3
  54. package/core/dist/runtime-v2/config/pd-config-defaults.js.map +1 -1
  55. package/core/dist/runtime-v2/config/pd-config-redaction.d.ts.map +1 -1
  56. package/core/dist/runtime-v2/config/pd-config-redaction.js +5 -2
  57. package/core/dist/runtime-v2/config/pd-config-redaction.js.map +1 -1
  58. package/core/dist/runtime-v2/config/pd-config-types.d.ts +6 -0
  59. package/core/dist/runtime-v2/config/pd-config-types.d.ts.map +1 -1
  60. package/core/dist/runtime-v2/config/pd-config-types.js.map +1 -1
  61. package/core/dist/runtime-v2/config/pd-config-validate.d.ts.map +1 -1
  62. package/core/dist/runtime-v2/config/pd-config-validate.js +11 -6
  63. package/core/dist/runtime-v2/config/pd-config-validate.js.map +1 -1
  64. package/core/dist/runtime-v2/index.d.ts +2 -1
  65. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  66. package/core/dist/runtime-v2/index.js +1 -0
  67. package/core/dist/runtime-v2/index.js.map +1 -1
  68. package/core/dist/runtime-v2/internalization/__tests__/artificer-prompt-builder-v2.test.js +7 -0
  69. package/core/dist/runtime-v2/internalization/__tests__/artificer-prompt-builder-v2.test.js.map +1 -1
  70. package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-runner.test.js +7 -6
  71. package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-runner.test.js.map +1 -1
  72. package/core/dist/runtime-v2/internalization/artificer-prompt-builder.js +1 -1
  73. package/core/dist/runtime-v2/internalization/diag-distiller-runner.js +4 -4
  74. package/core/dist/runtime-v2/internalization/diag-distiller-runner.js.map +1 -1
  75. package/core/dist/runtime-v2/internalization/diag-rootcause-runner.js +5 -5
  76. package/core/dist/runtime-v2/internalization/diag-rootcause-runner.js.map +1 -1
  77. package/core/dist/runtime-v2/internalization/diag-router-runner.js +4 -4
  78. package/core/dist/runtime-v2/internalization/diag-router-runner.js.map +1 -1
  79. package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts +2 -0
  80. package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts.map +1 -1
  81. package/core/dist/runtime-v2/pain-signal-runtime-factory.js +2 -0
  82. package/core/dist/runtime-v2/pain-signal-runtime-factory.js.map +1 -1
  83. package/dist/installer.d.ts.map +1 -1
  84. package/dist/installer.js +5 -1
  85. package/dist/installer.js.map +1 -1
  86. package/dist/mvp-config.d.ts.map +1 -1
  87. package/dist/mvp-config.js +22 -10
  88. package/dist/mvp-config.js.map +1 -1
  89. package/package.json +1 -1
  90. package/pd-cli/dist/commands/__tests__/runtime-probe-config.test.js +2 -2
  91. package/pd-cli/dist/commands/__tests__/runtime-probe-config.test.js.map +1 -1
  92. package/pd-cli/dist/commands/demo-story-a.d.ts.map +1 -1
  93. package/pd-cli/dist/commands/demo-story-a.js +4 -2
  94. package/pd-cli/dist/commands/demo-story-a.js.map +1 -1
  95. package/pd-cli/dist/commands/proven-channel-baseline.d.ts.map +1 -1
  96. package/pd-cli/dist/commands/proven-channel-baseline.js +4 -2
  97. package/pd-cli/dist/commands/proven-channel-baseline.js.map +1 -1
  98. package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
  99. package/pd-cli/dist/commands/runtime-activation.js +8 -2
  100. package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
  101. package/pd-cli/dist/commands/runtime-canary.d.ts.map +1 -1
  102. package/pd-cli/dist/commands/runtime-canary.js +4 -2
  103. package/pd-cli/dist/commands/runtime-canary.js.map +1 -1
  104. package/pd-cli/dist/commands/runtime-health-snapshot.d.ts.map +1 -1
  105. package/pd-cli/dist/commands/runtime-health-snapshot.js +4 -2
  106. package/pd-cli/dist/commands/runtime-health-snapshot.js.map +1 -1
  107. package/pd-cli/dist/commands/runtime-internalization-integrity.d.ts.map +1 -1
  108. package/pd-cli/dist/commands/runtime-internalization-integrity.js +4 -2
  109. package/pd-cli/dist/commands/runtime-internalization-integrity.js.map +1 -1
  110. package/pd-cli/dist/services/config-doctor.d.ts.map +1 -1
  111. package/pd-cli/dist/services/config-doctor.js +9 -2
  112. package/pd-cli/dist/services/config-doctor.js.map +1 -1
  113. package/pd-cli/dist/services/runtime-adapter-resolver.d.ts.map +1 -1
  114. package/pd-cli/dist/services/runtime-adapter-resolver.js +1 -0
  115. package/pd-cli/dist/services/runtime-adapter-resolver.js.map +1 -1
  116. package/plugin/dist/core/rule-host.d.ts +5 -2
  117. package/plugin/dist/core/rule-host.js +15 -2
  118. package/plugin/dist/hooks/gate.js +1 -1
  119. package/plugin/dist/service/evolution-dedup.d.ts +1 -1
  120. package/plugin/dist/service/evolution-worker.d.ts +7 -31
  121. package/plugin/dist/service/evolution-worker.js +17 -36
  122. package/plugin/dist/service/queue-io.js +14 -2
  123. package/plugin/dist/service/queue-migration.d.ts +27 -26
  124. package/plugin/dist/service/queue-migration.js +57 -0
  125. package/plugin/templates/langs/en/core/AGENTS.md +2 -2
  126. package/plugin/templates/langs/en/core/TOOLS.md +1 -1
  127. package/plugin/templates/langs/zh/core/AGENTS.md +2 -2
  128. package/plugin/templates/langs/zh/core/TOOLS.md +1 -1
  129. package/templates/langs/en/core/AGENTS.md +2 -2
  130. package/templates/langs/en/core/TOOLS.md +1 -1
  131. package/templates/langs/zh/core/AGENTS.md +2 -2
  132. package/templates/langs/zh/core/TOOLS.md +1 -1
  133. package/plugin/dist/constants/diagnostician.d.ts +0 -12
  134. package/plugin/dist/constants/diagnostician.js +0 -65
  135. package/plugin/dist/service/evolution-queue-migration.d.ts +0 -128
  136. package/plugin/dist/service/evolution-queue-migration.js +0 -53
  137. package/plugin/templates/langs/en/skills/pd-diagnostician/SKILL.md +0 -466
  138. package/plugin/templates/langs/zh/skills/pd-diagnostician/SKILL.md +0 -391
  139. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +0 -287
@@ -1,6 +1,6 @@
1
1
  import type { ApiResponse } from "../types.js";
2
2
  import { listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm } from "./utils/signal-keywords-api.js";
3
- import type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, ActivationsData, DisableActivationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, RollbackResultData, ApprovalRecordData, PrinciplesListData, ApprovalsGroupedData, EvidenceChainData, TrajectoryData, IntentSummaryData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, IntentInitResultData, IntentSaveResultData, IntentRawContentData, IntentVersionData } from "./utils/validators.js";
3
+ import type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, RuntimeProfileMutationData, ReadinessCheckData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, ActivationsData, DisableActivationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, RollbackResultData, ApprovalRecordData, PrinciplesListData, ApprovalsGroupedData, EvidenceChainData, TrajectoryData, IntentSummaryData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, IntentInitResultData, IntentSaveResultData, IntentRawContentData, IntentVersionData } from "./utils/validators.js";
4
4
  declare function getToken(): string | null;
5
5
  declare function setToken(token: string): void;
6
6
  declare function clearToken(): void;
@@ -41,6 +41,47 @@ declare function fetchConfigSummary(): Promise<ApiResponse<ConfigSummaryData>>;
41
41
  declare function fetchConfigCatalog(): Promise<ApiResponse<ConfigCatalogData>>;
42
42
  declare function updateAgentBinding(agentName: string, runtimeProfile: string, enabled: boolean): Promise<ApiResponse<AgentBindingUpdateData>>;
43
43
  declare function updateDefaultRuntime(defaultRuntime: string): Promise<ApiResponse<DefaultRuntimeUpdateData>>;
44
+ /**
45
+ * Create a new runtime profile.
46
+ *
47
+ * Body shape: `{ id: string, profile: { type, provider?, model?, ... } }`.
48
+ * Server validates per-type requirements (pi-ai needs provider/model/apiKeyEnv)
49
+ * and returns 400 with a message on validation failure. The server response is
50
+ * `{ profileId, profile }`; we validate the contract fields and rely on the
51
+ * caller to re-fetch the catalog for display.
52
+ *
53
+ * rc-9: server-side validation errors surface as `result.error` (no silent
54
+ * fallback) — the request() helper extracts the message from the error envelope.
55
+ */
56
+ declare function createRuntimeProfile(id: string, profile: Record<string, unknown>): Promise<ApiResponse<RuntimeProfileMutationData>>;
57
+ /**
58
+ * Update an existing runtime profile (partial patch).
59
+ *
60
+ * Body shape: a partial profile object (e.g. `{ model: 'new-model' }`).
61
+ * The server rejects type changes with 400; other fields are merged.
62
+ */
63
+ declare function updateRuntimeProfile(profileId: string, patch: Record<string, unknown>): Promise<ApiResponse<RuntimeProfileMutationData>>;
64
+ /**
65
+ * Delete a runtime profile.
66
+ *
67
+ * The server rejects deletion with 400 when the profile is the defaultRuntime
68
+ * or is referenced by any agent (error message lists the agent names). The
69
+ * caller must surface this error to the user (rc-9: no silent fallback).
70
+ */
71
+ declare function deleteRuntimeProfile(profileId: string): Promise<ApiResponse<RuntimeProfileMutationData>>;
72
+ /**
73
+ * Fetch dynamic readiness for a single agent (GET /api/v1/config/readiness/:name).
74
+ *
75
+ * The summary/catalog endpoints return a static, pessimistic readiness that
76
+ * doesn't probe the actual provider. This endpoint performs a live check
77
+ * (e.g. testing whether the API key env var is set and the provider responds).
78
+ *
79
+ * Used by AgentCard when L2 is expanded and the static readiness is 'unknown'
80
+ * — the pessimistic value is replaced with the live result. On failure the
81
+ * caller falls back to the static value (rc-9: the error is surfaced via the
82
+ * ApiResponse error envelope, not silently swallowed).
83
+ */
84
+ declare function fetchAgentReadiness(agentName: string): Promise<ApiResponse<ReadinessCheckData>>;
44
85
  declare function patchFeatureFlag(featureName: string, enabled: boolean): Promise<ApiResponse<FeatureFlagUpdateData>>;
45
86
  declare function fetchOutputLanguage(): Promise<ApiResponse<OutputLanguageData>>;
46
87
  declare function updateOutputLanguage(outputLanguage: string): Promise<ApiResponse<OutputLanguageData>>;
@@ -106,8 +147,8 @@ export interface FollowUpPayload {
106
147
  candidateId?: string;
107
148
  }
108
149
  declare function dispatchFollowUp(decisionId: string, payload: FollowUpPayload): Promise<ApiResponse<FollowUpResponseData>>;
109
- export { request, listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm, getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleTrajectory, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
110
- export type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, ActivationsData, DisableActivationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, RollbackResultData, ApprovalRecordData, PrinciplesListData, ApprovalsGroupedData, EvidenceChainData, EvidenceChainRecordData, EvidenceChainStateData, TrajectoryData, TrajectoryStageData, IntentSummaryData, IntentSectionsData, IntentDocWarningData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, LinkCandidateFollowUpData, GuideRulehostFollowUpData, GeneratePatchProposalFollowUpData, IntentVersionEntry, IntentVersionData, } from "./utils/validators.js";
150
+ export { request, listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm, getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleTrajectory, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
151
+ export type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, RuntimeProfileMutationData, ReadinessCheckData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, ActivationsData, DisableActivationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, RollbackResultData, ApprovalRecordData, PrinciplesListData, ApprovalsGroupedData, EvidenceChainData, EvidenceChainRecordData, EvidenceChainStateData, TrajectoryData, TrajectoryStageData, IntentSummaryData, IntentSectionsData, IntentDocWarningData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, LinkCandidateFollowUpData, GuideRulehostFollowUpData, GeneratePatchProposalFollowUpData, IntentVersionEntry, IntentVersionData, } from "./utils/validators.js";
111
152
  export type { SignalKeyword, PendingSignalTerm } from "./utils/signal-keywords-types.js";
112
153
  export type { ActivationRecordData as ActivationRecord } from "./utils/validators.js";
113
154
  export type { ApprovalRecordData as ApprovalRecord } from "./utils/validators.js";
@@ -1,5 +1,5 @@
1
1
  import { listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm, } from "./utils/signal-keywords-api.js";
2
- import { validateErrorResponse, validateHeaders, validateFeedbackReport, validateFeedbackDraftsList, validateFeedbackDraftEnvelope, validateDeleteEnvelope, validateWorkspaceEntry, validateWorkspaceList, validateRemovedEnvelope, validateSyncResult, validateConfigSummary, validateConfigCatalog, validateAgentBindingUpdate, validateDefaultRuntimeUpdate, validateFeatureFlagUpdate, validateOutputLanguage, validateGovernanceQueue, validateActivations, validateDisableActivation, validateLifecycleMetrics, validateUpdateStatus, validateUpdateHistory, validateApplyUpdateResult, validateRollbackResult, validateApprovalRecordDirect, validatePrinciplesList, validateApprovalsGrouped, validateEvidenceChain, validateTrajectoryData, validateIntentSummary, validateIntentDecisionList, validateIntentDecisionResult, validateIntentDecisionSummary, validateFollowUpResponse, validateIntentInitResult, validateIntentSaveResult, validateIntentRawContent, validateIntentVersions, } from "./utils/validators.js";
2
+ import { validateErrorResponse, validateHeaders, validateFeedbackReport, validateFeedbackDraftsList, validateFeedbackDraftEnvelope, validateDeleteEnvelope, validateWorkspaceEntry, validateWorkspaceList, validateRemovedEnvelope, validateSyncResult, validateConfigSummary, validateConfigCatalog, validateAgentBindingUpdate, validateDefaultRuntimeUpdate, validateRuntimeProfileMutation, validateReadinessCheck, validateFeatureFlagUpdate, validateOutputLanguage, validateGovernanceQueue, validateActivations, validateDisableActivation, validateLifecycleMetrics, validateUpdateStatus, validateUpdateHistory, validateApplyUpdateResult, validateRollbackResult, validateApprovalRecordDirect, validatePrinciplesList, validateApprovalsGrouped, validateEvidenceChain, validateTrajectoryData, validateIntentSummary, validateIntentDecisionList, validateIntentDecisionResult, validateIntentDecisionSummary, validateFollowUpResponse, validateIntentInitResult, validateIntentSaveResult, validateIntentRawContent, validateIntentVersions, } from "./utils/validators.js";
3
3
  // ── Auth ──────────────────────────────────────────────────────────────────────
4
4
  function getToken() {
5
5
  return sessionStorage.getItem("pd_token");
@@ -195,6 +195,62 @@ async function updateDefaultRuntime(defaultRuntime) {
195
195
  body: JSON.stringify({ defaultRuntime }),
196
196
  }, validateDefaultRuntimeUpdate);
197
197
  }
198
+ // ── Runtime Profile CRUD (POST/PATCH/DELETE /api/v1/config/profiles) ──────────
199
+ /**
200
+ * Create a new runtime profile.
201
+ *
202
+ * Body shape: `{ id: string, profile: { type, provider?, model?, ... } }`.
203
+ * Server validates per-type requirements (pi-ai needs provider/model/apiKeyEnv)
204
+ * and returns 400 with a message on validation failure. The server response is
205
+ * `{ profileId, profile }`; we validate the contract fields and rely on the
206
+ * caller to re-fetch the catalog for display.
207
+ *
208
+ * rc-9: server-side validation errors surface as `result.error` (no silent
209
+ * fallback) — the request() helper extracts the message from the error envelope.
210
+ */
211
+ async function createRuntimeProfile(id, profile) {
212
+ return request('/api/v1/config/profiles', {
213
+ method: 'POST',
214
+ body: JSON.stringify({ id, profile }),
215
+ }, validateRuntimeProfileMutation);
216
+ }
217
+ /**
218
+ * Update an existing runtime profile (partial patch).
219
+ *
220
+ * Body shape: a partial profile object (e.g. `{ model: 'new-model' }`).
221
+ * The server rejects type changes with 400; other fields are merged.
222
+ */
223
+ async function updateRuntimeProfile(profileId, patch) {
224
+ return request(`/api/v1/config/profiles/${encodeURIComponent(profileId)}`, {
225
+ method: 'PATCH',
226
+ body: JSON.stringify(patch),
227
+ }, validateRuntimeProfileMutation);
228
+ }
229
+ /**
230
+ * Delete a runtime profile.
231
+ *
232
+ * The server rejects deletion with 400 when the profile is the defaultRuntime
233
+ * or is referenced by any agent (error message lists the agent names). The
234
+ * caller must surface this error to the user (rc-9: no silent fallback).
235
+ */
236
+ async function deleteRuntimeProfile(profileId) {
237
+ return request(`/api/v1/config/profiles/${encodeURIComponent(profileId)}`, { method: 'DELETE' }, validateRuntimeProfileMutation);
238
+ }
239
+ /**
240
+ * Fetch dynamic readiness for a single agent (GET /api/v1/config/readiness/:name).
241
+ *
242
+ * The summary/catalog endpoints return a static, pessimistic readiness that
243
+ * doesn't probe the actual provider. This endpoint performs a live check
244
+ * (e.g. testing whether the API key env var is set and the provider responds).
245
+ *
246
+ * Used by AgentCard when L2 is expanded and the static readiness is 'unknown'
247
+ * — the pessimistic value is replaced with the live result. On failure the
248
+ * caller falls back to the static value (rc-9: the error is surfaced via the
249
+ * ApiResponse error envelope, not silently swallowed).
250
+ */
251
+ async function fetchAgentReadiness(agentName) {
252
+ return request(`/api/v1/config/readiness/${encodeURIComponent(agentName)}`, undefined, validateReadinessCheck);
253
+ }
198
254
  // ── Feature Flag Toggle (spec 2026-06-27 §13.5) ─────────────────────────────
199
255
  async function patchFeatureFlag(featureName, enabled) {
200
256
  return request(`/api/v1/config/features/${encodeURIComponent(featureName)}`, {
@@ -313,4 +369,4 @@ export { request,
313
369
  // signal-keywords (UI stubs, see signal-keywords-api.ts)
314
370
  listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm,
315
371
  // auth
316
- getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleTrajectory, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
372
+ getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleTrajectory, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
@@ -1,5 +1,23 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useTranslation } from 'react-i18next';
3
+ /**
4
+ * Map backend demo stage identifiers (snake_case English, stable contract
5
+ * from demo-story-a-runner.ts) to localized labels. Falls back to the raw
6
+ * name if no mapping exists, so new stages still render (rc-9: no silent
7
+ * failure) but future stages should be added here.
8
+ */
9
+ const STAGE_LABEL_KEYS = {
10
+ evidence_seed: 'pages.welcome.step2.stages.evidenceSeed',
11
+ principle_proposal: 'pages.welcome.step2.stages.principleProposal',
12
+ owner_review: 'pages.welcome.step2.stages.ownerReview',
13
+ activation: 'pages.welcome.step2.stages.activation',
14
+ follow_up_observation: 'pages.welcome.step2.stages.followUpObservation',
15
+ rollback_proof: 'pages.welcome.step2.stages.rollbackProof',
16
+ };
17
+ function localizeStageName(rawName, t) {
18
+ const key = STAGE_LABEL_KEYS[rawName];
19
+ return key ? t(key) : rawName;
20
+ }
3
21
  export function DemoResultView({ result, loading, error }) {
4
22
  const { t } = useTranslation();
5
23
  if (loading) {
@@ -11,5 +29,5 @@ export function DemoResultView({ result, loading, error }) {
11
29
  if (!result) {
12
30
  return null;
13
31
  }
14
- return (_jsxs("div", { className: "demo-result-view", role: "region", "aria-label": t('pages.welcome.step2.demoComplete'), children: [result.simulated && (_jsx("div", { className: "demo-simulated-banner", role: "note", children: t('pages.welcome.step2.demoSimulatedNote') })), result.stages && result.stages.length > 0 && (_jsx("ol", { className: "demo-stages", children: result.stages.map((stage, idx) => (_jsxs("li", { className: `demo-stage demo-stage-${stage.status}`, children: [_jsx("span", { className: "demo-stage-name", children: stage.name }), stage.reason && _jsx("span", { className: "demo-stage-detail", children: stage.reason })] }, idx))) })), _jsxs("div", { className: "demo-labels", children: [_jsx("div", { className: "demo-label-item", children: _jsx("span", { className: "demo-label-title", children: t('pages.welcome.step2.evidenceLabel') }) }), _jsx("div", { className: "demo-label-item", children: _jsx("span", { className: "demo-label-title", children: t('pages.welcome.step2.candidateLabel') }) }), _jsx("div", { className: "demo-label-item", children: _jsx("span", { className: "demo-label-title", children: t('pages.welcome.step2.ownerGateLabel') }) }), _jsx("div", { className: "demo-label-item", children: _jsx("span", { className: "demo-label-title", children: t('pages.welcome.step2.activationLabel') }) }), _jsx("div", { className: "demo-label-item", children: _jsx("span", { className: "demo-label-title", children: t('pages.welcome.step2.rollbackLabel') }) })] })] }));
32
+ return (_jsxs("div", { className: "demo-result-view", role: "region", "aria-label": t('pages.welcome.step2.demoComplete'), children: [result.simulated && (_jsx("div", { className: "demo-simulated-banner", role: "note", children: t('pages.welcome.step2.demoSimulatedNote') })), result.stages && result.stages.length > 0 && (_jsx("ol", { className: "demo-stages", children: result.stages.map((stage, idx) => (_jsxs("li", { className: `demo-stage demo-stage-${stage.status}`, children: [_jsx("span", { className: "demo-stage-name", children: localizeStageName(stage.name, t) }), stage.reason && _jsx("span", { className: "demo-stage-detail", children: stage.reason })] }, idx))) })), _jsxs("div", { className: "demo-labels", children: [_jsx("div", { className: "demo-label-item", children: _jsx("span", { className: "demo-label-title", children: t('pages.welcome.step2.evidenceLabel') }) }), _jsx("div", { className: "demo-label-item", children: _jsx("span", { className: "demo-label-title", children: t('pages.welcome.step2.candidateLabel') }) }), _jsx("div", { className: "demo-label-item", children: _jsx("span", { className: "demo-label-title", children: t('pages.welcome.step2.ownerGateLabel') }) }), _jsx("div", { className: "demo-label-item", children: _jsx("span", { className: "demo-label-title", children: t('pages.welcome.step2.activationLabel') }) }), _jsx("div", { className: "demo-label-item", children: _jsx("span", { className: "demo-label-title", children: t('pages.welcome.step2.rollbackLabel') }) })] })] }));
15
33
  }
@@ -697,8 +697,61 @@
697
697
  },
698
698
  "techDetail": "Technical Details",
699
699
  "profileLabelShort": "Runtime",
700
+ "manageProfiles": "Manage Profiles",
701
+ "readinessChecking": "Checking readiness…",
700
702
  "unknownAgentsWarning": "Detected {{count}} unrecognized agent(s): {{names}}. They are not shown in groups.",
701
- "footerNote": "9 agents are distributed across the internalization pipeline and sidechain services. The Core Trio must be enabled together — otherwise PD cannot turn errors into principles."
703
+ "footerNote": "9 agents are distributed across the internalization pipeline and sidechain services. The Core Trio must be enabled together — otherwise PD cannot turn errors into principles.",
704
+ "profiles": {
705
+ "sectionTitle": "Runtime Profile Management",
706
+ "sectionDescription": "Create, edit, and delete runtime profiles. Profiles referenced by an agent or set as default cannot be deleted.",
707
+ "createButton": "Create Profile",
708
+ "editButton": "Edit",
709
+ "deleteButton": "Delete",
710
+ "cancelButton": "Cancel",
711
+ "saveButton": "Save",
712
+ "creating": "Creating…",
713
+ "saving": "Saving…",
714
+ "deleting": "Deleting…",
715
+ "empty": "No runtime profiles yet.",
716
+ "columnId": "ID",
717
+ "columnType": "Type",
718
+ "columnProvider": "Provider",
719
+ "columnModel": "Model",
720
+ "columnApiKeyEnv": "API Key Env Var",
721
+ "columnReadiness": "Readiness",
722
+ "columnActions": "Actions",
723
+ "formTitleCreate": "Create Runtime Profile",
724
+ "formTitleEdit": "Edit Profile: {{id}}",
725
+ "fieldId": "Profile ID",
726
+ "fieldIdHint": "Unique identifier, cannot be changed after creation (e.g. anthropic-cloud)",
727
+ "fieldIdPlaceholder": "my-profile",
728
+ "fieldType": "Type",
729
+ "fieldProvider": "Provider",
730
+ "fieldProviderPlaceholder": "anthropic",
731
+ "fieldModel": "Model",
732
+ "fieldModelPlaceholder": "claude-sonnet-4",
733
+ "fieldApiKeyEnv": "API Key Env Var Name",
734
+ "fieldApiKeyEnvHint": "Environment variable name, not the key value (e.g. ANTHROPIC_API_KEY)",
735
+ "fieldApiKeyEnvPlaceholder": "ANTHROPIC_API_KEY",
736
+ "fieldBaseUrl": "Base URL (optional)",
737
+ "fieldBaseUrlPlaceholder": "https://api.anthropic.com",
738
+ "fieldSource": "Source (optional)",
739
+ "fieldSourcePlaceholder": "default",
740
+ "typeOpenclaw": "openclaw",
741
+ "typePiAi": "pi-ai",
742
+ "validationIdRequired": "Profile ID is required",
743
+ "validationProviderRequired": "pi-ai profile requires provider",
744
+ "validationModelRequired": "pi-ai profile requires model",
745
+ "validationApiKeyEnvRequired": "pi-ai profile requires apiKeyEnv",
746
+ "deleteConfirmTitle": "Confirm Delete",
747
+ "deleteConfirmMessage": "Delete profile \"{{id}}\"? This action cannot be undone.",
748
+ "deleteConfirmAck": "Confirm Delete",
749
+ "deleteConfirmCancel": "Cancel",
750
+ "createSuccess": "Profile created",
751
+ "updateSuccess": "Profile updated",
752
+ "deleteSuccess": "Profile deleted",
753
+ "operationFailed": "Operation failed"
754
+ }
702
755
  },
703
756
  "signalKeywords": {
704
757
  "title": "Signal Keywords",
@@ -1029,7 +1082,15 @@
1029
1082
  "candidateLabel": "Candidate Principle",
1030
1083
  "ownerGateLabel": "Owner Gate: Review and approve",
1031
1084
  "activationLabel": "Activation Result",
1032
- "rollbackLabel": "Rollback path available"
1085
+ "rollbackLabel": "Rollback path available",
1086
+ "stages": {
1087
+ "evidenceSeed": "Evidence (simulated)",
1088
+ "principleProposal": "Candidate principle",
1089
+ "ownerReview": "Owner review",
1090
+ "activation": "Activation result",
1091
+ "followUpObservation": "Follow-up observation",
1092
+ "rollbackProof": "Rollback path ready"
1093
+ }
1033
1094
  },
1034
1095
  "step3": {
1035
1096
  "title": "Ready to record real evidence",
@@ -697,8 +697,61 @@
697
697
  },
698
698
  "techDetail": "技术细节",
699
699
  "profileLabelShort": "运行时",
700
+ "manageProfiles": "管理 Profiles",
701
+ "readinessChecking": "探测就绪中…",
700
702
  "unknownAgentsWarning": "检测到 {{count}} 个未识别的代理:{{names}}。它们未被分组显示。",
701
- "footerNote": "9 个代理分布在内化管道与侧链服务两条路径上。核心三件套必须一起开,否则 PD 无法把错误转化为原则。"
703
+ "footerNote": "9 个代理分布在内化管道与侧链服务两条路径上。核心三件套必须一起开,否则 PD 无法把错误转化为原则。",
704
+ "profiles": {
705
+ "sectionTitle": "运行时配置管理",
706
+ "sectionDescription": "创建、编辑、删除 runtime profile。被智能体引用或设为默认的 profile 无法删除。",
707
+ "createButton": "新建 Profile",
708
+ "editButton": "编辑",
709
+ "deleteButton": "删除",
710
+ "cancelButton": "取消",
711
+ "saveButton": "保存",
712
+ "creating": "创建中…",
713
+ "saving": "保存中…",
714
+ "deleting": "删除中…",
715
+ "empty": "暂无 runtime profile。",
716
+ "columnId": "ID",
717
+ "columnType": "类型",
718
+ "columnProvider": "Provider",
719
+ "columnModel": "Model",
720
+ "columnApiKeyEnv": "API Key 环境变量",
721
+ "columnReadiness": "就绪",
722
+ "columnActions": "操作",
723
+ "formTitleCreate": "新建 Runtime Profile",
724
+ "formTitleEdit": "编辑 Profile: {{id}}",
725
+ "fieldId": "Profile ID",
726
+ "fieldIdHint": "唯一标识符,创建后不可修改(如 anthropic-cloud)",
727
+ "fieldIdPlaceholder": "my-profile",
728
+ "fieldType": "类型",
729
+ "fieldProvider": "Provider",
730
+ "fieldProviderPlaceholder": "anthropic",
731
+ "fieldModel": "Model",
732
+ "fieldModelPlaceholder": "claude-sonnet-4",
733
+ "fieldApiKeyEnv": "API Key 环境变量名",
734
+ "fieldApiKeyEnvHint": "环境变量名,不是 key 值(如 ANTHROPIC_API_KEY)",
735
+ "fieldApiKeyEnvPlaceholder": "ANTHROPIC_API_KEY",
736
+ "fieldBaseUrl": "Base URL(可选)",
737
+ "fieldBaseUrlPlaceholder": "https://api.anthropic.com",
738
+ "fieldSource": "Source(可选)",
739
+ "fieldSourcePlaceholder": "default",
740
+ "typeOpenclaw": "openclaw",
741
+ "typePiAi": "pi-ai",
742
+ "validationIdRequired": "Profile ID 不能为空",
743
+ "validationProviderRequired": "pi-ai profile 必须填写 provider",
744
+ "validationModelRequired": "pi-ai profile 必须填写 model",
745
+ "validationApiKeyEnvRequired": "pi-ai profile 必须填写 apiKeyEnv",
746
+ "deleteConfirmTitle": "确认删除",
747
+ "deleteConfirmMessage": "确定要删除 profile「{{id}}」吗?此操作不可撤销。",
748
+ "deleteConfirmAck": "确认删除",
749
+ "deleteConfirmCancel": "取消",
750
+ "createSuccess": "Profile 创建成功",
751
+ "updateSuccess": "Profile 已更新",
752
+ "deleteSuccess": "Profile 已删除",
753
+ "operationFailed": "操作失败"
754
+ }
702
755
  },
703
756
  "signalKeywords": {
704
757
  "title": "信号词库",
@@ -1029,7 +1082,15 @@
1029
1082
  "candidateLabel": "候选原则",
1030
1083
  "ownerGateLabel": "拥有者审查:批准 / 修改 / 拒绝",
1031
1084
  "activationLabel": "激活结果",
1032
- "rollbackLabel": "可回滚路径已就绪"
1085
+ "rollbackLabel": "可回滚路径已就绪",
1086
+ "stages": {
1087
+ "evidenceSeed": "证据(模拟)",
1088
+ "principleProposal": "候选原则",
1089
+ "ownerReview": "拥有者审查",
1090
+ "activation": "激活结果",
1091
+ "followUpObservation": "后续观察",
1092
+ "rollbackProof": "可回滚路径已就绪"
1093
+ }
1033
1094
  },
1034
1095
  "step3": {
1035
1096
  "title": "准备好记录真实证据",
@@ -25,14 +25,14 @@ function ActivationFactCard({ record, lifecycleData, onDisable, disabling, }) {
25
25
  const neverActivated = record.activatedAt === null;
26
26
  const channelLabel = getChannelLabel(record.channel, t);
27
27
  const reversible = isReversibleChannel(record.channel);
28
- return (_jsxs("article", { className: `relative pl-[22px] py-[18px] pr-[18px] bg-panel border rounded-[6px] transition-colors hover:border-line-2 ${neverActivated ? "border-amber/30 border-l-[3px] border-l-amber" : "border-line"}`, "data-testid": `activation-card-${record.id}`, children: [_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 ${record.status === "active"
28
+ return (_jsxs("article", { className: `relative pl-[22px] py-[18px] pr-[18px] bg-panel border rounded-[6px] transition-colors hover:border-line-2 ${neverActivated ? "border-amber/30 border-l-[3px] border-l-amber" : "border-line"}`, "data-testid": `activation-card-${record.activationId}`, children: [_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 ${record.status === "active"
29
29
  ? "border-green/35 text-green bg-green/5"
30
30
  : "border-line text-ink-4 bg-surface/80"}`, role: "status", children: record.status === "active" ? t("pages.activation.statusActive") : t("pages.activation.statusInactive") }), _jsx("span", { className: "inline-flex items-center border border-line rounded-[2px] px-[7px] py-1 font-mono text-[11px] text-ink-3 bg-surface/80 uppercase", children: channelLabel }), reversible && (_jsx("span", { className: "inline-flex items-center border border-amber/35 text-amber rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase", children: t("pages.activation.tagReversible") })), !reversible && record.channel === "code_tool_hook" && (_jsx("span", { className: "inline-flex items-center border border-danger/35 text-danger rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase", children: t("pages.activation.tagHighRisk") })), neverActivated && (_jsx("span", { className: "inline-flex items-center border border-amber/35 text-amber rounded-[2px] px-[7px] py-1 font-mono text-[11px] uppercase", children: t("pages.activation.tagNeverActivated") }))] }), _jsxs("div", { className: "mt-[14px] mb-2", children: [_jsx("span", { className: "text-ink-2 text-[13px]", children: t("pages.activation.principleLabel") }), " ", _jsx(Link, { to: `/principles/${record.principleId}`, className: "text-gov text-[13px] hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "data-testid": `principle-link-${record.principleId}`, title: record.principleId, children: record.action }), _jsx("span", { className: "ml-2 font-mono text-[11px] text-ink-4", children: record.principleId })] }), _jsxs("div", { className: "text-ink-3 text-[13px] leading-relaxed space-y-1", children: [_jsxs("div", { children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.actionLabel") }), " ", _jsx("span", { className: "text-ink-2", children: record.action })] }), _jsxs("div", { children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.targetLabel") }), " ", _jsx("span", { className: "text-ink-2 font-mono text-[12px]", children: record.targetRef })] }), _jsxs("div", { children: [_jsx("span", { className: "text-ink-4 font-mono text-[11px] uppercase", children: t("pages.activation.activatedAtLabel") }), " ", neverActivated ? (_jsx("span", { className: "text-amber", children: t("pages.activation.neverActivated") })) : (_jsx("span", { className: "text-ink-2 font-mono text-[12px] tabular-nums", children: new Date(record.activatedAt).toLocaleString() }))] })] }), lifecycleData !== undefined && (_jsxs("details", { className: "mt-4 group", children: [_jsx("summary", { className: "text-gov text-[13px] cursor-pointer hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("pages.activation.lifecycleToggle") }), _jsx("div", { className: "mt-2 pl-4 border-l-2 border-line", children: lifecycleData === null ? (_jsx("div", { className: "text-ink-4 text-[13px] py-2", children: t("pages.activation.lifecycleUnavailable") })) : lifecycleData.adherence.insufficientData ? (_jsx("div", { className: "text-ink-4 text-[13px] py-2", children: t("pages.activation.insufficientData") })) : (_jsxs("div", { className: "py-2 space-y-2", children: [_jsxs("div", { className: "text-ink-2 text-[13px]", children: [_jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: lifecycleData.adherence.rate !== null
31
31
  ? `${(lifecycleData.adherence.rate * 100).toFixed(0)}%`
32
- : "—" }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.adherenceLabel") }), _jsx("div", { className: "text-ink-4 text-[11px] mt-1 font-mono", children: t("pages.activation.lifecycleNote") })] }), lifecycleData.ruleMetrics.length > 0 && (_jsx("div", { className: "space-y-1", children: lifecycleData.ruleMetrics.map((rm) => (_jsxs("div", { className: "text-ink-3 text-[12px] font-mono", children: [_jsx("span", { className: "text-ink-2", children: rm.ruleId }), ":", " ", rm.triggered, " ", t("pages.activation.triggered"), " ", rm.lastTriggeredAt && (_jsxs("span", { className: "text-ink-4", children: ["(", new Date(rm.lastTriggeredAt).toLocaleString(), ")"] }))] }, rm.ruleId))) }))] })) })] })), record.status === "active" && reversible && (_jsx("div", { className: "mt-4", children: !showConfirm ? (_jsx("button", { onClick: () => setShowConfirm(true), disabled: disabling, className: "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 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "data-testid": `disable-btn-${record.id}`, children: t("pages.activation.disableAction") })) : (_jsxs("div", { className: "flex items-center gap-3 px-[14px] py-[10px] bg-surface border border-amber/25 rounded-[4px]", role: "alert", "data-testid": `confirm-bar-${record.id}`, children: [_jsx("span", { className: "text-ink-2 text-[13px] flex-1", children: t("pages.activation.confirmDisable") }), _jsx("button", { onClick: () => {
32
+ : "—" }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.adherenceLabel") }), _jsx("div", { className: "text-ink-4 text-[11px] mt-1 font-mono", children: t("pages.activation.lifecycleNote") })] }), lifecycleData.ruleMetrics.length > 0 && (_jsx("div", { className: "space-y-1", children: lifecycleData.ruleMetrics.map((rm) => (_jsxs("div", { className: "text-ink-3 text-[12px] font-mono", children: [_jsx("span", { className: "text-ink-2", children: rm.ruleId }), ":", " ", rm.triggered, " ", t("pages.activation.triggered"), " ", rm.lastTriggeredAt && (_jsxs("span", { className: "text-ink-4", children: ["(", new Date(rm.lastTriggeredAt).toLocaleString(), ")"] }))] }, rm.ruleId))) }))] })) })] })), record.status === "active" && reversible && (_jsx("div", { className: "mt-4", children: !showConfirm ? (_jsx("button", { onClick: () => setShowConfirm(true), disabled: disabling, className: "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 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "data-testid": `disable-btn-${record.activationId}`, children: t("pages.activation.disableAction") })) : (_jsxs("div", { className: "flex items-center gap-3 px-[14px] py-[10px] bg-surface border border-amber/25 rounded-[4px]", role: "alert", "data-testid": `confirm-bar-${record.activationId}`, children: [_jsx("span", { className: "text-ink-2 text-[13px] flex-1", children: t("pages.activation.confirmDisable") }), _jsx("button", { onClick: () => {
33
33
  onDisable(record);
34
34
  setShowConfirm(false);
35
- }, disabled: disabling, className: "inline-flex items-center border border-danger/40 text-danger bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-danger/5 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "data-testid": `confirm-disable-${record.id}`, children: disabling ? t("pages.activation.disabling") : t("common.confirm") }), _jsx("button", { onClick: () => setShowConfirm(false), className: "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 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("common.cancel") })] })) }))] }));
35
+ }, disabled: disabling, className: "inline-flex items-center border border-danger/40 text-danger bg-surface rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:bg-danger/5 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "data-testid": `confirm-disable-${record.activationId}`, children: disabling ? t("pages.activation.disabling") : t("common.confirm") }), _jsx("button", { onClick: () => setShowConfirm(false), className: "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 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("common.cancel") })] })) }))] }));
36
36
  }
37
37
  export function ActivationPage() {
38
38
  const { t } = useTranslation();
@@ -59,8 +59,8 @@ export function ActivationPage() {
59
59
  return;
60
60
  }
61
61
  setActivationsData(validated);
62
- if (validated.note) {
63
- setDegradedNote(validated.note);
62
+ if (validated.reason) {
63
+ setDegradedNote(validated.reason);
64
64
  }
65
65
  // Pre-fetch lifecycle metrics for active principles with rules
66
66
  // (only for principles that are active, to populate the expandable section)
@@ -92,8 +92,8 @@ export function ActivationPage() {
92
92
  loadData();
93
93
  }, [loadData]);
94
94
  const handleDisable = useCallback(async (record) => {
95
- setDisablingIds((prev) => new Set(prev).add(record.id));
96
- const result = await disableActivation(record.id);
95
+ setDisablingIds((prev) => new Set(prev).add(record.activationId));
96
+ const result = await disableActivation(record.activationId);
97
97
  if (result.success) {
98
98
  toast.success(t("pages.activation.disableSuccess"), {
99
99
  description: t("pages.activation.disableSuccessDescription", { id: record.principleId }),
@@ -105,7 +105,7 @@ export function ActivationPage() {
105
105
  return prev;
106
106
  return {
107
107
  ...prev,
108
- activations: prev.activations.map((a) => a.id === record.id ? { ...a, status: "inactive" } : a),
108
+ activations: prev.activations.map((a) => a.activationId === record.activationId ? { ...a, status: "inactive" } : a),
109
109
  };
110
110
  });
111
111
  }
@@ -121,7 +121,7 @@ export function ActivationPage() {
121
121
  }
122
122
  setDisablingIds((prev) => {
123
123
  const next = new Set(prev);
124
- next.delete(record.id);
124
+ next.delete(record.activationId);
125
125
  return next;
126
126
  });
127
127
  }, [t]);
@@ -138,7 +138,7 @@ export function ActivationPage() {
138
138
  const activeActivations = activations.filter((a) => a.status === "active");
139
139
  const inactiveActivations = activations.filter((a) => a.status === "inactive");
140
140
  const neverActivatedCount = activations.filter((a) => a.activatedAt === null).length;
141
- return (_jsx(PageShell, { children: _jsxs("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: [_jsx("div", { className: "font-mono text-[12px] tracking-[0.14em] text-ink-3 uppercase mb-3", children: t("pages.activation.eyebrow") }), _jsx(ShinyText, { as: "h1", className: "text-[29px] font-semibold tracking-tight text-ink mb-2", duration: 4.5, brightness: 0.5, disabled: activeActivations.length === 0, children: t("pages.activation.title") }), _jsx("p", { className: "text-ink-3 text-[14px] max-w-[760px] leading-relaxed mb-7", children: t("pages.activation.subtitle") }), _jsxs("div", { className: "text-sm leading-relaxed text-ink-2 mb-7 px-[18px] py-[14px] bg-panel border border-line rounded-[6px]", role: "status", "aria-live": "polite", children: [_jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: activeActivations.length }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.summaryActive") }), " ", "/", " ", _jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: inactiveActivations.length }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.summaryInactive") }), neverActivatedCount > 0 && (_jsxs(_Fragment, { children: [" ", "/", " ", _jsx("span", { className: "font-mono font-semibold text-amber tabular-nums", children: neverActivatedCount }), " ", _jsx("span", { className: "text-amber", children: t("pages.activation.summaryNeverActivated") })] }))] }), _jsx(CapabilityBoundaryDeclaration, {}), degradedNote && (_jsx("div", { className: "mt-4 text-ink-4 text-[13px] bg-surface/60 border-l-2 border-amber px-3 py-2", children: degradedNote })), _jsxs("section", { className: "mt-8", "aria-labelledby": "section-active", children: [_jsx(SectionTitle, { id: "section-active", children: t("pages.activation.sectionActive") }), activeActivations.length > 0 ? (_jsx("div", { className: "space-y-[14px]", children: activeActivations.map((record) => (_jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], onDisable: handleDisable, disabling: disablingIds.has(record.id) }, record.id))) })) : (_jsx("div", { className: "text-ink-3 text-[13px] leading-relaxed py-3", children: t("pages.activation.emptyActive") }))] }), inactiveActivations.length > 0 && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-inactive", children: [_jsx(SectionTitle, { id: "section-inactive", children: t("pages.activation.sectionInactive") }), _jsx("div", { className: "space-y-[14px]", children: inactiveActivations.map((record) => (_jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], onDisable: handleDisable, disabling: disablingIds.has(record.id) }, record.id))) })] })), neverActivatedCount > 0 && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-never-activated", children: [_jsx(SectionTitle, { id: "section-never-activated", children: t("pages.activation.sectionNeverActivated") }), _jsx("div", { className: "space-y-[10px]", children: activations
141
+ return (_jsx(PageShell, { children: _jsxs("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: [_jsx("div", { className: "font-mono text-[12px] tracking-[0.14em] text-ink-3 uppercase mb-3", children: t("pages.activation.eyebrow") }), _jsx(ShinyText, { as: "h1", className: "text-[29px] font-semibold tracking-tight text-ink mb-2", duration: 4.5, brightness: 0.5, disabled: activeActivations.length === 0, children: t("pages.activation.title") }), _jsx("p", { className: "text-ink-3 text-[14px] max-w-[760px] leading-relaxed mb-7", children: t("pages.activation.subtitle") }), _jsxs("div", { className: "text-sm leading-relaxed text-ink-2 mb-7 px-[18px] py-[14px] bg-panel border border-line rounded-[6px]", role: "status", "aria-live": "polite", children: [_jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: activeActivations.length }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.summaryActive") }), " ", "/", " ", _jsx("span", { className: "font-mono font-semibold text-ink tabular-nums", children: inactiveActivations.length }), " ", _jsx("span", { className: "text-ink-3", children: t("pages.activation.summaryInactive") }), neverActivatedCount > 0 && (_jsxs(_Fragment, { children: [" ", "/", " ", _jsx("span", { className: "font-mono font-semibold text-amber tabular-nums", children: neverActivatedCount }), " ", _jsx("span", { className: "text-amber", children: t("pages.activation.summaryNeverActivated") })] }))] }), _jsx(CapabilityBoundaryDeclaration, {}), degradedNote && (_jsx("div", { className: "mt-4 text-ink-4 text-[13px] bg-surface/60 border-l-2 border-amber px-3 py-2", children: degradedNote })), _jsxs("section", { className: "mt-8", "aria-labelledby": "section-active", children: [_jsx(SectionTitle, { id: "section-active", children: t("pages.activation.sectionActive") }), activeActivations.length > 0 ? (_jsx("div", { className: "space-y-[14px]", children: activeActivations.map((record) => (_jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], onDisable: handleDisable, disabling: disablingIds.has(record.activationId) }, record.activationId))) })) : (_jsx("div", { className: "text-ink-3 text-[13px] leading-relaxed py-3", children: t("pages.activation.emptyActive") }))] }), inactiveActivations.length > 0 && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-inactive", children: [_jsx(SectionTitle, { id: "section-inactive", children: t("pages.activation.sectionInactive") }), _jsx("div", { className: "space-y-[14px]", children: inactiveActivations.map((record) => (_jsx(ActivationFactCard, { record: record, lifecycleData: lifecycleCache[record.principleId], onDisable: handleDisable, disabling: disablingIds.has(record.activationId) }, record.activationId))) })] })), neverActivatedCount > 0 && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-never-activated", children: [_jsx(SectionTitle, { id: "section-never-activated", children: t("pages.activation.sectionNeverActivated") }), _jsx("div", { className: "space-y-[10px]", children: activations
142
142
  .filter((a) => a.activatedAt === null)
143
- .map((record) => (_jsxs("article", { className: "relative pl-[22px] py-[14px] pr-[18px] bg-panel border border-amber/20 border-l-[3px] border-l-amber rounded-[6px]", children: [_jsxs("div", { className: "text-ink-2 text-sm leading-relaxed", children: [_jsx("span", { className: "font-medium text-ink", children: t("pages.activation.neverActivatedCard") }), " ", "\u2014 ", record.action, " \u00B7 ", getChannelLabel(record.channel, t), _jsx("span", { className: "ml-2 font-mono text-[11px] text-ink-4", children: record.principleId })] }), _jsxs(Link, { to: "/debt", className: "inline-flex items-center mt-2 text-gov text-[13px] hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: [t("pages.activation.viewDebt"), " \u2192"] })] }, record.id))) })] })), _jsx("footer", { className: "mt-12 pt-6 border-t border-line text-ink-3 text-[13px]", children: t("pages.activation.footer") })] }) }));
143
+ .map((record) => (_jsxs("article", { className: "relative pl-[22px] py-[14px] pr-[18px] bg-panel border border-amber/20 border-l-[3px] border-l-amber rounded-[6px]", children: [_jsxs("div", { className: "text-ink-2 text-sm leading-relaxed", children: [_jsx("span", { className: "font-medium text-ink", children: t("pages.activation.neverActivatedCard") }), " ", "\u2014 ", record.action, " \u00B7 ", getChannelLabel(record.channel, t), _jsx("span", { className: "ml-2 font-mono text-[11px] text-ink-4", children: record.principleId })] }), _jsxs(Link, { to: "/debt", className: "inline-flex items-center mt-2 text-gov text-[13px] hover:underline focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: [t("pages.activation.viewDebt"), " \u2192"] })] }, record.activationId))) })] })), _jsx("footer", { className: "mt-12 pt-6 border-t border-line text-ink-3 text-[13px]", children: t("pages.activation.footer") })] }) }));
144
144
  }
@@ -19,7 +19,7 @@ const VALID_ACTIVATION_STATUSES = new Set(["active", "inactive", "deactivated",
19
19
  export function validateActivationRecord(raw) {
20
20
  if (!isRecord(raw))
21
21
  return null;
22
- if (!Object.hasOwn(raw, "id") ||
22
+ if (!Object.hasOwn(raw, "activationId") ||
23
23
  !Object.hasOwn(raw, "artifactId") ||
24
24
  !Object.hasOwn(raw, "principleId") ||
25
25
  !Object.hasOwn(raw, "channel") ||
@@ -29,9 +29,9 @@ export function validateActivationRecord(raw) {
29
29
  !Object.hasOwn(raw, "status")) {
30
30
  return null;
31
31
  }
32
- const { id, artifactId, principleId, channel, action, targetRef, activatedAt, status } = raw;
33
- if (typeof id !== "string" ||
34
- id.length === 0 ||
32
+ const { activationId, artifactId, principleId, channel, action, targetRef, activatedAt, status } = raw;
33
+ if (typeof activationId !== "string" ||
34
+ activationId.length === 0 ||
35
35
  typeof artifactId !== "string" ||
36
36
  typeof principleId !== "string" ||
37
37
  typeof channel !== "string" ||
@@ -45,7 +45,7 @@ export function validateActivationRecord(raw) {
45
45
  // Narrow status from string to union type via const assertion
46
46
  const narrowStatus = status;
47
47
  return {
48
- id: id,
48
+ activationId: activationId,
49
49
  artifactId: artifactId,
50
50
  principleId: principleId,
51
51
  channel: channel,
@@ -58,11 +58,11 @@ export function validateActivationRecord(raw) {
58
58
  export function validateActivationsData(raw) {
59
59
  if (!isRecord(raw))
60
60
  return null;
61
- if (!Object.hasOwn(raw, "activations") || !Object.hasOwn(raw, "generatedAt")) {
61
+ if (!Object.hasOwn(raw, "activations") || !Object.hasOwn(raw, "status")) {
62
62
  return null;
63
63
  }
64
- const { activations, generatedAt } = raw;
65
- if (!Array.isArray(activations) || typeof generatedAt !== "string") {
64
+ const { activations, status } = raw;
65
+ if (!Array.isArray(activations) || typeof status !== "string") {
66
66
  return null;
67
67
  }
68
68
  // Fail loud: any invalid record rejects the entire payload (ERR-009)
@@ -73,11 +73,12 @@ export function validateActivationsData(raw) {
73
73
  return null;
74
74
  validatedRecords.push(validated);
75
75
  }
76
- return {
77
- activations: validatedRecords,
78
- generatedAt,
79
- note: Object.hasOwn(raw, "note") && typeof raw.note === "string" ? raw.note : undefined,
80
- };
76
+ const result = { activations: validatedRecords, status };
77
+ if (Object.hasOwn(raw, "reason") && typeof raw.reason === "string")
78
+ result.reason = raw.reason;
79
+ if (Object.hasOwn(raw, "nextAction") && typeof raw.nextAction === "string")
80
+ result.nextAction = raw.nextAction;
81
+ return result;
81
82
  }
82
83
  // ── Lifecycle validators ─────────────────────────────────────────────────────
83
84
  export function validateLifecycleRuleMetric(raw) {