create-principles-disciple 1.126.2 → 1.127.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.
- package/core/dist/runtime-v2/__tests__/pain-ingress-persistence.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/pain-ingress-persistence.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-ingress-persistence.test.js +276 -0
- package/core/dist/runtime-v2/__tests__/pain-ingress-persistence.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-ingress-shared-semantics.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/pain-ingress-shared-semantics.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-ingress-shared-semantics.test.js +131 -0
- package/core/dist/runtime-v2/__tests__/pain-ingress-shared-semantics.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-outcome-convergence.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/pain-outcome-convergence.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-outcome-convergence.test.js +126 -0
- package/core/dist/runtime-v2/__tests__/pain-outcome-convergence.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-bridge-execute-pending.test.js +95 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-bridge-execute-pending.test.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +9 -1
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +6 -0
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/pain-ingress-payload.d.ts +207 -0
- package/core/dist/runtime-v2/pain-ingress-payload.d.ts.map +1 -0
- package/core/dist/runtime-v2/pain-ingress-payload.js +340 -0
- package/core/dist/runtime-v2/pain-ingress-payload.js.map +1 -0
- package/core/dist/runtime-v2/pain-ingress.d.ts +61 -0
- package/core/dist/runtime-v2/pain-ingress.d.ts.map +1 -0
- package/core/dist/runtime-v2/pain-ingress.js +163 -0
- package/core/dist/runtime-v2/pain-ingress.js.map +1 -0
- package/core/dist/runtime-v2/pain-signal-bridge.d.ts +39 -1
- package/core/dist/runtime-v2/pain-signal-bridge.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-bridge.js +163 -8
- package/core/dist/runtime-v2/pain-signal-bridge.js.map +1 -1
- package/core/dist/runtime-v2/pain-to-principle-service.d.ts +8 -1
- package/core/dist/runtime-v2/pain-to-principle-service.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-to-principle-service.js +3 -0
- package/core/dist/runtime-v2/pain-to-principle-service.js.map +1 -1
- package/host-runtime/dist/index.d.ts +1 -0
- package/host-runtime/dist/index.js +3 -0
- package/host-runtime/dist/pain-evidence-ingress.d.ts +16 -0
- package/host-runtime/dist/pain-evidence-ingress.js +15 -0
- package/package.json +2 -2
- package/pd-cli/dist/commands/build-trajectory-evidence.d.ts +25 -6
- package/pd-cli/dist/commands/build-trajectory-evidence.d.ts.map +1 -1
- package/pd-cli/dist/commands/build-trajectory-evidence.js +174 -114
- package/pd-cli/dist/commands/build-trajectory-evidence.js.map +1 -1
- package/pd-cli/dist/commands/pain-record.d.ts.map +1 -1
- package/pd-cli/dist/commands/pain-record.js +212 -17
- package/pd-cli/dist/commands/pain-record.js.map +1 -1
- package/pd-cli/dist/index.js +1 -1
- package/pd-cli/dist/index.js.map +1 -1
- package/plugin/dist/bundle.js +456 -454
- package/plugin/dist/governance-audit.js +152 -152
- package/plugin/dist/hooks/pain-ingress-adapter.d.ts +19 -0
- package/plugin/dist/hooks/trajectory-evidence.d.ts +32 -1
- package/plugin/dist/rulehost-evidence.js +155 -155
- package/plugin/dist/templates/langs/en/skills/pd-cli-operator/SKILL.md +11 -4
- package/plugin/dist/templates/langs/en/skills/pd-pain-signal/SKILL.md +36 -4
- package/plugin/dist/templates/langs/en/skills/pd-runtime-v2/SKILL.md +4 -1
- package/plugin/dist/templates/langs/zh/skills/pd-cli-operator/SKILL.md +9 -4
- package/plugin/dist/templates/langs/zh/skills/pd-pain-signal/SKILL.md +32 -4
- package/plugin/dist/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +3 -1
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +1 -1
- package/plugin/templates/langs/en/skills/pd-cli-operator/SKILL.md +11 -4
- package/plugin/templates/langs/en/skills/pd-pain-signal/SKILL.md +36 -4
- package/plugin/templates/langs/en/skills/pd-runtime-v2/SKILL.md +4 -1
- package/plugin/templates/langs/zh/skills/pd-cli-operator/SKILL.md +9 -4
- package/plugin/templates/langs/zh/skills/pd-pain-signal/SKILL.md +32 -4
- package/plugin/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pain-ingress-persistence.test.d.ts","sourceRoot":"","sources":["../../../src/runtime-v2/__tests__/pain-ingress-persistence.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRI-642 SPEC §9/§13 — painIngress.v1 dual-write SQLite round trip.
|
|
3
|
+
*
|
|
4
|
+
* submitPainSignal must persist BOTH the versioned `painIngress` namespace
|
|
5
|
+
* and the legacy top-level fields from one builder, consistently, in the
|
|
6
|
+
* real state store; re-entry validation must accept the round-tripped
|
|
7
|
+
* payload and reject a tampered nested/top-level contradiction.
|
|
8
|
+
*/
|
|
9
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
10
|
+
import * as fs from 'node:fs';
|
|
11
|
+
import * as os from 'node:os';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import { PainSignalBridge } from '../pain-signal-bridge.js';
|
|
14
|
+
import { RuntimeStateManager } from '../store/runtime-state-manager.js';
|
|
15
|
+
import { checkIngressTopLevelConsistency, parsePainIngressV1Payload } from '../pain-ingress-payload.js';
|
|
16
|
+
let tmpDir;
|
|
17
|
+
let stateManager;
|
|
18
|
+
function makeBridge() {
|
|
19
|
+
const runner = { run: async () => ({ status: 'succeeded', taskId: 't', attemptCount: 1 }) };
|
|
20
|
+
return new PainSignalBridge({
|
|
21
|
+
stateManager,
|
|
22
|
+
runner,
|
|
23
|
+
intakeService: {},
|
|
24
|
+
ledgerAdapter: { register: () => undefined, existsForCandidate: () => undefined, getEntries: () => [] },
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const BOUND_INGRESS = {
|
|
28
|
+
version: 'v1',
|
|
29
|
+
origin: { kind: 'owner_manual', channel: 'openclaw_command' },
|
|
30
|
+
correlation: { status: 'bound', hostKind: 'openclaw', sessionId: 'sess-rt-1' },
|
|
31
|
+
evidenceClass: { status: 'available', entryCount: 2 },
|
|
32
|
+
};
|
|
33
|
+
describe('painIngress.v1 dual-write round trip (PRI-642 §9, §13)', () => {
|
|
34
|
+
beforeEach(async () => {
|
|
35
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pd-ingress-rt-'));
|
|
36
|
+
stateManager = new RuntimeStateManager({ workspaceDir: tmpDir });
|
|
37
|
+
await stateManager.initialize();
|
|
38
|
+
});
|
|
39
|
+
afterEach(async () => {
|
|
40
|
+
await stateManager.close();
|
|
41
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
42
|
+
});
|
|
43
|
+
it('persists the nested namespace beside the legacy top-level fields, consistently', async () => {
|
|
44
|
+
const bridge = makeBridge();
|
|
45
|
+
const { taskId } = await bridge.submitPainSignal({
|
|
46
|
+
painId: 'manual_rt_1',
|
|
47
|
+
painType: 'user_frustration',
|
|
48
|
+
source: 'manual',
|
|
49
|
+
reason: 'round trip',
|
|
50
|
+
score: 70,
|
|
51
|
+
sessionId: 'sess-rt-1',
|
|
52
|
+
provenance: 'host_context_bound',
|
|
53
|
+
hostKind: 'openclaw',
|
|
54
|
+
evidence: [
|
|
55
|
+
{ sourceRef: 'owner_message:t1', note: 'fix it' },
|
|
56
|
+
{ sourceRef: 'tool_call_failure:t2', note: 'Tool bash failed' },
|
|
57
|
+
],
|
|
58
|
+
painIngress: BOUND_INGRESS,
|
|
59
|
+
});
|
|
60
|
+
const task = await stateManager.getTask(taskId);
|
|
61
|
+
expect(task).not.toBeNull();
|
|
62
|
+
if (task === null)
|
|
63
|
+
throw new Error('task missing after submit');
|
|
64
|
+
const parsed = JSON.parse(task.diagnosticJson);
|
|
65
|
+
// Legacy top-level fields all present.
|
|
66
|
+
expect(parsed.sourcePainId).toBe('manual_rt_1');
|
|
67
|
+
expect(parsed.provenance).toBe('host_context_bound');
|
|
68
|
+
expect(parsed.sessionIdHint).toBe('sess-rt-1');
|
|
69
|
+
expect(parsed.evidence.length).toBe(2);
|
|
70
|
+
expect(parsed.hostKind).toBe('openclaw');
|
|
71
|
+
// Nested namespace present, parseable, consistent with top-level.
|
|
72
|
+
const ingress = parsePainIngressV1Payload(parsed.painIngress);
|
|
73
|
+
expect(ingress.ok).toBe(true);
|
|
74
|
+
if (!ingress.ok)
|
|
75
|
+
return;
|
|
76
|
+
const mismatch = checkIngressTopLevelConsistency({
|
|
77
|
+
payload: ingress.payload,
|
|
78
|
+
topLevelProvenance: parsed.provenance,
|
|
79
|
+
topLevelSessionIdHint: parsed.sessionIdHint,
|
|
80
|
+
topLevelEvidenceCount: parsed.evidence.length,
|
|
81
|
+
});
|
|
82
|
+
expect(mismatch).toBeNull();
|
|
83
|
+
// Re-entry accepts the round-tripped payload.
|
|
84
|
+
const executed = await bridge.executePendingDiagnosis({ taskId });
|
|
85
|
+
expect(executed.message).not.toContain('diagnostic_payload_invalid');
|
|
86
|
+
expect(executed.message).not.toContain('ingress_payload_mismatch');
|
|
87
|
+
});
|
|
88
|
+
it('a submission without ingress facts keeps the legacy-only payload (compatibility window)', async () => {
|
|
89
|
+
const bridge = makeBridge();
|
|
90
|
+
const { taskId } = await bridge.submitPainSignal({
|
|
91
|
+
painId: 'manual_rt_2',
|
|
92
|
+
painType: 'user_frustration',
|
|
93
|
+
source: 'manual',
|
|
94
|
+
reason: 'legacy shape',
|
|
95
|
+
provenance: 'owner_reported_no_host_trace',
|
|
96
|
+
evidence: [],
|
|
97
|
+
});
|
|
98
|
+
const task = await stateManager.getTask(taskId);
|
|
99
|
+
if (task === null)
|
|
100
|
+
throw new Error('task missing after submit');
|
|
101
|
+
const parsed = JSON.parse(task.diagnosticJson);
|
|
102
|
+
expect(Object.hasOwn(parsed, 'painIngress')).toBe(false);
|
|
103
|
+
expect(parsed.provenance).toBe('owner_reported_no_host_trace');
|
|
104
|
+
});
|
|
105
|
+
it('re-entry rejects a payload whose nested facts were tampered after the write', async () => {
|
|
106
|
+
const bridge = makeBridge();
|
|
107
|
+
const { taskId } = await bridge.submitPainSignal({
|
|
108
|
+
painId: 'manual_rt_3',
|
|
109
|
+
painType: 'user_frustration',
|
|
110
|
+
source: 'manual',
|
|
111
|
+
reason: 'tamper target',
|
|
112
|
+
sessionId: 'sess-rt-1',
|
|
113
|
+
provenance: 'host_context_bound',
|
|
114
|
+
hostKind: 'openclaw',
|
|
115
|
+
evidence: [{ sourceRef: 'owner_message:t1', note: 'fix it' }],
|
|
116
|
+
painIngress: {
|
|
117
|
+
version: 'v1',
|
|
118
|
+
origin: { kind: 'owner_manual', channel: 'openclaw_command' },
|
|
119
|
+
correlation: { status: 'bound', hostKind: 'openclaw', sessionId: 'sess-rt-1' },
|
|
120
|
+
evidenceClass: { status: 'available', entryCount: 1 },
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
// Corrupt the persisted nested evidence count (simulates drift between
|
|
124
|
+
// the two namespaces).
|
|
125
|
+
const task = await stateManager.getTask(taskId);
|
|
126
|
+
if (task === null)
|
|
127
|
+
throw new Error('task missing after submit');
|
|
128
|
+
const payload = JSON.parse(task.diagnosticJson);
|
|
129
|
+
const nested = payload.painIngress;
|
|
130
|
+
const cls = nested.evidenceClass;
|
|
131
|
+
cls.entryCount = 9;
|
|
132
|
+
await stateManager.updateTask(taskId, { diagnosticJson: JSON.stringify(payload) });
|
|
133
|
+
const executed = await bridge.executePendingDiagnosis({ taskId });
|
|
134
|
+
expect(executed.status).toBe('failed');
|
|
135
|
+
expect(executed.message).toContain('ingress_payload_mismatch');
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
// ── Review blocker 2: re-entry validation must equal write-time validation ──
|
|
139
|
+
describe('painIngress.v1 re-entry invariant parity (review blocker 2)', () => {
|
|
140
|
+
const baseV1 = {
|
|
141
|
+
version: 'v1',
|
|
142
|
+
origin: { kind: 'owner_manual', channel: 'openclaw_command' },
|
|
143
|
+
correlation: { status: 'bound', hostKind: 'openclaw', sessionId: 'sess-real' },
|
|
144
|
+
evidenceClass: { status: 'available', entryCount: 2 },
|
|
145
|
+
};
|
|
146
|
+
it('T1: bound/openclaw/sessionId="cli" → reject (session_sentinel_invalid)', () => {
|
|
147
|
+
const parsed = parsePainIngressV1Payload({
|
|
148
|
+
...baseV1,
|
|
149
|
+
correlation: { status: 'bound', hostKind: 'openclaw', sessionId: 'cli' },
|
|
150
|
+
});
|
|
151
|
+
expect(parsed.ok).toBe(false);
|
|
152
|
+
if (parsed.ok)
|
|
153
|
+
return;
|
|
154
|
+
expect(parsed.reasonCode).toBe('session_sentinel_invalid');
|
|
155
|
+
});
|
|
156
|
+
it('T2: bound/openclaw/sessionId="unknown" → reject (session_sentinel_invalid)', () => {
|
|
157
|
+
const parsed = parsePainIngressV1Payload({
|
|
158
|
+
...baseV1,
|
|
159
|
+
correlation: { status: 'bound', hostKind: 'openclaw', sessionId: 'unknown' },
|
|
160
|
+
});
|
|
161
|
+
expect(parsed.ok).toBe(false);
|
|
162
|
+
if (parsed.ok)
|
|
163
|
+
return;
|
|
164
|
+
expect(parsed.reasonCode).toBe('session_sentinel_invalid');
|
|
165
|
+
});
|
|
166
|
+
it('T3: evidenceClass available with entryCount 0 → reject (write-time requires >= 1)', () => {
|
|
167
|
+
const parsed = parsePainIngressV1Payload({
|
|
168
|
+
...baseV1,
|
|
169
|
+
evidenceClass: { status: 'available', entryCount: 0 },
|
|
170
|
+
});
|
|
171
|
+
expect(parsed.ok).toBe(false);
|
|
172
|
+
if (parsed.ok)
|
|
173
|
+
return;
|
|
174
|
+
expect(parsed.reasonCode).toBe('ingress_evidence_class_invalid');
|
|
175
|
+
});
|
|
176
|
+
it('T4: owner_manual.external_cli_unbound + bound correlation → reject (impossible combination)', () => {
|
|
177
|
+
const parsed = parsePainIngressV1Payload({
|
|
178
|
+
...baseV1,
|
|
179
|
+
origin: { kind: 'owner_manual', channel: 'external_cli_unbound' },
|
|
180
|
+
});
|
|
181
|
+
expect(parsed.ok).toBe(false);
|
|
182
|
+
if (parsed.ok)
|
|
183
|
+
return;
|
|
184
|
+
expect(parsed.reasonCode).toBe('origin_correlation_mismatch');
|
|
185
|
+
});
|
|
186
|
+
it('T5: owner_manual.cli_explicit_session + unbound correlation → reject (impossible combination)', () => {
|
|
187
|
+
const parsed = parsePainIngressV1Payload({
|
|
188
|
+
...baseV1,
|
|
189
|
+
origin: { kind: 'owner_manual', channel: 'cli_explicit_session' },
|
|
190
|
+
correlation: { status: 'unbound', reason: 'external_cli' },
|
|
191
|
+
evidenceClass: { status: 'unavailable', reason: 'not_applicable_unbound' },
|
|
192
|
+
});
|
|
193
|
+
expect(parsed.ok).toBe(false);
|
|
194
|
+
if (parsed.ok)
|
|
195
|
+
return;
|
|
196
|
+
expect(parsed.reasonCode).toBe('origin_correlation_mismatch');
|
|
197
|
+
});
|
|
198
|
+
it('T6: legal bound OpenClaw v1 (real session, available entryCount > 0) → accept', () => {
|
|
199
|
+
const parsed = parsePainIngressV1Payload(baseV1);
|
|
200
|
+
expect(parsed.ok).toBe(true);
|
|
201
|
+
});
|
|
202
|
+
it('T7: legal external CLI unbound v1 (unbound + not_applicable_unbound) → accept', () => {
|
|
203
|
+
const parsed = parsePainIngressV1Payload({
|
|
204
|
+
version: 'v1',
|
|
205
|
+
origin: { kind: 'owner_manual', channel: 'external_cli_unbound' },
|
|
206
|
+
correlation: { status: 'unbound', reason: 'external_cli' },
|
|
207
|
+
evidenceClass: { status: 'unavailable', reason: 'not_applicable_unbound' },
|
|
208
|
+
});
|
|
209
|
+
expect(parsed.ok).toBe(true);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
// ── Review blocker 2 closure: nested/top-level consistency must catch
|
|
213
|
+
// every tampered dimension (not just provenance/session/count). ─────────────
|
|
214
|
+
describe('checkIngressTopLevelConsistency (review blocker 2 closure)', () => {
|
|
215
|
+
it('flags unavailable evidenceClass against a non-zero legacy evidence count', () => {
|
|
216
|
+
const payload = {
|
|
217
|
+
version: 'v1',
|
|
218
|
+
origin: { kind: 'owner_manual', channel: 'openclaw_command' },
|
|
219
|
+
correlation: { status: 'bound', hostKind: 'openclaw', sessionId: 'sess-real' },
|
|
220
|
+
evidenceClass: { status: 'unavailable', reason: 'not_applicable_unbound' },
|
|
221
|
+
};
|
|
222
|
+
const mismatch = checkIngressTopLevelConsistency({
|
|
223
|
+
payload,
|
|
224
|
+
topLevelProvenance: 'host_context_bound',
|
|
225
|
+
topLevelSessionIdHint: 'sess-real',
|
|
226
|
+
topLevelEvidenceCount: 2, // ← forged legacy entries
|
|
227
|
+
});
|
|
228
|
+
expect(mismatch).toBe('ingress_payload_mismatch:unavailable_evidence_count');
|
|
229
|
+
});
|
|
230
|
+
it('flags unbound v1 with a non-empty legacy sessionIdHint', () => {
|
|
231
|
+
const payload = {
|
|
232
|
+
version: 'v1',
|
|
233
|
+
origin: { kind: 'owner_manual', channel: 'external_cli_unbound' },
|
|
234
|
+
correlation: { status: 'unbound', reason: 'external_cli' },
|
|
235
|
+
evidenceClass: { status: 'unavailable', reason: 'not_applicable_unbound' },
|
|
236
|
+
};
|
|
237
|
+
const mismatch = checkIngressTopLevelConsistency({
|
|
238
|
+
payload,
|
|
239
|
+
topLevelProvenance: 'owner_reported_no_host_trace',
|
|
240
|
+
topLevelSessionIdHint: 'sess-forged',
|
|
241
|
+
topLevelEvidenceCount: 0,
|
|
242
|
+
});
|
|
243
|
+
expect(mismatch).toBe('ingress_payload_mismatch:unbound_session_hint');
|
|
244
|
+
});
|
|
245
|
+
it('accepts a consistent bound OpenClaw v1 with matching evidence count', () => {
|
|
246
|
+
const payload = {
|
|
247
|
+
version: 'v1',
|
|
248
|
+
origin: { kind: 'owner_manual', channel: 'openclaw_command' },
|
|
249
|
+
correlation: { status: 'bound', hostKind: 'openclaw', sessionId: 'sess-real' },
|
|
250
|
+
evidenceClass: { status: 'available', entryCount: 2 },
|
|
251
|
+
};
|
|
252
|
+
const mismatch = checkIngressTopLevelConsistency({
|
|
253
|
+
payload,
|
|
254
|
+
topLevelProvenance: 'host_context_bound',
|
|
255
|
+
topLevelSessionIdHint: 'sess-real',
|
|
256
|
+
topLevelEvidenceCount: 2,
|
|
257
|
+
});
|
|
258
|
+
expect(mismatch).toBeNull();
|
|
259
|
+
});
|
|
260
|
+
it('accepts a consistent external unbound v1 with no session hint', () => {
|
|
261
|
+
const payload = {
|
|
262
|
+
version: 'v1',
|
|
263
|
+
origin: { kind: 'owner_manual', channel: 'external_cli_unbound' },
|
|
264
|
+
correlation: { status: 'unbound', reason: 'external_cli' },
|
|
265
|
+
evidenceClass: { status: 'unavailable', reason: 'not_applicable_unbound' },
|
|
266
|
+
};
|
|
267
|
+
const mismatch = checkIngressTopLevelConsistency({
|
|
268
|
+
payload,
|
|
269
|
+
topLevelProvenance: 'owner_reported_no_host_trace',
|
|
270
|
+
topLevelSessionIdHint: null,
|
|
271
|
+
topLevelEvidenceCount: 0,
|
|
272
|
+
});
|
|
273
|
+
expect(mismatch).toBeNull();
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
//# sourceMappingURL=pain-ingress-persistence.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pain-ingress-persistence.test.js","sourceRoot":"","sources":["../../../src/runtime-v2/__tests__/pain-ingress-persistence.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pain-ingress-shared-semantics.test.d.ts","sourceRoot":"","sources":["../../../src/runtime-v2/__tests__/pain-ingress-shared-semantics.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRI-642 review blocker 1 — ONE ingress semantic authority for CLI and
|
|
3
|
+
* OpenClaw.
|
|
4
|
+
*
|
|
5
|
+
* Cases A–E are each evaluated through BOTH adapter entry shapes (the
|
|
6
|
+
* OpenClaw funnel's report construction and the pd-cli report construction)
|
|
7
|
+
* against the SAME evaluatePainIngress function. The point is not that each
|
|
8
|
+
* adapter "looks right" in isolation — it is that both adapters funnel the
|
|
9
|
+
* same facts into the same semantic evaluator and therefore cannot drift.
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect } from 'vitest';
|
|
12
|
+
import { evaluatePainIngress, parsePainIngressReport } from '../pain-ingress.js';
|
|
13
|
+
const SESSION = 'sess-openclaw-1';
|
|
14
|
+
const ENTRIES = [
|
|
15
|
+
{ kind: 'behavior_trace', sourceRef: 'owner_message:t1', note: 'fix it' },
|
|
16
|
+
{ kind: 'behavior_trace', sourceRef: 'tool_call_failure:t2', note: 'Tool write failed' },
|
|
17
|
+
];
|
|
18
|
+
/** The OpenClaw funnel's report construction (pain-ingress-adapter.ts shape). */
|
|
19
|
+
function openclawReport(partial) {
|
|
20
|
+
return {
|
|
21
|
+
identity: { kind: 'manual_pain_id', painId: 'manual_oc_1' },
|
|
22
|
+
painType: 'user_frustration',
|
|
23
|
+
source: 'manual',
|
|
24
|
+
reason: 'over-engineering',
|
|
25
|
+
score: 80,
|
|
26
|
+
origin: { kind: 'owner_manual', channel: 'openclaw_command' },
|
|
27
|
+
correlation: { status: 'bound', hostKind: 'openclaw', sessionId: SESSION },
|
|
28
|
+
evidence: { status: 'available', entries: ENTRIES },
|
|
29
|
+
...partial,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** The pd-cli report construction (pain-record.ts resolveIngressDecision shape). */
|
|
33
|
+
function cliReport(partial) {
|
|
34
|
+
return {
|
|
35
|
+
identity: { kind: 'manual_pain_id', painId: 'manual_cli_1' },
|
|
36
|
+
painType: 'user_frustration',
|
|
37
|
+
source: 'manual',
|
|
38
|
+
reason: 'over-engineering',
|
|
39
|
+
score: 80,
|
|
40
|
+
origin: { kind: 'owner_manual', channel: 'cli_explicit_session' },
|
|
41
|
+
correlation: { status: 'bound', hostKind: 'openclaw', sessionId: SESSION },
|
|
42
|
+
evidence: { status: 'available', entries: ENTRIES },
|
|
43
|
+
...partial,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
describe('Blocking 1 — one semantic authority for both adapters (Cases A–E)', () => {
|
|
47
|
+
it('Case A: owner manual + valid bound OpenClaw session + evidence → submit/host_context_bound/openclaw/bound (both adapters)', () => {
|
|
48
|
+
for (const report of [openclawReport({}), cliReport({})]) {
|
|
49
|
+
const decision = evaluatePainIngress(report);
|
|
50
|
+
expect(decision.action).toBe('submit');
|
|
51
|
+
if (decision.action !== 'submit')
|
|
52
|
+
return;
|
|
53
|
+
expect(decision.legacy.provenance).toBe('host_context_bound');
|
|
54
|
+
expect(decision.legacy.hostKind).toBe('openclaw');
|
|
55
|
+
expect(decision.legacy.sessionId).toBe(SESSION);
|
|
56
|
+
expect(decision.painIngress.correlation.status).toBe('bound');
|
|
57
|
+
expect(decision.painIngress.correlation).toMatchObject({ hostKind: 'openclaw', sessionId: SESSION });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
it('Case B: owner manual + unbound external CLI → owner_reported_no_host_trace, no fake session, no fake evidence (both adapters)', () => {
|
|
61
|
+
const unbound = {
|
|
62
|
+
correlation: { status: 'unbound', reason: 'external_cli' },
|
|
63
|
+
origin: { kind: 'owner_manual', channel: 'external_cli_unbound' },
|
|
64
|
+
evidence: { status: 'unavailable', reason: 'not_applicable_unbound' },
|
|
65
|
+
};
|
|
66
|
+
for (const report of [openclawReport(unbound), cliReport(unbound)]) {
|
|
67
|
+
const decision = evaluatePainIngress(report);
|
|
68
|
+
expect(decision.action).toBe('submit');
|
|
69
|
+
if (decision.action !== 'submit')
|
|
70
|
+
return;
|
|
71
|
+
expect(decision.legacy.provenance).toBe('owner_reported_no_host_trace');
|
|
72
|
+
expect(decision.legacy.sessionId).toBeUndefined();
|
|
73
|
+
expect(decision.legacy.evidence).toEqual([]);
|
|
74
|
+
expect(decision.warnings.join(' ')).toMatch(/context_unbound|--session/);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
it('Case C: automatic hook + bound + evidence → automatic_hook + submit (both adapters)', () => {
|
|
78
|
+
const auto = {
|
|
79
|
+
identity: { kind: 'host_observation', observationId: 'obs-1' },
|
|
80
|
+
origin: { kind: 'automatic_hook', source: 'gate_blocked' },
|
|
81
|
+
painType: 'user_frustration',
|
|
82
|
+
};
|
|
83
|
+
for (const report of [openclawReport(auto), cliReport(auto)]) {
|
|
84
|
+
const decision = evaluatePainIngress(report);
|
|
85
|
+
expect(decision.action).toBe('submit');
|
|
86
|
+
if (decision.action !== 'submit')
|
|
87
|
+
return;
|
|
88
|
+
expect(decision.legacy.provenance).toBe('automatic_hook');
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
it('Case D: automatic hook + no evidence → observation_only (both adapters)', () => {
|
|
92
|
+
const auto = {
|
|
93
|
+
identity: { kind: 'host_observation', observationId: 'obs-2' },
|
|
94
|
+
origin: { kind: 'automatic_hook', source: 'gate_blocked' },
|
|
95
|
+
painType: 'user_frustration',
|
|
96
|
+
evidence: { status: 'unavailable', reason: 'empty_trajectory' },
|
|
97
|
+
};
|
|
98
|
+
for (const report of [openclawReport(auto), cliReport(auto)]) {
|
|
99
|
+
const decision = evaluatePainIngress(report);
|
|
100
|
+
expect(decision.action).toBe('observation_only');
|
|
101
|
+
if (decision.action !== 'observation_only')
|
|
102
|
+
return;
|
|
103
|
+
expect(decision.reasonCode).toBe('empty_trajectory');
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
it('Case E: invalid origin/correlation combination → refuse (both adapters)', () => {
|
|
107
|
+
const invalid = {
|
|
108
|
+
correlation: { status: 'unbound', reason: 'external_cli' },
|
|
109
|
+
origin: { kind: 'owner_manual', channel: 'cli_explicit_session' },
|
|
110
|
+
};
|
|
111
|
+
for (const report of [openclawReport(invalid), cliReport(invalid)]) {
|
|
112
|
+
const decision = evaluatePainIngress(report);
|
|
113
|
+
expect(decision.action).toBe('refuse');
|
|
114
|
+
if (decision.action !== 'refuse')
|
|
115
|
+
return;
|
|
116
|
+
expect(decision.reasonCode).toBe('origin_correlation_mismatch');
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
it('parsePainIngressReport shares the same invariant surface for both adapters', () => {
|
|
120
|
+
// Both adapters can round-trip their report through the shared parser
|
|
121
|
+
// and get identical semantics — one parse, one invariant, one decision.
|
|
122
|
+
const parsed = parsePainIngressReport(cliReport({}));
|
|
123
|
+
expect(parsed.ok).toBe(true);
|
|
124
|
+
if (!parsed.ok)
|
|
125
|
+
return;
|
|
126
|
+
const decision = evaluatePainIngress(parsed.report);
|
|
127
|
+
expect(decision.action).toBe('submit');
|
|
128
|
+
expect(ENTRIES.length).toBe(2);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=pain-ingress-shared-semantics.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pain-ingress-shared-semantics.test.js","sourceRoot":"","sources":["../../../src/runtime-v2/__tests__/pain-ingress-shared-semantics.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pain-outcome-convergence.test.d.ts","sourceRoot":"","sources":["../../../src/runtime-v2/__tests__/pain-outcome-convergence.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRI-642 SPEC §10/§12.2.5 — mixed candidate decisions stay individually
|
|
3
|
+
* observable, and furthestStage never implies all-success.
|
|
4
|
+
*
|
|
5
|
+
* Exercises PainSignalBridge.onDiagnosisComplete with an in-memory state
|
|
6
|
+
* manager (the SQLite dual-write contract is covered separately in
|
|
7
|
+
* pain-ingress-persistence.test.ts).
|
|
8
|
+
*/
|
|
9
|
+
import { describe, it, expect } from 'vitest';
|
|
10
|
+
import { PainSignalBridge } from '../pain-signal-bridge.js';
|
|
11
|
+
const TASK_ID = 'diagnosis_pain-mixed';
|
|
12
|
+
const OUTPUT = {
|
|
13
|
+
diagnosisId: 'diag-1',
|
|
14
|
+
painType: 'user_frustration',
|
|
15
|
+
rootCause: 'Tooling: over-engineering',
|
|
16
|
+
evidence: [
|
|
17
|
+
{ sourceRef: 'owner_message:t1', note: 'fix it', relevance: 0.9 },
|
|
18
|
+
{ sourceRef: 'tool_call_failure:t2', note: 'Tool write failed', relevance: 0.8 },
|
|
19
|
+
],
|
|
20
|
+
confidence: 0.7,
|
|
21
|
+
};
|
|
22
|
+
function candidateRecord(candidateId, confidence, recommendationKind = 'prompt') {
|
|
23
|
+
return {
|
|
24
|
+
candidateId,
|
|
25
|
+
artifactId: 'art-1',
|
|
26
|
+
taskId: TASK_ID,
|
|
27
|
+
sourceRunId: 'run-1',
|
|
28
|
+
title: `candidate ${candidateId}`,
|
|
29
|
+
description: 'desc',
|
|
30
|
+
confidence,
|
|
31
|
+
status: 'pending',
|
|
32
|
+
createdAt: '2026-09-02T00:00:00.000Z',
|
|
33
|
+
sourceRecommendationJson: '{}',
|
|
34
|
+
recommendationKind,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function makeBridge() {
|
|
38
|
+
// Mixed by recommendation kind: the gate evaluates the diagnostician
|
|
39
|
+
// OUTPUT (one confidence for all candidates), so a genuine mixed outcome
|
|
40
|
+
// comes from a defer-kind candidate alongside an admitted prompt-kind one.
|
|
41
|
+
const candidates = [candidateRecord('cand-strong', 0.7), candidateRecord('cand-weak', 0.3, 'defer')];
|
|
42
|
+
const createdTasks = [];
|
|
43
|
+
const stateManager = {
|
|
44
|
+
getCandidatesByTaskId: async () => candidates,
|
|
45
|
+
getRunsByTask: async () => [],
|
|
46
|
+
getTask: async () => null,
|
|
47
|
+
createTask: async (t) => { createdTasks.push(t); },
|
|
48
|
+
updateCandidateStatus: async () => true,
|
|
49
|
+
};
|
|
50
|
+
const runner = {
|
|
51
|
+
run: async () => ({ status: 'succeeded', taskId: TASK_ID, attemptCount: 1 }),
|
|
52
|
+
};
|
|
53
|
+
const bridge = new PainSignalBridge({
|
|
54
|
+
stateManager,
|
|
55
|
+
runner,
|
|
56
|
+
intakeService: {
|
|
57
|
+
intake: async (candidateId) => ({ id: `ledger-${candidateId}` }),
|
|
58
|
+
},
|
|
59
|
+
ledgerAdapter: {
|
|
60
|
+
register: () => undefined,
|
|
61
|
+
existsForCandidate: () => undefined,
|
|
62
|
+
getEntries: () => [],
|
|
63
|
+
},
|
|
64
|
+
autoIntakeEnabled: true,
|
|
65
|
+
});
|
|
66
|
+
return { bridge, createdTasks };
|
|
67
|
+
}
|
|
68
|
+
describe('PainSignalBridge outcome convergence (PRI-642 §10)', () => {
|
|
69
|
+
it('reports each candidate decision separately with ledger/seed linkage', async () => {
|
|
70
|
+
const { bridge } = makeBridge();
|
|
71
|
+
const result = await bridge.onDiagnosisComplete({
|
|
72
|
+
taskId: TASK_ID,
|
|
73
|
+
diagnosticianOutput: OUTPUT,
|
|
74
|
+
painId: 'pain-mixed',
|
|
75
|
+
provenance: 'host_context_bound',
|
|
76
|
+
inputEvidenceCount: 2,
|
|
77
|
+
});
|
|
78
|
+
// Mixed outcome → degraded, never a clean success.
|
|
79
|
+
expect(result.status).toBe('degraded');
|
|
80
|
+
expect(result.candidateOutcomes).toBeDefined();
|
|
81
|
+
const byId = new Map((result.candidateOutcomes ?? []).map(o => [o.candidateId, o]));
|
|
82
|
+
const strong = byId.get('cand-strong');
|
|
83
|
+
const weak = byId.get('cand-weak');
|
|
84
|
+
expect(strong?.decision).toBe('admitted');
|
|
85
|
+
expect(strong?.ledgerEntryId).toBe('ledger-cand-strong');
|
|
86
|
+
expect(strong?.seededTaskId).toBeTruthy();
|
|
87
|
+
expect(weak?.decision).toBe('deferred');
|
|
88
|
+
expect(weak?.reason).toContain('defer');
|
|
89
|
+
expect(weak?.nextAction).toBeTruthy();
|
|
90
|
+
expect(weak?.ledgerEntryId).toBeUndefined();
|
|
91
|
+
// Progress reflects the aggregate with at-least-one semantics: one
|
|
92
|
+
// candidate seeded ⇒ internalization_seeded even though the other gated.
|
|
93
|
+
if (result.progress === undefined)
|
|
94
|
+
throw new Error('progress missing on mixed outcome');
|
|
95
|
+
expect(result.progress.admittedCandidateIds).toEqual(['cand-strong']);
|
|
96
|
+
expect(result.progress.generatedCandidateIds).toEqual(['cand-strong', 'cand-weak']);
|
|
97
|
+
expect(result.progress.ledgerEntryIds).toEqual(['ledger-cand-strong']);
|
|
98
|
+
expect(result.progress.furthestStage).toBe('internalization_seeded');
|
|
99
|
+
// Compatibility fields stay derived and intact.
|
|
100
|
+
expect(result.candidateIds).toEqual(['cand-strong', 'cand-weak']);
|
|
101
|
+
expect(result.ledgerEntryIds).toEqual(['ledger-cand-strong']);
|
|
102
|
+
expect(result.admissionResults?.length).toBe(2);
|
|
103
|
+
});
|
|
104
|
+
it('all-gated outcome reports diagnosis_completed without any ledger/seed progress', async () => {
|
|
105
|
+
const { bridge } = makeBridge();
|
|
106
|
+
const result = await bridge.onDiagnosisComplete({
|
|
107
|
+
taskId: TASK_ID,
|
|
108
|
+
// Both candidates defer → all gated, no ledger, no seed.
|
|
109
|
+
diagnosticianOutput: { ...OUTPUT, confidence: 0.3 },
|
|
110
|
+
painId: 'pain-gated',
|
|
111
|
+
provenance: 'host_context_bound',
|
|
112
|
+
inputEvidenceCount: 0,
|
|
113
|
+
});
|
|
114
|
+
expect(result.status).toBe('degraded');
|
|
115
|
+
if (result.progress === undefined)
|
|
116
|
+
throw new Error('progress missing on gated outcome');
|
|
117
|
+
expect(result.progress.furthestStage).toBe('diagnosis_completed');
|
|
118
|
+
expect(result.progress.admittedCandidateIds).toEqual([]);
|
|
119
|
+
expect(result.progress.seededTaskIds).toEqual([]);
|
|
120
|
+
for (const outcome of result.candidateOutcomes ?? []) {
|
|
121
|
+
expect(outcome.decision).not.toBe('admitted');
|
|
122
|
+
expect(outcome.ledgerEntryId).toBeUndefined();
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=pain-outcome-convergence.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pain-outcome-convergence.test.js","sourceRoot":"","sources":["../../../src/runtime-v2/__tests__/pain-outcome-convergence.test.ts"],"names":[],"mappings":"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"}
|