@checkstack/healthcheck-backend 1.7.2 → 1.8.1

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 CHANGED
@@ -1,5 +1,82 @@
1
1
  # @checkstack/healthcheck-backend
2
2
 
3
+ ## 1.8.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [bb6f0fe]
8
+ - Updated dependencies [bb6f0fe]
9
+ - @checkstack/maintenance-common@1.6.0
10
+ - @checkstack/ai-backend@0.6.1
11
+ - @checkstack/sdk@0.107.1
12
+ - @checkstack/automation-backend@0.8.1
13
+ - @checkstack/secrets-backend@0.2.8
14
+ - @checkstack/catalog-backend@1.4.12
15
+ - @checkstack/incident-backend@1.7.4
16
+ - @checkstack/satellite-backend@0.6.12
17
+ - @checkstack/script-packages-backend@0.3.11
18
+
19
+ ## 1.8.0
20
+
21
+ ### Minor Changes
22
+
23
+ - 4134ed9: Add a `healthcheck.runHistory` AI tool so the assistant can answer timeline and
24
+ root-cause questions ("what issues did system X have between T1 and T2", "show
25
+ the unhealthy runs in the last hour"). It projects the existing filtered
26
+ `getHistory` query, exposing the `systemId`, `startDate`/`endDate`, and
27
+ `statusFilter` filters, and is gated by the same public, default-on
28
+ `healthcheck.status` view rule the dashboard history view uses (no extra grant
29
+ needed). It complements `healthcheck.status`, which only reports current state.
30
+
31
+ ### Patch Changes
32
+
33
+ - 079369a: Fix producing automation actions that double-prefixed their artifact type. The
34
+ action registry qualifies `produces` with the owning plugin id, but several
35
+ actions set `produces` to an already-qualified id, so it became
36
+ `plugin.plugin.type` (e.g. `automation.automation.analysis`,
37
+ `maintenance.maintenance.window`). This stored artifacts under a type that
38
+ matched no registered artifact type, and — because the run scope exposes a
39
+ produced artifact under its type's local name — broke the documented downstream
40
+ reference `artifacts.<actionId>.<name>.<field>` (a `choose`/condition/template
41
+ referencing the analysis output, a created incident/maintenance/etc. silently
42
+ saw `undefined` and took the wrong branch).
43
+
44
+ Fixed in `ai_analyze` (`analysis`), the built-in `notify_user`
45
+ (`notify_user_result`), and the catalog (`system_record`), maintenance
46
+ (`window`), notification (`send_result`), dependency (`edge`), and healthcheck
47
+ (`assignment`) actions — each now uses the unqualified local id matching its
48
+ artifact-type definition.
49
+
50
+ BREAKING (beta): any automation that referenced one of these artifacts via the
51
+ old double-prefixed scope key (e.g. `artifacts.x['automation.analysis']`) must
52
+ switch to the documented form (`artifacts.x.analysis.<field>`). The
53
+ double-prefixed key was never the intended/documented path.
54
+
55
+ - Updated dependencies [079369a]
56
+ - Updated dependencies [4134ed9]
57
+ - Updated dependencies [6005271]
58
+ - Updated dependencies [748268c]
59
+ - Updated dependencies [4134ed9]
60
+ - Updated dependencies [4134ed9]
61
+ - Updated dependencies [079369a]
62
+ - Updated dependencies [079369a]
63
+ - @checkstack/ai-backend@0.6.0
64
+ - @checkstack/ai-common@0.4.0
65
+ - @checkstack/automation-backend@0.8.0
66
+ - @checkstack/backend-api@0.22.0
67
+ - @checkstack/catalog-backend@1.4.11
68
+ - @checkstack/incident-backend@1.7.3
69
+ - @checkstack/satellite-backend@0.6.11
70
+ - @checkstack/command-backend@0.2.8
71
+ - @checkstack/gitops-backend@0.5.8
72
+ - @checkstack/script-packages-backend@0.3.10
73
+ - @checkstack/secrets-backend@0.2.8
74
+ - @checkstack/sdk@0.106.1
75
+ - @checkstack/catalog-common@2.3.6
76
+ - @checkstack/healthcheck-common@1.6.2
77
+ - @checkstack/incident-common@1.5.2
78
+ - @checkstack/maintenance-common@1.5.2
79
+
3
80
  ## 1.7.2
4
81
 
5
82
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/healthcheck-backend",
3
- "version": "1.7.2",
3
+ "version": "1.8.1",
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.21.7",
18
- "@checkstack/ai-backend": "0.5.0",
19
- "@checkstack/ai-common": "0.3.0",
20
- "@checkstack/script-packages-backend": "0.3.9",
17
+ "@checkstack/backend-api": "0.22.0",
18
+ "@checkstack/ai-backend": "0.6.1",
19
+ "@checkstack/ai-common": "0.4.0",
20
+ "@checkstack/script-packages-backend": "0.3.11",
21
21
  "@checkstack/cache-api": "0.3.12",
22
22
  "@checkstack/cache-utils": "0.2.17",
23
- "@checkstack/catalog-backend": "1.4.10",
24
- "@checkstack/catalog-common": "2.3.5",
25
- "@checkstack/command-backend": "0.2.7",
23
+ "@checkstack/catalog-backend": "1.4.12",
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.7",
27
+ "@checkstack/gitops-backend": "0.5.8",
28
28
  "@checkstack/gitops-common": "0.6.3",
29
- "@checkstack/healthcheck-common": "1.6.1",
29
+ "@checkstack/healthcheck-common": "1.6.2",
30
30
  "@checkstack/secrets-common": "0.2.3",
31
- "@checkstack/secrets-backend": "0.2.7",
32
- "@checkstack/incident-backend": "1.7.2",
33
- "@checkstack/incident-common": "1.5.1",
34
- "@checkstack/automation-backend": "0.7.0",
35
- "@checkstack/maintenance-common": "1.5.1",
31
+ "@checkstack/secrets-backend": "0.2.8",
32
+ "@checkstack/incident-backend": "1.7.4",
33
+ "@checkstack/incident-common": "1.5.2",
34
+ "@checkstack/automation-backend": "0.8.1",
35
+ "@checkstack/maintenance-common": "1.6.0",
36
36
  "@checkstack/notification-common": "1.3.3",
37
37
  "@checkstack/queue-api": "0.3.12",
38
- "@checkstack/satellite-backend": "0.6.10",
39
- "@checkstack/sdk": "0.105.1",
38
+ "@checkstack/satellite-backend": "0.6.12",
39
+ "@checkstack/sdk": "0.107.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.41",
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
+ });
@@ -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: "healthcheck.assignment",
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: "healthcheck.assignment",
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: "healthcheck.assignment",
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)