cc-codeconductor 1.1.0 → 1.2.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 (143) hide show
  1. package/README.md +4 -2
  2. package/dist/core/verification/verification-runner.d.ts +7 -0
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +1413 -309
  5. package/dist/library.js +29 -1
  6. package/dist/validation/schemas.d.ts +97 -26
  7. package/package.json +1 -1
  8. package/presets/agy/AGENTS.md +10 -9
  9. package/presets/agy/hooks.json +2 -2
  10. package/presets/agy/scripts/invoke-hook.cjs +115 -0
  11. package/presets/agy/skills/backlog/SKILL.md +40 -70
  12. package/presets/agy/skills/cc-spec-mutation/SKILL.md +165 -0
  13. package/presets/agy/skills/cc-tdd-cycle/SKILL.md +3 -0
  14. package/presets/agy/skills/evaluation/SKILL.md +61 -2
  15. package/presets/agy/skills/openspec/SKILL.md +49 -19
  16. package/presets/agy/skills/testing-tdd/SKILL.md +53 -0
  17. package/presets/agy/skills/using-cc-skills/SKILL.md +48 -0
  18. package/presets/agy/workflows/cc-api-contract.md +14 -0
  19. package/presets/agy/workflows/cc-db-migration.md +14 -0
  20. package/presets/agy/workflows/cc-feature.md +18 -0
  21. package/presets/agy/workflows/cc-fix.md +14 -0
  22. package/presets/agy/workflows/cc-iterative.md +14 -0
  23. package/presets/agy/workflows/cc-openspec.md +14 -0
  24. package/presets/agy/workflows/cc-scorecard.md +2 -0
  25. package/presets/agy/workflows/cc-spec-mutation.md +191 -0
  26. package/presets/agy/workflows/cc-tdd-cycle.md +14 -0
  27. package/presets/claude/commands/cc/api-contract.md +14 -0
  28. package/presets/claude/commands/cc/db-migration.md +14 -0
  29. package/presets/claude/commands/cc/feature.md +18 -0
  30. package/presets/claude/commands/cc/fix.md +17 -0
  31. package/presets/claude/commands/cc/iterative.md +14 -0
  32. package/presets/claude/commands/cc/openspec.md +14 -0
  33. package/presets/claude/commands/cc/review.md +3 -0
  34. package/presets/claude/commands/cc/scorecard.md +2 -0
  35. package/presets/claude/commands/cc/spec-mutation.md +190 -0
  36. package/presets/claude/commands/cc/tdd-cycle.md +17 -0
  37. package/presets/claude/settings.json +13 -11
  38. package/presets/claude/skills/backlog/SKILL.md +40 -70
  39. package/presets/claude/skills/evaluation/SKILL.md +47 -24
  40. package/presets/claude/skills/openspec/SKILL.md +46 -38
  41. package/presets/claude/skills/testing-tdd/SKILL.md +53 -0
  42. package/presets/claude/skills/using-cc-skills/SKILL.md +48 -0
  43. package/presets/codex/AGENTS.md +16 -12
  44. package/presets/codex/skills/backlog/SKILL.md +61 -0
  45. package/presets/codex/skills/cc-api-contract/SKILL.md +87 -0
  46. package/presets/codex/skills/cc-backlog/SKILL.md +108 -0
  47. package/presets/codex/skills/cc-clarify/SKILL.md +36 -0
  48. package/presets/codex/skills/cc-council/SKILL.md +92 -0
  49. package/presets/codex/skills/cc-db-migration/SKILL.md +88 -0
  50. package/presets/codex/skills/cc-explore/SKILL.md +40 -0
  51. package/presets/codex/skills/cc-feature/SKILL.md +154 -0
  52. package/presets/codex/skills/cc-fix/SKILL.md +165 -0
  53. package/presets/codex/skills/cc-handoff/SKILL.md +45 -0
  54. package/presets/codex/skills/cc-iterative/SKILL.md +150 -0
  55. package/presets/codex/skills/cc-openspec/SKILL.md +191 -0
  56. package/presets/codex/skills/cc-pagespeed/SKILL.md +124 -0
  57. package/presets/codex/skills/cc-prototype/SKILL.md +42 -0
  58. package/presets/codex/skills/cc-refactor/SKILL.md +163 -0
  59. package/presets/codex/skills/cc-review/SKILL.md +152 -0
  60. package/presets/codex/skills/cc-scorecard/SKILL.md +82 -0
  61. package/presets/codex/skills/cc-security/SKILL.md +182 -0
  62. package/presets/codex/skills/cc-spec-mutation/SKILL.md +192 -0
  63. package/presets/codex/skills/cc-tdd-cycle/SKILL.md +266 -0
  64. package/presets/codex/skills/cc-test-plan/SKILL.md +153 -0
  65. package/presets/codex/skills/cc-triage/SKILL.md +38 -0
  66. package/presets/codex/skills/evaluation/SKILL.md +65 -0
  67. package/presets/codex/skills/openspec/SKILL.md +66 -0
  68. package/presets/codex/skills/testing-tdd/SKILL.md +53 -0
  69. package/presets/codex/skills/using-cc-skills/SKILL.md +48 -0
  70. package/presets/cursor/commands/cc/api-contract.md +14 -0
  71. package/presets/cursor/commands/cc/db-migration.md +14 -0
  72. package/presets/cursor/commands/cc/feature.md +18 -0
  73. package/presets/cursor/commands/cc/fix.md +17 -0
  74. package/presets/cursor/commands/cc/iterative.md +14 -0
  75. package/presets/cursor/commands/cc/openspec.md +14 -0
  76. package/presets/cursor/commands/cc/scorecard.md +2 -0
  77. package/presets/cursor/commands/cc/spec-mutation.md +190 -0
  78. package/presets/cursor/commands/cc/tdd-cycle.md +14 -0
  79. package/presets/cursor/skills/backlog/SKILL.md +40 -70
  80. package/presets/cursor/skills/evaluation/SKILL.md +61 -4
  81. package/presets/cursor/skills/openspec/SKILL.md +46 -36
  82. package/presets/cursor/skills/testing-tdd/SKILL.md +35 -574
  83. package/presets/cursor/skills/using-cc-skills/SKILL.md +48 -0
  84. package/presets/gemini/commands/cc/api-contract.toml +82 -0
  85. package/presets/gemini/commands/cc/ask.toml +54 -0
  86. package/presets/gemini/commands/cc/backlog.toml +103 -0
  87. package/presets/gemini/commands/cc/clarify.toml +31 -0
  88. package/presets/gemini/commands/cc/council.toml +87 -0
  89. package/presets/gemini/commands/cc/db-migration.toml +83 -0
  90. package/presets/gemini/commands/cc/explore.toml +35 -0
  91. package/presets/gemini/commands/cc/feature.toml +153 -0
  92. package/presets/gemini/commands/cc/fix.toml +163 -0
  93. package/presets/gemini/commands/cc/handoff.toml +40 -0
  94. package/presets/gemini/commands/cc/iterative.toml +145 -0
  95. package/presets/gemini/commands/cc/openspec.toml +186 -0
  96. package/presets/gemini/commands/cc/pagespeed.toml +119 -0
  97. package/presets/gemini/commands/cc/prototype.toml +37 -0
  98. package/presets/gemini/commands/cc/refactor.toml +158 -0
  99. package/presets/gemini/commands/cc/review.toml +150 -0
  100. package/presets/gemini/commands/cc/scorecard.toml +77 -0
  101. package/presets/gemini/commands/cc/security.toml +177 -0
  102. package/presets/gemini/commands/cc/spec-mutation.toml +187 -0
  103. package/presets/gemini/commands/cc/tdd-cycle.toml +264 -0
  104. package/presets/gemini/commands/cc/test-plan.toml +148 -0
  105. package/presets/gemini/commands/cc/triage.toml +33 -0
  106. package/presets/opencode/README.md +24 -21
  107. package/presets/opencode/agents/architect.md +6 -0
  108. package/presets/opencode/agents/implementer.md +7 -0
  109. package/presets/opencode/agents/reviewer.md +6 -0
  110. package/presets/opencode/agents/tester.md +6 -0
  111. package/presets/opencode/commands/cc-api-contract.md +14 -0
  112. package/presets/opencode/commands/cc-db-migration.md +14 -0
  113. package/presets/opencode/commands/cc-feature.md +18 -0
  114. package/presets/opencode/commands/cc-fix.md +17 -0
  115. package/presets/opencode/commands/cc-iterative.md +14 -0
  116. package/presets/opencode/commands/cc-openspec.md +14 -0
  117. package/presets/opencode/commands/cc-scorecard.md +2 -0
  118. package/presets/opencode/commands/cc-spec-mutation.md +190 -0
  119. package/presets/opencode/commands/cc-tdd-cycle.md +14 -0
  120. package/presets/opencode/opencode.jsonc +1 -1
  121. package/presets/opencode/prompts/v1.0.0/architect.md +6 -0
  122. package/presets/opencode/prompts/v1.0.0/implementer.md +7 -0
  123. package/presets/opencode/prompts/v1.0.0/reviewer.md +6 -0
  124. package/presets/opencode/prompts/v1.0.0/tester.md +6 -0
  125. package/presets/opencode/skills/backlog/SKILL.md +40 -70
  126. package/presets/opencode/skills/evaluation/SKILL.md +61 -2
  127. package/presets/opencode/skills/openspec/SKILL.md +46 -34
  128. package/presets/opencode/skills/testing-tdd/SKILL.md +35 -574
  129. package/presets/opencode/skills/using-cc-skills/SKILL.md +48 -0
  130. package/presets/shared/__pycache__/mutation_runner.cpython-314.pyc +0 -0
  131. package/presets/shared/invoke-hook.cjs +115 -0
  132. package/presets/shared/mutation_runner.py +273 -0
  133. package/src/presets/manifests/agy.yml +2 -0
  134. package/src/presets/manifests/claude.yml +3 -0
  135. package/src/presets/manifests/gemini.yml +15 -0
  136. package/src/presets/models/agy.yml +24 -24
  137. package/src/presets/models/claude.yml +10 -10
  138. package/src/presets/models/codex.yml +10 -10
  139. package/src/presets/models/cursor.yml +10 -10
  140. package/src/presets/models/gemini.yml +10 -10
  141. package/src/presets/models/opencode.yml +10 -10
  142. package/presets/agy/scripts/post-tool.sh +0 -25
  143. package/presets/agy/scripts/pre-tool.sh +0 -56
