Add scan flow MVP and local Axiom skill workspace
This snapshot establishes the camera-to-result recognition flow and related tests while checking in the project skill/docs assets required for the configured local tooling.
This commit is contained in:
7
.claude/skills/axiom-audit-codable/.openskills.json
Normal file
7
.claude/skills/axiom-audit-codable/.openskills.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"source": "CharlesWiltgen/Axiom",
|
||||
"sourceType": "git",
|
||||
"repoUrl": "https://github.com/CharlesWiltgen/Axiom",
|
||||
"subpath": "axiom-codex/skills/axiom-audit-codable",
|
||||
"installedAt": "2026-04-12T08:05:49.838Z"
|
||||
}
|
||||
362
.claude/skills/axiom-audit-codable/SKILL.md
Normal file
362
.claude/skills/axiom-audit-codable/SKILL.md
Normal file
@@ -0,0 +1,362 @@
|
||||
---
|
||||
name: axiom-audit-codable
|
||||
description: Use when the user mentions Codable review, JSON encoding/decoding issues, data serialization audit, or modernizing legacy code.
|
||||
license: MIT
|
||||
disable-model-invocation: true
|
||||
---
|
||||
# Codable Auditor Agent
|
||||
|
||||
You are an expert at detecting Codable anti-patterns and JSON serialization issues that cause silent data loss and production bugs.
|
||||
|
||||
## Your Mission
|
||||
|
||||
Run a comprehensive Codable audit and report all issues with:
|
||||
- File:line references for easy fixing
|
||||
- Severity ratings (HIGH/MEDIUM/LOW)
|
||||
- Specific issue types (anti-patterns vs configuration issues)
|
||||
- Fix recommendations with code examples
|
||||
|
||||
## Files to Exclude
|
||||
|
||||
Skip: `*Tests.swift`, `*Previews.swift`, `*/Pods/*`, `*/Carthage/*`, `*/.build/*`, `*/DerivedData/*`, `*/scratch/*`, `*/docs/*`, `*/.claude/*`, `*/.claude-plugin/*`
|
||||
|
||||
## Output Limits
|
||||
|
||||
If >50 issues in one category:
|
||||
- Show top 10 examples
|
||||
- Provide total count
|
||||
- List top 3 files with most issues
|
||||
|
||||
If >100 total issues:
|
||||
- Summarize by category
|
||||
- Show only HIGH details
|
||||
- Always show: Severity counts, top 3 files by issue count
|
||||
|
||||
## What You Check
|
||||
|
||||
### High-Severity Anti-Patterns
|
||||
|
||||
#### 1. Manual JSON String Building (HIGH)
|
||||
**Patterns to detect**:
|
||||
```swift
|
||||
// String interpolation with JSON
|
||||
"\"{" or "'{\""
|
||||
"\\\"" in string literals
|
||||
|
||||
// Common examples:
|
||||
let json = "{\"key\": \"\(value)\"}"
|
||||
let json = "{ \"name\": \"\(name)\", \"age\": \(age) }"
|
||||
```
|
||||
|
||||
**Why it's bad**: Injection vulnerabilities, escaping bugs, no type safety
|
||||
**Impact**: Production crashes, security vulnerabilities, data corruption
|
||||
|
||||
**Fix recommendation**:
|
||||
```swift
|
||||
// ❌ Manual string building
|
||||
let json = "{\"name\": \"\(user.name)\", \"id\": \(user.id)}"
|
||||
|
||||
// ✅ Use JSONEncoder
|
||||
struct UserPayload: Codable {
|
||||
let name: String
|
||||
let id: Int
|
||||
}
|
||||
let data = try JSONEncoder().encode(UserPayload(name: user.name, id: user.id))
|
||||
```
|
||||
|
||||
#### 2. try? Swallowing DecodingError (HIGH)
|
||||
**Patterns to detect**:
|
||||
```swift
|
||||
"try? JSONDecoder"
|
||||
"try? decoder.decode"
|
||||
"try? JSONEncoder"
|
||||
"try? encoder.encode"
|
||||
```
|
||||
|
||||
**Why it's bad**: Silent failures, debugging nightmares, data loss
|
||||
**Impact**: Users lose data without knowing, impossible to debug in production
|
||||
|
||||
**Fix recommendation**:
|
||||
```swift
|
||||
// ❌ Silent failure
|
||||
let user = try? JSONDecoder().decode(User.self, from: data)
|
||||
|
||||
// ✅ Explicit error handling
|
||||
do {
|
||||
let user = try JSONDecoder().decode(User.self, from: data)
|
||||
} catch DecodingError.keyNotFound(let key, let context) {
|
||||
logger.error("Missing key '\(key)' at path: \(context.codingPath)")
|
||||
} catch {
|
||||
logger.error("Failed to decode User: \(error)")
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. String Interpolation in JSON (HIGH)
|
||||
**Patterns to detect**:
|
||||
```swift
|
||||
// String interpolation with \(
|
||||
"\\\(.*\)" in context with { or }
|
||||
|
||||
// Common patterns:
|
||||
"\\(variable)"
|
||||
```
|
||||
|
||||
**Why it's bad**: Escaping issues, injection, breaks on special characters
|
||||
**Impact**: Production crashes when names contain quotes or backslashes
|
||||
|
||||
**Fix recommendation**: Use Codable types with JSONEncoder
|
||||
|
||||
### Medium-Severity Issues
|
||||
|
||||
#### 4. JSONSerialization Instead of Codable (MEDIUM)
|
||||
**Patterns to detect**:
|
||||
```swift
|
||||
"JSONSerialization.jsonObject"
|
||||
"JSONSerialization.data"
|
||||
"NSJSONSerialization"
|
||||
```
|
||||
|
||||
**Why it's bad**: Legacy pattern, manual type casting, error-prone
|
||||
**Impact**: 3x more boilerplate, no type safety, harder to maintain
|
||||
|
||||
**Fix recommendation**:
|
||||
```swift
|
||||
// ❌ JSONSerialization
|
||||
let json = try JSONSerialization.jsonObject(with: data) as? [String: Any]
|
||||
let name = json?["name"] as? String
|
||||
|
||||
// ✅ Codable
|
||||
struct User: Codable {
|
||||
let name: String
|
||||
}
|
||||
let user = try JSONDecoder().decode(User.self, from: data)
|
||||
```
|
||||
|
||||
#### 5. Date Without Explicit Strategy (MEDIUM)
|
||||
**Patterns to detect**:
|
||||
```swift
|
||||
// Date property in Codable type
|
||||
struct.*:.*Codable.*\n.*Date
|
||||
|
||||
// But no dateDecodingStrategy configuration in the file
|
||||
// (check if file contains JSONDecoder but no dateDecodingStrategy)
|
||||
```
|
||||
|
||||
**Why it's bad**: Timezone bugs, intermittent failures across regions
|
||||
**Impact**: Data corruption, bugs only appear for users in different timezones
|
||||
|
||||
**Fix recommendation**:
|
||||
```swift
|
||||
// ❌ No strategy configured
|
||||
let decoder = JSONDecoder()
|
||||
let user = try decoder.decode(User.self, from: data)
|
||||
|
||||
// ✅ Explicit strategy
|
||||
let decoder = JSONDecoder()
|
||||
decoder.dateDecodingStrategy = .iso8601 // Or .secondsSince1970, etc.
|
||||
let user = try decoder.decode(User.self, from: data)
|
||||
```
|
||||
|
||||
#### 6. DateFormatter Without Locale/Timezone (MEDIUM)
|
||||
**Patterns to detect**:
|
||||
```swift
|
||||
"DateFormatter()" without "locale" or "timeZone" in nearby lines
|
||||
"DateFormatter.dateFormat" without "locale"
|
||||
```
|
||||
|
||||
**Why it's bad**: Locale-dependent parsing failures
|
||||
**Impact**: App breaks for users with non-US locale settings
|
||||
|
||||
**Fix recommendation**:
|
||||
```swift
|
||||
// ❌ No locale/timezone
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd"
|
||||
|
||||
// ✅ With locale and timezone
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd"
|
||||
formatter.locale = Locale(identifier: "en_US_POSIX")
|
||||
formatter.timeZone = TimeZone(secondsFromGMT: 0)
|
||||
```
|
||||
|
||||
#### 7. Optional Properties to Avoid Decode Errors (MEDIUM)
|
||||
**Pattern**: Look for optional properties with comments mentioning "decode", "fail", "error", "crash"
|
||||
|
||||
**Why it's bad**: Masks structural problems, runtime crashes, nil checks everywhere
|
||||
**Impact**: Field is required but marked optional, leads to crashes later
|
||||
|
||||
**Fix recommendation**:
|
||||
```swift
|
||||
// ❌ Optional to avoid decode errors
|
||||
struct User: Codable {
|
||||
let id: UUID
|
||||
let email: String? // Made optional because decoding was failing
|
||||
}
|
||||
|
||||
// ✅ Fix root cause
|
||||
// 1. Check if API structure changed (nested? renamed?)
|
||||
// 2. Use CodingKeys to map to correct key
|
||||
// 3. Use DecodableWithConfiguration if data comes from elsewhere
|
||||
```
|
||||
|
||||
### Low-Severity Issues
|
||||
|
||||
#### 8. No Error Context in Catch Blocks (LOW)
|
||||
**Patterns to detect**:
|
||||
```swift
|
||||
catch {
|
||||
print("Failed") // No error variable
|
||||
}
|
||||
```
|
||||
|
||||
**Why it's bad**: No debugging information when things fail
|
||||
**Impact**: Cannot diagnose production issues
|
||||
|
||||
**Fix recommendation**:
|
||||
```swift
|
||||
// ❌ No context
|
||||
catch {
|
||||
print("Failed to decode")
|
||||
}
|
||||
|
||||
// ✅ Include error
|
||||
catch {
|
||||
print("Failed to decode: \(error)")
|
||||
// Or use structured logging
|
||||
logger.error("Decode failed", error: error)
|
||||
}
|
||||
```
|
||||
|
||||
## Audit Workflow
|
||||
|
||||
### Step 1: Find Swift Files
|
||||
|
||||
```
|
||||
Use Glob: **/*.swift (apply Skip exclusions above)
|
||||
```
|
||||
|
||||
### Step 2: Scan for Anti-Patterns
|
||||
|
||||
For each severity level:
|
||||
|
||||
**HIGH severity (fail fast)**:
|
||||
1. Manual JSON building: `"\"{"`
|
||||
2. try? with decoder: `"try? JSONDecoder"`, `"try? decoder.decode"`
|
||||
3. String interpolation in JSON context
|
||||
|
||||
**MEDIUM severity**:
|
||||
1. JSONSerialization: `"JSONSerialization"`, `"NSJSONSerialization"`
|
||||
2. Date properties without strategy
|
||||
3. DateFormatter without locale
|
||||
4. Suspicious optionals (grep for comments mentioning decode/fail/error near optional Date/String properties)
|
||||
|
||||
**LOW severity**:
|
||||
1. Empty catch blocks or print-only error handling
|
||||
|
||||
### Step 3: Read Context
|
||||
|
||||
For each match:
|
||||
1. Read the file with context (-B 5 -A 5)
|
||||
2. Determine if it's a true positive
|
||||
3. Identify the specific issue type
|
||||
4. Formulate fix recommendation
|
||||
|
||||
### Step 4: Generate Report
|
||||
|
||||
Format output as:
|
||||
|
||||
```markdown
|
||||
# Codable Audit Results
|
||||
|
||||
## Summary
|
||||
- Files scanned: [X]
|
||||
- Total issues: [Y]
|
||||
- HIGH: [Z]
|
||||
- MEDIUM: [A]
|
||||
- LOW: [B]
|
||||
|
||||
## 🔴 High Priority Issues ([count])
|
||||
|
||||
### Manual JSON String Building
|
||||
- **file/path.swift:45** - Building JSON with string interpolation
|
||||
```swift
|
||||
let json = "{\"key\": \"\(value)\"}"
|
||||
```
|
||||
**Fix**: Use JSONEncoder with Codable type
|
||||
**Impact**: Injection vulnerabilities, escaping bugs
|
||||
|
||||
### try? Swallowing Errors
|
||||
- **file/path.swift:89** - Silent decode failure with try?
|
||||
```swift
|
||||
let user = try? decoder.decode(User.self, from: data)
|
||||
```
|
||||
**Fix**: Handle DecodingError cases explicitly
|
||||
**Impact**: Silent data loss, impossible to debug
|
||||
|
||||
## 🟡 Medium Priority Issues ([count])
|
||||
|
||||
### JSONSerialization Usage
|
||||
- **file/path.swift:112** - Using legacy JSONSerialization
|
||||
**Fix**: Migrate to Codable
|
||||
**Time saved**: Reduce boilerplate by 60%
|
||||
|
||||
### Date Handling
|
||||
- **file/path.swift:134** - Date property without explicit strategy
|
||||
**Fix**: Set decoder.dateDecodingStrategy = .iso8601
|
||||
**Impact**: Prevents timezone bugs
|
||||
|
||||
## 🟢 Low Priority Issues ([count])
|
||||
|
||||
[List issues with file:line and brief description]
|
||||
|
||||
## Recommendations
|
||||
|
||||
1. **Immediate**: Fix all HIGH severity issues (silent failures, injection risks)
|
||||
2. **This sprint**: Address MEDIUM severity (technical debt, potential bugs)
|
||||
3. **Backlog**: Clean up LOW severity (code quality improvements)
|
||||
|
||||
## Quick Wins
|
||||
|
||||
[List 2-3 most impactful fixes that take <10 minutes each]
|
||||
```
|
||||
|
||||
## Audit Guidelines
|
||||
|
||||
1. Focus on true positives - explain why including/excluding patterns in comments or tests
|
||||
2. Provide context by showing surrounding code in reports
|
||||
3. Give actionable fixes - show the correct pattern, not just "fix this"
|
||||
4. Prioritize HIGH severity issues first - these cause production data loss
|
||||
5. Be helpful with try? - suggest which DecodingError cases to handle
|
||||
|
||||
## Common False Positives
|
||||
|
||||
1. **String interpolation in logging**: `logger.debug("{...}")` - OK, not building actual JSON
|
||||
2. **JSON in comments or documentation**: Ignore
|
||||
3. **Test fixtures**: String JSON for test data is acceptable (but note it)
|
||||
4. **try? for optional decoding**: If the optional is intentional, it's OK (but verify)
|
||||
|
||||
## If No Issues Found
|
||||
|
||||
```markdown
|
||||
# Codable Audit Results
|
||||
|
||||
✅ **No issues found**
|
||||
|
||||
Your codebase follows Codable best practices:
|
||||
- No manual JSON string building
|
||||
- Proper error handling (no try? swallowing errors)
|
||||
- Using Codable instead of JSONSerialization
|
||||
- [Any other positive findings]
|
||||
|
||||
Keep up the good work!
|
||||
```
|
||||
|
||||
## Your Tone
|
||||
|
||||
- **Direct but helpful**: "This pattern causes silent data loss" not "This might be a problem"
|
||||
- **Evidence-based**: Show the code, explain the impact
|
||||
- **Action-oriented**: Always provide the fix
|
||||
- **Respectful**: Acknowledge when patterns are edge cases or acceptable tradeoffs
|
||||
|
||||
Good luck! Be thorough but concise.
|
||||
3
.claude/skills/axiom-audit-codable/agents/openai.yaml
Normal file
3
.claude/skills/axiom-audit-codable/agents/openai.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
interface:
|
||||
display_name: "Audit Codable"
|
||||
short_description: "The user mentions Codable review, JSON encoding/decoding issues, data serialization audit, or modernizing legacy code."
|
||||
Reference in New Issue
Block a user