create-principles-disciple 1.147.0 → 1.147.2

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 (82) hide show
  1. package/_release/product-identity.json +1 -1
  2. package/codex-adapter/dist/ingestion/admission.d.ts +5 -10
  3. package/codex-adapter/dist/ingestion/admission.js +19 -77
  4. package/codex-adapter/dist/ingestion/explicit-owner-statement.js +1 -1
  5. package/codex-adapter/dist/ingestion/ingestion.d.ts +0 -2
  6. package/codex-adapter/dist/ingestion/ingestion.js +6 -4
  7. package/codex-adapter/dist/pd-hook.js +5 -7
  8. package/codex-adapter/package.json +1 -1
  9. package/console/dist/shared/prompt-injection-contract.d.ts +1 -1
  10. package/console/dist/web/assets/app.js +31 -31
  11. package/core/dist/prompt-builder/size-guard.d.ts.map +1 -1
  12. package/core/dist/prompt-builder/size-guard.js +6 -1
  13. package/core/dist/prompt-builder/size-guard.js.map +1 -1
  14. package/core/dist/prompt-builder/types.d.ts +2 -1
  15. package/core/dist/prompt-builder/types.d.ts.map +1 -1
  16. package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.d.ts +12 -1
  17. package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.d.ts.map +1 -1
  18. package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.js +12 -1
  19. package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.js.map +1 -1
  20. package/core/dist/runtime-v2/activation/prompt-budget-policy.d.ts +42 -11
  21. package/core/dist/runtime-v2/activation/prompt-budget-policy.d.ts.map +1 -1
  22. package/core/dist/runtime-v2/activation/prompt-budget-policy.js +82 -30
  23. package/core/dist/runtime-v2/activation/prompt-budget-policy.js.map +1 -1
  24. package/core/dist/runtime-v2/adapter/pi-ai-catalog.d.ts.map +1 -1
  25. package/core/dist/runtime-v2/adapter/pi-ai-catalog.js +17 -5
  26. package/core/dist/runtime-v2/adapter/pi-ai-catalog.js.map +1 -1
  27. package/core/dist/runtime-v2/evidence-triage/index.d.ts +0 -1
  28. package/core/dist/runtime-v2/evidence-triage/index.d.ts.map +1 -1
  29. package/core/dist/runtime-v2/evidence-triage/index.js +0 -2
  30. package/core/dist/runtime-v2/evidence-triage/index.js.map +1 -1
  31. package/core/dist/runtime-v2/evidence-triage/source-descriptors.d.ts +3 -8
  32. package/core/dist/runtime-v2/evidence-triage/source-descriptors.d.ts.map +1 -1
  33. package/core/dist/runtime-v2/evidence-triage/source-descriptors.js +5 -17
  34. package/core/dist/runtime-v2/evidence-triage/source-descriptors.js.map +1 -1
  35. package/core/dist/runtime-v2/evidence-triage/triage-policy.d.ts +11 -9
  36. package/core/dist/runtime-v2/evidence-triage/triage-policy.d.ts.map +1 -1
  37. package/core/dist/runtime-v2/evidence-triage/triage-policy.js +10 -103
  38. package/core/dist/runtime-v2/evidence-triage/triage-policy.js.map +1 -1
  39. package/core/dist/runtime-v2/evidence-triage/trigger-controller.js +1 -1
  40. package/core/dist/runtime-v2/evidence-triage/trigger-controller.js.map +1 -1
  41. package/core/dist/runtime-v2/evidence-triage/types.d.ts +4 -16
  42. package/core/dist/runtime-v2/evidence-triage/types.d.ts.map +1 -1
  43. package/core/dist/runtime-v2/evidence-triage/types.js.map +1 -1
  44. package/core/dist/runtime-v2/index.d.ts +1 -1
  45. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  46. package/core/dist/runtime-v2/index.js +1 -1
  47. package/core/dist/runtime-v2/index.js.map +1 -1
  48. package/core/dist/runtime-v2/intent/intent-friction-block.d.ts +2 -2
  49. package/core/dist/runtime-v2/intent/intent-friction-block.js +2 -2
  50. package/core/dist/runtime-v2/types/event-types.d.ts +2 -2
  51. package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
  52. package/core/dist/runtime-v2/types/event-types.js +1 -0
  53. package/core/dist/runtime-v2/types/event-types.js.map +1 -1
  54. package/core/package.json +1 -1
  55. package/host-runtime/dist/governance-signal-admission.d.ts +1 -77
  56. package/host-runtime/dist/governance-signal-admission.js +34 -294
  57. package/host-runtime/dist/production-pain-evidence.d.ts +8 -69
  58. package/host-runtime/dist/production-pain-evidence.js +19 -157
  59. package/host-runtime/dist/prompt-injection-budget-observation.js +4 -2
  60. package/host-runtime/package.json +1 -1
  61. package/package.json +3 -3
  62. package/pd-cli/package.json +1 -1
  63. package/pd-mcp-server/dist/version.d.ts +1 -1
  64. package/pd-mcp-server/dist/version.js +1 -1
  65. package/pd-mcp-server/package.json +1 -1
  66. package/plugin/dist/bundle.js +411 -412
  67. package/plugin/dist/governance-audit.js +2 -2
  68. package/plugin/dist/hooks/after-tool-call-helpers.d.ts +2 -35
  69. package/plugin/dist/hooks/after-tool-call-types.d.ts +1 -30
  70. package/plugin/dist/hooks/pain.d.ts +6 -19
  71. package/plugin/dist/hooks/trajectory-evidence.d.ts +3 -10
  72. package/plugin/dist/hooks/triage-adapter.d.ts +7 -20
  73. package/plugin/dist/host-runtime/openclaw-host-runtime.d.ts +0 -1
  74. package/plugin/dist/openclaw.plugin.json +1 -1
  75. package/plugin/openclaw.plugin.json +1 -1
  76. package/plugin/package.json +1 -1
  77. package/release-manager/package.json +1 -1
  78. package/workbuddy-adapter/dist/codec/input-decoder.js +3 -1
  79. package/workbuddy-adapter/dist/pd-hook.js +0 -26
  80. package/workbuddy-adapter/dist/worker/workspace-worker.d.ts +1 -7
  81. package/workbuddy-adapter/dist/worker/workspace-worker.js +11 -21
  82. package/workbuddy-adapter/package.json +1 -1
