@jspg-ai/coding-bb 0.0.1 → 0.0.2-beta.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/cbb/bin/cbb.js +6 -0
  2. package/cbb/bin/cbbm.js +6 -0
  3. package/cbb/dev-standards/rules/cbb-ai-behavior.md +103 -103
  4. package/cbb/dev-standards/rules/cbb-priority.md +55 -55
  5. package/cbb/lib/install/claude-code.js +2 -0
  6. package/cbb/lib/install/init.js +496 -290
  7. package/cbb/lib/install/opencode.js +31 -0
  8. package/cbb/lib/install/qoder.js +2 -0
  9. package/cbb/lib/install/workspaces.js +53 -13
  10. package/cbb/lib/openspec/index.js +3 -3
  11. package/cbb/lib/superpowers/index.js +1 -1
  12. package/cbb/lib/utils/check-update.js +16 -14
  13. package/cbb/lib/utils/gitignore.js +2 -1
  14. package/cbb/lib/utils/output.js +92 -4
  15. package/cbb/lib/utils/version.js +2 -31
  16. package/cbb/lib/wiki/cli.js +25 -25
  17. package/cbb/lib/wiki/index.js +16 -16
  18. package/cbb/tools/cbb-design-to-wiki/SKILL.md +14 -14
  19. package/cbb/tools/cbb-wiki-ops/SKILL.md +22 -22
  20. package/cbb/worktrees/_shared/scripts/find-target-worktree.js +2 -2
  21. package/cbb/worktrees/_shared/scripts/find-workspace-root.js +7 -7
  22. package/cbb/worktrees/_shared/scripts/push-core.js +18 -0
  23. package/cbb/worktrees/commands/{close.md → worktree-close.md} +8 -8
  24. package/cbb/worktrees/commands/{init.md → worktree-init.md} +9 -9
  25. package/cbb/worktrees/commands/{push.md → worktree-push.md} +3 -3
  26. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/SKILL.md +20 -20
  27. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/check-env.js +4 -4
  28. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/check-unarchived.js +1 -1
  29. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/delete-branches.js +3 -3
  30. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/discover-apps.js +6 -6
  31. package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-close}/scripts/find-target-worktree.js +2 -2
  32. package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-close}/scripts/find-workspace-root.js +7 -7
  33. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/remove-worktrees.js +4 -4
  34. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/safety-check.js +4 -4
  35. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/SKILL.md +81 -107
  36. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/auto-open.js +1 -1
  37. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/check-env-deep.js +4 -4
  38. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/check-env.js +6 -6
  39. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/check-repos.js +4 -4
  40. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/create-branches.js +4 -4
  41. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/create-worktrees.js +8 -7
  42. package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-init}/scripts/find-workspace-root.js +7 -7
  43. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/install-ai.js +33 -33
  44. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/parse-config.js +7 -7
  45. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/push-branches.js +9 -7
  46. package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-init}/scripts/push-core.js +18 -0
  47. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/sync-repos.js +10 -12
  48. package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-init}/scripts/update-gitignore.js +19 -6
  49. package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/SKILL.md +16 -16
  50. package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/scripts/commit-worktrees.js +2 -2
  51. package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/scripts/find-target-worktree.js +2 -2
  52. package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-push}/scripts/find-workspace-root.js +7 -7
  53. package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/scripts/push-core.js +18 -0
  54. package/cbb/worktrees/skills/{openspec-push-worktrees → cbb-worktree-push}/scripts/push-worktrees.js +7 -5
  55. package/config/workspace-config.sample.json +18 -0
  56. package/config/workspaces.json +11 -6
  57. package/openspec/.version +6 -6
  58. package/openspec/commands/apply.md +7 -7
  59. package/openspec/commands/archive.md +7 -7
  60. package/openspec/commands/bulk-archive.md +7 -7
  61. package/openspec/commands/continue.md +7 -7
  62. package/openspec/commands/explore.md +7 -7
  63. package/openspec/commands/ff.md +7 -7
  64. package/openspec/commands/new.md +7 -7
  65. package/openspec/commands/onboard.md +7 -7
  66. package/openspec/commands/propose.md +7 -7
  67. package/openspec/commands/sync.md +7 -7
  68. package/openspec/commands/update.md +7 -7
  69. package/openspec/commands/verify.md +7 -7
  70. package/openspec/skills/openspec-apply-change/SKILL.md +187 -187
  71. package/openspec/skills/openspec-archive-change/SKILL.md +181 -181
  72. package/openspec/skills/openspec-bulk-archive-change/SKILL.md +338 -338
  73. package/openspec/skills/openspec-continue-change/SKILL.md +117 -117
  74. package/openspec/skills/openspec-explore/SKILL.md +342 -342
  75. package/openspec/skills/openspec-ff-change/SKILL.md +116 -116
  76. package/openspec/skills/openspec-new-change/SKILL.md +76 -76
  77. package/openspec/skills/openspec-onboard/SKILL.md +560 -560
  78. package/openspec/skills/openspec-propose/SKILL.md +162 -162
  79. package/openspec/skills/openspec-sync-specs/SKILL.md +261 -261
  80. package/openspec/skills/openspec-update-change/SKILL.md +90 -90
  81. package/openspec/skills/openspec-verify-change/SKILL.md +174 -174
  82. package/package.json +4 -3
  83. package/superpowers/.version +6 -6
  84. package/superpowers/skills/brainstorming/SKILL.md +250 -250
  85. package/superpowers/skills/brainstorming/scripts/helper.js +167 -167
  86. package/superpowers/skills/brainstorming/scripts/start-server.sh +209 -209
  87. package/superpowers/skills/brainstorming/scripts/stop-server.sh +120 -120
  88. package/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -49
  89. package/superpowers/skills/brainstorming/visual-companion.md +299 -299
  90. package/superpowers/skills/dispatching-parallel-agents/SKILL.md +167 -167
  91. package/superpowers/skills/executing-plans/SKILL.md +64 -64
  92. package/superpowers/skills/finishing-a-development-branch/SKILL.md +225 -225
  93. package/superpowers/skills/receiving-code-review/SKILL.md +205 -205
  94. package/superpowers/skills/requesting-code-review/SKILL.md +95 -95
  95. package/superpowers/skills/requesting-code-review/code-reviewer.md +181 -181
  96. package/superpowers/skills/subagent-driven-development/SKILL.md +568 -568
  97. package/superpowers/skills/subagent-driven-development/implementer-prompt.md +154 -154
  98. package/superpowers/skills/subagent-driven-development/re-review-prompt.md +115 -115
  99. package/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +207 -207
  100. package/superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -119
  101. package/superpowers/skills/systematic-debugging/SKILL.md +283 -283
  102. package/superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
  103. package/superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -115
  104. package/superpowers/skills/systematic-debugging/defense-in-depth.md +122 -122
  105. package/superpowers/skills/systematic-debugging/find-polluter.sh +72 -72
  106. package/superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -169
  107. package/superpowers/skills/systematic-debugging/test-academic.md +14 -14
  108. package/superpowers/skills/systematic-debugging/test-pressure-1.md +58 -58
  109. package/superpowers/skills/systematic-debugging/test-pressure-2.md +68 -68
  110. package/superpowers/skills/systematic-debugging/test-pressure-3.md +69 -69
  111. package/superpowers/skills/test-driven-development/SKILL.md +320 -320
  112. package/superpowers/skills/test-driven-development/writing-good-tests.md +198 -198
  113. package/superpowers/skills/using-git-worktrees/SKILL.md +167 -167
  114. package/superpowers/skills/using-superpowers/SKILL.md +63 -63
  115. package/superpowers/skills/using-superpowers/references/antigravity-tools.md +23 -23
  116. package/superpowers/skills/using-superpowers/references/codex-tools.md +108 -108
  117. package/superpowers/skills/using-superpowers/references/gemini-tools.md +63 -63
  118. package/superpowers/skills/using-superpowers/references/hermes-tools.md +56 -56
  119. package/superpowers/skills/using-superpowers/references/pi-tools.md +16 -16
  120. package/superpowers/skills/verification-before-completion/SKILL.md +120 -120
  121. package/superpowers/skills/writing-plans/SKILL.md +171 -171
  122. package/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -49
  123. package/superpowers/skills/writing-skills/SKILL.md +679 -679
  124. package/superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -1150
  125. package/superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
  126. package/superpowers/skills/writing-skills/persuasion-principles.md +187 -187
  127. package/superpowers/skills/writing-skills/render-graphs.js +169 -169
  128. package/superpowers/skills/writing-skills/testing-skills-with-subagents.md +384 -384
  129. package/cbb/worktrees/commands/extend.md +0 -65
  130. package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-target-worktree.js +0 -96
  131. package/cbb/worktrees/skills/openspec-extend-worktree/SKILL.md +0 -390
  132. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-env.js +0 -95
  133. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-repos.js +0 -98
  134. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/create-branches-and-worktrees.js +0 -135
  135. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/install-ai.js +0 -150
  136. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/list-available-apps.js +0 -88
  137. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/sync-repos.js +0 -93
  138. package/cbb/worktrees/skills/openspec-init-worktree/scripts/find-workspace-root.js +0 -67
  139. package/cbb/worktrees/skills/openspec-init-worktree/scripts/generate-app-options.js +0 -93
  140. package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-core.js +0 -136
  141. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/silence-popup.js +0 -23
  142. package/config/config.sample.json +0 -16
  143. /package/cbb/worktrees/skills/{openspec-close-worktree → cbb-worktree-close}/scripts/silence-popup.js +0 -0
  144. /package/cbb/worktrees/skills/{openspec-extend-worktree → cbb-worktree-init}/scripts/silence-popup.js +0 -0
  145. /package/cbb/worktrees/skills/{openspec-init-worktree → cbb-worktree-push}/scripts/silence-popup.js +0 -0