@@ -1,592 +1,53 @@
1
1
  ---
2
- id: testing-tdd
3
- version: 1.0.0
4
- name: Test-Driven Development
5
- description: >
6
- Provides expert knowledge for applying the Red-Green-Refactor cycle, designing tests at the right pyramid layer, and implementing TDD across Spring Boot + Kotlin, Python (pytest), and Next.js / Astro (Vitest + Playwright) stacks.
7
-
8
- user-invokable: true
9
- license: MIT
10
- metadata:
11
- author: lgzarturo
12
- category: testing
13
-
14
- compatibility:
15
- tools: [claude, codex, gemini, agy, opencode]
16
- stacks:
17
- languages: []
18
- frameworks: []
19
-
20
- risk:
21
- level: low
22
- can_execute_shell: false
23
- can_modify_files: true
24
- requires_network: false
25
-
26
- inputs: []
27
-
28
- outputs: []
29
-
30
- quality:
31
- reviewed_by: codeconductor-core
32
- version: 0.1.0
2
+ name: testing-tdd
3
+ description:
4
+ Guides agents through Red-Green-Refactor with runner-captured evidence.
5
+ Use when running /cc-tdd-cycle, writing tests before implementation, or
6
+ Global TDD required is yes.
33
7
  ---
34
8
 
