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.
Files changed (28) hide show
  1. package/.blueprint/features/feature_feedback-test/FEATURE_SPEC.md +229 -0
  2. package/.blueprint/features/feature_feedback-test/IMPLEMENTATION_PLAN.md +25 -0
  3. package/.blueprint/features/feature_feedback-test/handoff-alex.md +20 -0
  4. package/.blueprint/features/feature_feedback-test/handoff-cass.md +21 -0
  5. package/.blueprint/features/feature_feedback-test/handoff-nigel.md +20 -0
  6. package/.blueprint/features/feature_feedback-test/story-config-management.md +103 -0
  7. package/.blueprint/features/feature_feedback-test/story-parse-pipeline.md +65 -0
  8. package/.blueprint/features/feature_feedback-test/story-validation-normalisation.md +99 -0
  9. package/.blueprint/features/feature_pipeline-telemetry/FEATURE_SPEC.md +297 -0
  10. package/.blueprint/features/feature_pipeline-telemetry/IMPLEMENTATION_PLAN.md +34 -0
  11. package/.blueprint/features/feature_pipeline-telemetry/handoff-alex.md +21 -0
  12. package/.blueprint/features/feature_pipeline-telemetry/handoff-cass.md +25 -0
  13. package/.blueprint/features/feature_pipeline-telemetry/handoff-nigel.md +20 -0
  14. package/.blueprint/features/feature_pipeline-telemetry/story-failed-queue-retry.md +53 -0
  15. package/.blueprint/features/feature_pipeline-telemetry/story-identifiers.md +47 -0
  16. package/.blueprint/features/feature_pipeline-telemetry/story-init-integration.md +48 -0
  17. package/.blueprint/features/feature_pipeline-telemetry/story-payload-send.md +54 -0
  18. package/.blueprint/features/feature_pipeline-telemetry/story-telemetry-activation.md +54 -0
  19. package/.blueprint/features/feature_pipeline-telemetry/story-telemetry-config-command.md +52 -0
  20. package/README.md +54 -0
  21. package/SKILL.md +35 -24
  22. package/package.json +1 -1
  23. package/src/commands/history.js +41 -2
  24. package/src/commands/telemetry-config.js +16 -0
  25. package/src/history.js +31 -0
  26. package/src/index.js +16 -1
  27. package/src/init.js +5 -0
  28. package/src/telemetry.js +198 -0