@@ -2,13 +2,8 @@ import { createHash } from 'node:crypto';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import Database from 'better-sqlite3';
5
- import { applyTrajectorySchemaBase, buildToolFailureObservation, evaluateTriage, evaluateTriggerController, resolveSourceKind, sanitizeToolParams, sanitizeValue, } from '@principles/core/runtime-v2';
6
- const WRITE_TOOLS = new Set(['write', 'edit', 'apply_patch', 'write_file', 'edit_file', 'replace']);
7
- /** Shared with the governance admission path so both gate tool failures identically. */
8
- export const PRODUCTION_WRITE_TOOLS = WRITE_TOOLS;
5
+ import { applyTrajectorySchemaBase, sanitizeToolParams, sanitizeValue, } from '@principles/core/runtime-v2';
9
6
  const MAX_PREVIEW = 500;
10
- const PAIN_COOLDOWN_WINDOW_MS = 15 * 60 * 1000;
11
- const cooldowns = new Map();
12
7
  function isRecord(value) {
13
8
  return typeof value === 'object' && value !== null && !Array.isArray(value);
14
9
  }
@@ -33,7 +28,7 @@ function field(value, key) {
33
28
  * legitimate completion of the tool contract and stay success (SPEC §5.1).
34
29
  */
35
30
  function normalizeOutcome(event) {
36
- const context = 'context' in event ? event.context : event;
31
+ const { context } = event;
37
32
  const envelope = context.toolOutput;
38
33
  const result = field(envelope, 'result') ?? envelope;
39
34
  const errorValue = field(envelope, 'error') ?? field(result, 'error');
@@ -79,46 +74,15 @@ function normalizeOutcome(event) {
79
74
  result,
80
75
  };
81
76
  }
82
- function isEvidence(value) {
83
- return Array.isArray(value) && value.length <= 8 && value.every((entry) => isRecord(entry) && typeof field(entry, 'sourceRef') === 'string' && String(field(entry, 'sourceRef')).trim().length > 0
84
- && String(field(entry, 'sourceRef')).length <= 300 && typeof field(entry, 'note') === 'string' && String(field(entry, 'note')).length <= 200);
85
- }
86
77
  function parseEnrichment(value) {
87
78
  if (value === undefined)
88
79
  return {};
89
80
  if (!isRecord(value))
90
81
  return null;
91
- const painScore = field(value, 'painScore');
92
- const isRisky = field(value, 'isRisky');
93
- const consecutiveErrors = field(value, 'consecutiveErrors');
94
- const evidence = field(value, 'evidence');
95
82
  const eventId = field(value, 'eventId');
96
- const relativePath = field(value, 'relativePath');
97
- const agentId = field(value, 'agentId');
98
- const errorHash = field(value, 'errorHash');
99
- if (painScore !== undefined && (typeof painScore !== 'number' || !Number.isFinite(painScore) || painScore < 0 || painScore > 100))
100
- return null;
101
- if (isRisky !== undefined && typeof isRisky !== 'boolean')
83
+ if (eventId !== undefined && (typeof eventId !== 'string' || eventId.trim().length === 0 || eventId.length > 500))
102
84
  return null;
103
- if (consecutiveErrors !== undefined && (typeof consecutiveErrors !== 'number' || !Number.isInteger(consecutiveErrors) || consecutiveErrors < 0))
104
- return null;
105
- for (const key of ['eventId', 'relativePath', 'agentId', 'errorHash']) {
106
- const candidate = field(value, key);
107
- if (candidate !== undefined && (typeof candidate !== 'string' || candidate.trim().length === 0 || candidate.length > 500))
108
- return null;
109
- }
110
- if (evidence !== undefined && !isEvidence(evidence))
111
- return null;
112
- return {
113
- ...(typeof eventId === 'string' ? { eventId } : {}),
114
- ...(typeof painScore === 'number' ? { painScore } : {}),
115
- ...(typeof isRisky === 'boolean' ? { isRisky } : {}),
116
- ...(typeof consecutiveErrors === 'number' ? { consecutiveErrors } : {}),
117
- ...(typeof relativePath === 'string' ? { relativePath } : {}),
118
- ...(typeof agentId === 'string' ? { agentId } : {}),
119
- ...(typeof errorHash === 'string' ? { errorHash } : {}),
120
- ...(isEvidence(evidence) ? { evidence } : {}),
121
- };
85
+ return typeof eventId === 'string' ? { eventId } : {};
122
86
  }
123
87
  function stable(value, seen = new WeakSet()) {
124
88
  if (value === null || typeof value !== 'object') {
@@ -165,42 +129,7 @@ function ids(input) {
165
129
  failure: outcome.failure,
166
130
  });
167
131
  const digest = createHash('sha256').update(canonical).digest('hex');
168
- return { eventId: `host_${digest}`, painId: `pain_host_${digest}` };
169
- }
170
- /**
171
- * The canonical tool-pain identity derivation, exposed for the governance
172
- * admission path (Codex Governance Closure SPEC §10): the same normalized
173
- * fields fed to the live production handler derive the same deterministic
174
- * `pain_host_<sha256>` id, so live and observation-delivered admissions of one
175
- * tool call converge on one canonical pain.
176
- *
177
- * I1 parity obligation: when the host supplies a call id, BOTH paths must pass
178
- * the same `toolCallId` (Codex admission candidates carry it from the same
179
- * `tool_use_id` the live decoder required) — otherwise one real call would
180
- * derive two canonical pains.
181
- */
182
- export function deriveProductionToolPainIdentity(fields) {
183
- const outcome = normalizeOutcome(fields);
184
- const sanitizedParams = sanitizeToolParams(outcome.params, fields.workspaceDir);
185
- const { eventId, painId } = ids({
186
- workspaceDir: fields.workspaceDir,
187
- sessionId: fields.sessionId,
188
- ...(fields.turnId !== undefined ? { turnId: fields.turnId } : {}),
189
- ...(fields.toolName !== undefined ? { toolName: fields.toolName } : {}),
190
- source: fields.source,
191
- ...(fields.canonicalEventId !== undefined ? { canonicalEventId: fields.canonicalEventId } : {}),
192
- ...(fields.toolCallId !== undefined ? { toolCallId: fields.toolCallId } : {}),
193
- outcome,
194
- sanitizedParams,
195
- });
196
- return {
197
- eventId,
198
- painId,
199
- outcome,
200
- sanitizedParams,
201
- paramsJson: stable(sanitizedParams),
202
- resultPreview: preview({ eventId, result: sanitizeValue(outcome.result, 0, fields.workspaceDir) }),
203
- };
132
+ return { eventId: `host_${digest}` };
204
133
  }
205
134
  /**
206
135
  * The canonical correction-pain identity derivation (SPEC §10/§12): deterministic,
@@ -415,6 +344,13 @@ export function recordVerifiedToolOutcomes(args) {
415
344
  return results;
416
345
  }
417
346
  /**
347
+ * Shared production tool-call evidence handler.
348
+ *
349
+ * Records the real host tool call in `trajectory.db` (tool_calls) and emits the
350
+ * receipt event. Phase A retired the legacy automatic Pain admission that used
351
+ * to ride on this path: a technical tool failure is trajectory + health
352
+ * evidence, never an Owner-pain by itself.
353
+ *
418
354
  * PRI-640: host attribution is supplied by the host adapter that constructs
419
355
  * this shared handler (OpenClaw / Codex adapters) — never guessed inside the
420
356
  * writer. Omitted -> NULL (unknown).
@@ -445,7 +381,7 @@ export function createProductionPainEvidenceHandler(options = {}) {
445
381
  }
446
382
  const dbPath = path.join(event.context.workspaceDir, '.state', 'trajectory.db');
447
383
  if (!fs.existsSync(dbPath)) {
448
- return { decision: 'observe', source: event.source, warnings: [...(emissionWarning ? [emissionWarning] : []), 'trajectory_db_not_found'], metadata: { outcome: 'unavailable', admitted: false, duplicate: false, nextAction: 'initialize the selected PD workspace before retrying the hook' } };
384
+ return { decision: 'observe', source: event.source, warnings: [...(emissionWarning ? [emissionWarning] : []), 'trajectory_db_not_found'], metadata: { outcome: 'unavailable', duplicate: false, nextAction: 'initialize the selected PD workspace before retrying the hook' } };
449
385
  }
450
386
  let db;
451
387
  try {
@@ -457,7 +393,7 @@ export function createProductionPainEvidenceHandler(options = {}) {
457
393
  if (!hasCanonicalSchema(db)) {
458
394
  db.close();
459
395
  db = undefined;
460
- return { decision: 'observe', source: event.source, warnings: [...(emissionWarning ? [emissionWarning] : []), 'trajectory_schema_invalid'], metadata: { outcome: 'unavailable', admitted: false, duplicate: false, nextAction: 'run the supported PD workspace migration' } };
396
+ return { decision: 'observe', source: event.source, warnings: [...(emissionWarning ? [emissionWarning] : []), 'trajectory_schema_invalid'], metadata: { outcome: 'unavailable', duplicate: false, nextAction: 'run the supported PD workspace migration' } };
461
397
  }
462
398
  }
463
399
  catch (error) {
@@ -465,7 +401,7 @@ export function createProductionPainEvidenceHandler(options = {}) {
465
401
  db?.close();
466
402
  }
467
403
  catch { /* best-effort cleanup of an unusable handle */ }
