@solaqua/ghosts 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +22 -3
  2. package/common/AGENTS.md +0 -11
  3. package/engineering/skills/code-review/SKILL.md +14 -7
  4. package/engineering/skills/coding/SKILL.md +15 -0
  5. package/engineering/skills/deep-module/SKILL.md +1 -1
  6. package/engineering/skills/explain-diff/SKILL.md +1 -1
  7. package/engineering/skills/github-issue/SKILL.md +35 -0
  8. package/engineering/skills/github-pr/SKILL.md +1 -1
  9. package/engineering/skills/grill-me/SKILL.md +1 -1
  10. package/engineering/skills/slop-shaking/SKILL.md +35 -0
  11. package/engineering/skills/stack-pr/SKILL.md +39 -0
  12. package/engineering/skills/task-handoff/SKILL.md +1 -1
  13. package/engineering/skills/test-review/SKILL.md +27 -13
  14. package/engineering/skills/work-breakdown/SKILL.md +38 -6
  15. package/engineering/skills/write-adr/SKILL.md +1 -1
  16. package/engineering/skills/write-glossary/SKILL.md +1 -1
  17. package/package.json +1 -1
  18. package/research/skills/deep-research/SKILL.md +30 -0
  19. package/tools/skills/vibe-notion/SKILL.md +1 -1
  20. package/writing/skills/cold-reader/SKILL.md +1 -1
  21. package/writing/skills/eli5/SKILL.md +1 -1
  22. package/writing/skills/humanize-korean/SKILL.md +1 -1
  23. package/writing/skills/make-skill/SKILL.md +15 -0
  24. package/writing/skills/rewrite/SKILL.md +1 -1
  25. package/engineering/skills/loop-coding/SKILL.md +0 -48
  26. package/engineering/skills/loop-coding/templates/plan.md +0 -14
  27. package/engineering/skills/loop-plan/SKILL.md +0 -219
  28. package/engineering/skills/loop-plan/templates/plan.md +0 -39
  29. package/engineering/skills/test-review/references/backend.md +0 -280
  30. package/engineering/skills/test-review/references/common.md +0 -30
  31. package/engineering/skills/test-review/references/frontend.md +0 -301
  32. package/engineering/skills/test-review/templates/review.md +0 -21
  33. package/research/skills/loop-research/SKILL.md +0 -129
  34. package/research/skills/loop-research/templates/decision-memo.md +0 -30
  35. package/writing/skills/loop-skills/SKILL.md +0 -101
