Skill: dachunggan/coding-contract (version 1.0.0)

--- name: coding-contract description: > Generate language-agnostic coding contracts (spec.md) from requirements. Outputs interface signatures, behavioral constraints, and verification checklists — never implementation code. Designed for the "strong model writes spec, weak model writes code" workflow. Spec files are reusable knowledge artifacts: write once, implement in any language. Use when the user wants to create a coding spec, define interfaces before implementation, or build a reusable engineering contract. Triggers on: "写规范", "生成 spec", "定义接口", "做实现蓝图", "coding contract", "implementation spec", "technical specification", or when a brainstorming design document needs to be converted into an actionable engineering plan. --- # Coding Contract Generator Generate coding contracts that capture engineering knowledge as persistent, language-agnostic artifacts. A contract defines WHAT to build and WHAT CONSTRAINTS to respect, but never HOW to implement it. Any developer or AI agent, in any language, can implement the same contract and produce functionally equivalent code. Produce spec.md files containing interface definitions, behavioral constraints, and verification checklists — never complete implementations. ## Core Principles ### Iron Rules (Non-Negotiable) 1. **NO COMPLETE CODE**: Output interface signatures and pseudocode only. Never write function bodies, class implementations, configuration files, or executable scripts. The implementer writes the code; you write the contract. 2. **CONSTRAINTS ARE MANDATORY**: Every spec MUST include a Constraint Layer (Section 4). If you think "this is obvious", write it anyway. The implementer may not share your assumptions. 3. **EVERY INTERFACE MUST HAVE TESTS**: For each public function in Section 3, at least one test case MUST exist in Section 5. Untested interfaces are unspecified interfaces. 4. **NO HARDCODED MAGIC VALUES**: Use descriptive placeholders (e.g., `[TIMEOUT_MS]`, `[MAX_RETRY_COUNT]`) or explain where the value comes from (e.g., "configured via environment variable"). Never embed literal numbers without context. 5. **SELF-VALIDATE BEFORE OUTPUT**: After drafting the spec, check against the Self-Validation Checklist below. Fix gaps before presenting. 6. **LANGUAGE-AGNOSTIC**: This skill works for any software domain — mobile, backend, frontend, embedded, ML, data pipelines. Do not assume a specific tech stack unless the user provides one. ## Workflow ### Phase 1: Requirement Ingestion Determine the input mode: **Mode A — Brainstorming Document Available:** If the user provides a design document from a brainstorming session, read it carefully. Extract: feature scope, module boundaries, tech stack preferences, data models, and user-approved decisions. Proceed to Phase 2. **Mode B — Raw Requirement (No Prior Design):** If the user provides only a natural language description, conduct a structured clarification dialog. Ask as many questions as needed — there is no limit. Goal: resolve all ambiguity before writing a single line of spec. Clarification topics to cover (ask selectively based on context): - **Scope**: What is in-scope vs. out-of-scope for this feature? - **Users/API Consumers**: Who calls this code? Human users, internal services, external API clients? - **Tech Stack**: Any language, framework, or library constraints? - **Existing Codebase**: Are we extending existing modules or creating new ones? - **Quality Requirements**: Performance targets, availability SLAs, security compliance needs? - **Failure Expectations**: What happens when things go wrong? Crash, degrade, retry, notify? - **Data & State**: Persistent storage? Caching? Real-time or batch? - **Integration Points**: External APIs, message queues, third-party services? - **Non-Functional**: Concurrency model, deployment constraints, regulatory requirements? Continue asking until the user confirms the picture is complete. Better to over-communicate than to guess. ### Phase 2: Context Analysis Read relevant existing code if available: - Identify current architecture patterns (layered, hexagonal, microservices, etc.) - Note existing conventions for naming, error handling, and module organization - Mark integration points where new code must connect to old code - Respect existing conventions; do not introduce foreign patterns unless explicitly requested If no existing codebase (greenfield), establish default conventions based on industry best practices for the chosen tech stack. Document these decisions in Section 6. ### Phase 3: Spec Generation Write the spec following the structure in `references/spec-template.md`. Key generation rules: - **Section 1 (Overview)**: One-paragraph goal. Explicit scope boundaries with "IN: ... OUT: ..." format. - **Section 2 (Module Structure)**: Directory tree (max 3 levels). Each module gets a one-sentence responsibility description. Arrows show dependencies. - **Section 3 (Interface Definitions)**: - Public function signatures with input/output types - Data class fields with types and semantic meaning - Thrown exceptions and their conditions - Pseudocode only — `// implementation left to implementer` - Group by module - **Section 4 (Constraint Layer)** — NEVER skip: - Performance (latency, throughput, memory, cpu) - Degradation strategies for each external dependency - Boundary conditions (empty input, null, max size, concurrency) - Threading model (what runs where, synchronization) - Security (auth, encryption, input validation, secrets handling) - Refer to `references/constraint-patterns.md` for common patterns. - **Section 5 (Verification Checklist)**: - Unit tests: input → expected output, including error cases - Integration tests: multi-component scenarios - Performance tests: measurable benchmarks - Use checkboxes (`- [ ]`) for trackability - **Section 6 (Decisions)**: - Architecture choices with rationale - Trade-offs made (what was sacrificed and why) - Explicit user approvals on contentious decisions ### Phase 4: Self-Validation Before output, verify: - [ ] Every public function in Section 3 has at least one test in Section 5 - [ ] Section 4 (Constraint Layer) is non-empty - [ ] No executable code appears in the spec (only signatures and pseudocode) - [ ] No hardcoded magic numbers without explanation - [ ] All external dependencies are listed with their purpose - [ ] No ambiguous language: "appropriate", "reasonable", "etc.", "as needed" — replace with precise definitions - [ ] Error cases are explicitly defined (not just "handle errors gracefully") - [ ] Threading model is specified (what runs on main thread vs. background) If any check fails, revise the spec and re-validate. ### Phase 5: Delivery Output the complete spec as a file named `spec.md`. Prefix with: ``` <!-- Generated by coding-contract skill --> <!-- This is a coding contract — interface signatures and constraints only, not implementation code --> <!-- Implementer: fill in all [PLACEHOLDER] values before coding --> ``` Save the file. Do not proceed to implementation unless explicitly asked. ## Output Location Default: `docs/specs/YYYY-MM-DD-<feature-name>.md` Override: If the user specifies a location, use theirs. ## References - **Output template**: Read `references/spec-template.md` for the complete spec.md format with annotated examples. - **Constraint patterns**: Read `references/constraint-patterns.md` when writing Section 4 to ensure comprehensive coverage.