35
-
36
-
37
9
  # Test-Driven Development
38
10
 
39
- ## The Red-Green-Refactor Cycle
40
-
41
- ```text
42
- ┌─────────────────────────────────────────────┐
43
- │ │
44
- │ RED → write a failing test │
45
- │ ↓ │
46
- │ GREEN → write the minimum code to pass │
47
- │ ↓ │
48
- │ REFACTOR → clean up without breaking │
49
- │ ↓ │
50
- │ repeat ───────────────────────────────────┘
51
- ```
52
-
53
- **Red**: Write a test that describes one behavior you want. Run it. It must
54
- fail — if it passes without implementation, the test is not testing anything.
55
-
56
- **Green**: Write the simplest code that makes the test pass. Do not optimize.
57
- Do not add features. Just pass the test.
58
-
59
- **Refactor**: Clean up duplication, naming, and structure. Run the tests after
60
- every change. If any test breaks, the refactor changed behavior — that is a bug.
61
-
62
- The cycle is short. Each iteration should take minutes, not hours. If a cycle
63
- takes longer than 30 minutes, the behavior being tested is too large — split it.
64
-
65
- ## When to Apply TDD
66
-
67
- **Apply TDD for:**
68
-
69
- - New business logic with clear rules (validation, calculations, state machines)
70
- - Bug fixes — write a regression test that reproduces the bug first
71
- - Public service layer methods
72
- - API endpoints with defined acceptance criteria
73
-
74
- **Do not apply TDD for:**
75
-
76
- - Exploratory code where the design is not yet known — spike first, then write
77
- tests for the final design
78
- - Trivial scaffolding (data class constructors, getters)
79
- - Database migrations — test the resulting schema state, not the migration steps
80
- - Third-party SDK wrappers where behavior is owned by the library
81
-
82
- ## Test Pyramid
83
-
84
- ```text
85
- /\
86
- / \
87
- / E2E\ 10% — full browser/API flows, happy path + critical errors
88
- /------\
89
- / Integ \ 20% — components with real dependencies (DB, HTTP clients)
90
- /----------\
91
- / Unit \ 70% — isolated logic, mocked dependencies, sub-millisecond
92
- /______________\
93
- ```
94
-
95
- Unit tests are the TDD workhorse. Write them first. Integration tests verify
96
- that components connect correctly. E2E tests verify that the system works for
97
- the user — keep them minimal and focused on the critical paths.
98
-
99
- ## TDD Rules
100
-
101
- **One failing test at a time.** Write one test, make it pass, then write the
102
- next. Do not write multiple failing tests before implementing.
103
-
104
- **The test must fail for the right reason.** A `NullPointerException` on setup
105
- is not a meaningful failure — that is a broken test. The failure must be the
106
- assertion, not an error in the test itself.
107
-
108
- **Minimum implementation.** In the Green phase, return a hardcoded value if
109
- that makes the test pass. The next test will force you to generalize.
110
-
111
- **Refactor only on green.** Never refactor when tests are failing. You lose the
112
- safety net that tells you whether the refactor changed behavior.
113
-
114
- **Tests are not optional after the fact.** Writing tests after implementation
115
- is not TDD. It is documentation. It catches far fewer design problems.
116
-
117
- ---
118
-
119
- ## Spring Boot + Kotlin
120
-
121
- ### Naming Convention
122
-
123
- ```kotlin
124
- @Test
125
- fun `should [expected behavior] when [condition]`()
126
- ```
127
-
128
- ```kotlin
129
- @Test
130
- fun `should return user when found by id`() { ... }
131
-
132
- @Test
133
- fun `should throw NotFoundException when user does not exist`() { ... }
134
-
135
- @Test
136
- fun `should not create user when email already exists`() { ... }
137
- ```
138
-
139
- ### TDD Cycle — Unit Test Example
140
-
141
- **Requirement**: `UserService.create()` should reject duplicate emails.
142
-
143
- **Red** — write the failing test first:
144
-
145
- ```kotlin
146
- @ExtendWith(MockKExtension::class)
147
- class UserServiceTest {
148
-
149
- @MockK
150
- private lateinit var userRepository: UserRepository
151
-
152
- private lateinit var userService: UserService
153
-
154
- @BeforeEach
155
- fun setUp() {
156
- userService = UserService(userRepository)
157
- }
158
-
159
- @Test
160
- fun `should throw ConflictException when email already exists`() {
161
- // Arrange
162
- val email = "existing@example.com"
163
- every { userRepository.existsByEmail(email) } returns true
164
-
165
- // Act & Assert
166
- assertThrows<ConflictException> {
167
- userService.create(email = email, name = "Test")
168
- }
169
- verify(exactly = 0) { userRepository.save(any()) }
170
- }
171
- }
172
- ```
173
-
174
- Run → fails (method does not exist yet).
175
-
176
- **Green** — minimum implementation:
177
-
178
- ```kotlin
179
- class UserService(private val userRepository: UserRepository) {
180
-
181
- fun create(email: String, name: String): User {
182
- if (userRepository.existsByEmail(email)) {
183
- throw ConflictException("Email $email is already registered")
184
- }
185
- return userRepository.save(User(email = email, name = name))
186
- }
187
- }
188
- ```
189
-
190
- Run → passes.
191
-
192
- **Refactor** — extract the check into a private guard, add KDoc only if the
193
- domain rule is non-obvious. Run tests → still green.
194
-
195
- **Next test** — happy path:
196
-
197
- ```kotlin
198
- @Test
199
- fun `should create and return user when email is unique`() {
200
- val email = "new@example.com"
201
- val saved = User(id = UUID.randomUUID(), email = email, name = "New User")
202
-
203
- every { userRepository.existsByEmail(email) } returns false
204
- every { userRepository.save(any()) } returns saved
205
-
206
- val result = userService.create(email = email, name = "New User")
207
-
208
- assertThat(result.email).isEqualTo(email)
209
- verify(exactly = 1) { userRepository.save(any()) }
210
- }
211
- ```
212
-
213
- ### TDD Cycle — Integration Test Example
214
-
215
- **Requirement**: `GET /api/users/{id}` returns 404 when the user does not exist.
216
-
217
- **Red**:
218
-
219
- ```kotlin
220
- @SpringBootTest
221
- @AutoConfigureMockMvc
222
- class UserControllerTest {
223
-
224
- @Autowired
225
- private lateinit var mockMvc: MockMvc
226
-
227
- @Test
228
- fun `should return 404 when user does not exist`() {
229
- mockMvc.perform(get("/api/users/${UUID.randomUUID()}"))
230
- .andExpect(status().isNotFound)
231
- .andExpect(jsonPath("$.code").value("NOT_FOUND"))
232
- }
233
- }
234
- ```
235
-
236
- Run → fails (endpoint may not exist yet, or returns wrong status).
237
-
238
- **Green** — add/fix the endpoint and error handler. Run → passes.
239
-
240
- **Refactor** — extract error response builder if duplicated across handlers.
241
-
242
- ### MockK Quick Reference
243
-
244
- ```kotlin
245
- // Stub return value
246
- every { repo.findById(id) } returns Optional.of(user)
247
-
248
- // Stub exception
249
- every { repo.save(any()) } throws DataIntegrityViolationException("duplicate")
250
-
251
- // Verify call count
252
- verify(exactly = 1) { repo.save(any()) }
253
- verify(exactly = 0) { emailService.send(any()) }
254
-
255
- // Capture argument
256
- val slot = slot<User>()
257
- every { repo.save(capture(slot)) } returns savedUser
258
- assertThat(slot.captured.email).isEqualTo("expected@example.com")
259
-
260
- // Coroutines
261
- coEvery { repo.findById(id) } returns user
262
- coVerify(exactly = 1) { repo.findById(id) }
263
- ```
264
-
265
- ---
11
+ ## Overview
266
12
 
