create-principles-disciple 1.125.0 → 1.126.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 (78) hide show
  1. package/console/dist/server/config/pd-config-store.js +23 -11
  2. package/console/dist/server/index.js +8 -1
  3. package/console/dist/server/models/PrinciplesConsoleModel.d.ts +10 -0
  4. package/console/dist/server/models/PrinciplesConsoleModel.js +76 -29
  5. package/console/dist/server/routes/principles.d.ts +9 -0
  6. package/console/dist/server/routes/principles.js +46 -2
  7. package/console/dist/ui/App.js +2 -1
  8. package/console/dist/ui/api.d.ts +4 -3
  9. package/console/dist/ui/api.js +7 -2
  10. package/console/dist/ui/i18n/en.json +12 -0
  11. package/console/dist/ui/i18n/zh-CN.json +12 -0
  12. package/console/dist/ui/pages/principles/CorePrinciplesPage.d.ts +10 -0
  13. package/console/dist/ui/pages/principles/CorePrinciplesPage.js +59 -0
  14. package/console/dist/ui/pages/principles/PrinciplesPage.js +2 -1
  15. package/console/dist/ui/pages/principles/PrinciplesViewNav.d.ts +8 -0
  16. package/console/dist/ui/pages/principles/PrinciplesViewNav.js +15 -0
  17. package/console/dist/ui/utils/validators.d.ts +13 -0
  18. package/console/dist/ui/utils/validators.js +34 -0
  19. package/console/dist/web/assets/app.css +6 -0
  20. package/console/dist/web/assets/app.js +2148 -1962
  21. package/core/dist/runtime-v2/__tests__/adversarial-loop.test.js +14 -2
  22. package/core/dist/runtime-v2/__tests__/adversarial-loop.test.js.map +1 -1
  23. package/core/dist/runtime-v2/__tests__/artificer-runner-vslice.test.js +55 -1
  24. package/core/dist/runtime-v2/__tests__/artificer-runner-vslice.test.js.map +1 -1
  25. package/core/dist/runtime-v2/__tests__/evaluator-runner-vslice-v2.test.js +25 -7
  26. package/core/dist/runtime-v2/__tests__/evaluator-runner-vslice-v2.test.js.map +1 -1
  27. package/core/dist/runtime-v2/config/__tests__/pd-config-provenance.test.d.ts +24 -0
  28. package/core/dist/runtime-v2/config/__tests__/pd-config-provenance.test.d.ts.map +1 -0
  29. package/core/dist/runtime-v2/config/__tests__/pd-config-provenance.test.js +208 -0
  30. package/core/dist/runtime-v2/config/__tests__/pd-config-provenance.test.js.map +1 -0
  31. package/core/dist/runtime-v2/config/index.d.ts +1 -1
  32. package/core/dist/runtime-v2/config/index.d.ts.map +1 -1
  33. package/core/dist/runtime-v2/config/index.js.map +1 -1
  34. package/core/dist/runtime-v2/config/pd-config-effective.d.ts.map +1 -1
  35. package/core/dist/runtime-v2/config/pd-config-effective.js +10 -2
  36. package/core/dist/runtime-v2/config/pd-config-effective.js.map +1 -1
  37. package/core/dist/runtime-v2/config/pd-config-feature-flags.d.ts +3 -1
  38. package/core/dist/runtime-v2/config/pd-config-feature-flags.d.ts.map +1 -1
  39. package/core/dist/runtime-v2/config/pd-config-feature-flags.js +2 -0
  40. package/core/dist/runtime-v2/config/pd-config-feature-flags.js.map +1 -1
  41. package/core/dist/runtime-v2/config/pd-config-types.d.ts +4 -0
  42. package/core/dist/runtime-v2/config/pd-config-types.d.ts.map +1 -1
  43. package/core/dist/runtime-v2/config/pd-config-types.js +23 -0
  44. package/core/dist/runtime-v2/config/pd-config-types.js.map +1 -1
  45. package/core/dist/runtime-v2/config/pd-config-validate.d.ts.map +1 -1
  46. package/core/dist/runtime-v2/config/pd-config-validate.js +12 -1
  47. package/core/dist/runtime-v2/config/pd-config-validate.js.map +1 -1
  48. package/core/dist/runtime-v2/feature-flags/__tests__/installer-config-parity.test.js +4 -3
  49. package/core/dist/runtime-v2/feature-flags/__tests__/installer-config-parity.test.js.map +1 -1
  50. package/core/dist/runtime-v2/internalization/__tests__/evaluator-gate-authority.test.js +223 -1
  51. package/core/dist/runtime-v2/internalization/__tests__/evaluator-gate-authority.test.js.map +1 -1
  52. package/core/dist/runtime-v2/internalization/__tests__/owner-decision.test.js +41 -0
  53. package/core/dist/runtime-v2/internalization/__tests__/owner-decision.test.js.map +1 -1
  54. package/core/dist/runtime-v2/internalization/artificer-runner.d.ts.map +1 -1
  55. package/core/dist/runtime-v2/internalization/artificer-runner.js +10 -0
  56. package/core/dist/runtime-v2/internalization/artificer-runner.js.map +1 -1
  57. package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts +10 -0
  58. package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
  59. package/core/dist/runtime-v2/internalization/evaluator-runner.js +143 -23
  60. package/core/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
  61. package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts +12 -0
  62. package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts.map +1 -1
  63. package/core/dist/runtime-v2/internalization/pitask-metadata.js +15 -0
  64. package/core/dist/runtime-v2/internalization/pitask-metadata.js.map +1 -1
  65. package/core/dist/telemetry-event.d.ts +2 -2
  66. package/core/dist/telemetry-event.d.ts.map +1 -1
  67. package/core/dist/telemetry-event.js +6 -0
  68. package/core/dist/telemetry-event.js.map +1 -1
  69. package/dist/mvp-config.d.ts.map +1 -1
  70. package/dist/mvp-config.js +30 -20
  71. package/dist/mvp-config.js.map +1 -1
  72. package/package.json +1 -1
  73. package/pd-cli/dist/commands/runtime-init.d.ts.map +1 -1
  74. package/pd-cli/dist/commands/runtime-init.js +12 -1
  75. package/pd-cli/dist/commands/runtime-init.js.map +1 -1
  76. package/plugin/dist/bundle.js +390 -390
  77. package/plugin/dist/governance-audit.js +2 -2
  78. package/plugin/dist/rulehost-evidence.js +1 -1
@@ -312,11 +312,15 @@ export function updateAgentBinding(workspaceDir, agentName, payload) {
312
312
  };
313
313
  }
314
314
  }