path: references/constraint-patterns.md
content: # Constraint Patterns Reference

Use this reference when writing Section 4 (Constraint Layer) of a spec.
Copy relevant patterns and adapt to the specific domain. This is a catalog,
not a checklist — include only constraints that apply to the feature.

## Table of Contents

1. [Performance Patterns](#performance-patterns)
2. [Degradation Patterns](#degradation-patterns)
3. [Boundary Condition Patterns](#boundary-condition-patterns)
4. [Threading & Concurrency Patterns](#threading--concurrency-patterns)
5. [Security Patterns](#security-patterns)
6. [State & Persistence Patterns](#state--persistence-patterns)
7. [Error Handling Patterns](#error-handling-patterns)

---

## Performance Patterns

### API / Service Latency

| Metric | Typical Targets | Measurement |
|--------|----------------|-------------|
| API response (p50) | < 50 ms | Endpoint load test |
| API response (p95) | < 200 ms | Endpoint load test |
| API response (p99) | < 500 ms | Endpoint load test |
| Database query | < 20 ms (simple), < 100 ms (complex) | Query analyzer |
| Cache hit | < 5 ms | Redis latency monitor |
| Cache miss penalty | < 2x baseline | Comparative test |

### Throughput

| Scenario | Target | Test Method |
|----------|--------|-------------|
| HTTP API | 1000+ req/s per instance | k6, Artillery, locust |
| Message processing | 10,000+ msg/s per consumer | Producer/consumer benchmark |
| Batch job | Process 1M records in < 1 hour | End-to-end timing |
| File upload | 100 MB/s sustained | Direct upload test |

### Resource Usage

| Resource | Typical Limit | Context |
|----------|--------------|---------|
| Memory per instance | < 512 MB (container), < 2 GB (VM) | RSS after warm-up |
| CPU per request | < 10 ms CPU time | Flame graph analysis |
| Disk I/O | Sequential read > 100 MB/s | fio benchmark |
| Connection pool | Max 20 DB connections | Pool exhaustion test |

---

## Degradation Patterns

### Dependency Failure Matrix

| Dependency State | Behavior | Example |
|------------------|----------|---------|
| **Healthy** | Normal path, full features | All services operational |
| **Degraded (slow)** | Timeout fallback, cached data, reduced freshness | Cache returns stale data with warning header |
| **Degraded (partial)** | Disable non-critical features, core path works | Payment down → browse still works, checkout blocked |
| **Unavailable** | Circuit breaker open, fail fast with clear error | Return 503 with retry-after header |

### Common Fallback Strategies

| Strategy | When to Use | Implementation |
|----------|-------------|----------------|
| **Cache fallback** | Read-heavy, stale data acceptable | Return cached value with `X-Cache: stale` header |
| **Static fallback** | Configuration or content data | Serve last-known-good default |
| **Simplified logic** | Complex computation | Skip ML model, use heuristic rule |
| **Queue & retry** | Write operations | Persist to dead-letter queue, retry with backoff |
| **Graceful reduction** | Resource exhaustion | Reduce batch size, lower quality, partial results |
| **Feature toggle off** | Non-critical feature | Disable feature, hide UI element, log metric |

### Circuit Breaker Configuration

| Parameter | Typical Value | Description |
|-----------|--------------|-------------|
| Failure threshold | 5 errors in 60 seconds | Trip breaker after this many failures |
| Timeout duration | 5 seconds | Consider call failed after this time |
| Recovery timeout | 30 seconds | Wait before attempting half-open test |
| Half-open requests | 1 request | Test with this many requests in half-open state |

---

## Boundary Condition Patterns

### Input Validation

| Category | Check | Error Response |
|----------|-------|----------------|
| **Null / Undefined** | Reject at API boundary | `400 Bad Request`, field-level error |
| **Empty collection** | Return empty result, not error | `200 OK` with `[]` |
| **Empty string** | Reject if meaningful; accept if optional | `400` if required; allow `""` if optional |
| **Max length** | Enforce on all string inputs | `400` with max length info |
| **Max payload** | Check Content-Length or body size | `413 Payload Too Large` |
| **Type mismatch** | Schema validation at entry point | `400` with type error detail |
| **Range validation** | Numeric fields: min, max | `400` with allowed range |
| **Enum validation** | Unknown enum value rejected | `400` with allowed values |
| **Format validation** | Email, UUID, date format | `400` with format specification |
| **Duplicate detection** | Unique key violation | `409 Conflict` with existing resource |

### Concurrency Boundaries

| Scenario | Expected Behavior |
|----------|-------------------|
| **Concurrent reads** | Safe without locking (immutable data or read replicas) |
| **Concurrent writes to same record** | Optimistic locking with version field; last write wins rejected |
| **Concurrent creates with same unique key** | Idempotency key deduplication; second request returns existing |
| **Rate limit exceeded** | `429 Too Many Requests` with `Retry-After` header |
| **Resource pool exhausted** | Queue with timeout; fail with `503` if queue full |
| **Distributed race condition** | Atomic compare-and-swap or distributed lock with TTL |

### Data Volume Boundaries

| Scenario | Limit | Behavior |
|----------|-------|----------|
| **Max page size** | 100 items | Reject larger with `400` |
| **Max export rows** | 100,000 | Stream response; reject larger with `400` |
| **Max file upload** | 50 MB | Reject with `413` |
| **Max batch operation** | 1,000 items | Reject larger; suggest chunking |
| **Max nested depth** | 10 levels | Reject circular/deep nesting |
| **Max total result set** | 10,000 | Paginate; return total count |

---

## Threading & Concurrency Patterns

### Execution Context Model

| Model | Use Case | Risk |
|-------|----------|------|
| **Single-threaded event loop** | I/O-bound, high concurrency | CPU-intensive tasks block loop |
| **Thread pool (fixed)** | CPU + I/O mixed | Thread exhaustion, context switching overhead |
| **Coroutine / async** | Many concurrent I/O operations | Complex error handling, debugging |
| **Actor model** | Stateful entities with message inbox | Mailbox overflow, ordering assumptions |
| **Fork-join** | Parallel decomposition of large task | Split overhead, load imbalance |

### Synchronization Patterns

| Pattern | When to Use |
|---------|-------------|
| **Mutex / Lock** | Short critical sections, low contention |
| **Read-Write Lock** | Read-heavy, rare writes |
| **Atomic operations** | Counters, flags, simple state changes |
| **Channel / Queue** | Producer-consumer, backpressure handling |
| **Semaphore** | Resource pool limiting |
| **Barrier** | Parallel phases requiring synchronization point |
| **CAS loop** | Lock-free updates to single variable |

### Common Anti-Patterns to Avoid

| Anti-Pattern | Problem | Fix |
|--------------|---------|-----|
| **Holding lock during I/O** | Blocks all other threads | Release lock before I/O, re-acquire after |
| **Nested locks** | Deadlock risk | Always acquire in same order, or use timeout |
| **Unbounded queues** | OOM under load | Use bounded queue with rejection policy |
| **Thread-local for request context** | Leaks in async/coroutine models | Use explicit context propagation |
| **Fire-and-forget without timeout** | Resource leak | Always set timeout on async operations |

---

## Security Patterns

### Authentication Patterns

| Pattern | Use Case | Notes |
|---------|----------|-------|
| **JWT (stateless)** | Microservices, SPA | Short expiry (15 min), refresh token rotation |
| **Session cookies** | Server-rendered web apps | HttpOnly, Secure, SameSite=Strict |
| **API keys** | Service-to-service | Rate limit per key, allow key rotation |
| **mTLS** | Internal service mesh | Certificate expiry monitoring |
| **OAuth 2.0 + OIDC** | Third-party login | PKCE for SPAs, state parameter for CSRF |

### Authorization Patterns

| Pattern | Use Case |
|---------|----------|
| **RBAC (Role-Based)** | Few roles, clear permissions (admin, user, guest) |
| **ABAC (Attribute-Based)** | Fine-grained, context-aware (department + time + location) |
| **Resource-level ACL** | Per-object permissions (user owns this document) |
| **Policy engine (OPA)** | Complex, changing rules; centralized decision |

### Input Security

| Check | Implementation |
|-------|----------------|
| **SQL injection** | Parameterized queries only; never string concatenation |
| **NoSQL injection** | Validate query operators; sanitize user input |
| **Command injection** | Never pass user input to shell; use exec with array args |
| **XSS prevention** | Output encoding on all user content; CSP headers |
| **Path traversal** | Canonicalize paths; reject `..`; whitelist allowed directories |
| **SSRF prevention** | Validate URLs against allowlist; block internal IPs |
| **XML External Entity** | Disable XXE parsing; use JSON instead |

### Secrets Management

| Secret Type | Storage | Access Pattern |
|-------------|---------|----------------|
| **Database credentials** | Vault / Secret Manager | Runtime injection, rotate monthly |
| **API keys (internal)** | Environment variables | Never log, never commit |
| **API keys (external)** | Encrypted database | Per-customer, rotate on compromise |
| **Encryption keys** | HSM / KMS | Never leave secure enclave |
| **JWT signing keys** | Secure key store | Rotate with grace period for old keys |

---

## State & Persistence Patterns

### Consistency Models

| Model | Use Case | Trade-off |
|-------|----------|-----------|
| **Strong consistency** | Financial transactions, inventory | Higher latency, lower availability |
| **Read-after-write** | User profile update | Slight latency increase |
| **Eventual consistency** | Social feed, analytics | Lower latency, stale reads possible |
| **Causal consistency** | Collaborative editing | Captures happens-before relationships |
| **Monotonic reads** | Timeline / stream | Guarantees forward progress in reads |

### Isolation Levels

| Level | Use When | Anomalies Allowed |
|-------|----------|-------------------|
| **Serializable** | Financial data, inventory | None |
| **Snapshot** | Complex reporting, analytics | Phantom reads (non-blocking) |
| **Read Committed** | General purpose | Non-repeatable reads |
| **Read Uncommitted** | Logging, analytics (rarely) | Dirty reads |

### Caching Strategies

| Strategy | Pattern | Invalidation |
|----------|---------|--------------|
| **Cache-aside** | App checks cache, then DB | TTL + explicit eviction on write |
| **Write-through** | Write to cache and DB synchronously | Automatic (always in sync) |
| **Write-behind** | Write to cache, async to DB | Complex; requires durability guarantee |
| **Read-through** | Cache loads from DB on miss | TTL-based |

---

## Error Handling Patterns

### Error Classification

| Category | Examples | HTTP Status | Client Action |
|----------|----------|-------------|---------------|
| **Client error (input)** | Validation, authentication, authorization | 400, 401, 403 | Fix request, do not retry |
| **Client error (state)** | Conflict, precondition failed | 409, 412 | Resolve conflict, retry |
| **Server error (transient)** | Timeout, rate limit, unavailable | 408, 429, 503 | Exponential backoff retry |
| **Server error (persistent)** | Internal error, not implemented | 500, 501 | Alert operator, limited retry |
| **Data error** | Not found, gone | 404, 410 | Do not retry; adjust logic |

### Retry Policy

| Parameter | Value | Rationale |
|-----------|-------|-----------|
| Max retries | 3 | Beyond 3, probability of success drops |
| Base delay | 1 second | Initial wait |
| Backoff multiplier | 2x | Exponential: 1s, 2s, 4s |
| Max delay | 30 seconds | Cap to prevent excessive wait |
| Jitter | +/- 25% | Prevent thundering herd |
| Retryable status codes | 408, 429, 502, 503, 504 | Only retry idempotent operations |

### Error Response Format

```json
{
  "error": {
    "code": "[MACHINE_READABLE_ERROR_CODE]",
    "message": "[Human-readable description]",
    "target": "[field_name or resource_identifier]",
    "details": [
      {
        "code": "[SUB_ERROR_CODE]",
        "message": "[Detail]",
        "target": "[specific_field]"
      }
    ]
  }
}
```

---

## Domain-Specific Adaptation Notes

### Web Backend
- Focus on: HTTP status codes, middleware ordering, CORS, rate limiting
- Degradation: API gateway timeouts, DB connection pool exhaustion

### Mobile App
- Focus on: Offline mode, battery efficiency, background task limits
- Degradation: Network type detection (WiFi/4G/offline), partial sync

### Frontend / SPA
- Focus on: Bundle size, rendering performance, accessibility
- Degradation: Skeleton screens, lazy loading, progressive enhancement

### Data Pipeline / ETL
- Focus on: Exactly-once processing, schema evolution, backfill support
- Degradation: Dead letter queue, partial batch acceptance

### ML / AI Service
- Focus on: Model versioning, inference latency, feature store consistency
- Degradation: Simpler model fallback, cached predictions, async batch

### Embedded / IoT
- Focus on: Memory constraints, power consumption, OTA updates
- Degradation: Reduced sampling rate, feature disablement


path: references/examples.md
content: # Good vs. Bad Specification Examples

Use these examples to calibrate output quality. The "Bad" examples show
common mistakes; the "Good" examples show the corrected form.

---

## Example 1: Interface Definition

### ❌ Bad — Implementation Leak

```typescript
// BAD: Contains implementation logic, not just signature
async function createUser(data: CreateUserDTO): Promise<User> {
  const hashedPassword = await bcrypt.hash(data.password, 12);
  const user = await db.users.insert({
    email: data.email.toLowerCase().trim(),
    passwordHash: hashedPassword,
    createdAt: new Date()
  });
  await sendWelcomeEmail(user.email);
  return user;
}
```

**Problems:**
- Complete implementation — implementer has nothing to do
- Hardcoded salt rounds (12)
- Calls specific external services (sendWelcomeEmail)
- Business logic embedded in spec

### ✅ Good — Contract Only

```typescript
// GOOD: Signature, types, constraints, no implementation

/**
 * Create a new user account with validated credentials.
 *
 * @param data — user registration data, validated by [RegistrationValidator]
 * @returns created User with generated id
 *
 * @throws ValidationError if email format invalid or password < [MIN_PASSWORD_LENGTH]
 * @throws DuplicateKeyError if email already exists (idempotent with same idempotencyKey)
 *
 * Side effects:
 * - Persists user to [USER_TABLE]
 * - Triggers welcome email workflow (async, non-blocking)
 *
 * Security: password hashed with bcrypt, salt rounds configured via [BCRYPT_ROUNDS]
 * Thread: safe for concurrent calls; duplicate email handled by unique constraint
 */
async function createUser(data: CreateUserDTO): Promise<User>;
// implementation left to implementer

interface CreateUserDTO {
  email: string;        // validated email format, normalized to lowercase
  [REDACTED_SECRET];     // plaintext, hashed by implementation, min length in [AUTH_CONFIG]
  idempotencyKey?: string;  // optional, for retry safety, UUID v4
}

interface User {
  id: UUID;             // generated by system on creation
  email: string;        // normalized lowercase
  createdAt: DateTime;  // UTC, set by system
  // passwordHash and sensitive fields intentionally omitted from return type
}
```

---

## Example 2: Constraint Layer

### ❌ Bad — Vague and Incomplete

```markdown
## Constraints

- Should be fast
- Handle errors gracefully
- Use caching for performance
- Secure authentication
```

**Problems:**
- "fast" — no measurable target
- "gracefully" — undefined behavior
- "caching" — no strategy, invalidation, or fallback specified
- "secure" — no mechanism specified

### ✅ Good — Precise and Measurable

```markdown
## 4. Constraint Layer

### 4.1 Performance

| Metric | Target | Measurement |
|--------|--------|-------------|
| API response latency | < 100 ms at p95 | Endpoint load test with k6 |
| Database query | < 20 ms (simple), < 100 ms (complex) | Query analyzer |
| Cache hit latency | < 5 ms | Redis INFO latencystats |

### 4.2 Degradation Strategies

| Dependency | Healthy | Degraded | Failed |
|------------|---------|----------|--------|
| PostgreSQL | Normal query | Read from replica | Circuit breaker open, queue writes to DLQ |
| Redis | Cache read/write | Cache miss → DB read | All reads go to DB, no write caching |
| Email service | Async send | Queue for retry (max 3) | Log failure, do not block user creation |

### 4.3 Boundary Conditions

| Scenario | Input | Behavior |
|----------|-------|----------|
| Empty user list | `[]` | Return `[]` with HTTP 200 |
| Null DTO | `null` | `400 ValidationError` with field detail |
| Duplicate email | [REDACTED_SECRET] | `409 Conflict`, return existing user id |
| Concurrent create | same email, same ms | Unique DB constraint prevents duplicate; first wins |
| Password too short | "123" | `400 ValidationError`, min length defined in [AUTH_CONFIG] |
| Rate limit exceeded | > 100 req/min per IP | `429 Too Many Requests`, `Retry-After: 60` |

### 4.4 Threading

| Operation | Context | Notes |
|-----------|---------|-------|
| HTTP handler | Event loop | Do not block; use async I/O |
| DB query | Connection pool | Max 20 connections; queue if exhausted |
| Email send | Background worker | Fire-and-forget; failures logged, not retried inline |
| Password hash | Background thread | CPU-intensive; off main thread |

### 4.5 Security

| Concern | Requirement |
|---------|-------------|
| Password storage | bcrypt with [BCRYPT_ROUNDS], never store plaintext |
| Email validation | RFC 5322 regex + confirmation email before activation |
| Rate limiting | 100 req/min per IP, 10 req/min per email |
| Input sanitization | Strip HTML tags, validate max lengths per field |
| Audit logging | Log all create/delete operations with actor ID, retention 90 days |
```

---

## Example 3: Test Case Definition

### ❌ Bad — Vague Test Descriptions

```markdown
## Tests

- Test creating a user
- Test error handling
- Test performance
```

**Problems:**
- No input specified
- No expected output
- No error condition defined
- Not implementable by a developer

### ✅ Good — Input/Output Specified

```markdown
## 5. Verification Checklist

### Unit Tests

- [ ] `createUser` — valid input `{email: "[REDACTED_SECRET]", [REDACTED_SECRET]"}`
  → returns `User` with valid UUID `id`, normalized email `"[REDACTED_SECRET]"`,
  `createdAt` within last 1000ms

- [ ] `createUser` — duplicate email `{email: "[REDACTED_SECRET]", [REDACTED_SECRET]"}`
  where email already exists
  → throws `DuplicateKeyError` with code `"EMAIL_EXISTS"`, status 409

- [ ] `createUser` — invalid email `{email: "not-an-email", [REDACTED_SECRET]"}`
  → throws `ValidationError` targeting field `"email"`, status 400

- [ ] `createUser` — short password `{email: "[REDACTED_SECRET]", password: "123"}`
  → throws `ValidationError` targeting field `"password"`,
  message includes minimum length requirement

- [ ] `createUser` — null input `null`
  → throws `ValidationError` with message "Request body required", status 400

- [ ] `createUser` — empty email `{email: "", [REDACTED_SECRET]"}`
  → throws `ValidationError` targeting field `"email"`, status 400

### Integration Tests

- [ ] End-to-end: POST /users with valid payload → 201 Created,
  Location header contains `/users/{id}`, welcome email queued

- [ ] Idempotency: POST /users twice with same `idempotencyKey`
  → second request returns 200 with same `id` as first (not 201)

- [ ] Degradation: create user when email service down → user still created (201),
  email failure logged, no error returned to client

### Performance Tests

- [ ] 100 concurrent createUser calls → p95 latency < 100ms, 0 errors
- [ ] Sustained 500 req/s for 5 minutes → memory usage stable (< 256MB),
  DB connections never exhausted
```

---

## Example 4: Module Boundaries

### ❌ Bad — Ambiguous Responsibilities

```markdown
## Modules

- src/
  - utils/       (helper stuff)
  - services/    (business logic)
  - models/      (data things)
```

**Problems:**
- "helper stuff" — meaningless
- "business logic" — which business? what logic?
- "data things" — too vague
- No dependency direction specified

### ✅ Good — Clear Single Responsibilities

```markdown
## 2. Module Structure

```
src/
├── auth/                    # Authentication & authorization
│   ├── handlers/            # HTTP route handlers (parse request, call service, format response)
│   ├── service.ts           # Business logic: validate, hash, persist, emit events
│   └── repository.ts        # Data access: SQL queries, transaction management
├── users/                   # User profile management (read-only for this spec)
│   ├── handlers/
│   ├── service.ts           # Profile retrieval, update, deletion
│   └── repository.ts        # User CRUD operations
├── email/                   # Email delivery abstraction
│   ├── client.ts            # Provider-agnostic interface (SendGrid, SES, etc.)
│   └── workers/             # Background job processors
└── shared/                  # Cross-cutting concerns
    ├── errors/              # Domain-specific error classes
    ├── middleware/          # Auth, rate limiting, request ID, logging
    └── types.ts             # Shared type definitions
```

| Module | Responsibility | Depends On |
|--------|---------------|------------|
| `auth` | Registration, login, credential validation | `shared`, `email` (event only) |
| `users` | Profile CRUD, search | `shared`, `auth` (for permission checks) |
| `email` | Async email delivery with retry | `shared` |
| `shared` | Error types, middleware, common utilities | — |

**Dependency Rule:** Domain modules (`auth`, `users`) may depend on `shared`
and `email`, but never on each other. Cross-domain operations use events or
the shared middleware layer.
```

---

## Example 5: Complete Mini-Spec (Good Example)

A compact but complete spec for a rate limiter module.

```markdown
# Rate Limiter Implementation Specification

## 1. Overview

### 1.1 Goal
Token bucket rate limiter supporting per-key limits with Redis backend,
usable across HTTP APIs, background jobs, and WebSocket connections.

### 1.2 Scope

**IN:**
- Token bucket algorithm with configurable capacity and refill rate
- Per-key limiting (IP, user ID, API key)
- Redis-based distributed storage
- Synchronous and async check interfaces

**OUT:**
- Sliding window algorithm (deferred to v2)
- Rate limit response headers (not in this spec)
- UI dashboard for limit configuration

### 1.3 Tech Stack

| Layer | Technology |
|-------|-----------|
| Language | TypeScript |
| Backend | Redis 7+ |
| Algorithm | Token bucket |

---

## 2. Module Structure

```
rate-limiter/
├── src/
│   ├── token-bucket.ts      # Core algorithm
│   ├── redis-store.ts       # Redis storage adapter
│   ├── limiter.ts           # Public API (simplified interface)
│   └── types.ts             # Shared type definitions
└── tests/
    ├── token-bucket.test.ts
    └── limiter.test.ts
```

| Module | Responsibility | Depends On |
|--------|---------------|------------|
| `token-bucket` | Algorithm logic: consume, refill, status | `types` |
| `redis-store` | Redis operations: get, set, Lua scripts | `types` |
| `limiter` | Public API, key resolution, error mapping | `token-bucket`, `redis-store`, `types` |
| `types` | Interfaces and type aliases | — |

---

## 3. Interface Definitions

### 3.1 Types

```typescript
// RateLimitConfig: parameters defining a single limit bucket
interface RateLimitConfig {
  key: string;              // unique identifier for this limit (e.g., "ip:1.2.3.4")
  capacity: number;         // maximum tokens, must be > 0
  refillRate: number;       // tokens added per second, must be > 0
  windowMs?: number;        // optional: time window for display purposes
}

// RateLimitStatus: result of a rate limit check
interface RateLimitStatus {
  allowed: boolean;         // true if request permitted
  remainingTokens: number;  // tokens left after this request (0 if denied)
  resetAt: DateTime;        // UTC time when bucket will be full
  retryAfterMs?: number;    // present and > 0 when allowed === false
}
```

### 3.2 Public API

```typescript
/**
 * Check if a request is allowed under the configured rate limit.
 * Consumes 1 token if allowed; does not modify state if denied.
 *
 * @param config — rate limit configuration for this key
 * @returns RateLimitStatus with allowance decision and metadata
 *
 * @throws RateLimitError if Redis unavailable (caller decides: fail open or fail closed)
 *
 * Performance: < 10 ms (Redis round-trip + Lua execution)
 * Thread: safe for concurrent calls; Redis Lua script is atomic
 */
async function checkLimit(config: RateLimitConfig): Promise<RateLimitStatus>;
// implementation left to implementer
```

---

## 4. Constraint Layer

### 4.1 Performance

| Metric | Target |
|--------|--------|
| Check latency | < 10 ms (Redis on same network) |
| Throughput | 10,000 checks/sec per Redis instance |
| Memory per key | ~100 bytes (bucket state in Redis hash) |

### 4.2 Degradation

| Dependency | Healthy | Degraded | Failed |
|------------|---------|----------|--------|
| Redis | Normal token bucket | N/A (stateless fallback impossible) | Fail open (allow request) or fail closed (deny) based on [FAILURE_MODE] config |

### 4.3 Boundary Conditions

| Scenario | Behavior |
|----------|----------|
| `capacity <= 0` | Throw `ValidationError` on config creation |
| `refillRate <= 0` | Throw `ValidationError` on config creation |
| Key does not exist in Redis | Treat as full bucket (capacity tokens available) |
| Concurrent checks on same key | Atomic via Redis Lua; no race conditions |
| Token fractional value | Floor to integer (0.9 tokens = 0 usable tokens) |
| Clock skew between instances | Tolerated: Redis server time is authoritative |

### 4.4 Threading

All operations are async/non-blocking. Redis Lua scripts execute atomically
on the Redis server; no client-side locking needed.

### 4.5 Security

- Keys must be sanitized: max length 256 chars, alphanumeric + `:.-_`
- Config values (capacity, refillRate) validated at creation time, never from user input
- Redis connection uses AUTH password, TLS in production

---

## 5. Verification Checklist

### Unit Tests

- [ ] `checkLimit` — new key, 1 capacity → first call allowed (remaining: 0),
  second call denied (retryAfterMs > 0)
- [ ] `checkLimit` — key with 10 capacity, 1/sec refill → 10 rapid calls all allowed,
  11th denied, wait 1s, 1 more allowed
- [ ] `checkLimit` — invalid config (capacity: 0) → throws `ValidationError`
- [ ] `checkLimit` — Redis unavailable, FAILURE_MODE=open → returns allowed=true
- [ ] `checkLimit` — Redis unavailable, FAILURE_MODE=closed → throws `RateLimitError`

### Integration Tests

- [ ] 100 concurrent `checkLimit` calls on same key with capacity=50 →
  exactly 50 allowed, 50 denied, no negative remaining tokens
- [ ] Refill accuracy: consume all tokens, wait `capacity/refillRate` seconds,
  check bucket is full again (within 1 token tolerance)

### Performance Tests

- [ ] 10,000 checks/sec sustained for 60s → p95 < 10ms, 0 errors,
  Redis CPU < 50%

---

## 6. Decisions

| Decision | Chosen | Rejected | Rationale |
|----------|--------|----------|-----------|
| Algorithm | Token bucket | Sliding window | Simpler implementation, good burst handling, Redis Lua friendly |
| Storage | Redis hash + Lua | In-memory + gossip | Required for distributed deployments |
| Failure mode | Configurable | Always fail closed | Some endpoints require availability over rate limiting |
```

---

## Common Patterns Summary

When in doubt, prefer:

| Aspect | Prefer | Avoid |
|--------|--------|-------|
| Specificity | `"< 200 ms at p95"` | `"fast"` |
| Test cases | Input + expected output + error condition | Vague descriptions |
| Interfaces | Signature + thrown exceptions + constraints | Complete implementation |
| Constraints | Tables with scenarios | Prose paragraphs |
| Responsibilities | One sentence per module | Vague grouping words |
| Decisions | Explicit rationale for rejection | Stating choice without context |


path: references/spec-template.md
content: # Specification Output Template

Use this template when generating spec.md. Replace all bracketed placeholders
with project-specific content. Annotated comments (like this one) should NOT
appear in the final output — they are instructional for the spec author only.

---

```markdown
# [Feature/Module Name] Coding Contract

> Generated: [DATE]
> Scope: [one-line scope summary]
> Author: [human or "coding-contract skill"]

---

## 1. Overview

### 1.1 Goal
[One paragraph describing what this feature accomplishes from a technical
perspective. Not a product pitch — an engineering objective.]

### 1.2 Scope

**IN scope:**
- [Specific capability 1]
- [Specific capability 2]
- [Specific capability 3]

**OUT of scope (explicitly excluded):**
- [Capability that might be assumed but is NOT included]
- [Future work that is deferred]

### 1.3 Tech Stack

| Layer | Technology | Purpose |
|-------|-----------|---------|
| Language | [e.g., TypeScript, Kotlin, Go] | Primary implementation |
| Framework | [e.g., NestJS, Spring Boot, React] | Application structure |
| Data Store | [e.g., PostgreSQL, Redis, S3] | Persistence |
| External | [e.g., Stripe API, AWS SNS] | Third-party integration |

### 1.4 Related Specifications
- [Link to upstream/downstream spec if applicable]
- [Link to API contract, design doc, or RFC]

---

## 2. Module Structure

```
[project-root]/
├── [module-a]/
│   ├── [subpackage]/
│   │   └── [KeyInterface].ts
│   └── [subpackage]/
│       └── [Repository].ts
├── [module-b]/
│   └── [subpackage]/
│       └── [Service].ts
└── shared/
    └── [types|utils]/
```

| Module | Responsibility | Depends On |
|--------|---------------|------------|
| `[module-a]` | [one sentence] | `[module-b]`, `shared` |
| `[module-b]` | [one sentence] | `shared` |
| `shared` | [one sentence] | — |

---

## 3. Interface Definitions

### 3.1 [Module A]

#### Data Models

```typescript
// [ModelName]: [semantic description of what this represents]
interface [ModelName] {
  id: [UUID | string | number];        // unique identifier, generated by [mechanism]
  field1: string;                       // [semantic meaning, constraints]
  field2: number;                       // [semantic meaning, unit if applicable]
  createdAt: Date;                      // UTC timestamp, set on creation
  // ... additional fields
}
```

#### Public Functions / Methods

```typescript
// [Service/Interface Name]

/**
 * [One-line description of what this function does.]
 *
 * @param param1 — [description, type, constraints]
 * @param param2 — [description, type, constraints]
 * @returns [description of return value, error cases]
 *
 * @throws [ExceptionType] when [specific condition]
 * @throws [ExceptionType] when [specific condition]
 *
 * Thread: [main | background | either]
 * Performance: must complete within [N] [ms|s]
 */
function [functionName](param1: Type1, param2: Type2): ReturnType;
// implementation left to implementer
```

### 3.2 [Module B]

[Repeat structure above for each module]

---

## 4. Constraint Layer

### 4.1 Performance

| Metric | Target | Measurement Method |
|--------|--------|-------------------|
| [Operation] latency | < [N] ms at p95 | [benchmark method] |
| [Operation] throughput | > [N] req/s | [load test scenario] |
| Memory usage | < [N] MB per instance | [profiling tool] |
| Startup time | < [N] ms | [cold start measurement] |

### 4.2 Degradation Strategies

| Dependency | Healthy Behavior | Degraded Behavior | Failure Behavior |
|------------|-----------------|-------------------|-----------------|
| [Service/DB/API] | [normal flow] | [cache fallback, skip non-critical] | [circuit breaker, return error] |

### 4.3 Boundary Conditions

| Scenario | Input | Expected Behavior |
|----------|-------|-------------------|
| Empty collection | `[]` | Return empty result, HTTP 200, not error |
| Null/undefined input | `null` | Throw `ValidationError` with field name |
| Max payload | `[MAX_SIZE]` + 1 byte | Reject with `PayloadTooLargeError` |
| Concurrent modification | Two writes to same record | Optimistic locking, second write gets `ConflictError` |
| Duplicate create | Same unique key | `DuplicateKeyError`, idempotent on retry with same idempotency key |

### 4.4 Threading / Concurrency

| Operation | Execution Context | Sync Mechanism |
|-----------|------------------|----------------|
| [I/O operation] | Background thread pool | None needed |
| [State mutation] | Single writer queue | Mutex/channel |
| [UI update] | Main / UI thread | Dispatch to main |

### 4.5 Security

| Concern | Requirement |
|---------|-------------|
| Authentication | [JWT / API Key / OAuth2 — specify mechanism] |
| Authorization | [RBAC / ACL / resource-level permissions] |
| Input validation | [schema validation, max length, sanitization rules] |
| Secrets management | [env vars, vault, secret manager — never hardcode] |
| Data encryption | [at rest: AES-256, in transit: TLS 1.3] |
| Audit logging | [which operations are logged, retention period] |

### 4.6 State & Persistence

| State Type | Storage | Consistency Model | TTL / Cleanup |
|------------|---------|-------------------|---------------|
| Session | [Redis / DB] | [strong / eventual] | [TTL in seconds] |
| Cache | [Redis / in-memory] | [write-through / write-behind] | [eviction policy] |
| Persistent | [PostgreSQL / MongoDB] | ACID / [isolation level] | permanent |

---

## 5. Verification Checklist

### 5.1 Unit Tests

- [ ] `[functionName]` — valid input → returns expected `[ReturnType]`
- [ ] `[functionName]` — `null` input → throws `ValidationError`
- [ ] `[functionName]` — duplicate key → throws `DuplicateKeyError`
- [ ] `[functionName]` — max length exceeded → throws `ValidationError`
- [ ] `[functionName]` — empty collection → returns `[]` (not error)

### 5.2 Integration Tests

- [ ] Full happy path: [input] → [module A] → [module B] → [expected output]
- [ ] Cache miss path: [input] → cache miss → DB query → cache populate → return
- [ ] Degradation path: [dependency down] → fallback behavior → [expected degraded output]
- [ ] Error propagation: [module B failure] → [error bubbles correctly to caller]

### 5.3 Performance Tests

- [ ] `[endpoint/operation]` — 100 concurrent requests → p95 < [N] ms
- [ ] `[endpoint/operation]` — sustained 1000 req/s for 5 min → no errors, memory stable

### 5.4 Security Tests

- [ ] Unauthenticated request → `401 Unauthorized`
- [ ] Insufficient permissions → `403 Forbidden`
- [ ] SQL injection payload → safely rejected / parameterized
- [ ] Oversized payload → `413 Payload Too Large`

---

## 6. Decisions & Trade-offs

| Decision | Chosen Approach | Alternatives Considered | Rationale |
|----------|----------------|------------------------|-----------|
| [Architecture choice] | [What we picked] | [What we rejected] | [Why — 1-2 sentences] |
| [Library selection] | [What we picked] | [What we rejected] | [Why — 1-2 sentences] |
| [Concurrency model] | [What we picked] | [What we rejected] | [Why — 1-2 sentences] |

### User-Approved Trade-offs
- [User explicitly accepted: reducing scope of X to meet deadline Y]
- [User explicitly accepted: using simpler algorithm for v1, optimize later]

---

## 7. Open Questions / Follow-up

- [ ] [Question that could not be resolved during spec generation]
- [ ] [Dependency on external team or decision]
- [ ] [Risk that needs monitoring]
```

---

## Usage Notes for Spec Authors

1. **Replace all `[bracketed placeholders]`** with project-specific content.
   Do not leave placeholders in the final spec.

2. **Section 4 is the most important section.** Spend the most time here.
   The implementer can figure out code; they cannot figure out constraints
   that live only in your head.

3. **Pseudocode syntax:** Use the target language's type notation but replace
   function bodies with `// implementation left to implementer`.

4. **Tables over prose:** Prefer tables for boundary conditions, degradation
   strategies, and test cases. They are scannable and unambiguous.

5. **One spec per bounded context.** If a feature spans multiple independent
   subsystems, split into separate spec files — one per subsystem.


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)