267
- ## Python (pytest)
13
+ Red (failing test) → Green (minimal code) → Refactor. Evidence comes from
14
+ `captureTddSuiteEvidence`, not handmade JSON.
268
15
 
269
- ### Naming Convention
16
+ ## When to Use
270
17
 
271
- ```python
272
- def test_[behavior]_when_[condition]():
273
- ```
18
+ - `/cc-tdd-cycle`, new behavior, bug fixes, TDD-required OpenSpec items
274
19
 
275
- ```python
276
- def test_returns_user_when_found_by_id(): ...
277
- def test_raises_not_found_when_user_does_not_exist(): ...
278
- def test_does_not_create_user_when_email_already_exists(): ...
279
- ```
20
+ **NOT** for docs-only changes or when the Task Card forbids tests.
280
21
 
281
- ### TDD Cycle — Unit Test Example
22
+ ## Process
282
23
 
283
- **Requirement**: `UserService.create()` should reject duplicate emails.
24
+ 1. Write the failing test that encodes one acceptance criterion. Run the suite.
25
+ It MUST fail (`suiteFails === true`).
26
+ 2. Implement the minimum that turns it green. Do not expand scope.
27
+ 3. Refactor only with a green suite.
28
+ 4. Capture evidence via the verification runner (`openspec done` on test/implement
29
+ when TDD is required).
30
+ 5. Cover happy path, edge, and error for each behavior.
284
31
 