315
- // Merge: start from raw config, overlay known sections, update internalAgents.agents
315
+ // Merge: start from raw config, overlay known sections, update internalAgents.agents.
316
+ // PRI-637: preserve the file's own `features:` section instead of re-writing
317
+ // the merged effective map. Defaults belong in the registry, not in config —
318
+ // snapshotting `effective.config.features` here would materialize every
319
+ // missing default flag into an immortal override on any agent-binding change.
316
320
  const updatedConfig = {
317
321
  ...rawConfig,
318
322
  version: effective.config.version,
319
- features: { ...effective.config.features },
323
+ features: isRecord(rawConfig.features) ? rawConfig.features : { ...effective.config.features },
320
324
  runtimeProfiles: { ...effective.config.runtimeProfiles },
321
325
  internalAgents: {
322
326
  defaultRuntime: effective.config.internalAgents.defaultRuntime,
@@ -434,11 +438,13 @@ export function updateDefaultRuntime(workspaceDir, payload) {
434
438
  else {
435
439
  // No agents in file — write nothing (all agents inherit default)
436
440
  }
437
- // Merge: update only defaultRuntime, preserve agent overrides
441
+ // Merge: update only defaultRuntime, preserve agent overrides.
442
+ // PRI-637: preserve the file's own `features:` section (same rationale as
443
+ // updateAgentBinding — never re-snapshot merged defaults into config).
438
444
  const updatedConfig = {
439
445
  ...rawConfig,
440
446
  version: effective.config.version,
441
- features: { ...effective.config.features },
447
+ features: isRecord(rawConfig.features) ? rawConfig.features : { ...effective.config.features },
442
448
  runtimeProfiles: { ...effective.config.runtimeProfiles },
443
449
  internalAgents: {
444
450
  defaultRuntime: defaultRuntimeRaw,
@@ -814,13 +820,14 @@ export function updateFeatureFlag(workspaceDir, featureName, enabled) {
814
820
  // Use Object.hasOwn for untrusted key check (ERR-013).
815
821
  let featuresSection;
816
822
  if (!Object.hasOwn(rawConfig, 'features')) {
817
- // Section absent — seed with defaults from the registered flag set so the
818
- // subsequent validatePdConfig passes (it requires prompt/code_tool_hook /
819
- // defer_archive as registered flags). Computed once at module load.
823
+ // Section absent — create an EMPTY features map (PRI-637). Defaults belong
824
+ // in the registry, not in config: seeding the whole registered flag set here
825
+ // would materialize an immortal default snapshot on the first toggle of a
826
+ // fresh install. `features: {}` is fully valid — validatePdConfig only
827
+ // requires the key to be an object, and the effective config merges missing
828
+ // flags from DEFAULT_FEATURE_FLAGS at read time. Step 6 below then writes
829
+ // exactly one flag: the one the Owner toggled.
820
830
  featuresSection = {};
821
- for (const [flagId, flag] of Object.entries(_DEFAULT_FLAGS_RESULT.flags)) {
822
- featuresSection[flagId] = { category: flag.category, enabled: flag.enabled };
823
- }
824
831
  rawConfig.features = featuresSection;
825
832
  }
826
833
  else if (isRecord(rawConfig.features)) {
@@ -865,7 +872,12 @@ export function updateFeatureFlag(workspaceDir, featureName, enabled) {
865
872
  const category = (isRecord(existingEntry) && Object.hasOwn(existingEntry, 'category') && typeof existingEntry.category === 'string')
866
873
  ? existingEntry.category
867
874
  : (DEFAULT_FLAG_CATEGORY.get(featureName) ?? 'quiet');
868
- existingFeatures[featureName] = { category, enabled };
875
+ // PRI-637: the Console toggle is the canonical Owner action — an authenticated
876
+ // server writes this override under an explicit owner intent, so it records
877
+ // `source: 'owner'` (OWNER_PIN). This also upgrades a previously source-less
878
+ // LEGACY_UNKNOWN or system override: an explicit Owner action converts it to
879
+ // OWNER_PIN, which graduation must forever respect.
880
+ existingFeatures[featureName] = { category, enabled, source: 'owner' };
869
881
  rawConfig.features = existingFeatures;
870
882
  // 7. Validate the updated config before writing
871
883
  const validation = validatePdConfig(rawConfig);
@@ -12,7 +12,7 @@ import { handleFeedbackReportsRoute, handleFeedbackChannelsRoute, disposeFeedbac
12
12
  import { handleFailedTasksRoute, disposeFailedTasksModels } from './routes/failed-tasks.js';
13
13
  import { handleApprovalsRoute, disposeApprovalsModels } from './routes/approvals.js';
14
14
  import { handleHealthRoute, disposeHealthModels } from './routes/health.js';
15
- import { handlePrinciplesRoute, disposePrinciplesModels } from './routes/principles.js';
15
+ import { handlePrinciplesRoute, handleCorePrinciplesRoute, disposePrinciplesModels } from './routes/principles.js';
16
16
  import { handleLifecycleRoute, disposeLifecycleModels } from './routes/lifecycle.js';
17
17
  import { handleActivationsRoute, disposeActivationsModels } from './routes/activations.js';
18
18
  import { handleReceiptsRoute, disposeReceiptsModels } from './routes/receipts.js';
@@ -338,6 +338,13 @@ function handleRequest(services) {
338
338
  asyncHandler(() => handleApprovalsRoute(req, res, services.workspaceDir, subPath))(req, res);
339
339
  return;
340
340
  }
341
+ // GET /api/principles/core — read-only PD Core Principles reference
342
+ // (MUST be before the /api/principles catch-all so "core" is not parsed
343
+ // as a principle id; the /api/v1/principles mount does not expose it.)
344
+ if (urlPath === '/api/principles/core') {
345
+ asyncHandler(() => handleCorePrinciplesRoute(req, res))(req, res);
346
+ return;
347
+ }
341
348
  // GET /api/principles, /api/principles/:id
342
349
  if (urlPath === '/api/principles' || urlPath.startsWith('/api/principles/')) {
343
350
  const subPath = urlPath.slice('/api/principles'.length);
@@ -1,5 +1,15 @@
1
1
  import type { PrincipleStatus } from '@principles/core/runtime-v2';
2
2
  export type { PrincipleStatus };
3
+ /** Core principle refused for a workspace governance mutation (archive/unarchive). */
4
+ export declare class ImmutableCorePrincipleError extends Error {
5
+ readonly principleId: string;
6
+ constructor(principleId: string);
7
+ }
8
+ /** Core principle refused from the ordinary Owner Principle detail flow. */
9
+ export declare class CorePrincipleNotGovernedError extends Error {
10
+ readonly principleId: string;
11
+ constructor(principleId: string);
12
+ }
3
13
  export type PrinciplePriority = 'P0' | 'P1' | 'P2';
4
14
  export type PrincipleScope = 'general' | 'domain';
5
15
  export type PrincipleEvaluability = 'manual_only' | 'deterministic' | 'weak_heuristic';
@@ -2,6 +2,29 @@ import * as path from 'path';
2
2
  import * as fs from 'fs';
3
3
  import { classifyPrinciples, filterOwnerActionable } from './PrincipleClassifier.js';
4
4
  import { updatePrinciple } from '@principles/core/principle-tree-ledger';
5
+ import { isCorePrincipleId } from '@principles/core/runtime-v2';
6
+ // ── PRI-641: Core principle boundary errors ─────────────────────────────────
7
+ // Core principles (registry T-01..T-10) are PD's built-in semantics, not
8
+ // workspace governance targets. Refusals must be distinguishable from storage
9
+ // failures (`false`), so they surface as typed errors at the model boundary.
10
+ /** Core principle refused for a workspace governance mutation (archive/unarchive). */
11
+ export class ImmutableCorePrincipleError extends Error {
12
+ principleId;
13
+ constructor(principleId) {
14
+ super(`Core principle "${principleId}" is built into Principles Disciple and cannot be modified through workspace governance.`);
15
+ this.name = 'ImmutableCorePrincipleError';
16
+ this.principleId = principleId;
17
+ }
18
+ }
19
+ /** Core principle refused from the ordinary Owner Principle detail flow. */
20
+ export class CorePrincipleNotGovernedError extends Error {
21
+ principleId;
22
+ constructor(principleId) {
23
+ super(`Core principle "${principleId}" is not owner-managed.`);
24
+ this.name = 'CorePrincipleNotGovernedError';
25
+ this.principleId = principleId;
26
+ }
27
+ }
5
28
  const VALID_STATUSES = ['candidate', 'active', 'archived', 'deprecated', 'probation'];
6
29
  const VALID_PRIORITIES = ['P0', 'P1', 'P2'];
7
30
  const VALID_SCOPES = ['general', 'domain'];
@@ -128,34 +151,9 @@ export class PrinciplesConsoleModel {
128
151
  async listPrinciples(filter, decidedPrincipleIds, pendingApprovalPrincipleIds) {
129
152
  const ledger = this.loadLedger();
130
153
  const principles = Object.values(ledger.tree.principles);
131
- const summary = {
132
- candidate: 0,
133
- probation: 0,
134
- active: 0,
135
- deprecated: 0,
136
- archived: 0,
137
- total: principles.length,
138
- };
139
154
  const items = [];
140
155
  for (const p of principles) {
141
156
  const status = safeCastEnum(p.status, VALID_STATUSES, 'candidate');
142
- switch (status) {
143
- case 'candidate':
144
- summary.candidate++;
145
- break;
146
- case 'probation':
147
- summary.probation++;
148
- break;
149
- case 'active':
150
- summary.active++;
151
- break;
152
- case 'deprecated':
153
- summary.deprecated++;
154
- break;
155
- case 'archived':
156
- summary.archived++;
157
- break;
158
- }
159
157
  const principleText = p.text ?? '';
160
158
  const principleTrigger = p.triggerPattern ?? '';
161
159
  items.push({
@@ -180,20 +178,61 @@ export class PrinciplesConsoleModel {
180
178
  });
181
179
  }
182
180
  items.sort((a, b) => b.valueScore - a.valueScore);
183
- // PRI-330: classify and optionally filter
181
+ // PRI-330 + PRI-641: classify first, then remove builtin from the corpus.
182
+ // The workspace projection is "workspace-governed principles only" —
183
+ // builtin axioms are PD's immutable semantics and never governance
184
+ // targets, so they must not reach lists, summary, or Debt consumers.
184
185
  const classified = classifyPrinciples(items, decidedPrincipleIds, pendingApprovalPrincipleIds);
186
+ const workspaceClassified = classified.filter((c) => c.category !== 'builtin');
187
+ const workspaceItems = workspaceClassified.map((c) => c.principle);
188
+ // PRI-641: summary and categories are computed over the same workspace
189
+ // corpus the caller sees, so `principles[]` and `summary` can never
190
+ // disagree (no "list 3, total 13" projection).
191
+ const summary = {
192
+ candidate: 0,
193
+ probation: 0,
194
+ active: 0,
195
+ deprecated: 0,
196
+ archived: 0,
197
+ total: workspaceItems.length,
198
+ };
199
+ for (const p of workspaceItems) {
200
+ switch (p.status) {
201
+ case 'candidate':
202
+ summary.candidate++;
203
+ break;
204
+ case 'probation':
205
+ summary.probation++;
206
+ break;
207
+ case 'active':
208
+ summary.active++;
209
+ break;
210
+ case 'deprecated':
211
+ summary.deprecated++;
212
+ break;
213
+ case 'archived':
214
+ summary.archived++;
215
+ break;
216
+ }
217
+ }
185
218
  const categories = {};
186
- for (const c of classified) {
219
+ for (const c of workspaceClassified) {
187
220
  categories[c.category] = (categories[c.category] ?? 0) + 1;
188
221
  }
189
- let outputItems = items;
222
+ let outputItems = workspaceItems;
190
223
  if (filter === 'actionable') {
191
- const actionable = filterOwnerActionable(classified);
224
+ const actionable = filterOwnerActionable(workspaceClassified);
192
225
  outputItems = actionable.map((c) => c.principle);
193
226
  }
194
227
  return { principles: outputItems, summary, categories };
195
228
  }
196
229
  async getPrincipleDetail(principleId) {
230
+ // PRI-641: Core principles are not workspace-governed objects — they have
231
+ // no ordinary Owner detail (approvals/lifecycle/trajectory/receipts) and
232
+ // are viewed read-only via the Core Principles surface instead.
233
+ if (isCorePrincipleId(principleId)) {
234
+ throw new CorePrincipleNotGovernedError(principleId);
235
+ }
197
236
  const ledger = this.loadLedger();
198
237
  const p = ledger.tree.principles[principleId];
199
238
  if (!p) {
@@ -247,6 +286,10 @@ export class PrinciplesConsoleModel {
247
286
  return { principle };
248
287
  }
249
288
  async archivePrinciple(principleId) {
289
+ // PRI-641: refuse before any write — builtin axioms are immutable
290
+ if (isCorePrincipleId(principleId)) {
291
+ throw new ImmutableCorePrincipleError(principleId);
292
+ }
250
293
  try {
251
294
  const stateDir = path.join(this.workspaceDir, '.state');
252
295
  updatePrinciple(stateDir, principleId, {
@@ -264,6 +307,10 @@ export class PrinciplesConsoleModel {
264
307
  }
265
308
  }
266
309
  async unarchivePrinciple(principleId) {
310
+ // PRI-641: refuse before any write — builtin axioms are immutable
311
+ if (isCorePrincipleId(principleId)) {
312
+ throw new ImmutableCorePrincipleError(principleId);
313
+ }
267
314
  try {
268
315
  const stateDir = path.join(this.workspaceDir, '.state');
269
316
  updatePrinciple(stateDir, principleId, {
@@ -1,4 +1,13 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ /**
3
+ * GET /api/principles/core — read-only PD Core Principles reference (PRI-641).
4
+ *
5
+ * Served directly from the canonical `CORE_PRINCIPLES` registry (no ledger /
6
+ * DB read). Dispatched in server/index.ts BEFORE the `/api/principles`
7
+ * catch-all so `core` is never parsed as `/:id`; the `/api/v1/principles`
8
+ * mount intentionally does NOT expose this endpoint.
9
+ */
10
+ export declare function handleCorePrinciplesRoute(req: IncomingMessage, res: ServerResponse): Promise<void>;
2
11
  interface PrinciplesRouteParams {
3
12
  req: IncomingMessage;
4
13
  res: ServerResponse;
@@ -1,9 +1,9 @@
1
1
  import * as path from 'path';
2
2
  import * as fs from 'fs';
3
- import { PrinciplesConsoleModel } from '../models/PrinciplesConsoleModel.js';
3
+ import { PrinciplesConsoleModel, ImmutableCorePrincipleError, CorePrincipleNotGovernedError, } from '../models/PrinciplesConsoleModel.js';
4
4
  import { PrincipleTrajectoryModel } from '../models/PrincipleTrajectoryModel.js';
5
5
  import { GovernanceProjectionCollector, GovernanceProjectionCollectionError } from '../models/GovernanceProjectionCollector.js';
6
- import { OwnerGovernanceViewSchema, deriveOwnerGovernanceView } from '@principles/core/runtime-v2';
6
+ import { CORE_PRINCIPLES, OwnerGovernanceViewSchema, deriveOwnerGovernanceView } from '@principles/core/runtime-v2';
7
7
  import { Value } from '@sinclair/typebox/value';
8
8
  import { sendSuccess, sendError, sendNotFound } from '../utils/response.js';
9
9
  const models = new Map();
@@ -16,6 +16,30 @@ function getModel(workspaceDir) {
16
16
  }
17
17
  return model;
18
18
  }
19
+ /**
20
+ * GET /api/principles/core — read-only PD Core Principles reference (PRI-641).
21
+ *
22
+ * Served directly from the canonical `CORE_PRINCIPLES` registry (no ledger /
23
+ * DB read). Dispatched in server/index.ts BEFORE the `/api/principles`
24
+ * catch-all so `core` is never parsed as `/:id`; the `/api/v1/principles`
25
+ * mount intentionally does NOT expose this endpoint.
26
+ */
27
+ export async function handleCorePrinciplesRoute(req, res) {
28
+ if (req.method !== 'GET') {
29
+ sendNotFound(res, `Route ${req.method} /api/principles/core not found`);
30
+ return;
31
+ }
32
+ sendSuccess(res, {
33
+ principles: CORE_PRINCIPLES.map((p) => ({
34
+ id: p.id,
35
+ layer: p.layer,
36
+ name: p.name,
37
+ nameZh: p.nameZh,
38
+ statement: p.statement,
39
+ statementZh: p.statementZh,
40
+ })),
41
+ });
42
+ }
19
43
  /**
20
44
  * Safely read an own string property from an unknown object.
21
45
  * Returns the string value if the key exists and the value is a string,
@@ -153,6 +177,12 @@ export async function handlePrinciplesRoute({ req, res, workspaceDir, subPath, f
153
177
  }
154
178
  }
155
179
  catch (err) {
180
+ if (err instanceof ImmutableCorePrincipleError) {
181
+ sendError(res, 403, 'immutable_core_principle', err.message, {
182
+ nextAction: 'View this principle under PD Core Principles.',
183
+ });
184
+ return;
185
+ }
156
186
  sendError(res, 500, 'archive_failed', err instanceof Error ? err.message : String(err));
157
187
  }
158
188
  return;
@@ -183,6 +213,12 @@ export async function handlePrinciplesRoute({ req, res, workspaceDir, subPath, f
183
213
  }
184
214
  }
185
215
  catch (err) {
216
+ if (err instanceof ImmutableCorePrincipleError) {
217
+ sendError(res, 403, 'immutable_core_principle', err.message, {
218
+ nextAction: 'View this principle under PD Core Principles.',
219
+ });
220
+ return;
221
+ }
186
222
  sendError(res, 500, 'unarchive_failed', err instanceof Error ? err.message : String(err));
187
223
  }
188
224
  return;
@@ -264,6 +300,14 @@ export async function handlePrinciplesRoute({ req, res, workspaceDir, subPath, f
264
300
  sendSuccess(res, result);
265
301
  }
266
302
  catch (err) {
303
+ if (err instanceof CorePrincipleNotGovernedError) {
304
+ // PRI-641: Core principles never enter the ordinary Owner detail flow
305
+ // (approvals/lifecycle/trajectory/receipts are workspace-governance data).
306
+ sendError(res, 404, 'core_principle_not_owner_managed', err.message, {
307
+ nextAction: 'View this principle under PD Core Principles.',
308
+ });
309
+ return;
310
+ }
267
311
  sendError(res, 500, 'principle_detail_error', err instanceof Error ? err.message : String(err));
268
312
  }
269
313
  return;
@@ -15,6 +15,7 @@ import { Toaster } from "./components/ui/sonner.js";
15
15
  import { FocusPage } from "./pages/focus/FocusPage.js";
16
16
  import { PainPage } from "./pages/pain/PainPage.js";
17
17
  import { PrinciplesPage } from "./pages/principles/PrinciplesPage.js";
18
+ import { CorePrinciplesPage } from "./pages/principles/CorePrinciplesPage.js";
18
19
  import { PrincipleDetailPage } from "./pages/principles/PrincipleDetailPage.js";
19
20
  import { ActivationPage } from "./pages/activation/ActivationPage.js";
20
21
  import { DebtPage } from "./pages/debt/DebtPage.js";
@@ -130,7 +131,7 @@ function AuthRoutes() {
130
131
  }, []);
131
132
  return (_jsxs(Routes, { children: [_jsx(Route, { path: "/splash", element: _jsx(SplashScreen, { onComplete: () => {
132
133
  setShowSplash(false);
133
- } }) }), _jsx(Route, { path: "/login", element: _jsx(LoginForm, { onAuthSuccess: handleAuthSuccess }) }), _jsx(Route, { path: "/*", element: authed === null ? (_jsx("div", { className: "min-h-screen bg-paper flex items-center justify-center", children: _jsxs("div", { className: "flex flex-col items-center gap-4", children: [_jsx("div", { className: "w-8 h-8 border-2 border-gov border-t-transparent rounded-full animate-spin" }), _jsx("span", { className: "text-[12px] font-mono tracking-wider text-ink-3 uppercase", children: "Verifying Session..." })] }) })) : authed ? (_jsx(NotificationProvider, { children: _jsxs("div", { className: "min-h-screen bg-paper text-ink", children: [_jsx("a", { href: "#main-content", className: "sr-only focus:not-sr-only focus:absolute focus:z-50 focus:p-4 focus:bg-paper focus:text-ink", children: "Skip to main content" }), _jsx(AppSidebar, { featureFlags: featureFlags ?? undefined }), _jsx("main", { id: "main-content", className: "ml-[256px] min-h-screen overflow-y-auto", children: _jsx(ErrorBoundary, { children: _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(Navigate, { to: "/focus", replace: true }) }), _jsx(Route, { path: "/welcome", element: _jsx(WelcomePage, { workspaceId: currentWorkspaceId }) }), _jsx(Route, { path: "/focus", element: _jsx(FocusPage, { featureFlags: featureFlags ?? undefined }) }), _jsx(Route, { path: "/pain", element: _jsx(PainPage, {}) }), _jsx(Route, { path: "/principles", element: _jsx(PrinciplesPage, {}) }), _jsx(Route, { path: "/principles/:id", element: _jsx(PrincipleDetailPage, {}) }), _jsx(Route, { path: "/activation", element: _jsx(ActivationPage, {}) }), _jsx(Route, { path: "/debt", element: _jsx(DebtPage, {}) }), _jsx(Route, { path: "/control-center", element: _jsx(ControlCenterPage, {}) }), _jsx(Route, { path: "/control-center/signal-keywords", element: _jsx(SignalKeywordsPage, {}) }), _jsx(Route, { path: "/settings", element: _jsx(SettingsPage, {}) }), _jsx(Route, { path: "/update", element: _jsx(UpdatePage, {}) }), _jsx(Route, { path: "/report-problem", element: _jsx(ReportProblemPage, {}) }), _jsx(Route, { path: "/failed-tasks", element: _jsx(FailedTasksPage, {}) }), _jsx(Route, { path: "/intent", element: _jsx(IntentPage, {}) }), IS_DEV && (_jsx(Route, { path: "/design-system", element: _jsx(DesignSystemPage, {}) })), !IS_DEV && (_jsx(Route, { path: "/design-system", element: _jsx(Navigate, { to: "/focus", replace: true }) }))] }) }) })] }) })) : (_jsx(Navigate, { to: "/login", replace: true })) })] }));
134
+ } }) }), _jsx(Route, { path: "/login", element: _jsx(LoginForm, { onAuthSuccess: handleAuthSuccess }) }), _jsx(Route, { path: "/*", element: authed === null ? (_jsx("div", { className: "min-h-screen bg-paper flex items-center justify-center", children: _jsxs("div", { className: "flex flex-col items-center gap-4", children: [_jsx("div", { className: "w-8 h-8 border-2 border-gov border-t-transparent rounded-full animate-spin" }), _jsx("span", { className: "text-[12px] font-mono tracking-wider text-ink-3 uppercase", children: "Verifying Session..." })] }) })) : authed ? (_jsx(NotificationProvider, { children: _jsxs("div", { className: "min-h-screen bg-paper text-ink", children: [_jsx("a", { href: "#main-content", className: "sr-only focus:not-sr-only focus:absolute focus:z-50 focus:p-4 focus:bg-paper focus:text-ink", children: "Skip to main content" }), _jsx(AppSidebar, { featureFlags: featureFlags ?? undefined }), _jsx("main", { id: "main-content", className: "ml-[256px] min-h-screen overflow-y-auto", children: _jsx(ErrorBoundary, { children: _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(Navigate, { to: "/focus", replace: true }) }), _jsx(Route, { path: "/welcome", element: _jsx(WelcomePage, { workspaceId: currentWorkspaceId }) }), _jsx(Route, { path: "/focus", element: _jsx(FocusPage, { featureFlags: featureFlags ?? undefined }) }), _jsx(Route, { path: "/pain", element: _jsx(PainPage, {}) }), _jsx(Route, { path: "/principles", element: _jsx(PrinciplesPage, {}) }), _jsx(Route, { path: "/principles/core", element: _jsx(CorePrinciplesPage, {}) }), _jsx(Route, { path: "/principles/:id", element: _jsx(PrincipleDetailPage, {}) }), _jsx(Route, { path: "/activation", element: _jsx(ActivationPage, {}) }), _jsx(Route, { path: "/debt", element: _jsx(DebtPage, {}) }), _jsx(Route, { path: "/control-center", element: _jsx(ControlCenterPage, {}) }), _jsx(Route, { path: "/control-center/signal-keywords", element: _jsx(SignalKeywordsPage, {}) }), _jsx(Route, { path: "/settings", element: _jsx(SettingsPage, {}) }), _jsx(Route, { path: "/update", element: _jsx(UpdatePage, {}) }), _jsx(Route, { path: "/report-problem", element: _jsx(ReportProblemPage, {}) }), _jsx(Route, { path: "/failed-tasks", element: _jsx(FailedTasksPage, {}) }), _jsx(Route, { path: "/intent", element: _jsx(IntentPage, {}) }), IS_DEV && (_jsx(Route, { path: "/design-system", element: _jsx(DesignSystemPage, {}) })), !IS_DEV && (_jsx(Route, { path: "/design-system", element: _jsx(Navigate, { to: "/focus", replace: true }) }))] }) }) })] }) })) : (_jsx(Navigate, { to: "/login", replace: true })) })] }));
134
135
  }
135
136
  export function App() {
136
137
  return (_jsx(ThemeProvider, { children: _jsxs(I18nextProvider, { i18n: i18n, children: [_jsx(HashRouter, { children: _jsx(AuthRoutes, {}) }), _jsx(Toaster, {})] }) }));
@@ -3,7 +3,7 @@ import type { OwnerDecisionsData, OwnerResolutionResultData } from "./utils/vali
3
3
  import { listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm } from "./utils/signal-keywords-api.js";
4
4
  import type { GovernanceExperienceSnapshot, OwnerGovernanceView } from '@principles/core/runtime-v2';
5
5
  import type { OwnerIdentityViewData, OwnerIdentityRegisterData, OwnerIdentityUnregisterData } from "./utils/validators.js";
6
- import type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, FeedbackChannelsData, FeedbackSubmitResultData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, RuntimeProfileMutationData, ReadinessCheckData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, RecoveryResultData, ActivationsData, DisableActivationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, RollbackResultData, ApprovalRecordData, PrinciplesListData, ApprovalsGroupedData, EvidenceChainData, TrajectoryData, IntentSummaryData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, IntentInitResultData, IntentSaveResultData, IntentRawContentData, IntentVersionData, RuleCodeOwnerReviewData, RuleCodeMutationData } from "./utils/validators.js";
6
+ import type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, FeedbackChannelsData, FeedbackSubmitResultData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, RuntimeProfileMutationData, ReadinessCheckData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, RecoveryResultData, ActivationsData, DisableActivationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, RollbackResultData, ApprovalRecordData, PrinciplesListData, CorePrinciplesData, ApprovalsGroupedData, EvidenceChainData, TrajectoryData, IntentSummaryData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, IntentInitResultData, IntentSaveResultData, IntentRawContentData, IntentVersionData, RuleCodeOwnerReviewData, RuleCodeMutationData } from "./utils/validators.js";
7
7
  declare function getToken(): string | null;
8
8
  declare function setToken(token: string): void;
9
9
  declare function clearToken(): void;
@@ -27,6 +27,7 @@ declare function addWorkspace(name: string, path: string): Promise<ApiResponse<W
27
27
  declare function removeWorkspace(name: string): Promise<ApiResponse<RemovedEnvelopeData>>;
28
28
  declare function syncWorkspace(name: string): Promise<ApiResponse<SyncResultData>>;
29
29
  declare function fetchPrinciples(filter?: 'all' | 'actionable'): Promise<ApiResponse<PrinciplesListData>>;
30
+ declare function fetchCorePrinciples(): Promise<ApiResponse<CorePrinciplesData>>;
30
31
  declare function fetchPrincipleDetail(principleId: string): Promise<ApiResponse<unknown>>;
31
32
  declare function fetchPrincipleGovernance(principleId: string): Promise<ApiResponse<OwnerGovernanceView>>;
32
33
  declare function archivePrinciple(principleId: string): Promise<ApiResponse<unknown>>;
@@ -230,8 +231,8 @@ export interface FollowUpPayload {
230
231
  candidateId?: string;
231
232
  }
232
233
  declare function dispatchFollowUp(decisionId: string, payload: FollowUpPayload): Promise<ApiResponse<FollowUpResponseData>>;
233
- export { request, listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm, getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleGovernance, fetchPrincipleTrajectory, fetchPrincipleReceipts, fetchReceiptCounts, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport, fetchFeedbackChannels, submitFeedbackReport, markFeedbackReportSent, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchGovernanceExperience, recoverFailedTask, fetchOwnerDecisions, resolveOwnerDecision, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchRuleCodeOwnerReview, ruleCodeDecision, pauseAllRuleCode, releaseRuleCodePause, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, applyFullUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
234
- export type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, FeedbackChannelsData, FeedbackSubmitResultData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, RuntimeProfileMutationData, ReadinessCheckData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, RecoveryResultData, ActivationsData, DisableActivationData, RuleCodeOwnerReviewData, RuleCodeMutationData, 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";
234
+ export { request, listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm, getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchCorePrinciples, fetchPrincipleDetail, fetchPrincipleGovernance, fetchPrincipleTrajectory, fetchPrincipleReceipts, fetchReceiptCounts, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport, fetchFeedbackChannels, submitFeedbackReport, markFeedbackReportSent, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchGovernanceExperience, recoverFailedTask, fetchOwnerDecisions, resolveOwnerDecision, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchRuleCodeOwnerReview, ruleCodeDecision, pauseAllRuleCode, releaseRuleCodePause, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, applyFullUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
235
+ export type { FeedbackReportData, FeedbackDraftSummaryData, FeedbackDraftEnvelopeData, FeedbackChannelsData, FeedbackSubmitResultData, DeleteEnvelopeData, WorkspaceEntryData, RemovedEnvelopeData, SyncResultData, ConfigSummaryData, ConfigCatalogData, AgentBindingUpdateData, DefaultRuntimeUpdateData, RuntimeProfileMutationData, ReadinessCheckData, FeatureFlagUpdateData, OutputLanguageData, GovernanceQueueData, RecoveryResultData, ActivationsData, DisableActivationData, RuleCodeOwnerReviewData, RuleCodeMutationData, LifecycleMetricsData, UpdateStatusData, UpdateHistoryData, ApplyUpdateResultData, RollbackResultData, ApprovalRecordData, PrinciplesListData, CorePrinciplesData, CorePrincipleData, ApprovalsGroupedData, EvidenceChainData, EvidenceChainRecordData, EvidenceChainStateData, TrajectoryData, TrajectoryStageData, IntentSummaryData, IntentSectionsData, IntentDocWarningData, IntentDecisionRecordData, IntentDecisionResultData, IntentDecisionSummaryData, FollowUpResponseData, LinkCandidateFollowUpData, GuideRulehostFollowUpData, GeneratePatchProposalFollowUpData, IntentVersionEntry, IntentVersionData, } from "./utils/validators.js";
235
236
  export type { SignalKeyword, PendingSignalTerm } from "./utils/signal-keywords-types.js";
236
237
  export type { ActivationRecordData as ActivationRecord } from "./utils/validators.js";
237
238
  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, validateFeedbackChannels, validateFeedbackSubmitResult, validateDeleteEnvelope, validateWorkspaceEntry, validateWorkspaceList, validateRemovedEnvelope, validateSyncResult, validateConfigSummary, validateConfigCatalog, validateAgentBindingUpdate, validateDefaultRuntimeUpdate, validateRuntimeProfileMutation, validateReadinessCheck, validateFeatureFlagUpdate, validateOutputLanguage, validateGovernanceQueue, validateRecoveryResult, validateOwnerDecisionsData, validateOwnerResolutionResult, validateActivations, validateDisableActivation, validateLifecycleMetrics, validateUpdateStatus, validateUpdateHistory, validateApplyUpdateResult, validateRollbackResult, validateApprovalRecordDirect, validatePrinciplesList, validateApprovalsGrouped, validateEvidenceChain, validateTrajectoryData, validateIntentSummary, validateIntentDecisionList, validateIntentDecisionResult, validateIntentDecisionSummary, validateFollowUpResponse, validateIntentInitResult, validateIntentSaveResult, validateIntentRawContent, validateIntentVersions, validateOwnerGovernanceView, validateGovernanceExperienceSnapshot, validateRuleCodeOwnerReview, validateRuleCodeMutation, validateOwnerIdentityView, validateOwnerIdentityRegister, validateOwnerIdentityUnregister, } from "./utils/validators.js";
2
+ import { validateErrorResponse, validateHeaders, validateFeedbackReport, validateFeedbackDraftsList, validateFeedbackDraftEnvelope, validateFeedbackChannels, validateFeedbackSubmitResult, validateDeleteEnvelope, validateWorkspaceEntry, validateWorkspaceList, validateRemovedEnvelope, validateSyncResult, validateConfigSummary, validateConfigCatalog, validateAgentBindingUpdate, validateDefaultRuntimeUpdate, validateRuntimeProfileMutation, validateReadinessCheck, validateFeatureFlagUpdate, validateOutputLanguage, validateGovernanceQueue, validateRecoveryResult, validateOwnerDecisionsData, validateOwnerResolutionResult, validateActivations, validateDisableActivation, validateLifecycleMetrics, validateUpdateStatus, validateUpdateHistory, validateApplyUpdateResult, validateRollbackResult, validateApprovalRecordDirect, validatePrinciplesList, validateCorePrinciples, validateApprovalsGrouped, validateEvidenceChain, validateTrajectoryData, validateIntentSummary, validateIntentDecisionList, validateIntentDecisionResult, validateIntentDecisionSummary, validateFollowUpResponse, validateIntentInitResult, validateIntentSaveResult, validateIntentRawContent, validateIntentVersions, validateOwnerGovernanceView, validateGovernanceExperienceSnapshot, validateRuleCodeOwnerReview, validateRuleCodeMutation, validateOwnerIdentityView, validateOwnerIdentityRegister, validateOwnerIdentityUnregister, } from "./utils/validators.js";
3
3
  // ── Auth ──────────────────────────────────────────────────────────────────────
4
4
  function getToken() {
5
5
  return sessionStorage.getItem("pd_token");
@@ -113,6 +113,11 @@ async function fetchPrinciples(filter) {
113
113
  const query = filter === undefined ? '' : `?filter=${filter}`;
114
114
  return request(`/api/principles${query}`, undefined, validatePrinciplesList);
115
115
  }
116
+ // PRI-641: read-only PD Core Principles reference. Served from the canonical
117
+ // registry by the server; validated here for network shape only.
118
+ async function fetchCorePrinciples() {
119
+ return request("/api/principles/core", undefined, validateCorePrinciples);
120
+ }
116
121
  // Principle detail is deeply nested; for now we accept unvalidated until a
117
122
  // dedicated validator is added (the page already handles missing fields gracefully).
118
123
  // This endpoint is marked legacy/deferred for full validation.
@@ -575,6 +580,6 @@ export { request,
575
580
  // signal-keywords (UI stubs, see signal-keywords-api.ts)
576
581
  listActiveSignalKeywords, listPendingSignalTerms, fetchKeywordStore, fetchPendingTerms, updateKeywordStore, admitPendingTerm, rejectPendingTerm,
577
582
  // auth
578
- getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchPrincipleDetail, fetchPrincipleGovernance, fetchPrincipleTrajectory, fetchPrincipleReceipts, fetchReceiptCounts, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport,
583
+ getToken, setToken, clearToken, checkAuth, approveApproval, rejectApproval, editApproval, fetchPrinciples, fetchCorePrinciples, fetchPrincipleDetail, fetchPrincipleGovernance, fetchPrincipleTrajectory, fetchPrincipleReceipts, fetchReceiptCounts, archivePrinciple, unarchivePrinciple, createFeedbackReport, listFeedbackReports, getFeedbackReport, deleteFeedbackReport,
579
584
  // Feedback submit ladder (Slice 3, spec §8)
580
585
  fetchFeedbackChannels, submitFeedbackReport, markFeedbackReportSent, fetchConfigSummary, fetchConfigCatalog, updateAgentBinding, updateDefaultRuntime, createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, fetchAgentReadiness, patchFeatureFlag, fetchOutputLanguage, updateOutputLanguage, fetchWorkspaces, addWorkspace, removeWorkspace, syncWorkspace, fetchGovernanceQueue, fetchGovernanceExperience, recoverFailedTask, fetchOwnerDecisions, resolveOwnerDecision, fetchApprovalsGrouped, fetchAllActivations, disableActivation, fetchRuleCodeOwnerReview, ruleCodeDecision, pauseAllRuleCode, releaseRuleCodePause, fetchLifecycleMetrics, fetchUpdateStatus, fetchUpdateHistory, applyUpdate, applyFullUpdate, rollbackUpdate, fetchEvidenceChain, fetchIntentSummary, fetchIntentContent, createIntentTemplate, saveIntentContent, fetchIntentVersions, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, fetchIntentDecisionSummary, dispatchFollowUp, };
@@ -506,6 +506,18 @@
506
506
  "reviewTitle": "Principle Review",
507
507
  "reviewSubtitle": "Review the principles distilled from observed behavior.",
508
508
  "reviewDescription": "These are not cold rules — they are behavioral principles your Agent has distilled from real use.",
509
+ "viewNavLabel": "Principles views",
510
+ "tabWorkspace": "Workspace Principles",
511
+ "tabCore": "PD Core Principles",
512
+ "coreSectionTitle": "PRINCIPLES",
513
+ "coreTitle": "PD Core Principles",
514
+ "coreDescription": "These are the built-in principles PD uses to guide how an agent understands problems, makes judgments, and learns from experience. They are provided by the PD Runtime and are not workspace-learned principles.",
515
+ "coreReadOnly": "Read-only",
516
+ "coreLayerFoundational": "Foundational Axioms",
517
+ "coreLayerOperating": "Operating Principles",
518
+ "coreLoading": "Loading…",
519
+ "coreLoadFailed": "Unable to load PD Core Principles",
520
+ "coreRetry": "Retry",
509
521
  "metricDeposited": "Deposited Principles",
510
522
  "metricActive": "Active Principles",
511
523
  "metricLatest": "Last Updated",
@@ -506,6 +506,18 @@
506
506
  "reviewTitle": "原则审查",
507
507
  "reviewSubtitle": "审阅从真实行为中沉淀出的原则。",
508
508
  "reviewDescription": "这些不是冰冷的规则,而是智能体在真实使用过程中沉淀下来的行为准则。",
509
+ "viewNavLabel": "原则视图",
510
+ "tabWorkspace": "工作区原则",
511
+ "tabCore": "PD 核心原则",
512
+ "coreSectionTitle": "原则",
513
+ "coreTitle": "PD 核心原则",
514
+ "coreDescription": "这些是 PD 内置的基本原则,用来指导智能体如何理解问题、作出判断,以及从经验中学习。它们由 PD Runtime 提供,不属于工作区的学习原则。",
515
+ "coreReadOnly": "只读",
516
+ "coreLayerFoundational": "基础公理",
517
+ "coreLayerOperating": "操作原则",
518
+ "coreLoading": "加载中…",
519
+ "coreLoadFailed": "无法加载 PD 核心原则",
520
+ "coreRetry": "重试",
509
521
  "metricDeposited": "沉淀原则",
510
522
  "metricActive": "已生效原则",
511
523
  "metricLatest": "最近更新",
@@ -0,0 +1,10 @@
1
+ /**
2
+ * PD Core Principles — read-only reference surface (PRI-641).
3
+ *
4
+ * The 10 builtin axioms (T-01..T-10) are PD's own semantics, served from the
5
+ * canonical registry via GET /api/principles/core. They are not workspace
6
+ * governance targets: no lifecycle, no approvals, no archive, no edit. This
7
+ * page renders exactly id / name / statement / layer, localized with the
8
+ * registry's own bilingual fields.
9
+ */
10
+ export declare function CorePrinciplesPage(): import("react").JSX.Element;
@@ -0,0 +1,59 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect, useCallback } from "react";
3
+ import { useTranslation } from "react-i18next";
4
+ import { PageShell } from "../../components/layout/page-shell.js";
5
+ import { SectionTitle } from "../../components/layout/section-title.js";
6
+ import { Button } from "../../components/ui/button.js";
7
+ import { Skeleton } from "../../components/ui/skeleton.js";
8
+ import { fetchCorePrinciples } from "../../api.js";
9
+ import { PrinciplesViewNav } from "./PrinciplesViewNav.js";
10
+ /**
11
+ * PD Core Principles — read-only reference surface (PRI-641).
12
+ *
13
+ * The 10 builtin axioms (T-01..T-10) are PD's own semantics, served from the
14
+ * canonical registry via GET /api/principles/core. They are not workspace
15
+ * governance targets: no lifecycle, no approvals, no archive, no edit. This
16
+ * page renders exactly id / name / statement / layer, localized with the
17
+ * registry's own bilingual fields.
18
+ */
19
+ export function CorePrinciplesPage() {
20
+ const { t, i18n } = useTranslation("pages");
21
+ const [principles, setPrinciples] = useState([]);
22
+ const [loading, setLoading] = useState(true);
23
+ const [error, setError] = useState(null);
24
+ const loadCore = useCallback(async () => {
25
+ setLoading(true);
26
+ setError(null);
27
+ try {
28
+ // Response shape is runtime-validated in fetchCorePrinciples
29
+ // (validateCorePrinciples); no fallback to hardcoded principles on error.
30
+ const result = await fetchCorePrinciples();
31
+ if (!result.success) {
32
+ setError(result.error ?? t("principles.coreLoadFailed"));
33
+ return;
34
+ }
35
+ setPrinciples(result.data.principles);
36
+ }
37
+ catch (err) {
38
+ setError(err instanceof Error ? err.message : t("principles.coreLoadFailed"));
39
+ }
40
+ finally {
41
+ setLoading(false);
42
+ }
43
+ }, [t]);
44
+ useEffect(() => {
45
+ loadCore();
46
+ }, [loadCore]);
47
+ const isZh = (i18n.language ?? "").startsWith("zh");
48
+ const foundational = principles.filter((p) => p.layer === "foundational");
49
+ const operating = principles.filter((p) => p.layer === "operating");
50
+ return (_jsxs(PageShell, { children: [_jsx(SectionTitle, { children: t("principles.coreSectionTitle") }), _jsx("h1", { className: "text-[29px] font-semibold tracking-tight text-ink mb-2", children: t("principles.coreTitle") }), _jsx("p", { className: "text-ink-3 text-[14px] leading-relaxed mb-1", children: t("principles.coreDescription") }), _jsxs("p", { className: "text-ink-4 text-[12px] font-mono mb-6", children: ["\uD83D\uDD12 ", t("principles.coreReadOnly")] }), _jsx(PrinciplesViewNav, { view: "core" }), loading && (_jsx("div", { className: "grid gap-3", role: "status", "aria-live": "polite", "aria-label": t("principles.coreLoading"), children: Array.from({ length: 4 }).map((_, i) => (_jsxs("div", { className: "bg-panel border border-line rounded-[var(--radius-md)] p-4", children: [_jsx(Skeleton, { className: "h-5 w-[40%] rounded-sm mb-3" }), _jsx(Skeleton, { className: "h-4 w-full rounded-sm mb-2" }), _jsx(Skeleton, { className: "h-4 w-[70%] rounded-sm" })] }, i))) })), error && (_jsxs("div", { className: "border border-danger/30 rounded-[var(--radius-md)] p-4 mb-4", children: [_jsx("p", { className: "text-danger text-sm", children: t("principles.coreLoadFailed") }), _jsx("p", { className: "text-ink-4 text-[12px] mt-1 font-mono break-all", children: error }), _jsx(Button, { variant: "outline", size: "sm", onClick: loadCore, className: "mt-2", children: t("principles.coreRetry") })] })), !loading && !error && (_jsxs(_Fragment, { children: [_jsx(CoreLayerGroup, { label: t("principles.coreLayerFoundational"), principles: foundational, isZh: isZh }), _jsx(CoreLayerGroup, { label: t("principles.coreLayerOperating"), principles: operating, isZh: isZh })] }))] }));
51
+ }
52
+ function CoreLayerGroup({ label, principles, isZh, }) {
53
+ const { t } = useTranslation("pages");
54
+ return (_jsxs("section", { className: "mb-8", "aria-label": label, children: [_jsxs("h2", { className: "font-mono text-[11px] uppercase tracking-[0.02em] text-ink-3 border-b border-line pb-2 mb-4", children: [label, " \u00B7 ", principles.length] }), _jsx("div", { className: "grid gap-3 animate-[pdFadeIn_400ms_ease-out]", children: principles.map((p) => {
55
+ const name = isZh ? p.nameZh : p.name;
56
+ const statement = isZh ? p.statementZh : p.statement;
57
+ return (_jsxs("article", { id: p.id, className: "bg-panel border border-line rounded-[var(--radius-md)] p-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-2", children: [_jsx("span", { className: "font-mono text-[11px] tracking-[0.02em] border border-line rounded-[2px] px-2 py-0.5 text-ink-3", children: p.id }), _jsx("span", { className: "font-mono text-[11px] tracking-[0.02em] text-ink-4", children: t("principles.coreLayer" + (p.layer === "foundational" ? "Foundational" : "Operating")) })] }), _jsx("h3", { className: "font-semibold text-ink mb-1", children: name }), _jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed", children: statement })] }, p.id));
58
+ }) })] }));
59
+ }
@@ -10,6 +10,7 @@ import { ShinyText } from "../../components/ui/shiny-text.js";
10
10
  import { fetchPrinciples, fetchApprovalsGrouped, } from "../../api.js";
11
11
  import { enumLabel } from "../../utils/enum-labels.js";
12
12
  import { formatDate } from "../../utils/format-date.js";
13
+ import { PrinciplesViewNav } from "./PrinciplesViewNav.js";
13
14
  // ── Map principle status to review status ───────────────────────────────────
14
15
  function toReviewStatus(principleStatus, approvalStatus) {
15
16
  if (approvalStatus === "approved")
@@ -259,7 +260,7 @@ export function PrinciplesPage() {
259
260
  ];
260
261
  // PRI-558: most recent update across loaded principles (drives "Last Updated" metric)
261
262
  const latestUpdatedAt = principles.reduce((max, p) => (new Date(p.updatedAt).getTime() > new Date(max).getTime() ? p.updatedAt : max), principles[0]?.updatedAt ?? "");
262
- return (_jsxs(PageShell, { children: [_jsx(SectionTitle, { children: t("principles.reviewTitle") }), _jsx(ShinyText, { as: "h1", className: "text-[29px] font-semibold tracking-tight text-ink mb-2", duration: 4.5, brightness: 0.5, disabled: !(filterMode === 'actionable' && (categories?.owner_actionable ?? 0) > 0), children: t("principles.reviewSubtitle") }), _jsx("p", { className: "text-ink-3 text-[14px] leading-relaxed mb-6", children: t("principles.reviewDescription") }), _jsxs("div", { className: "flex flex-wrap items-center gap-3 mb-6", children: [_jsxs("div", { className: "flex gap-1", role: "group", "aria-label": "Filter mode", children: [_jsxs("button", { onClick: () => setFilterMode('actionable'), className: "font-mono text-[11px] uppercase tracking-[0.02em] border rounded-[2px] px-2 py-1 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov " +
263
+ return (_jsxs(PageShell, { children: [_jsx(SectionTitle, { children: t("principles.reviewTitle") }), _jsx(ShinyText, { as: "h1", className: "text-[29px] font-semibold tracking-tight text-ink mb-2", duration: 4.5, brightness: 0.5, disabled: !(filterMode === 'actionable' && (categories?.owner_actionable ?? 0) > 0), children: t("principles.reviewSubtitle") }), _jsx("p", { className: "text-ink-3 text-[14px] leading-relaxed mb-6", children: t("principles.reviewDescription") }), _jsx(PrinciplesViewNav, { view: "workspace" }), _jsxs("div", { className: "flex flex-wrap items-center gap-3 mb-6", children: [_jsxs("div", { className: "flex gap-1", role: "group", "aria-label": "Filter mode", children: [_jsxs("button", { onClick: () => setFilterMode('actionable'), className: "font-mono text-[11px] uppercase tracking-[0.02em] border rounded-[2px] px-2 py-1 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov " +
263
264
  (filterMode === 'actionable'
264
265
  ? "bg-gov text-paper border-gov"
265
266
  : "bg-surface text-ink-3 border-line hover:border-line-2"), children: [t("principles.filterActionable", { defaultValue: "Actionable" }), categories?.owner_actionable ? ` (${categories.owner_actionable})` : ''] }), _jsxs("button", { onClick: () => setFilterMode('all'), className: "font-mono text-[11px] uppercase tracking-[0.02em] border rounded-[2px] px-2 py-1 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gov " +
@@ -0,0 +1,8 @@
1
+ /**
2
+ * PRI-641: internal navigation inside the Principles section — Workspace
3
+ * Principles vs the read-only PD Core Principles reference surface. The
4
+ * sidebar keeps a single "Principles" entry; this is the only extra nav.
5
+ */
6
+ export declare function PrinciplesViewNav({ view }: {
7
+ view: "workspace" | "core";
8
+ }): import("react").JSX.Element;