murmur8 4.5.1 → 4.7.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.
Files changed (31) hide show
  1. package/.blueprint/features/feature_pipeline-telemetry/FEATURE_SPEC.md +297 -0
  2. package/.blueprint/features/feature_pipeline-telemetry/IMPLEMENTATION_PLAN.md +34 -0
  3. package/.blueprint/features/feature_pipeline-telemetry/handoff-alex.md +21 -0
  4. package/.blueprint/features/feature_pipeline-telemetry/handoff-cass.md +25 -0
  5. package/.blueprint/features/feature_pipeline-telemetry/handoff-nigel.md +20 -0
  6. package/.blueprint/features/feature_pipeline-telemetry/story-failed-queue-retry.md +53 -0
  7. package/.blueprint/features/feature_pipeline-telemetry/story-identifiers.md +47 -0
  8. package/.blueprint/features/feature_pipeline-telemetry/story-init-integration.md +48 -0
  9. package/.blueprint/features/feature_pipeline-telemetry/story-payload-send.md +54 -0
  10. package/.blueprint/features/feature_pipeline-telemetry/story-telemetry-activation.md +54 -0
  11. package/.blueprint/features/feature_pipeline-telemetry/story-telemetry-config-command.md +52 -0
  12. package/.blueprint/features/feature_refine-feature-skill/FEATURE_SPEC.md +180 -0
  13. package/.blueprint/features/feature_refine-feature-skill/IMPLEMENTATION_PLAN.md +47 -0
  14. package/.blueprint/features/feature_refine-feature-skill/handoff-alex.md +19 -0
  15. package/.blueprint/features/feature_refine-feature-skill/handoff-cass.md +26 -0
  16. package/.blueprint/features/feature_refine-feature-skill/handoff-nigel.md +30 -0
  17. package/.blueprint/features/feature_refine-feature-skill/story-codey-confirmation.md +41 -0
  18. package/.blueprint/features/feature_refine-feature-skill/story-conversation-approval.md +41 -0
  19. package/.blueprint/features/feature_refine-feature-skill/story-initiation.md +42 -0
  20. package/.blueprint/features/feature_refine-feature-skill/story-story-propagation.md +42 -0
  21. package/.blueprint/features/feature_refine-feature-skill/story-telemetry-lineage.md +47 -0
  22. package/.blueprint/features/feature_refine-feature-skill/story-test-propagation.md +42 -0
  23. package/README.md +98 -7
  24. package/bin/cli.js +2 -1
  25. package/package.json +1 -1
  26. package/src/commands/refine.js +37 -0
  27. package/src/commands/telemetry-config.js +16 -0
  28. package/src/index.js +38 -1
  29. package/src/init.js +5 -0
  30. package/src/refine.js +172 -0
  31. 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://`)