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.
- package/_release/product-identity.json +1 -1
- package/codex-adapter/dist/ingestion/admission.d.ts +5 -10
- package/codex-adapter/dist/ingestion/admission.js +19 -77
- package/codex-adapter/dist/ingestion/explicit-owner-statement.js +1 -1
- package/codex-adapter/dist/ingestion/ingestion.d.ts +0 -2
- package/codex-adapter/dist/ingestion/ingestion.js +6 -4
- package/codex-adapter/dist/pd-hook.js +5 -7
- package/codex-adapter/package.json +1 -1
- package/console/dist/shared/prompt-injection-contract.d.ts +1 -1
- package/console/dist/web/assets/app.js +31 -31
- package/core/dist/prompt-builder/size-guard.d.ts.map +1 -1
- package/core/dist/prompt-builder/size-guard.js +6 -1
- package/core/dist/prompt-builder/size-guard.js.map +1 -1
- package/core/dist/prompt-builder/types.d.ts +2 -1
- package/core/dist/prompt-builder/types.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.d.ts +12 -1
- package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.js +12 -1
- package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.js.map +1 -1
- package/core/dist/runtime-v2/activation/prompt-budget-policy.d.ts +42 -11
- package/core/dist/runtime-v2/activation/prompt-budget-policy.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/prompt-budget-policy.js +82 -30
- package/core/dist/runtime-v2/activation/prompt-budget-policy.js.map +1 -1
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.js +17 -5
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/index.d.ts +0 -1
- package/core/dist/runtime-v2/evidence-triage/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/index.js +0 -2
- package/core/dist/runtime-v2/evidence-triage/index.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/source-descriptors.d.ts +3 -8
- package/core/dist/runtime-v2/evidence-triage/source-descriptors.d.ts.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/source-descriptors.js +5 -17
- package/core/dist/runtime-v2/evidence-triage/source-descriptors.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/triage-policy.d.ts +11 -9
- package/core/dist/runtime-v2/evidence-triage/triage-policy.d.ts.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/triage-policy.js +10 -103
- package/core/dist/runtime-v2/evidence-triage/triage-policy.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/trigger-controller.js +1 -1
- package/core/dist/runtime-v2/evidence-triage/trigger-controller.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/types.d.ts +4 -16
- package/core/dist/runtime-v2/evidence-triage/types.d.ts.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/types.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +1 -1
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +1 -1
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/intent/intent-friction-block.d.ts +2 -2
- package/core/dist/runtime-v2/intent/intent-friction-block.js +2 -2
- package/core/dist/runtime-v2/types/event-types.d.ts +2 -2
- package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-types.js +1 -0
- package/core/dist/runtime-v2/types/event-types.js.map +1 -1
- package/core/package.json +1 -1
- package/host-runtime/dist/governance-signal-admission.d.ts +1 -77
- package/host-runtime/dist/governance-signal-admission.js +34 -294
- package/host-runtime/dist/production-pain-evidence.d.ts +8 -69
- package/host-runtime/dist/production-pain-evidence.js +19 -157
- package/host-runtime/dist/prompt-injection-budget-observation.js +4 -2
- package/host-runtime/package.json +1 -1
- package/package.json +3 -3
- package/pd-cli/package.json +1 -1
- package/pd-mcp-server/dist/version.d.ts +1 -1
- package/pd-mcp-server/dist/version.js +1 -1
- package/pd-mcp-server/package.json +1 -1
- package/plugin/dist/bundle.js +411 -412
- package/plugin/dist/governance-audit.js +2 -2
- package/plugin/dist/hooks/after-tool-call-helpers.d.ts +2 -35
- package/plugin/dist/hooks/after-tool-call-types.d.ts +1 -30
- package/plugin/dist/hooks/pain.d.ts +6 -19
- package/plugin/dist/hooks/trajectory-evidence.d.ts +3 -10
- package/plugin/dist/hooks/triage-adapter.d.ts +7 -20
- package/plugin/dist/host-runtime/openclaw-host-runtime.d.ts +0 -1
- package/plugin/dist/openclaw.plugin.json +1 -1
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +1 -1
- package/release-manager/package.json +1 -1
- package/workbuddy-adapter/dist/codec/input-decoder.js +3 -1
- package/workbuddy-adapter/dist/pd-hook.js +0 -26
- package/workbuddy-adapter/dist/worker/workspace-worker.d.ts +1 -7
- package/workbuddy-adapter/dist/worker/workspace-worker.js +11 -21
- 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,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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}
|
|
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',
|
|
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',
|
|
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',
|
|
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',
|
|
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
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-principles-disciple",
|
|
3
|
-
"version": "1.147.
|
|
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.
|
|
101
|
+
"bundledPluginVersion": "2.5.0"
|
|
102
102
|
},
|
|
103
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "94d353a428b6fc27dd41ff63b767bf915b9ed147"
|
|
104
104
|
}
|
package/pd-cli/package.json
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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",
|