murmur8 4.5.0 → 4.6.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/.blueprint/features/feature_feedback-test/FEATURE_SPEC.md +229 -0
- package/.blueprint/features/feature_feedback-test/IMPLEMENTATION_PLAN.md +25 -0
- package/.blueprint/features/feature_feedback-test/handoff-alex.md +20 -0
- package/.blueprint/features/feature_feedback-test/handoff-cass.md +21 -0
- package/.blueprint/features/feature_feedback-test/handoff-nigel.md +20 -0
- package/.blueprint/features/feature_feedback-test/story-config-management.md +103 -0
- package/.blueprint/features/feature_feedback-test/story-parse-pipeline.md +65 -0
- package/.blueprint/features/feature_feedback-test/story-validation-normalisation.md +99 -0
- package/.blueprint/features/feature_pipeline-telemetry/FEATURE_SPEC.md +297 -0
- package/.blueprint/features/feature_pipeline-telemetry/IMPLEMENTATION_PLAN.md +34 -0
- package/.blueprint/features/feature_pipeline-telemetry/handoff-alex.md +21 -0
- package/.blueprint/features/feature_pipeline-telemetry/handoff-cass.md +25 -0
- package/.blueprint/features/feature_pipeline-telemetry/handoff-nigel.md +20 -0
- package/.blueprint/features/feature_pipeline-telemetry/story-failed-queue-retry.md +53 -0
- package/.blueprint/features/feature_pipeline-telemetry/story-identifiers.md +47 -0
- package/.blueprint/features/feature_pipeline-telemetry/story-init-integration.md +48 -0
- package/.blueprint/features/feature_pipeline-telemetry/story-payload-send.md +54 -0
- package/.blueprint/features/feature_pipeline-telemetry/story-telemetry-activation.md +54 -0
- package/.blueprint/features/feature_pipeline-telemetry/story-telemetry-config-command.md +52 -0
- package/README.md +54 -0
- package/SKILL.md +35 -24
- package/package.json +1 -1
- package/src/commands/history.js +41 -2
- package/src/commands/telemetry-config.js +16 -0
- package/src/history.js +31 -0
- package/src/index.js +16 -1
- package/src/init.js +5 -0
- package/src/telemetry.js +198 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
---
|
|
2
|
+
featureId: a3f8c2d1-7e54-4b09-8f16-23a1e5d94c72
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Feature Specification — Pipeline Telemetry
|
|
6
|
+
|
|
7
|
+
## 1. Feature Intent
|
|
8
|
+
|
|
9
|
+
**Why this feature exists.**
|
|
10
|
+
|
|
11
|
+
- **Problem being addressed:** Teams using murmur8 have no visibility into pipeline usage across projects or over time at an aggregate level. Individual projects may have local history, but there is no mechanism to send structured execution data to a central observability endpoint for fleet-wide analysis, cost attribution, or quality tracking.
|
|
12
|
+
- **User need:** Platform teams and administrators want to understand how murmur8 is being used — which features succeed or fail, how long stages take, and whether quality is improving. This is opt-in by configuration, not mandated.
|
|
13
|
+
- **System purpose alignment:** Per SYSTEM_SPEC.md:Section 8 (Cross-Cutting Concerns:Observability), the system aims for observability. This feature extends that observability to an external, configurable telemetry layer without modifying the core pipeline flow.
|
|
14
|
+
|
|
15
|
+
> This feature reinforces the system's observability goals and does not alter pipeline behaviour. It is completely silent when no endpoint is configured.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 2. Scope
|
|
20
|
+
|
|
21
|
+
### In Scope
|
|
22
|
+
|
|
23
|
+
- Sending a structured JSON event payload via HTTP POST to a configurable telemetry endpoint at the end of each pipeline run
|
|
24
|
+
- Reading endpoint URL and API key from `.env` file and real environment variables (env vars take precedence)
|
|
25
|
+
- Non-blocking send: failures never interrupt the pipeline
|
|
26
|
+
- Queuing failed sends to `.claude/telemetry-failed.json`; retrying queued sends at the start of the next pipeline run
|
|
27
|
+
- Compressing artifact content (FEATURE_SPEC.md and story files) with zlib gzip + base64 before inclusion in payload
|
|
28
|
+
- Generating a `runId` (UUID v4) at pipeline start for correlating events
|
|
29
|
+
- Writing a `featureId` (UUID v4) into FEATURE_SPEC.md YAML frontmatter by Alex on first creation; stable across retries
|
|
30
|
+
- New CLI command `murmur8 telemetry-config` to display current telemetry configuration
|
|
31
|
+
- `init` command creating/appending a commented-out telemetry template to `.env` and ensuring `.env` is in `.gitignore`
|
|
32
|
+
- Exporting telemetry functions from `src/index.js`
|
|
33
|
+
- Storing `runId` in the history entry
|
|
34
|
+
|
|
35
|
+
### Out of Scope
|
|
36
|
+
|
|
37
|
+
- An opt-out flag (presence of URL = opt-in; absence = opt-out)
|
|
38
|
+
- Real-time or streaming telemetry (end-of-run POST only)
|
|
39
|
+
- Telemetry for non-pipeline CLI commands (e.g., `history`, `queue`)
|
|
40
|
+
- Encryption of payload beyond HTTPS transport
|
|
41
|
+
- Telemetry dashboard or receiver implementation
|
|
42
|
+
- dotenv or any third-party `.env` parsing dependency (manual parsing only)
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 3. Actors Involved
|
|
47
|
+
|
|
48
|
+
### Human User / Administrator
|
|
49
|
+
|
|
50
|
+
- **Can do:** Configure telemetry endpoint and key via `.env`; view telemetry config via `murmur8 telemetry-config`; remove config to disable
|
|
51
|
+
- **Cannot do:** Trigger telemetry manually; view the contents of failed send queue via CLI (file inspection only)
|
|
52
|
+
|
|
53
|
+
### Pipeline Orchestrator (internal)
|
|
54
|
+
|
|
55
|
+
- **Can do:** Generate `runId` at pipeline start; call telemetry send at pipeline end; enqueue failed sends; retry failed sends at start of next run
|
|
56
|
+
- **Cannot do:** Block pipeline on telemetry failure; modify payload after send attempt
|
|
57
|
+
|
|
58
|
+
### Alex Agent (internal)
|
|
59
|
+
|
|
60
|
+
- **Can do:** Write `featureId` UUID into FEATURE_SPEC.md YAML frontmatter on first creation; preserve existing `featureId` on re-runs
|
|
61
|
+
- **Cannot do:** Regenerate `featureId` if one already exists
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 4. Behaviour Overview
|
|
66
|
+
|
|
67
|
+
### Happy-path behaviour
|
|
68
|
+
|
|
69
|
+
1. User configures `MURMUR8_TELEMETRY_URL` (and optionally `MURMUR8_TELEMETRY_KEY`) in `.env` or as real environment variables
|
|
70
|
+
2. At pipeline start (Step 5 of SKILL.md), orchestrator generates a `runId` UUID v4 and stores it in working context
|
|
71
|
+
3. Alex writes a `featureId` UUID into FEATURE_SPEC.md YAML frontmatter (if not already present)
|
|
72
|
+
4. Pipeline executes normally; timings, stage statuses, and feedback are collected as usual
|
|
73
|
+
5. At pipeline end (Step 12 of SKILL.md), `src/telemetry.js` builds the payload, compresses artifacts, and POSTs to the configured URL
|
|
74
|
+
6. On success, no user-visible output occurs (silent)
|
|
75
|
+
7. On failure, the payload is appended to `.claude/telemetry-failed.json` silently
|
|
76
|
+
|
|
77
|
+
### Key alternatives or branches
|
|
78
|
+
|
|
79
|
+
- **No URL configured:** Telemetry module does nothing; pipeline continues as normal
|
|
80
|
+
- **Send failure (network error, non-2xx response):** Payload written to failed queue; no pipeline interruption
|
|
81
|
+
- **Retry at next run start:** Any entries in `.claude/telemetry-failed.json` are attempted before the new run proceeds; failures remain in queue
|
|
82
|
+
- **`--no-feedback` flag used:** `feedback` block omitted from payload
|
|
83
|
+
- **`featureId` already present in FEATURE_SPEC.md:** Alex preserves existing value; does not regenerate
|
|
84
|
+
|
|
85
|
+
### User-visible outcomes
|
|
86
|
+
|
|
87
|
+
- No output when telemetry is working correctly (fully silent)
|
|
88
|
+
- `murmur8 telemetry-config` shows configured URL (masked key), retry queue depth
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 5. State & Lifecycle Interactions
|
|
93
|
+
|
|
94
|
+
### States entered
|
|
95
|
+
|
|
96
|
+
- **telemetry_pending:** `runId` generated at pipeline start; stored in working context
|
|
97
|
+
- **telemetry_sent:** Payload successfully POSTed at pipeline end
|
|
98
|
+
- **telemetry_queued:** Send failed; payload appended to `.claude/telemetry-failed.json`
|
|
99
|
+
|
|
100
|
+
### States modified
|
|
101
|
+
|
|
102
|
+
- `featureId` written into FEATURE_SPEC.md frontmatter (by Alex, on first run only)
|
|
103
|
+
- History entry extended with `runId` field
|
|
104
|
+
- `.claude/telemetry-failed.json` appended to on send failure; entries removed on successful retry
|
|
105
|
+
|
|
106
|
+
### This feature is:
|
|
107
|
+
|
|
108
|
+
- **State-creating:** Creates `runId` per run; may create `telemetry-failed.json`
|
|
109
|
+
- **State-transitioning:** Moves failed payloads from queued → sent on retry
|
|
110
|
+
- **Not state-constraining:** Does not block any pipeline operations
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 6. Rules & Decision Logic
|
|
115
|
+
|
|
116
|
+
### Rule: Telemetry Activation
|
|
117
|
+
|
|
118
|
+
- **Description:** Telemetry is active if and only if `MURMUR8_TELEMETRY_URL` is set (non-empty) in `.env` or real env
|
|
119
|
+
- **Inputs:** Presence and value of `MURMUR8_TELEMETRY_URL`
|
|
120
|
+
- **Outputs:** Active or inactive module
|
|
121
|
+
- **Deterministic:** Yes
|
|
122
|
+
|
|
123
|
+
### Rule: Environment Variable Precedence
|
|
124
|
+
|
|
125
|
+
- **Description:** Real environment variables take precedence over `.env` file values for both `MURMUR8_TELEMETRY_URL` and `MURMUR8_TELEMETRY_KEY`
|
|
126
|
+
- **Inputs:** `process.env` values, `.env` file parse result
|
|
127
|
+
- **Outputs:** Resolved URL and key
|
|
128
|
+
- **Deterministic:** Yes
|
|
129
|
+
|
|
130
|
+
### Rule: runId Generation
|
|
131
|
+
|
|
132
|
+
- **Description:** A new UUID v4 `runId` is generated at Step 5 of SKILL.md for every pipeline run, regardless of whether telemetry is active
|
|
133
|
+
- **Inputs:** None (random UUID)
|
|
134
|
+
- **Outputs:** UUID v4 string stored in working context and history entry
|
|
135
|
+
- **Deterministic:** No (random)
|
|
136
|
+
|
|
137
|
+
### Rule: featureId Stability
|
|
138
|
+
|
|
139
|
+
- **Description:** `featureId` is written by Alex into FEATURE_SPEC.md frontmatter on first creation. If FEATURE_SPEC.md already contains a `featureId`, it must not be changed.
|
|
140
|
+
- **Inputs:** Existing FEATURE_SPEC.md content
|
|
141
|
+
- **Outputs:** Frontmatter with stable `featureId`
|
|
142
|
+
- **Deterministic:** Yes (preserves existing); No for initial generation (random UUID)
|
|
143
|
+
|
|
144
|
+
### Rule: Non-blocking Send
|
|
145
|
+
|
|
146
|
+
- **Description:** The HTTP POST to the telemetry endpoint must not block or throw into the pipeline. Any network or HTTP error results in silent queue, not pipeline abort.
|
|
147
|
+
- **Inputs:** HTTP response code, network errors
|
|
148
|
+
- **Outputs:** Success (silent) or enqueue to failed queue (silent)
|
|
149
|
+
- **Deterministic:** Yes
|
|
150
|
+
|
|
151
|
+
### Rule: Failed Queue Retry
|
|
152
|
+
|
|
153
|
+
- **Description:** At the start of each pipeline run (before Step 1 processing), any entries in `.claude/telemetry-failed.json` are attempted. Successfully sent entries are removed; failures remain.
|
|
154
|
+
- **Inputs:** Contents of `.claude/telemetry-failed.json`
|
|
155
|
+
- **Outputs:** Updated queue file (or file removed if empty)
|
|
156
|
+
- **Deterministic:** Yes
|
|
157
|
+
|
|
158
|
+
### Rule: Artifact Compression
|
|
159
|
+
|
|
160
|
+
- **Description:** FEATURE_SPEC.md and any `story-*.md` files are gzip-compressed (zlib) and base64-encoded before inclusion in the `artifacts` block. Each file is keyed by its filename.
|
|
161
|
+
- **Inputs:** File contents
|
|
162
|
+
- **Outputs:** `{ "filename": "<base64-gzip>" }` per file
|
|
163
|
+
- **Deterministic:** Yes (given same input)
|
|
164
|
+
|
|
165
|
+
### Rule: Authorization Header
|
|
166
|
+
|
|
167
|
+
- **Description:** If `MURMUR8_TELEMETRY_KEY` is set, it is sent as `Authorization: Bearer <key>` header. If not set, the header is omitted.
|
|
168
|
+
- **Inputs:** Key value
|
|
169
|
+
- **Outputs:** HTTP Authorization header presence
|
|
170
|
+
- **Deterministic:** Yes
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 7. Dependencies
|
|
175
|
+
|
|
176
|
+
### System components
|
|
177
|
+
|
|
178
|
+
- `src/history.js` — Must pass `runId` to the history entry write
|
|
179
|
+
- `SKILL.md` Step 5 — Must generate `runId`; Step 12 — Must call telemetry send
|
|
180
|
+
- `src/init.js` — Must create/append `.env` template and update `.gitignore`
|
|
181
|
+
- `bin/cli.js` — Must register `telemetry-config` command
|
|
182
|
+
- `src/index.js` — Must export telemetry functions
|
|
183
|
+
|
|
184
|
+
### External systems
|
|
185
|
+
|
|
186
|
+
- Configurable HTTP/HTTPS endpoint (operator-supplied); must accept POST with JSON body
|
|
187
|
+
- zlib (Node.js built-in) — for gzip compression
|
|
188
|
+
- Node.js `crypto` module (built-in) — for UUID v4 generation
|
|
189
|
+
- Node.js `https`/`http` modules (built-in) — for HTTP POST; no external HTTP library
|
|
190
|
+
|
|
191
|
+
### Operational dependencies
|
|
192
|
+
|
|
193
|
+
- `.env` file at project root (optional; telemetry inactive if absent or URL not set)
|
|
194
|
+
- File system access to `.claude/` directory for failed queue
|
|
195
|
+
- Network access to configured endpoint (no hard dependency — failures are tolerated)
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 8. Non-Functional Considerations
|
|
200
|
+
|
|
201
|
+
### Performance sensitivity
|
|
202
|
+
|
|
203
|
+
- Telemetry send is fire-and-forget (async, non-blocking); it must not add measurable latency to the user-visible pipeline completion
|
|
204
|
+
- Artifact compression is performed in-process; acceptable for typical spec file sizes (<50 KB combined)
|
|
205
|
+
|
|
206
|
+
### Audit/logging needs
|
|
207
|
+
|
|
208
|
+
- The telemetry payload itself constitutes a structured audit record
|
|
209
|
+
- `runId` links telemetry events to local history entries for cross-referencing
|
|
210
|
+
- `featureId` provides stable identity across retries of the same feature
|
|
211
|
+
|
|
212
|
+
### Error tolerance
|
|
213
|
+
|
|
214
|
+
- Send failures must be fully silent to the user (no output, no pipeline interruption)
|
|
215
|
+
- Failed queue must not grow unboundedly — implementations should consider a maximum retry depth (e.g., 50 entries), dropping oldest on overflow; exact limit is an implementation decision
|
|
216
|
+
|
|
217
|
+
### Security implications
|
|
218
|
+
|
|
219
|
+
- `MURMUR8_TELEMETRY_KEY` must never be logged or displayed in plaintext; `telemetry-config` command must mask the key (e.g., `sk-****1234`)
|
|
220
|
+
- `.env` file must be added to `.gitignore` by the `init` command to prevent accidental credential commit
|
|
221
|
+
- `gitEmail` and `repoUrl` are included in the identity block; operators must be aware these are transmitted to the configured endpoint
|
|
222
|
+
- Payload transmitted over HTTPS (URL is operator-configured; framework does not enforce HTTPS but should warn if `http://` is used)
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 9. Assumptions & Open Questions
|
|
227
|
+
|
|
228
|
+
### Assumptions
|
|
229
|
+
|
|
230
|
+
- ASSUMPTION: Node.js built-in `zlib`, `crypto`, `https`/`http` modules are sufficient; no external dependencies needed
|
|
231
|
+
- ASSUMPTION: `git config user.name`, `git config user.email`, and `git remote get-url origin` are available and executable in the pipeline environment
|
|
232
|
+
- ASSUMPTION: Artifact files (FEATURE_SPEC.md, story files) are small enough that synchronous gzip compression is non-blocking in practice
|
|
233
|
+
- ASSUMPTION: The telemetry endpoint is operator-managed; murmur8 does not validate the endpoint URL beyond basic format
|
|
234
|
+
- ASSUMPTION: UUID v4 can be generated using `crypto.randomUUID()` (Node.js 15.6+; within Node.js 18+ requirement)
|
|
235
|
+
|
|
236
|
+
### Open Questions
|
|
237
|
+
|
|
238
|
+
- Should the failed queue have a configurable maximum depth, or a fixed cap (e.g., 50)?
|
|
239
|
+
- Should `telemetry-config` provide a `--test` flag to send a synthetic ping to verify connectivity?
|
|
240
|
+
- Should the `init` command emit a user-visible notice that `.env` was created (to aid discoverability)?
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 10. Impact on System Specification
|
|
245
|
+
|
|
246
|
+
### Alignment assessment
|
|
247
|
+
|
|
248
|
+
This feature **reinforces existing system assumptions** and introduces a minor extension:
|
|
249
|
+
|
|
250
|
+
- Per SYSTEM_SPEC.md:Section 8 (Observability), the system already exposes queue status and completion summaries. This feature adds an optional external observability channel.
|
|
251
|
+
- SYSTEM_SPEC.md:Section 3 (Out of Scope) excludes CI/CD integration, but telemetry to an operator endpoint is a distinct concern (usage analytics, not CI automation). No contradiction.
|
|
252
|
+
- SYSTEM_SPEC.md:Section 9 (Non-Functional:Reliability) states the system must not be blocked by side-effects. This feature's non-blocking, silent-failure design directly upholds that invariant.
|
|
253
|
+
|
|
254
|
+
### Minor extension to system spec warranted
|
|
255
|
+
|
|
256
|
+
The following additions to SYSTEM_SPEC.md are flagged for consideration (not applied here):
|
|
257
|
+
|
|
258
|
+
1. **Section 5 (Core Domain Concepts):** Add entry for `Run Identifier (runId)` — a UUID v4 generated per pipeline invocation for telemetry correlation and history linkage.
|
|
259
|
+
2. **Section 5:** Add entry for `Feature Identifier (featureId)` — a UUID v4 written into FEATURE_SPEC.md frontmatter by Alex on first creation; stable across retries.
|
|
260
|
+
3. **Section 8 (Cross-Cutting Concerns):** Add sub-section for external telemetry noting the opt-in model.
|
|
261
|
+
|
|
262
|
+
These are **non-breaking extensions** flagged for Alex/human decision.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## 11. Handover to BA (Cass)
|
|
267
|
+
|
|
268
|
+
### Story themes
|
|
269
|
+
|
|
270
|
+
1. **Telemetry activation** — Configuring the endpoint and key; understanding opt-in model
|
|
271
|
+
2. **runId and featureId generation** — Identifier lifecycle at pipeline start and spec creation
|
|
272
|
+
3. **Payload construction and send** — Building and POSTing the event at pipeline end
|
|
273
|
+
4. **Failed send queue** — Queuing failed sends and retrying at next run start
|
|
274
|
+
5. **init integration** — `.env` template creation and `.gitignore` protection
|
|
275
|
+
6. **telemetry-config command** — Viewing current configuration with masked key
|
|
276
|
+
|
|
277
|
+
### Expected story boundaries
|
|
278
|
+
|
|
279
|
+
- Activation/config story should be separate from the payload/send story
|
|
280
|
+
- `featureId` (Alex behaviour) and `runId` (orchestrator behaviour) may be combined into one story or split by agent concern
|
|
281
|
+
- Failed queue retry is a distinct story (edge case behaviour, important for reliability)
|
|
282
|
+
- `init` changes are a small story but have a user-visible outcome (discoverability of the feature)
|
|
283
|
+
|
|
284
|
+
### Areas needing careful story framing
|
|
285
|
+
|
|
286
|
+
- The "completely silent when no endpoint configured" behaviour needs an explicit AC (absence of output is the expected outcome)
|
|
287
|
+
- The precedence rule (real env vars override `.env`) needs a dedicated AC
|
|
288
|
+
- The `featureId` preservation rule (no regeneration on re-run) needs a dedicated AC
|
|
289
|
+
- Security: key masking in `telemetry-config` output needs explicit AC
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## 12. Change Log (Feature-Level)
|
|
294
|
+
|
|
295
|
+
| Date | Change | Reason | Raised By |
|
|
296
|
+
|------------|----------------------------------------|--------------------------------|-----------|
|
|
297
|
+
| 2026-05-19 | Initial feature specification created | New feature: telemetry layer | Alex |
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Implementation Plan — pipeline-telemetry
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
Create `src/telemetry.js` as the core module exporting all telemetry primitives (config loading, UUID generation, payload building, gzip compression, queue management, init helpers, and config formatting). Add `src/commands/telemetry-config.js` as a thin CLI wrapper, then wire the new module into `src/index.js`, `src/init.js`, and `bin/cli.js`. No external dependencies are required; Node.js built-ins (`crypto`, `zlib`, `https`, `fs`) cover all needs.
|
|
6
|
+
|
|
7
|
+
## Files to Create / Modify
|
|
8
|
+
|
|
9
|
+
| File | Action | Purpose |
|
|
10
|
+
|------|--------|---------|
|
|
11
|
+
| `src/telemetry.js` | **Create** | All exported telemetry functions |
|
|
12
|
+
| `src/commands/telemetry-config.js` | **Create** | CLI command handler for `telemetry-config` |
|
|
13
|
+
| `src/index.js` | **Modify** | Export telemetry functions |
|
|
14
|
+
| `src/init.js` | **Modify** | Call `ensureDotenv` and `ensureGitignore` during init |
|
|
15
|
+
| `bin/cli.js` | **No change needed** | Dynamic command loading already handles new commands |
|
|
16
|
+
|
|
17
|
+
## Numbered Steps
|
|
18
|
+
|
|
19
|
+
1. `src/telemetry.js` CREATE `loadConfig(dotenvPath)` — manual `.env` parse; env vars win; returns `{ url, key }` (null if absent) | Tests: T-TA-1 to T-TA-6
|
|
20
|
+
2. `src/telemetry.js` ADD `generateRunId()` — returns `crypto.randomUUID()` | Tests: T-ID-1, T-ID-2, T-ID-5
|
|
21
|
+
3. `src/telemetry.js` ADD `ensureFeatureId(specPath)` — reads file, extracts YAML frontmatter `featureId`; generates UUID v4 and prepends/updates frontmatter if absent | Tests: T-ID-3, T-ID-4, T-ID-5
|
|
22
|
+
4. `src/telemetry.js` ADD `buildPayload(runData)` — assembles `{ runId, run: { featureId, slug, status, startedAt, completedAt, totalDurationMs, stages } }`; omits `feedback` key when value is falsy/empty; passes `artifacts` through unchanged | Tests: T-PS-1 to T-PS-4, T-PS-6
|
|
23
|
+
5. `src/telemetry.js` ADD `compressArtifact(content)` — synchronous `zlib.gzipSync(content)` then `.toString('base64')` | Tests: T-PS-3, T-PS-5
|
|
24
|
+
6. `src/telemetry.js` ADD `enqueueFailure(payload, queuePath)` — reads queue (or `[]` on missing/corrupt); appends payload; trims to last 50; writes JSON | Tests: T-FQ-1, T-FQ-6
|
|
25
|
+
7. `src/telemetry.js` ADD `retryQueue(queuePath, sendFn)` — reads queue; calls `sendFn(payload)` for each entry; keeps entries where `sendFn` returns falsy; writes remaining (or `[]`) back to file | Tests: T-FQ-2 to T-FQ-5
|
|
26
|
+
8. `src/telemetry.js` ADD `ensureDotenv(targetDir)` and `ensureGitignore(targetDir)` — create/append `.env` template (idempotent on `MURMUR8_TELEMETRY_URL` presence); add `.env` line to `.gitignore` if absent (create if needed) | Tests: T-II-1 to T-II-5
|
|
27
|
+
9. `src/telemetry.js` ADD `formatTelemetryConfig(config, queuePath)` — returns string with URL, masked key (`****last4` or "not set"), active/inactive status, queue depth (reads file or 0) | Tests: T-TC-1 to T-TC-6
|
|
28
|
+
10. `src/commands/telemetry-config.js` CREATE `run(args)` — loads config via `loadConfig`, reads queue path, calls `formatTelemetryConfig`, prints result; `src/index.js` ADD telemetry exports; `src/init.js` CALL `ensureDotenv`+`ensureGitignore` | Tests: T-TC-1 to T-TC-6, T-II-1 to T-II-5
|
|
29
|
+
|
|
30
|
+
## Risks
|
|
31
|
+
|
|
32
|
+
- `ensureFeatureId` must handle three frontmatter states: no frontmatter, frontmatter without `featureId`, and frontmatter with existing `featureId`. YAML is parsed with regex/string logic (no yaml dep); edge cases like multi-document or trailing dashes need careful handling.
|
|
33
|
+
- `retryQueue` contract: `sendFn` returns truthy on success (synchronous). If the real `sendTelemetry` is async, callers must `await` and pass a resolved boolean — document this clearly in comments.
|
|
34
|
+
- Queue overflow logic drops the **oldest** entries (index 0), keeping the newest. Verify slice direction: `queue.slice(-49)` then push gives correct oldest-dropped behaviour.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
## Handoff Summary
|
|
2
|
+
**For:** Cass
|
|
3
|
+
**Feature:** pipeline-telemetry
|
|
4
|
+
|
|
5
|
+
### Key Decisions
|
|
6
|
+
- Telemetry is opt-in by configuration: setting `MURMUR8_TELEMETRY_URL` activates it; absence = fully silent (no flag needed to disable)
|
|
7
|
+
- Non-blocking by design: HTTP send failures enqueue to `.claude/telemetry-failed.json` silently; retry happens at next pipeline start — pipeline is never interrupted
|
|
8
|
+
- Two stable identifiers: `runId` (UUID v4, per run, generated at Step 5) and `featureId` (UUID v4, per feature spec, written by Alex into frontmatter on first creation, never regenerated)
|
|
9
|
+
- No external dependencies: uses Node.js built-ins only (`zlib`, `crypto`, `https`/`http`) — no dotenv, no HTTP client library
|
|
10
|
+
- `.env` parsed manually with real env vars taking precedence; `init` command adds commented template and ensures `.gitignore` protection
|
|
11
|
+
|
|
12
|
+
### Files Created
|
|
13
|
+
- .blueprint/features/feature_pipeline-telemetry/FEATURE_SPEC.md
|
|
14
|
+
|
|
15
|
+
### Open Questions
|
|
16
|
+
- Should the failed-send queue have a configurable max depth or a fixed cap (e.g., 50 entries)?
|
|
17
|
+
- Should `telemetry-config` offer a `--test` flag to ping the endpoint for connectivity verification?
|
|
18
|
+
- Should `init` emit a visible notice that `.env` was created, to improve discoverability?
|
|
19
|
+
|
|
20
|
+
### Critical Context
|
|
21
|
+
This feature is infrastructure-level and cross-cutting: it touches SKILL.md (Step 5 for runId, Step 12 for send), `src/init.js` (`.env` + `.gitignore`), `src/history.js` (store runId), and introduces two new files (`src/telemetry.js`, `src/commands/telemetry-config.js`). The core principle is **silent by default** — no output when working, no errors surfaced to user on failure. Cass should write stories that make the "absence of output is correct behaviour" expectation explicit in acceptance criteria, as this is counter-intuitive but intentional. The `featureId` preservation rule (Alex must not regenerate an existing featureId) is a critical correctness invariant that needs a precise AC.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
## Handoff Summary
|
|
2
|
+
**For:** Nigel
|
|
3
|
+
**Feature:** pipeline-telemetry
|
|
4
|
+
|
|
5
|
+
### Key Decisions
|
|
6
|
+
- Telemetry is fully silent in both directions: no output when working correctly, no error output on failure — "absence of output is the correct behaviour" is an explicit AC in story-payload-send and story-failed-queue-retry
|
|
7
|
+
- Six stories map directly to Alex's six story themes; each is independently testable
|
|
8
|
+
- `featureId` preservation (AC-4 of story-identifiers) is a critical invariant: Alex must never regenerate a `featureId` that already exists in FEATURE_SPEC.md frontmatter
|
|
9
|
+
- Environment variable precedence (process env overrides `.env`) is a dedicated AC in story-telemetry-activation (AC-3 and AC-6)
|
|
10
|
+
- API key masking in `telemetry-config` output is an explicit security AC (story-telemetry-config-command AC-2)
|
|
11
|
+
|
|
12
|
+
### Files Created
|
|
13
|
+
- .blueprint/features/feature_pipeline-telemetry/story-telemetry-activation.md
|
|
14
|
+
- .blueprint/features/feature_pipeline-telemetry/story-identifiers.md
|
|
15
|
+
- .blueprint/features/feature_pipeline-telemetry/story-payload-send.md
|
|
16
|
+
- .blueprint/features/feature_pipeline-telemetry/story-failed-queue-retry.md
|
|
17
|
+
- .blueprint/features/feature_pipeline-telemetry/story-init-integration.md
|
|
18
|
+
- .blueprint/features/feature_pipeline-telemetry/story-telemetry-config-command.md
|
|
19
|
+
|
|
20
|
+
### Open Questions
|
|
21
|
+
- Should the failed queue cap be configurable or hard-coded? (left as implementation-defined in story-failed-queue-retry AC-6)
|
|
22
|
+
- Should `init` emit a visible notice when `.env` is created? (scoped out of story-init-integration per Alex's silent-by-default principle)
|
|
23
|
+
|
|
24
|
+
### Critical Context
|
|
25
|
+
This feature is infrastructure-level and cross-cutting. Tests must cover: (1) complete silence on success and failure paths, (2) the `featureId` no-regeneration invariant, (3) env var precedence over `.env`, (4) non-blocking behaviour (pipeline state unaffected by telemetry errors), and (5) key masking security property. All new code lives in `src/telemetry.js` and `src/commands/telemetry-config.js`; existing files touched are SKILL.md (Steps 5 and 12), `src/history.js`, `src/init.js`, `bin/cli.js`, and `src/index.js`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## Handoff Summary
|
|
2
|
+
**For:** Codey
|
|
3
|
+
**Feature:** pipeline-telemetry
|
|
4
|
+
|
|
5
|
+
### Key Decisions
|
|
6
|
+
- Tests are self-contained: all helper functions (loadConfig, buildPayload, compressArtifact, etc.) are inlined in the test file — Codey must match these contracts exactly in src/telemetry.js
|
|
7
|
+
- HTTP is never called in tests; send behaviour is validated via contract (headers, payload shape, silence on success)
|
|
8
|
+
- Queue capped at 50 entries; overflow drops oldest
|
|
9
|
+
- Queue cleanup on full success: write `[]` (not delete file)
|
|
10
|
+
- All 7 story ambiguities resolved in test-spec.md assumptions
|
|
11
|
+
|
|
12
|
+
### Files Created
|
|
13
|
+
- test/artifacts/feature_pipeline-telemetry/test-spec.md
|
|
14
|
+
- test/feature_pipeline-telemetry.test.js
|
|
15
|
+
|
|
16
|
+
### Open Questions
|
|
17
|
+
- None
|
|
18
|
+
|
|
19
|
+
### Critical Context
|
|
20
|
+
Tests define the contracts Codey must implement. Key exported functions expected from src/telemetry.js: `loadConfig(dotenvPath)`, `generateRunId()`, `ensureFeatureId(specPath)`, `buildPayload(runData)`, `compressArtifact(content)`, `sendTelemetry(payload, config)`, `retryQueue(queuePath, sendFn)`. The telemetry-config command logic is also inlined in tests — match the masking format (`****last4`) and output format exactly.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Story — Failed Send Queue and Retry
|
|
2
|
+
|
|
3
|
+
### User story
|
|
4
|
+
As a platform administrator, I want failed telemetry sends to be queued silently and retried at the start of the next pipeline run so that transient network issues do not cause data loss and never interrupt pipeline execution.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
### Context / scope
|
|
9
|
+
- Failed payloads are appended to `.claude/telemetry-failed.json`
|
|
10
|
+
- Retry happens at pipeline start (before Step 1 processing) on subsequent runs
|
|
11
|
+
- All failure handling is silent: no output to user on queue write or retry
|
|
12
|
+
- The queue has a maximum depth (implementation-defined, e.g. 50 entries); oldest entries are dropped on overflow
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
### Acceptance criteria
|
|
17
|
+
|
|
18
|
+
**AC-1 — Failed send is silently queued; pipeline continues**
|
|
19
|
+
- Given telemetry is active and the HTTP POST fails (network error or non-2xx response),
|
|
20
|
+
- When the send attempt completes,
|
|
21
|
+
- Then the payload is appended to `.claude/telemetry-failed.json`, no error or warning is output to the user, and the pipeline continues normally.
|
|
22
|
+
|
|
23
|
+
**AC-2 — Queued payloads are retried at the start of the next run**
|
|
24
|
+
- Given `.claude/telemetry-failed.json` contains one or more queued payloads,
|
|
25
|
+
- When the next pipeline run starts (before Step 1),
|
|
26
|
+
- Then `src/telemetry.js` attempts to send each queued payload to the configured endpoint.
|
|
27
|
+
|
|
28
|
+
**AC-3 — Successfully retried entries are removed from the queue**
|
|
29
|
+
- Given a queued payload is retried and the endpoint returns a 2xx response,
|
|
30
|
+
- When the retry completes,
|
|
31
|
+
- Then that entry is removed from `.claude/telemetry-failed.json`; remaining failed entries stay in the file.
|
|
32
|
+
|
|
33
|
+
**AC-4 — Queue file is removed when all entries are successfully sent**
|
|
34
|
+
- Given `.claude/telemetry-failed.json` exists with entries that are all successfully retried,
|
|
35
|
+
- When the last entry is sent successfully,
|
|
36
|
+
- Then `.claude/telemetry-failed.json` is deleted (or written as an empty array — implementation choice, file absence is acceptable).
|
|
37
|
+
|
|
38
|
+
**AC-5 — Retry failures remain in queue silently**
|
|
39
|
+
- Given a queued payload is retried and the send fails again,
|
|
40
|
+
- When the retry completes,
|
|
41
|
+
- Then the entry remains in `.claude/telemetry-failed.json` and no output is produced.
|
|
42
|
+
|
|
43
|
+
**AC-6 — Queue does not grow unboundedly**
|
|
44
|
+
- Given `.claude/telemetry-failed.json` already contains the maximum allowed entries,
|
|
45
|
+
- When a new send failure occurs,
|
|
46
|
+
- Then the oldest entry is dropped and the new payload is appended, keeping the queue at the maximum depth.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
### Out of scope
|
|
51
|
+
- CLI command to inspect or clear the failed queue (file inspection only)
|
|
52
|
+
- Configurable retry delay or backoff (retry happens at next pipeline start, no timer)
|
|
53
|
+
- Retry of payloads when telemetry URL is unconfigured
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Story — Run and Feature Identifiers
|
|
2
|
+
|
|
3
|
+
### User story
|
|
4
|
+
As a platform administrator, I want each pipeline run to carry a unique `runId` and each feature spec to carry a stable `featureId` so that I can correlate telemetry events with local history and track the same feature across multiple retries.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
### Context / scope
|
|
9
|
+
- `runId`: UUID v4, generated at pipeline start (Step 5 of SKILL.md), stored in working context and in the history entry
|
|
10
|
+
- `featureId`: UUID v4, written into FEATURE_SPEC.md YAML frontmatter by Alex on first creation only
|
|
11
|
+
- Both identifiers are generated using Node.js built-in `crypto.randomUUID()` — no external library
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
### Acceptance criteria
|
|
16
|
+
|
|
17
|
+
**AC-1 — runId generated at pipeline start for every run**
|
|
18
|
+
- Given a pipeline run is initiated,
|
|
19
|
+
- When the pipeline reaches Step 5 of SKILL.md,
|
|
20
|
+
- Then a UUID v4 `runId` is generated and stored in the working context for use throughout that run.
|
|
21
|
+
|
|
22
|
+
**AC-2 — runId is stored in the history entry**
|
|
23
|
+
- Given a pipeline run completes (successfully or with failure),
|
|
24
|
+
- When the history entry is written to `.claude/pipeline-history.json`,
|
|
25
|
+
- Then the entry includes the `runId` generated at pipeline start.
|
|
26
|
+
|
|
27
|
+
**AC-3 — featureId written into FEATURE_SPEC.md frontmatter on first creation**
|
|
28
|
+
- Given Alex creates a new FEATURE_SPEC.md that has no YAML frontmatter `featureId`,
|
|
29
|
+
- When Alex writes the file,
|
|
30
|
+
- Then a UUID v4 `featureId` is added to the YAML frontmatter of FEATURE_SPEC.md.
|
|
31
|
+
|
|
32
|
+
**AC-4 — featureId is never regenerated if already present**
|
|
33
|
+
- Given FEATURE_SPEC.md already contains a `featureId` in its YAML frontmatter,
|
|
34
|
+
- When Alex processes the feature spec (on a re-run or update),
|
|
35
|
+
- Then the existing `featureId` value is preserved unchanged.
|
|
36
|
+
|
|
37
|
+
**AC-5 — runId is unique per run even for the same feature**
|
|
38
|
+
- Given the same feature is run twice (e.g., after a failure and retry),
|
|
39
|
+
- When both pipeline runs complete,
|
|
40
|
+
- Then each run's history entry contains a different `runId`, while both FEATURE_SPEC.md entries retain the same `featureId`.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### Out of scope
|
|
45
|
+
- Exposing `runId` in any user-visible CLI output
|
|
46
|
+
- User-configurable or manually set `runId` or `featureId`
|
|
47
|
+
- `featureId` for artifacts other than FEATURE_SPEC.md
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Story — Init Command Integration (.env Template and .gitignore)
|
|
2
|
+
|
|
3
|
+
### User story
|
|
4
|
+
As a developer initialising a new murmur8 project, I want the `init` command to create a commented-out telemetry template in `.env` and ensure `.env` is protected by `.gitignore` so that I know telemetry exists and cannot accidentally commit credentials.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
### Context / scope
|
|
9
|
+
- `murmur8 init` runs `src/init.js` which copies framework files to the target project
|
|
10
|
+
- `.env` file is at the project root; it is optional — telemetry is inactive if absent
|
|
11
|
+
- `.gitignore` must include `.env` to prevent accidental credential commits
|
|
12
|
+
- If `.env` already exists, the template block is appended (not overwritten) only if not already present
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
### Acceptance criteria
|
|
17
|
+
|
|
18
|
+
**AC-1 — `.env` created with commented telemetry template when absent**
|
|
19
|
+
- Given the target project has no `.env` file,
|
|
20
|
+
- When `murmur8 init` is run,
|
|
21
|
+
- Then a `.env` file is created at the project root containing a commented-out block documenting `MURMUR8_TELEMETRY_URL` and `MURMUR8_TELEMETRY_KEY`.
|
|
22
|
+
|
|
23
|
+
**AC-2 — `.env` template appended when file already exists**
|
|
24
|
+
- Given the target project already has a `.env` file that does not contain the murmur8 telemetry template block,
|
|
25
|
+
- When `murmur8 init` is run,
|
|
26
|
+
- Then the commented-out telemetry template block is appended to the existing `.env` file without modifying existing content.
|
|
27
|
+
|
|
28
|
+
**AC-3 — `.env` not modified if template already present**
|
|
29
|
+
- Given the target project has a `.env` file that already contains the murmur8 telemetry template block,
|
|
30
|
+
- When `murmur8 init` is run,
|
|
31
|
+
- Then the `.env` file is not modified (no duplicate block appended).
|
|
32
|
+
|
|
33
|
+
**AC-4 — `.env` added to `.gitignore` when absent from it**
|
|
34
|
+
- Given the target project has a `.gitignore` file that does not contain `.env`,
|
|
35
|
+
- When `murmur8 init` is run,
|
|
36
|
+
- Then `.env` is appended to `.gitignore`.
|
|
37
|
+
|
|
38
|
+
**AC-5 — `.gitignore` not modified if `.env` already listed**
|
|
39
|
+
- Given the target project's `.gitignore` already contains `.env`,
|
|
40
|
+
- When `murmur8 init` is run,
|
|
41
|
+
- Then `.gitignore` is not modified (no duplicate entry added).
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
### Out of scope
|
|
46
|
+
- Emitting a user-visible notice that `.env` was created (silent operation, matching overall telemetry design)
|
|
47
|
+
- Validating that existing `.env` values are correct
|
|
48
|
+
- Creating or modifying `.gitignore` if neither `.gitignore` nor `.env` exist (no `.gitignore` needed without a `.env`)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Story — Telemetry Payload Construction and Send
|
|
2
|
+
|
|
3
|
+
### User story
|
|
4
|
+
As a platform administrator, I want a structured JSON event payload to be POST-ed to my telemetry endpoint at the end of each pipeline run so that I have complete execution data including identifiers, timings, stage statuses, and compressed artifacts.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
### Context / scope
|
|
9
|
+
- Send occurs at pipeline end (Step 12 of SKILL.md) via `src/telemetry.js`
|
|
10
|
+
- Payload is a JSON body sent via HTTP POST using Node.js built-in `https`/`http` modules — no external HTTP library
|
|
11
|
+
- Artifacts (FEATURE_SPEC.md and `story-*.md` files) are gzip-compressed with `zlib` and base64-encoded before inclusion
|
|
12
|
+
- Send is fire-and-forget: the pipeline does not wait for confirmation beyond a reasonable timeout
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
### Acceptance criteria
|
|
17
|
+
|
|
18
|
+
**AC-1 — Payload contains required identity and run fields**
|
|
19
|
+
- Given telemetry is active and a pipeline run completes,
|
|
20
|
+
- When the payload is constructed,
|
|
21
|
+
- Then it includes: `runId`, `featureId`, `featureSlug`, `status` (success/failure), `startedAt`, `completedAt`, and `durationMs`.
|
|
22
|
+
|
|
23
|
+
**AC-2 — Payload includes per-stage timing and status**
|
|
24
|
+
- Given a pipeline run completes with one or more stages executed,
|
|
25
|
+
- When the payload is constructed,
|
|
26
|
+
- Then the `stages` block includes each executed stage with its `name`, `status`, and `durationMs`.
|
|
27
|
+
|
|
28
|
+
**AC-3 — Artifacts are gzip-compressed and base64-encoded**
|
|
29
|
+
- Given FEATURE_SPEC.md and any `story-*.md` files exist for the feature,
|
|
30
|
+
- When the payload is constructed,
|
|
31
|
+
- Then the `artifacts` block contains each file keyed by filename, with its content gzip-compressed (zlib) and base64-encoded.
|
|
32
|
+
|
|
33
|
+
**AC-4 — Feedback block omitted when `--no-feedback` is used**
|
|
34
|
+
- Given the pipeline is run with the `--no-feedback` flag,
|
|
35
|
+
- When the payload is constructed,
|
|
36
|
+
- Then the `feedback` block is absent from the payload.
|
|
37
|
+
|
|
38
|
+
**AC-5 — Successful send produces no user-visible output**
|
|
39
|
+
- Given telemetry is active and the HTTP POST returns a 2xx response,
|
|
40
|
+
- When the send completes,
|
|
41
|
+
- Then no message, log line, or output is written to stdout or stderr.
|
|
42
|
+
|
|
43
|
+
**AC-6 — Payload sent with correct Content-Type header**
|
|
44
|
+
- Given telemetry is active,
|
|
45
|
+
- When the POST request is made,
|
|
46
|
+
- Then the request includes the header `Content-Type: application/json`.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
### Out of scope
|
|
51
|
+
- Real-time or streaming telemetry (end-of-run POST only)
|
|
52
|
+
- Telemetry for non-pipeline commands (`history`, `queue`, `validate`, etc.)
|
|
53
|
+
- Encryption of payload beyond HTTPS transport
|
|
54
|
+
- Validating or enforcing HTTPS on the configured URL (though a warning may be emitted for `http://`)
|