@checkstack/healthcheck-backend 1.7.1 → 1.8.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/CHANGELOG.md +84 -0
- package/package.json +18 -18
- package/src/ai/healthcheck-projection.test.ts +37 -0
- package/src/automations.ts +3 -3
- package/src/index.ts +26 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,89 @@
|
|
|
1
1
|
# @checkstack/healthcheck-backend
|
|
2
2
|
|
|
3
|
+
## 1.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 4134ed9: Add a `healthcheck.runHistory` AI tool so the assistant can answer timeline and
|
|
8
|
+
root-cause questions ("what issues did system X have between T1 and T2", "show
|
|
9
|
+
the unhealthy runs in the last hour"). It projects the existing filtered
|
|
10
|
+
`getHistory` query, exposing the `systemId`, `startDate`/`endDate`, and
|
|
11
|
+
`statusFilter` filters, and is gated by the same public, default-on
|
|
12
|
+
`healthcheck.status` view rule the dashboard history view uses (no extra grant
|
|
13
|
+
needed). It complements `healthcheck.status`, which only reports current state.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 079369a: Fix producing automation actions that double-prefixed their artifact type. The
|
|
18
|
+
action registry qualifies `produces` with the owning plugin id, but several
|
|
19
|
+
actions set `produces` to an already-qualified id, so it became
|
|
20
|
+
`plugin.plugin.type` (e.g. `automation.automation.analysis`,
|
|
21
|
+
`maintenance.maintenance.window`). This stored artifacts under a type that
|
|
22
|
+
matched no registered artifact type, and — because the run scope exposes a
|
|
23
|
+
produced artifact under its type's local name — broke the documented downstream
|
|
24
|
+
reference `artifacts.<actionId>.<name>.<field>` (a `choose`/condition/template
|
|
25
|
+
referencing the analysis output, a created incident/maintenance/etc. silently
|
|
26
|
+
saw `undefined` and took the wrong branch).
|
|
27
|
+
|
|
28
|
+
Fixed in `ai_analyze` (`analysis`), the built-in `notify_user`
|
|
29
|
+
(`notify_user_result`), and the catalog (`system_record`), maintenance
|
|
30
|
+
(`window`), notification (`send_result`), dependency (`edge`), and healthcheck
|
|
31
|
+
(`assignment`) actions — each now uses the unqualified local id matching its
|
|
32
|
+
artifact-type definition.
|
|
33
|
+
|
|
34
|
+
BREAKING (beta): any automation that referenced one of these artifacts via the
|
|
35
|
+
old double-prefixed scope key (e.g. `artifacts.x['automation.analysis']`) must
|
|
36
|
+
switch to the documented form (`artifacts.x.analysis.<field>`). The
|
|
37
|
+
double-prefixed key was never the intended/documented path.
|
|
38
|
+
|
|
39
|
+
- Updated dependencies [079369a]
|
|
40
|
+
- Updated dependencies [4134ed9]
|
|
41
|
+
- Updated dependencies [6005271]
|
|
42
|
+
- Updated dependencies [748268c]
|
|
43
|
+
- Updated dependencies [4134ed9]
|
|
44
|
+
- Updated dependencies [4134ed9]
|
|
45
|
+
- Updated dependencies [079369a]
|
|
46
|
+
- Updated dependencies [079369a]
|
|
47
|
+
- @checkstack/ai-backend@0.6.0
|
|
48
|
+
- @checkstack/ai-common@0.4.0
|
|
49
|
+
- @checkstack/automation-backend@0.8.0
|
|
50
|
+
- @checkstack/backend-api@0.22.0
|
|
51
|
+
- @checkstack/catalog-backend@1.4.11
|
|
52
|
+
- @checkstack/incident-backend@1.7.3
|
|
53
|
+
- @checkstack/satellite-backend@0.6.11
|
|
54
|
+
- @checkstack/command-backend@0.2.8
|
|
55
|
+
- @checkstack/gitops-backend@0.5.8
|
|
56
|
+
- @checkstack/script-packages-backend@0.3.10
|
|
57
|
+
- @checkstack/secrets-backend@0.2.8
|
|
58
|
+
- @checkstack/sdk@0.106.1
|
|
59
|
+
- @checkstack/catalog-common@2.3.6
|
|
60
|
+
- @checkstack/healthcheck-common@1.6.2
|
|
61
|
+
- @checkstack/incident-common@1.5.2
|
|
62
|
+
- @checkstack/maintenance-common@1.5.2
|
|
63
|
+
|
|
64
|
+
## 1.7.2
|
|
65
|
+
|
|
66
|
+
### Patch Changes
|
|
67
|
+
|
|
68
|
+
- Updated dependencies [ebef442]
|
|
69
|
+
- Updated dependencies [ebef442]
|
|
70
|
+
- @checkstack/automation-backend@0.7.0
|
|
71
|
+
- @checkstack/ai-backend@0.5.0
|
|
72
|
+
- @checkstack/ai-common@0.3.0
|
|
73
|
+
- @checkstack/incident-backend@1.7.2
|
|
74
|
+
- @checkstack/sdk@0.105.1
|
|
75
|
+
- @checkstack/catalog-backend@1.4.10
|
|
76
|
+
- @checkstack/satellite-backend@0.6.10
|
|
77
|
+
- @checkstack/catalog-common@2.3.5
|
|
78
|
+
- @checkstack/script-packages-backend@0.3.9
|
|
79
|
+
- @checkstack/secrets-backend@0.2.7
|
|
80
|
+
- @checkstack/healthcheck-common@1.6.1
|
|
81
|
+
- @checkstack/incident-common@1.5.1
|
|
82
|
+
- @checkstack/maintenance-common@1.5.1
|
|
83
|
+
- @checkstack/backend-api@0.21.7
|
|
84
|
+
- @checkstack/command-backend@0.2.7
|
|
85
|
+
- @checkstack/gitops-backend@0.5.7
|
|
86
|
+
|
|
3
87
|
## 1.7.1
|
|
4
88
|
|
|
5
89
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/healthcheck-backend",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -14,29 +14,29 @@
|
|
|
14
14
|
"lint:code": "eslint . --max-warnings 0"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@checkstack/backend-api": "0.
|
|
18
|
-
"@checkstack/ai-backend": "0.
|
|
19
|
-
"@checkstack/ai-common": "0.
|
|
20
|
-
"@checkstack/script-packages-backend": "0.3.
|
|
17
|
+
"@checkstack/backend-api": "0.22.0",
|
|
18
|
+
"@checkstack/ai-backend": "0.6.0",
|
|
19
|
+
"@checkstack/ai-common": "0.4.0",
|
|
20
|
+
"@checkstack/script-packages-backend": "0.3.10",
|
|
21
21
|
"@checkstack/cache-api": "0.3.12",
|
|
22
22
|
"@checkstack/cache-utils": "0.2.17",
|
|
23
|
-
"@checkstack/catalog-backend": "1.4.
|
|
24
|
-
"@checkstack/catalog-common": "2.3.
|
|
25
|
-
"@checkstack/command-backend": "0.2.
|
|
23
|
+
"@checkstack/catalog-backend": "1.4.11",
|
|
24
|
+
"@checkstack/catalog-common": "2.3.6",
|
|
25
|
+
"@checkstack/command-backend": "0.2.8",
|
|
26
26
|
"@checkstack/common": "0.15.0",
|
|
27
|
-
"@checkstack/gitops-backend": "0.5.
|
|
27
|
+
"@checkstack/gitops-backend": "0.5.8",
|
|
28
28
|
"@checkstack/gitops-common": "0.6.3",
|
|
29
|
-
"@checkstack/healthcheck-common": "1.6.
|
|
29
|
+
"@checkstack/healthcheck-common": "1.6.2",
|
|
30
30
|
"@checkstack/secrets-common": "0.2.3",
|
|
31
|
-
"@checkstack/secrets-backend": "0.2.
|
|
32
|
-
"@checkstack/incident-backend": "1.7.
|
|
33
|
-
"@checkstack/incident-common": "1.5.
|
|
34
|
-
"@checkstack/automation-backend": "0.
|
|
35
|
-
"@checkstack/maintenance-common": "1.5.
|
|
31
|
+
"@checkstack/secrets-backend": "0.2.8",
|
|
32
|
+
"@checkstack/incident-backend": "1.7.3",
|
|
33
|
+
"@checkstack/incident-common": "1.5.2",
|
|
34
|
+
"@checkstack/automation-backend": "0.8.0",
|
|
35
|
+
"@checkstack/maintenance-common": "1.5.2",
|
|
36
36
|
"@checkstack/notification-common": "1.3.3",
|
|
37
37
|
"@checkstack/queue-api": "0.3.12",
|
|
38
|
-
"@checkstack/satellite-backend": "0.6.
|
|
39
|
-
"@checkstack/sdk": "0.
|
|
38
|
+
"@checkstack/satellite-backend": "0.6.11",
|
|
39
|
+
"@checkstack/sdk": "0.106.1",
|
|
40
40
|
"@checkstack/signal-common": "0.2.9",
|
|
41
41
|
"@hono/zod-validator": "^0.7.6",
|
|
42
42
|
"drizzle-orm": "^0.45.0",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@checkstack/drizzle-helper": "0.0.5",
|
|
52
52
|
"@checkstack/scripts": "0.6.1",
|
|
53
|
-
"@checkstack/test-utils-backend": "0.1.
|
|
53
|
+
"@checkstack/test-utils-backend": "0.1.42",
|
|
54
54
|
"@checkstack/tsconfig": "0.0.7",
|
|
55
55
|
"@types/bun": "^1.0.0",
|
|
56
56
|
"@types/tdigest": "^0.1.5",
|
|
@@ -34,3 +34,40 @@ describe("healthcheck.status projection", () => {
|
|
|
34
34
|
expect(tool.requiredAccessRules).not.toEqual(["ai.chat.read"]);
|
|
35
35
|
});
|
|
36
36
|
});
|
|
37
|
+
|
|
38
|
+
// The run-history projection lets the assistant answer timeline / root-cause
|
|
39
|
+
// questions ("what issues did system X have between T1 and T2"). It must expose
|
|
40
|
+
// the filter inputs (systemId, date window, statusFilter) and be gated by the
|
|
41
|
+
// public, default-on `healthcheck.status` VIEW rule (the same one the dashboard
|
|
42
|
+
// history view uses), so it needs no special grant.
|
|
43
|
+
describe("healthcheck.runHistory projection", () => {
|
|
44
|
+
const tool = buildProjectedTool({
|
|
45
|
+
procedure: healthCheckContract.getHistory,
|
|
46
|
+
sourcePluginMetadata: pluginMetadata,
|
|
47
|
+
procedureKey: "getHistory",
|
|
48
|
+
name: "healthcheck.runHistory",
|
|
49
|
+
description: "List historical health-check runs. Read-only.",
|
|
50
|
+
effect: "read",
|
|
51
|
+
execute: deferredProjectionExecute,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("uses the overridden tool name", () => {
|
|
55
|
+
expect(tool.name).toBe("healthcheck.runHistory");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("is classified as a read-only effect", () => {
|
|
59
|
+
expect(tool.effect).toBe("read");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("exposes the timespan/system/status filter inputs to the model", () => {
|
|
63
|
+
const inputShape = tool.input as { shape?: Record<string, unknown> };
|
|
64
|
+
expect(inputShape.shape).toBeDefined();
|
|
65
|
+
for (const field of ["systemId", "startDate", "endDate", "statusFilter"]) {
|
|
66
|
+
expect(inputShape.shape?.[field]).toBeDefined();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("is gated by the public healthcheck.status view rule, not the chat gate", () => {
|
|
71
|
+
expect(tool.requiredAccessRules).toEqual(["healthcheck.healthcheck.status.read"]);
|
|
72
|
+
});
|
|
73
|
+
});
|
package/src/automations.ts
CHANGED
|
@@ -232,7 +232,7 @@ export function createHealthCheckActions(
|
|
|
232
232
|
category: "Health",
|
|
233
233
|
icon: "Play",
|
|
234
234
|
config: new Versioned({ version: 1, schema: runNowConfigSchema }),
|
|
235
|
-
produces: "
|
|
235
|
+
produces: "assignment",
|
|
236
236
|
execute: async ({ config, logger }) => {
|
|
237
237
|
const queue = deps.queueManager.getQueue<HealthCheckJobPayload>(
|
|
238
238
|
HEALTH_CHECK_QUEUE,
|
|
@@ -267,7 +267,7 @@ export function createHealthCheckActions(
|
|
|
267
267
|
category: "Health",
|
|
268
268
|
icon: "Power",
|
|
269
269
|
config: new Versioned({ version: 1, schema: assignmentToggleConfigSchema }),
|
|
270
|
-
produces: "
|
|
270
|
+
produces: "assignment",
|
|
271
271
|
execute: async ({ config, logger }) => {
|
|
272
272
|
const updated = await deps.service.setAssignmentEnabled(
|
|
273
273
|
config.systemId,
|
|
@@ -310,7 +310,7 @@ export function createHealthCheckActions(
|
|
|
310
310
|
category: "Health",
|
|
311
311
|
icon: "PowerOff",
|
|
312
312
|
config: new Versioned({ version: 1, schema: assignmentToggleConfigSchema }),
|
|
313
|
-
produces: "
|
|
313
|
+
produces: "assignment",
|
|
314
314
|
execute: async ({ config, logger }) => {
|
|
315
315
|
const updated = await deps.service.setAssignmentEnabled(
|
|
316
316
|
config.systemId,
|
package/src/index.ts
CHANGED
|
@@ -270,6 +270,32 @@ export default createBackendPlugin({
|
|
|
270
270
|
execute: deferredProjectionExecute,
|
|
271
271
|
});
|
|
272
272
|
|
|
273
|
+
// Historical run-by-run check results, filterable by system, time
|
|
274
|
+
// window, and status. Complements `healthcheck.status` (which is only
|
|
275
|
+
// CURRENT state): this is how the assistant answers "what issues did
|
|
276
|
+
// system X have between T1 and T2" or "show the unhealthy runs in the
|
|
277
|
+
// last hour". Gated by the public, default-on `healthcheck.status` VIEW
|
|
278
|
+
// rule (the same one the dashboard's history view uses) - it returns the
|
|
279
|
+
// public run shape with no sensitive `result` payload, so it needs no
|
|
280
|
+
// special grant. (The detailed variant carrying `result` lives behind
|
|
281
|
+
// `healthcheck.details` and is intentionally NOT projected.)
|
|
282
|
+
env.getExtensionPoint(aiToolProjectionExtensionPoint).expose({
|
|
283
|
+
procedure: healthCheckContract.getHistory,
|
|
284
|
+
sourcePluginMetadata: pluginMetadata,
|
|
285
|
+
procedureKey: "getHistory",
|
|
286
|
+
name: "healthcheck.runHistory",
|
|
287
|
+
description:
|
|
288
|
+
"List historical health-check runs (individual timestamped results) " +
|
|
289
|
+
"for root-cause and timeline questions. Filter by `systemId`, a " +
|
|
290
|
+
"`startDate`/`endDate` window, and/or `statusFilter` (e.g. " +
|
|
291
|
+
"[\"unhealthy\",\"degraded\"]) to find when and how a system was " +
|
|
292
|
+
"failing over a period. Pass `sortOrder` (\"desc\" for most recent " +
|
|
293
|
+
"first) and use `limit`/`offset` to page. Use this for past/timespan " +
|
|
294
|
+
"questions; use healthcheck.status for the current state. Read-only.",
|
|
295
|
+
effect: "read",
|
|
296
|
+
execute: deferredProjectionExecute,
|
|
297
|
+
});
|
|
298
|
+
|
|
273
299
|
// Contribute this plugin's per-system health problems to the AI
|
|
274
300
|
// `system.issues` aggregator. PER-SOURCE access is OUR job: gate on the
|
|
275
301
|
// principal's `healthcheck.status` grant and return {} (never throw)
|