@principles/pd-cli 1.147.2 → 1.147.3
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/commands/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/commands/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AA2EtD,UAAU,aAAa;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAoBD,wBAAsB,YAAY,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuI1E;AAED;;;;GAIG;AACH,UAAU,qBAAqB;IAC7B,MAAM,CAAC,EAAE,OAAO,YAAY,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,iBAAiB,CAAC;CACxC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,GAAE,qBAA0B,GAAG,IAAI,CAkClG"}
|
package/dist/commands/health.js
CHANGED
|
@@ -13,7 +13,35 @@ import Database from 'better-sqlite3';
|
|
|
13
13
|
import { resolveWorkspaceDir } from '../resolve-workspace.js';
|
|
14
14
|
import { PruningReadModel, PainChainReadModel, auditCandidateLedgerConsistency } from '@principles/core/runtime-v2';
|
|
15
15
|
import { getLedgerFilePathPublic } from '@principles/core/principle-tree-ledger';
|
|
16
|
+
import { createEvaluatorRuntimeContext, loadHostToolDeclarations, resolveWorkspaceHostToolSemantics, } from '@principles/host-runtime';
|
|
16
17
|
import { handleHealthCodex } from './health-codex.js';
|
|
18
|
+
function assessReliability(workspaceDir) {
|
|
19
|
+
const loaded = loadHostToolDeclarations(workspaceDir);
|
|
20
|
+
const resolver = resolveWorkspaceHostToolSemantics(workspaceDir);
|
|
21
|
+
const replay = createEvaluatorRuntimeContext({ workspaceDir });
|
|
22
|
+
if (loaded.ok) {
|
|
23
|
+
return {
|
|
24
|
+
registry: {
|
|
25
|
+
status: 'ok',
|
|
26
|
+
hosts: loaded.declarations.map((d) => d.hostKind).sort(),
|
|
27
|
+
declaredTools: loaded.declarations.reduce((n, d) => n + d.mappings.length, 0),
|
|
28
|
+
},
|
|
29
|
+
resolver: resolver.ok ? 'ready' : 'not_ready',
|
|
30
|
+
replay: replay.ok ? 'ready' : 'not_ready',
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// Fresh-install expected state until each host starts once — explicit, never
|
|
34
|
+
// a silent baseline fallback (ERR-114). Informational: the refusal authority
|
|
35
|
+
// lives in the activation/evaluator paths, so the health exit code is
|
|
36
|
+
// unchanged by this section.
|
|
37
|
+
return {
|
|
38
|
+
registry: { status: 'degraded', hosts: [], declaredTools: 0 },
|
|
39
|
+
resolver: 'not_ready',
|
|
40
|
+
replay: 'not_ready',
|
|
41
|
+
reason: loaded.reason,
|
|
42
|
+
nextAction: loaded.nextAction,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
17
45
|
function painChainTraceToLastSuccessfulChain(trace) {
|
|
18
46
|
const totalMs = (trace.latencyMs.painToTask ?? 0)
|
|
19
47
|
+ (trace.latencyMs.taskToRun ?? 0)
|
|
@@ -42,6 +70,7 @@ export async function handleHealth(opts = {}) {
|
|
|
42
70
|
const healthSummary = pruningModel.getHealthSummary();
|
|
43
71
|
const ledgerByStatus = healthSummary.byStatus;
|
|
44
72
|
const { missingLedgerCount } = await auditCandidateLedgerConsistency(workspaceDir);
|
|
73
|
+
const reliability = assessReliability(workspaceDir);
|
|
45
74
|
let candidatesTotal = 0, candidatesConsumed = 0, candidatesPending = 0;
|
|
46
75
|
let tasksTotal = 0;
|
|
47
76
|
const tasksByStatus = {};
|
|
@@ -66,6 +95,7 @@ export async function handleHealth(opts = {}) {
|
|
|
66
95
|
status: missingLedgerCount === 0 ? 'ok' : 'degraded',
|
|
67
96
|
missing: missingLedgerCount,
|
|
68
97
|
},
|
|
98
|
+
reliability,
|
|
69
99
|
lastSuccessfulChain,
|
|
70
100
|
};
|
|
71
101
|
}
|
|
@@ -92,6 +122,15 @@ export async function handleHealth(opts = {}) {
|
|
|
92
122
|
console.log(`tasks.byStatus: ${JSON.stringify(health.tasks.byStatus)}`);
|
|
93
123
|
console.log(`candidateLedgerConsistency.status: ${health.candidateLedgerConsistency.status}`);
|
|
94
124
|
console.log(`candidateLedgerConsistency.missing: ${health.candidateLedgerConsistency.missing}`);
|
|
125
|
+
console.log(`reliability.registry.status: ${health.reliability.registry.status}`);
|
|
126
|
+
console.log(`reliability.registry.hosts: ${health.reliability.registry.hosts.join('+') || '(none)'}`);
|
|
127
|
+
console.log(`reliability.registry.declaredTools: ${health.reliability.registry.declaredTools}`);
|
|
128
|
+
console.log(`reliability.resolver: ${health.reliability.resolver}`);
|
|
129
|
+
console.log(`reliability.replay: ${health.reliability.replay}`);
|
|
130
|
+
if (health.reliability.reason) {
|
|
131
|
+
console.log(`reliability.reason: ${health.reliability.reason}`);
|
|
132
|
+
console.log(`reliability.nextAction: ${health.reliability.nextAction}`);
|
|
133
|
+
}
|
|
95
134
|
if (health.lastSuccessfulChain) {
|
|
96
135
|
console.log('lastSuccessfulChain:');
|
|
97
136
|
console.log(` taskId: ${health.lastSuccessfulChain.taskId}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/commands/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAEpH,OAAO,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/commands/health.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principles/pd-cli",
|
|
3
|
-
"version": "1.147.
|
|
3
|
+
"version": "1.147.3",
|
|
4
4
|
"description": "PD CLI — Pain recording, sample management, and governance tasks for Principles Disciple",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"@principles/core": "^1.74.1",
|
|
17
17
|
"@principles/codex-adapter": "^0.1.0",
|
|
18
18
|
"@principles/host-runtime": "^0.1.0",
|
|
19
|
-
"@principles/install-layout": "0.
|
|
19
|
+
"@principles/install-layout": "^0.2.0",
|
|
20
20
|
"principles-disciple": "^1.74.1",
|
|
21
21
|
"better-sqlite3": "^13.0.3",
|
|
22
22
|
"commander": "^12.0.0",
|
package/src/commands/health.ts
CHANGED
|
@@ -16,6 +16,11 @@ import { resolveWorkspaceDir } from '../resolve-workspace.js';
|
|
|
16
16
|
import { PruningReadModel, PainChainReadModel, auditCandidateLedgerConsistency } from '@principles/core/runtime-v2';
|
|
17
17
|
import type { PainChainTrace } from '@principles/core/runtime-v2';
|
|
18
18
|
import { getLedgerFilePathPublic } from '@principles/core/principle-tree-ledger';
|
|
19
|
+
import {
|
|
20
|
+
createEvaluatorRuntimeContext,
|
|
21
|
+
loadHostToolDeclarations,
|
|
22
|
+
resolveWorkspaceHostToolSemantics,
|
|
23
|
+
} from '@principles/host-runtime';
|
|
19
24
|
import { handleHealthCodex } from './health-codex.js';
|
|
20
25
|
|
|
21
26
|
interface LastSuccessfulChain {
|
|
@@ -30,6 +35,54 @@ interface LastSuccessfulChain {
|
|
|
30
35
|
checkedAt: string;
|
|
31
36
|
}
|
|
32
37
|
|
|
38
|
+
/**
|
|
39
|
+
* PRI-662: reliability readiness — the post-upgrade validation surface.
|
|
40
|
+
* Reads the SAME durable host declarations and uses the SAME resolver /
|
|
41
|
+
* evaluator runtime-context builder as the production activation and
|
|
42
|
+
* evaluator replay paths, so "replay: ready" here means exactly "the
|
|
43
|
+
* replay the gate will run is constructible" — no parallel truth.
|
|
44
|
+
*/
|
|
45
|
+
interface ReliabilityHealth {
|
|
46
|
+
registry: {
|
|
47
|
+
status: 'ok' | 'degraded';
|
|
48
|
+
hosts: string[];
|
|
49
|
+
declaredTools: number;
|
|
50
|
+
};
|
|
51
|
+
resolver: 'ready' | 'not_ready';
|
|
52
|
+
replay: 'ready' | 'not_ready';
|
|
53
|
+
reason?: string;
|
|
54
|
+
nextAction?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function assessReliability(workspaceDir: string): ReliabilityHealth {
|
|
58
|
+
const loaded = loadHostToolDeclarations(workspaceDir);
|
|
59
|
+
const resolver = resolveWorkspaceHostToolSemantics(workspaceDir);
|
|
60
|
+
const replay = createEvaluatorRuntimeContext({ workspaceDir });
|
|
61
|
+
|
|
62
|
+
if (loaded.ok) {
|
|
63
|
+
return {
|
|
64
|
+
registry: {
|
|
65
|
+
status: 'ok',
|
|
66
|
+
hosts: loaded.declarations.map((d) => d.hostKind).sort(),
|
|
67
|
+
declaredTools: loaded.declarations.reduce((n, d) => n + d.mappings.length, 0),
|
|
68
|
+
},
|
|
69
|
+
resolver: resolver.ok ? 'ready' : 'not_ready',
|
|
70
|
+
replay: replay.ok ? 'ready' : 'not_ready',
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// Fresh-install expected state until each host starts once — explicit, never
|
|
74
|
+
// a silent baseline fallback (ERR-114). Informational: the refusal authority
|
|
75
|
+
// lives in the activation/evaluator paths, so the health exit code is
|
|
76
|
+
// unchanged by this section.
|
|
77
|
+
return {
|
|
78
|
+
registry: { status: 'degraded', hosts: [], declaredTools: 0 },
|
|
79
|
+
resolver: 'not_ready',
|
|
80
|
+
replay: 'not_ready',
|
|
81
|
+
reason: loaded.reason,
|
|
82
|
+
nextAction: loaded.nextAction,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
33
86
|
interface WorkspaceHealth {
|
|
34
87
|
generatedAt: string;
|
|
35
88
|
workspace: string;
|
|
@@ -39,6 +92,7 @@ interface WorkspaceHealth {
|
|
|
39
92
|
candidates: { total: number; consumed: number; pending: number };
|
|
40
93
|
tasks: { total: number; byStatus: Record<string, number> };
|
|
41
94
|
candidateLedgerConsistency: { status: 'ok' | 'degraded'; missing: number };
|
|
95
|
+
reliability: ReliabilityHealth;
|
|
42
96
|
lastSuccessfulChain?: LastSuccessfulChain;
|
|
43
97
|
}
|
|
44
98
|
|
|
@@ -80,6 +134,7 @@ export async function handleHealth(opts: HealthOptions = {}): Promise<void> {
|
|
|
80
134
|
const ledgerByStatus = healthSummary.byStatus;
|
|
81
135
|
|
|
82
136
|
const { missingLedgerCount } = await auditCandidateLedgerConsistency(workspaceDir);
|
|
137
|
+
const reliability = assessReliability(workspaceDir);
|
|
83
138
|
|
|
84
139
|
let candidatesTotal = 0, candidatesConsumed = 0, candidatesPending = 0;
|
|
85
140
|
let tasksTotal = 0;
|
|
@@ -106,6 +161,7 @@ export async function handleHealth(opts: HealthOptions = {}): Promise<void> {
|
|
|
106
161
|
status: missingLedgerCount === 0 ? 'ok' : 'degraded',
|
|
107
162
|
missing: missingLedgerCount,
|
|
108
163
|
},
|
|
164
|
+
reliability,
|
|
109
165
|
lastSuccessfulChain,
|
|
110
166
|
};
|
|
111
167
|
}
|
|
@@ -134,6 +190,15 @@ export async function handleHealth(opts: HealthOptions = {}): Promise<void> {
|
|
|
134
190
|
console.log(`tasks.byStatus: ${JSON.stringify(health.tasks.byStatus)}`);
|
|
135
191
|
console.log(`candidateLedgerConsistency.status: ${health.candidateLedgerConsistency.status}`);
|
|
136
192
|
console.log(`candidateLedgerConsistency.missing: ${health.candidateLedgerConsistency.missing}`);
|
|
193
|
+
console.log(`reliability.registry.status: ${health.reliability.registry.status}`);
|
|
194
|
+
console.log(`reliability.registry.hosts: ${health.reliability.registry.hosts.join('+') || '(none)'}`);
|
|
195
|
+
console.log(`reliability.registry.declaredTools: ${health.reliability.registry.declaredTools}`);
|
|
196
|
+
console.log(`reliability.resolver: ${health.reliability.resolver}`);
|
|
197
|
+
console.log(`reliability.replay: ${health.reliability.replay}`);
|
|
198
|
+
if (health.reliability.reason) {
|
|
199
|
+
console.log(`reliability.reason: ${health.reliability.reason}`);
|
|
200
|
+
console.log(`reliability.nextAction: ${health.reliability.nextAction}`);
|
|
201
|
+
}
|
|
137
202
|
if (health.lastSuccessfulChain) {
|
|
138
203
|
console.log('lastSuccessfulChain:');
|
|
139
204
|
console.log(` taskId: ${health.lastSuccessfulChain.taskId}`);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRI-662 — reliability readiness section of `pd health`, against REAL
|
|
3
|
+
* declaration files on disk (no fs mock, no host-runtime mock): the upgrade
|
|
4
|
+
* validation surface must observe exactly what the production paths observe.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, afterEach, vi } from 'vitest';
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as os from 'node:os';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
import { saveHostToolDeclaration } from '@principles/host-runtime';
|
|
11
|
+
import { handleHealth } from '../../src/commands/health.js';
|
|
12
|
+
|
|
13
|
+
const dirs: string[] = [];
|
|
14
|
+
|
|
15
|
+
function makeWorkspace(): string {
|
|
16
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'pd-health-reliability-'));
|
|
17
|
+
dirs.push(dir);
|
|
18
|
+
return dir;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
vi.restoreAllMocks();
|
|
23
|
+
for (const dir of dirs.splice(0)) {
|
|
24
|
+
try { fs.rmSync(dir, { recursive: true, force: true }); } catch { /* temp */ }
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('pd health reliability section (real declaration files)', () => {
|
|
29
|
+
it('fresh workspace (no declaration): explicit degraded + host_tool_declaration_missing, informational only', async () => {
|
|
30
|
+
const workspaceDir = makeWorkspace();
|
|
31
|
+
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
32
|
+
try {
|
|
33
|
+
await handleHealth({ workspace: workspaceDir, json: true });
|
|
34
|
+
const parsed = JSON.parse(logSpy.mock.calls[0][0]) as {
|
|
35
|
+
reliability: { registry: { status: string }; resolver: string; replay: string; reason?: string; nextAction?: string };
|
|
36
|
+
};
|
|
37
|
+
expect(parsed.reliability.registry.status).toBe('degraded');
|
|
38
|
+
expect(parsed.reliability.resolver).toBe('not_ready');
|
|
39
|
+
expect(parsed.reliability.replay).toBe('not_ready');
|
|
40
|
+
expect(parsed.reliability.reason).toBe('host_tool_declaration_missing');
|
|
41
|
+
expect(parsed.reliability.nextAction ?? '').not.toBe('');
|
|
42
|
+
} finally {
|
|
43
|
+
vi.restoreAllMocks();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('declared workspace: registry ok with per-host counts, resolver/replay ready', async () => {
|
|
48
|
+
const workspaceDir = makeWorkspace();
|
|
49
|
+
saveHostToolDeclaration(workspaceDir, {
|
|
50
|
+
version: 1,
|
|
51
|
+
hostKind: 'openclaw',
|
|
52
|
+
mappings: [
|
|
53
|
+
{ rawToolName: 'Write', canonicalKind: 'write' },
|
|
54
|
+
{ rawToolName: 'Edit', canonicalKind: 'write' },
|
|
55
|
+
{ rawToolName: 'Bash', canonicalKind: 'execute' },
|
|
56
|
+
],
|
|
57
|
+
declaredAt: new Date().toISOString(),
|
|
58
|
+
});
|
|
59
|
+
saveHostToolDeclaration(workspaceDir, {
|
|
60
|
+
version: 1,
|
|
61
|
+
hostKind: 'codex',
|
|
62
|
+
mappings: [{ rawToolName: 'shell', canonicalKind: 'execute' }],
|
|
63
|
+
declaredAt: new Date().toISOString(),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
67
|
+
try {
|
|
68
|
+
await handleHealth({ workspace: workspaceDir, json: false });
|
|
69
|
+
const allOutput = logSpy.mock.calls.map((c) => c.join(' ')).join('\n');
|
|
70
|
+
expect(allOutput).toContain('reliability.registry.status: ok');
|
|
71
|
+
expect(allOutput).toContain('reliability.registry.hosts: codex+openclaw');
|
|
72
|
+
expect(allOutput).toContain('reliability.registry.declaredTools: 4');
|
|
73
|
+
expect(allOutput).toContain('reliability.resolver: ready');
|
|
74
|
+
expect(allOutput).toContain('reliability.replay: ready');
|
|
75
|
+
} finally {
|
|
76
|
+
vi.restoreAllMocks();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('malformed declaration: explicit invalid reason with a repair action', async () => {
|
|
81
|
+
const workspaceDir = makeWorkspace();
|
|
82
|
+
const dir = path.join(workspaceDir, '.pd', 'host-tool-semantics');
|
|
83
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
84
|
+
fs.writeFileSync(path.join(dir, 'openclaw.json'), '{broken', 'utf-8');
|
|
85
|
+
|
|
86
|
+
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
87
|
+
try {
|
|
88
|
+
await handleHealth({ workspace: workspaceDir, json: true });
|
|
89
|
+
const parsed = JSON.parse(logSpy.mock.calls[0][0]) as {
|
|
90
|
+
reliability: { registry: { status: string }; reason?: string; nextAction?: string };
|
|
91
|
+
};
|
|
92
|
+
expect(parsed.reliability.registry.status).toBe('degraded');
|
|
93
|
+
expect(parsed.reliability.reason).toContain('host_tool_declaration_invalid');
|
|
94
|
+
expect(parsed.reliability.nextAction ?? '').not.toBe('');
|
|
95
|
+
} finally {
|
|
96
|
+
vi.restoreAllMocks();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -60,6 +60,28 @@ vi.mock('../../src/resolve-workspace.js', () => ({
|
|
|
60
60
|
resolveWorkspaceDir: vi.fn().mockReturnValue('/fake/workspace'),
|
|
61
61
|
}));
|
|
62
62
|
|
|
63
|
+
// PRI-662: the reliability section reads REAL declaration files through the
|
|
64
|
+
// host-runtime seam — mock the three functions (this file mocks `fs`
|
|
65
|
+
// wholesale, so the real loader cannot run here). Real-file coverage lives in
|
|
66
|
+
// health-reliability.test.ts.
|
|
67
|
+
const { mockLoadHostToolDeclarations, mockResolveWorkspaceHostToolSemantics, mockCreateEvaluatorRuntimeContext } = vi.hoisted(() => {
|
|
68
|
+
return {
|
|
69
|
+
mockLoadHostToolDeclarations: vi.fn().mockReturnValue({
|
|
70
|
+
ok: true,
|
|
71
|
+
declarations: [
|
|
72
|
+
{ version: 1, hostKind: 'openclaw', mappings: [{}, {}, {}], declaredAt: '2026-09-04T00:00:00.000Z' },
|
|
73
|
+
],
|
|
74
|
+
}),
|
|
75
|
+
mockResolveWorkspaceHostToolSemantics: vi.fn().mockReturnValue({ ok: true, registry: {}, hostKinds: ['openclaw'] }),
|
|
76
|
+
mockCreateEvaluatorRuntimeContext: vi.fn().mockReturnValue({ ok: true, gateDeps: {} }),
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
vi.mock('@principles/host-runtime', () => ({
|
|
80
|
+
loadHostToolDeclarations: mockLoadHostToolDeclarations,
|
|
81
|
+
resolveWorkspaceHostToolSemantics: mockResolveWorkspaceHostToolSemantics,
|
|
82
|
+
createEvaluatorRuntimeContext: mockCreateEvaluatorRuntimeContext,
|
|
83
|
+
}));
|
|
84
|
+
|
|
63
85
|
vi.mock('fs', () => ({
|
|
64
86
|
existsSync: mockExistsSync,
|
|
65
87
|
}));
|
|
@@ -158,6 +180,51 @@ describe('handleHealth', () => {
|
|
|
158
180
|
expect(allOutput).toContain('pdStateDb.exists: false');
|
|
159
181
|
});
|
|
160
182
|
|
|
183
|
+
it('reports the reliability readiness section (PRI-662) — declared workspace', async () => {
|
|
184
|
+
mockPruningGetHealthSummary.mockReturnValue(healthyPruningSummary());
|
|
185
|
+
mockAuditCandidateLedgerConsistency.mockResolvedValue({ missingLedgerCount: 0 });
|
|
186
|
+
|
|
187
|
+
await handleHealth({ workspace: WS, json: true });
|
|
188
|
+
|
|
189
|
+
const jsonOutput = JSON.parse(consoleLogSpy.mock.calls[0][0]);
|
|
190
|
+
expect(jsonOutput.reliability).toEqual({
|
|
191
|
+
registry: { status: 'ok', hosts: ['openclaw'], declaredTools: 3 },
|
|
192
|
+
resolver: 'ready',
|
|
193
|
+
replay: 'ready',
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('reports reliability as explicitly degraded (host_tool_declaration_missing) without failing health', async () => {
|
|
198
|
+
mockPruningGetHealthSummary.mockReturnValue(healthyPruningSummary());
|
|
199
|
+
mockAuditCandidateLedgerConsistency.mockResolvedValue({ missingLedgerCount: 0 });
|
|
200
|
+
mockLoadHostToolDeclarations.mockReturnValueOnce({
|
|
201
|
+
ok: false,
|
|
202
|
+
reason: 'host_tool_declaration_missing',
|
|
203
|
+
nextAction: 'start each workspace host once (OpenClaw plugin / Codex worker) so it persists its tool declaration',
|
|
204
|
+
});
|
|
205
|
+
mockResolveWorkspaceHostToolSemantics.mockReturnValueOnce({
|
|
206
|
+
ok: false,
|
|
207
|
+
reason: 'host_tool_declaration_missing',
|
|
208
|
+
nextAction: 'start each workspace host once (OpenClaw plugin / Codex worker) so it persists its tool declaration',
|
|
209
|
+
});
|
|
210
|
+
mockCreateEvaluatorRuntimeContext.mockReturnValueOnce({
|
|
211
|
+
ok: false,
|
|
212
|
+
reason: 'host_tool_declaration_missing',
|
|
213
|
+
nextAction: 'start each workspace host once (OpenClaw plugin / Codex worker) so it persists its tool declaration',
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
await handleHealth({ workspace: WS, json: false });
|
|
217
|
+
|
|
218
|
+
const allOutput = consoleLogSpy.mock.calls.map(c => c.join(' ')).join('\n');
|
|
219
|
+
expect(allOutput).toContain('reliability.registry.status: degraded');
|
|
220
|
+
expect(allOutput).toContain('reliability.resolver: not_ready');
|
|
221
|
+
expect(allOutput).toContain('reliability.replay: not_ready');
|
|
222
|
+
expect(allOutput).toContain('reliability.reason: host_tool_declaration_missing');
|
|
223
|
+
// Fresh-install expected state: informational only, health exit code unchanged.
|
|
224
|
+
expect(process.exitCode).toBeUndefined();
|
|
225
|
+
expect(consoleWarnSpy).not.toHaveBeenCalledWith(expect.stringContaining('DEGRADED'));
|
|
226
|
+
});
|
|
227
|
+
|
|
161
228
|
it('reports zero candidate and task counts', async () => {
|
|
162
229
|
mockPruningGetHealthSummary.mockReturnValue(healthyPruningSummary());
|
|
163
230
|
mockAuditCandidateLedgerConsistency.mockResolvedValue({ missingLedgerCount: 0 });
|