@@ -0,0 +1,229 @@
1
+ # Feature Specification — Feedback Module Test Suite
2
+
3
+ ## 1. Feature Intent
4
+ **Why this feature exists.**
5
+
6
+ - **Problem being addressed:** The `src/feedback.js` module provides foundational logic for the agent feedback loop — schema validation, quality gate evaluation, key normalisation, config management, and feedback parsing. No test file directly imports and exercises this module's exported API. Existing tests (feature_feedback-loop, feature_compressed-feedback) re-implement helper logic inline rather than testing the real module, leaving the production code untested.
7
+ - **User need:** Developers maintaining or extending `src/feedback.js` need confidence that the exported functions behave correctly and that regressions are caught immediately by the test suite.
8
+ - **System alignment:** Per SYSTEM_SPEC.md:Section 7 (Implementation Rules), "tests are contracts" and the suite must be green before a feature is considered complete. Untested production modules violate this principle and expose the pipeline to silent breakage.
9
+
10
+ > This feature creates a direct unit-test harness for `src/feedback.js`, closing the coverage gap introduced by the feedback-loop and compressed-feedback features.
11
+
12
+ ---
13
+
14
+ ## 2. Scope
15
+
16
+ ### In Scope
17
+
18
+ - Unit tests that `require('../src/feedback')` and call its exported functions directly
19
+ - Coverage of all exported functions:
20
+ - `validateFeedback(feedback)` — schema validation
21
+ - `normalizeFeedbackKeys(feedback)` — `rec` → `recommendation` normalisation
22
+ - `parseFeedbackFromOutput(output)` — regex extraction and JSON parsing
23
+ - `shouldPause(feedback, config)` — quality gate decision logic
24
+ - `getDefaultConfig()` — default config shape and values
25
+ - `readConfig()` — file read with fallback to defaults
26
+ - `writeConfig(config)` — file write
27
+ - `setConfigValue(key, value)` — validated config mutation
28
+ - `resetConfig()` — restores defaults
29
+ - `displayConfig()` — smoke test (no crash, correct output shape)
30
+ - File system isolation using `tmp` directories, matching the pattern established by `feature_feedback-loop.test.js`
31
+ - Edge cases: corrupt config file, missing config file, boundary rating values, both `rec` and `recommendation` keys present
32
+
33
+ ### Out of Scope
34
+
35
+ - Testing agent prompt text (covered by feature_compressed-feedback)
36
+ - Integration tests spanning multiple modules (covered by feature_feedback-loop)
37
+ - Testing `displayConfig` output formatting exhaustively (smoke test only)
38
+ - Testing the insights calibration or issue-correlation logic (covered by feature_feedback-loop:Feedback Insights)
39
+
40
+ ---
41
+
42
+ ## 3. Actors Involved
43
+
44
+ ### Developer / Test Runner
45
+
46
+ - **Can do:** Run `node --test test/feature_feedback-test.test.js` to verify `src/feedback.js` behaviour
47
+ - **Cannot do:** Modify production code via test execution
48
+
49
+ ### src/feedback.js (module under test)
50
+
51
+ - **Provides:** All exported functions listed in Section 2
52
+ - **Constrained by:** Existing call sites; test must not require API changes
53
+
54
+ ### File System (test isolation)
55
+
56
+ - **Provides:** Temporary directories for config file read/write tests
57
+ - **Pattern:** `fs.mkdtempSync` setup / `fs.rmSync` teardown per describe block
58
+
59
+ ---
60
+
61
+ ## 4. Behaviour Overview
62
+
63
+ ### Happy Path: All Exported Functions Are Tested
64
+
65
+ 1. Test file imports `src/feedback.js` module
66
+ 2. Each exported function has one or more test cases covering:
67
+ - Correct inputs → expected outputs
68
+ - Boundary inputs → correct handling
69
+ - Invalid inputs → appropriate rejection or graceful degradation
70
+ 3. File system tests use isolated `tmp` directories to avoid cross-test pollution
71
+ 4. `process.chdir` is restored after each file-system test group
72
+ 5. All tests pass green; CI accepts the file
73
+
74
+ ### Alternative: Config File Corruption
75
+
76
+ 1. Test writes deliberately malformed JSON to the config file path
77
+ 2. `readConfig()` catches the parse error and returns defaults
78
+ 3. No exception propagates; test asserts returned value equals `getDefaultConfig()`
79
+
80
+ ### Alternative: Boundary Rating Validation
81
+
82
+ 1. Tests cover ratings 1, 5 (valid boundaries) and 0, 6 (invalid outside range)
83
+ 2. Tests cover `rating: 3.5` (non-integer, invalid) and `rating: 3` (integer, valid)
84
+ 3. `validateFeedback` returns `{ valid: false, errors: [...] }` for all invalid cases
85
+
86
+ ---
87
+
88
+ ## 5. State & Lifecycle Interactions
89
+
90
+ - **State-creating:** None — the test file does not introduce new runtime state
91
+ - **State-constrained:** Tests manage transient file system state (tmp directories)
92
+ - **Module lifecycle:** `require('../src/feedback')` is resolved once per test file run; config file paths are relative and resolved against `process.cwd()` which tests temporarily redirect
93
+
94
+ **Key constraint:** `src/feedback.js` uses a module-level constant `CONFIG_FILE = '.claude/feedback-config.json'` resolved relative to `process.cwd()`. Tests must `process.chdir(testDir)` before any call that reads/writes config, and restore `process.cwd()` in teardown.
95
+
96
+ ---
97
+
98
+ ## 6. Rules & Decision Logic
99
+
100
+ ### Rule 1: Direct Module Import Required
101
+
102
+ - **Description:** Tests must import the real `src/feedback.js` rather than re-implementing its logic
103
+ - **Rationale:** Inline reimplementation does not catch bugs in production code
104
+ - **Inputs:** `require('../src/feedback')`
105
+ - **Outputs:** Live module reference
106
+ - **Type:** Structural constraint
107
+
108
+ ### Rule 2: Isolated File System Per Describe Block
109
+
110
+ - **Description:** Each describe block that touches the config file must set up and tear down its own `tmp` directory
111
+ - **Inputs:** `fs.mkdtempSync`, `process.chdir`
112
+ - **Outputs:** Isolated state per describe block
113
+ - **Type:** Deterministic
114
+
115
+ ### Rule 3: Boundary Coverage for Rating
116
+
117
+ - **Description:** Rating validation must be tested at values 0, 1, 3, 5, 6 and non-integer 3.5
118
+ - **Type:** Deterministic
119
+
120
+ ### Rule 4: Dual-Key Normalisation Coverage
121
+
122
+ - **Description:** `normalizeFeedbackKeys` must be tested for: `rec` only, `recommendation` only, both present (recommendation wins), neither present
123
+ - **Type:** Deterministic
124
+
125
+ ### Rule 5: Parse-and-Validate Pipeline
126
+
127
+ - **Description:** At least one test must chain `parseFeedbackFromOutput` → `normalizeFeedbackKeys` → `validateFeedback` to verify the end-to-end extraction path works against the real module
128
+ - **Type:** Integration within module boundary
129
+
130
+ ---
131
+
132
+ ## 7. Dependencies
133
+
134
+ ### System Components
135
+
136
+ - **src/feedback.js:** Module under test — no modifications required
137
+ - **node:test, node:assert:** Node.js built-in test runner and assertions (Node 18+)
138
+ - **fs, path, os:** Standard library for file system isolation
139
+
140
+ ### File Dependencies
141
+
142
+ - Input: `src/feedback.js` (read-only from test perspective)
143
+ - Output: `test/feature_feedback-test.test.js` (new file)
144
+
145
+ ### Existing Test Patterns
146
+
147
+ - Isolation pattern from `test/feature_feedback-loop.test.js` (setupTestDir / teardownTestDir)
148
+ - Module import pattern from `test/feature_theme-adoption.test.js` and `test/feature_config-factory.test.js`
149
+
150
+ ---
151
+
152
+ ## 8. Non-Functional Considerations
153
+
154
+ ### Performance
155
+
156
+ - All tests are synchronous file system operations on tmp dirs; expected runtime < 100ms total
157
+
158
+ ### Maintainability
159
+
160
+ - Tests are structured to mirror `src/feedback.js` exported API, making it easy to add tests as the module evolves
161
+ - Describe block names match function groups: `validateFeedback`, `normalizeFeedbackKeys`, `parseFeedbackFromOutput`, `shouldPause`, `Config Management`
162
+
163
+ ### Error Tolerance
164
+
165
+ - Tmp directory teardown uses `{ force: true }` to tolerate partial cleanup on test failure
166
+
167
+ ### No Side Effects
168
+
169
+ - Tests do not modify any project-level `.claude/` files; all file I/O is confined to `tmp` directories
170
+
171
+ ---
172
+
173
+ ## 9. Assumptions & Open Questions
174
+
175
+ ### Assumptions
176
+
177
+ - ASSUMPTION: `src/feedback.js` exports are stable; no API changes are required to make it testable
178
+ - ASSUMPTION: `process.chdir` correctly redirects the module's relative path resolution for `CONFIG_FILE`
179
+ - ASSUMPTION: Node.js 18+ is available (required by SYSTEM_SPEC.md:Section 2)
180
+ - ASSUMPTION: `displayConfig` writes to stdout; smoke test asserts it does not throw
181
+
182
+ ### Open Questions
183
+
184
+ - Should `displayConfig` be tested with a captured stdout mock, or is a non-throw assertion sufficient? (INFERRED: non-throw is sufficient for this feature)
185
+ - Should `setConfigValue` with unknown keys be tested? (INFERRED: yes, as the function throws a typed error that should be verified)
186
+ - Are there any async code paths in `src/feedback.js`? (INFERRED: no — all operations are synchronous based on current implementation)
187
+
188
+ ---
189
+
190
+ ## 10. Impact on System Specification
191
+
192
+ ### Reinforces Existing Assumptions
193
+
194
+ - Per SYSTEM_SPEC.md:Section 7, "tests are contracts" and "green suite required" — this feature closes a gap where contracts were implied but not enforced
195
+ - Per SYSTEM_SPEC.md:Section 8 (Traceability), tests that directly import production modules create a firmer traceability chain than tests using reimplemented helpers
196
+
197
+ ### No Contradiction
198
+
199
+ This feature introduces no new behaviour, state, or API. It adds test coverage for existing production code. No system spec update is required.
200
+
201
+ ---
202
+
203
+ ## 11. Handover to BA (Cass)
204
+
205
+ ### Story Themes
206
+
207
+ 1. **Direct Module Tests:** Tests that import and exercise `validateFeedback`, `normalizeFeedbackKeys`, `parseFeedbackFromOutput`, and `shouldPause` via the real module
208
+ 2. **Config Management Tests:** Tests for `readConfig`, `writeConfig`, `setConfigValue`, `resetConfig`, and `getDefaultConfig` with file system isolation
209
+ 3. **End-to-End Parse Pipeline:** A chained test covering `parseFeedbackFromOutput` → `normalizeFeedbackKeys` → `validateFeedback` as an integrated path
210
+
211
+ ### Expected Story Boundaries
212
+
213
+ - Story 1: Validation and normalisation functions (no file system needed)
214
+ - Story 2: Config management functions (file system isolation required)
215
+ - Story 3: Parse pipeline (combines Stories 1 and 2 patterns)
216
+
217
+ ### Areas Needing Careful Story Framing
218
+
219
+ - `process.chdir` usage must be clearly framed as test infrastructure, not production behaviour
220
+ - The distinction between this test file and `feature_feedback-loop.test.js` must be explicit: this tests the real module; that uses inline helpers
221
+ - `displayConfig` story should be framed as a smoke test, not a full output assertion
222
+
223
+ ---
224
+
225
+ ## 12. Change Log (Feature-Level)
226
+
227
+ | Date | Change | Reason | Raised By |
228
+ |------------|-------------------------------------|-----------------------------------------|-----------|
229
+ | 2026-05-19 | Initial feature specification | Close test coverage gap for src/feedback.js | Alex |
@@ -0,0 +1,25 @@
1
+ # Implementation Plan — feedback-test
2
+
3
+ ## Summary
4
+
5
+ This feature adds a test suite for `src/feedback.js`. All 34 tests were written and verified green by Nigel prior to this planning phase — `src/feedback.js` already exports every required function and no production code changes are needed. Implementation is test-only: the test file and its artifact already exist and pass.
6
+
7
+ ## Files to Create/Modify
8
+
9
+ | Path | Action | Purpose |
10
+ |------|--------|---------|
11
+ | `test/feature_feedback-test.test.js` | Already created (Nigel) | 34 tests covering all exported feedback functions |
12
+ | `test/artifacts/feature_feedback-test/test-spec.md` | Already created (Nigel) | AC-to-test-ID mapping and assumptions |
13
+ | `src/feedback.js` | No change required | All required exports already present and correct |
14
+
15
+ ## Implementation Steps
16
+
17
+ 1. **Verify tests pass as-is** — Run `node --test test/feature_feedback-test.test.js` to confirm all 34 tests are green. Addresses all test IDs (T-VN-*, T-CM-*, T-PP-*).
18
+
19
+ 2. **No production code changes needed** — `src/feedback.js` already exports `validateFeedback`, `normalizeFeedbackKeys`, `parseFeedbackFromOutput`, `shouldPause`, `getDefaultConfig`, `readConfig`, `writeConfig`, `setConfigValue`, `displayConfig`, and `resetConfig` with correct behaviour.
20
+
21
+ 3. **Commit the new test artefacts** — Stage and commit `test/feature_feedback-test.test.js` and `test/artifacts/feature_feedback-test/test-spec.md` along with this plan.
22
+
23
+ ## Risks / Questions
24
+
25
+ - None. Nigel confirmed all 34 tests pass against the unmodified production file before handoff.
@@ -0,0 +1,20 @@
1
+ ## Handoff Summary
2
+ **For:** Cass
3
+ **Feature:** feedback-test
4
+
5
+ ### Key Decisions
6
+ - Scope is unit tests for `src/feedback.js` exclusively — the production module is imported directly, not reimplemented inline
7
+ - All nine exported functions are covered: `validateFeedback`, `normalizeFeedbackKeys`, `parseFeedbackFromOutput`, `shouldPause`, `getDefaultConfig`, `readConfig`, `writeConfig`, `setConfigValue`, `resetConfig`
8
+ - File system tests use `tmp` directory isolation with `process.chdir` (matching `feature_feedback-loop.test.js` pattern)
9
+ - `displayConfig` is smoke-tested only (non-throw assertion); full stdout capture is out of scope
10
+ - One chained integration test covers the full parse pipeline: `parseFeedbackFromOutput` → `normalizeFeedbackKeys` → `validateFeedback`
11
+
12
+ ### Files Created
13
+ - .blueprint/features/feature_feedback-test/FEATURE_SPEC.md
14
+
15
+ ### Open Questions
16
+ - Whether `displayConfig` warrants stdout capture mocking (deferred; non-throw is sufficient for now)
17
+ - Async paths in `src/feedback.js`: inferred none exist, but Cass should confirm before writing stories
18
+
19
+ ### Critical Context
20
+ The key distinction from existing feedback tests: `feature_feedback-loop.test.js` and `feature_compressed-feedback.test.js` both re-implement feedback logic as inline helpers — they do not import `src/feedback.js`. This feature exists precisely to test the real production module. Stories must keep this boundary clear. The output file is `test/feature_feedback-test.test.js` and must use `require('../src/feedback')`.
@@ -0,0 +1,21 @@
1
+ ## Handoff Summary
2
+ **For:** Nigel
3
+ **Feature:** feedback-test
4
+
5
+ ### Key Decisions
6
+ - Split into three stories matching Alex's expected boundaries: validation/normalisation (pure), config management (file I/O), and parse pipeline (chained integration)
7
+ - `normalizeFeedbackKeys` with both `rec` and `recommendation` present: production code does NOT delete `rec` when `recommendation` already exists — both keys are preserved; ACs reflect actual implementation
8
+ - File system isolation pattern documented explicitly per `feature_feedback-loop.test.js`; `process.chdir` restore is mandatory in teardown
9
+ - `displayConfig` framed as smoke test (no-throw only); no stdout capture required
10
+ - All functions confirmed synchronous — no async/await needed in tests
11
+
12
+ ### Files Created
13
+ - .blueprint/features/feature_feedback-test/story-validation-normalisation.md
14
+ - .blueprint/features/feature_feedback-test/story-config-management.md
15
+ - .blueprint/features/feature_feedback-test/story-parse-pipeline.md
16
+
17
+ ### Open Questions
18
+ - None
19
+
20
+ ### Critical Context
21
+ Output file is `test/feature_feedback-test.test.js` using `require('../src/feedback')` — not inline reimplementations. `CONFIG_FILE` is resolved relative to `process.cwd()`; all config tests must `chdir` into a `tmp` dir before calling any read/write function. Story-parse-pipeline covers Rule 5 (chained integration test) from FEATURE_SPEC.md. Rating boundary values to test: 0, 1, 3, 5, 6, 3.5.
@@ -0,0 +1,20 @@
1
+ ## Handoff Summary
2
+ **For:** Codey
3
+ **Feature:** feedback-test
4
+
5
+ ### Key Decisions
6
+ - Tests import `require('../src/feedback')` directly — no inline reimplementation anywhere
7
+ - Config tests use `before`/`after` (not `beforeEach`/`afterEach`) since all config tests share one tmp dir with sequential state
8
+ - `normalizeFeedbackKeys` dual-key test asserts both keys are preserved (production does NOT delete `rec` when `recommendation` already exists)
9
+ - `displayConfig` covered as smoke test only (no stdout capture)
10
+ - All 34 tests are synchronous; no async/await used
11
+
12
+ ### Files Created
13
+ - test/artifacts/feature_feedback-test/test-spec.md
14
+ - test/feature_feedback-test.test.js
15
+
16
+ ### Open Questions
17
+ - None
18
+
19
+ ### Critical Context
20
+ All 34 tests pass green (`node --test test/feature_feedback-test.test.js`). No changes to `src/feedback.js` are required — the existing exports satisfy all ACs. The Config Management describe block uses a single shared tmp dir (`before`/`after`), so tests within it run sequentially and depend on one another for state (e.g. T-CM-4.1 leaves a modified config file that T-CM-5.1 then resets). Codey need not modify production code; this feature is test-only.
@@ -0,0 +1,103 @@
1
+ # Story: Config Management Functions
2
+
3
+ ## User Story
4
+
5
+ As a developer maintaining `src/feedback.js`,
6
+ I want direct unit tests for `getDefaultConfig`, `readConfig`, `writeConfig`, `setConfigValue`, `resetConfig`, and `displayConfig`,
7
+ so that config persistence logic in the production module is verified against real file I/O in an isolated environment.
8
+
9
+ ---
10
+
11
+ ## Acceptance Criteria
12
+
13
+ **Given** `getDefaultConfig()` is called,
14
+ **When** the function returns,
15
+ **Then** the result has `minRatingThreshold: 3.0`, `enabled: true`, and an `issueMappings` object containing all six standard mappings defined in `src/feedback.js`.
16
+
17
+ **Given** a `tmp` directory is set as `process.cwd()` and no config file exists there,
18
+ **When** `readConfig()` is called,
19
+ **Then** it returns a value equal to `getDefaultConfig()` and does not throw.
20
+
21
+ **Given** a `tmp` directory is set as `process.cwd()` and `.claude/feedback-config.json` contains valid JSON,
22
+ **When** `readConfig()` is called,
23
+ **Then** it returns the parsed config object matching the written content.
24
+
25
+ **Given** a `tmp` directory is set as `process.cwd()` and `.claude/feedback-config.json` contains malformed JSON (e.g. `{bad json`),
26
+ **When** `readConfig()` is called,
27
+ **Then** it returns `getDefaultConfig()` and does not throw.
28
+
29
+ **Given** a `tmp` directory is set as `process.cwd()`,
30
+ **When** `writeConfig(config)` is called with a valid config object,
31
+ **Then** `.claude/feedback-config.json` is created at the expected path and its content parses back to the original config object.
32
+
33
+ **Given** a `tmp` directory is set as `process.cwd()` and a config file exists,
34
+ **When** `setConfigValue('minRatingThreshold', '4.5')` is called,
35
+ **Then** `readConfig()` returns a config with `minRatingThreshold: 4.5`.
36
+
37
+ **Given** a `tmp` directory is set as `process.cwd()`,
38
+ **When** `setConfigValue('enabled', 'false')` is called,
39
+ **Then** `readConfig()` returns a config with `enabled: false`.
40
+
41
+ **Given** a `tmp` directory is set as `process.cwd()`,
42
+ **When** `setConfigValue` is called with an unknown key (e.g. `'nonExistentKey'`),
43
+ **Then** it throws an `Error` whose message contains `'Unknown config key'`.
44
+
45
+ **Given** a `tmp` directory is set as `process.cwd()` and a modified config file exists,
46
+ **When** `resetConfig()` is called,
47
+ **Then** `readConfig()` returns a value equal to `getDefaultConfig()`.
48
+
49
+ **Given** a `tmp` directory is set as `process.cwd()`,
50
+ **When** `displayConfig()` is called,
51
+ **Then** it does not throw (smoke test only — output format is not asserted).
52
+
53
+ ---
54
+
55
+ ## File System Isolation Pattern
56
+
57
+ Each describe block that exercises config file I/O must follow this pattern:
58
+
59
+ ```
60
+ before(): testDir = fs.mkdtempSync(os.tmpdir() + path.sep + 'feedback-test-')
61
+ originalCwd = process.cwd()
62
+ process.chdir(testDir)
63
+
64
+ after(): process.chdir(originalCwd)
65
+ fs.rmSync(testDir, { recursive: true, force: true })
66
+ ```
67
+
68
+ This mirrors the isolation pattern in `test/feature_feedback-loop.test.js`.
69
+
70
+ The `CONFIG_FILE` constant in `src/feedback.js` is `.claude/feedback-config.json`, resolved relative to `process.cwd()`. Tests must `chdir` before calling any function that reads or writes config.
71
+
72
+ ---
73
+
74
+ ## `setConfigValue` Invalid Input Cases
75
+
76
+ | key | value | Expected behaviour |
77
+ |-----------------------|-----------|-------------------------------------------------|
78
+ | `minRatingThreshold` | `'0.5'` | throws — below minimum (1.0) |
79
+ | `minRatingThreshold` | `'5.5'` | throws — above maximum (5.0) |
80
+ | `minRatingThreshold` | `'abc'` | throws — not a number |
81
+ | `enabled` | `'yes'` | throws — not `'true'` or `'false'` |
82
+ | `nonExistentKey` | `'val'` | throws — unknown key |
83
+
84
+ ---
85
+
86
+ ## Out of Scope
87
+
88
+ - Testing `displayConfig` output format or colour rendering
89
+ - Testing stdout mock/capture for `displayConfig`
90
+ - Testing `validateFeedback`, `normalizeFeedbackKeys`, `parseFeedbackFromOutput`, `shouldPause` (covered in story-validation-normalisation.md)
91
+ - End-to-end pipeline chain (covered in story-parse-pipeline.md)
92
+ - Any modification of `src/feedback.js` production code
93
+ - Modifying project-level `.claude/` files
94
+
95
+ ---
96
+
97
+ ## Implementation Notes
98
+
99
+ - Import: `const { getDefaultConfig, readConfig, writeConfig, setConfigValue, resetConfig, displayConfig } = require('../src/feedback')`
100
+ - Also import: `fs`, `os`, `path` for file system isolation
101
+ - Group under a single `describe('Config Management', ...)` or per-function sub-describes
102
+ - `displayConfig` reads config via `readConfig()`, so it also requires `chdir` setup
103
+ - See: `.blueprint/features/feature_feedback-test/FEATURE_SPEC.md` for full rules and constraints
@@ -0,0 +1,65 @@
1
+ # Story: End-to-End Parse Pipeline
2
+
3
+ ## User Story
4
+
5
+ As a developer maintaining `src/feedback.js`,
6
+ I want an integrated test that chains `parseFeedbackFromOutput` → `normalizeFeedbackKeys` → `validateFeedback` using the real production module,
7
+ so that the complete feedback extraction and validation path is verified end-to-end within the module boundary.
8
+
9
+ ---
10
+
11
+ ## Acceptance Criteria
12
+
13
+ **Given** an agent output string containing a valid `FEEDBACK: { "rating": 4, "issues": [], "rec": "proceed" }` block,
14
+ **When** the output is passed to `parseFeedbackFromOutput`, the result to `normalizeFeedbackKeys`, and that result to `validateFeedback`,
15
+ **Then** `parseFeedbackFromOutput` returns a non-null object, `normalizeFeedbackKeys` returns an object with `recommendation: 'proceed'` (not `rec`), and `validateFeedback` returns `{ valid: true, errors: [] }`.
16
+
17
+ **Given** an agent output string containing `FEEDBACK: { "rating": 2, "issues": ["unclear-scope"], "rec": "pause" }`,
18
+ **When** the same three-step chain is applied,
19
+ **Then** `validateFeedback` returns `{ valid: true, errors: [] }` (both `rec`-normalised recommendation and rating are valid), and the normalised object has `recommendation: 'pause'`.
20
+
21
+ **Given** an agent output string with `FEEDBACK: { "rating": 0, "issues": [], "recommendation": "proceed" }`,
22
+ **When** the three-step chain is applied,
23
+ **Then** `validateFeedback` returns `{ valid: false, errors: [...] }` with an error referencing the invalid rating.
24
+
25
+ **Given** an agent output string with no `FEEDBACK:` marker,
26
+ **When** `parseFeedbackFromOutput` is called,
27
+ **Then** it returns `null` and the pipeline terminates at that stage (normalisation and validation are not called with null).
28
+
29
+ ---
30
+
31
+ ## Pipeline Sequence (Explicit)
32
+
33
+ ```
34
+ input: raw output string
35
+ └─► parseFeedbackFromOutput(output)
36
+ → null → pipeline terminates (no further steps)
37
+ → parsed object → continue
38
+ └─► normalizeFeedbackKeys(parsed)
39
+ → normalised object
40
+ └─► validateFeedback(normalised)
41
+ → { valid, errors }
42
+ ```
43
+
44
+ All three functions are called on the real `src/feedback.js` module export. No step reimplements logic inline.
45
+
46
+ ---
47
+
48
+ ## Out of Scope
49
+
50
+ - File system I/O (not required for this pipeline — all functions are in-memory)
51
+ - `shouldPause` integration (not part of the parse pipeline; covered in story-validation-normalisation.md)
52
+ - Config management functions (covered in story-config-management.md)
53
+ - Any modification of `src/feedback.js` production code
54
+ - Exhaustive permutations of each step (those are covered in story-validation-normalisation.md)
55
+
56
+ ---
57
+
58
+ ## Implementation Notes
59
+
60
+ - Import: `const { parseFeedbackFromOutput, normalizeFeedbackKeys, validateFeedback } = require('../src/feedback')`
61
+ - Group under `describe('Parse Pipeline', ...)` or similar
62
+ - No file system setup required — all three functions operate on in-memory values
63
+ - This story's tests serve as the single chained integration test called for in FEATURE_SPEC.md:Rule 5
64
+ - The `rec` → `recommendation` normalisation step is critical: the raw parsed object uses `rec`, and `validateFeedback` accepts both keys — but the test should verify normalisation works correctly in the chain
65
+ - See: `.blueprint/features/feature_feedback-test/FEATURE_SPEC.md` for Rule 5 context
@@ -0,0 +1,99 @@
1
+ # Story: Validation and Normalisation Functions
2
+
3
+ ## User Story
4
+
5
+ As a developer maintaining `src/feedback.js`,
6
+ I want direct unit tests for `validateFeedback`, `normalizeFeedbackKeys`, `parseFeedbackFromOutput`, and `shouldPause`,
7
+ so that regressions in the production module are caught immediately by the test suite without relying on inline reimplementations.
8
+
9
+ ---
10
+
11
+ ## Acceptance Criteria
12
+
13
+ **Given** a feedback object with a valid integer rating (1–5), an array of strings as issues, and a valid recommendation (`proceed`, `pause`, or `revise`),
14
+ **When** `validateFeedback(feedback)` is called,
15
+ **Then** it returns `{ valid: true, errors: [] }`.
16
+
17
+ **Given** a feedback object with a rating of `0` (below range), `6` (above range), `3.5` (non-integer), or a value that is not a number,
18
+ **When** `validateFeedback(feedback)` is called,
19
+ **Then** it returns `{ valid: false, errors: [...] }` containing an appropriate error message for each invalid rating.
20
+
21
+ **Given** a feedback object where `issues` is not an array, or contains non-string elements,
22
+ **When** `validateFeedback(feedback)` is called,
23
+ **Then** it returns `{ valid: false, errors: [...] }` containing an error message describing the issues field violation.
24
+
25
+ **Given** a feedback object with `rec` key only (no `recommendation` key),
26
+ **When** `normalizeFeedbackKeys(feedback)` is called,
27
+ **Then** it returns an object with `recommendation` set to the `rec` value and no `rec` key present.
28
+
29
+ **Given** a feedback object with both `rec` and `recommendation` keys,
30
+ **When** `normalizeFeedbackKeys(feedback)` is called,
31
+ **Then** `recommendation` retains its original value (wins over `rec`) and `rec` is not deleted (both remain as-is per the production implementation).
32
+
33
+ **Given** an agent output string containing a `FEEDBACK: { ... }` JSON block with valid content,
34
+ **When** `parseFeedbackFromOutput(output)` is called,
35
+ **Then** it returns the parsed feedback object.
36
+
37
+ **Given** a feedback object with `recommendation: 'pause'` and a rating above `minRatingThreshold`,
38
+ **When** `shouldPause(feedback, config)` is called,
39
+ **Then** it returns `true`.
40
+
41
+ **Given** a feedback object with `recommendation: 'proceed'` and a rating below `minRatingThreshold`,
42
+ **When** `shouldPause(feedback, config)` is called,
43
+ **Then** it returns `true` (rating-based gate triggers independently of recommendation).
44
+
45
+ ---
46
+
47
+ ## Test Boundary Details
48
+
49
+ ### `validateFeedback` — rating boundary values to test
50
+ | Value | Expected valid |
51
+ |-------|---------------|
52
+ | 0 | false |
53
+ | 1 | true |
54
+ | 3 | true |
55
+ | 5 | true |
56
+ | 6 | false |
57
+ | 3.5 | false |
58
+
59
+ ### `normalizeFeedbackKeys` — key scenarios to test
60
+ | Scenario | Expected result |
61
+ |---------------------------------------|------------------------------------------|
62
+ | `rec` only | Renamed to `recommendation`; `rec` removed |
63
+ | `recommendation` only | Unchanged |
64
+ | Both `rec` and `recommendation` | Both keys preserved; `recommendation` value unchanged |
65
+ | Neither `rec` nor `recommendation` | Object returned unchanged |
66
+
67
+ ### `parseFeedbackFromOutput` — scenarios to test
68
+ | Input | Expected result |
69
+ |---------------------------------------|-------------------|
70
+ | Valid `FEEDBACK: { ... }` block | Parsed object |
71
+ | No `FEEDBACK:` marker | `null` |
72
+ | Malformed JSON after `FEEDBACK:` | `null` |
73
+
74
+ ### `shouldPause` — scenarios to test
75
+ | rating | minRatingThreshold | recommendation | Expected |
76
+ |--------|--------------------|----------------|----------|
77
+ | 4 | 3.0 | 'proceed' | false |
78
+ | 2 | 3.0 | 'proceed' | true |
79
+ | 4 | 3.0 | 'pause' | true |
80
+ | 2 | 3.0 | 'pause' | true |
81
+
82
+ ---
83
+
84
+ ## Out of Scope
85
+
86
+ - Config file system interaction (covered in story-config-management.md)
87
+ - End-to-end parse pipeline chain (covered in story-parse-pipeline.md)
88
+ - `displayConfig` output assertion (smoke-tested in story-config-management.md)
89
+ - Any modification of `src/feedback.js` production code
90
+ - Testing agent prompt text or insights correlation logic
91
+
92
+ ---
93
+
94
+ ## Implementation Notes
95
+
96
+ - Import: `const { validateFeedback, normalizeFeedbackKeys, parseFeedbackFromOutput, shouldPause } = require('../src/feedback')`
97
+ - No file system setup required for this story — all functions are pure or in-memory
98
+ - Describe block names should match function names: `validateFeedback`, `normalizeFeedbackKeys`, `parseFeedbackFromOutput`, `shouldPause`
99
+ - See: `.blueprint/features/feature_feedback-test/FEATURE_SPEC.md` for full rules