一键导入
tdd
Write tests following TDD cycle and BDD conventions with domain-first coding philosophy
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Write tests following TDD cycle and BDD conventions with domain-first coding philosophy
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Produce a shareable, non-technical feature guide as a published Artifact — live screenshots of every surface in the feature's story, captured from the running dev app with Playwright (including interaction states: open menus, drawers, drill-downs), annotated with numbered callout dots and plain-language legends, organized around the feature's own mental model (levels, flow, or lifecycle), with "reading the numbers", "what it can't show (yet)", and "who can see it" sections. Self-contained HTML (base64-embedded images, light + dark themes, project brand tokens) published via the Artifact tool and iterated in place at the same URL.
Build or refactor a great Shopify `maintenance_tasks` Task (Rails) — the full design, not just batching. Starts from the decision that shapes everything — which of the four collection shapes fits: an AR **Relation** (per-record `process`), a **`Model.in_batches(of: N)`** batch enumerator (one set-based bulk write per batch), a plain **Array** (small finite computed collections like catalogs or date ranges), or **`no_collection`** (a single atomic SQL statement, no iteration) — then layers on idempotency, large-table timeout rules, callback/PaperTrail-aware writes, and the opt-in features (dry-run, attributes, throttling, callbacks). Encodes the traps agents hit repeatedly: a collection Relation must carry NO `ORDER BY`/`LIMIT` (the cursor adds its own PK ordering and it raises at runtime); `find_each` ignores a custom `order`; never override `count` for a batch enumerator; prefer the collection API over `no_collection` so you get progress + pause/resume; data backfills belong in a task, not a migration; use `
Write code comments deliberately — sparingly, only when they add real value, in plain natural-language prose rather than dense justification. The default is no comment: let names and structure speak. A comment earns its place only when it tells a future reader something they could NOT infer from the code — a non-obvious WHY, a gotcha, a load-bearing decision, or a grep anchor for a source-of-truth table. Strips the recurring failure modes: restating the method name, narrating mechanics the reader can see, baking in transient snapshot facts (row counts, "for V1"), citing planning docs, sprinkling ADR refs on routine code, and writing in a verbose PR-description register. Also fixes the VOICE — terse, present-tense, stating the noun-fact or the gotcha-with-"so". Use BEFORE writing or editing any inline/method/class comment, and when reviewing or auditing comments in a changeset. If you are about to type a `#` comment in Ruby (or `//`, `/* */`, `<%# %>` elsewhere), this applies. Triggers: writing a new method/cl
Decide WHERE new domain code lives so a codebase organized by bounded context stays predictable as contexts get added — the rule a contributor (agent or human) follows before introducing a new domain noun. Models the domain in two coordinates: which bounded context owns the code (slices by meaning) and which layer it sits in (slices by dependency direction), with one hard rule — dependencies point down, a lower layer never names a higher one. Places behavior by KIND not amount (record / domain / framework), namespaces by ownership not reference, names from domain language not one customer's vocabulary, and treats boundary purity as a default with an evidence-based escape valve, never a tax. The durable rule lives here; each project's own contexts table and migration state live in its .claude/bounded_contexts.md, which this skill reads (and offers to scaffold when missing). Loads a frameworks/<stack>.md appendix for stack-specific placement (e.g. Rails directory coupling) and degrades to generic shapes when no
Systematically answer "where does this data actually come from?" questions — is X the source of truth, why did Y stop updating, which table feeds this surface — by combining production-query evidence with code-path and git-history tracing, then producing an evidence-grounded results document where every claim cites a query result or a file:line. Enforces a strict evidence-first discipline: frame competing hypotheses, trace write paths before read paths, profile the grain BEFORE filtering, reconcile by a globally-unique key, quantify coverage and leaks, and refute your own hypotheses out loud. No claim ships without a citation; no number ships without the query that produced it. Opportunistically uses any connected MCP servers (read-only production DB, hosting/deploy logs, observability) to deepen the evidence, and degrades gracefully to local tooling when they aren't present.
基于 SOC 职业分类
| name | tdd |
| description | Write tests following TDD cycle and BDD conventions with domain-first coding philosophy |
| allowed-tools | ["Read","Edit","Write","Glob","Grep","Bash(bin/rspec:*)","Bash(bundle exec rspec:*)","Bash(bin/rails test:*)","Bash(bundle exec rake test:*)","Bash(ruby -Itest:*)","Bash(npm test:*)","Bash(npx vitest:*)","Bash(npx jest:*)","Bash(yarn test:*)","Bash(pnpm test:*)","Bash(go test:*)","Bash(pytest:*)","Bash(python -m pytest:*)","Bash(python -m unittest:*)","Bash(uv run pytest:*)","Bash(poetry run pytest:*)","Bash(bats:*)","Agent"] |
| when_to_use | Use when the user asks to implement a feature, fix a bug, add a spec, or do any code change that should follow TDD. This includes when the user says 'go ahead', 'let's do it', 'start', 'begin', or similar to kick off previously discussed implementation work. If you are about to write production code or test files, this skill applies. Examples: 'add filtering to transactions', 'fix the zero-amount bug', 'write tests for the parser', 'TDD this', 'implement...', 'go ahead'. |
Every code change follows RED → GREEN → REFACTOR. Tests describe behavior in domain language. Implementation is minimal and domain-first.
Before writing any test, identify the project's test runner and load the
matching reference file from frameworks/:
| Signal | Reference |
|---|---|
Gemfile with rspec-rails/rspec or a spec/ dir | frameworks/rspec.md |
Gemfile with minitest or a test/ dir (Rails default) | frameworks/minitest.md |
package.json using vitest or jest | frameworks/vitest.md |
go.mod present | frameworks/go.md |
pyproject.toml/requirements*.txt/setup.py, or tests/test_*.py, or a conftest.py | frameworks/python.md |
*.bats files or a test/bats/ dir | frameworks/bats.md |
If the signal is ambiguous or missing, ask the user which runner to use. Read the framework file once per session — it supplies the exact run commands, file paths, idiomatic test syntax, factory conventions, language idioms, and framework-specific anti-patterns for the universal rules below.
Read the relevant modules and existing tests. You should be able to articulate in one sentence, in domain language, what behavior will change. Check how tests are organized in this repo, and which factory/fixture helpers already exist.
Success criteria: you can name the behavior under test using ubiquitous language from the domain.
Write one test describing the desired behavior. Run it and confirm it fails with a meaningful message.
BDD naming (principle — see the framework file for exact syntax):
Test quality (universal, non-negotiable):
Multi-write unit check: if the behavior under test writes more than one
record — a loop of saves, a service touching several rows, or "X and Y" /
"as a unit" / "whole cloth" in the test name — the unit needs an explicit
atomicity decision (usually a transaction) and the test list needs a
rollback test. Raising on failure is not atomicity: an exception mid-way
rolls back nothing already committed. Write the rollback test to fail a
later record so an earlier record's committed write proves the rollback
(fail-on-first is vacuous — it passes even without a transaction).
Framework-specific traps live in the matching frameworks/*.md.
Success criteria: the test fails with a message that clearly shows what behavior is missing.
Write the simplest code that makes the failing test pass. Run the test.
Rules (universal):
Success criteria: the new test passes, no other tests break, the implementation is the simplest thing that works.
If the code benefits from restructuring, do it now. Tests are the safety net.
Success criteria: all tests still pass, code is cleaner, no behavior changed.
If the feature has multiple slices, loop back to Step 2. Each slice is one RED → GREEN → REFACTOR cycle producing one atomic, independently revertable change.
Feature rhythm:
Cycle 1 → feat: display transaction list
Cycle 2 → feat: add date range filter
Cycle 3 → refactor: extract query scope (optional)
Cycle 4 → feat: add pagination
Bug fix rhythm:
Cycle 1 → fix: handle zero-amount fee calculation
(regression test + fix in one commit)
Success criteria: every cycle has a passing test suite; commit history reads like a changelog.
If you catch yourself doing any of these, stop and correct:
| Smell | Fix |
|---|---|
| Writing implementation before the test | Stop. Write the test first. |
| Test name describes a method instead of behavior | Rename to describe the behavior |
| Mocking a method on the unit under test | Test the outcome instead |
| Reaching into private members from a test | Test through the public interface |
| Test with 10+ assertions | Split into separate test blocks |
| Constructing objects directly when factories exist | Use the project's factory helper |
| Adding features the test didn't ask for | Delete them. Stay GREEN. |
| Extracting an abstraction on first use | Wait for the third use |
| Multiple writes between entry and return, atomicity undecided | Wrap the unit in a transaction; add a rollback test that fails a later record |
| Adding a retry to silence a flaky test | Find the cause — a flake is a false negative. See Flaky tests |
Framework-specific anti-patterns live in the matching frameworks/*.md.
A flaky test passes or fails on the same code. It's a false negative that makes every red ambiguous, so fix the cause — never paper over it with a retry. Almost all flakes fall into two families:
See the matching frameworks/*.md for the exact freeze-time and wait helpers.