285
- **Red**:
286
-
287
- ```python
288
- # tests/users/test_services.py
289
- import pytest
290
- from unittest.mock import MagicMock
291
- from apps.users.services import UserService
292
-
293
-
294
- def test_raises_when_email_already_exists():
295
- repo = MagicMock()
296
- repo.exists_by_email.return_value = True
297
- service = UserService(repo)
298
-
299
- with pytest.raises(ValueError, match="already registered"):
300
- service.create(email="taken@example.com", name="Test")
301
-
302
- repo.save.assert_not_called()
303
- ```
304
-
305
- Run → fails (`UserService` does not exist).
306
-
307
- **Green**:
308
-
309
- ```python
310
- # apps/users/services.py
311
- class UserService:
312
-
313
- def __init__(self, repository):
314
- self._repo = repository
315
-
316
- def create(self, *, email: str, name: str):
317
- if self._repo.exists_by_email(email):
318
- raise ValueError(f"Email {email!r} is already registered")
319
- return self._repo.save({"email": email, "name": name})
320
- ```
321
-
322
- Run → passes.
323
-
324
- ### pytest with Django and factory-boy
325
-
326
- ```python
327
- # tests/users/factories.py
328
- import factory
329
- from factory.django import DjangoModelFactory
330
- from apps.users.models import User
331
-
332
-
333
- class UserFactory(DjangoModelFactory):
334
- class Meta:
335
- model = User
336
-
337
- email = factory.Sequence(lambda n: f"user{n}@example.com")
338
- name = factory.Faker("name")
339
- is_active = True
340
- ```
341
-
342
- ```python
343
- # conftest.py
344
- import pytest
345
- from pytest_factoryboy import register
346
- from tests.users.factories import UserFactory
347
-
348
- register(UserFactory)
349
- ```
350
-
351
- ```python
352
- # tests/users/test_services.py
353
- import pytest
354
- from apps.users.services import UserService
355
-
356
-
357
- @pytest.mark.django_db
358
- def test_create_user_succeeds_with_unique_email():
359
- service = UserService()
360
-
361
- user = service.create(email="new@example.com", name="Alice")
362
-
363
- assert user.pk is not None
364
- assert user.email == "new@example.com"
365
-
366
-
367
- @pytest.mark.django_db
368
- def test_create_user_raises_when_email_taken(user_factory):
369
- user_factory(email="taken@example.com")
370
-
371
- with pytest.raises(ValueError, match="already registered"):
372
- UserService().create(email="taken@example.com", name="Bob")
373
- ```
374
-
375
- ### pytest Fixtures
376
-
377
- ```python
378
- # conftest.py
379
- import pytest
380
-
381
-
382
- @pytest.fixture
383
- def authenticated_client(client, user_factory):
384
- user = user_factory()
385
- client.force_login(user)
386
- return client, user
387
-
388
-
389
- # In test
390
- def test_profile_requires_auth(client):
391
- response = client.get("/api/profile/")
392
- assert response.status_code == 401
393
-
394
-
395
- def test_profile_returns_user_data(authenticated_client):
396
- client, user = authenticated_client
397
- response = client.get("/api/profile/")
398
- assert response.status_code == 200
399
- assert response.json()["email"] == user.email
400
- ```
401
-
402
- ---
403
-
404
- ## Next.js / Astro (Vitest + RTL + Playwright)
405
-
406
- ### Naming Convention
407
-
408
- ```typescript
409
- it('should [behavior] when [condition]', () => { ... })
410
- describe('ComponentName', () => {
411
- describe('when [state]', () => {
412
- it('should [behavior]', () => { ... })
413
- })
414
- })
415
- ```
416
-
417
- ### TDD Cycle — Component Test Example (Vitest + RTL)
418
-
419
- **Requirement**: `<Counter>` increments when the button is clicked.
420
-
421
- **Red**:
422
-
423
- ```typescript
424
- // components/counter.test.tsx
425
- import { render, screen, fireEvent } from '@testing-library/react';
426
- import { Counter } from './counter';
427
-
428
- describe('Counter', () => {
429
- it('should display initial count of 0', () => {
430
- render(<Counter />);
431
- expect(screen.getByText('Count: 0')).toBeInTheDocument();
432
- });
433
-
434
- it('should increment count when button is clicked', () => {
435
- render(<Counter />);
436
- fireEvent.click(screen.getByRole('button', { name: /increment/i }));
437
- expect(screen.getByText('Count: 1')).toBeInTheDocument();
438
- });
439
- });
440
- ```
441
-
442
- Run → fails (component does not exist).
443
-
444
- **Green**:
445
-
446
- ```tsx
447
- // components/counter.tsx
448
- 'use client';
449
- import { useState } from 'react';
450
-
451
- export function Counter() {
452
- const [count, setCount] = useState(0);
453
- return (
454
- <div>
455
- <p>Count: {count}</p>
456
- <button onClick={() => setCount(c => c + 1)} aria-label="increment">
457
- +
458
- </button>
459
- </div>
460
- );
461
- }
462
- ```
463
-
464
- Run → passes.
465
-
466
- **Refactor** — extract `useCounter` hook if logic grows. Run tests → green.
467
-
468
- ### Vitest Setup
469
-
470
- ```typescript
471
- // vitest.config.ts
472
- import { defineConfig } from 'vitest/config';
473
- import react from '@vitejs/plugin-react';
474
-
475
- export default defineConfig({
476
- plugins: [react()],
477
- test: {
478
- environment: 'jsdom',
479
- globals: true,
480
- setupFiles: ['./vitest.setup.ts'],
481
- },
482
- });
483
- ```
484
-
485
- ```typescript
486
- // vitest.setup.ts
487
- import '@testing-library/jest-dom';
488
- ```
489
-
490
- ### Server Action Testing
491
-
492
- Test Server Actions by calling them directly in unit tests — no HTTP overhead.
493
-
494
- ```typescript
495
- // app/posts/create/actions.test.ts
496
- import { createPost } from './actions';
497
-
498
- vi.mock('@/lib/db', () => ({
499
- db: {
500
- post: {
501
- create: vi.fn(),
502
- },
503
- },
504
- }));
505
-
506
- describe('createPost', () => {
507
- it('should return validation error when title is empty', async () => {
508
- const formData = new FormData();
509
- formData.set('title', '');
510
- formData.set('content', 'Some content');
511
-
512
- const result = await createPost(formData);
513
-
514
- expect(result?.error?.title).toBeDefined();
515
- });
516
- });
517
- ```
518
-
519
- ### E2E Testing with Playwright
520
-
521
- Reserve Playwright for critical user flows only. Do not replicate unit test
522
- scenarios in E2E.
523
-
524
- ```typescript
525
- // e2e/auth.spec.ts
526
- import { test, expect } from '@playwright/test';
527
-
528
- test.describe('Authentication', () => {
529
- test('should redirect to login when accessing protected route unauthenticated', async ({ page }) => {
530
- await page.goto('/dashboard');
531
- await expect(page).toHaveURL('/login');
532
- });
533
-
534
- test('should show dashboard after successful login', async ({ page }) => {
535
- await page.goto('/login');
536
- await page.getByLabel('Email').fill('user@example.com');
537
- await page.getByLabel('Password').fill('password123');
538
- await page.getByRole('button', { name: 'Sign in' }).click();
539
- await expect(page).toHaveURL('/dashboard');
540
- });
541
- });
542
- ```
543
-
544
- ```typescript
545
- // playwright.config.ts
546
- import { defineConfig } from '@playwright/test';
547
-
548
- export default defineConfig({
549
- testDir: './e2e',
550
- use: {
551
- baseURL: 'http://localhost:3000',
552
- },
553
- webServer: {
554
- command: 'npm run build && npm run start',
555
- port: 3000,
556
- reuseExistingServer: !process.env.CI,
557
- },
558
- });
559
- ```
560
-
561
- ---
32
+ Local: `bun run dev`. Pyramid default: many unit, fewer integration, rare E2E.
562
33
 
