cc-codeconductor 1.4.1 → 1.5.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/README.md +61 -13
- package/dist/core/verification/rdd-receipt.d.ts +39 -0
- package/dist/core/verification/verification-runner.d.ts +8 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1257 -330
- package/dist/library.js +267 -26
- package/dist/validation/schemas.d.ts +521 -26
- package/docs/generated/cli.md +20 -0
- package/package.json +1 -1
- package/presets/agy/AGENTS.md +6 -0
- package/presets/agy/README.md +1 -1
- package/presets/agy/hooks.json +1 -1
- package/presets/agy/scripts/invoke-hook.cjs +20 -5
- package/presets/agy/settings.json +1 -1
- package/presets/agy/skills/api-versioning/SKILL.md +394 -0
- package/presets/agy/skills/astro/SKILL.md +318 -0
- package/presets/agy/skills/auth-token-inspector/SKILL.md +30 -0
- package/presets/agy/skills/cc-pagespeed/SKILL.md +2 -3
- package/presets/agy/skills/code-review/SKILL.md +207 -0
- package/presets/agy/skills/django-orm/SKILL.md +460 -0
- package/presets/agy/skills/django-uv/SKILL.md +405 -0
- package/presets/agy/skills/drizzle-schema-architect/SKILL.md +50 -0
- package/presets/agy/skills/fastapi-pydantic-strict/SKILL.md +43 -0
- package/presets/agy/skills/jpa-nplusone-detector/SKILL.md +45 -0
- package/presets/agy/skills/jpa-postgres/SKILL.md +623 -0
- package/presets/agy/skills/livewire-alpine-bridge/SKILL.md +35 -0
- package/presets/agy/skills/nextjs-typescript/SKILL.md +390 -0
- package/presets/agy/skills/python/SKILL.md +611 -0
- package/presets/agy/skills/seo-analytics-injector/SKILL.md +43 -0
- package/presets/agy/skills/spring-auth-auditor/SKILL.md +29 -0
- package/presets/agy/skills/spring-boot-feature/SKILL.md +563 -0
- package/presets/agy/skills/spring-boot-testing-strategy/SKILL.md +475 -0
- package/presets/agy/skills/tailwind-responsive-auditor/SKILL.md +29 -0
- package/presets/agy/skills/tdd-mutation-tester/SKILL.md +27 -0
- package/presets/agy/workflows/cc-handoff.md +2 -1
- package/presets/agy/workflows/cc-odd.md +15 -0
- package/presets/agy/workflows/cc-pagespeed.md +2 -3
- package/presets/agy/workflows/cc-review.md +31 -0
- package/presets/agy/workflows/cc-security.md +1 -1
- package/presets/claude/CLAUDE.md +6 -0
- package/presets/claude/commands/cc/handoff.md +2 -1
- package/presets/claude/commands/cc/odd.md +15 -0
- package/presets/claude/commands/cc/review.md +33 -0
- package/presets/claude/settings.json +2 -2
- package/presets/claude/skills/android/SKILL.md +1 -1
- package/presets/claude/skills/api-versioning/SKILL.md +1 -1
- package/presets/claude/skills/astro/SKILL.md +318 -0
- package/presets/claude/skills/auth-token-inspector/SKILL.md +30 -0
- package/presets/claude/skills/code-review/SKILL.md +207 -0
- package/presets/claude/skills/django-orm/SKILL.md +1 -1
- package/presets/claude/skills/django-testing/SKILL.md +1 -1
- package/presets/claude/skills/django-uv/SKILL.md +405 -0
- package/presets/claude/skills/drizzle-schema-architect/SKILL.md +50 -0
- package/presets/claude/skills/fastapi-pydantic-strict/SKILL.md +43 -0
- package/presets/claude/skills/jpa-nplusone-detector/SKILL.md +45 -0
- package/presets/claude/skills/jpa-postgres/SKILL.md +1 -1
- package/presets/claude/skills/livewire-alpine-bridge/SKILL.md +35 -0
- package/presets/claude/skills/nextjs-typescript/SKILL.md +390 -0
- package/presets/claude/skills/pagespeed-perf/SKILL.md +1 -1
- package/presets/claude/skills/python/SKILL.md +1 -1
- package/presets/claude/skills/python-django-stack/SKILL.md +1 -1
- package/presets/claude/skills/python-fastapi-stack/SKILL.md +1 -1
- package/presets/claude/skills/security/SKILL.md +1 -1
- package/presets/claude/skills/seo-analytics-injector/SKILL.md +43 -0
- package/presets/claude/skills/spring-auth-auditor/SKILL.md +29 -0
- package/presets/claude/skills/spring-boot-feature/SKILL.md +1 -1
- package/presets/claude/skills/spring-boot-kotlin/SKILL.md +1 -1
- package/presets/claude/skills/spring-boot-testing-strategy/SKILL.md +475 -0
- package/presets/claude/skills/sqlalchemy/SKILL.md +1 -1
- package/presets/claude/skills/tailwind-responsive-auditor/SKILL.md +29 -0
- package/presets/claude/skills/tdd-mutation-tester/SKILL.md +27 -0
- package/presets/claude/skills/testing-strategy/SKILL.md +1 -1
- package/presets/codex/AGENTS.md +6 -0
- package/presets/codex/skills/android/SKILL.md +1 -1
- package/presets/codex/skills/api-versioning/SKILL.md +1 -1
- package/presets/codex/skills/astro/SKILL.md +318 -0
- package/presets/codex/skills/auth-token-inspector/SKILL.md +30 -0
- package/presets/codex/skills/cc-handoff/SKILL.md +3 -1
- package/presets/codex/skills/cc-odd/SKILL.md +25 -0
- package/presets/codex/skills/cc-openspec/SKILL.md +5 -1
- package/presets/codex/skills/cc-pagespeed/SKILL.md +2 -3
- package/presets/codex/skills/cc-review/SKILL.md +31 -0
- package/presets/codex/skills/cc-security/SKILL.md +1 -1
- package/presets/codex/skills/cc-spec-mutation/SKILL.md +5 -0
- package/presets/codex/skills/cc-tdd-cycle/SKILL.md +8 -0
- package/presets/codex/skills/code-review/SKILL.md +207 -0
- package/presets/codex/skills/django-orm/SKILL.md +1 -1
- package/presets/codex/skills/django-testing/SKILL.md +1 -1
- package/presets/codex/skills/django-uv/SKILL.md +405 -0
- package/presets/codex/skills/drizzle-schema-architect/SKILL.md +50 -0
- package/presets/codex/skills/fastapi-pydantic-strict/SKILL.md +43 -0
- package/presets/codex/skills/jpa-nplusone-detector/SKILL.md +45 -0
- package/presets/codex/skills/jpa-postgres/SKILL.md +1 -1
- package/presets/codex/skills/livewire-alpine-bridge/SKILL.md +35 -0
- package/presets/codex/skills/nextjs-typescript/SKILL.md +390 -0
- package/presets/codex/skills/pagespeed-perf/SKILL.md +1 -1
- package/presets/codex/skills/python/SKILL.md +1 -1
- package/presets/codex/skills/python-django-stack/SKILL.md +1 -1
- package/presets/codex/skills/python-fastapi-stack/SKILL.md +1 -1
- package/presets/codex/skills/security-ai-llm/SKILL.md +43 -0
- package/presets/codex/skills/security-blue-team/SKILL.md +43 -0
- package/presets/codex/skills/security-cloud/SKILL.md +43 -0
- package/presets/codex/skills/security-crypto/SKILL.md +43 -0
- package/presets/codex/skills/security-exploit-dev/SKILL.md +45 -0
- package/presets/codex/skills/security-grc/SKILL.md +43 -0
- package/presets/codex/skills/security-incident-response/SKILL.md +45 -0
- package/presets/codex/skills/security-log-analysis/SKILL.md +43 -0
- package/presets/codex/skills/security-malware-analysis/SKILL.md +44 -0
- package/presets/codex/skills/security-mobile/SKILL.md +43 -0
- package/presets/codex/skills/security-network/SKILL.md +43 -0
- package/presets/codex/skills/security-ot-ics/SKILL.md +43 -0
- package/presets/codex/skills/security-recon/SKILL.md +45 -0
- package/presets/codex/skills/security-red-team/SKILL.md +44 -0
- package/presets/codex/skills/security-reverse-engineering/SKILL.md +44 -0
- package/presets/codex/skills/security-soc-automation/SKILL.md +43 -0
- package/presets/codex/skills/security-threat-hunting/SKILL.md +43 -0
- package/presets/codex/skills/security-vuln-assessment/SKILL.md +45 -0
- package/presets/codex/skills/security-web/SKILL.md +44 -0
- package/presets/codex/skills/seo-analytics-injector/SKILL.md +43 -0
- package/presets/codex/skills/spring-auth-auditor/SKILL.md +29 -0
- package/presets/codex/skills/spring-boot-feature/SKILL.md +2 -2
- package/presets/codex/skills/spring-boot-kotlin/SKILL.md +1 -1
- package/presets/codex/skills/spring-boot-testing-strategy/SKILL.md +475 -0
- package/presets/codex/skills/sqlalchemy/SKILL.md +1 -1
- package/presets/codex/skills/tailwind-responsive-auditor/SKILL.md +29 -0
- package/presets/codex/skills/tdd-mutation-tester/SKILL.md +27 -0
- package/presets/codex/skills/testing-strategy/SKILL.md +1 -1
- package/presets/cursor/AGENTS.md +6 -0
- package/presets/cursor/commands/cc/handoff.md +3 -1
- package/presets/cursor/commands/cc/odd.md +20 -0
- package/presets/cursor/commands/cc/openspec.md +5 -1
- package/presets/cursor/commands/cc/pagespeed.md +2 -3
- package/presets/cursor/commands/cc/review.md +31 -0
- package/presets/cursor/commands/cc/security.md +1 -1
- package/presets/cursor/commands/cc/spec-mutation.md +5 -0
- package/presets/cursor/commands/cc/tdd-cycle.md +8 -0
- package/presets/cursor/skills/android/SKILL.md +1 -1
- package/presets/cursor/skills/api-versioning/SKILL.md +2 -1
- package/presets/cursor/skills/astro/SKILL.md +1 -1
- package/presets/cursor/skills/auth-token-inspector/SKILL.md +1 -1
- package/presets/cursor/skills/code-review/SKILL.md +1 -1
- package/presets/cursor/skills/django-orm/SKILL.md +3 -5
- package/presets/cursor/skills/django-testing/SKILL.md +1 -1
- package/presets/cursor/skills/django-uv/SKILL.md +1 -1
- package/presets/cursor/skills/drizzle-schema-architect/SKILL.md +1 -1
- package/presets/cursor/skills/fastapi-pydantic-strict/SKILL.md +1 -1
- package/presets/cursor/skills/jpa-nplusone-detector/SKILL.md +1 -1
- package/presets/cursor/skills/jpa-postgres/SKILL.md +2 -4
- package/presets/cursor/skills/livewire-alpine-bridge/SKILL.md +1 -1
- package/presets/cursor/skills/nextjs-typescript/SKILL.md +1 -1
- package/presets/cursor/skills/pagespeed-perf/SKILL.md +1 -1
- package/presets/cursor/skills/python/SKILL.md +6 -7
- package/presets/cursor/skills/python-django-stack/SKILL.md +1 -1
- package/presets/cursor/skills/python-fastapi-stack/SKILL.md +1 -1
- package/presets/cursor/skills/security/SKILL.md +1 -1
- package/presets/cursor/skills/seo-analytics-injector/SKILL.md +1 -1
- package/presets/cursor/skills/spring-auth-auditor/SKILL.md +1 -1
- package/presets/cursor/skills/spring-boot-feature/SKILL.md +2 -4
- package/presets/cursor/skills/spring-boot-kotlin/SKILL.md +1 -1
- package/presets/cursor/skills/spring-boot-testing-strategy/SKILL.md +1 -1
- package/presets/cursor/skills/sqlalchemy/SKILL.md +1 -1
- package/presets/cursor/skills/tailwind-responsive-auditor/SKILL.md +1 -1
- package/presets/cursor/skills/tdd-mutation-tester/SKILL.md +1 -1
- package/presets/gemini/GEMINI.md +6 -0
- package/presets/gemini/commands/cc/handoff.toml +3 -1
- package/presets/gemini/commands/cc/odd.toml +20 -0
- package/presets/gemini/commands/cc/openspec.toml +5 -1
- package/presets/gemini/commands/cc/pagespeed.toml +2 -3
- package/presets/gemini/commands/cc/review.toml +31 -0
- package/presets/gemini/commands/cc/security.toml +1 -1
- package/presets/gemini/commands/cc/spec-mutation.toml +5 -0
- package/presets/gemini/commands/cc/tdd-cycle.toml +8 -0
- package/presets/opencode/README.md +45 -52
- package/presets/opencode/agents/implementer.md +2 -0
- package/presets/opencode/agents/reviewer.md +2 -0
- package/presets/opencode/agents/tester.md +2 -0
- package/presets/opencode/commands/cc-handoff.md +2 -1
- package/presets/opencode/commands/cc-odd.md +15 -0
- package/presets/opencode/commands/cc-pagespeed.md +2 -3
- package/presets/opencode/commands/cc-review.md +31 -0
- package/presets/opencode/commands/cc-security.md +1 -1
- package/presets/opencode/opencode.jsonc +1 -1
- package/presets/opencode/skills/android/SKILL.md +1 -1
- package/presets/opencode/skills/api-versioning/SKILL.md +2 -1
- package/presets/opencode/skills/astro/SKILL.md +1 -1
- package/presets/opencode/skills/auth-token-inspector/SKILL.md +1 -1
- package/presets/opencode/skills/code-review/SKILL.md +1 -1
- package/presets/opencode/skills/django-orm/SKILL.md +3 -3
- package/presets/opencode/skills/django-testing/SKILL.md +1 -1
- package/presets/opencode/skills/django-uv/SKILL.md +1 -1
- package/presets/opencode/skills/drizzle-schema-architect/SKILL.md +1 -1
- package/presets/opencode/skills/fastapi-pydantic-strict/SKILL.md +1 -1
- package/presets/opencode/skills/jpa-nplusone-detector/SKILL.md +1 -1
- package/presets/opencode/skills/jpa-postgres/SKILL.md +2 -1
- package/presets/opencode/skills/livewire-alpine-bridge/SKILL.md +1 -1
- package/presets/opencode/skills/nextjs-typescript/SKILL.md +1 -1
- package/presets/opencode/skills/pagespeed-perf/SKILL.md +1 -1
- package/presets/opencode/skills/python/SKILL.md +6 -5
- package/presets/opencode/skills/python-django-stack/SKILL.md +1 -1
- package/presets/opencode/skills/python-fastapi-stack/SKILL.md +1 -1
- package/presets/opencode/skills/security/SKILL.md +1 -1
- package/presets/opencode/skills/seo-analytics-injector/SKILL.md +1 -1
- package/presets/opencode/skills/spring-auth-auditor/SKILL.md +1 -1
- package/presets/opencode/skills/spring-boot-feature/SKILL.md +2 -1
- package/presets/opencode/skills/spring-boot-kotlin/SKILL.md +1 -1
- package/presets/opencode/skills/spring-boot-testing-strategy/SKILL.md +1 -1
- package/presets/opencode/skills/sqlalchemy/SKILL.md +1 -1
- package/presets/opencode/skills/tailwind-responsive-auditor/SKILL.md +1 -1
- package/presets/opencode/skills/tdd-mutation-tester/SKILL.md +1 -1
- package/presets/pi/AGENTS.md +6 -0
- package/presets/seo-hotel/skills/astro-seo/SKILL.md +1 -1
- package/presets/seo-hotel/skills/geo-readiness/SKILL.md +1 -1
- package/presets/seo-hotel/skills/off-page/SKILL.md +1 -1
- package/presets/seo-hotel/skills/schema-validator/SKILL.md +1 -1
- package/presets/seo-hotel/skills/seo-audit/SKILL.md +1 -1
- package/presets/shared/invoke-hook.cjs +20 -5
- package/src/presets/models/roles.yml +28 -28
- package/src/presets/shared-skills.yml +58 -22
- package/src/presets/targets/pi.yml +1 -0
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: spring-boot-testing-strategy
|
|
3
|
+
name: spring-boot-testing-strategy
|
|
4
|
+
description: >
|
|
5
|
+
Provides expert knowledge of the testing pyramid, test design principles, MockK patterns, and integration testing conventions for Spring Boot + Kotlin projects.
|
|
6
|
+
|
|
7
|
+
user-invokable: true
|
|
8
|
+
license: MIT
|
|
9
|
+
metadata:
|
|
10
|
+
author: lgzarturo
|
|
11
|
+
category: testing
|
|
12
|
+
|
|
13
|
+
compatibility:
|
|
14
|
+
tools: [claude, codex, gemini, agy, opencode]
|
|
15
|
+
stacks:
|
|
16
|
+
languages: [kotlin, java]
|
|
17
|
+
frameworks: [spring-boot, kotest, mockk, junit5, mockk, testcontainers, assertj]
|
|
18
|
+
databases: [postgresql, sqlite, h2]
|
|
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
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
# Testing Strategy
|
|
36
|
+
|
|
37
|
+
## Testing Pyramid
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
/\
|
|
41
|
+
/ \
|
|
42
|
+
/ E2E\ 10% — full API, happy path + main error cases
|
|
43
|
+
/------\
|
|
44
|
+
/ Integ \ 20% — components with real dependencies (DB, HTTP)
|
|
45
|
+
/----------\
|
|
46
|
+
/ Unit \ 70% — isolated, mocked dependencies, fast
|
|
47
|
+
/______________\
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Unit tests are the foundation. They are fast, deterministic, and cheap to run.
|
|
51
|
+
Integration tests validate that components work together. E2E tests validate
|
|
52
|
+
that the system works end to end — keep them minimal.
|
|
53
|
+
|
|
54
|
+
If you find yourself writing more integration tests than unit tests, the code
|
|
55
|
+
under test has too many responsibilities bundled together.
|
|
56
|
+
|
|
57
|
+
## Test Naming Convention
|
|
58
|
+
|
|
59
|
+
Format: `should [expected behavior] when [condition]`
|
|
60
|
+
|
|
61
|
+
```kotlin
|
|
62
|
+
@Test
|
|
63
|
+
fun `should return user when found by id`() { ... }
|
|
64
|
+
|
|
65
|
+
@Test
|
|
66
|
+
fun `should return 404 when user does not exist`() { ... }
|
|
67
|
+
|
|
68
|
+
@Test
|
|
69
|
+
fun `should throw ConflictException when email already exists`() { ... }
|
|
70
|
+
|
|
71
|
+
@Test
|
|
72
|
+
fun `should not return deleted users in list`() { ... }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Group related tests with `@Nested`:
|
|
76
|
+
|
|
77
|
+
```kotlin
|
|
78
|
+
@ExtendWith(MockKExtension::class)
|
|
79
|
+
class UserServiceTest {
|
|
80
|
+
|
|
81
|
+
@Nested
|
|
82
|
+
inner class GetById {
|
|
83
|
+
@Test
|
|
84
|
+
fun `should return user when found`() { ... }
|
|
85
|
+
|
|
86
|
+
@Test
|
|
87
|
+
fun `should return NotFound when user does not exist`() { ... }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@Nested
|
|
91
|
+
inner class Create {
|
|
92
|
+
@Test
|
|
93
|
+
fun `should create and return user when email is unique`() { ... }
|
|
94
|
+
|
|
95
|
+
@Test
|
|
96
|
+
fun `should throw ConflictException when email already exists`() { ... }
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Unit Test Structure (AAA)
|
|
102
|
+
|
|
103
|
+
Every test follows Arrange → Act → Assert. Use blank lines to separate each
|
|
104
|
+
phase.
|
|
105
|
+
|
|
106
|
+
```kotlin
|
|
107
|
+
@Test
|
|
108
|
+
fun `should return user when found by id`() {
|
|
109
|
+
// Arrange
|
|
110
|
+
val userId = UUID.randomUUID()
|
|
111
|
+
val user = User(id = userId, email = "user@example.com", name = "Test User")
|
|
112
|
+
every { userRepository.findById(userId) } returns Optional.of(user)
|
|
113
|
+
|
|
114
|
+
// Act
|
|
115
|
+
val result = userService.getById(userId)
|
|
116
|
+
|
|
117
|
+
// Assert
|
|
118
|
+
assertThat(result).isInstanceOf(UserResult.Found::class.java)
|
|
119
|
+
val found = result as UserResult.Found
|
|
120
|
+
assertThat(found.user.id).isEqualTo(userId)
|
|
121
|
+
verify(exactly = 1) { userRepository.findById(userId) }
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
No inline comments between phases once the structure is clear. The blank lines
|
|
126
|
+
are enough.
|
|
127
|
+
|
|
128
|
+
## What NOT to Test
|
|
129
|
+
|
|
130
|
+
**Framework wiring.** Spring handles dependency injection. Do not write tests
|
|
131
|
+
that verify `@Autowired` works.
|
|
132
|
+
|
|
133
|
+
**JPA mapping.** Do not test that `@Column(name = "email")` maps to the right
|
|
134
|
+
column. That is Hibernate's job.
|
|
135
|
+
|
|
136
|
+
**Trivial getters and setters.** A data class property has no logic. There is
|
|
137
|
+
nothing to test.
|
|
138
|
+
|
|
139
|
+
**Private methods directly.** Private methods are implementation details. Test
|
|
140
|
+
them through the public behavior that uses them. If a private method is complex
|
|
141
|
+
enough to need its own test, it should be extracted into a separate class.
|
|
142
|
+
|
|
143
|
+
**Implementation, not behavior.** Tests that verify HOW something is done (mock
|
|
144
|
+
call order, internal state) are brittle. Test WHAT the output or side effect is.
|
|
145
|
+
|
|
146
|
+
```kotlin
|
|
147
|
+
// bad — tests implementation detail
|
|
148
|
+
verify { userRepository.findById(any()) }
|
|
149
|
+
verify { cacheService.put(any(), any()) }
|
|
150
|
+
verify(ordering = Ordering.ORDERED) { // this is too coupled to internals
|
|
151
|
+
userRepository.findById(userId)
|
|
152
|
+
cacheService.put(userId, user)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// good — tests observable behavior
|
|
156
|
+
assertThat(result).isEqualTo(expectedUser)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## MockK Patterns
|
|
160
|
+
|
|
161
|
+
### Basic Setup
|
|
162
|
+
|
|
163
|
+
```kotlin
|
|
164
|
+
@ExtendWith(MockKExtension::class)
|
|
165
|
+
class UserServiceTest {
|
|
166
|
+
|
|
167
|
+
@MockK
|
|
168
|
+
private lateinit var userRepository: UserRepository
|
|
169
|
+
|
|
170
|
+
@MockK
|
|
171
|
+
private lateinit var emailService: EmailService
|
|
172
|
+
|
|
173
|
+
private lateinit var userService: UserService
|
|
174
|
+
|
|
175
|
+
@BeforeEach
|
|
176
|
+
fun setUp() {
|
|
177
|
+
userService = UserService(userRepository, emailService)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Stubbing
|
|
183
|
+
|
|
184
|
+
```kotlin
|
|
185
|
+
// Return value
|
|
186
|
+
every { userRepository.findById(userId) } returns Optional.of(user)
|
|
187
|
+
|
|
188
|
+
// Return null (for nullable return types)
|
|
189
|
+
every { userRepository.findByEmail(any()) } returns null
|
|
190
|
+
|
|
191
|
+
// Throw exception
|
|
192
|
+
every { userRepository.save(any()) } throws DataIntegrityViolationException("Duplicate")
|
|
193
|
+
|
|
194
|
+
// Return different values on successive calls
|
|
195
|
+
every { userRepository.findById(any()) } returnsMany listOf(Optional.of(user), Optional.empty())
|
|
196
|
+
|
|
197
|
+
// Answer with computation
|
|
198
|
+
every { userRepository.save(any()) } answers { firstArg() }
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Verification
|
|
202
|
+
|
|
203
|
+
```kotlin
|
|
204
|
+
// Verify called exactly once with specific argument
|
|
205
|
+
verify(exactly = 1) { userRepository.findById(userId) }
|
|
206
|
+
|
|
207
|
+
// Verify called with any argument
|
|
208
|
+
verify { emailService.sendWelcome(any()) }
|
|
209
|
+
|
|
210
|
+
// Verify never called
|
|
211
|
+
verify(exactly = 0) { emailService.sendWelcome(any()) }
|
|
212
|
+
|
|
213
|
+
// Verify called with specific argument
|
|
214
|
+
verify { emailService.sendWelcome(match { it.email == "user@example.com" }) }
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Relaxed Mocks
|
|
218
|
+
|
|
219
|
+
```kotlin
|
|
220
|
+
// relaxed = true — returns default values (null, 0, false, empty list)
|
|
221
|
+
// Use only when you do not care about the return value of any method
|
|
222
|
+
val logger = mockk<Logger>(relaxed = true)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Do not use `relaxed = true` on mocks where you need to verify behavior — a
|
|
226
|
+
relaxed mock does not fail on unexpected calls, which can hide bugs.
|
|
227
|
+
|
|
228
|
+
### Coroutines
|
|
229
|
+
|
|
230
|
+
```kotlin
|
|
231
|
+
// Stubbing suspend functions
|
|
232
|
+
coEvery { userRepository.findById(userId) } returns user
|
|
233
|
+
|
|
234
|
+
// Verifying suspend functions
|
|
235
|
+
coVerify(exactly = 1) { userRepository.findById(userId) }
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Argument Matchers
|
|
239
|
+
|
|
240
|
+
```kotlin
|
|
241
|
+
// Any value
|
|
242
|
+
every { service.process(any()) } returns result
|
|
243
|
+
|
|
244
|
+
// Specific type
|
|
245
|
+
every { service.process(any<UserRequest>()) } returns result
|
|
246
|
+
|
|
247
|
+
// Custom predicate
|
|
248
|
+
every { service.notify(match { it.email.endsWith("@example.com") }) } just Runs
|
|
249
|
+
|
|
250
|
+
// Capture for assertion
|
|
251
|
+
val slot = slot<User>()
|
|
252
|
+
every { userRepository.save(capture(slot)) } returns savedUser
|
|
253
|
+
// ... trigger the action ...
|
|
254
|
+
assertThat(slot.captured.email).isEqualTo("expected@example.com")
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Integration Test Patterns
|
|
258
|
+
|
|
259
|
+
### Controller Tests with MockMvc
|
|
260
|
+
|
|
261
|
+
```kotlin
|
|
262
|
+
@SpringBootTest
|
|
263
|
+
@AutoConfigureMockMvc
|
|
264
|
+
class UserControllerTest {
|
|
265
|
+
|
|
266
|
+
@Autowired
|
|
267
|
+
private lateinit var mockMvc: MockMvc
|
|
268
|
+
|
|
269
|
+
@Autowired
|
|
270
|
+
private lateinit var objectMapper: ObjectMapper
|
|
271
|
+
|
|
272
|
+
@Test
|
|
273
|
+
fun `should return 200 with user when found`() {
|
|
274
|
+
mockMvc.perform(
|
|
275
|
+
get("/api/v1/users/${existingUser.id}")
|
|
276
|
+
.contentType(MediaType.APPLICATION_JSON)
|
|
277
|
+
)
|
|
278
|
+
.andExpect(status().isOk)
|
|
279
|
+
.andExpect(jsonPath("$.email").value(existingUser.email))
|
|
280
|
+
.andExpect(jsonPath("$.id").value(existingUser.id.toString()))
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
@Test
|
|
284
|
+
fun `should return 400 when request body is invalid`() {
|
|
285
|
+
val invalidRequest = mapOf("email" to "not-an-email")
|
|
286
|
+
|
|
287
|
+
mockMvc.perform(
|
|
288
|
+
post("/api/v1/users")
|
|
289
|
+
.contentType(MediaType.APPLICATION_JSON)
|
|
290
|
+
.content(objectMapper.writeValueAsString(invalidRequest))
|
|
291
|
+
)
|
|
292
|
+
.andExpect(status().isBadRequest)
|
|
293
|
+
.andExpect(jsonPath("$.code").value("VALIDATION_ERROR"))
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
@Test
|
|
297
|
+
fun `should return 404 when user is not found`() {
|
|
298
|
+
mockMvc.perform(get("/api/v1/users/${UUID.randomUUID()}"))
|
|
299
|
+
.andExpect(status().isNotFound)
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
`@AutoConfigureMockMvc` configures MockMvc without starting a real HTTP server.
|
|
305
|
+
The test is faster than `RANDOM_PORT` but still tests the full Spring MVC stack.
|
|
306
|
+
|
|
307
|
+
Use `RANDOM_PORT` only when you need real HTTP (e.g., testing HTTP client
|
|
308
|
+
behavior, WebSockets, or SSE).
|
|
309
|
+
|
|
310
|
+
### Database Tests with Testcontainers
|
|
311
|
+
|
|
312
|
+
```kotlin
|
|
313
|
+
@SpringBootTest
|
|
314
|
+
@Testcontainers
|
|
315
|
+
class UserRepositoryIntegrationTest {
|
|
316
|
+
|
|
317
|
+
companion object {
|
|
318
|
+
@Container
|
|
319
|
+
@JvmStatic
|
|
320
|
+
val postgres = PostgreSQLContainer<Nothing>("postgres:16").apply {
|
|
321
|
+
withDatabaseName("testdb")
|
|
322
|
+
withUsername("test")
|
|
323
|
+
withPassword("test")
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
@DynamicPropertySource
|
|
327
|
+
@JvmStatic
|
|
328
|
+
fun overrideProperties(registry: DynamicPropertyRegistry) {
|
|
329
|
+
registry.add("spring.datasource.url", postgres::getJdbcUrl)
|
|
330
|
+
registry.add("spring.datasource.username", postgres::getUsername)
|
|
331
|
+
registry.add("spring.datasource.password", postgres::getPassword)
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
@Autowired
|
|
336
|
+
private lateinit var userRepository: UserRepository
|
|
337
|
+
|
|
338
|
+
@Test
|
|
339
|
+
fun `should enforce unique email at database level`() {
|
|
340
|
+
userRepository.save(User(email = "unique@example.com", name = "First"))
|
|
341
|
+
assertThrows<DataIntegrityViolationException> {
|
|
342
|
+
userRepository.save(User(email = "unique@example.com", name = "Second"))
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Share the container across test classes using a base class with `@Container` on
|
|
349
|
+
a static field. Testcontainers reuses the same container if the configuration is
|
|
350
|
+
identical.
|
|
351
|
+
|
|
352
|
+
### Seed Data with @Sql
|
|
353
|
+
|
|
354
|
+
```kotlin
|
|
355
|
+
@SpringBootTest
|
|
356
|
+
@AutoConfigureMockMvc
|
|
357
|
+
@Sql("/test-data/users.sql") // runs before each test in this class
|
|
358
|
+
class UserControllerTest { ... }
|
|
359
|
+
|
|
360
|
+
// Or per-test
|
|
361
|
+
@Test
|
|
362
|
+
@Sql("/test-data/users-with-orders.sql")
|
|
363
|
+
fun `should return orders when user has orders`() { ... }
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
SQL files go in `src/test/resources/test-data/`. Use descriptive names that
|
|
367
|
+
explain what state they create, not what feature they serve.
|
|
368
|
+
|
|
369
|
+
## Test Data Factories
|
|
370
|
+
|
|
371
|
+
Never hardcode UUIDs or share mutable state between tests.
|
|
372
|
+
|
|
373
|
+
```kotlin
|
|
374
|
+
object UserTestFactory {
|
|
375
|
+
|
|
376
|
+
fun create(
|
|
377
|
+
id: UUID = UUID.randomUUID(),
|
|
378
|
+
email: String = "user-${UUID.randomUUID()}@example.com",
|
|
379
|
+
name: String = "Test User",
|
|
380
|
+
role: UserRole = UserRole.USER
|
|
381
|
+
): User = User(
|
|
382
|
+
id = id,
|
|
383
|
+
email = email,
|
|
384
|
+
name = name,
|
|
385
|
+
role = role
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
fun createRequest(
|
|
389
|
+
email: String = "user-${UUID.randomUUID()}@example.com",
|
|
390
|
+
name: String = "Test User"
|
|
391
|
+
): CreateUserRequest = CreateUserRequest(
|
|
392
|
+
email = email,
|
|
393
|
+
name = name
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
fun createAdmin(): User = create(role = UserRole.ADMIN)
|
|
397
|
+
|
|
398
|
+
fun createList(count: Int): List<User> = (1..count).map { create() }
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Usage in tests:
|
|
403
|
+
|
|
404
|
+
```kotlin
|
|
405
|
+
val user = UserTestFactory.create(email = "specific@example.com")
|
|
406
|
+
val admin = UserTestFactory.createAdmin()
|
|
407
|
+
val users = UserTestFactory.createList(5)
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Default values use `UUID.randomUUID()` to ensure tests do not share state
|
|
411
|
+
through hardcoded IDs or emails.
|
|
412
|
+
|
|
413
|
+
## When Tests Are Required
|
|
414
|
+
|
|
415
|
+
**New behavior.** Every new feature requires at minimum one unit test and one
|
|
416
|
+
integration test covering the happy path. Edge cases and error paths require
|
|
417
|
+
additional unit tests.
|
|
418
|
+
|
|
419
|
+
**Bug fix.** Write a regression test that reproduces the bug before fixing it.
|
|
420
|
+
The test must fail before the fix and pass after. This prevents the bug from
|
|
421
|
+
reappearing silently.
|
|
422
|
+
|
|
423
|
+
```kotlin
|
|
424
|
+
// Example: bug where findByEmail returned deleted users
|
|
425
|
+
@Test
|
|
426
|
+
fun `should not return deleted user — regression for bug #42`() {
|
|
427
|
+
val user = userRepository.save(UserTestFactory.create(email = "gone@example.com"))
|
|
428
|
+
userRepository.delete(user)
|
|
429
|
+
val result = userRepository.findByEmail("gone@example.com")
|
|
430
|
+
assertThat(result).isNull()
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
**Refactor.** Do not write new tests. The existing tests must pass unchanged. If
|
|
435
|
+
they do not, the refactor changed behavior — that is a bug.
|
|
436
|
+
|
|
437
|
+
**High-risk paths.** Security, payment processing, data migrations, and
|
|
438
|
+
permission checks require contract tests in addition to unit and integration
|
|
439
|
+
tests. These paths have severe consequences if broken.
|
|
440
|
+
|
|
441
|
+
## CI Integration
|
|
442
|
+
|
|
443
|
+
Tests must run in CI on every pull request. The pipeline must fail if any test
|
|
444
|
+
fails.
|
|
445
|
+
|
|
446
|
+
Recommended test execution order:
|
|
447
|
+
|
|
448
|
+
1. Unit tests (fastest — fail fast)
|
|
449
|
+
2. Integration tests with H2 (`@DataJpaTest`)
|
|
450
|
+
3. Integration tests with Testcontainers (slowest — run last)
|
|
451
|
+
|
|
452
|
+
Separate test tasks in Gradle:
|
|
453
|
+
|
|
454
|
+
```kotlin
|
|
455
|
+
// build.gradle.kts
|
|
456
|
+
tasks.register<Test>("integrationTest") {
|
|
457
|
+
description = "Runs integration tests"
|
|
458
|
+
group = "verification"
|
|
459
|
+
useJUnitPlatform {
|
|
460
|
+
includeTags("integration")
|
|
461
|
+
}
|
|
462
|
+
shouldRunAfter(tasks.test)
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
Tag integration tests:
|
|
467
|
+
|
|
468
|
+
```kotlin
|
|
469
|
+
@Tag("integration")
|
|
470
|
+
@SpringBootTest
|
|
471
|
+
class UserRepositoryIntegrationTest { ... }
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
Do not mix unit and integration test tags in the same class. A test class is
|
|
475
|
+
either one or the other.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: tailwind-responsive-auditor
|
|
3
|
+
name: tailwind-responsive-auditor
|
|
4
|
+
description: >
|
|
5
|
+
Audits Tailwind CSS usage ensuring mobile-first responsive utilities and clean classes.
|
|
6
|
+
user-invokable: true
|
|
7
|
+
license: MIT
|
|
8
|
+
metadata:
|
|
9
|
+
author: lgzarturo
|
|
10
|
+
category: frontend
|
|
11
|
+
compatibility:
|
|
12
|
+
tools: [claude, codex, gemini, agy, opencode]
|
|
13
|
+
stacks:
|
|
14
|
+
languages: [typescript, javascript, html]
|
|
15
|
+
frameworks: [astro, nextjs, react, tailwindcss]
|
|
16
|
+
---
|
|
17
|
+
# Tailwind Responsive Auditor
|
|
18
|
+
|
|
19
|
+
## Core Principles
|
|
20
|
+
|
|
21
|
+
1. **Mobile-First Design**: Always apply styles for mobile first (without breakpoints), then override them for larger screens (`sm:`, `md:`, `lg:`, `xl:`).
|
|
22
|
+
2. **Class Deduplication**: Avoid redundant classes (e.g. `w-full w-auto` or `text-red-500 text-blue-500`).
|
|
23
|
+
3. **No Arbitrary Values**: Avoid using arbitrary values like `w-[327px]` or `bg-[#f0f0f0]` unless absolutely necessary. Rely on the configured Tailwind theme.
|
|
24
|
+
|
|
25
|
+
## Audit Checklist
|
|
26
|
+
|
|
27
|
+
- Do not use desktop-first design (e.g., max-width utilities should be avoided unless specified).
|
|
28
|
+
- Ensure that elements have responsive margins, padding, and layout flex/grid direction where needed.
|
|
29
|
+
- Alert on duplicate or conflicting utility classes in component files.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: tdd-mutation-tester
|
|
3
|
+
name: tdd-mutation-tester
|
|
4
|
+
description: >
|
|
5
|
+
Performs simple mutation testing to verify test coverage and assertions.
|
|
6
|
+
user-invokable: true
|
|
7
|
+
license: MIT
|
|
8
|
+
metadata:
|
|
9
|
+
author: lgzarturo
|
|
10
|
+
category: testing
|
|
11
|
+
compatibility:
|
|
12
|
+
tools: [claude, codex, gemini, agy, opencode]
|
|
13
|
+
stacks:
|
|
14
|
+
languages: [typescript, javascript, python, kotlin, java, php]
|
|
15
|
+
---
|
|
16
|
+
# TDD Mutation Tester
|
|
17
|
+
|
|
18
|
+
## Core Principles
|
|
19
|
+
|
|
20
|
+
1. **Verify Assertion Quality**: Coverage percentage can be misleading. Tests must fail when business logic changes.
|
|
21
|
+
2. **Mutation Process**:
|
|
22
|
+
- Locate the core logic implemented by the `implementer`.
|
|
23
|
+
- Temporarily mutate a logical operator (e.g. swap `>` for `<`, `==` for `!=`, `+` for `-`, or invert a boolean).
|
|
24
|
+
- Run the test suite.
|
|
25
|
+
- **Expected Result**: At least one test MUST fail.
|
|
26
|
+
- **Clean Up**: Revert the mutated symbol immediately after running the test.
|
|
27
|
+
3. **Scorecard**: If the test suite passes even with mutated business logic, report a "0 in Real Coverage" on the scorecard and return the task for better test assertions.
|
package/presets/cursor/AGENTS.md
CHANGED
|
@@ -459,6 +459,12 @@ docs | test **Risk:** low | medium | high **Scope:** [files or modules affected]
|
|
|
459
459
|
**Agent:** [agent name] **Requires review:** yes | no
|
|
460
460
|
```
|
|
461
461
|
|
|
462
|
+
## Receipt integrity
|
|
463
|
+
|
|
464
|
+
- For any implementation, test, review, handoff, or delivery decision, capture or verify the current RDD receipt with `bun run dev rdd`.
|
|
465
|
+
- A receipt is valid only for its exact candidate. If code, tests, contracts, or runner configuration changed, repeat the affected verification.
|
|
466
|
+
- TDD and Mutation Testing retain their existing gates; RDD verifies that their observed evidence still belongs to the current candidate.
|
|
467
|
+
|
|
462
468
|
<!-- CODECONDUCTOR:END managed -->
|
|
463
469
|
|
|
464
470
|
---
|
|
@@ -30,7 +30,9 @@ errors instead of pasting dumps. If unresolved credential material remains, stop
|
|
|
30
30
|
and wait for a human (CCEP `stopOnHighRisk`).
|
|
31
31
|
|
|
32
32
|
Include: goal, Task Card status (no secret fields), files touched, test
|
|
33
|
-
pass/fail (not log dumps), open questions,
|
|
33
|
+
pass/fail (not log dumps), open questions, the next `/cc:` command, plus links
|
|
34
|
+
to the Delivery Ledger and verification evidence when they exist. Do not repeat
|
|
35
|
+
the original request or transcript.
|
|
34
36
|
|
|
35
37
|
Do not edit source or tests.
|
|
36
38
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create or resume an opt-in Delivery Ledger for substantial authorized work.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /cc:odd
|
|
6
|
+
|
|
7
|
+
## Step 0 — CCEP Bootstrap
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun run dev ccep parse --command odd "$ARGUMENTS"
|
|
11
|
+
bun run dev ccep resolve --command odd "$ARGUMENTS"
|
|
12
|
+
bun run dev ccep profile --command odd
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Create a ledger only after authorization and tracked coordination. Read-only and small work do not create state.
|
|
16
|
+
|
|
17
|
+
When ODD has verification evidence, include its RDD receipt in the ledger
|
|
18
|
+
handoff. On resume, verify it against the workspace before relying on a prior
|
|
19
|
+
test or review result. If it is stale, keep the ledger and repeat only the
|
|
20
|
+
invalidated verification.
|
|
@@ -135,6 +135,10 @@ npx cc-codeconductor openspec archive <itemId>
|
|
|
135
135
|
|
|
136
136
|
`start` moves the card `pending → doing` and the item `PLANNED → IN_PROGRESS`. `done` marks the card complete, updates Progress, and moves the item to `REVIEW` when every card is done and review is required. `archive` requires all cards done (and review evidence when Global review is required) and moves `openspec/changes/<slug>` to `archive/`.
|
|
137
137
|
|
|
138
|
+
For test and implementation cards, `done` also requires a current RDD-backed
|
|
139
|
+
RED or GREEN receipt respectively. Do not reuse evidence after candidate files
|
|
140
|
+
change; capture and verify the matching receipt again.
|
|
141
|
+
|
|
138
142
|
---
|
|
139
143
|
|
|
140
144
|
## Step 5 — Model matrix and execute loop
|
|
@@ -207,4 +211,4 @@ Report completion: Task Cards executed, scorecard verdict, change folder path, f
|
|
|
207
211
|
|
|
208
212
|
## Skill
|
|
209
213
|
|
|
210
|
-
Apply `.
|
|
214
|
+
Apply `.cursor/skills/openspec/SKILL.md` for backlog format rules and state transitions.
|
|
@@ -63,9 +63,8 @@ the following steps in order:
|
|
|
63
63
|
the output filename: `{YYYY-MM-DD}_pagespeed-{hostname}-claude.md`.
|
|
64
64
|
|
|
65
65
|
2. **Collect** — Call the PageSpeed Insights API for the requested strategy
|
|
66
|
-
(`mobile`, `desktop`, or `both`)
|
|
67
|
-
|
|
68
|
-
Otherwise, use `WebFetch` to call the PSI endpoint directly.
|
|
66
|
+
(`mobile`, `desktop`, or `both`) using `WebFetch` to call the PSI endpoint
|
|
67
|
+
directly.
|
|
69
68
|
|
|
70
69
|
3. **Analyze** — Extract Core Web Vitals (LCP, INP, CLS, FCP, TTFB, TBT),
|
|
71
70
|
identify the LCP element, enumerate third-party scripts by blocking time,
|
|
@@ -113,6 +113,37 @@ Evaluate the diff against the following checklist:
|
|
|
113
113
|
|
|
114
114
|
---
|
|
115
115
|
|
|
116
|
+
## Severity Rubric
|
|
117
|
+
|
|
118
|
+
Classify every finding using these concrete anchors — not general judgment —
|
|
119
|
+
so the same finding gets the same category on any run.
|
|
120
|
+
|
|
121
|
+
**CRITICAL** (always):
|
|
122
|
+
|
|
123
|
+
- Unauthenticated access to a protected resource
|
|
124
|
+
- Injection (SQL, command, XSS) reachable from untrusted input
|
|
125
|
+
- A secret or credential present in the diff
|
|
126
|
+
- A destructive operation with no confirmation
|
|
127
|
+
- The build or test suite is broken
|
|
128
|
+
- A direct contradiction of an explicit acceptance criterion
|
|
129
|
+
|
|
130
|
+
**WARNING**:
|
|
131
|
+
|
|
132
|
+
- Missing test for a new branch or edge case
|
|
133
|
+
- An error is silently swallowed — no log, no propagation
|
|
134
|
+
- A change outside the declared scope
|
|
135
|
+
- Inconsistent with an established pattern already in the module
|
|
136
|
+
- Missing input validation in an internal function (not exposed at a trust boundary)
|
|
137
|
+
|
|
138
|
+
**SUGGESTION**:
|
|
139
|
+
|
|
140
|
+
- Style or naming
|
|
141
|
+
- Minor readability
|
|
142
|
+
- Speculative refactor that wasn't requested
|
|
143
|
+
- Non-blocking micro-optimization
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
116
147
|
## Step 3 — Review Report
|
|
117
148
|
|
|
118
149
|
Produce a structured Review Report with findings in three categories:
|
|
@@ -62,7 +62,7 @@ If `graphify-out/graph.json` exists, run `graphify query "$ARGUMENTS"` (and
|
|
|
62
62
|
`graphify path` / `graphify explain` when needed). Then invoke `repo-explorer`
|
|
63
63
|
to map modules, conventions, and impact radius. Do not write code in this step.
|
|
64
64
|
Record a Repo Map artifact before intake. Load the matching `security-*` skill
|
|
65
|
-
for the named domain (see `.
|
|
65
|
+
for the named domain (see `.cursor/skills/security-*/SKILL.md`). Keep the OWASP
|
|
66
66
|
`security` skill for application-security reviews.
|
|
67
67
|
|
|
68
68
|
---
|
|
@@ -129,6 +129,11 @@ Verdict is binary: PASS continues to the mutation gate; REJECT returns to the
|
|
|
129
129
|
|
|
130
130
|
## Stage 5 — Mutation gate (`mutation_testing`)
|
|
131
131
|
|
|
132
|
+
RDD complements this gate: capture the candidate receipt before Mutation Testing
|
|
133
|
+
and verify it after the runner restores production source. A survivor opens a
|
|
134
|
+
new tester/reviewer-approved test revision; it never makes an earlier receipt
|
|
135
|
+
valid again.
|
|
136
|
+
|
|
132
137
|
Run the deterministic AST mutator shipped with this preset:
|
|
133
138
|
|
|
134
139
|
```bash
|