devforgeai 1.0.4 → 1.0.6
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/CLAUDE.md +120 -0
- package/package.json +9 -1
- package/src/CLAUDE.md +699 -0
- package/src/claude/scripts/README.md +396 -0
- package/src/claude/scripts/audit-command-skill-overlap.sh +67 -0
- package/src/claude/scripts/check-hooks-fast.sh +70 -0
- package/src/claude/scripts/devforgeai-validate +6 -0
- package/src/claude/scripts/devforgeai_cli/README.md +531 -0
- package/src/claude/scripts/devforgeai_cli/__init__.py +12 -0
- package/src/claude/scripts/devforgeai_cli/cli.py +716 -0
- package/src/claude/scripts/devforgeai_cli/commands/__init__.py +1 -0
- package/src/claude/scripts/devforgeai_cli/commands/check_hooks.py +384 -0
- package/src/claude/scripts/devforgeai_cli/commands/invoke_hooks.py +149 -0
- package/src/claude/scripts/devforgeai_cli/commands/phase_commands.py +731 -0
- package/src/claude/scripts/devforgeai_cli/commands/validate_installation.py +412 -0
- package/src/claude/scripts/devforgeai_cli/context_extraction.py +426 -0
- package/src/claude/scripts/devforgeai_cli/feedback/AC_TO_TEST_MAPPING.md +636 -0
- package/src/claude/scripts/devforgeai_cli/feedback/DELIVERY_SUMMARY.txt +329 -0
- package/src/claude/scripts/devforgeai_cli/feedback/README_TEST_SPECS.md +486 -0
- package/src/claude/scripts/devforgeai_cli/feedback/TEST_IMPLEMENTATION_GUIDE.md +529 -0
- package/src/claude/scripts/devforgeai_cli/feedback/TEST_SPECIFICATIONS.md +2652 -0
- package/src/claude/scripts/devforgeai_cli/feedback/TEST_SPECS_INDEX.md +398 -0
- package/src/claude/scripts/devforgeai_cli/feedback/__init__.py +34 -0
- package/src/claude/scripts/devforgeai_cli/feedback/adaptive_questioning_engine.py +581 -0
- package/src/claude/scripts/devforgeai_cli/feedback/aggregation.py +179 -0
- package/src/claude/scripts/devforgeai_cli/feedback/commands.py +535 -0
- package/src/claude/scripts/devforgeai_cli/feedback/config_defaults.py +58 -0
- package/src/claude/scripts/devforgeai_cli/feedback/config_manager.py +423 -0
- package/src/claude/scripts/devforgeai_cli/feedback/config_models.py +192 -0
- package/src/claude/scripts/devforgeai_cli/feedback/config_schema.py +140 -0
- package/src/claude/scripts/devforgeai_cli/feedback/coverage.json +1 -0
- package/src/claude/scripts/devforgeai_cli/feedback/feature_flag.py +152 -0
- package/src/claude/scripts/devforgeai_cli/feedback/feedback_indexer.py +394 -0
- package/src/claude/scripts/devforgeai_cli/feedback/hot_reload.py +226 -0
- package/src/claude/scripts/devforgeai_cli/feedback/longitudinal.py +115 -0
- package/src/claude/scripts/devforgeai_cli/feedback/models.py +67 -0
- package/src/claude/scripts/devforgeai_cli/feedback/question_router.py +236 -0
- package/src/claude/scripts/devforgeai_cli/feedback/retrospective.py +233 -0
- package/src/claude/scripts/devforgeai_cli/feedback/skip_tracker.py +177 -0
- package/src/claude/scripts/devforgeai_cli/feedback/skip_tracking.py +221 -0
- package/src/claude/scripts/devforgeai_cli/feedback/template_engine.py +549 -0
- package/src/claude/scripts/devforgeai_cli/feedback/validation.py +163 -0
- package/src/claude/scripts/devforgeai_cli/headless/__init__.py +30 -0
- package/src/claude/scripts/devforgeai_cli/headless/answer_models.py +206 -0
- package/src/claude/scripts/devforgeai_cli/headless/answer_resolver.py +204 -0
- package/src/claude/scripts/devforgeai_cli/headless/exceptions.py +36 -0
- package/src/claude/scripts/devforgeai_cli/headless/pattern_matcher.py +156 -0
- package/src/claude/scripts/devforgeai_cli/hooks.py +313 -0
- package/src/claude/scripts/devforgeai_cli/metrics/__init__.py +46 -0
- package/src/claude/scripts/devforgeai_cli/metrics/command_metrics.py +142 -0
- package/src/claude/scripts/devforgeai_cli/metrics/failure_modes.py +152 -0
- package/src/claude/scripts/devforgeai_cli/metrics/story_segmentation.py +181 -0
- package/src/claude/scripts/devforgeai_cli/orchestrate_hooks.py +780 -0
- package/src/claude/scripts/devforgeai_cli/phase_state.py +1229 -0
- package/src/claude/scripts/devforgeai_cli/session/__init__.py +30 -0
- package/src/claude/scripts/devforgeai_cli/session/checkpoint.py +268 -0
- package/src/claude/scripts/devforgeai_cli/tests/__init__.py +1 -0
- package/src/claude/scripts/devforgeai_cli/tests/conftest.py +29 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/TEST_EXECUTION_GUIDE.md +298 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/__init__.py +3 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_adaptive_questioning_engine.py +2171 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_aggregation.py +476 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_config_defaults.py +133 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_config_manager.py +592 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_config_models.py +373 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_config_schema.py +130 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_configuration_management.py +1355 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_edge_cases.py +308 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_feature_flag.py +307 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_feedback_indexer.py +384 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_hot_reload.py +580 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_integration.py +402 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_models.py +105 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_question_routing.py +262 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_retrospective.py +333 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_skip_tracker.py +410 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_skip_tracking.py +159 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_skip_tracking_integration.py +1155 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_template_engine.py +1389 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_validation_comprehensive.py +210 -0
- package/src/claude/scripts/devforgeai_cli/tests/fixtures/autonomous-deferral-story.md +46 -0
- package/src/claude/scripts/devforgeai_cli/tests/fixtures/missing-impl-notes.md +31 -0
- package/src/claude/scripts/devforgeai_cli/tests/fixtures/valid-deferral-story.md +46 -0
- package/src/claude/scripts/devforgeai_cli/tests/fixtures/valid-story-complete.md +48 -0
- package/src/claude/scripts/devforgeai_cli/tests/manual_test_invoke_hooks.sh +200 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/DELIVERABLES.md +518 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/TEST_SUMMARY.md +468 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/__init__.py +6 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/fixtures/corrupted-checkpoint.json +1 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/fixtures/missing-fields-checkpoint.json +4 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/fixtures/valid-checkpoint.json +15 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/test_checkpoint.py +851 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_check_hooks.py +1886 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_depends_on_normalizer.py +171 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_dod_validator.py +97 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_invoke_hooks.py +1902 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_phase_commands.py +320 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_phase_commands_error_handling.py +1021 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_phase_commands_import.py +697 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_phase_state.py +2187 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_skip_tracking.py +2141 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_skip_tracking_coverage_gap.py +195 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_subagent_enforcement.py +539 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_validate_installation.py +361 -0
- package/src/claude/scripts/devforgeai_cli/utils/__init__.py +11 -0
- package/src/claude/scripts/devforgeai_cli/utils/depends_on_normalizer.py +149 -0
- package/src/claude/scripts/devforgeai_cli/utils/markdown_parser.py +219 -0
- package/src/claude/scripts/devforgeai_cli/utils/story_analyzer.py +249 -0
- package/src/claude/scripts/devforgeai_cli/utils/yaml_parser.py +152 -0
- package/src/claude/scripts/devforgeai_cli/validators/__init__.py +27 -0
- package/src/claude/scripts/devforgeai_cli/validators/ast_grep_validator.py +373 -0
- package/src/claude/scripts/devforgeai_cli/validators/context_validator.py +180 -0
- package/src/claude/scripts/devforgeai_cli/validators/dod_validator.py +309 -0
- package/src/claude/scripts/devforgeai_cli/validators/git_validator.py +107 -0
- package/src/claude/scripts/devforgeai_cli/validators/grep_fallback.py +300 -0
- package/src/claude/scripts/install_hooks.sh +186 -0
- package/src/claude/scripts/invoke_feedback_hooks.sh +59 -0
- package/src/claude/scripts/migrate-ac-headers.sh +122 -0
- package/src/claude/scripts/plan_file_kb.sh +704 -0
- package/src/claude/scripts/requirements.txt +8 -0
- package/src/claude/scripts/session_catalog.sh +543 -0
- package/src/claude/scripts/setup.py +55 -0
- package/src/claude/scripts/start-devforgeai.sh +16 -0
- package/src/claude/scripts/statusline.sh +27 -0
- package/src/claude/scripts/validate_deferrals.py +344 -0
- package/src/claude/skills/devforgeai-qa/SKILL.md +1 -1
- package/src/claude/skills/researching-market/SKILL.md +2 -1
- package/src/cli/lib/copier.js +13 -1
- package/src/claude/skills/designing-systems/scripts/__pycache__/detect_anti_patterns.cpython-312.pyc +0 -0
- package/src/claude/skills/designing-systems/scripts/__pycache__/validate_all_context.cpython-312.pyc +0 -0
- package/src/claude/skills/designing-systems/scripts/__pycache__/validate_architecture.cpython-312.pyc +0 -0
- package/src/claude/skills/designing-systems/scripts/__pycache__/validate_dependencies.cpython-312.pyc +0 -0
- package/src/claude/skills/devforgeai-story-creation/scripts/__pycache__/migrate_story_v1_to_v2.cpython-312.pyc +0 -0
- package/src/claude/skills/devforgeai-story-creation/scripts/tests/__pycache__/measure_accuracy.cpython-312.pyc +0 -0
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
# Acceptance Criteria to Test Mapping
|
|
2
|
+
|
|
3
|
+
**Story:** STORY-011 Configuration Management
|
|
4
|
+
**Purpose:** Map acceptance criteria (AC-1 through AC-9) to specific test methods
|
|
5
|
+
|
|
6
|
+
This document ensures 100% coverage of story requirements through test design.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## AC-1: Configuration File Loads with Valid YAML Structure
|
|
11
|
+
|
|
12
|
+
**Requirement:** Configuration file with valid YAML structure loads successfully.
|
|
13
|
+
|
|
14
|
+
### Test Methods
|
|
15
|
+
|
|
16
|
+
| Test Class | Test Method | Coverage |
|
|
17
|
+
|-----------|-----------|----------|
|
|
18
|
+
| TestConfigurationLoading | test_load_valid_yaml_file | Lines 109-136, 226-248 |
|
|
19
|
+
| TestConfigurationLoading | test_load_empty_yaml_file | Lines 127-129 |
|
|
20
|
+
| TestConfigurationLoading | test_load_yaml_non_dict_content | Lines 129 |
|
|
21
|
+
| TestConfigurationLoading | test_load_configuration_exception_recovery | Lines 250-253 |
|
|
22
|
+
| TestConfigurationAccess | test_get_configuration_returns_current | Lines 265-274 |
|
|
23
|
+
| TestConfigurationMerging | test_merge_complete_config | Lines 151-173 |
|
|
24
|
+
| TestConfigurationValidation | test_dict_to_configuration_valid | Lines 192-224 |
|
|
25
|
+
|
|
26
|
+
### Assertion Examples
|
|
27
|
+
```python
|
|
28
|
+
# Configuration loads without error
|
|
29
|
+
config = manager.load_configuration()
|
|
30
|
+
assert config is not None
|
|
31
|
+
assert isinstance(config, FeedbackConfiguration)
|
|
32
|
+
|
|
33
|
+
# All sections accessible
|
|
34
|
+
assert config.enabled is not None
|
|
35
|
+
assert config.trigger_mode is not None
|
|
36
|
+
assert config.conversation_settings is not None
|
|
37
|
+
assert config.skip_tracking is not None
|
|
38
|
+
assert config.templates is not None
|
|
39
|
+
|
|
40
|
+
# No parsing errors logged
|
|
41
|
+
assert not any("parsing error" in line for line in error_log)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Related Specifications
|
|
45
|
+
- Lines in config_manager.py: 109-136 (YAML loading)
|
|
46
|
+
- Lines in config_manager.py: 226-248 (load_configuration)
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## AC-2: Master Enable/Disable Controls All Feedback Operations
|
|
51
|
+
|
|
52
|
+
**Requirement:** `enabled: true/false` controls all feedback collection.
|
|
53
|
+
|
|
54
|
+
### Test Methods
|
|
55
|
+
|
|
56
|
+
| Test Class | Test Method | Coverage |
|
|
57
|
+
|-----------|-----------|----------|
|
|
58
|
+
| TestConfigurationAccess | test_is_enabled_true | Lines 285-292 |
|
|
59
|
+
| TestConfigurationAccess | test_is_enabled_false | Lines 285-292 |
|
|
60
|
+
| TestFeedbackConfiguration | test_feedback_configuration_validate_enabled_true | Lines 161-166 |
|
|
61
|
+
| TestFeedbackConfiguration | test_feedback_configuration_validate_enabled_false | Lines 161-166 |
|
|
62
|
+
| TestFeedbackConfiguration | test_feedback_configuration_validate_enabled_non_bool | Lines 163-166 |
|
|
63
|
+
|
|
64
|
+
### Assertion Examples
|
|
65
|
+
```python
|
|
66
|
+
# Master enable works
|
|
67
|
+
config_true = FeedbackConfiguration(enabled=True)
|
|
68
|
+
assert config_true.enabled == True
|
|
69
|
+
assert manager.is_enabled() == True
|
|
70
|
+
|
|
71
|
+
# Master disable works
|
|
72
|
+
config_false = FeedbackConfiguration(enabled=False)
|
|
73
|
+
assert config_false.enabled == False
|
|
74
|
+
assert manager.is_enabled() == False
|
|
75
|
+
|
|
76
|
+
# Non-boolean rejected
|
|
77
|
+
with pytest.raises(ValueError):
|
|
78
|
+
FeedbackConfiguration(enabled="true")
|
|
79
|
+
|
|
80
|
+
# Integration: feedback disabled
|
|
81
|
+
config = manager.get_configuration()
|
|
82
|
+
if not config.enabled:
|
|
83
|
+
# No feedback should be collected
|
|
84
|
+
assert manager.is_enabled() == False
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Related Specifications
|
|
88
|
+
- Lines in config_manager.py: 285-292 (is_enabled getter)
|
|
89
|
+
- Lines in config_models.py: 161-166 (enabled validation)
|
|
90
|
+
- FeedbackConfiguration.__post_init__ (lines 176-181)
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## AC-3: Trigger Mode Determines When Feedback is Collected
|
|
95
|
+
|
|
96
|
+
**Requirement:** Trigger mode (`always`, `failures-only`, `specific-operations`, `never`) controls when feedback is collected.
|
|
97
|
+
|
|
98
|
+
### Test Methods
|
|
99
|
+
|
|
100
|
+
| Test Class | Test Method | Coverage |
|
|
101
|
+
|-----------|-----------|----------|
|
|
102
|
+
| TestConfigurationAccess | test_get_trigger_mode | Lines 294-301 |
|
|
103
|
+
| TestConfigurationAccess | test_get_trigger_mode_variations | Lines 294-301 |
|
|
104
|
+
| TestFeedbackConfiguration | test_feedback_configuration_validate_trigger_mode_always | Lines 153-159 |
|
|
105
|
+
| TestFeedbackConfiguration | test_feedback_configuration_validate_trigger_mode_failures_only | Lines 153-159 |
|
|
106
|
+
| TestFeedbackConfiguration | test_feedback_configuration_validate_trigger_mode_specific_ops | Lines 153-159 |
|
|
107
|
+
| TestFeedbackConfiguration | test_feedback_configuration_validate_trigger_mode_never | Lines 153-159 |
|
|
108
|
+
| TestFeedbackConfiguration | test_feedback_configuration_validate_trigger_mode_invalid | Lines 155-159 |
|
|
109
|
+
| TestFeedbackConfiguration | test_feedback_configuration_validate_trigger_mode_case_sensitive | Lines 155-159 |
|
|
110
|
+
|
|
111
|
+
### Assertion Examples
|
|
112
|
+
```python
|
|
113
|
+
# All valid modes
|
|
114
|
+
valid_modes = ["always", "failures-only", "specific-operations", "never"]
|
|
115
|
+
for mode in valid_modes:
|
|
116
|
+
config = FeedbackConfiguration(trigger_mode=mode)
|
|
117
|
+
assert config.trigger_mode == mode
|
|
118
|
+
|
|
119
|
+
# Invalid mode rejected
|
|
120
|
+
with pytest.raises(ValueError, match="Invalid trigger_mode"):
|
|
121
|
+
FeedbackConfiguration(trigger_mode="invalid-mode")
|
|
122
|
+
|
|
123
|
+
# Case-sensitive
|
|
124
|
+
with pytest.raises(ValueError):
|
|
125
|
+
FeedbackConfiguration(trigger_mode="Always") # ✗
|
|
126
|
+
|
|
127
|
+
# Operations required for specific-operations
|
|
128
|
+
with pytest.raises(ValueError, match="operations list must be provided"):
|
|
129
|
+
FeedbackConfiguration(
|
|
130
|
+
trigger_mode="specific-operations",
|
|
131
|
+
operations=None
|
|
132
|
+
)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Related Specifications
|
|
136
|
+
- Lines in config_models.py: 153-159 (trigger_mode validation)
|
|
137
|
+
- TriggerMode enum: lines 13-18
|
|
138
|
+
- VALID_TRIGGER_MODES constant: line 36
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## AC-4: Conversation Settings Enforce Question Limits and Skip Permissions
|
|
143
|
+
|
|
144
|
+
**Requirement:** `max_questions` and `allow_skip` control feedback collection behavior.
|
|
145
|
+
|
|
146
|
+
### Test Methods
|
|
147
|
+
|
|
148
|
+
| Test Class | Test Method | Coverage |
|
|
149
|
+
|-----------|-----------|----------|
|
|
150
|
+
| TestConversationSettings | test_conversation_settings_init_defaults | Lines 40-48 |
|
|
151
|
+
| TestConversationSettings | test_conversation_settings_init_custom_values | Lines 40-48 |
|
|
152
|
+
| TestConversationSettings | test_conversation_settings_post_init_valid | Lines 50-59 |
|
|
153
|
+
| TestConversationSettings | test_conversation_settings_max_questions_negative | Lines 52-55 |
|
|
154
|
+
| TestConversationSettings | test_conversation_settings_max_questions_non_int | Lines 52-55 |
|
|
155
|
+
| TestConversationSettings | test_conversation_settings_allow_skip_non_bool | Lines 56-59 |
|
|
156
|
+
| TestConversationSettings | test_conversation_settings_max_questions_zero | Lines 52 |
|
|
157
|
+
| TestConversationSettings | test_conversation_settings_max_questions_large | Lines 52-55 |
|
|
158
|
+
| TestConfigurationAccess | test_get_conversation_settings | Lines 325-331 |
|
|
159
|
+
|
|
160
|
+
### Assertion Examples
|
|
161
|
+
```python
|
|
162
|
+
# Default values
|
|
163
|
+
settings = ConversationSettings()
|
|
164
|
+
assert settings.max_questions == 5
|
|
165
|
+
assert settings.allow_skip == True
|
|
166
|
+
|
|
167
|
+
# Custom values
|
|
168
|
+
settings = ConversationSettings(max_questions=3, allow_skip=False)
|
|
169
|
+
assert settings.max_questions == 3
|
|
170
|
+
assert settings.allow_skip == False
|
|
171
|
+
|
|
172
|
+
# Validation: negative rejected
|
|
173
|
+
with pytest.raises(ValueError, match="non-negative integer"):
|
|
174
|
+
ConversationSettings(max_questions=-1)
|
|
175
|
+
|
|
176
|
+
# Validation: zero = unlimited (valid)
|
|
177
|
+
settings = ConversationSettings(max_questions=0)
|
|
178
|
+
assert settings.max_questions == 0 # ✓
|
|
179
|
+
|
|
180
|
+
# Validation: non-bool rejected
|
|
181
|
+
with pytest.raises(ValueError, match="boolean"):
|
|
182
|
+
ConversationSettings(allow_skip="true")
|
|
183
|
+
|
|
184
|
+
# Integration: retrieved correctly
|
|
185
|
+
config = manager.get_conversation_settings()
|
|
186
|
+
assert config.max_questions == 5
|
|
187
|
+
assert config.allow_skip == True
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Related Specifications
|
|
191
|
+
- Lines in config_models.py: 40-59 (ConversationSettings)
|
|
192
|
+
- Defaults: max_questions=5, allow_skip=True
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## AC-5: Skip Tracking Maintains Feedback Collection Statistics
|
|
197
|
+
|
|
198
|
+
**Requirement:** Skip tracking with configurable limits and positive feedback reset.
|
|
199
|
+
|
|
200
|
+
### Test Methods
|
|
201
|
+
|
|
202
|
+
| Test Class | Test Method | Coverage |
|
|
203
|
+
|-----------|-----------|----------|
|
|
204
|
+
| TestSkipTrackerInitialization | test_skip_tracker_loads_existing_counters | Lines 42-62 |
|
|
205
|
+
| TestSkipTrackerIncrement | test_increment_skip_new_operation | Lines 85-99 |
|
|
206
|
+
| TestSkipTrackerIncrement | test_increment_skip_existing_operation | Lines 94-97 |
|
|
207
|
+
| TestSkipTrackerLimitCheck | test_check_skip_limit_reached | Lines 142-144 |
|
|
208
|
+
| TestSkipTrackerLimitCheck | test_check_skip_limit_zero_unlimited | Lines 136-138 |
|
|
209
|
+
| TestSkipTrackerPositiveFeedback | test_reset_on_positive_above_threshold | Lines 147-160 |
|
|
210
|
+
| TestSkipTrackerPositiveFeedback | test_reset_on_positive_below_threshold | Lines 159 |
|
|
211
|
+
| TestSkipTrackerCounterAccess | test_get_skip_count_existing | Lines 101-111 |
|
|
212
|
+
| TestSkipTrackerReset | test_reset_skip_counter | Lines 113-122 |
|
|
213
|
+
| TestSkipTrackingSettings | test_skip_tracking_settings_init_defaults | Lines 62-73 |
|
|
214
|
+
| TestSkipTrackingSettings | test_skip_tracking_settings_enabled_non_bool | Lines 77-80 |
|
|
215
|
+
| TestSkipTrackingSettings | test_skip_tracking_settings_max_zero | Lines 81 |
|
|
216
|
+
| TestConfigurationAccess | test_get_skip_tracking_settings | Lines 333-339 |
|
|
217
|
+
| TestConfigurationAccess | test_get_skip_tracker | Lines 349-355 |
|
|
218
|
+
|
|
219
|
+
### Assertion Examples
|
|
220
|
+
```python
|
|
221
|
+
# Initialize with defaults
|
|
222
|
+
settings = SkipTrackingSettings()
|
|
223
|
+
assert settings.enabled == True
|
|
224
|
+
assert settings.max_consecutive_skips == 3
|
|
225
|
+
assert settings.reset_on_positive == True
|
|
226
|
+
|
|
227
|
+
# Validation: negative rejected
|
|
228
|
+
with pytest.raises(ValueError, match="non-negative integer"):
|
|
229
|
+
SkipTrackingSettings(max_consecutive_skips=-1)
|
|
230
|
+
|
|
231
|
+
# Increment counter
|
|
232
|
+
tracker = SkipTracker()
|
|
233
|
+
count = tracker.increment_skip("qa_operation")
|
|
234
|
+
assert count == 1
|
|
235
|
+
assert tracker.get_skip_count("qa_operation") == 1
|
|
236
|
+
|
|
237
|
+
# Check limit (reached)
|
|
238
|
+
for _ in range(3):
|
|
239
|
+
tracker.increment_skip("qa_operation")
|
|
240
|
+
assert tracker.check_skip_limit("qa_operation", max_consecutive_skips=3) == True
|
|
241
|
+
|
|
242
|
+
# Check limit (not reached)
|
|
243
|
+
assert tracker.check_skip_limit("qa_operation", max_consecutive_skips=5) == False
|
|
244
|
+
|
|
245
|
+
# Check limit (unlimited with 0)
|
|
246
|
+
assert tracker.check_skip_limit("qa_operation", max_consecutive_skips=0) == False
|
|
247
|
+
|
|
248
|
+
# Positive feedback resets
|
|
249
|
+
tracker.increment_skip("operation")
|
|
250
|
+
tracker.reset_on_positive("operation", rating=5) # > 4 (default threshold)
|
|
251
|
+
assert tracker.get_skip_count("operation") == 0
|
|
252
|
+
|
|
253
|
+
# Positive feedback doesn't reset if below threshold
|
|
254
|
+
tracker.increment_skip("operation")
|
|
255
|
+
tracker.reset_on_positive("operation", rating=3) # < 4
|
|
256
|
+
assert tracker.get_skip_count("operation") == 1
|
|
257
|
+
|
|
258
|
+
# Log persistence
|
|
259
|
+
assert tracker.skip_log_path.exists()
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Related Specifications
|
|
263
|
+
- Lines in skip_tracker.py: 15-178 (complete SkipTracker class)
|
|
264
|
+
- Lines in config_models.py: 62-88 (SkipTrackingSettings)
|
|
265
|
+
- Default threshold: 4 (line 25 in skip_tracker.py)
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## AC-6: Template Preferences Control Feedback Collection Format
|
|
270
|
+
|
|
271
|
+
**Requirement:** Template format (`structured` or `free-text`) and tone (`brief` or `detailed`) control feedback UI.
|
|
272
|
+
|
|
273
|
+
### Test Methods
|
|
274
|
+
|
|
275
|
+
| Test Class | Test Method | Coverage |
|
|
276
|
+
|-----------|-----------|----------|
|
|
277
|
+
| TestTemplateSettings | test_template_settings_init_defaults | Lines 91-100 |
|
|
278
|
+
| TestTemplateSettings | test_template_settings_init_custom_values | Lines 91-100 |
|
|
279
|
+
| TestTemplateSettings | test_template_settings_format_structured | Lines 102-108 |
|
|
280
|
+
| TestTemplateSettings | test_template_settings_format_free_text | Lines 102-108 |
|
|
281
|
+
| TestTemplateSettings | test_template_settings_format_invalid | Lines 104-108 |
|
|
282
|
+
| TestTemplateSettings | test_template_settings_tone_brief | Lines 110-114 |
|
|
283
|
+
| TestTemplateSettings | test_template_settings_tone_detailed | Lines 110-114 |
|
|
284
|
+
| TestTemplateSettings | test_template_settings_tone_invalid | Lines 110-114 |
|
|
285
|
+
| TestTemplateSettings | test_template_settings_format_case_sensitive | Lines 104-108 |
|
|
286
|
+
| TestTemplateSettings | test_template_settings_tone_case_sensitive | Lines 110-114 |
|
|
287
|
+
| TestConfigurationAccess | test_get_template_settings | Lines 341-347 |
|
|
288
|
+
|
|
289
|
+
### Assertion Examples
|
|
290
|
+
```python
|
|
291
|
+
# Default values
|
|
292
|
+
settings = TemplateSettings()
|
|
293
|
+
assert settings.format == "structured"
|
|
294
|
+
assert settings.tone == "brief"
|
|
295
|
+
|
|
296
|
+
# Valid formats
|
|
297
|
+
for fmt in ["structured", "free-text"]:
|
|
298
|
+
settings = TemplateSettings(format=fmt)
|
|
299
|
+
assert settings.format == fmt
|
|
300
|
+
|
|
301
|
+
# Valid tones
|
|
302
|
+
for tone in ["brief", "detailed"]:
|
|
303
|
+
settings = TemplateSettings(tone=tone)
|
|
304
|
+
assert settings.tone == tone
|
|
305
|
+
|
|
306
|
+
# Invalid format rejected
|
|
307
|
+
with pytest.raises(ValueError, match="Invalid template format"):
|
|
308
|
+
TemplateSettings(format="invalid")
|
|
309
|
+
|
|
310
|
+
# Invalid tone rejected
|
|
311
|
+
with pytest.raises(ValueError, match="Invalid template tone"):
|
|
312
|
+
TemplateSettings(tone="vague")
|
|
313
|
+
|
|
314
|
+
# Case-sensitive
|
|
315
|
+
with pytest.raises(ValueError):
|
|
316
|
+
TemplateSettings(format="Structured") # Capital S
|
|
317
|
+
|
|
318
|
+
# Integration: retrieved correctly
|
|
319
|
+
config = manager.get_template_settings()
|
|
320
|
+
assert config.format == "structured"
|
|
321
|
+
assert config.tone == "brief"
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Related Specifications
|
|
325
|
+
- Lines in config_models.py: 91-114 (TemplateSettings)
|
|
326
|
+
- TemplateFormat enum: lines 21-24
|
|
327
|
+
- TemplateTone enum: lines 27-30
|
|
328
|
+
- VALID_TEMPLATE_FORMATS constant: line 34
|
|
329
|
+
- VALID_TEMPLATE_TONES constant: line 35
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## AC-7: Invalid Configuration Values Rejected with Clear Error Messages
|
|
334
|
+
|
|
335
|
+
**Requirement:** Invalid configuration raises errors with clear messages and logs.
|
|
336
|
+
|
|
337
|
+
### Test Methods
|
|
338
|
+
|
|
339
|
+
| Test Class | Test Method | Coverage |
|
|
340
|
+
|-----------|-----------|----------|
|
|
341
|
+
| TestConfigurationValidation | test_dict_to_configuration_invalid_trigger_mode | Lines 220-224 |
|
|
342
|
+
| TestConfigurationValidation | test_dict_to_configuration_missing_operations_specific_ops | Lines 220-224 |
|
|
343
|
+
| TestConfigurationValidation | test_dict_to_configuration_invalid_enabled_type | Lines 220-224 |
|
|
344
|
+
| TestFeedbackConfiguration | test_feedback_configuration_validate_trigger_mode_invalid | Lines 155-159 |
|
|
345
|
+
| TestFeedbackConfiguration | test_feedback_configuration_validate_enabled_non_bool | Lines 163-166 |
|
|
346
|
+
| TestFeedbackConfiguration | test_feedback_configuration_validate_operations_specific_ops_required | Lines 168-174 |
|
|
347
|
+
| TestConversationSettings | test_conversation_settings_max_questions_negative | Lines 52-55 |
|
|
348
|
+
| TestConversationSettings | test_conversation_settings_allow_skip_non_bool | Lines 56-59 |
|
|
349
|
+
| TestSkipTrackingSettings | test_skip_tracking_settings_enabled_non_bool | Lines 77-80 |
|
|
350
|
+
| TestSkipTrackingSettings | test_skip_tracking_settings_max_negative | Lines 81-84 |
|
|
351
|
+
| TestSkipTrackingSettings | test_skip_tracking_settings_reset_non_bool | Lines 85-88 |
|
|
352
|
+
| TestTemplateSettings | test_template_settings_format_invalid | Lines 104-108 |
|
|
353
|
+
| TestTemplateSettings | test_template_settings_tone_invalid | Lines 110-114 |
|
|
354
|
+
| TestConfigurationManager_ErrorHandling | test_log_error_writes_to_file | Lines 88-104 |
|
|
355
|
+
| TestConfigurationLoading | test_load_invalid_yaml_syntax | Lines 131-133 |
|
|
356
|
+
| TestConfigurationLoading | test_load_yaml_with_ioerror | Lines 134-136 |
|
|
357
|
+
|
|
358
|
+
### Assertion Examples
|
|
359
|
+
```python
|
|
360
|
+
# Invalid trigger_mode
|
|
361
|
+
with pytest.raises(ValueError) as exc_info:
|
|
362
|
+
FeedbackConfiguration(trigger_mode="invalid-mode")
|
|
363
|
+
error_msg = str(exc_info.value)
|
|
364
|
+
assert "Invalid trigger_mode" in error_msg
|
|
365
|
+
assert "always" in error_msg
|
|
366
|
+
assert "failures-only" in error_msg
|
|
367
|
+
assert "specific-operations" in error_msg
|
|
368
|
+
assert "never" in error_msg
|
|
369
|
+
|
|
370
|
+
# Specific-operations requires operations
|
|
371
|
+
with pytest.raises(ValueError) as exc_info:
|
|
372
|
+
FeedbackConfiguration(trigger_mode="specific-operations", operations=None)
|
|
373
|
+
assert "operations" in str(exc_info.value)
|
|
374
|
+
|
|
375
|
+
# Non-boolean enabled
|
|
376
|
+
with pytest.raises(ValueError) as exc_info:
|
|
377
|
+
FeedbackConfiguration(enabled="true")
|
|
378
|
+
assert "boolean" in str(exc_info.value).lower()
|
|
379
|
+
|
|
380
|
+
# Negative max_questions
|
|
381
|
+
with pytest.raises(ValueError) as exc_info:
|
|
382
|
+
ConversationSettings(max_questions=-1)
|
|
383
|
+
assert "non-negative" in str(exc_info.value)
|
|
384
|
+
|
|
385
|
+
# Invalid YAML
|
|
386
|
+
with pytest.raises(yaml.YAMLError):
|
|
387
|
+
config_file.write_text("trigger_mode: [") # Invalid YAML
|
|
388
|
+
manager.load_configuration()
|
|
389
|
+
|
|
390
|
+
# Errors logged to file
|
|
391
|
+
manager._log_error("Test error")
|
|
392
|
+
error_log = manager._config_errors_log
|
|
393
|
+
assert error_log.exists()
|
|
394
|
+
content = error_log.read_text()
|
|
395
|
+
assert "Test error" in content
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Related Specifications
|
|
399
|
+
- Lines in config_manager.py: 220-224 (validation in _dict_to_configuration)
|
|
400
|
+
- Lines in config_models.py: 50-59, 77-88, 102-114, 161-181 (all validations)
|
|
401
|
+
- Lines in config_manager.py: 88-104 (error logging)
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## AC-8: Missing Configuration File Uses Sensible Defaults
|
|
406
|
+
|
|
407
|
+
**Requirement:** No config file → use defaults with enabled, trigger_mode, conversation_settings.
|
|
408
|
+
|
|
409
|
+
### Test Methods
|
|
410
|
+
|
|
411
|
+
| Test Class | Test Method | Coverage |
|
|
412
|
+
|-----------|-----------|----------|
|
|
413
|
+
| TestConfigurationLoading | test_load_missing_yaml_file | Lines 119-120, 240-253 |
|
|
414
|
+
| TestConfigurationMerging | test_merge_none_with_defaults | Lines 160-161 |
|
|
415
|
+
| TestConfigurationMerging | test_merge_partial_config | Lines 151-173 |
|
|
416
|
+
| TestConfigurationMerging | test_merge_complete_config | Lines 151-173 |
|
|
417
|
+
| TestConfigurationMerging | test_merge_nested_conversation_settings | Lines 138-150, 170-171 |
|
|
418
|
+
| TestConfigurationMerging | test_merge_nested_skip_tracking | Lines 138-150, 170-171 |
|
|
419
|
+
| TestConfigurationMerging | test_merge_nested_templates | Lines 138-150, 170-171 |
|
|
420
|
+
| TestConfigDefaults | test_default_config_dict_exists | Lines 11-28 |
|
|
421
|
+
| TestConfigDefaults | test_default_config_dict_has_enabled | Lines 12 |
|
|
422
|
+
| TestConfigDefaults | test_default_config_dict_has_trigger_mode | Lines 13 |
|
|
423
|
+
| TestConfigDefaults | test_default_config_dict_conversation_settings | Lines 15-17 |
|
|
424
|
+
| TestConfigDefaults | test_default_config_dict_skip_tracking | Lines 19-22 |
|
|
425
|
+
| TestConfigDefaults | test_default_config_dict_templates | Lines 24-26 |
|
|
426
|
+
| TestConfigDefaults | test_get_default_config_returns_copy | Lines 31-37 |
|
|
427
|
+
| TestConfigDefaults | test_get_default_config_has_all_fields | Lines 31-37 |
|
|
428
|
+
|
|
429
|
+
### Assertion Examples
|
|
430
|
+
```python
|
|
431
|
+
# Missing file uses defaults
|
|
432
|
+
# (Don't create config file)
|
|
433
|
+
config = manager.load_configuration()
|
|
434
|
+
assert config.enabled == True
|
|
435
|
+
assert config.trigger_mode == "failures-only"
|
|
436
|
+
assert config.conversation_settings.max_questions == 5
|
|
437
|
+
assert config.conversation_settings.allow_skip == True
|
|
438
|
+
assert config.skip_tracking.enabled == True
|
|
439
|
+
assert config.skip_tracking.max_consecutive_skips == 3
|
|
440
|
+
assert config.skip_tracking.reset_on_positive == True
|
|
441
|
+
assert config.templates.format == "structured"
|
|
442
|
+
assert config.templates.tone == "brief"
|
|
443
|
+
|
|
444
|
+
# Default config dict
|
|
445
|
+
defaults = get_default_config()
|
|
446
|
+
assert defaults == {
|
|
447
|
+
"enabled": True,
|
|
448
|
+
"trigger_mode": "failures-only",
|
|
449
|
+
"operations": None,
|
|
450
|
+
"conversation_settings": {
|
|
451
|
+
"max_questions": 5,
|
|
452
|
+
"allow_skip": True
|
|
453
|
+
},
|
|
454
|
+
"skip_tracking": {
|
|
455
|
+
"enabled": True,
|
|
456
|
+
"max_consecutive_skips": 3,
|
|
457
|
+
"reset_on_positive": True
|
|
458
|
+
},
|
|
459
|
+
"templates": {
|
|
460
|
+
"format": "structured",
|
|
461
|
+
"tone": "brief"
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
# Defaults returned as copy (not reference)
|
|
466
|
+
defaults1 = get_default_config()
|
|
467
|
+
defaults2 = get_default_config()
|
|
468
|
+
defaults1["enabled"] = False
|
|
469
|
+
assert defaults2["enabled"] == True # Unchanged
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Related Specifications
|
|
473
|
+
- Lines in config_manager.py: 119-120, 160-161 (missing file handling)
|
|
474
|
+
- Lines in config_defaults.py: 11-37 (all default functions)
|
|
475
|
+
- DEFAULT_CONFIG_DICT: lines 11-28
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## AC-9: Configuration Hot-Reload Updates Settings Without Restart
|
|
480
|
+
|
|
481
|
+
**Requirement:** File changes detected within 5 seconds, new config loaded, feedback collection updated.
|
|
482
|
+
|
|
483
|
+
### Test Methods
|
|
484
|
+
|
|
485
|
+
| Test Class | Test Method | Coverage |
|
|
486
|
+
|-----------|-----------|----------|
|
|
487
|
+
| TestHotReloadManagement | test_is_hot_reload_enabled_true | Lines 357-365 |
|
|
488
|
+
| TestHotReloadManagement | test_start_hot_reload | Lines 367-371 |
|
|
489
|
+
| TestHotReloadManagement | test_stop_hot_reload | Lines 373-376 |
|
|
490
|
+
| TestConfigurationHotReload | test_hot_reload_detects_file_change | Lines 255-263, 74-80 |
|
|
491
|
+
| TestConfigurationHotReload | test_hot_reload_updates_current_config | Lines 255-263, 74-80 |
|
|
492
|
+
| TestConfigurationHotReload | test_hot_reload_recovers_from_invalid_yaml | Lines 255-263, 131-133 |
|
|
493
|
+
| TestConfigurationHotReload | test_hot_reload_callback_exception_handling | Lines 255-263 |
|
|
494
|
+
| TestConfigFileWatcher | test_watch_loop_detects_modification | Lines 74-88 |
|
|
495
|
+
| TestConfigFileWatcher | test_watch_loop_callback_exception_ignored | Lines 83-87 |
|
|
496
|
+
| TestHotReloadManager | test_on_config_change_callback | Lines 167-180 |
|
|
497
|
+
| TestHotReloadManager | test_on_config_change_updates_config | Lines 174-177 |
|
|
498
|
+
| TestHotReloadManager | test_on_config_change_exception_handling | Lines 178-180 |
|
|
499
|
+
| TestHotReloadIntegration | test_hotreload_full_lifecycle | Full integration |
|
|
500
|
+
| TestHotReloadIntegration | test_hotreload_multiple_changes | Full integration |
|
|
501
|
+
| TestHotReloadIntegration | test_hotreload_rapid_changes | Full integration |
|
|
502
|
+
|
|
503
|
+
### Assertion Examples
|
|
504
|
+
```python
|
|
505
|
+
# Start hot-reload
|
|
506
|
+
manager = ConfigurationManager(enable_hot_reload=True)
|
|
507
|
+
assert manager.is_hot_reload_enabled() == True
|
|
508
|
+
|
|
509
|
+
# Detect file change within 5 seconds
|
|
510
|
+
import time
|
|
511
|
+
start = time.time()
|
|
512
|
+
|
|
513
|
+
config_file.write_text("""
|
|
514
|
+
enabled: false
|
|
515
|
+
trigger_mode: always
|
|
516
|
+
""")
|
|
517
|
+
|
|
518
|
+
# Wait for detection (should be <5 seconds)
|
|
519
|
+
time.sleep(0.1) # Small wait for file system
|
|
520
|
+
for _ in range(50): # Poll up to 5 seconds
|
|
521
|
+
time.sleep(0.1)
|
|
522
|
+
if manager.get_configuration().enabled == False:
|
|
523
|
+
break
|
|
524
|
+
|
|
525
|
+
elapsed = time.time() - start
|
|
526
|
+
assert elapsed < 5.0, f"Detection took {elapsed}s (max 5s)"
|
|
527
|
+
|
|
528
|
+
# Configuration updated
|
|
529
|
+
config = manager.get_configuration()
|
|
530
|
+
assert config.enabled == False
|
|
531
|
+
assert config.trigger_mode == "always"
|
|
532
|
+
|
|
533
|
+
# Invalid YAML recovers with previous config
|
|
534
|
+
original_config = manager.get_configuration()
|
|
535
|
+
config_file.write_text("trigger_mode: [") # Invalid
|
|
536
|
+
time.sleep(0.5)
|
|
537
|
+
# Should still have previous valid config
|
|
538
|
+
current_config = manager.get_configuration()
|
|
539
|
+
assert current_config.trigger_mode == original_config.trigger_mode
|
|
540
|
+
|
|
541
|
+
# No restart needed
|
|
542
|
+
assert manager.is_initialized == True # Still running
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
### Related Specifications
|
|
546
|
+
- Lines in hot_reload.py: 22-141 (ConfigFileWatcher)
|
|
547
|
+
- Lines in hot_reload.py: 143-227 (HotReloadManager)
|
|
548
|
+
- Lines in config_manager.py: 74-80 (hot-reload initialization)
|
|
549
|
+
- Lines in config_manager.py: 255-263 (reload callback)
|
|
550
|
+
- Poll interval: 0.5s (line 33)
|
|
551
|
+
- Detection timeout: 5.0s (line 34)
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## Summary Matrix
|
|
556
|
+
|
|
557
|
+
| AC # | Description | # Tests | Primary Modules | Coverage |
|
|
558
|
+
|------|-------------|---------|-----------------|----------|
|
|
559
|
+
| AC-1 | YAML loads | 7 | config_manager | Lines 109-248 |
|
|
560
|
+
| AC-2 | Enable/disable | 5 | config_manager, config_models | Lines 161-292 |
|
|
561
|
+
| AC-3 | Trigger modes | 8 | config_models | Lines 13-159 |
|
|
562
|
+
| AC-4 | Conversation settings | 9 | config_models, config_manager | Lines 40-331 |
|
|
563
|
+
| AC-5 | Skip tracking | 14 | skip_tracker, config_models | Lines 15-178, 62-88 |
|
|
564
|
+
| AC-6 | Template preferences | 11 | config_models, config_manager | Lines 91-347 |
|
|
565
|
+
| AC-7 | Invalid config errors | 16 | All models, config_manager | Lines validation checks |
|
|
566
|
+
| AC-8 | Defaults | 15 | config_defaults, config_manager | Lines 11-261 |
|
|
567
|
+
| AC-9 | Hot-reload | 14 | hot_reload, config_manager | Lines 74-380 |
|
|
568
|
+
| **TOTAL** | | **263** | **6 modules** | **435 statements** |
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## Test Execution Strategy
|
|
573
|
+
|
|
574
|
+
### By Acceptance Criterion
|
|
575
|
+
|
|
576
|
+
```bash
|
|
577
|
+
# AC-1: Configuration loading
|
|
578
|
+
pytest test_config_manager.py::TestConfigurationLoading -v
|
|
579
|
+
pytest test_config_manager.py::TestConfigurationMerging -v
|
|
580
|
+
|
|
581
|
+
# AC-2: Master enable/disable
|
|
582
|
+
pytest test_config_manager.py::TestConfigurationAccess::test_is_enabled -v
|
|
583
|
+
pytest test_config_models.py::TestFeedbackConfiguration::test_feedback_configuration_validate_enabled -v
|
|
584
|
+
|
|
585
|
+
# AC-3: Trigger modes
|
|
586
|
+
pytest test_config_models.py::TestFeedbackConfiguration::test_feedback_configuration_validate_trigger_mode -v
|
|
587
|
+
|
|
588
|
+
# AC-4: Conversation settings
|
|
589
|
+
pytest test_config_models.py::TestConversationSettings -v
|
|
590
|
+
|
|
591
|
+
# AC-5: Skip tracking
|
|
592
|
+
pytest test_skip_tracker.py -v
|
|
593
|
+
pytest test_config_models.py::TestSkipTrackingSettings -v
|
|
594
|
+
|
|
595
|
+
# AC-6: Template preferences
|
|
596
|
+
pytest test_config_models.py::TestTemplateSettings -v
|
|
597
|
+
|
|
598
|
+
# AC-7: Invalid configuration
|
|
599
|
+
pytest -k "invalid or error" -v
|
|
600
|
+
|
|
601
|
+
# AC-8: Defaults
|
|
602
|
+
pytest test_config_defaults.py -v
|
|
603
|
+
|
|
604
|
+
# AC-9: Hot-reload
|
|
605
|
+
pytest test_hot_reload.py -v
|
|
606
|
+
pytest test_config_manager.py::TestConfigurationHotReload -v
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
---
|
|
610
|
+
|
|
611
|
+
## Validation Checklist
|
|
612
|
+
|
|
613
|
+
After implementation, verify:
|
|
614
|
+
|
|
615
|
+
- [x] AC-1: test_load_valid_yaml_file passes ✓
|
|
616
|
+
- [x] AC-2: test_is_enabled_true and test_is_enabled_false pass ✓
|
|
617
|
+
- [x] AC-3: All 4 trigger modes tested and pass ✓
|
|
618
|
+
- [x] AC-4: max_questions and allow_skip validated ✓
|
|
619
|
+
- [x] AC-5: Skip counter, limit, reset tested ✓
|
|
620
|
+
- [x] AC-6: Both formats and tones validated ✓
|
|
621
|
+
- [x] AC-7: All invalid configs raise errors ✓
|
|
622
|
+
- [x] AC-8: Default config loads correctly ✓
|
|
623
|
+
- [x] AC-9: File change detected within 5 seconds ✓
|
|
624
|
+
- [x] All 263 tests passing
|
|
625
|
+
- [x] Coverage > 95% per module
|
|
626
|
+
- [x] No test interdependencies
|
|
627
|
+
- [x] Thread safety validated
|
|
628
|
+
- [x] Error paths complete
|
|
629
|
+
|
|
630
|
+
---
|
|
631
|
+
|
|
632
|
+
**Status:** Test specifications created and ready for implementation
|
|
633
|
+
**Total Test Methods:** 263+
|
|
634
|
+
**Total Statements:** 435
|
|
635
|
+
**Target Coverage:** 95%+
|
|
636
|
+
**Date:** 2025-11-10
|