@@ -1,198 +1,198 @@
1
- # Writing Good Tests
2
-
3
- **Load this reference when:** writing or changing tests, adding mocks, or
4
- adding cleanup/helper methods for tests.
5
-
6
- ## Overview
7
-
8
- A test exists to catch a specific break. Two principles govern everything
9
- here:
10
-
11
- ```
12
- 1. Every test names the break it catches
13
- 2. Every test exercises the real thing
14
- ```
15
-
16
- Strict TDD produces both naturally: a test written first and watched
17
- failing against real code has already proven it can fail, and only earns
18
- a mock when the real dependency proves slow or external.
19
-
20
- ## Principle 1: Name the Break
21
-
22
- Before writing the test body, answer: **what production change should
23
- make this test fail — and is that change a bug or a decision?** A test
24
- earns its place by catching a wrong branch, missing side effect, wrong
25
- argument, boundary case, or broken contract.
26
-
27
- **Derive expectations independently.** Use literals and hand-checked
28
- fixtures; table-driven tests with literal `want` values are the preferred
29
- shape. An expectation computed by the code under test — or its helpers —
30
- passes no matter what that code does:
31
-
32
- ```typescript
33
- // ❌ Mirror assertion: the same builder computes both sides — always true
34
- const expected = buildSearchQuery({ tag: 'urgent' });
35
- expect(buildSearchQuery({ tag: 'urgent' })).toBe(expected);
36
-
37
- // ✅ Hand-derived literal
38
- expect(buildSearchQuery({ tag: 'urgent' })).toBe('tag:"urgent"');
39
- ```
40
-
41
- **No change detectors.** If only intentional decisions can fail a test —
42
- a constant's value, exact message wording, private structure — it fires
43
- on redesign and sleeps through bugs. Test the behavior that depends on
44
- the decision: not `expect(MAX_RETRIES).toBe(5)` but "a failing call is
45
- retried 5 times and the 6th attempt never happens."
46
-
47
- **Behavior, not text.** Asserting that a script, skill, or config
48
- contains an exact line proves only that the source is the source. Run
49
- scripts against controlled inputs and assert outputs, side effects, or
50
- exit codes. Documents that instruct agents are tested by the consuming
51
- agent's behavior (superpowers:writing-skills); prose for humans earns no
52
- test at all.
53
-
54
- **Your code, not the framework.** Test the contract your code makes at
55
- its boundaries — the route you register, the query you emit, the payload
56
- you produce. Upstream mechanics are their maintainers' tests to write
57
- (the classic: asserting your router invokes a registered handler — that
58
- is the framework's test, not yours). When upstream behavior genuinely
59
- surprised you, write one narrow characterization test naming the
60
- assumption. The same boundary applies inside your code: constructors,
61
- getters, constants, and trivial forwarding earn tests only when they
62
- validate, normalize, default, derive, enforce, or cause side effects —
63
- otherwise assert the first consumer-visible result that depends on them.
64
-
65
- ### Gate Function
66
-
67
- ```
68
- BEFORE writing the test body:
69
- Name the production change that would make this test fail.
70
-
71
- Cannot name one → redesign around an observable behavior
72
- "The source text changed" → run the artifact and assert its effects
73
- Only intentional decisions → change detector; test the behavior
74
- that depends on the decision
75
-
76
- Confirm the expected value is derived without the code under test.
77
- IF it reuses the code's logic or helpers:
78
- Replace it with a literal or hand-checked fixture
79
- ```
80
-
81
- ## Principle 2: Exercise the Real Thing
82
-
83
- **The mock earns no assertions.** A mock assertion passes when the mock
84
- is present and fails when it is absent — it says nothing about the
85
- component. Assert the real component's behavior; if the mock is what you
86
- are checking, unmock it or delete the assertion.
87
-
88
- ```typescript
89
- // ✅ Real behavior
90
- expect(screen.getByRole('navigation')).toBeInTheDocument();
91
-
92
- // ❌ Mock existence
93
- expect(screen.getByTestId('sidebar-mock')).toBeInTheDocument();
94
- ```
95
-
96
- **your human partner's correction:** "Are we testing the behavior of a
97
- mock?"
98
-
99
- **Mock at the right level.** Learn every side effect of the real method
100
- before replacing it; mock the slow or external operation and keep what
101
- the test depends on real. When unsure, run the test against the real
102
- implementation first and observe what actually needs to happen.
103
-
104
- ```typescript
105
- // ❌ The mock swallows the config write that duplicate detection reads
106
- vi.mock('ToolCatalog', () => ({
107
- discoverAndCacheTools: vi.fn().mockResolvedValue(undefined)
108
- }));
109
-
110
- // ✅ Mock only the slow server startup; the config write stays real
111
- vi.mock('MCPServerManager');
112
- ```
113
-
114
- **Make doubles specific.** When arguments, call counts, or ordering are
115
- part of the contract, assert them — a fake that accepts anything verifies
116
- nothing. Give each branch (success, error, malformed) its own fixture or
117
- spy, so the wrong branch cannot satisfy the expectation.
118
-
119
- **Mirror real data completely.** Mock the complete structure as it exists
120
- in reality — all documented fields — not just the ones your test reads.
121
- Partial mocks fail silently when downstream code reads an omitted field:
122
- the test passes while integration breaks.
123
-
124
- **Production classes carry production methods only.** Cleanup that only
125
- tests need lives in test utilities, never as a `destroy()` on the
126
- production class. Ask: is this method called only from tests? Does this
127
- class own this resource's lifecycle? Wrong answers → test utility.
128
-
129
- **Prefer real components over complex mocks.** When mock setup outgrows
130
- the test logic, mocks miss methods the real components have, or tests
131
- break when the mock changes, switch to an integration test with real
132
- components. **your human partner's question:** "Do we need to be using a
133
- mock here?"
134
-
135
- ### Gate Function
136
-
137
- ```
138
- BEFORE adding a mock or test helper:
139
- List the real method's side effects; keep the ones the test
140
- depends on real — mock the slow/external level below them.
141
-
142
- Mock responses mirror the complete real structure.
143
-
144
- A method only tests call lives in test utilities, not production.
145
-
146
- About to assert on the mock itself?
147
- Unmock it or delete the assertion.
148
- ```
149
-
150
- ## Tests Ship With the Implementation
151
-
152
- The TDD cycle — failing test, minimal implementation, refactor — is what
153
- "complete" means. Ship the tests the behavior needs and only those:
154
- trivial code and human prose earn none, and a test written to satisfy
155
- process costs maintenance forever.
156
-
157
- ## The Mutation Check
158
-
159
- Before finishing, mentally mutate the production code; at least one test
160
- should fail for each realistic mutation:
161
-
162
- - Wrong constant or argument
163
- - Wrong branch handler
164
- - Missing state change or side effect
165
- - Empty or default return
166
- - Missing validation for zero, empty, nil, unauthorized, or malformed input
167
-
168
- A mutation nothing catches marks the behavior as unprotected — or the
169
- test as tautological.
170
-
171
- ## Quick Reference
172
-
173
- | When you... | Do |
174
- |-------------|-----|
175
- | Write any test | Name the break it catches — a bug, not a decision |
176
- | Build an expected value | Derive it by hand; never with the code under test |
177
- | Test a script or document | Run it / pressure-test its consumer; never grep its text |
178
- | Reach for a dependency test | Test your boundary contract, not their documented mechanics |
179
- | Want to assert on a mocked element | Test the real component, or unmock it |
180
- | Are about to mock a method | Learn its side effects; mock the slow/external level |
181
- | Build a mock response | Mirror the real structure completely |
182
- | Need cleanup only tests use | Put it in test utilities |
183
- | Watch mock setup balloon | Switch to an integration test with real components |
184
- | Finish a test file | Run the mutation check |
185
-
186
- ## Warning Signs
187
-
188
- - Setup and assertion share the same object, guaranteeing equality
189
- - The test can fail only through a panic, crash, or missing selector
190
- - The test fails on every intentional change, never on accidental breakage
191
- - Expected values are hidden behind loops, builders, or helpers
192
- - The test greps source text, or asserts a removed symbol stays removed
193
- - The test would still matter if only the framework remained
194
- - The test exists for coverage, checking no side effect or outcome
195
- - An assertion checks a `*-mock` test ID, or fails if you remove the mock
196
- - A method is called only from test files
197
- - Mock setup is more than half the test, or you can't explain why the mock is needed
198
- - Mocking "just to be safe"
1
+ # Writing Good Tests
2
+
3
+ **Load this reference when:** writing or changing tests, adding mocks, or
4
+ adding cleanup/helper methods for tests.
5
+
6
+ ## Overview
7
+
8
+ A test exists to catch a specific break. Two principles govern everything
9
+ here:
10
+
11
+ ```
12
+ 1. Every test names the break it catches
13
+ 2. Every test exercises the real thing
14
+ ```
15
+
16
+ Strict TDD produces both naturally: a test written first and watched
17
+ failing against real code has already proven it can fail, and only earns
18
+ a mock when the real dependency proves slow or external.
19
+
20
+ ## Principle 1: Name the Break
21
+
22
+ Before writing the test body, answer: **what production change should
23
+ make this test fail — and is that change a bug or a decision?** A test
24
+ earns its place by catching a wrong branch, missing side effect, wrong
25
+ argument, boundary case, or broken contract.
26
+
27
+ **Derive expectations independently.** Use literals and hand-checked
28
+ fixtures; table-driven tests with literal `want` values are the preferred
29
+ shape. An expectation computed by the code under test — or its helpers —
30
+ passes no matter what that code does:
31
+
32
+ ```typescript
33
+ // ❌ Mirror assertion: the same builder computes both sides — always true
34
+ const expected = buildSearchQuery({ tag: 'urgent' });
35
+ expect(buildSearchQuery({ tag: 'urgent' })).toBe(expected);
36
+
37
+ // ✅ Hand-derived literal
38
+ expect(buildSearchQuery({ tag: 'urgent' })).toBe('tag:"urgent"');
39
+ ```
40
+
41
+ **No change detectors.** If only intentional decisions can fail a test —
42
+ a constant's value, exact message wording, private structure — it fires
43
+ on redesign and sleeps through bugs. Test the behavior that depends on
44
+ the decision: not `expect(MAX_RETRIES).toBe(5)` but "a failing call is
45
+ retried 5 times and the 6th attempt never happens."
46
+
47
+ **Behavior, not text.** Asserting that a script, skill, or config
48
+ contains an exact line proves only that the source is the source. Run
49
+ scripts against controlled inputs and assert outputs, side effects, or
50
+ exit codes. Documents that instruct agents are tested by the consuming
51
+ agent's behavior (superpowers:writing-skills); prose for humans earns no
52
+ test at all.
53
+
54
+ **Your code, not the framework.** Test the contract your code makes at
55
+ its boundaries — the route you register, the query you emit, the payload
56
+ you produce. Upstream mechanics are their maintainers' tests to write
57
+ (the classic: asserting your router invokes a registered handler — that
58
+ is the framework's test, not yours). When upstream behavior genuinely
59
+ surprised you, write one narrow characterization test naming the
60
+ assumption. The same boundary applies inside your code: constructors,
61
+ getters, constants, and trivial forwarding earn tests only when they
62
+ validate, normalize, default, derive, enforce, or cause side effects —
63
+ otherwise assert the first consumer-visible result that depends on them.
64
+
65
+ ### Gate Function
66
+
67
+ ```
68
+ BEFORE writing the test body:
69
+ Name the production change that would make this test fail.
70
+
71
+ Cannot name one → redesign around an observable behavior
72
+ "The source text changed" → run the artifact and assert its effects
73
+ Only intentional decisions → change detector; test the behavior
74
+ that depends on the decision
75
+
76
+ Confirm the expected value is derived without the code under test.
77
+ IF it reuses the code's logic or helpers:
78
+ Replace it with a literal or hand-checked fixture
79
+ ```
80
+
81
+ ## Principle 2: Exercise the Real Thing
82
+
83
+ **The mock earns no assertions.** A mock assertion passes when the mock
84
+ is present and fails when it is absent — it says nothing about the
85
+ component. Assert the real component's behavior; if the mock is what you
86
+ are checking, unmock it or delete the assertion.
87
+
88
+ ```typescript
89
+ // ✅ Real behavior
90
+ expect(screen.getByRole('navigation')).toBeInTheDocument();
91
+
92
+ // ❌ Mock existence
93
+ expect(screen.getByTestId('sidebar-mock')).toBeInTheDocument();
94
+ ```
95
+
96
+ **your human partner's correction:** "Are we testing the behavior of a
97
+ mock?"
98
+
99
+ **Mock at the right level.** Learn every side effect of the real method
100
+ before replacing it; mock the slow or external operation and keep what
101
+ the test depends on real. When unsure, run the test against the real
102
+ implementation first and observe what actually needs to happen.
103
+
104
+ ```typescript
105
+ // ❌ The mock swallows the config write that duplicate detection reads
106
+ vi.mock('ToolCatalog', () => ({
107
+ discoverAndCacheTools: vi.fn().mockResolvedValue(undefined)
108
+ }));
109
+
110
+ // ✅ Mock only the slow server startup; the config write stays real
111
+ vi.mock('MCPServerManager');
112
+ ```
113
+
114
+ **Make doubles specific.** When arguments, call counts, or ordering are
115
+ part of the contract, assert them — a fake that accepts anything verifies
116
+ nothing. Give each branch (success, error, malformed) its own fixture or
117
+ spy, so the wrong branch cannot satisfy the expectation.
118
+
119
+ **Mirror real data completely.** Mock the complete structure as it exists
120
+ in reality — all documented fields — not just the ones your test reads.
121
+ Partial mocks fail silently when downstream code reads an omitted field:
122
+ the test passes while integration breaks.
123
+
124
+ **Production classes carry production methods only.** Cleanup that only
125
+ tests need lives in test utilities, never as a `destroy()` on the
126
+ production class. Ask: is this method called only from tests? Does this
127
+ class own this resource's lifecycle? Wrong answers → test utility.
128
+
129
+ **Prefer real components over complex mocks.** When mock setup outgrows
130
+ the test logic, mocks miss methods the real components have, or tests
131
+ break when the mock changes, switch to an integration test with real
132
+ components. **your human partner's question:** "Do we need to be using a
133
+ mock here?"
134
+
135
+ ### Gate Function
136
+
137
+ ```
138
+ BEFORE adding a mock or test helper:
139
+ List the real method's side effects; keep the ones the test
140
+ depends on real — mock the slow/external level below them.
141
+
142
+ Mock responses mirror the complete real structure.
143
+
144
+ A method only tests call lives in test utilities, not production.
145
+
146
+ About to assert on the mock itself?
147
+ Unmock it or delete the assertion.
148
+ ```
149
+
150
+ ## Tests Ship With the Implementation
151
+
152
+ The TDD cycle — failing test, minimal implementation, refactor — is what
153
+ "complete" means. Ship the tests the behavior needs and only those:
154
+ trivial code and human prose earn none, and a test written to satisfy
155
+ process costs maintenance forever.
156
+
157
+ ## The Mutation Check
158
+
159
+ Before finishing, mentally mutate the production code; at least one test
160
+ should fail for each realistic mutation:
161
+
162
+ - Wrong constant or argument
163
+ - Wrong branch handler
164
+ - Missing state change or side effect
165
+ - Empty or default return
166
+ - Missing validation for zero, empty, nil, unauthorized, or malformed input
167
+
168
+ A mutation nothing catches marks the behavior as unprotected — or the
169
+ test as tautological.
170
+
171
+ ## Quick Reference
172
+
173
+ | When you... | Do |
174
+ |-------------|-----|
175
+ | Write any test | Name the break it catches — a bug, not a decision |
176
+ | Build an expected value | Derive it by hand; never with the code under test |
177
+ | Test a script or document | Run it / pressure-test its consumer; never grep its text |
178
+ | Reach for a dependency test | Test your boundary contract, not their documented mechanics |
179
+ | Want to assert on a mocked element | Test the real component, or unmock it |
180
+ | Are about to mock a method | Learn its side effects; mock the slow/external level |
181
+ | Build a mock response | Mirror the real structure completely |
182
+ | Need cleanup only tests use | Put it in test utilities |
183
+ | Watch mock setup balloon | Switch to an integration test with real components |
184
+ | Finish a test file | Run the mutation check |
185
+
186
+ ## Warning Signs
187
+
188
+ - Setup and assertion share the same object, guaranteeing equality
189
+ - The test can fail only through a panic, crash, or missing selector
190
+ - The test fails on every intentional change, never on accidental breakage
191
+ - Expected values are hidden behind loops, builders, or helpers
192
+ - The test greps source text, or asserts a removed symbol stays removed
193
+ - The test would still matter if only the framework remained
194
+ - The test exists for coverage, checking no side effect or outcome
195
+ - An assertion checks a `*-mock` test ID, or fails if you remove the mock
196
+ - A method is called only from test files
197
+ - Mock setup is more than half the test, or you can't explain why the mock is needed
198
+ - Mocking "just to be safe"