Stack Compliance Review
Audit code for @outfitter/* pattern compliance.
6-Step Audit Process
Step 1: Scan for Anti-Patterns
Run searches to identify issues:
# Thrown exceptions (Critical)
rg "throw new" --type ts
# try/catch control flow (Critical)
rg "try \{" --type ts
# Console usage (High)
rg "console\.(log|error|warn)" --type ts
# Hardcoded paths (High)
rg "(homedir|~\/\.)" --type ts
# Custom error classes (Medium)
rg "class \w+Error extends Error" --type ts
Step 2: Review Handler Signatures
Check each handler for:
- Returns
Result<T, E>notPromise<T> - Has context parameter as second argument
- Error types explicitly listed in union
- Uses
Handler<TInput, TOutput, TError>type
# Find handlers
rg "Handler<" --type ts -A 2
# Find missing context
rg "Handler<.*> = async \(input\)" --type ts
Step 3: Check Error Usage
Verify errors:
- Use
@outfitter/contractsclasses - Have correct category for use case
- Include appropriate details
- Are returned via
Result.err(), not thrown
Step 4: Validate Logging
Check logging:
- Uses
ctx.logger, not console - Metadata is object, not string concatenation
- Sensitive fields would be redacted
- Child loggers used for request context
Step 5: Check Path Safety
Verify paths:
- User paths validated with
securePath() - XDG helpers used (
getConfigDir, etc.) - Atomic writes for file modifications
- No hardcoded home paths
Step 6: Review Context
Check context:
createContext()at entry points- Context passed through handler chain
requestIdused for tracing
Quick Audit
# Critical issues (count)
rg "throw new|catch \(" --type ts -c
# Console usage (count)
rg "console\.(log|error|warn)" --type ts -c
# Handler patterns
rg "Handler<" --type ts -A 2
Checklist
Result Types
- [ ] Handlers return
Result<T, E>, not thrown exceptions - [ ] Errors use taxonomy classes (
ValidationError,NotFoundError, etc.) - [ ] Result checks use
isOk()/isErr(), not try/catch - [ ] Combined results use
combine2,combine3, etc.
Anti-patterns:
// BAD: Throwing
if (!user) throw new Error("Not found");
// GOOD: Result.err
if (!user) return Result.err(new NotFoundError("user", id));
// BAD: try/catch for control flow
try { await handler(input, ctx); } catch (e) { ... }
// GOOD: Result checking
const result = await handler(input, ctx);
if (result.isErr()) { ... }
Error Taxonomy
- [ ] Errors from
@outfitter/contracts - [ ]
categorymatches use case - [ ]
_tagused for pattern matching
| Category | Use For |
|----------|---------|
| validation | Invalid input, schema failures |
| not_found | Resource doesn't exist |
| conflict | Already exists, version mismatch |
| permission | Forbidden action |
| internal | Unexpected errors, bugs |
Logging
- [ ] Uses
ctx.logger, notconsole.log - [ ] Metadata is object, not string concatenation
- [ ] Sensitive fields redacted
Anti-patterns:
// BAD
console.log("User " + user.name);
logger.info("Config: " + JSON.stringify(config));
// GOOD
ctx.logger.info("Processing", { userId: user.id });
ctx.logger.debug("Config loaded", { config }); // redaction enabled
Path Safety
- [ ] User paths validated with
securePath() - [ ] No hardcoded
~/.paths - [ ] XDG paths via
@outfitter/config - [ ] Atomic writes for file modifications
Anti-patterns:
// BAD
const configPath = path.join(os.homedir(), ".myapp", "config.json");
const userFile = path.join(baseDir, userInput); // traversal risk!
// GOOD
const configDir = getConfigDir("myapp");
const result = securePath(userInput, workspaceRoot);
await atomicWriteJson(configPath, data);
Context Propagation
- [ ]
createContext()at entry points - [ ] Context passed through handler chain
- [ ]
requestIdused for tracing
Validation
- [ ] Uses
createValidator()with Zod - [ ] Validation at handler entry
- [ ] Validation errors returned, not thrown
Output
- [ ] CLI uses
await output()with mode detection - [ ]
exitWithError()for error exits - [ ] Exit codes from error categories
Audit Commands
# Find thrown exceptions
rg "throw new" --type ts
# Find console usage
rg "console\.(log|error|warn)" --type ts
# Find hardcoded paths
rg "(homedir|~\/\.)" --type ts
# Find custom errors
rg "class \w+Error extends Error" --type ts
# Find handlers without context
rg "Handler<.*> = async \(input\)" --type ts
Severity Levels
| Level | Examples | |-------|----------| | Critical | Thrown exceptions, unvalidated paths, missing error handling | | High | Console logging, hardcoded paths, missing context | | Medium | Missing type annotations, non-atomic writes | | Low | Style issues, missing documentation |
Report Format
## Stack Compliance: [file/module]
**Status**: PASS | WARNINGS | FAIL
**Issues**: X critical, Y high, Z medium
### Critical
1. [file:line] Issue description
### High
1. [file:line] Issue description
### Recommendations
- Recommendation with fix
Related Skills
outfitter-stack:stack-patterns— Correct patterns referenceoutfitter-stack:stack-audit— Scan codebase for adoption scopeoutfitter-stack:stack-debug— Troubleshooting issues