Windsurf rules
.windsurf/rules/develop-tdd.mdTest-driven development with red-green-refactor loop using vertical slices. Use for features (epic tasks) or bugs (specs/bugs/BUG-*.md).
Windsurf rules
Quality
85/100
Scores the file, not the repository.Length
2,141 words
32 headings · 14 code blocksRepository
114
— · pushed 0 days agoLast changed
3 days ago
First indexed 3 days ago.1234567# Develop TDD89> **HARD GATE** — Do NOT proceed if on `main` or `master`. Run `kickoff-branch` first to create a feature branch or worktree.10>11> **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).12>13> **RECURSIVE DISCIPLINE** — This lifecycle applies to EVERY task, including updating these skills. Never skip planning because a task is "meta" or "just documentation."1415## Philosophy1617Tests 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.1819## Red Flags2021If you catch yourself thinking these, stop and reconsider — you are likely deviating from production-grade craft.2223| Red Flag | Reality |24| :--- | :--- |25| "This is too simple to need tests." | Simple code is where bugs hide. If it's simple, the test is cheap. |26| "I'll refactor this later." | "Later" is when technical debt becomes bankruptcy. Refactor while Green. |27| "The tests are already comprehensive." | If you're adding behavior, you need a new test. Coverage ≠ Correctness. |28| "I'm just fixing a small bug." | Small bugs often indicate deep interface flaws. Investigate root cause. |29| "I need to mock this internal class." | Mocking internals couples tests to implementation. Mock only I/O. |30| "This refactor is out of scope." | Leave the code cleaner than you found it (Boy Scout Rule). |31| "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. |32| "I'll note the red gate and continue." | Narrating a failure is banned. fix-or-log is mandatory per CONVENTIONS § Discovered Defects. |3334## Workflow3536> **Timing:** `bash scripts/bp-timing.sh start develop-tdd` at invocation; `bash scripts/bp-timing.sh end develop-tdd` before handoff.3738### 1. Planning3940- [ ] Read active `specs/epics/*/epic.yaml` story tasks or `specs/bugs/BUG-*.md` — understand verify steps41- [ ] 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.42- [ ] Confirm interface changes and behaviors to test (prioritize)43- [ ] Design interfaces for testability — identify [deep modules](deep-modules.md) opportunities44- [ ] Get user approval on the plan4546Apply the **enforce-first** F.I.R.S.T rubric: Fast, Independent, Repeatable, Self-Validating, Timely.4748### 2. Tracer Bullet4950Write ONE test that confirms ONE thing about the system:5152```53RED: Write test for first behavior → test fails → commit: test(<scope>): ... (test-only; red in CI)54GREEN: Write minimal code to pass → test passes → commit: feat(<scope>): ... (fix commit; green)55REFACTOR (optional): clean up → commit: refactor(<scope>): ...56```5758> **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:5960```bash61bash scripts/verify-tdd-red-commit.sh62```6364Show `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.6566> **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.6768### 3. Incremental Loop6970> **Snapshot-before-transition (e45s34):** Before each RED → GREEN or GREEN → REFACTOR transition, create a checkpoint so a failed transition can be rolled back cleanly:7172```bash73bash scripts/bp-yaml-snapshot.sh specs/state.yaml # if state changed this cycle74git stash push -m "tdd-checkpoint-$(git rev-parse --short HEAD)-red" --keep-index 2>/dev/null || true75```7677After GREEN passes and is committed, drop the stash (`git stash drop` if empty). Never refactor while RED.7879For 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.8081### 4. Visual Slices (UI alternate workflow)8283For 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.8485### 5. Refactor8687After all tests pass: extract duplication, deepen modules, apply SOLID principles. **Never refactor while RED.**8889### 6. Verify9091After every behavior cycle, run the verify command from the active epic task. Show evidence before declaring the step done.9293### 7. Manual Verification Handover9495Once 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.969798### 6a. CI dry-run sub-step99100If this cycle modified files in `.github/workflows/`, run the CI dry-run procedure documented in [REFERENCE.md](REFERENCE.md#ci-dry-run).101102## Checklist Per Cycle103104```105[ ] Test describes behavior, not implementation106[ ] No test is ignored without an explicit ambiguity note (T4)107[ ] Boundary conditions tested: empty, max, min, off-by-one (T5)108[ ] Tests verify behavior through public interface only — no private methods (T8)109[ ] Test would survive internal refactor110[ ] Code is minimal for this test111[ ] No speculative features added112[ ] Every new abstraction has an explicit "Reason for Depth" justification113[ ] Progress committed (Conventional Commits)114[ ] verify: command passes115```116117118119## Handoff120121Gate: READY -> next: verify-work122Writes: state.yaml handoff.next_skill = verify-work123124## BCP Plus Integration125126At 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.127128## Verify129130→ 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`131132133<!-- story: e02s04 -->134135---136137# Develop TDD — Reference138139## Anti-Pattern: Horizontal Slices140141**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."142143This produces **crap tests**:144- Tests written in bulk test _imagined_ behavior, not _actual_ behavior145- You end up testing the _shape_ of things rather than user-facing behavior146- Tests become insensitive to real changes147148**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat.149150```151WRONG (horizontal):152 RED: test1, test2, test3, test4, test5153 GREEN: impl1, impl2, impl3, impl4, impl5154155RIGHT (vertical):156 RED→GREEN: test1→impl1157 RED→GREEN: test2→impl2158 RED→GREEN: test3→impl3159 ...160```161162> The Red Flags table lives in [SKILL.md](SKILL.md#red-flags) — it is core behavioral guidance, not reference detail.163164## TDD Phases (Detail)165166### Red Phase167168Write a failing test first:169- Test describes the desired observable behavior through the public interface170- Run the test to confirm it fails for the right reason (not a syntax error, not a typo)171- Commit: `git commit -m "test(<scope>): <description>"`172173### Green Phase174175Write the minimum code to make the test pass:176- No extra logic, no anticipated future cases, no premature optimization177- Focus only on making the current test pass178- Commit: `git commit -m "feat(<scope>): <description>"` or `"fix(<scope>): <description>"`179180### Refactor Phase181182Improve structure without changing behavior:183- Extract duplication, apply SOLID principles where natural, deepen modules184- Run tests after each refactor step to ensure behavior is preserved185- Commit: `git commit -m "refactor(<scope>): <description>"`186- Apply the Boy Scout Rule: leave the code cleaner than you found it187188## Visual Slices (UI Alternate Workflow)189190For UI components (SwiftUI, React, Flutter) where behavioral unit testing is brittle or low-signal:1911921. **Test-First Logic**: Extract logic (state transitions, formatting, validation) into a Controller, ViewModel, or Hook. This logic MUST follow pure TDD.1932. **Visual Verification**: For the View/Component itself:194 - **RED**: Write the component signature and a basic preview/snapshot that fails (or displays placeholder).195 - **GREEN**: Implement the UI and verify visually via manual run, preview, or snapshot test.196 - **REFINE**: Adjust styling and layout until it matches the design.1973. **COMMIT**: `git commit -m "feat(ui): <component name> visual slice verified"`198199---200201# Deep Modules202203From "A Philosophy of Software Design":204205**Deep module** = small interface + lots of implementation206207```208┌─────────────────────┐209│ Small Interface │ ← Few methods, simple params210├─────────────────────┤211│ │212│ │213│ Deep Implementation│ ← Complex logic hidden214│ │215│ │216└─────────────────────┘217```218219**Shallow module** = large interface + little implementation (avoid)220221```222┌─────────────────────────────────┐223│ Large Interface │ ← Many methods, complex params224├─────────────────────────────────┤225│ Thin Implementation │ ← Just passes through226└─────────────────────────────────┘227```228229When designing interfaces, ask:230231- Can I reduce the number of methods?232- Can I simplify the parameters?233- Can I hide more complexity inside?234235---236237# Interface Design for Testability238239Good interfaces make testing natural:2402411. **Accept dependencies, don't create them**242243```typescript244 // Testable245 function processOrder(order, paymentGateway) {}246247 // Hard to test248 function processOrder(order) {249 const gateway = new StripeGateway();250 }251```2522532. **Return results, don't produce side effects**254255```typescript256 // Testable257 function calculateDiscount(cart): Discount {}258259 // Hard to test260 function applyDiscount(cart): void {261 cart.total -= discount;262 }263```2642653. **Small surface area**266 - Fewer methods = fewer tests needed267 - Fewer params = simpler test setup268269---270271# When to Mock272273Mock at **system boundaries** only:274275- External APIs (payment, email, etc.)276- Databases (sometimes - prefer test DB)277- Time/randomness278- File system (sometimes)279280Don't mock:281282- Your own classes/modules283- Internal collaborators284- Anything you control285286## Designing for Mockability287288At system boundaries, design interfaces that are easy to mock:289290**1. Use dependency injection**291292Pass external dependencies in rather than creating them internally:293294```typescript295// Easy to mock296function processPayment(order, paymentClient) {297 return paymentClient.charge(order.total);298}299300// Hard to mock301function processPayment(order) {302 const client = new StripeClient(process.env.STRIPE_KEY);303 return client.charge(order.total);304}305```306307**2. Prefer SDK-style interfaces over generic fetchers**308309Create specific functions for each external operation instead of one generic function with conditional logic:310311```typescript312// GOOD: Each function is independently mockable313const api = {314 getUser: (id) => fetch(`/users/${id}`),315 getOrders: (userId) => fetch(`/users/${userId}/orders`),316 createOrder: (data) => fetch('/orders', { method: 'POST', body: data }),317};318319// BAD: Mocking requires conditional logic inside the mock320const api = {321 fetch: (endpoint, options) => fetch(endpoint, options),322};323```324325The SDK approach means:326- Each mock returns one specific shape327- No conditional logic in test setup328- Easier to see which endpoints a test exercises329- Type safety per endpoint330331---332333# Refactor Candidates334335After TDD cycle, look for:336337- **Duplication** → Extract function/class338- **Long methods** → Break into private helpers (keep tests on public interface)339- **Shallow modules** → Combine or deepen340- **Feature envy** → Move logic to where data lives341- **Primitive obsession** → Introduce value objects342- **Existing code** the new code reveals as problematic343344---345346# Good and Bad Tests347348## Good Tests349350**Integration-style**: Test through real interfaces, not mocks of internal parts.351352```typescript353// GOOD: Tests observable behavior354test("user can checkout with valid cart", async () => {355 const cart = createCart();356 cart.add(product);357 const result = await checkout(cart, paymentMethod);358 expect(result.status).toBe("confirmed");359});360```361362Characteristics:363364- Tests behavior users/callers care about365- Uses public API only366- Survives internal refactors367- Describes WHAT, not HOW368- One logical assertion per test369370## Bad Tests371372**Implementation-detail tests**: Coupled to internal structure.373374```typescript375// BAD: Tests implementation details376test("checkout calls paymentService.process", async () => {377 const mockPayment = jest.mock(paymentService);378 await checkout(cart, payment);379 expect(mockPayment.process).toHaveBeenCalledWith(cart.total);380});381```382383Red flags:384385- Mocking internal collaborators386- Testing private methods387- Asserting on call counts/order388- Test breaks when refactoring without behavior change389- Test name describes HOW not WHAT390- Verifying through external means instead of interface391392```typescript393// BAD: Bypasses interface to verify394test("createUser saves to database", async () => {395 await createUser({ name: "Alice" });396 const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);397 expect(row).toBeDefined();398});399400// GOOD: Verifies through interface401test("createUser makes user retrievable", async () => {402 const user = await createUser({ name: "Alice" });403 const retrieved = await getUser(user.id);404 expect(retrieved.name).toBe("Alice");405});406```407408## Clean Test Heuristics (Uncle Bob, Ch 17)409410Apply these specific heuristics to maintain a high-quality suite:411412- **T1: Insufficient Tests**: A test suite should test everything that could possibly break. Don't stop at "it seems to work."413- **T4: Ignored Tests**: Never ignore a test without documenting the ambiguity. An ignored test is a silent warning of a gap in understanding.414- **T5: Test Boundary Conditions**: Most bugs happen at the edges. Test the exact boundaries (e.g., empty strings, max integers, off-by-one indices).415- **T6: Exhaustively Test Near Bugs**: Bugs congregate. If you find one, there are likely others nearby; test that area thoroughly.416- **T9: Tests Should Be Fast**: Slow tests don't get run. Keep them fast so they remain part of the core developer loop.417
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 · 114 | Cursor rules | lint-formatdo-notagent-behaviour | 65/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/assess-impact.mdc · 114 | Cursor rules | testtesting-strategydeployment | 66/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/audit-code.mdc · 114 | Cursor rules | setuptestlint-formatstyle+4 | 66/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/audit-plan.mdc · 114 | Cursor rules | buildteststylegit | 74/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/build-epic.mdc · 114 | Cursor rules | buildgit | 58/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/change-request.mdc · 114 | Cursor rules | no sections | 48/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/commit-message.mdc · 114 | Cursor rules | lint-formatstyletypesgit+3 | 82/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/compose-workflow.mdc · 114 | Cursor rules | styledo-notagent-behaviour | 65/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/context7-mcp.mdc · 114 | Cursor rules | style | 54/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/craft-skill.mdc · 114 | Cursor rules | stylearchgitdo-not | 69/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/deepen-architecture.mdc · 114 | Cursor rules | testtesting-strategydo-not | 57/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/define-language.mdc · 114 | Cursor rules | lint-formatdo-not | 65/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/define-success.mdc · 114 | Cursor rules | no sections | 4/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/delegate-task.mdc · 114 | Cursor rules | git | 62/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/deploy.mdc · 114 | Cursor rules | setupbuildtestdeployment | 77/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/design-interface.mdc · 114 | Cursor rules | styleagent-behaviour | 58/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/develop-tdd.mdc · 114 | Cursor rules | teststylearchtesting-strategy+5 | 85/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/diagnose-root.mdc · 114 | Cursor rules | no sections | 39/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/diagnose-stall.mdc · 114 | Cursor rules | no sections | 44/100 | 3 days ago | |
| danielvm-git/bigpowers.cursor/rules/dispatch-agents.mdc · 114 | Cursor rules | git | 54/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/craft-skill.mdc Diff against .cursor/rules/deepen-architecture.mdc Diff against .cursor/rules/define-language.mdc Diff against .cursor/rules/define-success.mdc Diff against .cursor/rules/delegate-task.mdc Diff against .cursor/rules/deploy.mdc Diff against .cursor/rules/design-interface.mdc Diff against .cursor/rules/develop-tdd.mdc Diff against .cursor/rules/diagnose-root.mdc Diff against .cursor/rules/diagnose-stall.mdc Diff against .cursor/rules/dispatch-agents.mdc
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| danielvm-git/bigpowers.windsurf/rules/organize-workspace.md · 114 | Windsurf rules | buildstylegitdeployment+2 | 89/100 | 3 days ago | |
| danielvm-git/bigpowers.windsurf/rules/guard-git.md · 114 | Windsurf rules | stylearchgitsecurity+2 | 89/100 | 3 days ago | |
| danielvm-git/bigpowers.windsurf/rules/quick-fix.md · 114 | Windsurf rules | teststylegitdeployment+1 | 85/100 | 3 days ago | |
| danielvm-git/bigpowers.windsurf/rules/session-state.md · 114 | Windsurf rules | lint-formatstyleagent-behaviour | 82/100 | 3 days ago | |
| danielvm-git/bigpowers.windsurf/rules/extract-design.md · 114 | Windsurf rules | lint-formatstyledependenciesui | 82/100 | 3 days ago | |
| danielvm-git/bigpowers.windsurf/rules/commit-message.md · 114 | Windsurf rules | lint-formatstyletypesgit+3 | 82/100 | 3 days ago | |
| danielvm-git/bigpowers.windsurf/rules/setup-environment.md · 114 | Windsurf rules | setupstylesecuritydo-not+1 | 81/100 | 3 days ago | |
| danielvm-git/bigpowers.windsurf/rules/wire-ci.md · 114 | Windsurf rules | buildtestlint-formatstyle+1 | 81/100 | 3 days ago |
