@desplega.ai/agent-swarm 1.103.0 → 1.104.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/README.md +2 -0
- package/dist/{actions-7txktrdj.js → actions-2expzt47.js} +6 -6
- package/dist/{app-xm3xsdye.js → app-dr8hwx7z.js} +3 -3
- package/dist/{assistant-qpv63wk6.js → assistant-9rhgsw7v.js} +9 -10
- package/dist/{boot-reembed-chxhrwv8.js → boot-reembed-3q1aywnz.js} +5 -4
- package/dist/{boot-reembed-9cxqka3e.js → boot-reembed-9kt97g1z.js} +4 -3
- package/dist/{boot-scrub-logs-8qtfkcz8.js → boot-scrub-logs-vskq108e.js} +2 -2
- package/dist/{cli-fedn86nz.js → cli-0jw6j755.js} +8 -3
- package/dist/{cli-yeemwevj.js → cli-23zk7xqy.js} +20 -16
- package/dist/{cli-v9283nma.js → cli-2g9jf9ek.js} +1 -1
- package/dist/{cli-rvae030h.js → cli-2hap19dv.js} +3 -3
- package/dist/{cli-wjyyv518.js → cli-3j01d33e.js} +9 -14
- package/dist/{cli-8hyv6c2v.js → cli-54h5daha.js} +41 -23
- package/dist/{cli-fygaw191.js → cli-5pf0b84v.js} +2 -2
- package/dist/{cli-m8f6qzck.js → cli-7v4y3hyd.js} +1 -1
- package/dist/{cli-fwxdt7kt.js → cli-d4z1csms.js} +30 -5
- package/dist/{cli-jt9d9fjw.js → cli-e7bwjntj.js} +1 -1
- package/dist/{cli-s14sb64w.js → cli-etvgz5x8.js} +5 -7
- package/dist/{cli-2qynerth.js → cli-gj2n2ec1.js} +1 -1
- package/dist/{cli-dz3d6zjg.js → cli-nzc0h54v.js} +121 -2
- package/dist/{cli-8w95v19d.js → cli-p4cj4vhc.js} +351 -24
- package/dist/{cli-xmtsan9k.js → cli-q5tshxd6.js} +1 -1
- package/dist/{http-zts4haq7.js → cli-qvzgncd8.js} +83966 -76422
- package/dist/{cli-4fnp2tc3.js → cli-s42f54ja.js} +1 -1
- package/dist/{cli-krvxq8bc.js → cli-t9v14cnd.js} +23 -4
- package/dist/{cli-gzepjz54.js → cli-v1syqkcb.js} +900 -352
- package/dist/{cli-ksq38x4n.js → cli-w1nfskkg.js} +2 -2
- package/dist/{cli-ns0r7mkr.js → cli-y9p3e94h.js} +3 -3
- package/dist/{cli-85pf4z38.js → cli-yjt8a36k.js} +3 -3
- package/dist/{cli-yfwwjeft.js → cli-yvektv79.js} +1 -1
- package/dist/{cli-kk51f3tf.js → cli-zaxksbgj.js} +5 -5
- package/dist/{cli-rttgde5f.js → cli-zghef0em.js} +1 -1
- package/dist/cli.js +10 -10
- package/dist/{commands-aqn63mcw.js → commands-wfrkef57.js} +2 -2
- package/dist/{db-azrvwsnj.js → db-c42pxt7h.js} +2 -2
- package/dist/{handlers-hf61har3.js → handlers-n36zkfvx.js} +10 -12
- package/dist/{hook-306p3yz4.js → hook-gw3vhv6s.js} +7 -5
- package/dist/http-59ygpn2h.js +17263 -0
- package/dist/{index-h2yqjyk0.js → index-881c1baf.js} +9 -8
- package/dist/{index-29vg51x6.js → index-jca7jdpt.js} +23 -10
- package/dist/{index-bfh9hgek.js → index-xf6fp4y1.js} +5 -5
- package/dist/{index-3c651yfk.js → index-xz8vaa5c.js} +14 -11
- package/dist/{keepalive-a0dg5pds.js → keepalive-mj4302vw.js} +4 -4
- package/dist/{lead-7mcxedkc.js → lead-qm0xjvkv.js} +19 -19
- package/dist/{maintenance-mrzqd53t.js → maintenance-xppxbe4t.js} +5 -4
- package/dist/{onboard-4dkpv9wa.js → onboard-ejx6yxh8.js} +2 -2
- package/dist/{otel-impl-jt7gpyp9.js → otel-impl-zs5exkpk.js} +1 -1
- package/dist/{pricing-refresh-xqnzh8dt.js → pricing-refresh-nqyf8bkb.js} +4 -4
- package/dist/{seed-pricing-56tjm1fj.js → seed-pricing-w3x550cj.js} +3 -3
- package/dist/{setup-tbwk8j10.js → setup-7729ktfj.js} +2 -2
- package/dist/{worker-e03za92t.js → worker-4ttemwhw.js} +19 -19
- package/openapi.json +90 -4
- package/package.json +3 -3
- package/src/be/memory/constants.ts +6 -0
- package/src/be/memory/providers/sqlite-store.ts +468 -71
- package/src/be/memory/raters/retrieval.ts +4 -2
- package/src/be/memory/reranker.ts +5 -2
- package/src/be/memory/retrieval-store.ts +2 -0
- package/src/be/memory/types.ts +46 -0
- package/src/be/migrations/099_memory_structured_key_versioning.sql +41 -0
- package/src/be/migrations/100_memory_retrieval_source.sql +8 -0
- package/src/be/migrations/101_script_connections.sql +67 -0
- package/src/be/script-connections.ts +744 -0
- package/src/be/script-credential-broker.ts +38 -0
- package/src/be/scripts/typecheck.ts +23 -2
- package/src/be/seed-scripts/catalog/boot-triage.inline.ts +16 -4
- package/src/be/seed-scripts/catalog/boot-triage.ts +16 -4
- package/src/commands/runner.ts +8 -6
- package/src/heartbeat/heartbeat.ts +42 -1
- package/src/heartbeat/index.ts +7 -1
- package/src/http/memory.ts +127 -14
- package/src/http/scripts.ts +15 -14
- package/src/scripts-runtime/api-client.ts +100 -0
- package/src/scripts-runtime/api-types.ts +45 -0
- package/src/scripts-runtime/credential-broker/README.md +40 -0
- package/src/scripts-runtime/credential-broker/broker.ts +51 -0
- package/src/scripts-runtime/credential-broker/default-bindings.ts +19 -0
- package/src/scripts-runtime/credential-broker/fetch-patch.ts +102 -0
- package/src/scripts-runtime/credential-broker/index.ts +17 -0
- package/src/scripts-runtime/credential-broker/store.ts +72 -0
- package/src/scripts-runtime/credential-broker/types.ts +54 -0
- package/src/scripts-runtime/ctx.ts +11 -1
- package/src/scripts-runtime/egress-secrets.ts +14 -76
- package/src/scripts-runtime/eval-harness.ts +1 -1
- package/src/scripts-runtime/executors/types.ts +5 -5
- package/src/scripts-runtime/loader.ts +6 -1
- package/src/scripts-runtime/sdk-allowlist.ts +1 -0
- package/src/scripts-runtime/types/stdlib.d.ts +11 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +11 -0
- package/src/server.ts +6 -0
- package/src/tests/credential-broker.test.ts +281 -0
- package/src/tests/heartbeat.test.ts +239 -0
- package/src/tests/memory-edit.test.ts +177 -0
- package/src/tests/memory-hybrid.test.ts +212 -0
- package/src/tests/runner-repo-autostash.test.ts +39 -8
- package/src/tests/script-connections.test.ts +360 -0
- package/src/tests/scripts-http.test.ts +16 -10
- package/src/tests/scripts-runtime-secret-egress.test.ts +26 -5
- package/src/tests/swarm-config-reserved-keys.test.ts +23 -0
- package/src/tests/update-schedule-mcp-tool.test.ts +83 -4
- package/src/tools/credential-bindings/index.ts +1 -0
- package/src/tools/credential-bindings/tool.ts +238 -0
- package/src/tools/memory-edit.ts +148 -0
- package/src/tools/memory-search.ts +17 -10
- package/src/tools/schedules/delete-schedule.ts +18 -8
- package/src/tools/schedules/update-schedule.ts +4 -9
- package/src/tools/script-connections/index.ts +1 -0
- package/src/tools/script-connections/tool.ts +167 -0
- package/src/tools/swarm-config/delete-config.ts +5 -0
- package/src/tools/swarm-config/set-config.ts +23 -1
- package/src/tools/tool-config.ts +6 -1
- package/src/types.ts +6 -0
- package/src/workflows/executors/swarm-script.ts +2 -0
- package/templates/community/dora-metrics/PLAYBOOK.md +294 -0
- package/templates/community/dora-metrics/README.md +39 -0
- package/templates/community/dora-metrics/lead-prompt.md +56 -0
- package/templates/community/dora-metrics/report.mjs +393 -0
- package/templates/community/dora-metrics/run.sh +113 -0
- package/templates/schedules/weekly-dora-metrics/config.json +13 -0
- package/templates/schedules/weekly-dora-metrics/content.md +61 -0
- package/dist/cli-2307phk1.js +0 -24223
- package/dist/cli-2deg0cen.js +0 -120
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
import { getAgentById } from "@/be/db";
|
|
4
|
+
import {
|
|
5
|
+
listScriptConnections,
|
|
6
|
+
setScriptConnectionEnabled,
|
|
7
|
+
upsertCredentialBinding,
|
|
8
|
+
upsertScriptConnection,
|
|
9
|
+
} from "@/be/script-connections";
|
|
10
|
+
import { placeholderForConfigKey } from "@/scripts-runtime/credential-broker";
|
|
11
|
+
import { createToolRegistrar } from "@/tools/utils";
|
|
12
|
+
|
|
13
|
+
const scriptConnectionsInputSchema = z.object({
|
|
14
|
+
action: z
|
|
15
|
+
.enum(["list", "upsert-openapi", "disable"])
|
|
16
|
+
.describe("List, create/update, or disable a script connection."),
|
|
17
|
+
id: z.string().uuid().optional(),
|
|
18
|
+
slug: z.string().min(1).max(80).optional(),
|
|
19
|
+
displayName: z.string().max(160).optional(),
|
|
20
|
+
scope: z.enum(["global", "agent", "repo"]).default("global").optional(),
|
|
21
|
+
scopeId: z.string().uuid().nullable().optional(),
|
|
22
|
+
baseUrl: z.string().url().optional(),
|
|
23
|
+
allowedHosts: z.array(z.string().min(1)).optional(),
|
|
24
|
+
credentialBindingId: z.string().uuid().nullable().optional(),
|
|
25
|
+
configKey: z.string().min(1).max(255).optional(),
|
|
26
|
+
headerTemplate: z.string().min(1).optional(),
|
|
27
|
+
queryTemplate: z.string().min(1).optional(),
|
|
28
|
+
openapiSpecJson: z.string().optional(),
|
|
29
|
+
enabled: z.boolean().default(true).optional(),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const scriptConnectionsOutputSchema = z.object({
|
|
33
|
+
yourAgentId: z.string().uuid().optional(),
|
|
34
|
+
success: z.boolean(),
|
|
35
|
+
message: z.string(),
|
|
36
|
+
connections: z.array(z.unknown()),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const registerScriptConnectionsTool = (server: McpServer) => {
|
|
40
|
+
createToolRegistrar(server)(
|
|
41
|
+
"script-connections",
|
|
42
|
+
{
|
|
43
|
+
title: "Script Connections",
|
|
44
|
+
description:
|
|
45
|
+
"Lead-only registry management for scripts ctx.api/ctx.mcp connections. Phase 1 supports OpenAPI ctx.api connections with generated args and response types.",
|
|
46
|
+
annotations: { idempotentHint: true },
|
|
47
|
+
inputSchema: scriptConnectionsInputSchema,
|
|
48
|
+
outputSchema: scriptConnectionsOutputSchema,
|
|
49
|
+
},
|
|
50
|
+
async (args, requestInfo) => {
|
|
51
|
+
if (!requestInfo.agentId) {
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: "text", text: 'Agent ID not found. Set the "X-Agent-ID" header.' }],
|
|
54
|
+
structuredContent: {
|
|
55
|
+
success: false,
|
|
56
|
+
message: 'Agent ID not found. Set the "X-Agent-ID" header.',
|
|
57
|
+
connections: [],
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const agent = getAgentById(requestInfo.agentId);
|
|
63
|
+
if (!agent?.isLead) {
|
|
64
|
+
return {
|
|
65
|
+
content: [{ type: "text", text: "Only the lead can manage script connections." }],
|
|
66
|
+
structuredContent: {
|
|
67
|
+
yourAgentId: requestInfo.agentId,
|
|
68
|
+
success: false,
|
|
69
|
+
message: "Only the lead can manage script connections.",
|
|
70
|
+
connections: [],
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (args.action === "list") {
|
|
76
|
+
const connections = listScriptConnections({ includeDisabled: true });
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: "text", text: `Found ${connections.length} script connection(s).` }],
|
|
79
|
+
structuredContent: {
|
|
80
|
+
yourAgentId: requestInfo.agentId,
|
|
81
|
+
success: true,
|
|
82
|
+
message: `Found ${connections.length} script connection(s).`,
|
|
83
|
+
connections,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (args.action === "disable") {
|
|
89
|
+
if (!args.id) {
|
|
90
|
+
return {
|
|
91
|
+
content: [{ type: "text", text: "id is required for disable." }],
|
|
92
|
+
structuredContent: {
|
|
93
|
+
yourAgentId: requestInfo.agentId,
|
|
94
|
+
success: false,
|
|
95
|
+
message: "id is required for disable.",
|
|
96
|
+
connections: listScriptConnections({ includeDisabled: true }),
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
setScriptConnectionEnabled(args.id, false);
|
|
101
|
+
const connections = listScriptConnections({ includeDisabled: true });
|
|
102
|
+
return {
|
|
103
|
+
content: [{ type: "text", text: "Script connection disabled." }],
|
|
104
|
+
structuredContent: {
|
|
105
|
+
yourAgentId: requestInfo.agentId,
|
|
106
|
+
success: true,
|
|
107
|
+
message: "Script connection disabled.",
|
|
108
|
+
connections,
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (!args.slug || !args.baseUrl || !args.openapiSpecJson) {
|
|
114
|
+
return {
|
|
115
|
+
content: [{ type: "text", text: "slug, baseUrl, and openapiSpecJson are required." }],
|
|
116
|
+
structuredContent: {
|
|
117
|
+
yourAgentId: requestInfo.agentId,
|
|
118
|
+
success: false,
|
|
119
|
+
message: "slug, baseUrl, and openapiSpecJson are required.",
|
|
120
|
+
connections: listScriptConnections({ includeDisabled: true }),
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let credentialBindingId = args.credentialBindingId ?? null;
|
|
126
|
+
if (!credentialBindingId && args.configKey) {
|
|
127
|
+
const placeholder = placeholderForConfigKey(args.configKey);
|
|
128
|
+
const binding = upsertCredentialBinding({
|
|
129
|
+
configKey: args.configKey,
|
|
130
|
+
allowedHosts: args.allowedHosts ?? [new URL(args.baseUrl).hostname],
|
|
131
|
+
headerTemplate: args.headerTemplate ?? `Authorization: Bearer ${placeholder}`,
|
|
132
|
+
queryTemplate: args.queryTemplate,
|
|
133
|
+
scope: args.scope ?? "global",
|
|
134
|
+
scopeId: args.scope === "global" ? null : (args.scopeId ?? null),
|
|
135
|
+
});
|
|
136
|
+
credentialBindingId = binding.id;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const connection = upsertScriptConnection({
|
|
140
|
+
id: args.id,
|
|
141
|
+
slug: args.slug,
|
|
142
|
+
displayName: args.displayName,
|
|
143
|
+
kind: "openapi",
|
|
144
|
+
scope: args.scope ?? "global",
|
|
145
|
+
scopeId: args.scope === "global" ? null : (args.scopeId ?? null),
|
|
146
|
+
baseUrl: args.baseUrl,
|
|
147
|
+
allowedHosts: args.allowedHosts ?? [new URL(args.baseUrl).hostname],
|
|
148
|
+
credentialBindingId,
|
|
149
|
+
openapiSpecJson: args.openapiSpecJson,
|
|
150
|
+
enabled: args.enabled !== false,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const connections = listScriptConnections({ includeDisabled: true });
|
|
154
|
+
return {
|
|
155
|
+
content: [{ type: "text", text: `Script connection ${connection.slug} saved.` }],
|
|
156
|
+
structuredContent: {
|
|
157
|
+
yourAgentId: requestInfo.agentId,
|
|
158
|
+
success: !connection.generationError,
|
|
159
|
+
message: connection.generationError
|
|
160
|
+
? `Saved but generation failed: ${connection.generationError}`
|
|
161
|
+
: `Script connection ${connection.slug} saved.`,
|
|
162
|
+
connections,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
},
|
|
166
|
+
);
|
|
167
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import * as z from "zod";
|
|
3
3
|
import { deleteSwarmConfig, getSwarmConfigLookupById } from "@/be/db";
|
|
4
|
+
import { scheduleIntegrationsReload } from "@/http/core";
|
|
4
5
|
import { createToolRegistrar } from "@/tools/utils";
|
|
5
6
|
|
|
6
7
|
export const registerDeleteConfigTool = (server: McpServer) => {
|
|
@@ -58,6 +59,10 @@ export const registerDeleteConfigTool = (server: McpServer) => {
|
|
|
58
59
|
};
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
if (existing.scope === "global") {
|
|
63
|
+
scheduleIntegrationsReload();
|
|
64
|
+
}
|
|
65
|
+
|
|
61
66
|
return {
|
|
62
67
|
content: [
|
|
63
68
|
{
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import * as z from "zod";
|
|
3
|
-
import { maskSecrets, upsertSwarmConfig } from "@/be/db";
|
|
3
|
+
import { getAgentById, maskSecrets, upsertSwarmConfig } from "@/be/db";
|
|
4
4
|
import {
|
|
5
5
|
isReservedConfigKey,
|
|
6
6
|
reservedKeyError,
|
|
7
7
|
validateConfigValue,
|
|
8
8
|
} from "@/be/swarm-config-guard";
|
|
9
|
+
import { scheduleIntegrationsReload } from "@/http/core";
|
|
10
|
+
import { CREDENTIAL_BINDINGS_CONFIG_KEY } from "@/scripts-runtime/credential-broker";
|
|
9
11
|
import { createToolRegistrar } from "@/tools/utils";
|
|
10
12
|
import { SwarmConfigSchema, SwarmConfigScopeSchema } from "@/types";
|
|
11
13
|
|
|
@@ -93,6 +95,22 @@ export const registerSetConfigTool = (server: McpServer) => {
|
|
|
93
95
|
};
|
|
94
96
|
}
|
|
95
97
|
|
|
98
|
+
if (key.toUpperCase() === CREDENTIAL_BINDINGS_CONFIG_KEY) {
|
|
99
|
+
const agent = getAgentById(requestInfo.agentId);
|
|
100
|
+
if (!agent?.isLead) {
|
|
101
|
+
const message =
|
|
102
|
+
"Only the lead can manage SCRIPT_CREDENTIAL_BINDINGS. Use the credential-bindings tool.";
|
|
103
|
+
return {
|
|
104
|
+
content: [{ type: "text", text: message }],
|
|
105
|
+
structuredContent: {
|
|
106
|
+
yourAgentId: requestInfo.agentId,
|
|
107
|
+
success: false,
|
|
108
|
+
message,
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
96
114
|
const validationError = validateConfigValue(key, value);
|
|
97
115
|
if (validationError) {
|
|
98
116
|
return {
|
|
@@ -115,6 +133,10 @@ export const registerSetConfigTool = (server: McpServer) => {
|
|
|
115
133
|
description,
|
|
116
134
|
});
|
|
117
135
|
|
|
136
|
+
if (scope === "global") {
|
|
137
|
+
scheduleIntegrationsReload();
|
|
138
|
+
}
|
|
139
|
+
|
|
118
140
|
const [masked] = maskSecrets([config]);
|
|
119
141
|
|
|
120
142
|
return {
|
package/src/tools/tool-config.ts
CHANGED
|
@@ -66,11 +66,16 @@ export const DEFERRED_TOOLS = new Set([
|
|
|
66
66
|
"list-services",
|
|
67
67
|
"update-service-status",
|
|
68
68
|
|
|
69
|
-
// Config (
|
|
69
|
+
// Config (5)
|
|
70
70
|
"set-config",
|
|
71
71
|
"get-config",
|
|
72
72
|
"list-config",
|
|
73
73
|
"delete-config",
|
|
74
|
+
"credential-bindings",
|
|
75
|
+
"script-connections",
|
|
76
|
+
|
|
77
|
+
// Memory (1)
|
|
78
|
+
"memory-edit",
|
|
74
79
|
|
|
75
80
|
// Repos (2)
|
|
76
81
|
"get-repos",
|
package/src/types.ts
CHANGED
|
@@ -1001,6 +1001,8 @@ export const EventNameSchema = z.enum([
|
|
|
1001
1001
|
"system.error",
|
|
1002
1002
|
// Script catalog events
|
|
1003
1003
|
"script.global_upsert",
|
|
1004
|
+
// Schedule events
|
|
1005
|
+
"schedule.deleted",
|
|
1004
1006
|
]);
|
|
1005
1007
|
|
|
1006
1008
|
export const SwarmEventSchema = z.object({
|
|
@@ -1146,6 +1148,7 @@ export const AgentMemorySchema = z.object({
|
|
|
1146
1148
|
id: z.string().uuid(),
|
|
1147
1149
|
agentId: z.string().uuid().nullable(),
|
|
1148
1150
|
scope: AgentMemoryScopeSchema,
|
|
1151
|
+
key: z.string().nullable().optional(),
|
|
1149
1152
|
name: z.string().min(1).max(500),
|
|
1150
1153
|
content: z.string(),
|
|
1151
1154
|
summary: z.string().nullable(),
|
|
@@ -1156,10 +1159,13 @@ export const AgentMemorySchema = z.object({
|
|
|
1156
1159
|
totalChunks: z.number().int().min(1).default(1),
|
|
1157
1160
|
tags: z.array(z.string()),
|
|
1158
1161
|
createdAt: z.string(),
|
|
1162
|
+
updatedAt: z.string().nullable().optional(),
|
|
1159
1163
|
accessedAt: z.string(),
|
|
1160
1164
|
expiresAt: z.string().nullable().optional(),
|
|
1161
1165
|
accessCount: z.number().int().min(0).default(0).optional(),
|
|
1162
1166
|
embeddingModel: z.string().nullable().optional(),
|
|
1167
|
+
contentHash: z.string().nullable().optional(),
|
|
1168
|
+
version: z.number().int().min(1).default(1).optional(),
|
|
1163
1169
|
});
|
|
1164
1170
|
|
|
1165
1171
|
export type AgentMemoryScope = z.infer<typeof AgentMemoryScopeSchema>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { buildScriptCredentialBindings } from "../../be/script-credential-broker";
|
|
2
3
|
import { getScript, getScriptVersion } from "../../be/scripts/db";
|
|
3
4
|
import { DEFAULT_SCRIPT_RESOURCES } from "../../scripts-runtime/executors/types";
|
|
4
5
|
import { runScript } from "../../scripts-runtime/loader";
|
|
@@ -72,6 +73,7 @@ export class SwarmScriptExecutor extends BaseExecutor<
|
|
|
72
73
|
args: config.args,
|
|
73
74
|
fsMode: "none",
|
|
74
75
|
agentId: agentId ?? "workflow",
|
|
76
|
+
egressSecrets: buildScriptCredentialBindings({ agentId: agentId ?? undefined }),
|
|
75
77
|
timeoutMs: config.timeoutMs,
|
|
76
78
|
});
|
|
77
79
|
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# DORA Metrics for Your Codebase, on Autopilot
|
|
2
|
+
|
|
3
|
+
An Agent-Swarm playbook template for running recurring DORA metrics reports on any Git repository that has a reliable deployment tag signal.
|
|
4
|
+
|
|
5
|
+
## What You Get
|
|
6
|
+
|
|
7
|
+
This setup gives your swarm a stable DORA report page for one repository:
|
|
8
|
+
|
|
9
|
+
- Deployment Frequency: release throughput over a configurable window.
|
|
10
|
+
- Lead Time for Changes: median time from commit to the release tag that deployed it.
|
|
11
|
+
- Change Failure Rate: proxy estimate from revert/hotfix-style remediation signals.
|
|
12
|
+
- Failed Deployment Recovery Time: proxy estimate from the failed-release tag to the fixing tag.
|
|
13
|
+
- A weekly refresh that updates the same page in place, so the URL does not change.
|
|
14
|
+
|
|
15
|
+
The key caveat is part of the product: Deployment Frequency and Lead Time for Changes are exact when release tags map to production deployments. Change Failure Rate and Failed Deployment Recovery Time are proxy estimates until you connect a formal incident source.
|
|
16
|
+
|
|
17
|
+
## Template Files
|
|
18
|
+
|
|
19
|
+
The community template lives in `templates/community/dora-metrics/` and contains:
|
|
20
|
+
|
|
21
|
+
- `PLAYBOOK.md`: this playbook.
|
|
22
|
+
- `run.sh`: the parameterized runner.
|
|
23
|
+
- `report.mjs`: the static report generator.
|
|
24
|
+
- `lead-prompt.md`: the copy-paste Lead kickoff prompt.
|
|
25
|
+
|
|
26
|
+
Install shape:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
mkdir -p /workspace/dora-metrics
|
|
30
|
+
cp templates/community/dora-metrics/run.sh /workspace/dora-metrics/
|
|
31
|
+
cp templates/community/dora-metrics/report.mjs /workspace/dora-metrics/
|
|
32
|
+
cp templates/community/dora-metrics/lead-prompt.md /workspace/dora-metrics/
|
|
33
|
+
chmod +x /workspace/dora-metrics/run.sh
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Parameterize each run with environment variables:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
BASE_DIR=/workspace/dora-metrics \
|
|
40
|
+
REPO_NAME=my-repo \
|
|
41
|
+
REPO_URL=https://github.com/OWNER/REPO.git \
|
|
42
|
+
BRANCH=main \
|
|
43
|
+
TAG_PATTERN='v*' \
|
|
44
|
+
WINDOW_DAYS=90 \
|
|
45
|
+
bash /workspace/dora-metrics/run.sh
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Libraries and Runtime Shape
|
|
49
|
+
|
|
50
|
+
The workflow uses:
|
|
51
|
+
|
|
52
|
+
- Git tags: the canonical deployment event, when `TAG_PATTERN` maps 1:1 to production releases.
|
|
53
|
+
- Git commit history: exact commit timestamps used for lead time.
|
|
54
|
+
- GitHub CLI: optional but preferred for merged PR title metadata when identifying hotfix/revert signals.
|
|
55
|
+
- jq: required utility dependency for predictable JSON handling in the runner environment.
|
|
56
|
+
- Node.js: runs `report.mjs`, which computes metrics and writes static `report.html` plus `summary.json`.
|
|
57
|
+
|
|
58
|
+
The generated HTML is static. The only network fetch at view time is D3:
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Template Directory Structure
|
|
65
|
+
|
|
66
|
+
Use a workspace outside the target repository so report artifacts do not pollute the codebase:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
/workspace/dora-metrics/
|
|
70
|
+
run.sh
|
|
71
|
+
report.mjs
|
|
72
|
+
lead-prompt.md
|
|
73
|
+
repos/
|
|
74
|
+
<repo-name>/ # scratch clone, push URL disabled
|
|
75
|
+
out/
|
|
76
|
+
<repo-name>/
|
|
77
|
+
<YYYY-MM-DD>/
|
|
78
|
+
tags.tsv
|
|
79
|
+
recent-commits.tsv
|
|
80
|
+
remediation-commits.tsv
|
|
81
|
+
prs.json
|
|
82
|
+
revision.txt
|
|
83
|
+
revision-summary.txt
|
|
84
|
+
summary.json
|
|
85
|
+
report.html
|
|
86
|
+
latest-pointer.json
|
|
87
|
+
latest.json
|
|
88
|
+
latest.html
|
|
89
|
+
latest-pointer.json
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## First-Run Behavior
|
|
93
|
+
|
|
94
|
+
`run.sh` does the following:
|
|
95
|
+
|
|
96
|
+
- Installs `git`, `jq`, and `nodejs` if missing.
|
|
97
|
+
- Clones the target repository into a scratch directory.
|
|
98
|
+
- Disables the scratch clone push URL so the scheduled job cannot push accidentally.
|
|
99
|
+
- Fetches the configured branch and release tags matching `TAG_PATTERN`.
|
|
100
|
+
- Writes release tag, recent commit, remediation commit, and optional PR metadata.
|
|
101
|
+
- Runs `report.mjs`.
|
|
102
|
+
- Copies the latest artifacts to stable `latest.html`, `latest.json`, and `latest-pointer.json` paths.
|
|
103
|
+
|
|
104
|
+
## Runner Parameters
|
|
105
|
+
|
|
106
|
+
Set these variables before calling `run.sh`:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
BASE_DIR=/workspace/dora-metrics
|
|
110
|
+
REPO_NAME=my-repo
|
|
111
|
+
REPO_URL=https://github.com/OWNER/REPO.git
|
|
112
|
+
BRANCH=main
|
|
113
|
+
TAG_PATTERN='v*'
|
|
114
|
+
WINDOW_DAYS=90
|
|
115
|
+
HOTFIX_WINDOW_HOURS=24
|
|
116
|
+
LOCAL_SOURCE= # optional local git clone seed
|
|
117
|
+
RUN_DATE=2026-06-26 # optional, defaults to current UTC date
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The runner extracts release tags with:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
git -C "$REPO_DIR" for-each-ref "refs/tags/$TAG_PATTERN" --sort=creatordate --format='%(refname:short)%09%(objectname)%09%(creatordate:iso-strict)%09%(creatordate:unix)'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
It extracts remediation signals with:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
git -C "$REPO_DIR" log "origin/$BRANCH" --since="$WINDOW_DAYS days ago" --grep='revert' --grep='rollback' --grep='hotfix' --grep='fix-forward' --regexp-ignore-case
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
When authenticated, it also asks `gh pr list` for merged PR titles so hotfix-style PRs can contribute to the proxy stability keys.
|
|
133
|
+
|
|
134
|
+
## Metric Definitions and Bands
|
|
135
|
+
|
|
136
|
+
The report uses the four DORA keys and 2024 performance bands as configurable constants in `report.mjs`.
|
|
137
|
+
|
|
138
|
+
| Metric | Source | Quality | Band logic |
|
|
139
|
+
|---|---|---|---|
|
|
140
|
+
| Deployment Frequency | `TAG_PATTERN` release tags in the window | EXACT | Elite: at least daily. High: daily to weekly. Medium: weekly to monthly. Low: slower. |
|
|
141
|
+
| Lead Time for Changes | Commit timestamp to containing release tag timestamp | EXACT | Elite: under 1 day. High: 1 day to 1 week. Medium: 1 week to 1 month. Low: slower. |
|
|
142
|
+
| Change Failure Rate | Releases paired to revert, rollback, hotfix, or fix-forward signals | PROXY | 2024 cluster thresholds: ~5%, ~20%, ~10%, ~40%. Medium's lower CFR than High is a known 2024 cluster anomaly. |
|
|
143
|
+
| Failed Deployment Recovery Time | Failed-release proxy tag to fixing tag | PROXY | Elite: under 1 hour. High/Medium: under 1 day. Low: slower. |
|
|
144
|
+
|
|
145
|
+
The stability keys are intentionally labeled as proxy/estimated because a release tag plus commit/PR title heuristic is not an incident tracker. It can undercount fix-forward/manual incidents and overcount ordinary fixes.
|
|
146
|
+
|
|
147
|
+
## Report Generator
|
|
148
|
+
|
|
149
|
+
`report.mjs` parses the runner outputs, computes the four metrics, and embeds the final data in a static HTML file.
|
|
150
|
+
|
|
151
|
+
The generator interface:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
node /workspace/dora-metrics/report.mjs \
|
|
155
|
+
/workspace/dora-metrics/out/<repo-name>/<YYYY-MM-DD> \
|
|
156
|
+
/workspace/dora-metrics/repos/<repo-name> \
|
|
157
|
+
<repo-name> \
|
|
158
|
+
<YYYY-MM-DD> \
|
|
159
|
+
<BRANCH> \
|
|
160
|
+
<WINDOW_DAYS> \
|
|
161
|
+
<HOTFIX_WINDOW_HOURS> \
|
|
162
|
+
<TAG_PATTERN>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The generated report includes:
|
|
166
|
+
|
|
167
|
+
- Four DORA metric cards.
|
|
168
|
+
- `EXACT` / `PROXY` quality labels.
|
|
169
|
+
- Deployment and lead-time charts.
|
|
170
|
+
- Recent deployments table.
|
|
171
|
+
- Proxy remediation signal table.
|
|
172
|
+
- D3 v7 loaded from CDN at view time.
|
|
173
|
+
|
|
174
|
+
## Step-by-Step Playbook
|
|
175
|
+
|
|
176
|
+
1. Confirm the deployment signal.
|
|
177
|
+
|
|
178
|
+
The default assumes `v*` tags map 1:1 to production releases. If your repository tags packages without deploying them, stop and configure a better deployment signal before using this template.
|
|
179
|
+
|
|
180
|
+
2. Install the template.
|
|
181
|
+
|
|
182
|
+
Copy `run.sh`, `report.mjs`, and `lead-prompt.md` from `templates/community/dora-metrics/` into `/workspace/dora-metrics`, then make the runner executable.
|
|
183
|
+
|
|
184
|
+
3. Run it once manually.
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
BASE_DIR=/workspace/dora-metrics \
|
|
188
|
+
REPO_NAME=my-repo \
|
|
189
|
+
REPO_URL=https://github.com/OWNER/REPO.git \
|
|
190
|
+
BRANCH=main \
|
|
191
|
+
TAG_PATTERN='v*' \
|
|
192
|
+
WINDOW_DAYS=90 \
|
|
193
|
+
bash /workspace/dora-metrics/run.sh
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
4. Review local output.
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
ls /workspace/dora-metrics/out/my-repo/latest.html
|
|
200
|
+
ls /workspace/dora-metrics/out/my-repo/latest.json
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
5. Publish the HTML to your swarm page system.
|
|
204
|
+
|
|
205
|
+
Create the page once, then store the returned stable page ID somewhere your scheduled task can read it. On later runs, update that same page by ID instead of creating a new page.
|
|
206
|
+
|
|
207
|
+
```text
|
|
208
|
+
First run:
|
|
209
|
+
create page from /workspace/dora-metrics/out/my-repo/latest.html
|
|
210
|
+
save PAGE_ID=<stable-page-id>
|
|
211
|
+
|
|
212
|
+
Later runs:
|
|
213
|
+
update page PAGE_ID with /workspace/dora-metrics/out/my-repo/latest.html
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
6. Wire a weekly schedule.
|
|
217
|
+
|
|
218
|
+
Use a code-capable worker because this job may need to repair the script when upstream repo conventions, branch names, tag patterns, or page APIs change.
|
|
219
|
+
|
|
220
|
+
```yaml
|
|
221
|
+
name: weekly-dora-metrics
|
|
222
|
+
cadence:
|
|
223
|
+
cron: "0 22 * * 0"
|
|
224
|
+
timezone: "UTC"
|
|
225
|
+
target:
|
|
226
|
+
worker: "<code-capable-worker>"
|
|
227
|
+
env:
|
|
228
|
+
BASE_DIR: "/workspace/dora-metrics"
|
|
229
|
+
REPO_NAME: "my-repo"
|
|
230
|
+
REPO_URL: "https://github.com/OWNER/REPO.git"
|
|
231
|
+
BRANCH: "main"
|
|
232
|
+
TAG_PATTERN: "v*"
|
|
233
|
+
WINDOW_DAYS: "90"
|
|
234
|
+
HOTFIX_WINDOW_HOURS: "24"
|
|
235
|
+
PAGE_ID: "<stable-page-id>"
|
|
236
|
+
task:
|
|
237
|
+
- run /workspace/dora-metrics/run.sh
|
|
238
|
+
- update the existing page PAGE_ID in place with latest.html
|
|
239
|
+
- verify D3 charts render and the exact/proxy labels are visible
|
|
240
|
+
- if the run fails, diagnose and repair the runner/report generator before reporting failure
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
7. Keep the same page URL.
|
|
244
|
+
|
|
245
|
+
The report should update in place. The page URL should not change between weekly runs.
|
|
246
|
+
|
|
247
|
+
## Copy-Paste Lead Prompt
|
|
248
|
+
|
|
249
|
+
The canonical copy lives in `lead-prompt.md` in the template and is also included below so this playbook can stand alone.
|
|
250
|
+
|
|
251
|
+
# Lead Kickoff Prompt
|
|
252
|
+
|
|
253
|
+
Copy this into your agent-swarm Lead to bootstrap the recurring report.
|
|
254
|
+
|
|
255
|
+
```text
|
|
256
|
+
Bootstrap a recurring DORA metrics report for my repository.
|
|
257
|
+
|
|
258
|
+
Parameters:
|
|
259
|
+
- Repository URL: <REPO_URL>
|
|
260
|
+
- Default branch: <BRANCH>
|
|
261
|
+
- Release tag pattern: <TAG_PATTERN, default v*>
|
|
262
|
+
- Report name/slug: <REPORT_NAME>
|
|
263
|
+
- Analysis window: <WINDOW_DAYS, default 90>
|
|
264
|
+
- Hotfix/revert matching window: <HOTFIX_WINDOW_HOURS, default 24>
|
|
265
|
+
- Cadence: weekly by default, cron "0 22 * * 0" in <TIMEZONE>
|
|
266
|
+
- Stable page behavior: create the page once, then update the same page ID in place on every run.
|
|
267
|
+
|
|
268
|
+
Requirements:
|
|
269
|
+
1. Work outside the target repository under /workspace/dora-metrics.
|
|
270
|
+
2. Install the community template files there: run.sh, report.mjs, and lead-prompt.md.
|
|
271
|
+
3. Clone the repository into /workspace/dora-metrics/repos/<REPORT_NAME>, disable its push URL, fetch the requested branch, and fetch release tags matching <TAG_PATTERN>.
|
|
272
|
+
4. Treat <TAG_PATTERN> tags as production deployments only if they map 1:1 to production releases.
|
|
273
|
+
5. Compute Deployment Frequency and Lead Time for Changes exactly from tags and commits.
|
|
274
|
+
6. Compute Change Failure Rate and Failed Deployment Recovery Time as proxy estimates from revert/hotfix signals.
|
|
275
|
+
7. Label CFR and recovery time as proxy/estimated everywhere. Do not present them as precise incident metrics unless a formal incident source is added.
|
|
276
|
+
8. Publish the first report as a swarm page and persist its stable page ID in the workflow configuration.
|
|
277
|
+
9. Create a weekly schedule that executes run.sh, updates the same page ID, verifies render, and self-repairs local runner/report failures.
|
|
278
|
+
10. Do not push any PR unless I explicitly ask for a versioned repository change.
|
|
279
|
+
|
|
280
|
+
Deliver back:
|
|
281
|
+
- The stable page URL.
|
|
282
|
+
- The workspace paths for run.sh, report.mjs, latest.html, and latest.json.
|
|
283
|
+
- The schedule name, cron, timezone, and how to change them.
|
|
284
|
+
- A one-line caveat naming which metrics are exact and which are proxy estimates.
|
|
285
|
+
- Any prerequisites or assumptions you could not satisfy automatically.
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## References
|
|
289
|
+
|
|
290
|
+
- [DORA metrics guide](https://dora.dev/guides/dora-metrics/): official definitions for Deployment Frequency, Lead Time for Changes, Change Failure Rate, and Failed Deployment Recovery Time.
|
|
291
|
+
- [2024 Accelerate State of DevOps Report](https://dora.dev/research/2024/dora-report/): 2024 performance bands and cluster-analysis context.
|
|
292
|
+
- [DORA research program](https://dora.dev/research/): background on the annual DORA reports and metric evolution.
|
|
293
|
+
- [GitHub CLI](https://cli.github.com/manual/): optional PR metadata source used to enrich hotfix/revert proxy detection.
|
|
294
|
+
- [D3.js](https://d3js.org): JavaScript library used for the browser-side charts.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# DORA Metrics for Your Codebase, on Autopilot
|
|
2
|
+
|
|
3
|
+
Community template for running recurring DORA metrics reports from an agent-swarm instance.
|
|
4
|
+
|
|
5
|
+
Files:
|
|
6
|
+
|
|
7
|
+
- `PLAYBOOK.md`: end-to-end setup and weekly schedule playbook.
|
|
8
|
+
- `run.sh`: parameterized runner for any Git repository that uses release tags.
|
|
9
|
+
- `report.mjs`: static HTML + JSON report generator.
|
|
10
|
+
- `lead-prompt.md`: copy-paste prompt for your agent-swarm Lead.
|
|
11
|
+
|
|
12
|
+
Quick start:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
mkdir -p /workspace/dora-metrics
|
|
16
|
+
cp run.sh report.mjs lead-prompt.md /workspace/dora-metrics/
|
|
17
|
+
chmod +x /workspace/dora-metrics/run.sh
|
|
18
|
+
|
|
19
|
+
BASE_DIR=/workspace/dora-metrics \
|
|
20
|
+
REPO_NAME=my-repo \
|
|
21
|
+
REPO_URL=https://github.com/OWNER/REPO.git \
|
|
22
|
+
BRANCH=main \
|
|
23
|
+
TAG_PATTERN='v*' \
|
|
24
|
+
WINDOW_DAYS=90 \
|
|
25
|
+
bash /workspace/dora-metrics/run.sh
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Default weekly schedule cadence:
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
cron: "0 22 * * 0"
|
|
32
|
+
timezone: "UTC"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Change the `cron` field to adjust when the report refreshes. Keep the same page ID when publishing refreshes so the report URL remains stable.
|
|
36
|
+
|
|
37
|
+
Deployment Frequency and Lead Time for Changes are exact when `TAG_PATTERN` maps 1:1 to production releases. Change Failure Rate and Failed Deployment Recovery Time are proxy estimates from revert/hotfix signals and are labeled that way in the generated report.
|
|
38
|
+
|
|
39
|
+
See `PLAYBOOK.md` for the full setup flow, references, and metric-definition notes.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Lead Kickoff Prompt
|
|
2
|
+
|
|
3
|
+
Copy this into your agent-swarm Lead to bootstrap the recurring report.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
Bootstrap a recurring DORA metrics report for my repository.
|
|
7
|
+
|
|
8
|
+
Parameters:
|
|
9
|
+
- Repository URL: <REPO_URL>
|
|
10
|
+
- Default branch: <BRANCH>
|
|
11
|
+
- Release tag pattern: <TAG_PATTERN, default v*>
|
|
12
|
+
- Report name/slug: <REPORT_NAME>
|
|
13
|
+
- Analysis window: <WINDOW_DAYS, default 90>
|
|
14
|
+
- Hotfix/revert matching window: <HOTFIX_WINDOW_HOURS, default 24>
|
|
15
|
+
- Cadence: weekly by default, cron "0 22 * * 0" in <TIMEZONE>
|
|
16
|
+
- Stable page behavior: create the page once, then update the same page ID in place on every run.
|
|
17
|
+
|
|
18
|
+
Requirements:
|
|
19
|
+
1. Work outside the target repository under /workspace/dora-metrics.
|
|
20
|
+
2. Install the community template files there:
|
|
21
|
+
- run.sh
|
|
22
|
+
- report.mjs
|
|
23
|
+
- lead-prompt.md
|
|
24
|
+
3. On first run, install missing runtime dependencies:
|
|
25
|
+
- git
|
|
26
|
+
- jq
|
|
27
|
+
- Node.js
|
|
28
|
+
- GitHub CLI is optional but preferred for PR title metadata.
|
|
29
|
+
4. Clone the repository into /workspace/dora-metrics/repos/<REPORT_NAME>, disable its push URL, fetch the requested branch, and fetch release tags matching <TAG_PATTERN>.
|
|
30
|
+
5. Treat <TAG_PATTERN> tags as production deployments only if they map 1:1 to production releases. If they do not, stop and ask for the correct deployment signal.
|
|
31
|
+
6. Compute the four DORA keys:
|
|
32
|
+
- Deployment Frequency: EXACT from release tags.
|
|
33
|
+
- Lead Time for Changes: EXACT from commit timestamps to the containing release tag.
|
|
34
|
+
- Change Failure Rate: PROXY from revert, rollback, hotfix, and fix-forward signals near release tags.
|
|
35
|
+
- Failed Deployment Recovery Time: PROXY from failed-release proxy tag to fixing tag.
|
|
36
|
+
7. Label CFR and recovery time as proxy/estimated everywhere. Do not present them as precise incident metrics unless a formal incident source is added.
|
|
37
|
+
8. Generate a static report with:
|
|
38
|
+
- Four DORA metric cards.
|
|
39
|
+
- EXACT/PROXY quality labels.
|
|
40
|
+
- Deployment and lead-time charts.
|
|
41
|
+
- Recent deployments table.
|
|
42
|
+
- Proxy remediation signal table.
|
|
43
|
+
9. Publish the first report as a swarm page and persist its stable page ID in the workflow configuration.
|
|
44
|
+
10. Create a schedule pinned to a code-capable worker:
|
|
45
|
+
- Default cadence: weekly, cron "0 22 * * 0".
|
|
46
|
+
- To change the cadence, edit the cron field and timezone only.
|
|
47
|
+
- Each run executes run.sh, updates the same page ID in place, verifies the page renders, and self-repairs the runner/report if the failure is local and fixable.
|
|
48
|
+
11. Do not push any PR unless I explicitly ask for a versioned repository change.
|
|
49
|
+
|
|
50
|
+
Deliver back:
|
|
51
|
+
- The stable page URL.
|
|
52
|
+
- The workspace paths for run.sh, report.mjs, latest.html, and latest.json.
|
|
53
|
+
- The schedule name, cron, timezone, and how to change them.
|
|
54
|
+
- A one-line caveat naming which metrics are exact and which are proxy estimates.
|
|
55
|
+
- Any prerequisites or assumptions you could not satisfy automatically.
|
|
56
|
+
```
|