[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71JF25VDMPWAPVVRFE6ADHB":3,"skill-same:01M71JF25VDMPWAPVVRFE6ADHB":98},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":49,"commitSha":50,"skillDirectory":51,"forksCount":52,"repositoryHtmlUrl":53,"repositoryHomepageUrl":54,"ownerHtmlUrl":55,"ownerBlogUrl":56,"ownerDescription":6,"updatedAt":57,"install":58,"resources":71},"01M71JF25VDMPWAPVVRFE6ADHB","develop-tdd",null,"Test-driven development with red-green-refactor loop using vertical slices. Use for features (epic tasks) or bugs (specs\u002Fbugs\u002FBUG-*.md).","danielvm-git\u002Fbigpowers","danielvm-git","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1020864?v=4","01M71H1N1CTQ529S0KN7KETVG6","Daniel V M","01M71H1N218Y3S8WHCJ58NPRSW",289,"MIT","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002F.pi\u002Fskills\u002Fdevelop-tdd\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000007","代码审查","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"develop","tdd","develop tdd","test","with","EPIC","use","for","development","bugs","sonnet","refactor","refactor loop","bug","features","tasks","loop","red-green-refactor","green","test-driven","2026-11-10 10:12:30",false,"---\nname: develop-tdd\nmodel: sonnet\ndescription: \"Test-driven development with red-green-refactor loop using vertical slices. Use for features (epic tasks) or bugs (specs\u002Fbugs\u002FBUG-*.md).\"\n---\n\n# Develop TDD\n\n> **HARD GATE** — Do NOT proceed if on `main` or `master`. Run `kickoff-branch` first to create a feature branch or worktree.\n>\n> **HARD GATE** — Do NOT write code before you have a plan. New feature: `plan-work` → epic capsule tasks. Bug: `investigate-bug` → `specs\u002Fbugs\u002FBUG-*.md` (or use `fix-bug` orchestrator).\n>\n> **RECURSIVE DISCIPLINE** — This lifecycle applies to EVERY task, including updating these skills. Never skip planning because a task is \"meta\" or \"just documentation.\"\n\n## Philosophy\n\nTests verify behavior through public interfaces, not implementation details. A good test reads like a specification. See [REFERENCE.md](..\u002F..\u002F..\u002Fskills\u002Fdevelop-tdd\u002FREFERENCE.md) for the horizontal-slice anti-pattern and TDD phase detail.\n\n## Red Flags\n\nIf you catch yourself thinking these, stop and reconsider — you are likely deviating from production-grade craft.\n\n| Red Flag | Reality |\n| :--- | :--- |\n| \"This is too simple to need tests.\" | Simple code is where bugs hide. If it's simple, the test is cheap. |\n| \"I'll refactor this later.\" | \"Later\" is when technical debt becomes bankruptcy. Refactor while Green. |\n| \"The tests are already comprehensive.\" | If you're adding behavior, you need a new test. Coverage ≠ Correctness. |\n| \"I'm just fixing a small bug.\" | Small bugs often indicate deep interface flaws. Investigate root cause. |\n| \"I need to mock this internal class.\" | Mocking internals couples tests to implementation. Mock only I\u002FO. |\n| \"This refactor is out of scope.\" | Leave the code cleaner than you found it (Boy Scout Rule). |\n| \"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. |\n| \"I'll note the red gate and continue.\" | Narrating a failure is banned. fix-or-log is mandatory per CONVENTIONS § Discovered Defects. |\n\n## Workflow\n\n> **Timing:** `bash scripts\u002Fbp-timing.sh start develop-tdd` at invocation; `bash scripts\u002Fbp-timing.sh end develop-tdd` before handoff.\n\n### 1. Planning\n\n- [ ] Read active `specs\u002Fepics\u002F*\u002Fepic.yaml` story tasks or `specs\u002Fbugs\u002FBUG-*.md` — understand verify steps\n- [ ] If `specs\u002Ftech-architecture\u002FeNN-TEST_PLAN_LATEST.md` exists for the active epic, read it before writing the first test. Implement P0 scenarios (`SC-*-P0-*`) before P1. P2\u002FP3 scenarios are optional per time budget.\n- [ ] Confirm interface changes and behaviors to test (prioritize)\n- [ ] Design interfaces for testability — identify [deep modules](..\u002F..\u002F..\u002Fskills\u002Fdevelop-tdd\u002Fdeep-modules.md) opportunities\n- [ ] Get user approval on the plan\n\nApply the **enforce-first** F.I.R.S.T rubric: Fast, Independent, Repeatable, Self-Validating, Timely.\n\n### 2. Tracer Bullet\n\nWrite ONE test that confirms ONE thing about the system:\n\n```\nRED:    Write test for first behavior → test fails → commit: test(\u003Cscope>): ...  (test-only; red in CI)\nGREEN:  Write minimal code to pass → test passes → commit: feat(\u003Cscope>): ...   (fix commit; green)\nREFACTOR (optional): clean up → commit: refactor(\u003Cscope>): ...\n```\n\n> **Two-commit red\u002Fgreen 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:\n\n```bash\nbash scripts\u002Fverify-tdd-red-commit.sh\n```\n\nShow `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.\n\n> **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.\n\n### 3. Incremental Loop\n\n> **Snapshot-before-transition (e45s34):** Before each RED → GREEN or GREEN → REFACTOR transition, create a checkpoint so a failed transition can be rolled back cleanly:\n\n```bash\nbash scripts\u002Fbp-yaml-snapshot.sh specs\u002Fstate.yaml   # if state changed this cycle\ngit stash push -m \"tdd-checkpoint-$(git rev-parse --short HEAD)-red\" --keep-index 2>\u002Fdev\u002Fnull || true\n```\n\nAfter GREEN passes and is committed, drop the stash (`git stash drop` if empty). Never refactor while RED.\n\nFor 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.\n\n### 4. Visual Slices (UI alternate workflow)\n\nFor UI components where behavioral unit testing is brittle: extract logic into a Controller\u002FViewModel\u002FHook (pure TDD), then use Visual Slices for the View layer. See [REFERENCE.md](..\u002F..\u002F..\u002Fskills\u002Fdevelop-tdd\u002FREFERENCE.md) for the full Visual Slices procedure.\n\n### 5. Refactor\n\nAfter all tests pass: extract duplication, deepen modules, apply SOLID principles. **Never refactor while RED.**\n\n### 6. Verify\n\nAfter every behavior cycle, run the verify command from the active epic task. Show evidence before declaring the step done.\n\n### 7. Manual Verification Handover\n\nOnce 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.\n\n\n### 6a. CI dry-run sub-step\n\nIf this cycle modified files in `.github\u002Fworkflows\u002F`, run the CI dry-run procedure documented in [REFERENCE.md](..\u002F..\u002F..\u002Fskills\u002Fdevelop-tdd\u002FREFERENCE.md#ci-dry-run).\n\n## Checklist Per Cycle\n\n```\n[ ] Test describes behavior, not implementation\n[ ] No test is ignored without an explicit ambiguity note (T4)\n[ ] Boundary conditions tested: empty, max, min, off-by-one (T5)\n[ ] Tests verify behavior through public interface only — no private methods (T8)\n[ ] Test would survive internal refactor\n[ ] Code is minimal for this test\n[ ] No speculative features added\n[ ] Every new abstraction has an explicit \"Reason for Depth\" justification\n[ ] Progress committed (Conventional Commits)\n[ ] verify: command passes\n```\n\n\n\n## Handoff\n\nGate: READY -> next: verify-work\nWrites: state.yaml handoff.next_skill = verify-work\n\n## BCP Plus Integration\n\nAt 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\u002Freferences\u002Fbcp-plus.md` for the full methodology and NFR Gate pattern.\n\n## Verify\n\n→ verify: `test -x scripts\u002Fverify-tdd-red-commit.sh && bash scripts\u002Fverify-tdd-red-commit.sh --self-test && grep -q 'verify-tdd-red-commit' skills\u002Fdevelop-tdd\u002FSKILL.md && echo OK`\n\n\n\u003C!-- story: e02s04 -->\n\n---\n\n# Develop TDD — Reference\n\n## Anti-Pattern: Horizontal Slices\n\n**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.\"\n\nThis produces **crap tests**:\n- Tests written in bulk test _imagined_ behavior, not _actual_ behavior\n- You end up testing the _shape_ of things rather than user-facing behavior\n- Tests become insensitive to real changes\n\n**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat.\n\n```\nWRONG (horizontal):\n  RED:   test1, test2, test3, test4, test5\n  GREEN: impl1, impl2, impl3, impl4, impl5\n\nRIGHT (vertical):\n  RED→GREEN: test1→impl1\n  RED→GREEN: test2→impl2\n  RED→GREEN: test3→impl3\n  ...\n```\n\n> The Red Flags table lives in [SKILL.md](..\u002F..\u002F..\u002Fskills\u002Fdevelop-tdd\u002FSKILL.md#red-flags) — it is core behavioral guidance, not reference detail.\n\n## TDD Phases (Detail)\n\n### Red Phase\n\nWrite a failing test first:\n- Test describes the desired observable behavior through the public interface\n- Run the test to confirm it fails for the right reason (not a syntax error, not a typo)\n- Commit: `git commit -m \"test(\u003Cscope>): \u003Cdescription>\"`\n\n### Green Phase\n\nWrite the minimum code to make the test pass:\n- No extra logic, no anticipated future cases, no premature optimization\n- Focus only on making the current test pass\n- Commit: `git commit -m \"feat(\u003Cscope>): \u003Cdescription>\"` or `\"fix(\u003Cscope>): \u003Cdescription>\"`\n\n### Refactor Phase\n\nImprove structure without changing behavior:\n- Extract duplication, apply SOLID principles where natural, deepen modules\n- Run tests after each refactor step to ensure behavior is preserved\n- Commit: `git commit -m \"refactor(\u003Cscope>): \u003Cdescription>\"`\n- Apply the Boy Scout Rule: leave the code cleaner than you found it\n\n## Visual Slices (UI Alternate Workflow)\n\nFor UI components (SwiftUI, React, Flutter) where behavioral unit testing is brittle or low-signal:\n\n1. **Test-First Logic**: Extract logic (state transitions, formatting, validation) into a Controller, ViewModel, or Hook. This logic MUST follow pure TDD.\n2. **Visual Verification**: For the View\u002FComponent itself:\n   - **RED**: Write the component signature and a basic preview\u002Fsnapshot that fails (or displays placeholder).\n   - **GREEN**: Implement the UI and verify visually via manual run, preview, or snapshot test.\n   - **REFINE**: Adjust styling and layout until it matches the design.\n3. **COMMIT**: `git commit -m \"feat(ui): \u003Ccomponent name> visual slice verified\"`\n\n---\n\n# Deep Modules\n\nFrom \"A Philosophy of Software Design\":\n\n**Deep module** = small interface + lots of implementation\n\n```\n┌─────────────────────┐\n│   Small Interface   │  ← Few methods, simple params\n├─────────────────────┤\n│                     │\n│                     │\n│  Deep Implementation│  ← Complex logic hidden\n│                     │\n│                     │\n└─────────────────────┘\n```\n\n**Shallow module** = large interface + little implementation (avoid)\n\n```\n┌─────────────────────────────────┐\n│       Large Interface           │  ← Many methods, complex params\n├─────────────────────────────────┤\n│  Thin Implementation            │  ← Just passes through\n└─────────────────────────────────┘\n```\n\nWhen designing interfaces, ask:\n\n- Can I reduce the number of methods?\n- Can I simplify the parameters?\n- Can I hide more complexity inside?\n\n---\n\n# Interface Design for Testability\n\nGood interfaces make testing natural:\n\n1. **Accept dependencies, don't create them**\n\n   ```typescript\n   \u002F\u002F Testable\n   function processOrder(order, paymentGateway) {}\n\n   \u002F\u002F Hard to test\n   function processOrder(order) {\n     const gateway = new StripeGateway();\n   }\n   ```\n\n2. **Return results, don't produce side effects**\n\n   ```typescript\n   \u002F\u002F Testable\n   function calculateDiscount(cart): Discount {}\n\n   \u002F\u002F Hard to test\n   function applyDiscount(cart): void {\n     cart.total -= discount;\n   }\n   ```\n\n3. **Small surface area**\n   - Fewer methods = fewer tests needed\n   - Fewer params = simpler test setup\n\n---\n\n# When to Mock\n\nMock at **system boundaries** only:\n\n- External APIs (payment, email, etc.)\n- Databases (sometimes - prefer test DB)\n- Time\u002Frandomness\n- File system (sometimes)\n\nDon't mock:\n\n- Your own classes\u002Fmodules\n- Internal collaborators\n- Anything you control\n\n## Designing for Mockability\n\nAt system boundaries, design interfaces that are easy to mock:\n\n**1. Use dependency injection**\n\nPass external dependencies in rather than creating them internally:\n\n```typescript\n\u002F\u002F Easy to mock\nfunction processPayment(order, paymentClient) {\n  return paymentClient.charge(order.total);\n}\n\n\u002F\u002F Hard to mock\nfunction processPayment(order) {\n  const client = new StripeClient(process.env.STRIPE_KEY);\n  return client.charge(order.total);\n}\n```\n\n**2. Prefer SDK-style interfaces over generic fetchers**\n\nCreate specific functions for each external operation instead of one generic function with conditional logic:\n\n```typescript\n\u002F\u002F GOOD: Each function is independently mockable\nconst api = {\n  getUser: (id) => fetch(`\u002Fusers\u002F${id}`),\n  getOrders: (userId) => fetch(`\u002Fusers\u002F${userId}\u002Forders`),\n  createOrder: (data) => fetch('\u002Forders', { method: 'POST', body: data }),\n};\n\n\u002F\u002F BAD: Mocking requires conditional logic inside the mock\nconst api = {\n  fetch: (endpoint, options) => fetch(endpoint, options),\n};\n```\n\nThe SDK approach means:\n- Each mock returns one specific shape\n- No conditional logic in test setup\n- Easier to see which endpoints a test exercises\n- Type safety per endpoint\n\n---\n\n# Refactor Candidates\n\nAfter TDD cycle, look for:\n\n- **Duplication** → Extract function\u002Fclass\n- **Long methods** → Break into private helpers (keep tests on public interface)\n- **Shallow modules** → Combine or deepen\n- **Feature envy** → Move logic to where data lives\n- **Primitive obsession** → Introduce value objects\n- **Existing code** the new code reveals as problematic\n\n---\n\n# Good and Bad Tests\n\n## Good Tests\n\n**Integration-style**: Test through real interfaces, not mocks of internal parts.\n\n```typescript\n\u002F\u002F GOOD: Tests observable behavior\ntest(\"user can checkout with valid cart\", async () => {\n  const cart = createCart();\n  cart.add(product);\n  const result = await checkout(cart, paymentMethod);\n  expect(result.status).toBe(\"confirmed\");\n});\n```\n\nCharacteristics:\n\n- Tests behavior users\u002Fcallers care about\n- Uses public API only\n- Survives internal refactors\n- Describes WHAT, not HOW\n- One logical assertion per test\n\n## Bad Tests\n\n**Implementation-detail tests**: Coupled to internal structure.\n\n```typescript\n\u002F\u002F BAD: Tests implementation details\ntest(\"checkout calls paymentService.process\", async () => {\n  const mockPayment = jest.mock(paymentService);\n  await checkout(cart, payment);\n  expect(mockPayment.process).toHaveBeenCalledWith(cart.total);\n});\n```\n\nRed flags:\n\n- Mocking internal collaborators\n- Testing private methods\n- Asserting on call counts\u002Forder\n- Test breaks when refactoring without behavior change\n- Test name describes HOW not WHAT\n- Verifying through external means instead of interface\n\n```typescript\n\u002F\u002F BAD: Bypasses interface to verify\ntest(\"createUser saves to database\", async () => {\n  await createUser({ name: \"Alice\" });\n  const row = await db.query(\"SELECT * FROM users WHERE name = ?\", [\"Alice\"]);\n  expect(row).toBeDefined();\n});\n\n\u002F\u002F GOOD: Verifies through interface\ntest(\"createUser makes user retrievable\", async () => {\n  const user = await createUser({ name: \"Alice\" });\n  const retrieved = await getUser(user.id);\n  expect(retrieved.name).toBe(\"Alice\");\n});\n```\n\n## Clean Test Heuristics (Uncle Bob, Ch 17)\n\nApply these specific heuristics to maintain a high-quality suite:\n\n- **T1: Insufficient Tests**: A test suite should test everything that could possibly break. Don't stop at \"it seems to work.\"\n- **T4: Ignored Tests**: Never ignore a test without documenting the ambiguity. An ignored test is a silent warning of a gap in understanding.\n- **T5: Test Boundary Conditions**: Most bugs happen at the edges. Test the exact boundaries (e.g., empty strings, max integers, off-by-one indices).\n- **T6: Exhaustively Test Near Bugs**: Bugs congregate. If you find one, there are likely others nearby; test that area thoroughly.\n- **T9: Tests Should Be Fast**: Slow tests don't get run. Keep them fast so they remain part of the core developer loop.\n","# Develop TDD\n\n> **HARD GATE** — Do NOT proceed if on `main` or `master`. Run `kickoff-branch` first to create a feature branch or worktree.\n>\n> **HARD GATE** — Do NOT write code before you have a plan. New feature: `plan-work` → epic capsule tasks. Bug: `investigate-bug` → `specs\u002Fbugs\u002FBUG-*.md` (or use `fix-bug` orchestrator).\n>\n> **RECURSIVE DISCIPLINE** — This lifecycle applies to EVERY task, including updating these skills. Never skip planning because a task is \"meta\" or \"just documentation.\"\n\n## Philosophy\n\nTests verify behavior through public interfaces, not implementation details. A good test reads like a specification. See [REFERENCE.md](..\u002F..\u002F..\u002Fskills\u002Fdevelop-tdd\u002FREFERENCE.md) for the horizontal-slice anti-pattern and TDD phase detail.\n\n## Red Flags\n\nIf you catch yourself thinking these, stop and reconsider — you are likely deviating from production-grade craft.\n\n| Red Flag | Reality |\n| :--- | :--- |\n| \"This is too simple to need tests.\" | Simple code is where bugs hide. If it's simple, the test is cheap. |\n| \"I'll refactor this later.\" | \"Later\" is when technical debt becomes bankruptcy. Refactor while Green. |\n| \"The tests are already comprehensive.\" | If you're adding behavior, you need a new test. Coverage ≠ Correctness. |\n| \"I'm just fixing a small bug.\" | Small bugs often indicate deep interface flaws. Investigate root cause. |\n| \"I need to mock this internal class.\" | Mocking internals couples tests to implementation. Mock only I\u002FO. |\n| \"This refactor is out of scope.\" | Leave the code cleaner than you found it (Boy Scout Rule). |\n| \"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. |\n| \"I'll note the red gate and continue.\" | Narrating a failure is banned. fix-or-log is mandatory per CONVENTIONS § Discovered Defects. |\n\n## Workflow\n\n> **Timing:** `bash scripts\u002Fbp-timing.sh start develop-tdd` at invocation; `bash scripts\u002Fbp-timing.sh end develop-tdd` before handoff.\n\n### 1. Planning\n\n- [ ] Read active `specs\u002Fepics\u002F*\u002Fepic.yaml` story tasks or `specs\u002Fbugs\u002FBUG-*.md` — understand verify steps\n- [ ] If `specs\u002Ftech-architecture\u002FeNN-TEST_PLAN_LATEST.md` exists for the active epic, read it before writing the first test. Implement P0 scenarios (`SC-*-P0-*`) before P1. P2\u002FP3 scenarios are optional per time budget.\n- [ ] Confirm interface changes and behaviors to test (prioritize)\n- [ ] Design interfaces for testability — identify [deep modules](..\u002F..\u002F..\u002Fskills\u002Fdevelop-tdd\u002Fdeep-modules.md) opportunities\n- [ ] Get user approval on the plan\n\nApply the **enforce-first** F.I.R.S.T rubric: Fast, Independent, Repeatable, Self-Validating, Timely.\n\n### 2. Tracer Bullet\n\nWrite ONE test that confirms ONE thing about the system:\n\n```\nRED:    Write test for first behavior → test fails → commit: test(\u003Cscope>): ...  (test-only; red in CI)\nGREEN:  Write minimal code to pass → test passes → commit: feat(\u003Cscope>): ...   (fix commit; green)\nREFACTOR (optional): clean up → commit: refactor(\u003Cscope>): ...\n```\n\n> **Two-commit red\u002Fgreen 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:\n\n```bash\nbash scripts\u002Fverify-tdd-red-commit.sh\n```\n\nShow `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.\n\n> **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.\n\n### 3. Incremental Loop\n\n> **Snapshot-before-transition (e45s34):** Before each RED → GREEN or GREEN → REFACTOR transition, create a checkpoint so a failed transition can be rolled back cleanly:\n\n```bash\nbash scripts\u002Fbp-yaml-snapshot.sh specs\u002Fstate.yaml   # if state changed this cycle\ngit stash push -m \"tdd-checkpoint-$(git rev-parse --short HEAD)-red\" --keep-index 2>\u002Fdev\u002Fnull || true\n```\n\nAfter GREEN passes and is committed, drop the stash (`git stash drop` if empty). Never refactor while RED.\n\nFor 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.\n\n### 4. Visual Slices (UI alternate workflow)\n\nFor UI components where behavioral unit testing is brittle: extract logic into a Controller\u002FViewModel\u002FHook (pure TDD), then use Visual Slices for the View layer. See [REFERENCE.md](..\u002F..\u002F..\u002Fskills\u002Fdevelop-tdd\u002FREFERENCE.md) for the full Visual Slices procedure.\n\n### 5. Refactor\n\nAfter all tests pass: extract duplication, deepen modules, apply SOLID principles. **Never refactor while RED.**\n\n### 6. Verify\n\nAfter every behavior cycle, run the verify command from the active epic task. Show evidence before declaring the step done.\n\n### 7. Manual Verification Handover\n\nOnce 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.\n\n\n### 6a. CI dry-run sub-step\n\nIf this cycle modified files in `.github\u002Fworkflows\u002F`, run the CI dry-run procedure documented in [REFERENCE.md](..\u002F..\u002F..\u002Fskills\u002Fdevelop-tdd\u002FREFERENCE.md#ci-dry-run).\n\n## Checklist Per Cycle\n\n```\n[ ] Test describes behavior, not implementation\n[ ] No test is ignored without an explicit ambiguity note (T4)\n[ ] Boundary conditions tested: empty, max, min, off-by-one (T5)\n[ ] Tests verify behavior through public interface only — no private methods (T8)\n[ ] Test would survive internal refactor\n[ ] Code is minimal for this test\n[ ] No speculative features added\n[ ] Every new abstraction has an explicit \"Reason for Depth\" justification\n[ ] Progress committed (Conventional Commits)\n[ ] verify: command passes\n```\n\n\n\n## Handoff\n\nGate: READY -> next: verify-work\nWrites: state.yaml handoff.next_skill = verify-work\n\n## BCP Plus Integration\n\nAt 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\u002Freferences\u002Fbcp-plus.md` for the full methodology and NFR Gate pattern.\n\n## Verify\n\n→ verify: `test -x scripts\u002Fverify-tdd-red-commit.sh && bash scripts\u002Fverify-tdd-red-commit.sh --self-test && grep -q 'verify-tdd-red-commit' skills\u002Fdevelop-tdd\u002FSKILL.md && echo OK`\n\n\n\u003C!-- story: e02s04 -->\n\n---\n\n# Develop TDD — Reference\n\n## Anti-Pattern: Horizontal Slices\n\n**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.\"\n\nThis produces **crap tests**:\n- Tests written in bulk test _imagined_ behavior, not _actual_ behavior\n- You end up testing the _shape_ of things rather than user-facing behavior\n- Tests become insensitive to real changes\n\n**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat.\n\n```\nWRONG (horizontal):\n  RED:   test1, test2, test3, test4, test5\n  GREEN: impl1, impl2, impl3, impl4, impl5\n\nRIGHT (vertical):\n  RED→GREEN: test1→impl1\n  RED→GREEN: test2→impl2\n  RED→GREEN: test3→impl3\n  ...\n```\n\n> The Red Flags table lives in [SKILL.md](..\u002F..\u002F..\u002Fskills\u002Fdevelop-tdd\u002FSKILL.md#red-flags) — it is core behavioral guidance, not reference detail.\n\n## TDD Phases (Detail)\n\n### Red Phase\n\nWrite a failing test first:\n- Test describes the desired observable behavior through the public interface\n- Run the test to confirm it fails for the right reason (not a syntax error, not a typo)\n- Commit: `git commit -m \"test(\u003Cscope>): \u003Cdescription>\"`\n\n### Green Phase\n\nWrite the minimum code to make the test pass:\n- No extra logic, no anticipated future cases, no premature optimization\n- Focus only on making the current test pass\n- Commit: `git commit -m \"feat(\u003Cscope>): \u003Cdescription>\"` or `\"fix(\u003Cscope>): \u003Cdescription>\"`\n\n### Refactor Phase\n\nImprove structure without changing behavior:\n- Extract duplication, apply SOLID principles where natural, deepen modules\n- Run tests after each refactor step to ensure behavior is preserved\n- Commit: `git commit -m \"refactor(\u003Cscope>): \u003Cdescription>\"`\n- Apply the Boy Scout Rule: leave the code cleaner than you found it\n\n## Visual Slices (UI Alternate Workflow)\n\nFor UI components (SwiftUI, React, Flutter) where behavioral unit testing is brittle or low-signal:\n\n1. **Test-First Logic**: Extract logic (state transitions, formatting, validation) into a Controller, ViewModel, or Hook. This logic MUST follow pure TDD.\n2. **Visual Verification**: For the View\u002FComponent itself:\n   - **RED**: Write the component signature and a basic preview\u002Fsnapshot that fails (or displays placeholder).\n   - **GREEN**: Implement the UI and verify visually via manual run, preview, or snapshot test.\n   - **REFINE**: Adjust styling and layout until it matches the design.\n3. **COMMIT**: `git commit -m \"feat(ui): \u003Ccomponent name> visual slice verified\"`\n\n---\n\n# Deep Modules\n\nFrom \"A Philosophy of Software Design\":\n\n**Deep module** = small interface + lots of implementation\n\n```\n┌─────────────────────┐\n│   Small Interface   │  ← Few methods, simple params\n├─────────────────────┤\n│                     │\n│                     │\n│  Deep Implementation│  ← Complex logic hidden\n│                     │\n│                     │\n└─────────────────────┘\n```\n\n**Shallow module** = large interface + little implementation (avoid)\n\n```\n┌─────────────────────────────────┐\n│       Large Interface           │  ← Many methods, complex params\n├─────────────────────────────────┤\n│  Thin Implementation            │  ← Just passes through\n└─────────────────────────────────┘\n```\n\nWhen designing interfaces, ask:\n\n- Can I reduce the number of methods?\n- Can I simplify the parameters?\n- Can I hide more complexity inside?\n\n---\n\n# Interface Design for Testability\n\nGood interfaces make testing natural:\n\n1. **Accept dependencies, don't create them**\n\n   ```typescript\n   \u002F\u002F Testable\n   function processOrder(order, paymentGateway) {}\n\n   \u002F\u002F Hard to test\n   function processOrder(order) {\n     const gateway = new StripeGateway();\n   }\n   ```\n\n2. **Return results, don't produce side effects**\n\n   ```typescript\n   \u002F\u002F Testable\n   function calculateDiscount(cart): Discount {}\n\n   \u002F\u002F Hard to test\n   function applyDiscount(cart): void {\n     cart.total -= discount;\n   }\n   ```\n\n3. **Small surface area**\n   - Fewer methods = fewer tests needed\n   - Fewer params = simpler test setup\n\n---\n\n# When to Mock\n\nMock at **system boundaries** only:\n\n- External APIs (payment, email, etc.)\n- Databases (sometimes - prefer test DB)\n- Time\u002Frandomness\n- File system (sometimes)\n\nDon't mock:\n\n- Your own classes\u002Fmodules\n- Internal collaborators\n- Anything you control\n\n## Designing for Mockability\n\nAt system boundaries, design interfaces that are easy to mock:\n\n**1. Use dependency injection**\n\nPass external dependencies in rather than creating them internally:\n\n```typescript\n\u002F\u002F Easy to mock\nfunction processPayment(order, paymentClient) {\n  return paymentClient.charge(order.total);\n}\n\n\u002F\u002F Hard to mock\nfunction processPayment(order) {\n  const client = new StripeClient(process.env.STRIPE_KEY);\n  return client.charge(order.total);\n}\n```\n\n**2. Prefer SDK-style interfaces over generic fetchers**\n\nCreate specific functions for each external operation instead of one generic function with conditional logic:\n\n```typescript\n\u002F\u002F GOOD: Each function is independently mockable\nconst api = {\n  getUser: (id) => fetch(`\u002Fusers\u002F${id}`),\n  getOrders: (userId) => fetch(`\u002Fusers\u002F${userId}\u002Forders`),\n  createOrder: (data) => fetch('\u002Forders', { method: 'POST', body: data }),\n};\n\n\u002F\u002F BAD: Mocking requires conditional logic inside the mock\nconst api = {\n  fetch: (endpoint, options) => fetch(endpoint, options),\n};\n```\n\nThe SDK approach means:\n- Each mock returns one specific shape\n- No conditional logic in test setup\n- Easier to see which endpoints a test exercises\n- Type safety per endpoint\n\n---\n\n# Refactor Candidates\n\nAfter TDD cycle, look for:\n\n- **Duplication** → Extract function\u002Fclass\n- **Long methods** → Break into private helpers (keep tests on public interface)\n- **Shallow modules** → Combine or deepen\n- **Feature envy** → Move logic to where data lives\n- **Primitive obsession** → Introduce value objects\n- **Existing code** the new code reveals as problematic\n\n---\n\n# Good and Bad Tests\n\n## Good Tests\n\n**Integration-style**: Test through real interfaces, not mocks of internal parts.\n\n```typescript\n\u002F\u002F GOOD: Tests observable behavior\ntest(\"user can checkout with valid cart\", async () => {\n  const cart = createCart();\n  cart.add(product);\n  const result = await checkout(cart, paymentMethod);\n  expect(result.status).toBe(\"confirmed\");\n});\n```\n\nCharacteristics:\n\n- Tests behavior users\u002Fcallers care about\n- Uses public API only\n- Survives internal refactors\n- Describes WHAT, not HOW\n- One logical assertion per test\n\n## Bad Tests\n\n**Implementation-detail tests**: Coupled to internal structure.\n\n```typescript\n\u002F\u002F BAD: Tests implementation details\ntest(\"checkout calls paymentService.process\", async () => {\n  const mockPayment = jest.mock(paymentService);\n  await checkout(cart, payment);\n  expect(mockPayment.process).toHaveBeenCalledWith(cart.total);\n});\n```\n\nRed flags:\n\n- Mocking internal collaborators\n- Testing private methods\n- Asserting on call counts\u002Forder\n- Test breaks when refactoring without behavior change\n- Test name describes HOW not WHAT\n- Verifying through external means instead of interface\n\n```typescript\n\u002F\u002F BAD: Bypasses interface to verify\ntest(\"createUser saves to database\", async () => {\n  await createUser({ name: \"Alice\" });\n  const row = await db.query(\"SELECT * FROM users WHERE name = ?\", [\"Alice\"]);\n  expect(row).toBeDefined();\n});\n\n\u002F\u002F GOOD: Verifies through interface\ntest(\"createUser makes user retrievable\", async () => {\n  const user = await createUser({ name: \"Alice\" });\n  const retrieved = await getUser(user.id);\n  expect(retrieved.name).toBe(\"Alice\");\n});\n```\n\n## Clean Test Heuristics (Uncle Bob, Ch 17)\n\nApply these specific heuristics to maintain a high-quality suite:\n\n- **T1: Insufficient Tests**: A test suite should test everything that could possibly break. Don't stop at \"it seems to work.\"\n- **T4: Ignored Tests**: Never ignore a test without documenting the ambiguity. An ignored test is a silent warning of a gap in understanding.\n- **T5: Test Boundary Conditions**: Most bugs happen at the edges. Test the exact boundaries (e.g., empty strings, max integers, off-by-one indices).\n- **T6: Exhaustively Test Near Bugs**: Bugs congregate. If you find one, there are likely others nearby; test that area thoroughly.\n- **T9: Tests Should Be Fast**: Slow tests don't get run. Keep them fast so they remain part of the core developer loop.\n",{"name":5,"model":34,"description":7},"main","72f5e4c8b43f60cf86b37078ad8cd7e22daf67aa",".pi\u002Fskills\u002Fdevelop-tdd",24,"https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers","https:\u002F\u002Fdanielvm-git.github.io\u002Fbigpowers\u002F","https:\u002F\u002Fgithub.com\u002Fdanielvm-git","danielvm.net","2026-11-10 01:18:54",{"source":8,"skillName":5,"commands":59,"prompt":69,"zipAvailable":70},[60,63,66],{"tool":61,"command":62},"npx","npx skills add danielvm-git\u002Fbigpowers --skill develop-tdd",{"tool":64,"command":65},"bunx","bunx skills add danielvm-git\u002Fbigpowers --skill develop-tdd",{"tool":67,"command":68},"pnpm","pnpm dlx skills add danielvm-git\u002Fbigpowers --skill develop-tdd","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002F.pi\u002Fskills\u002Fdevelop-tdd\u002FSKILL.md",true,[72,78,82,86,90,94],{"path":73,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":76,"sourceHtmlUrl":77},"deep-modules.md","REFERENCE","参考文档",1239,"https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002F.pi\u002Fskills\u002Fdevelop-tdd\u002Fdeep-modules.md",{"path":79,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":80,"sourceHtmlUrl":81},"interface-design.md",653,"https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002F.pi\u002Fskills\u002Fdevelop-tdd\u002Finterface-design.md",{"path":83,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":84,"sourceHtmlUrl":85},"mocking.md",1481,"https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002F.pi\u002Fskills\u002Fdevelop-tdd\u002Fmocking.md",{"path":87,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":88,"sourceHtmlUrl":89},"refactoring.md",387,"https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002F.pi\u002Fskills\u002Fdevelop-tdd\u002Frefactoring.md",{"path":91,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":92,"sourceHtmlUrl":93},"REFERENCE.md",2521,"https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002F.pi\u002Fskills\u002Fdevelop-tdd\u002FREFERENCE.md",{"path":95,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":96,"sourceHtmlUrl":97},"tests.md",2426,"https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002F.pi\u002Fskills\u002Fdevelop-tdd\u002Ftests.md",[99,117,124,152,174,194],{"skillNo":100,"name":101,"nameZh":6,"description":102,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":103,"categories":104,"keywords":108,"publishedAt":44},"01M71KBG9F8X644MJB16H4V8M7","skill-verify-fail-open-fixture","Negative-path fixture for run-skill-verify.sh — must never PASS.","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002Fspecs\u002Fverifications\u002Ffixtures\u002Fskill-verify-fail-open\u002FSKILL.md",[105],{"categoryNo":106,"categoryName":107,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[109,110,111,112,113,114,115,31,116],"fixture","open","verify","skill verify fail open fixture","skill verify","path","run","never",{"skillNo":118,"name":119,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":120,"categories":121,"keywords":122,"publishedAt":44},"01M71KBE3BKEMKNE0C5DGVDWZH","negative-path","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002Fspecs\u002Fverifications\u002Ffixtures\u002Fnegative-path\u002FSKILL.md",[],[123,114],"negative path",{"skillNo":125,"name":126,"nameZh":6,"description":127,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":128,"categories":129,"keywords":133,"publishedAt":44},"01M71KBBGF7Y4EB4AMHBZ8CJFC","write-document","Write, organize, and sync high-integrity technical documents using the BMAD methodology. Ensures every document is Bold, Minimal, Actionable, and Durable. Use when creating architectural docs, technical guides, or organizing the specs\u002F directory.","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002Fskills\u002Fwrite-document\u002FSKILL.md",[130],{"categoryNo":131,"categoryName":132,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000002","文档处理",[134,135,136,137,138,139,140,141,142,143,30,144,145,146,34,147,148,149,150,151],"write","write document","document","documents","actionable","technical","methodology","high","bmad","standard","when","minimal","bold","integrity","organize","sync","directory","guides",{"skillNo":153,"name":154,"nameZh":6,"description":155,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":156,"categories":157,"keywords":158,"publishedAt":44},"01M71KB8TM089JJD5AY5KAFSDM","wire-observability","Add structured JSON logging, observability commands, and idempotent setup scripts to a project. Use when a project needs production-readiness instrumentation, when user wants structured logging, or as a production-readiness gate at any phase of development.","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002Fskills\u002Fwire-observability\u002FSKILL.md",[],[159,160,161,143,162,30,32,163,164,165,34,166,167,168,169,170,171,144,172,173],"observability","wire observability","readiness","commands","as","logging","add","instrumentation","at","structured logging","production-readiness","idempotent","phase","project","scripts",{"skillNo":175,"name":176,"nameZh":6,"description":177,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":178,"categories":179,"keywords":180,"publishedAt":44},"01M71KB6CNRANP449DQA3NJZ96","wire-ci","CI pipeline setup with bundled, forge-neutral templates and local validation. Detects the forge from the git remote, generates workflows for supported forges, and skips honestly for the rest. The CI equivalent of wire-observability.","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002Fskills\u002Fwire-ci\u002FSKILL.md",[],[181,182,183,184,185,186,187,188,189,190,28,143,191,31,159,34,192,193],"wire ci","ci","remote","local","pipeline","forge","validation","setup","templates","REST","ci pipeline setup","git","workflows",{"skillNo":195,"name":196,"nameZh":6,"description":197,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":198,"categories":199,"keywords":211,"publishedAt":44},"01M71KB2ZV98P03X88QR8MT9F1","visual-dashboard","Start a browser-based dashboard that visualizes architecture, implementation plans, and project status. Persists artifacts in .bigpowers\u002Fdashboard\u002F. Reads specs\u002Fstate.yaml, release-plan.yaml, epics, and planning-status via HTTP API or opencode panel.","https:\u002F\u002Fgithub.com\u002Fdanielvm-git\u002Fbigpowers\u002Fblob\u002Fmain\u002Fskills\u002Fvisual-dashboard\u002FSKILL.md",[200,203,208],{"categoryNo":201,"categoryName":202,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000013","分析与可视化",{"categoryNo":204,"categoryName":205,"taxonomyType":206,"taxonomyTypeDesc":207},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",{"categoryNo":209,"categoryName":210,"taxonomyType":206,"taxonomyTypeDesc":207},"01JBSEEDCAT000000000000033","数据分析师",[212,213,214,215,216,217,218,219,220,34,221,222,223,224,225,226,227,172,228,229],"dashboard","visual","visual dashboard","status","artifacts","http","plans","planning","panel","start","release","opencode","plan","browser","api","architecture","project status","http api"]