con un clic
tdd
Test-Driven Development with vertical slices and tracer bullets
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
Test-Driven Development with vertical slices and tracer bullets
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
Manage OMA skills — list, add, remove, search, and edit skills
Socratic deep interview with mathematical ambiguity gating before autonomous execution
Remove AI slop - low-quality, generic, or verbose content. Use for "clean up", "remove fluff", and "make concise".
Consensus planning - agree before executing. Use for "ralplan", "consensus", "pre-execution review".
Setup routing and environment configuration. Use for "setup", "configure", and "get started".
N coordinated agents on shared task list using Claude Code native teams, with git worktree isolation per executor
| name | tdd |
| description | Test-Driven Development with vertical slices and tracer bullets |
| triggers | ["/oma:tdd"] |
| Tool | When to Use |
|---|---|
Bash (test runner) | Run npm test, pytest, go test, or equivalent to get fast per-file feedback during RED-GREEN cycles. |
Write / Edit | Write failing test first (RED), then write minimal production code (GREEN), then clean up (REFACTOR). |
mcp__plugin_oh-my-claudecode_t__lsp_diagnostics | Catch type errors and missing imports immediately after edits. |
mcp__plugin_oh-my-claudecode_t__lsp_diagnostics_directory | Run full project diagnostics before marking a cycle done. |
Grep | Find existing tests for the same module before writing a new one — avoid duplication. |
Glob | Locate test files matching the module under development. |
Typical cycle:
Write to the test file.Bash to confirm the failure.Edit the production file.mcp__plugin_oh-my-claudecode_t__lsp_diagnostics on both files.Edit production code, confirm tests stay green.TDD provides a tight feedback loop that keeps implementation anchored to behavior. Without it, code grows inward — implementation details proliferate, coupling increases, and tests (when written at all) fight the code instead of guiding it.
The OMC-specific variant emphasizes vertical slices via tracer bullets rather than horizontal layering. Horizontal TDD (write all tests for Layer A, then all for Layer B) produces integration gaps: every layer compiles in isolation but the system fails end-to-end. Vertical TDD traces one complete path from user input to data storage before moving to the next slice, delivering working software incrementally.
Deep modules are preferred because they minimize the interface surface you must test, making each test more powerful and easier to reason about. A large, well-hidden implementation behind a small interface is easier to verify, easier to refactor, and cheaper to change.
A test for a user-authentication module:
// auth.test.ts
import { authenticate } from './auth';
describe('authenticate', () => {
it('returns a session token when credentials are valid', async () => {
const token = await authenticate({ username: 'alice', password: 'secret123' });
expect(token).toMatch(/^[a-z0-9]{32}$/);
});
it('throws AuthError when password is incorrect', async () => {
await expect(
authenticate({ username: 'alice', password: 'wrong' })
).rejects.toThrow('Invalid credentials');
});
});
Notice: tests describe what the function returns and when it throws — not how it works internally.
// auth.ts
import crypto from 'crypto';
export class AuthError extends Error {
constructor(message: string) {
super(message);
this.name = 'AuthError';
}
}
const VALID_CREDENTIALS = { alice: 'secret123' };
export async function authenticate({
username,
password,
}: {
username: string;
password: string;
}): Promise<string> {
const expected = VALID_CREDENTIALS[username];
if (!expected || expected !== password) {
throw new AuthError('Invalid credentials');
}
return crypto.randomBytes(16).toString('hex');
}
This is the minimum code to make both tests pass. It is not the final architecture — it is the seed. The test survives refactoring because it tests behavior, not implementation.
The first green pass exposes that the credentials check and token generation are interleaved. Refactor to a deep module:
// credentials.ts (deep module — small interface, large hidden implementation)
const STORE = new Map<string, string>(); // currently in-memory; swap to DB later
export async function checkCredentials(username: string, password: string): Promise<boolean> {
const stored = STORE.get(username);
return stored !== undefined && stored === password;
}
export async function addCredential(username: string, password: string): Promise<void> {
// future: hash before storing
STORE.set(username, password);
}
The authenticate function becomes a thin, shallow orchestrator that delegates to deep modules. Tests for authenticate do not change — they only test the public interface.
Slice 1 — Register and retrieve a user
// user.test.ts
it('stores a user and retrieves them by id', async () => {
const id = await registerUser({ username: 'bob', password: 'pw' });
const user = await getUser(id);
expect(user.username).toBe('bob');
});
Write minimal code: in-memory store, registerUser writes to it, getUser reads back.
Slice 2 — Reject duplicate usernames
it('throws DuplicateError when username is already taken', async () => {
await registerUser({ username: 'bob', password: 'pw' });
await expect(
registerUser({ username: 'bob', password: 'pw2' })
).rejects.toThrow('Duplicate username');
});
Add the check to the existing registerUser — no new classes, no abstraction layers yet.
Slice 3 — Persist to database
Swap the in-memory store for a real DB adapter. Tests pass unchanged because the interface is the same.
Horizontal TDD would have written all in-memory tests, then all DB tests, then all business-logic tests — producing a large integration gap before any slice works end-to-end. Vertical TDD delivered a working registration flow after Slice 1.
lsp_diagnostics_directory reports zero errors.Run through these before marking a TDD cycle complete:
Is this test focused on a PUBLIC interface, not internals?
Test authenticate(params) — not authenticate._tokenCache or any private state.
Does the test describe BEHAVIOR, not implementation?
"returns a session token when credentials are valid" is behavior.
"calls crypto.randomBytes" is implementation — avoid it.
Will this test SURVIVE refactoring?
If you refactor credentials.ts internals, does this test still pass?
If not, the test is coupled to internals — rewrite it.
Is the code I wrote the MINIMAL amount to pass? No early optimization. No generalized abstractions. No extra parameters. Write what makes the test pass, nothing more.
Is this slice vertical — does it span from input to storage? If you only added a DB call without connecting it to the public API, the slice is incomplete.
Before declaring a TDD skill session complete:
npm test (or equivalent) runs green with zero failures.lsp_diagnostics_directory reports zero errors across the modified package.TODO, HACK, debugger, or console.log statements remain in production or test code.