563
- ## CI Integration
34
+ ## Common Rationalizations
564
35
 
565
- Run tests in this order — fail fast on the cheapest failures first:
36
+ | Rationalization | Reality |
37
+ | --- | --- |
38
+ | I'll add tests later | Later means never. Red first. |
39
+ | This is too small to test | If it can break, it needs a failing test first. |
40
+ | I'll write the evidence JSON | Handmade TDD JSON is rejected. |
566
41
 
567
- ```text
568
- 1. Unit tests — sub-second feedback; block all subsequent steps on failure
569
- 2. Integration tests — real DB, real HTTP; slower but necessary
570
- 3. E2E tests — slowest; run only on main branch or release branches
571
- ```
42
+ ## Red Flags
572
43
 
573
- ```yaml
574
- # Example GitHub Actions
575
- jobs:
576
- test:
577
- steps:
578
- - name: Unit tests
579
- run: npx vitest run --reporter=verbose
580
- - name: Integration tests
581
- run: npx vitest run --project=integration
582
- - name: E2E tests
583
- if: github.ref == 'refs/heads/main'
584
- run: npx playwright test
585
- ```
44
+ - Tests that assert implementation details instead of behavior
45
+ - Green without a recorded red
46
+ - Skipping error cases
586
47
 
587
- **Pipeline rules:**
48
+ ## Verification
588
49
 