@@ -1,219 +0,0 @@
1
- ---
2
- name: loop-plan
3
- description: Planning-only loop for complex development and design problems, adaptable to other domains; uses evidence, alternatives, counterarguments, and premortems to resolve material uncertainty or costly tradeoffs. Skip routine implementation planning.
4
- disable-model-invocation: true
5
- ---
6
- # Loop Plan
7
-
8
- Create a plan another person or agent can execute without rediscovering key
9
- decisions. Inspect context and write planning artifacts only; stop before
10
- implementation or invoking an execution skill. Scale depth to uncertainty and
11
- the cost of a wrong decision, not the number of tasks or document length. For
12
- other domains, replace files, interfaces, and tests with the relevant
13
- deliverables, dependencies, and verification; omit software-only checks.
14
- Write responses and the plan in plain, natural English, or in Korean when the
15
- user writes in Korean, including template headings.
16
-
17
- ## Runtime loop
18
-
19
- Before acting, create `/tmp/loop-plan-<safe-task-slug>.md` with a unique slug
20
- or timestamp, `Current state: Pass 1 / Next: Understand`, the checklist below,
21
- and an empty append-only `Repair log:`. Process items in order, finish each
22
- before moving on, record a short outcome, and update `Current state`. Mark
23
- `[x]` only after completion and `[-]` only with a reason; never erase or
24
- uncheck historical rows. After a repair, append a numbered `[ ] Recheck P2: ...`
25
- row for the earliest affected item and record the trigger, change, rechecked
26
- items, and result in the repair log. Finish only after final validation.
27
-
28
- ```text
29
- - [ ] Understand the outcome, constraints, and relevant evidence
30
- - [ ] Resolve research and user-decision dependencies before framing
31
- - [ ] Frame success, scope, principles, and decision drivers
32
- - [ ] Set the review budget from uncertainty, impact, and reversibility
33
- - [ ] Compare viable approaches and choose a provisional direction
34
- - [ ] Draft ordered work packages and validation
35
- - [ ] Challenge the design and run a premortem
36
- - [ ] Any unsupported assumption, unresolved decision, or stronger alternative that changes the plan?
37
- - [ ] Any unaddressed failure, dependency, or unverifiable completion criterion?
38
- - [ ] Any unnecessary scope, complexity, or detail?
39
- - [ ] Final validation and delivery of the plan
40
- ```
41
-
42
- Answer every `Any ...?` row Yes or No. On Yes, repair the smallest material
43
- issue and return to the earliest affected step before repeating the review. If
44
- progress depends on missing evidence or a user decision, identify the exact
45
- blocker instead of repeating the review or claiming readiness.
46
-
47
- ## Adaptive review
48
-
49
- Do not make the user choose a mode. After framing, keep a decision ledger with
50
- each material decision's impact, uncertainty, reversibility, and needed
51
- evidence. Use qualitative `low`, `medium`, or `high` values and states such as
52
- `open`, `investigating`, `supported`, `disputed`, `gated`, and `closed`.
53
- Require at least one independent targeted review for a decision with high
54
- impact and high uncertainty, low reversibility, or cross-component effects. A
55
- request for `ralplan` or subagents raises the review budget without imposing a
56
- fixed ceremony.
57
-
58
- ```text
59
- [Understand] → [Route unknowns]
60
- ├─ evidence → [$loop-research] ┐
61
- ├─ user decision → [$grill-me] ├→ [Frame + ledger] → [Draft]
62
- └─ known →─────────────────────┘ ↓
63
- [Any high-impact uncertainty?]
64
- ├─ No → [Self challenge]
65
- └─ Yes → [Targeted subagent questions]
66
- → [Synthesize] → [Revise] ↺
67
- → [Premortem] → [Any material issue?]
68
- → [Validate + deliver]
69
- ```
70
-
71
- For each unresolved ledger item, record a question ID, covered decision IDs,
72
- capability, required inputs, `depends_on` question IDs, decision criterion,
73
- and required evidence. Dispatch only ready questions; run independent ones in
74
- parallel and refresh the snapshot after upstream results.
75
-
76
- Choose a narrow capability rather than a permanent role:
77
-
78
- - **Investigation:** establish a missing fact, constraint, dependency, or
79
- feasibility signal.
80
- - **Design challenge:** test boundaries, responsibilities, dependency
81
- direction, and the strongest case against the chosen approach.
82
- - **Execution challenge:** test prerequisites, rollout, recovery,
83
- observability, and demonstrable completion.
84
- - **Adversarial challenge:** identify a credible failure or attack path when
85
- relevant.
86
-
87
- Give each subagent the exact question, context snapshot, candidate options,
88
- decision criterion, and required evidence. Keep it read-only and request
89
- `finding`, `evidence`, `consequence`, and `recommendation`. Record each call as
90
- `complete`, `failed`, `timed_out`, or `invalid`. Retry or reassign once when
91
- useful, counting that attempt against the single follow-up budget; then use
92
- self-review only when the risk permits. An unresolved high-impact item stays
93
- `conditional` or `blocked`.
94
-
95
- When two independent reviews are warranted, give them the same snapshot without
96
- either review's findings, then record disagreements and their resolution. The
97
- primary agent alone synthesizes the findings, records which decision changed
98
- and why, and revises the draft.
99
-
100
- When a finding changes a material decision, scope, or acceptance criterion,
101
- send the revised delta to the relevant completed reviewer for one confirmation
102
- pass. Ask whether the original concern is resolved, what new consequence the
103
- revision creates, and whether a material objection remains. Record the response
104
- and any objection in the question record and decision ledger. Skip the pass
105
- when no material change occurred; when used, it counts against the single
106
- follow-up budget and is review evidence, not user approval.
107
- Preserve blind independence for reviews that have not run. If confirmation is
108
- unavailable or a material objection remains, keep the item `conditional` or
109
- `blocked`.
110
-
111
- Set a bounded budget at delegation: one initial question per high-impact item,
112
- one follow-up per item for conflicting, insufficient, or materially changed
113
- evidence or drafts (including retry, reassignment, or confirmation), and at
114
- most five synthesis passes. Repeat only while a material item lacks support or
115
- a credible objection remains. Stop when high-impact decisions have evidence or
116
- explicit gates, no unresolved objection changes the recommendation, and
117
- acceptance and verification criteria are concrete. If the budget is exhausted
118
- or the same material objection survives two revisions, deliver `conditional`
119
- or `blocked` with the exact reason. If delegation is unavailable, perform the
120
- same questions as self-review and state that no independent review occurred.
121
- Subagent findings are review evidence, never user approval or authorization to
122
- implement.
123
-
124
- For high-risk work, deepen relevant challenges with three premortem scenarios
125
- and the verification levels the problem needs. Do not add irrelevant test
126
- layers to a design-only problem.
127
-
128
- ## Understand and frame
129
-
130
- Inspect relevant code, documents, existing plans, and constraints before asking
131
- questions that inspection can answer. Distinguish observed facts, inferences,
132
- and assumptions; cite supporting files or sources. Identify the observable
133
- outcome, non-goals, affected users or systems, and material constraints.
134
-
135
- Route unresolved inputs before making design decisions. Use `$loop-research` for
136
- repository or document investigation, current or contested evidence,
137
- comparisons, feasibility checks, or source citations; it returns verified
138
- claims, provenance, uncertainty, and leads that could change the plan. Use
139
- `$grill-me` for choices only the user can make, such as outcome, scope, priority,
140
- risk tolerance, or external action. It asks the whole ready frontier in each
141
- round and returns a short, grouped decision summary. Wait for the user to confirm
142
- the shared understanding before carrying its decisions into the plan. Do not
143
- ask the user for facts that inspection or research can establish, or infer a
144
- material preference. Carry both outputs into the decision ledger.
145
-
146
- Resolve material user choices through the interview's dependency-aware rounds;
147
- continue independent inspection while waiting. State ordinary assumptions only
148
- when they do not replace a material user decision. If feasibility remains
149
- unestablished, put the cheapest useful investigation first with a decision
150
- criterion and keep dependent work conditional rather than inventing certainty.
151
- State task-specific principles, rank decision drivers, resolve conflicts
152
- explicitly, and define observable success before choosing.
153
-
154
- ## Compare and draft
155
-
156
- Compare at least two genuinely viable approaches against the same principles
157
- and drivers, including a smaller change or no change when viable. Give each its
158
- strongest case, cost, and downside. If only one survives the constraints,
159
- explain why the alternatives fail. Recommend a direction, name the accepted
160
- tradeoff, and state what evidence would reverse it.
161
-
162
- Break the direction into dependency-ordered, independently verifiable work
163
- packages. For each, name the outcome, affected components or files, important
164
- interfaces, prerequisites, and completion evidence. Prefer end-to-end slices;
165
- mark proposed paths as new and verify existing references. Specify correctness
166
- contracts and ordering without prescribing incidental implementation details.
167
- Do not invent precise estimates or parallelism without a basis.
168
-
169
- Map success criteria to concrete checks, including material failure paths and
170
- relevant existing tests. Add tests only for meaningful behavior. Include
171
- rollout, observability, recovery, or stop conditions when operational
172
- consequences require them.
173
-
174
- ## Challenge and repair
175
-
176
- Review a fixed draft in two separate self-review passes before revising:
177
-
178
- 1. **Design challenge:** make the strongest case against the recommendation;
179
- check principle violations, responsibility boundaries, dependency direction,
180
- and whether a simpler alternative achieves the outcome. Resolve a real
181
- tension through evidence or an explicit tradeoff.
182
- 2. **Execution challenge:** walk through representative work packages as an
183
- implementer, including a failure path; check prerequisites, missing
184
- decisions, feasibility, and demonstrable completion.
185
-
186
- These are not independent agent consensus. If the user requests separate
187
- reviewers, give them the same draft and source context without the other
188
- review's conclusions, combine findings only after both finish, and do not claim
189
- independent review unless it occurred.
190
-
191
- Run a premortem: assume failure at a meaningful milestone and trace the most
192
- consequential plausible failures to plan details. For each, capture the causal
193
- sequence, enabling assumption, likelihood and impact separately, earliest
194
- warning, check time, mitigation, and revision or stop trigger. Label unverified
195
- scenarios as hypotheses and thresholds as provisional; do not invent numerical
196
- probabilities or promise to eliminate every risk. Include an adversary's
197
- response only when adversarial behavior is relevant to the actual problem.
198
-
199
- Use findings to change the plan and give a short reason for each material
200
- revision. Put cheap checks of critical assumptions before expensive dependent
201
- work. Resolve material objections or expose them as blockers; do not bury them
202
- in a risk list. Recheck affected decisions and packages after each repair.
203
-
204
- ## Deliver
205
-
206
- Save the plan to the user-specified path if one is given; otherwise use
207
- `/tmp/loop-plan-<safe-task-slug>-result.md` (append a timestamp when a collision
208
- is possible). Keep the runtime log separate. Make the plan understandable
209
- without the preceding conversation. Follow
210
- [templates/plan.md](templates/plan.md), replacing each placeholder or omitting
211
- the section as it directs.
212
-
213
- Before delivery, verify references are accurate, critical assumptions are
214
- validated or explicitly gated, acceptance checks cover intended behavior, and
215
- another implementer can proceed without hidden design decisions.
216
- Readiness describes the plan; it is not user approval or evidence that planned
217
- checks passed. If handing the document to `loop-coding`, preserve explicit
218
- approval of that plan and let its implementation workflow own execution. End
219
- with the plan path, chosen direction, and remaining decisions.
@@ -1,39 +0,0 @@
1
- # <Plan title>
2
-
3
- **Readiness:** <ready for approval | conditional | blocked> — <reason>
4
- **Direction:** <Chosen approach in one sentence>
5
- **Alternative:** <Strongest alternative and the tradeoff that ruled it out; omit when none is viable>
6
-
7
- ## Outcome
8
- - <Observable outcome and success criteria>
9
- - **Out of scope:** <Explicit non-goals>
10
-
11
- ## Work packages
12
- 1. **<Outcome of the package>**
13
- - `<path>` — <What changes and why, without implementation details; mark new files>
14
- - **Depends on:** <Earlier package or decision; omit when none>
15
- - **Done when:** <Completion evidence>
16
-
17
- ## Validation
18
- - <Check to run and what it proves>
19
-
20
- ---
21
-
22
- ## Details
23
- Supporting context for reviewers; omit any subsection with nothing material to add.
24
-
25
- ### Open decisions
26
- - <Decision only the user can make, with options and a recommendation>
27
-
28
- ### Constraints and assumptions
29
- - <Constraint, or assumption with its source or the check that will verify it>
30
-
31
- ### Alternatives
32
- - **<Alternative>** — <Its strongest case, and why it lost>
33
- - **Would change if:** <Evidence that would reverse the chosen direction>
34
-
35
- ### Risks
36
- - **<Plausible failure>** — <Early signal>; <mitigation>; <stop or revise trigger>
37
-
38
- ### Decision ledger
39
- - **<ID> <Decision>** (<status>) — <Evidence and review call IDs>; <unresolved disagreement, only if any>
@@ -1,280 +0,0 @@
1
- # Backend Testing Guide
2
-
3
- This document defines the shared testing standards for backend teams. Tests are not written just to see `Pass`. They are written to fail quickly and clearly when important behavior is broken.
4
-
5
- Repository structure, fixture names, and test commands may differ by repository. This guide focuses on shared judgment criteria for writing and reviewing backend tests, rather than repository-specific usage.
6
-
7
- ## 1. Testing Philosophy
8
-
9
- ### 1.1 Meaningful Failure
10
-
11
- - A test should fail when the behavior it protects is broken.
12
- - A test that keeps passing after a requirement change or bug does not provide safety. It only adds maintenance cost.
13
- - If a refactor breaks a test while observable behavior remains the same, the test is likely coupled too tightly to implementation details.
14
- - Regression tests and snapshot tests are useful when they protect contracts that must not change accidentally.
15
- - If a test failure does not reveal which requirement was broken, improve the test name, setup, or assertions.
16
-
17
- ### 1.2 Choose Test Targets By Value
18
-
19
- Apply [Test Target Value](common.md#test-target-value), and:
20
-
21
- - When an integration test already protects a behavior, do not automatically repeat it in unit tests for every participating layer. Add focused tests where they provide additional protection or clearer checks of important edge cases.
22
-
23
- High-priority targets:
24
-
25
- - Business-critical flows such as payment, authentication, authorization, subscriptions, and event publishing
26
- - Tasks and workers that are expensive to recover from when they fail
27
- - Complex queries, pagination, cursors, ordering, locks, and idempotency
28
- - Logic that interprets external system responses and mutates local state
29
- - Edge-case-heavy logic such as dates, timezones, market holidays, exchange rates, decimals, and discounts
30
-
31
- Lower-priority targets:
32
-
33
- - Simple getters, setters, and DTO declarations
34
- - Behavior already guaranteed by the library
35
- - Shape errors that static analysis, type checkers, or linters catch better
36
- - Tests that only repeat the implementation without improving behavioral safety
37
-
38
- ## 2. Test Scope Strategy
39
-
40
- Prefer tests that keep the real collaboration needed to deliver a feature intact. A test can exercise an API, service, repository, and DB together while protecting one clearly defined behavior. The number of participating components and the number of concerns being tested are separate choices.
41
-
42
- Apply [Focused Scenarios](common.md#focused-scenarios).
43
-
44
- Recommended approach:
45
-
46
- 1. First check whether the behavior can be tested through an existing public entrypoint from the perspective of a user or external system. Do not expand production interfaces solely for testing convenience.
47
- 2. Prefer integration tests when API, service, repository, DB, and cache behavior can be verified together clearly.
48
- 3. Narrow the scope one level when the integration test becomes too slow, too hard to set up, or too hard to debug.
49
- 4. Use unit tests directly for naturally small units such as pure calculations, parsers, and validators.
50
- 5. Replace external systems we do not control at the test boundary, such as third-party APIs, payment providers, email, and object storage.
51
-
52
- Why we prefer larger tests:
53
-
54
- - They catch real wiring, transaction, serialization, and dependency override issues.
55
- - They remain stable when internal calls change but the feature behavior stays the same.
56
- - They produce a signal closer to production behavior than tests with heavy mocking.
57
-
58
- When to narrow the scope:
59
-
60
- - The setup is so large that the important condition is hard to see.
61
- - The failure cause is difficult to isolate.
62
- - Replacing external dependencies takes up most of the test.
63
- - Slow tests start hurting the feedback loop.
64
- - One complex rule needs many focused edge-case checks.
65
-
66
- ## 3. Test Naming And Grouping
67
-
68
- Test names should reveal both the situation and the expected outcome.
69
-
70
- Basic rules:
71
-
72
- - Use `test_<situation>_<expected_outcome>` for test function names.
73
- - Every test should have a docstring.
74
- - For complex tests, use the docstring to describe the requirement or intent more specifically.
75
- - Prefer capability- and outcome-oriented names over implementation-shaped names.
76
- - Describe what the test actually exercises and observes. Do not claim to verify behavior that has been replaced by a test double.
77
- - Use `pytest.mark.parametrize` with readable `ids` for cases of the same behavior that share an execution flow. Split cases when combining them introduces branches that obscure their different scenarios.
78
-
79
- Example:
80
-
81
- ```python
82
- async def test_expired_subscription_removes_user_role(...) -> None:
83
- """An expired subscription removes the user's role."""
84
- ```
85
-
86
- Avoid implementation-shaped names:
87
-
88
- ```python
89
- async def test_calls_delete_role(...) -> None:
90
- ...
91
- ```
92
-
93
- ### 3.1 Class Grouping
94
-
95
- Use classes when related tests are easier to read as one group. Standalone test functions are appropriate when grouping adds no clarity.
96
-
97
- - Group tests by feature or public entrypoint.
98
- - Do not use classes to hide important setup or build complex lifecycles.
99
- - Each test inside the class should still be understandable on its own.
100
-
101
- ## 4. AAA Pattern
102
-
103
- Write test bodies in the `given / when / then` flow.
104
-
105
- - `given`: Data, fixtures, mocks, and fixed time required for the scenario
106
- - `when`: The behavior under test
107
- - `then`: Observable results of `when`, such as the response, DB state, events, and external calls
108
-
109
- Example:
110
-
111
- ```python
112
- async def test_expired_subscription_removes_user_role(...) -> None:
113
- """An expired subscription removes the user's role."""
114
- # given
115
- subscription = create_subscription(status="active", expired=True)
116
-
117
- # when
118
- await expire_subscriptions()
119
-
120
- # then
121
- assert not user_has_role(subscription.user_id, "premium")
122
- ```
123
-
124
- Notes:
125
-
126
- - If `when` contains several independent actions, it becomes unclear which action caused the failure.
127
- - One test may verify multiple results, but they should all come from the same behavior.
128
- - Use helpers when setup becomes long, but keep the important scenario conditions visible in the test body.
129
-
130
- ## 5. Layer-Specific Guidelines
131
-
132
- Use the largest layer that still gives a clear signal.
133
-
134
- - API tests are a good default when behavior is observable through HTTP. Verify the response contract and important side effects.
135
- - Service or domain tests are useful when the business rule is the main concern and an API test would be too heavy.
136
- - Repository or DAO behavior is usually covered through a higher-level test. Test it directly only when the query contract itself is the main risk.
137
- - Task and worker tests should focus on operational concerns such as duplicate handling, retries, partial failures, and idempotency.
138
- - Avoid API loops for large setup. Insert data directly or use helpers/factories when setup is not the behavior under test.
139
-
140
- ## 6. Fixture And Test Data
141
-
142
- Fixtures are tools for readability. They should not hide the important conditions of a test.
143
-
144
- Good fixtures:
145
-
146
- - Hide repeated infrastructure setup.
147
- - Provide common dependencies such as DB sessions, clients, caches, repositories, and services.
148
- - Make their provided state clear from the name.
149
-
150
- Fixtures to be careful with:
151
-
152
- - Fixtures that automatically create too many rows and make test conditions hard to trace.
153
- - Fixtures that hide the core condition of a scenario.
154
- - Fixtures that accept many scenario-specific parameters and become a small DSL.
155
- - Deep fixture dependency chains that make failures hard to diagnose.
156
-
157
- Recommended approach:
158
-
159
- - Promote helpers or fixtures to a shared place when multiple domains reuse them.
160
- - Keep domain-specific helpers near that domain.
161
- - Keep scenario-specific core conditions in the test body.
162
- - Reuse established setup helpers when their behavior is outside the test's concern.
163
- - Extract helpers to make scenarios easier to understand, not just to remove repeated lines. A little duplication is preferable to an abstraction that hides the important conditions or execution flow.
164
- - Use helper and factory names that reveal intent. Examples: `create_expired_subscription`, `create_verified_user`
165
- - Create only the minimum rows required by the test.
166
-
167
- ### 6.1 DB Setup
168
-
169
- - Isolate DB changes with transaction rollback whenever possible.
170
- - Use `flush` when DB-generated values or query-visible rows are needed.
171
- - Use `commit` only when verifying behavior that is visible only after commit, across separate transactions, or through task/worker entrypoints.
172
- - Do not clean tables manually in tests. Before adding cleanup fixtures, confirm why transaction rollback cannot solve the problem.
173
- - Prefer DB bulk inserts over API loops for large setup.
174
-
175
- ### 6.2 Cache And External State
176
-
177
- - Prefer shared fixtures for cache cleanup, dependency overrides, monkeypatches, and environment overrides.
178
- - Do not repeat cleanup setup in individual tests when the repository already handles it globally.
179
- - Verify cache keys, TTLs, and session values directly when they are part of the contract.
180
-
181
- ## 7. Test Double Policy
182
-
183
- Use test doubles to move the external world and unstable inputs to the test boundary.
184
-
185
- Good targets for test doubles:
186
-
187
- - Payment providers, Google Play, Apple, Firebase, S3, Discord, email, and Kafka producers
188
- - Other servers or external HTTP clients
189
- - Current time, randomness, and UUIDs
190
- - Very slow or nondeterministic library calls
191
-
192
- Avoid replacing when possible:
193
-
194
- - Services, repositories, and DAOs in the same process
195
- - Internal helpers called by the function under test
196
- - Private properties or private methods
197
- - The DB session itself
198
- - The entire service behind an endpoint
199
-
200
- Guidelines:
201
-
202
- - Test doubles should make the test condition clearer.
203
- - If replacing internal collaborators makes the test fragile during refactoring, switch to a larger-scope test.
204
- - If a dependency is already mocked at an upper boundary, do not also mock the lower DAO unnecessarily.
205
- - Use `spec` or real-object-based `patch.object` for `Mock` and `AsyncMock` whenever possible.
206
- - Patch where the object is used, not where it is defined.
207
-
208
- Partial replacement can be better than replacing the whole object. For example, instead of replacing an entire external client, create the client through the real factory and patch only the failing method. This keeps more framework wiring intact.
209
-
210
- ## 8. Time, Randomness, And Determinism
211
-
212
- Tests should produce the same result every time they run.
213
-
214
- - Freeze or patch the current time.
215
- - When timezone behavior matters, assert the base timezone, UTC conversion, and epoch values explicitly.
216
- - Use fixed values when randomness, UUIDs, or current time appear in DB values or responses.
217
- - For ordering-sensitive tests, make `created_at`, `id`, and cursor values explicit.
218
- - External API response fixtures should contain only the fields needed, but enough fields to represent the edge case.
219
-
220
- ## 9. Assertions
221
-
222
- Good assertions make it clear what broke when the test fails.
223
-
224
- Recommended:
225
-
226
- - In API tests, assert `status_code` first.
227
- - Use snapshots or exact dictionaries when the whole response is the contract.
228
- - Assert only the important fields explicitly when only some fields are contractual.
229
- - Verify DB side effects by reading them back through a repository or query.
230
- - Assert downstream contracts directly, such as event payloads, unique keys, and published flags.
231
- - For lists, assert length, order, and important identifiers together.
232
-
233
- Avoid:
234
-
235
- - Assertions that provide little signal, such as `assert response.json() is not None`
236
- - Overly broad snapshots that fail on unrelated field changes
237
- - Tests that only assert mock call counts without verifying actual state changes
238
- - Recomputing the expected value with the same logic as the implementation under test
239
-
240
- ## 10. Snapshot Usage
241
-
242
- Snapshots are useful when protecting large JSON responses or complex payload contracts.
243
-
244
- Use snapshots when:
245
-
246
- - The entire response structure is part of the API contract.
247
- - Volatile values are stabilized with matchers, fixed time, or fixed IDs.
248
- - Snapshot updates are intentional and reviewed in the same PR as the code change.
249
- - The diff is small enough for reviewers to understand.
250
-
251
- Avoid snapshots when:
252
-
253
- - Only a few fields matter.
254
- - The collection ordering is not stable.
255
- - Timestamps, UUIDs, or ordering change on every run.
256
- - The payload is so large that failures are hard to interpret.
257
-
258
- ## 11. Coverage
259
-
260
- Coverage is a signal, not the quality goal itself.
261
-
262
- - Whether changed code protects important branches and failure cases matters more than total coverage.
263
- - If PR coverage is low, explain why the code does not need tests or which higher-level test covers it.
264
- - Use missing lines in the coverage report to find candidate test targets.
265
- - Do not add meaningless tests just to increase coverage.
266
-
267
- ## 12. Review Checklist
268
-
269
- Apply the [Review Checklist](common.md#review-checklist), and check the implementation and remaining risks:
270
-
271
- - If the scope was narrowed, is the reason clear?
272
- - Do the name and docstring accurately describe what the test exercises and observes?
273
- - Is the `given / when / then` flow clear?
274
- - Can DB, cache, and dependency overrides leak between tests?
275
- - Are time, UUIDs, randomness, and ordering deterministic?
276
- - Are necessary failure, permission, and authentication cases covered?
277
- - Are backend-specific concerns such as pagination, cursors, idempotency, and transactions covered?
278
- - If a snapshot is used, can reviewers understand the diff?
279
- - If test doubles keep increasing, should the test move to a larger scope?
280
- - If fixtures hide too many conditions, should those conditions move back into the test body?
@@ -1,30 +0,0 @@
1
- # Common Testing Standards
2
-
3
- Sections shared by [frontend.md](frontend.md) and [backend.md](backend.md).
4
-
5
- ## Test Target Value
6
-
7
- Do not try to test all code at the same density. Evaluate the protection each test adds to the existing suite against the cost of writing, reading, running, and maintaining it. The goal is reliable protection of important behavior, not the fewest tests or the highest coverage number.
8
-
9
- - Before adding or retaining a test, identify the important regression it catches that existing tests do not adequately cover.
10
- - When a new feature reuses shared behavior, check what existing tests already protect. Add tests for how the feature uses that behavior and for any differences in its contract, rather than copying all tests for the shared behavior.
11
- - Before removing a test, confirm that important requirements and failure cases remain protected.
12
-
13
- ## Focused Scenarios
14
-
15
- Keep each scenario focused on its intended behavior. Combine multiple actions when their sequence is itself the requirement, not merely because they can be placed in one workflow. Do not extend an existing test with unrelated assertions for a new feature when that behavior belongs in another test.
16
-
17
- ## Review Checklist
18
-
19
- Start with the test's purpose and contribution to the suite:
20
-
21
- 1. What important behavior does this test protect beyond the protection already provided by other tests?
22
- 2. Does it contain only the setup, actions, and assertions needed for that behavior?
23
- 3. Can a reader immediately understand the conditions, action, and expected outcome?
24
-
25
- Then check:
26
-
27
- - Would this test actually fail if that behavior broke?
28
- - Does it preserve useful collaboration between real components while keeping its concern focused?
29
- - Does the test verify externally observable behavior instead of internal implementation?
30
- - Do test doubles replace external or unstable dependencies without replacing the behavior under test?