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.
Files changed (67) hide show
  1. package/core/dist/runtime-v2/__tests__/pain-ingress-persistence.test.d.ts +2 -0
  2. package/core/dist/runtime-v2/__tests__/pain-ingress-persistence.test.d.ts.map +1 -0
  3. package/core/dist/runtime-v2/__tests__/pain-ingress-persistence.test.js +276 -0
  4. package/core/dist/runtime-v2/__tests__/pain-ingress-persistence.test.js.map +1 -0
  5. package/core/dist/runtime-v2/__tests__/pain-ingress-shared-semantics.test.d.ts +2 -0
  6. package/core/dist/runtime-v2/__tests__/pain-ingress-shared-semantics.test.d.ts.map +1 -0
  7. package/core/dist/runtime-v2/__tests__/pain-ingress-shared-semantics.test.js +131 -0
  8. package/core/dist/runtime-v2/__tests__/pain-ingress-shared-semantics.test.js.map +1 -0
  9. package/core/dist/runtime-v2/__tests__/pain-outcome-convergence.test.d.ts +2 -0
  10. package/core/dist/runtime-v2/__tests__/pain-outcome-convergence.test.d.ts.map +1 -0
  11. package/core/dist/runtime-v2/__tests__/pain-outcome-convergence.test.js +126 -0
  12. package/core/dist/runtime-v2/__tests__/pain-outcome-convergence.test.js.map +1 -0
  13. package/core/dist/runtime-v2/__tests__/pain-signal-bridge-execute-pending.test.js +95 -0
  14. package/core/dist/runtime-v2/__tests__/pain-signal-bridge-execute-pending.test.js.map +1 -1
  15. package/core/dist/runtime-v2/index.d.ts +9 -1
  16. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  17. package/core/dist/runtime-v2/index.js +6 -0
  18. package/core/dist/runtime-v2/index.js.map +1 -1
  19. package/core/dist/runtime-v2/pain-ingress-payload.d.ts +207 -0
  20. package/core/dist/runtime-v2/pain-ingress-payload.d.ts.map +1 -0
  21. package/core/dist/runtime-v2/pain-ingress-payload.js +340 -0
  22. package/core/dist/runtime-v2/pain-ingress-payload.js.map +1 -0
  23. package/core/dist/runtime-v2/pain-ingress.d.ts +61 -0
  24. package/core/dist/runtime-v2/pain-ingress.d.ts.map +1 -0
  25. package/core/dist/runtime-v2/pain-ingress.js +163 -0
  26. package/core/dist/runtime-v2/pain-ingress.js.map +1 -0
  27. package/core/dist/runtime-v2/pain-signal-bridge.d.ts +39 -1
  28. package/core/dist/runtime-v2/pain-signal-bridge.d.ts.map +1 -1
  29. package/core/dist/runtime-v2/pain-signal-bridge.js +163 -8
  30. package/core/dist/runtime-v2/pain-signal-bridge.js.map +1 -1
  31. package/core/dist/runtime-v2/pain-to-principle-service.d.ts +8 -1
  32. package/core/dist/runtime-v2/pain-to-principle-service.d.ts.map +1 -1
  33. package/core/dist/runtime-v2/pain-to-principle-service.js +3 -0
  34. package/core/dist/runtime-v2/pain-to-principle-service.js.map +1 -1
  35. package/host-runtime/dist/index.d.ts +1 -0
  36. package/host-runtime/dist/index.js +3 -0
  37. package/host-runtime/dist/pain-evidence-ingress.d.ts +16 -0
  38. package/host-runtime/dist/pain-evidence-ingress.js +15 -0
  39. package/package.json +2 -2
  40. package/pd-cli/dist/commands/build-trajectory-evidence.d.ts +25 -6
  41. package/pd-cli/dist/commands/build-trajectory-evidence.d.ts.map +1 -1
  42. package/pd-cli/dist/commands/build-trajectory-evidence.js +174 -114
  43. package/pd-cli/dist/commands/build-trajectory-evidence.js.map +1 -1
  44. package/pd-cli/dist/commands/pain-record.d.ts.map +1 -1
  45. package/pd-cli/dist/commands/pain-record.js +212 -17
  46. package/pd-cli/dist/commands/pain-record.js.map +1 -1
  47. package/pd-cli/dist/index.js +1 -1
  48. package/pd-cli/dist/index.js.map +1 -1
  49. package/plugin/dist/bundle.js +456 -454
  50. package/plugin/dist/governance-audit.js +152 -152
  51. package/plugin/dist/hooks/pain-ingress-adapter.d.ts +19 -0
  52. package/plugin/dist/hooks/trajectory-evidence.d.ts +32 -1
  53. package/plugin/dist/rulehost-evidence.js +155 -155
  54. package/plugin/dist/templates/langs/en/skills/pd-cli-operator/SKILL.md +11 -4
  55. package/plugin/dist/templates/langs/en/skills/pd-pain-signal/SKILL.md +36 -4
  56. package/plugin/dist/templates/langs/en/skills/pd-runtime-v2/SKILL.md +4 -1
  57. package/plugin/dist/templates/langs/zh/skills/pd-cli-operator/SKILL.md +9 -4
  58. package/plugin/dist/templates/langs/zh/skills/pd-pain-signal/SKILL.md +32 -4
  59. package/plugin/dist/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +3 -1
  60. package/plugin/openclaw.plugin.json +1 -1
  61. package/plugin/package.json +1 -1
  62. package/plugin/templates/langs/en/skills/pd-cli-operator/SKILL.md +11 -4
  63. package/plugin/templates/langs/en/skills/pd-pain-signal/SKILL.md +36 -4
  64. package/plugin/templates/langs/en/skills/pd-runtime-v2/SKILL.md +4 -1
  65. package/plugin/templates/langs/zh/skills/pd-cli-operator/SKILL.md +9 -4
  66. package/plugin/templates/langs/zh/skills/pd-pain-signal/SKILL.md +32 -4
  67. package/plugin/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +3 -1
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pain-ingress-persistence.test.d.ts.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pain-ingress-shared-semantics.test.d.ts.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pain-outcome-convergence.test.d.ts.map
@@ -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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"}