📦 deps(thirdparty): update snapshots
This commit is contained in:
@@ -0,0 +1,352 @@
|
||||
---
|
||||
name: software-craft
|
||||
description: This skill should be used when making design decisions, evaluating trade-offs, assessing code quality, or when "engineering judgment" or "code quality" are mentioned.
|
||||
metadata:
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# Software Engineering
|
||||
|
||||
Engineering judgment - thoughtful decisions - quality code.
|
||||
|
||||
<when_to_use>
|
||||
|
||||
- Making architectural or design decisions
|
||||
- Evaluating trade-offs between approaches
|
||||
- Determining appropriate level of thoroughness
|
||||
- Assessing when code needs refactoring
|
||||
- Deciding when to ask vs proceed independently
|
||||
- Balancing speed, quality, maintainability
|
||||
|
||||
NOT for: mechanical tasks, clear-cut decisions, following explicit instructions
|
||||
|
||||
</when_to_use>
|
||||
|
||||
<principles>
|
||||
|
||||
Core engineering judgment framework.
|
||||
|
||||
**User preferences trump defaults**
|
||||
`CLAUDE.md`, project rules, existing patterns always override skill suggestions.
|
||||
|
||||
**Simplest thing that works**
|
||||
Start simple. Add complexity only when requirements demand.
|
||||
- Boring solutions for boring problems
|
||||
- Proven libraries over custom implementations
|
||||
- Progressive enhancement over rewrites
|
||||
|
||||
**Read before write**
|
||||
Understand existing patterns before modifying.
|
||||
- Check how similar features implemented
|
||||
- Follow established conventions
|
||||
- Maintain consistency
|
||||
|
||||
**Small, focused changes**
|
||||
One idea per commit, 20-100 LOC, 1-5 files.
|
||||
- Easy to review/understand
|
||||
- Lower bug risk
|
||||
- Simpler to revert
|
||||
- Faster feedback
|
||||
|
||||
**Security awareness**
|
||||
Don't introduce vulnerabilities.
|
||||
- Validate external input
|
||||
- Parameterized queries
|
||||
- Handle auth properly
|
||||
- No secrets in code/logs
|
||||
|
||||
**Know when to stop**
|
||||
Ship working code, don't gold-plate.
|
||||
- Implement requirements, not assumptions
|
||||
- No unrequested features
|
||||
- No speculative abstraction
|
||||
|
||||
</principles>
|
||||
|
||||
<type_safety>
|
||||
|
||||
Type safety across languages.
|
||||
|
||||
**Core principle**: Make illegal states unrepresentable. Type system should prevent invalid data at compile time, not runtime.
|
||||
|
||||
**Hierarchy**: Correct (type-safe) - Clear (self-documenting) - Precise (not overly broad)
|
||||
|
||||
**Key patterns**:
|
||||
- **Result types** - Errors explicit in signatures, not hidden in exceptions
|
||||
- **Discriminated unions** - Mutually exclusive states with discriminator field
|
||||
- **Branded types** - Distinct types for domain concepts (user ID vs product ID)
|
||||
- **Parse, don't validate** - Transform untyped to typed at boundaries, trust types internally
|
||||
|
||||
See [type-patterns.md](references/type-patterns.md) for detailed concepts.
|
||||
Load `typescript-dev/SKILL.md` for TypeScript implementations.
|
||||
|
||||
</type_safety>
|
||||
|
||||
<decision_framework>
|
||||
|
||||
Systematic approach to engineering choices.
|
||||
|
||||
**Understand before deciding**
|
||||
- What problem being solved?
|
||||
- What constraints exist?
|
||||
- What's already in codebase?
|
||||
- What patterns does project use?
|
||||
|
||||
**Consider trade-offs**
|
||||
No perfect solutions:
|
||||
- Speed vs robustness
|
||||
- Simplicity vs flexibility
|
||||
- Consistency vs optimization
|
||||
- Implement time vs maintain time
|
||||
|
||||
**Recognize good-enough**
|
||||
Perfect is enemy of shipped:
|
||||
- Meets requirements?
|
||||
- Maintainable by team?
|
||||
- Tested adequately?
|
||||
- Can improve incrementally?
|
||||
|
||||
If yes to all - ship it.
|
||||
|
||||
**Document significant choices**
|
||||
Non-obvious decisions: comment why, note trade-offs, link discussions, flag assumptions.
|
||||
|
||||
</decision_framework>
|
||||
|
||||
<when_to_ask>
|
||||
|
||||
Balance autonomy with collaboration.
|
||||
|
||||
**Proceed independently**:
|
||||
- Task clear and well-defined
|
||||
- Approach follows existing patterns
|
||||
- Changes small and localized
|
||||
- Requirements fully understood
|
||||
- No security/data integrity risks
|
||||
|
||||
**Ask questions**:
|
||||
- Requirements ambiguous
|
||||
- Multiple approaches, unclear trade-offs
|
||||
- Changes affect architecture
|
||||
- Security/compliance implications
|
||||
- Unfamiliar domain/technology
|
||||
|
||||
**Escalate immediately**:
|
||||
- Security vulnerabilities discovered
|
||||
- Data corruption/loss risk
|
||||
- Breaking changes to public APIs
|
||||
- Performance degradation detected
|
||||
|
||||
Don't guess on high-stakes decisions.
|
||||
|
||||
</when_to_ask>
|
||||
|
||||
<code_quality>
|
||||
|
||||
Standards separating good from professional code.
|
||||
|
||||
**Type safety**: Make illegal states unrepresentable via discriminated unions, branded types.
|
||||
|
||||
**Error handling**: Every error path needs explicit handling. No silent failures.
|
||||
|
||||
**Naming**: Functions=verbs (`calculateTotal`), variables=nouns (`userId`), booleans=questions (`isValid`).
|
||||
|
||||
**Function design**: One thing well. 10-30 lines typical, max 50. 3 params ideal, max 5. Pure when possible.
|
||||
|
||||
**Comments**: Explain why, not what.
|
||||
|
||||
See [code-quality-patterns.md](references/code-quality-patterns.md) for examples.
|
||||
|
||||
</code_quality>
|
||||
|
||||
<refactoring>
|
||||
|
||||
When and how to improve existing code.
|
||||
|
||||
**Refactor when**:
|
||||
- Adding feature reveals poor structure
|
||||
- Code duplicated 3+ times
|
||||
- Function exceeds 50 lines
|
||||
- Naming unclear/misleading
|
||||
- Tests difficult to write
|
||||
|
||||
**Don't refactor when**:
|
||||
- Code works and won't be touched
|
||||
- Time-critical delivery in progress
|
||||
- No test coverage to verify
|
||||
- Scope creep from main task
|
||||
- Just preference, no clear benefit
|
||||
|
||||
**Guidelines**:
|
||||
- Have tests first (or write them)
|
||||
- One refactoring at a time
|
||||
- Keep tests passing throughout
|
||||
- Commit refactors separately from features
|
||||
- Don't change behavior
|
||||
|
||||
</refactoring>
|
||||
|
||||
<testing>
|
||||
|
||||
Testing philosophy.
|
||||
|
||||
**Test the right things**:
|
||||
- Public interfaces, not implementation
|
||||
- Edge cases and error paths
|
||||
- Critical business logic
|
||||
- Integration points
|
||||
- Security boundaries
|
||||
|
||||
**Don't over-test**:
|
||||
- No tests for trivial getters/setters
|
||||
- Don't test framework behavior
|
||||
- Avoid brittle implementation-coupled tests
|
||||
|
||||
**Coverage targets**:
|
||||
- Critical paths: 90%+
|
||||
- Business logic: 80%+
|
||||
- Utility functions: 80%+
|
||||
- Overall: 70%+
|
||||
|
||||
Low coverage acceptable for: config, type definitions, framework boilerplate.
|
||||
|
||||
</testing>
|
||||
|
||||
<performance>
|
||||
|
||||
Balance optimization with delivery.
|
||||
|
||||
**Premature optimization is root of evil**
|
||||
- Make it work first
|
||||
- Make it right second
|
||||
- Make it fast only if needed
|
||||
|
||||
**Optimize when**:
|
||||
- Measured performance issue exists
|
||||
- User experience degraded
|
||||
- Resource costs excessive
|
||||
- Profiler shows clear bottleneck
|
||||
|
||||
**Before optimizing**:
|
||||
1. Measure current performance
|
||||
2. Set target metrics
|
||||
3. Profile to find bottleneck
|
||||
4. Optimize specific bottleneck
|
||||
5. Measure improvement
|
||||
6. Document trade-offs
|
||||
|
||||
Don't optimize based on gut feeling or without measurement.
|
||||
|
||||
</performance>
|
||||
|
||||
<security>
|
||||
|
||||
Security mindset for all code.
|
||||
|
||||
**Input validation**: Validate all external input, sanitize before processing, allowlists over blocklists.
|
||||
|
||||
**Auth**: Never trust client-side checks, verify on server, use proven libraries, don't roll your own crypto.
|
||||
|
||||
**Data handling**: Never log sensitive data, hash passwords (bcrypt/argon2), parameterized queries, strict file upload validation.
|
||||
|
||||
**Dependencies**: Keep updated, review advisories, minimize count, audit before adding.
|
||||
|
||||
**Red flags to escalate**: Payment info, user credentials, health/financial data, encryption implementation, session management.
|
||||
|
||||
</security>
|
||||
|
||||
<anti_patterns>
|
||||
|
||||
Common mistakes to avoid.
|
||||
|
||||
**Over-engineering**: Building "might need" features, premature abstraction, excessive config, enterprise patterns for simple problems.
|
||||
Fix: YAGNI. Build for today.
|
||||
|
||||
**Under-engineering**: No error handling, no input validation, ignoring edge cases, copy-paste over functions.
|
||||
Fix: Basic quality isn't optional.
|
||||
|
||||
**Scope creep**: "While I'm here...", refactoring unrelated code, adding unrequested features.
|
||||
Fix: Stay focused. File issues for unrelated work.
|
||||
|
||||
**Guess-and-check**: Random solutions, copying without understanding, no root cause investigation.
|
||||
Fix: Systematic debugging. Understand before changing.
|
||||
|
||||
**Analysis paralysis**: Endless design discussions, researching every option, waiting for perfect.
|
||||
Fix: Good enough + shipping > perfect + delayed.
|
||||
|
||||
</anti_patterns>
|
||||
|
||||
<communication>
|
||||
|
||||
Senior engineer collaboration.
|
||||
|
||||
**Clear issues/PRs**: Context (problem), approach (solution), trade-offs (alternatives), testing (verification), impact (risks).
|
||||
|
||||
**Code review**: Focus on correctness/clarity/security. Suggest, don't demand perfection. Approve when good enough.
|
||||
|
||||
**When blocked**: Try 30 min self-unblock, gather context, ask specific question with context, propose solutions.
|
||||
|
||||
**Saying no**: "That would work, but have you considered X?" / "This introduces Y risk. Can we mitigate with Z?"
|
||||
|
||||
Back opinions with reasoning. Stay open to being wrong.
|
||||
|
||||
</communication>
|
||||
|
||||
<workflow_integration>
|
||||
|
||||
Connect with other outfitter skills.
|
||||
|
||||
**With TDD**: Senior judgment decides what's worth testing. TDD skill provides how.
|
||||
|
||||
**With debugging**: Senior judgment decides if worth fixing now. Debugging skill provides systematic investigation.
|
||||
|
||||
**With dev-* skills**: Software engineering provides the "why" and "when". dev-* skills provide the "how" for specific technologies (typescript-dev, react-dev, hono-dev, bun-dev).
|
||||
|
||||
</workflow_integration>
|
||||
|
||||
<rules>
|
||||
|
||||
ALWAYS:
|
||||
- Read `CLAUDE.md` and project rules first
|
||||
- Follow existing codebase patterns
|
||||
- Make small, focused changes
|
||||
- Validate external input
|
||||
- Handle errors explicitly
|
||||
- Test critical paths
|
||||
- Document non-obvious decisions
|
||||
- Ask when uncertain on high-stakes
|
||||
|
||||
NEVER:
|
||||
- Add features not in requirements
|
||||
- Ignore error handling
|
||||
- Skip input validation
|
||||
- Commit secrets or credentials
|
||||
- Guess on security decisions
|
||||
- Refactor without tests
|
||||
- Optimize without measuring
|
||||
- Over-engineer simple solutions
|
||||
|
||||
</rules>
|
||||
|
||||
<references>
|
||||
|
||||
Complements other outfitter skills:
|
||||
|
||||
**Core Practices:**
|
||||
- [tdd/SKILL.md](../tdd/SKILL.md) - TDD methodology
|
||||
- [debugging/SKILL.md](../debugging/SKILL.md) - systematic debugging
|
||||
- [pathfinding/SKILL.md](../pathfinding/SKILL.md) - requirements clarification
|
||||
|
||||
**Development Skills** (load for implementation patterns):
|
||||
- [typescript-dev/SKILL.md](../typescript-dev/SKILL.md) - TypeScript, Zod, modern features
|
||||
- [react-dev/SKILL.md](../react-dev/SKILL.md) - React 18-19, hooks typing
|
||||
- [hono-dev/SKILL.md](../hono-dev/SKILL.md) - Hono API framework
|
||||
- [bun-dev/SKILL.md](../bun-dev/SKILL.md) - Bun runtime, SQLite, testing
|
||||
|
||||
**Detailed Patterns:**
|
||||
- [type-patterns.md](references/type-patterns.md) - language-agnostic type patterns
|
||||
- [code-quality-patterns.md](references/code-quality-patterns.md) - code examples
|
||||
|
||||
**Standards:**
|
||||
|
||||
</references>
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
# Code Quality Patterns
|
||||
|
||||
Concrete examples for code quality standards.
|
||||
|
||||
## Type Safety Examples
|
||||
|
||||
**Stringly-typed vs Type-safe:**
|
||||
|
||||
```typescript
|
||||
// Bad: stringly-typed state
|
||||
type Status = string;
|
||||
|
||||
// Good: discriminated union
|
||||
type Status = 'pending' | 'approved' | 'rejected';
|
||||
|
||||
// Better: type-safe with associated data
|
||||
type Request =
|
||||
| { status: 'pending' }
|
||||
| { status: 'approved'; by: User; at: Date }
|
||||
| { status: 'rejected'; reason: string };
|
||||
```
|
||||
|
||||
## Error Handling Examples
|
||||
|
||||
**Explicit error handling:**
|
||||
|
||||
```typescript
|
||||
// Bad: ignoring errors
|
||||
await saveUser(user);
|
||||
|
||||
// Good: explicit handling with Result type
|
||||
const result = await saveUser(user);
|
||||
if (result.type === 'error') {
|
||||
logger.error('Failed to save user', result.error);
|
||||
return { type: 'error', message: 'Could not save user' };
|
||||
}
|
||||
```
|
||||
|
||||
## Comment Examples
|
||||
|
||||
**Why vs What:**
|
||||
|
||||
```typescript
|
||||
// Bad: describes what code does (obvious)
|
||||
// Set user active to true
|
||||
user.active = true;
|
||||
|
||||
// Good: explains why (non-obvious intent)
|
||||
// Mark user active to enable login after email verification
|
||||
user.active = true;
|
||||
```
|
||||
|
||||
**Trade-off documentation:**
|
||||
|
||||
```typescript
|
||||
// Using simple polling instead of WebSocket because:
|
||||
// - Simpler to implement and maintain
|
||||
// - Acceptable for current 5-minute update interval
|
||||
// - Can migrate to WebSocket if requirements tighten
|
||||
```
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
| Category | Pattern | Examples |
|
||||
|----------|---------|----------|
|
||||
| Functions | Verbs describing action | `calculateTotal`, `validateEmail`, `fetchUser` |
|
||||
| Variables | Nouns describing data | `userId`, `orderTotal`, `activeUsers` |
|
||||
| Booleans | Questions | `isValid`, `hasPermission`, `canEdit` |
|
||||
| Constants | SCREAMING_SNAKE_CASE | `MAX_RETRIES`, `DEFAULT_TIMEOUT` |
|
||||
| Types/Interfaces | PascalCase | `User`, `OrderRequest`, `AuthConfig` |
|
||||
|
||||
## Function Design Guidelines
|
||||
|
||||
**Size and complexity:**
|
||||
- Do one thing well
|
||||
- 10-30 lines typical, max 50
|
||||
- 3 parameters ideal, max 5
|
||||
- Pure when possible (same input = same output)
|
||||
|
||||
**Signs a function needs splitting:**
|
||||
- Multiple levels of nesting
|
||||
- Multiple responsibilities
|
||||
- Hard to name clearly
|
||||
- Hard to test in isolation
|
||||
|
||||
## Refactoring Commits
|
||||
|
||||
**Keep refactors separate from features:**
|
||||
|
||||
```bash
|
||||
# Good: isolated refactoring commit
|
||||
git commit -m "refactor: extract user validation logic"
|
||||
git commit -m "feat: add email verification"
|
||||
|
||||
# Bad: mixed changes
|
||||
git commit -m "feat: add email verification and refactor validation"
|
||||
```
|
||||
|
||||
Separating commits enables easier review, safer reverts, and cleaner history.
|
||||
@@ -0,0 +1,160 @@
|
||||
# Type Safety Patterns
|
||||
|
||||
Language-agnostic principles for type-safe software design.
|
||||
|
||||
## Core Philosophy
|
||||
|
||||
**Make illegal states unrepresentable**
|
||||
|
||||
The fundamental goal of type safety: if a state is invalid, the type system should reject it at compile time. Don't rely on runtime checks to catch impossible combinations—structure types so they can't exist.
|
||||
|
||||
**Type safety hierarchy**:
|
||||
1. Correct — no runtime type errors possible
|
||||
2. Clear — types serve as documentation
|
||||
3. Precise — exact constraints, not overly broad
|
||||
|
||||
## Result Types
|
||||
|
||||
**The Problem**
|
||||
|
||||
Exceptions hide failure modes from function signatures. Callers can't tell from the type alone that a function might fail.
|
||||
|
||||
**The Solution**
|
||||
|
||||
Return types that explicitly model success and failure. The caller must handle both cases—the type system enforces it.
|
||||
|
||||
**Key Properties**:
|
||||
- Success and error are mutually exclusive branches
|
||||
- Error types are specific, not generic "Error"
|
||||
- Callers handle errors explicitly, not via try/catch
|
||||
- Compiler verifies all cases handled
|
||||
|
||||
**When to Use**:
|
||||
- Operations that can fail (I/O, parsing, validation)
|
||||
- Business logic with multiple outcome types
|
||||
- Any function where callers should handle failure
|
||||
|
||||
**When Not to Use**:
|
||||
- Truly exceptional cases (out of memory, corrupted state)
|
||||
- Internal assertions that indicate bugs
|
||||
|
||||
## Discriminated Unions
|
||||
|
||||
**The Problem**
|
||||
|
||||
Loose object types allow impossible state combinations. A request object with status "loading" shouldn't have data or error fields—but loose types permit this.
|
||||
|
||||
**The Solution**
|
||||
|
||||
Model each state as a separate branch in a union, distinguished by a discriminator field. Each branch contains only the fields valid for that state.
|
||||
|
||||
**Key Properties**:
|
||||
- Single discriminator field (usually `type` or `status`)
|
||||
- Each branch has different required fields
|
||||
- Pattern matching exhaustively handles all branches
|
||||
- Compiler errors if a branch is unhandled
|
||||
|
||||
**Common Applications**:
|
||||
- Request/loading states (idle, loading, success, error)
|
||||
- Form states (editing, submitting, submitted, error)
|
||||
- Authentication (anonymous, authenticated, admin)
|
||||
- Any multi-state entity
|
||||
|
||||
## Branded Types
|
||||
|
||||
**The Problem**
|
||||
|
||||
Primitives of the same underlying type are interchangeable. A user ID and product ID are both strings—the type system can't distinguish them.
|
||||
|
||||
**The Solution**
|
||||
|
||||
"Brand" types with a phantom marker that exists only at compile time. The runtime representation is unchanged, but the compiler treats them as distinct types.
|
||||
|
||||
**Key Properties**:
|
||||
- Compile-time distinction, zero runtime overhead
|
||||
- Smart constructors validate and brand values
|
||||
- Cannot accidentally pass wrong branded type
|
||||
- Enforces validation at construction
|
||||
|
||||
**Common Applications**:
|
||||
- Entity IDs (user, product, order)
|
||||
- Sanitized strings (HTML, SQL, paths)
|
||||
- Validated formats (email, URL, phone)
|
||||
- Units (meters, pixels, seconds)
|
||||
|
||||
## Parse, Don't Validate
|
||||
|
||||
**The Principle**
|
||||
|
||||
Don't validate data and continue using the untyped version. Parse it into a typed structure, then work only with the typed version.
|
||||
|
||||
**Key Insight**
|
||||
|
||||
Validation answers "is this valid?" but leaves data untyped. Parsing answers "what is this?" and produces typed data. After parsing, the type system guarantees validity.
|
||||
|
||||
**Application**:
|
||||
- API responses → parse into domain types
|
||||
- User input → parse into validated types
|
||||
- Configuration → parse into typed config
|
||||
- Files → parse into structured data
|
||||
|
||||
**Boundary Rule**:
|
||||
Parse at system boundaries. Inside the boundary, trust the types.
|
||||
|
||||
## Runtime Validation at Boundaries
|
||||
|
||||
**System Boundaries**
|
||||
|
||||
External data enters untyped:
|
||||
- HTTP request/response bodies
|
||||
- File contents
|
||||
- Environment variables
|
||||
- User input
|
||||
- Database results (sometimes)
|
||||
- Third-party API responses
|
||||
|
||||
**Inside vs Outside**
|
||||
|
||||
- Outside the boundary: data is untyped, validation required
|
||||
- Inside the boundary: data is typed, trust the types
|
||||
|
||||
**Validation Strategy**:
|
||||
1. Accept untyped data at boundary
|
||||
2. Validate and parse into typed structure
|
||||
3. Reject invalid data with clear errors
|
||||
4. Pass typed data to internal functions
|
||||
5. Internal functions trust their input types
|
||||
|
||||
## Exhaustive Pattern Matching
|
||||
|
||||
**The Principle**
|
||||
|
||||
When handling discriminated unions, ensure all branches are covered. The compiler should error if a new branch is added but not handled.
|
||||
|
||||
**Implementation Pattern**
|
||||
|
||||
Use a "never" check in the default case. If a new branch is added to the union, the compiler will error because the new case falls through to the never check.
|
||||
|
||||
**Benefits**:
|
||||
- Compiler enforces completeness
|
||||
- Adding new states requires updating all handlers
|
||||
- No silent failures from unhandled cases
|
||||
|
||||
## Type Narrowing
|
||||
|
||||
**The Principle**
|
||||
|
||||
Control flow should inform the type system. After checking a condition, subsequent code should have access to the narrowed type.
|
||||
|
||||
**Applications**:
|
||||
- Null checks narrow `T | null` to `T`
|
||||
- Type guards narrow `unknown` to specific types
|
||||
- Discriminator checks narrow unions to specific branches
|
||||
- instanceof checks narrow class hierarchies
|
||||
|
||||
## See Also
|
||||
|
||||
For TypeScript-specific implementations of these patterns:
|
||||
- Load `typescript-dev/SKILL.md` for code examples
|
||||
- Result types, branded types, discriminated unions with TypeScript syntax
|
||||
- Zod for runtime validation with type inference
|
||||
Reference in New Issue
Block a user