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,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
|