589
- - A failing unit test blocks the entire pipeline — do not merge broken tests
590
- - E2E tests are expensive; run them on CI but not in pre-commit hooks
591
- - Flaky tests must be fixed or deleted — a test that sometimes passes is worse
592
- than no test, because it erodes trust in the suite
50
+ - [ ] Suite failed before implement
51
+ - [ ] Suite passed after implement
52
+ - [ ] Runner evidence exists (not handmade)
53
+ - [ ] Optional: `bun run dev scorecard suite-run --suite workflow-gates`
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: using-cc-skills
3
+ description:
4
+ Maps incoming work to the CodeConductor slash command and workflow skill.
5
+ Use when starting a session or deciding which /cc-* command applies.
6
+ ---
7
+
8
+ # Using CodeConductor skills
9
+
10
+ ## Overview
11
+
12
+ Pick one slash command. Follow its skill. Invoke CLI for gates. Do not invent
13
+ a parallel process.
14
+
15
+ ## When to Use
16
+
17
+ - Start of a session, ambiguous request, or "which /cc should I run?"
18
+
19
+ ## Process
20
+
21
+ | Intent | Command | Skill |
22
+ | --- | --- | --- |
23
+ | New backlog item | `/cc-backlog` | `backlog` |
24
+ | Deliver a BC-xxx item | `/cc-openspec` | `openspec` |
25
+ | New feature | `/cc-feature` | `openspec` + `testing-tdd` |
26
+ | Bug fix | `/cc-fix` | `testing-tdd` |
27
+ | Review a diff | `/cc-review` | `evaluation` |
28
+ | TDD cycle only | `/cc-tdd-cycle` | `testing-tdd` |
29
+ | Scorecard / suites | `/cc-scorecard` | `evaluation` |
30
+
31
+ Then run the matching CLI (`openspec validate`, `scorecard create --from-diff`,
32
+ `hook pre-tool`, `scorecard suite-run`).
33
+
34
+ ## Common Rationalizations
35
+
36
+ | Rationalization | Reality |
37
+ | --- | --- |
38
+ | I'll skip the slash and just code | Skipping the workflow is a defect. |
39
+
40
+ ## Red Flags
41
+
42
+ - Two slash commands in parallel that mutate the same files
43
+ - Implementing before `openspec analyze` when a change folder is active
44
+
45
+ ## Verification
46
+
47
+ - [ ] One command selected and shown to the user
48
+ - [ ] Matching skill loaded before edits