Cursor rule
.cursor/rules/develop-tdd.mdcTest-driven development with red-green-refactor loop using vertical slices. Use for features (epic tasks) or bugs (specs/bugs/BUG-*.md).
Cursor rules
Quality
85/100
Scores the file, not the repository.Length
2,141 words
32 headings · 14 code blocksRepository
119
— · pushed 1 days agoLast changed
3 days ago
First indexed 3 days ago.123456# Develop TDD78> **HARD GATE** — Do NOT proceed if on `main` or `master`. Run `kickoff-branch` first to create a feature branch or worktree.9>10> **HARD GATE** — Do NOT write code before you have a plan. New feature: `plan-work` → epic capsule tasks. Bug: `investigate-bug` → `specs/bugs/BUG-*.md` (or use `fix-bug` orchestrator).11>12> **RECURSIVE DISCIPLINE** — This lifecycle applies to EVERY task, including updating these skills. Never skip planning because a task is "meta" or "just documentation."1314## Philosophy1516Tests verify behavior through public interfaces, not implementation details. A good test reads like a specification. See [REFERENCE.md](REFERENCE.md) for the horizontal-slice anti-pattern and TDD phase detail.1718## Red Flags1920If you catch yourself thinking these, stop and reconsider — you are likely deviating from production-grade craft.2122| Red Flag | Reality |23| :--- | :--- |24| "This is too simple to need tests." | Simple code is where bugs hide. If it's simple, the test is cheap. |25| "I'll refactor this later." | "Later" is when technical debt becomes bankruptcy. Refactor while Green. |26| "The tests are already comprehensive." | If you're adding behavior, you need a new test. Coverage ≠ Correctness. |27| "I'm just fixing a small bug." | Small bugs often indicate deep interface flaws. Investigate root cause. |28| "I need to mock this internal class." | Mocking internals couples tests to implementation. Mock only I/O. |29| "This refactor is out of scope." | Leave the code cleaner than you found it (Boy Scout Rule). |30| "Preflight failed but it's unrelated." | **Always Green:** any reproducible gate failure routes **quick-fix → fix-bug** before forward work. Session boundaries do not waive Preflight. |31| "I'll note the red gate and continue." | Narrating a failure is banned. fix-or-log is mandatory per CONVENTIONS § Discovered Defects. |3233## Workflow3435> **Timing:** `bash scripts/bp-timing.sh start develop-tdd` at invocation; `bash scripts/bp-timing.sh end develop-tdd` before handoff.3637### 1. Planning3839- [ ] Read active `specs/epics/*/epic.yaml` story tasks or `specs/bugs/BUG-*.md` — understand verify steps40- [ ] If `specs/tech-architecture/eNN-TEST_PLAN_LATEST.md` exists for the active epic, read it before writing the first test. Implement P0 scenarios (`SC-*-P0-*`) before P1. P2/P3 scenarios are optional per time budget.41- [ ] Confirm interface changes and behaviors to test (prioritize)42- [ ] Design interfaces for testability — identify [deep modules](deep-modules.md) opportunities43- [ ] Get user approval on the plan4445Apply the **enforce-first** F.I.R.S.T rubric: Fast, Independent, Repeatable, Self-Validating, Timely.4647### 2. Tracer Bullet4849Write ONE test that confirms ONE thing about the system:5051```52RED: Write test for first behavior → test fails → commit: test(<scope>): ... (test-only; red in CI)53GREEN: Write minimal code to pass → test passes → commit: feat(<scope>): ... (fix commit; green)54REFACTOR (optional): clean up → commit: refactor(<scope>): ...55```5657> **Two-commit red/green policy (HARD GATE — e45s08)** — Each behavior cycle requires **two separate commits**: (1) test-only commit that fails in CI (RED), then (2) implementation commit that makes it pass (GREEN). Never combine test + fix in one commit. Before proceeding, run the mechanical RED isolation check:5859```bash60bash scripts/verify-tdd-red-commit.sh61```6263Show `git log -2 --oneline` **and** the script output as evidence. If the test-only commit passes in isolation, the RED gate is violated — stop and fix before GREEN.6465> **tasks.yaml ledger (e45s06)** — After each task's `verify:` exits 0, update `eNNsYY-tasks.yaml`: set that task's `status: passing`. Story-level `status: passing` only when all tasks pass.6667### 3. Incremental Loop6869> **Snapshot-before-transition (e45s34):** Before each RED → GREEN or GREEN → REFACTOR transition, create a checkpoint so a failed transition can be rolled back cleanly:7071```bash72bash scripts/bp-yaml-snapshot.sh specs/state.yaml # if state changed this cycle73git stash push -m "tdd-checkpoint-$(git rev-parse --short HEAD)-red" --keep-index 2>/dev/null || true74```7576After GREEN passes and is committed, drop the stash (`git stash drop` if empty). Never refactor while RED.7778For each remaining behavior: RED → GREEN → REFACTOR (optional). One test at a time. **Two commits per behavior** (test-only RED, then fix GREEN). Commit after every GREEN phase.7980### 4. Visual Slices (UI alternate workflow)8182For UI components where behavioral unit testing is brittle: extract logic into a Controller/ViewModel/Hook (pure TDD), then use Visual Slices for the View layer. See [REFERENCE.md](REFERENCE.md) for the full Visual Slices procedure.8384### 5. Refactor8586After all tests pass: extract duplication, deepen modules, apply SOLID principles. **Never refactor while RED.**8788### 6. Verify8990After every behavior cycle, run the verify command from the active epic task. Show evidence before declaring the step done.9192### 7. Manual Verification Handover9394Once all tests pass: locate the Verification Script in the active epic capsule, present it to the user step-by-step, and wait for confirmation of behavioral correctness.959697### 6a. CI dry-run sub-step9899If this cycle modified files in `.github/workflows/`, run the CI dry-run procedure documented in [REFERENCE.md](REFERENCE.md#ci-dry-run).100101## Checklist Per Cycle102103```104[ ] Test describes behavior, not implementation105[ ] No test is ignored without an explicit ambiguity note (T4)106[ ] Boundary conditions tested: empty, max, min, off-by-one (T5)107[ ] Tests verify behavior through public interface only — no private methods (T8)108[ ] Test would survive internal refactor109[ ] Code is minimal for this test110[ ] No speculative features added111[ ] Every new abstraction has an explicit "Reason for Depth" justification112[ ] Progress committed (Conventional Commits)113[ ] verify: command passes114```115116117118## Handoff119120Gate: READY -> next: verify-work121Writes: state.yaml handoff.next_skill = verify-work122123## BCP Plus Integration124125At story completion, if the story was sized with BCP Plus (13-dimension breakdown), log the `bcp_plus.total` alongside the standard `bcps:` count in the story's tasks.yaml. The breakdown is available from the epic capsule's `bcp_plus_breakdown` field. See `docs/references/bcp-plus.md` for the full methodology and NFR Gate pattern.126127## Verify128129→ verify: `test -x scripts/verify-tdd-red-commit.sh && bash scripts/verify-tdd-red-commit.sh --self-test && grep -q 'verify-tdd-red-commit' skills/develop-tdd/SKILL.md && echo OK`130131132<!-- story: e02s04 -->133134---135136# Develop TDD — Reference137138## Anti-Pattern: Horizontal Slices139140**DO NOT write all tests first, then all implementation.** This is "horizontal slicing" — treating RED as "write all tests" and GREEN as "write all code."141142This produces **crap tests**:143- Tests written in bulk test _imagined_ behavior, not _actual_ behavior144- You end up testing the _shape_ of things rather than user-facing behavior145- Tests become insensitive to real changes146147**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat.148149```150WRONG (horizontal):151 RED: test1, test2, test3, test4, test5152 GREEN: impl1, impl2, impl3, impl4, impl5153154RIGHT (vertical):155 RED→GREEN: test1→impl1156 RED→GREEN: test2→impl2157 RED→GREEN: test3→impl3158 ...159```160161> The Red Flags table lives in [SKILL.md](SKILL.md#red-flags) — it is core behavioral guidance, not reference detail.162163## TDD Phases (Detail)164165### Red Phase166167Write a failing test first:168- Test describes the desired observable behavior through the public interface169- Run the test to confirm it fails for the right reason (not a syntax error, not a typo)170- Commit: `git commit -m "test(<scope>): <description>"`171172### Green Phase173174Write the minimum code to make the test pass:175- No extra logic, no anticipated future cases, no premature optimization176- Focus only on making the current test pass177- Commit: `git commit -m "feat(<scope>): <description>"` or `"fix(<scope>): <description>"`178179### Refactor Phase180181Improve structure without changing behavior:182- Extract duplication, apply SOLID principles where natural, deepen modules183- Run tests after each refactor step to ensure behavior is preserved184- Commit: `git commit -m "refactor(<scope>): <description>"`185- Apply the Boy Scout Rule: leave the code cleaner than you found it186187## Visual Slices (UI Alternate Workflow)188189For UI components (SwiftUI, React, Flutter) where behavioral unit testing is brittle or low-signal:1901911. **Test-First Logic**: Extract logic (state transitions, formatting, validation) into a Controller, ViewModel, or Hook. This logic MUST follow pure TDD.1922. **Visual Verification**: For the View/Component itself:193 - **RED**: Write the component signature and a basic preview/snapshot that fails (or displays placeholder).194 - **GREEN**: Implement the UI and verify visually via manual run, preview, or snapshot test.195 - **REFINE**: Adjust styling and layout until it matches the design.1963. **COMMIT**: `git commit -m "feat(ui): <component name> visual slice verified"`197198---199200# Deep Modules201202From "A Philosophy of Software Design":203204**Deep module** = small interface + lots of implementation205206```207┌─────────────────────┐208│ Small Interface │ ← Few methods, simple params209├─────────────────────┤210│ │211│ │212│ Deep Implementation│ ← Complex logic hidden213│ │214│ │215└─────────────────────┘216```217218**Shallow module** = large interface + little implementation (avoid)219220```221┌─────────────────────────────────┐222│ Large Interface │ ← Many methods, complex params223├─────────────────────────────────┤224│ Thin Implementation │ ← Just passes through225└─────────────────────────────────┘226```227228When designing interfaces, ask:229230- Can I reduce the number of methods?231- Can I simplify the parameters?232- Can I hide more complexity inside?233234---235236# Interface Design for Testability237238Good interfaces make testing natural:2392401. **Accept dependencies, don't create them**241242```typescript243 // Testable244 function processOrder(order, paymentGateway) {}245246 // Hard to test247 function processOrder(order) {248 const gateway = new StripeGateway();249 }250```2512522. **Return results, don't produce side effects**253254```typescript255 // Testable256 function calculateDiscount(cart): Discount {}257258 // Hard to test259 function applyDiscount(cart): void {260 cart.total -= discount;261 }262```2632643. **Small surface area**265 - Fewer methods = fewer tests needed266 - Fewer params = simpler test setup267268---269270# When to Mock271272Mock at **system boundaries** only:273274- External APIs (payment, email, etc.)275- Databases (sometimes - prefer test DB)276- Time/randomness277- File system (sometimes)278279Don't mock:280281- Your own classes/modules282- Internal collaborators283- Anything you control284285## Designing for Mockability286287At system boundaries, design interfaces that are easy to mock:288289**1. Use dependency injection**290291Pass external dependencies in rather than creating them internally:292293```typescript294// Easy to mock295function processPayment(order, paymentClient) {296 return paymentClient.charge(order.total);297}298299// Hard to mock300function processPayment(order) {301 const client = new StripeClient(process.env.STRIPE_KEY);302 return client.charge(order.total);303}304```305306**2. Prefer SDK-style interfaces over generic fetchers**307308Create specific functions for each external operation instead of one generic function with conditional logic:309310```typescript311// GOOD: Each function is independently mockable312const api = {313 getUser: (id) => fetch(`/users/${id}`),314 getOrders: (userId) => fetch(`/users/${userId}/orders`),315 createOrder: (data) => fetch('/orders', { method: 'POST', body: data }),316};317318// BAD: Mocking requires conditional logic inside the mock319const api = {320 fetch: (endpoint, options) => fetch(endpoint, options),321};322```323324The SDK approach means:325- Each mock returns one specific shape326- No conditional logic in test setup327- Easier to see which endpoints a test exercises328- Type safety per endpoint329330---331332# Refactor Candidates333334After TDD cycle, look for:335336- **Duplication** → Extract function/class337- **Long methods** → Break into private helpers (keep tests on public interface)338- **Shallow modules** → Combine or deepen339- **Feature envy** → Move logic to where data lives340- **Primitive obsession** → Introduce value objects341- **Existing code** the new code reveals as problematic342343---344345# Good and Bad Tests346347## Good Tests348349**Integration-style**: Test through real interfaces, not mocks of internal parts.350351```typescript352// GOOD: Tests observable behavior353test("user can checkout with valid cart", async () => {354 const cart = createCart();355 cart.add(product);356 const result = await checkout(cart, paymentMethod);357 expect(result.status).toBe("confirmed");358});359```360361Characteristics:362363- Tests behavior users/callers care about364- Uses public API only365- Survives internal refactors366- Describes WHAT, not HOW367- One logical assertion per test368369## Bad Tests370371**Implementation-detail tests**: Coupled to internal structure.372373```typescript374// BAD: Tests implementation details375test("checkout calls paymentService.process", async () => {376 const mockPayment = jest.mock(paymentService);377 await checkout(cart, payment);378 expect(mockPayment.process).toHaveBeenCalledWith(cart.total);379});380```381382Red flags:383384- Mocking internal collaborators385- Testing private methods386- Asserting on call counts/order387- Test breaks when refactoring without behavior change388- Test name describes HOW not WHAT389- Verifying through external means instead of interface390391```typescript392// BAD: Bypasses interface to verify393test("createUser saves to database", async () => {394 await createUser({ name: "Alice" });395 const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);396 expect(row).toBeDefined();397});398399// GOOD: Verifies through interface400test("createUser makes user retrievable", async () => {401 const user = await createUser({ name: "Alice" });402 const retrieved = await getUser(user.id);403 expect(retrieved.name).toBe("Alice");404});405```406407## Clean Test Heuristics (Uncle Bob, Ch 17)408409Apply these specific heuristics to maintain a high-quality suite:410411- **T1: Insufficient Tests**: A test suite should test everything that could possibly break. Don't stop at "it seems to work."412- **T4: Ignored Tests**: Never ignore a test without documenting the ambiguity. An ignored test is a silent warning of a gap in understanding.413- **T5: Test Boundary Conditions**: Most bugs happen at the edges. Test the exact boundaries (e.g., empty strings, max integers, off-by-one indices).414- **T6: Exhaustively Test Near Bugs**: Bugs congregate. If you find one, there are likely others nearby; test that area thoroughly.415- **T9: Tests Should Be Fast**: Slow tests don't get run. Keep them fast so they remain part of the core developer loop.416
Also in danielvm-git/bigpowers
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| danielvm-git/bigpowers.cursor/rules/align-grid.mdc · 119 | Cursor rules | lint-formatdo-notagent-behaviour | 65/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/assess-impact.mdc · 119 | Cursor rules | testtesting-strategydeployment | 66/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/audit-code.mdc · 119 | Cursor rules | setuptestlint-formatstyle+4 | 66/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/audit-plan.mdc · 119 | Cursor rules | buildteststylegit | 74/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/build-epic.mdc · 119 | Cursor rules | buildgit | 58/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/change-request.mdc · 119 | Cursor rules | no sections | 48/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/commit-message.mdc · 119 | Cursor rules | lint-formatstyletypesgit+3 | 82/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/compose-workflow.mdc · 119 | Cursor rules | styledo-notagent-behaviour | 65/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/context7-mcp.mdc · 119 | Cursor rules | style | 54/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/deepen-architecture.mdc · 119 | Cursor rules | testtesting-strategydo-not | 57/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/define-language.mdc · 119 | Cursor rules | lint-formatdo-not | 65/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/delegate-task.mdc · 119 | Cursor rules | git | 62/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/deploy.mdc · 119 | Cursor rules | setupbuildtestdeployment | 77/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/diagnose-root.mdc · 119 | Cursor rules | no sections | 39/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/dispatch-agents.mdc · 119 | Cursor rules | git | 54/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/edit-document.mdc · 119 | Cursor rules | no sections | 39/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/elaborate-spec.mdc · 119 | Cursor rules | test | 58/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/enforce-first.mdc · 119 | Cursor rules | no sections | 50/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/evolve-skill.mdc · 119 | Cursor rules | no sections | 50/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/execute-plan.mdc · 119 | Cursor rules | do-not | 51/100 | 3 days ago |
Diff against .cursor/rules/align-grid.mdc Diff against .cursor/rules/assess-impact.mdc Diff against .cursor/rules/audit-code.mdc Diff against .cursor/rules/audit-plan.mdc Diff against .cursor/rules/build-epic.mdc Diff against .cursor/rules/change-request.mdc Diff against .cursor/rules/commit-message.mdc Diff against .cursor/rules/compose-workflow.mdc Diff against .cursor/rules/context7-mcp.mdc Diff against .cursor/rules/deepen-architecture.mdc Diff against .cursor/rules/define-language.mdc Diff against .cursor/rules/delegate-task.mdc Diff against .cursor/rules/deploy.mdc Diff against .cursor/rules/diagnose-root.mdc Diff against .cursor/rules/dispatch-agents.mdc Diff against .cursor/rules/edit-document.mdc Diff against .cursor/rules/elaborate-spec.mdc Diff against .cursor/rules/enforce-first.mdc Diff against .cursor/rules/evolve-skill.mdc Diff against .cursor/rules/execute-plan.mdc
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 45 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 3 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 3 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 45 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 3 days ago |