468
- return { decision: 'observe', source: event.source, warnings: [...(emissionWarning ? [emissionWarning] : []), `trajectory_database_unavailable:${error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200)}`], metadata: { outcome: 'unavailable', admitted: false, duplicate: false, nextAction: 'inspect or repair the selected PD trajectory database' } };
404
+ return { decision: 'observe', source: event.source, warnings: [...(emissionWarning ? [emissionWarning] : []), `trajectory_database_unavailable:${error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200)}`], metadata: { outcome: 'unavailable', duplicate: false, nextAction: 'inspect or repair the selected PD trajectory database' } };
469
405
  }
470
406
  const warnings = [];
471
407
  let enrichment;
@@ -481,49 +417,12 @@ export function createProductionPainEvidenceHandler(options = {}) {
481
417
  db.close();
482
418
  }
483
419
  catch { /* no business write occurred */ }
484
- return { decision: 'observe', source: event.source, warnings: [...(emissionWarning ? [emissionWarning] : []), ...(warnings.length > 0 ? warnings : ['pain_enrichment_invalid'])], metadata: { outcome: 'unavailable', admitted: false, duplicate: false, nextAction: 'inspect host pain enrichment input' } };
420
+ return { decision: 'observe', source: event.source, warnings: [...(emissionWarning ? [emissionWarning] : []), ...(warnings.length > 0 ? warnings : ['pain_enrichment_invalid'])], metadata: { outcome: 'unavailable', duplicate: false, nextAction: 'inspect host tool-call enrichment input' } };
485
421
  }
486
422
  const outcome = normalizeOutcome(event);
487
423
  const sanitizedParams = sanitizeToolParams(outcome.params, event.context.workspaceDir);
488
424
  const toolName = event.context.toolName ?? '';
489
- const sourceObservation = buildToolFailureObservation({ toolName, error: outcome.error, exitCode: outcome.exitCode ?? undefined });
490
- const nonZeroExit = outcome.exitCode !== null && outcome.exitCode !== 0;
491
- const sourceKind = resolveSourceKind({
492
- observedAt: new Date().toISOString(), workspaceId: event.context.workspaceDir,
493
- sessionId: event.context.sessionId, toolName, failureSource: sourceObservation.failureSource,
494
- toolNotFound: sourceObservation.toolNotFound, nonZeroExit,
495
- });
496
- const relativePath = enrichment.relativePath ?? String(field(outcome.params, 'file_path') ?? field(outcome.params, 'path') ?? 'unknown').slice(0, 500);
497
- const isRisky = enrichment.isRisky ?? (path.isAbsolute(relativePath) && !path.resolve(relativePath).startsWith(`${path.resolve(event.context.workspaceDir)}${path.sep}`));
498
- // Merged scoring semantics (WorkBuddy admission floor × CR-01): the 70
499
- // failure base requires a VERIFIED non-zero exit code (branch review
500
- // round: a thrown error with no exit evidence stays at the risky-path
501
- // bonus only, honestly below the GOVERNANCE_STRONG_PAIN_SCORE floor, so
502
- // unverified error shapes never spawn diagnostician work on their own).
503
- // Classification and RECORDING remain main's three-way contract — the
504
- // row still records outcome='failure' with exit_code NULL (never a
505
- // fabricated 0).
506
- const verifiedNonZeroExit = outcome.exitCode !== null && outcome.exitCode !== 0;
507
- const painScore = enrichment.painScore ?? Math.min(100, (verifiedNonZeroExit ? 70 : 0) + (isRisky ? 20 : 0));
508
- const errorHash = enrichment.errorHash ?? createHash('sha256').update(outcome.error ?? String(outcome.exitCode)).digest('hex');
509
- // Cooldown is DEBOUNCE, not event identity (I1): the key deliberately has
510
- // NO toolCallId. Repeated failures of the same failureSource+error within
511
- // the window suppress the diagnostic trigger storm, while each real call
512
- // still earns its own tool_calls evidence row through call-id-sensitive
513
- // identity below.
514
- const cooldownKey = `${path.resolve(event.context.workspaceDir)}:${event.context.sessionId}:${sourceObservation.failureSource}:${errorHash}`;
515
- const last = cooldowns.get(cooldownKey);
516
- const cooldownActive = last !== undefined && Date.now() - last < PAIN_COOLDOWN_WINDOW_MS;
517
- const triage = evaluateTriage({ sourceKind, score: painScore, consecutiveErrors: enrichment.consecutiveErrors, isRisky });
518
- const trigger = evaluateTriggerController({ triageResult: triage, isOwnerManual: false, isCooldownActive: cooldownActive, isValid: true, score: painScore, sessionId: event.context.sessionId });
519
- // Merged semantics (WorkBuddy × CR-01): the three-way classification from
520
- // SPEC-CODEX-PAIN-CLOSURE-001 gates admission ('unknown' results are never
521
- // pain), and WorkBuddy tool names are capitalized (Write/Edit — probe P03)
522
- // while OpenClaw/Codex are lowercase; admission is about the tool FAMILY,
523
- // so compare case-insensitively at this one boundary. tool_calls evidence
524
- // above keeps the raw host name.
525
- const admitted = outcome.outcome === 'failure' && WRITE_TOOLS.has(toolName.toLowerCase()) && trigger.shouldCreateDiagnosticTask;
526
- const { eventId, painId } = ids({
425
+ const { eventId } = ids({
527
426
  workspaceDir: event.context.workspaceDir,
528
427
  sessionId: event.context.sessionId,
529
428
  ...(event.context.turnId !== undefined ? { turnId: event.context.turnId } : {}),
@@ -542,7 +441,6 @@ export function createProductionPainEvidenceHandler(options = {}) {
542
441
  const paramsJson = stable(sanitizedParams);
543
442
  const resultPreview = preview({ eventId, result: sanitizeValue(outcome.result, 0, event.context.workspaceDir) });
544
443
  let duplicate = false;
545
- let duplicateAdmitted = false;
546
444
  try {
547
445
  db.transaction(() => {
548
446
  // CR-01: the host tool-call id is the stable join key for the
@@ -557,7 +455,6 @@ export function createProductionPainEvidenceHandler(options = {}) {
557
455
  ? db.prepare('SELECT 1 FROM tool_calls WHERE session_id = ? AND tool_use_id = ? AND host_kind = ?').get(event.context.sessionId, event.context.toolCallId, options.hostKind)
558
456
  : db.prepare('SELECT 1 FROM tool_calls WHERE session_id = ? AND tool_use_id = ?').get(event.context.sessionId, event.context.toolCallId)) !== undefined) {
559
457
  duplicate = true;
560
- duplicateAdmitted = db.prepare('SELECT 1 FROM pain_events WHERE canonical_pain_id = ?').get(painId) !== undefined;
561
458
  return;
562
459
  }
563
460
  // Review R3/P2: the content-shape fallback dedup is host-scoped the
@@ -566,40 +463,15 @@ export function createProductionPainEvidenceHandler(options = {}) {
566
463
  ? db.prepare('SELECT 1 FROM tool_calls WHERE session_id = ? AND tool_name = ? AND params_json = ? AND outcome = ? AND exit_code IS ? AND error_message IS ? AND result_preview IS ? AND host_kind = ?').get(event.context.sessionId, toolName, paramsJson, outcome.outcome, outcome.exitCode, outcome.error ?? null, resultPreview, options.hostKind)
567
464
  : db.prepare('SELECT 1 FROM tool_calls WHERE session_id = ? AND tool_name = ? AND params_json = ? AND outcome = ? AND exit_code IS ? AND error_message IS ? AND result_preview IS ?').get(event.context.sessionId, toolName, paramsJson, outcome.outcome, outcome.exitCode, outcome.error ?? null, resultPreview)) !== undefined) {
568
465
  duplicate = true;
569
- duplicateAdmitted = db.prepare('SELECT 1 FROM pain_events WHERE canonical_pain_id = ?').get(painId) !== undefined;
570
466
  return;
571
467
  }
572
468
  db.prepare(`INSERT INTO sessions (session_id, started_at, updated_at) VALUES (?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET updated_at = excluded.updated_at`).run(event.context.sessionId, createdAt, createdAt);
573
469
  db.prepare(`INSERT INTO tool_calls (session_id, tool_name, outcome, duration_ms, exit_code, error_type, error_message, gfi_before, gfi_after, params_json, result_preview, created_at, tool_use_id, project_dir, host_kind) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
574
470
  .run(event.context.sessionId, toolName, outcome.outcome, outcome.durationMs ?? null, outcome.exitCode, outcome.error ? outcome.error.split(/[\s:]/, 1)[0] : null, outcome.error ?? null, null, null, paramsJson, resultPreview, createdAt, event.context.toolCallId ?? null, path.resolve(options.projectDir ?? event.context.workspaceDir), options.hostKind ?? null);
575
- if (admitted) {
576
- // Raw observation only (Pain Diagnosis Persistence SPEC §8): the
577
- // pain row must record WHAT happened, not WHY. Attribution
578
- // (People/Design/Assumption/Tooling) belongs to the Diagnostician.
579
- // confidence stays null — no attribution confidence exists at
580
- // detection time. origin remains 'system_infer' because origin is a
581
- // declared enum (event-types.ts: who reported the pain), not an
582
- // attribution claim.
583
- const reason = `tool=${toolName}; error=${outcome.error ?? `exit=${outcome.exitCode}`}; path=${relativePath}`;
584
- db.prepare(`INSERT INTO pain_events (session_id, source, score, reason, severity, origin, confidence, text, canonical_pain_id, runtime_task_id, host_kind, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
585
- .run(event.context.sessionId, sourceObservation.failureSource ?? 'tool_failure', painScore, reason, painScore >= 70 ? 'severe' : painScore >= 40 ? 'moderate' : 'mild', 'system_infer', null, enrichment.evidence?.map((entry) => `${entry.sourceRef}: ${entry.note}`).join('\n') ?? null, painId, null, options.hostKind ?? null, createdAt);
586
- }
587
471
  })();
588
- if (admitted && !duplicate) {
589
- const admittedAt = Date.now();
590
- // Bound the module-level cooldown map in long-lived host processes
591
- // (OpenClaw): keys carry sessionId + errorHash, so unbounded retention
592
- // grows monotonically. Evict entries outside the cooldown window —
593
- // they can never be consulted again.
594
- for (const [staleKey, staleAt] of cooldowns) {
595
- if (admittedAt - staleAt >= PAIN_COOLDOWN_WINDOW_MS)
596
- cooldowns.delete(staleKey);
597
- }
598
- cooldowns.set(cooldownKey, admittedAt);
599
- }
600
472
  }
601
473
  catch (error) {
602
- return { decision: 'observe', source: event.source, warnings: [...(emissionWarning ? [emissionWarning] : []), `trajectory_write_failed:${error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200)}`], metadata: { outcome: outcome.outcome, admitted: false, duplicate: false, nextAction: 'inspect the workspace trajectory database and retry' } };
474
+ return { decision: 'observe', source: event.source, warnings: [...(emissionWarning ? [emissionWarning] : []), `trajectory_write_failed:${error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200)}`], metadata: { outcome: outcome.outcome, duplicate: false, nextAction: 'inspect the workspace trajectory database and retry' } };
603
475
  }
604
476
  finally {
605
477
  try {
@@ -607,24 +479,14 @@ export function createProductionPainEvidenceHandler(options = {}) {
607
479
  }
608
480
  catch { /* write result already determined; cleanup is best-effort */ }
609
481
  }
610
- const effectiveAdmitted = admitted || duplicateAdmitted;
611
482
  return {
612
483
  decision: 'observe',
613
484
  source: event.source,
614
485
  ...(emissionWarning ? { warnings: [emissionWarning] } : {}),
615
486
  metadata: {
616
- eventId, painId: effectiveAdmitted ? painId : null, outcome: outcome.outcome, ...(outcome.unknownReason !== undefined ? { outcomeReason: outcome.unknownReason } : {}), exitCode: outcome.exitCode, admitted: effectiveAdmitted, duplicate,
617
- sourceKind, failureSource: sourceObservation.failureSource ?? null, triggerOutcome: trigger.outcome,
618
- triggerReason: trigger.reason, painScore, isRisky, relativePath, agentId: enrichment.agentId ?? null,
619
- evidence: enrichment.evidence ?? [],
487
+ eventId, outcome: outcome.outcome, ...(outcome.unknownReason !== undefined ? { outcomeReason: outcome.unknownReason } : {}), exitCode: outcome.exitCode, duplicate,
620
488
  }
621
489
  };
622
490
  };
623
491
  }
624
- export function resetProductionPainCooldownForTest() {
625
- cooldowns.clear();
626
- }
627
- export function productionPainCooldownEntryCountForTest() {
628
- return cooldowns.size;
629
- }
630
492
  export { hasCanonicalSchema as hasProductionPainSchema };
@@ -107,6 +107,7 @@ const BUDGET_CAPACITY_SOURCES = new Set([
107
107
  'operator_declared',
108
108
  'host_effective_window',
109
109
  'pi_catalog_exact',
110
+ 'pi_catalog_model_id',
110
111
  'legacy_fallback',
111
112
  ]);
112
113
  const BUDGET_CAPACITY_STATUSES = new Set(['confirmed', 'unknown']);
@@ -181,8 +182,9 @@ function narrowObservation(parsed, workspaceDir, nowMs) {
181
182
  // PRI-1020: operator_declared joins the confirmed set — a declared window
182
183
  // is a real window (the Owner's explicit cap), so its observations carry
183
184
  // the window and the exact formula budget like the other confirmed
184
- // sources.
185
- if (rawSource !== 'operator_declared' && rawSource !== 'host_effective_window' && rawSource !== 'pi_catalog_exact')
185
+ // sources. v0.3: pi_catalog_model_id is the weaker name-only catalog tier
186
+ // (still a real window claim, own source label).
187
+ if (rawSource !== 'operator_declared' && rawSource !== 'host_effective_window' && rawSource !== 'pi_catalog_exact' && rawSource !== 'pi_catalog_model_id')
186
188
  return null;
187
189
  if (!isValidContextWindowTokens(rawWindow))
188
190
  return null;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principles/host-runtime",
3
- "version": "0.15.0",
3
+ "version": "1.0.0",
4
4
  "description": "Shared host-neutral orchestration for Principles Disciple MVP-Core hook paths.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-principles-disciple",
3
- "version": "1.147.0",
3
+ "version": "1.147.2",
4
4
  "description": "Interactive CLI installer for Principles Disciple OpenClaw plugin",
5
5
  "type": "module",
6
6
  "bin": {
@@ -98,7 +98,7 @@
98
98
  "directory": "packages/create-principles-disciple"
99
99
  },
100
100
  "pd": {
101
- "bundledPluginVersion": "2.4.0"
101
+ "bundledPluginVersion": "2.5.0"
102
102
  },
103
- "gitHead": "d3355465b090daf098581cdb4c174634fe1e5279"
103
+ "gitHead": "94d353a428b6fc27dd41ff63b767bf915b9ed147"
104
104
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principles/pd-cli",
3
- "version": "1.162.8",
3
+ "version": "1.163.1",
4
4
  "description": "PD CLI — Pain recording, sample management, and governance tasks for Principles Disciple",
5
5
  "type": "module",
6
6
  "bin": {
@@ -7,7 +7,7 @@
7
7
  * package.json. A unit test pins it to package.json so the two cannot drift.
8
8
  */
9
9
  export declare const SERVER_NAME: 'pd-mcp-server';
10
- export declare const SERVER_VERSION: '0.2.0';
10
+ export declare const SERVER_VERSION: '0.2.1';
11
11
  /** The only MCP SDK family/version this server is released against
12
12
  * (Gate 4-A freeze, PD_MCP_GATE4A_REALITY_CHECK §3). Exact pin — no ranges. */
13
13
  export declare const MCP_SDK_PIN: '@modelcontextprotocol/server@2.4.0';
@@ -7,7 +7,7 @@
7
7
  * package.json. A unit test pins it to package.json so the two cannot drift.
8
8
  */
9
9
  export const SERVER_NAME = 'pd-mcp-server';
10
- export const SERVER_VERSION = '0.2.0';
10
+ export const SERVER_VERSION = '0.2.1';
11
11
  /** The only MCP SDK family/version this server is released against
12
12
  * (Gate 4-A freeze, PD_MCP_GATE4A_REALITY_CHECK §3). Exact pin — no ranges. */
13
13
  export const MCP_SDK_PIN = '@modelcontextprotocol/server@2.4.0';
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principles/pd-mcp-server",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Principles Disciple MCP Server — the single shared MCP server implementation for the three PD hosts (Codex, OpenClaw, WorkBuddy). Read-only pain recall through the Gate 3 Capability (SPEC-PD-MCP-GATE4-001).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",