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-core-data/.openskills.json
Normal file
7
.claude/skills/axiom-audit-core-data/.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-core-data",
|
||||
"installedAt": "2026-04-12T08:05:49.840Z"
|
||||
}
|
||||
407
.claude/skills/axiom-audit-core-data/SKILL.md
Normal file
407
.claude/skills/axiom-audit-core-data/SKILL.md
Normal file
@@ -0,0 +1,407 @@
|
||||
---
|
||||
name: axiom-audit-core-data
|
||||
description: Use when the user mentions Core Data review, schema migration, production crashes, or data safety checking.
|
||||
license: MIT
|
||||
disable-model-invocation: true
|
||||
---
|
||||
# Core Data Auditor Agent
|
||||
|
||||
You are an expert at detecting Core Data safety violations that cause production crashes and permanent data loss.
|
||||
|
||||
## Your Mission
|
||||
|
||||
Run a comprehensive Core Data safety audit and report all issues with:
|
||||
- File:line references for easy fixing
|
||||
- Severity ratings (CRITICAL/HIGH/MEDIUM/LOW)
|
||||
- Specific violation types
|
||||
- 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 CRITICAL/HIGH details
|
||||
- Always show: Severity counts, top 3 files by issue count
|
||||
|
||||
## What You Check
|
||||
|
||||
### 1. Schema Migration Safety (CRITICAL)
|
||||
**Pattern**: Missing `NSMigratePersistentStoresAutomaticallyOption` and `NSInferMappingModelAutomaticallyOption`
|
||||
**Issue**: 100% of users crash on app launch when schema changes
|
||||
**Fix**: Add lightweight migration options to store configuration
|
||||
|
||||
### 2. Thread-Confinement Violations (CRITICAL)
|
||||
**Pattern**: NSManagedObject accessed outside `perform/performAndWait`
|
||||
**Issue**: Production crashes when objects accessed from wrong threads
|
||||
**Fix**: Use `perform` or `performAndWait` for all context access
|
||||
|
||||
### 3. N+1 Query Patterns (MEDIUM)
|
||||
**Pattern**: Relationship access inside loops without prefetching
|
||||
**Issue**: 1000 items = 1000 extra database queries, 30x slower
|
||||
**Fix**: Use `relationshipKeyPathsForPrefetching` before fetch
|
||||
|
||||
### 4. Production Risk Patterns (CRITICAL)
|
||||
**Pattern**: Hard-coded store deletion, `try!` on migration
|
||||
**Issue**: Permanent data loss for all users
|
||||
**Fix**: Remove delete patterns, add proper error handling
|
||||
|
||||
### 5. Performance Issues (LOW)
|
||||
**Pattern**: Missing `fetchBatchSize`, no faulting controls
|
||||
**Issue**: Higher memory usage with large result sets
|
||||
**Fix**: Add `fetchBatchSize = 20` to fetch requests
|
||||
|
||||
## Audit Process
|
||||
|
||||
### Step 1: Find All Core Data Files
|
||||
|
||||
Use Glob tool to find files:
|
||||
- Swift files: `**/*.swift`
|
||||
- Core Data models: `**/*.xcdatamodeld`
|
||||
|
||||
### Step 2: Search for Safety Violations
|
||||
|
||||
**Schema Migration Safety**:
|
||||
```bash
|
||||
# Find persistent store coordinator usage
|
||||
grep -rn "NSPersistentStoreCoordinator" --include="*.swift"
|
||||
grep -rn "addPersistentStore" --include="*.swift"
|
||||
|
||||
# Check for migration options (should match coordinator count)
|
||||
grep -rn "NSMigratePersistentStoresAutomaticallyOption" --include="*.swift"
|
||||
grep -rn "NSInferMappingModelAutomaticallyOption" --include="*.swift"
|
||||
|
||||
# Find dangerous store deletion
|
||||
grep -rn "FileManager.*removeItem.*storeURL" --include="*.swift"
|
||||
grep -rn "FileManager.*removeItem.*persistent" --include="*.swift"
|
||||
```
|
||||
|
||||
**Thread-Confinement Violations**:
|
||||
```bash
|
||||
# Find DispatchQueue usage with managed objects
|
||||
grep -rn "DispatchQueue.*NSManagedObject" --include="*.swift"
|
||||
grep -rn "Task.*NSManagedObject" --include="*.swift"
|
||||
|
||||
# Find async/await usage with managed objects (Swift 5.5+)
|
||||
grep -rn "async.*NSManagedObject" --include="*.swift"
|
||||
grep -rn "await.*\.save\(\)" --include="*.swift" | grep -v "perform"
|
||||
|
||||
# Check for proper context usage (should be frequent)
|
||||
grep -rn "\.perform\s*{" --include="*.swift"
|
||||
grep -rn "\.performAndWait" --include="*.swift"
|
||||
|
||||
# Check for Swift Concurrency context access (iOS 15+)
|
||||
grep -rn "context\.perform.*async" --include="*.swift"
|
||||
```
|
||||
|
||||
**N+1 Query Patterns**:
|
||||
```bash
|
||||
# Find relationship access in loops (more comprehensive)
|
||||
grep -rn "for.*in.*\." --include="*.swift" -A 3 | grep -E "\..*\?\..*|\..*\..*"
|
||||
|
||||
# Find fetch requests followed by loops without prefetching
|
||||
grep -rn "NSFetchRequest" --include="*.swift" -A 10 | grep "for.*in"
|
||||
|
||||
# Check for prefetching (should match fetch requests with loops)
|
||||
grep -rn "relationshipKeyPathsForPrefetching" --include="*.swift"
|
||||
|
||||
# Check for batch faulting as alternative
|
||||
grep -rn "\.propertiesToFetch" --include="*.swift"
|
||||
```
|
||||
|
||||
**Production Risk Patterns**:
|
||||
```bash
|
||||
# Find forced unwrapping/try! in Core Data
|
||||
grep -rn "try!\s*.*addPersistentStore" --include="*.swift"
|
||||
grep -rn "try!\s*.*coordinator" --include="*.swift"
|
||||
grep -rn "try!\s*.*context\.save" --include="*.swift"
|
||||
|
||||
# Find store deletion patterns
|
||||
grep -rn "removeItem.*persistent" --include="*.swift"
|
||||
|
||||
# Find saveContext without error handling
|
||||
grep -rn "func saveContext" --include="*.swift" -A 10 | grep -v "catch"
|
||||
grep -rn "context\.save\(\)" --include="*.swift" | grep -v "try" | grep -v "throws"
|
||||
```
|
||||
|
||||
**Performance Issues**:
|
||||
```bash
|
||||
# Find fetch requests
|
||||
grep -rn "NSFetchRequest" --include="*.swift"
|
||||
|
||||
# Check for batch size usage (should match fetch requests)
|
||||
grep -rn "fetchBatchSize" --include="*.swift"
|
||||
|
||||
# Check for faulting controls
|
||||
grep -rn "returnsObjectsAsFaults" --include="*.swift"
|
||||
```
|
||||
|
||||
### Step 3: Categorize by Severity
|
||||
|
||||
**CRITICAL** (Guaranteed crash or data loss):
|
||||
- Missing lightweight migration options
|
||||
- Thread-confinement violations
|
||||
- Hard-coded store deletion
|
||||
- `try!` on migration operations
|
||||
|
||||
**MEDIUM** (Performance degradation):
|
||||
- N+1 query patterns in loops
|
||||
- Missing relationship prefetching
|
||||
|
||||
**LOW** (Memory pressure):
|
||||
- Missing fetchBatchSize
|
||||
- No faulting controls
|
||||
|
||||
## Output Format
|
||||
|
||||
```markdown
|
||||
# Core Data Safety Audit Results
|
||||
|
||||
## Summary
|
||||
- **CRITICAL Issues**: [count] (Crash/data loss risk)
|
||||
- **MEDIUM Issues**: [count] (Performance degradation)
|
||||
- **LOW Issues**: [count] (Memory pressure)
|
||||
|
||||
## Risk Score: [0-10]
|
||||
(Each CRITICAL = +3 points, MEDIUM = +1 point, LOW = +0.5 points)
|
||||
|
||||
## CRITICAL Issues
|
||||
|
||||
### Missing Lightweight Migration Options
|
||||
- `AppDelegate.swift:45` - NSPersistentStoreCoordinator without migration options
|
||||
- **Risk**: 100% crash rate on schema change with error "The model used to open the store is incompatible with the one used to create the store"
|
||||
- **Fix**: Add migration options to store configuration
|
||||
```swift
|
||||
let options = [
|
||||
NSMigratePersistentStoresAutomaticallyOption: true,
|
||||
NSInferMappingModelAutomaticallyOption: true
|
||||
]
|
||||
try coordinator.addPersistentStore(
|
||||
ofType: NSSQLiteStoreType,
|
||||
configurationName: nil,
|
||||
at: storeURL,
|
||||
options: options // ✅ Enables automatic lightweight migration
|
||||
)
|
||||
```
|
||||
|
||||
### Thread-Confinement Violations
|
||||
- `DataManager.swift:67` - NSManagedObject accessed from DispatchQueue.global()
|
||||
- **Risk**: Production crash with "NSManagedObject accessed from wrong thread"
|
||||
- **Fix**: Use backgroundContext.perform { }
|
||||
```swift
|
||||
// ❌ DANGER
|
||||
DispatchQueue.global().async {
|
||||
let user = context.object(with: objectID) as! User
|
||||
print(user.name) // Thread-confinement violation!
|
||||
}
|
||||
|
||||
// ✅ SAFE
|
||||
backgroundContext.perform {
|
||||
let user = backgroundContext.object(with: objectID) as! User
|
||||
print(user.name) // Safe - on correct thread
|
||||
}
|
||||
```
|
||||
|
||||
### Hard-Coded Store Deletion
|
||||
- `SetupManager.swift:89` - FileManager.removeItem(storeURL) in production code path
|
||||
- **Risk**: Permanent data loss for all users who hit this code path
|
||||
- **Typical scenario**: 10,000 users → 10,000 uninstalls + 1-star reviews
|
||||
- **Fix**: Remove or gate behind debug flag
|
||||
```swift
|
||||
// Option 1: Remove entirely
|
||||
// Deleted: try? FileManager.default.removeItem(at: storeURL)
|
||||
|
||||
// Option 2: Debug-only
|
||||
#if DEBUG
|
||||
try? FileManager.default.removeItem(at: storeURL)
|
||||
#endif
|
||||
```
|
||||
|
||||
### Forced Try on Migration
|
||||
- `PersistenceController.swift:123` - try! coordinator.addPersistentStore(...)
|
||||
- **Risk**: App crashes immediately on launch if migration fails
|
||||
- **Fix**: Add proper error handling
|
||||
```swift
|
||||
// ❌ DANGER
|
||||
try! coordinator.addPersistentStore(...) // Crashes if migration fails
|
||||
|
||||
// ✅ SAFE
|
||||
do {
|
||||
try coordinator.addPersistentStore(
|
||||
ofType: NSSQLiteStoreType,
|
||||
configurationName: nil,
|
||||
at: storeURL,
|
||||
options: migrationOptions
|
||||
)
|
||||
} catch {
|
||||
// Log error, show user message, attempt recovery
|
||||
handleMigrationFailure(error)
|
||||
}
|
||||
```
|
||||
|
||||
## MEDIUM Issues
|
||||
|
||||
### N+1 Query Pattern
|
||||
- `UserListView.swift:89` - Accessing user.posts in loop without prefetching
|
||||
- **Impact**: 1000 users = 1000 extra queries, 30x slower
|
||||
- **Fix**: Prefetch relationships before loop
|
||||
```swift
|
||||
// ❌ N+1 PROBLEM
|
||||
for user in users {
|
||||
print(user.posts.count) // Fires 1 query per user!
|
||||
}
|
||||
|
||||
// ✅ SOLUTION
|
||||
fetchRequest.relationshipKeyPathsForPrefetching = ["posts"]
|
||||
let users = try context.fetch(fetchRequest)
|
||||
for user in users {
|
||||
print(user.posts.count) // No extra queries!
|
||||
}
|
||||
```
|
||||
|
||||
- `DataSync.swift:201` - Accessing relationships in sync loop
|
||||
- **Impact**: Sync takes 30 seconds instead of 3 seconds
|
||||
- **Fix**: Same as above - prefetch relationships
|
||||
|
||||
## LOW Issues
|
||||
|
||||
### Missing Fetch Batch Size
|
||||
- `FetchController.swift:45` - NSFetchRequest without fetchBatchSize
|
||||
- **Impact**: Higher memory usage with large result sets (10,000 objects loaded at once)
|
||||
- **Fix**: Add batch size
|
||||
```swift
|
||||
fetchRequest.fetchBatchSize = 20
|
||||
// Loads 20 at a time - lower memory usage
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Fix CRITICAL issues immediately** - Production crash and data loss risk
|
||||
2. **Fix MEDIUM issues in next sprint** - Performance degradation
|
||||
3. **Test migration on real device** with production data copy
|
||||
4. **Add Core Data unit tests** for migration safety
|
||||
|
||||
## Testing Recommendations
|
||||
|
||||
After fixes:
|
||||
```bash
|
||||
# Test migration safety
|
||||
1. Install current version on device
|
||||
2. Add test data
|
||||
3. Build new version with schema change
|
||||
4. Install new version
|
||||
5. Verify: App launches + data intact
|
||||
|
||||
# Test thread-confinement
|
||||
1. Enable Thread Sanitizer in scheme
|
||||
2. Run app with extensive Core Data usage
|
||||
3. Check console for thread-confinement warnings
|
||||
|
||||
# Test N+1 queries
|
||||
1. Add logging to fetch requests
|
||||
2. Run UI with 1000+ items
|
||||
3. Count queries - should be minimal
|
||||
```
|
||||
|
||||
## For Detailed Diagnosis
|
||||
|
||||
Use `/skill axiom-core-data-diag` for:
|
||||
- Comprehensive Core Data diagnostics
|
||||
- Production crisis defense scenarios
|
||||
- Safe migration patterns
|
||||
- Schema change workflows
|
||||
```
|
||||
|
||||
## Audit Guidelines
|
||||
|
||||
1. Run all 5 pattern searches for comprehensive coverage
|
||||
2. Provide file:line references to make issues easy to locate
|
||||
3. Show exact fixes with code examples for each issue
|
||||
4. Categorize by severity to help prioritize fixes
|
||||
5. Calculate risk score to quantify overall safety level
|
||||
|
||||
## When Issues Found
|
||||
|
||||
If CRITICAL issues found:
|
||||
- Emphasize crash risk and data loss
|
||||
- Recommend fixing before production release
|
||||
- Provide explicit error handling code examples
|
||||
- Calculate time to fix (usually 5-20 minutes per issue)
|
||||
|
||||
If NO issues found:
|
||||
- Report "No Core Data safety violations detected"
|
||||
- Note that runtime testing is still recommended
|
||||
- Suggest migration testing checklist
|
||||
|
||||
## False Positives
|
||||
|
||||
These are acceptable (not issues):
|
||||
- Store deletion behind `#if DEBUG` flag
|
||||
- One-time migration scripts (not in production code)
|
||||
- Background context access with proper `perform` blocks
|
||||
- Small loops (< 10 iterations) may not need prefetching
|
||||
|
||||
## Risk Score Calculation
|
||||
|
||||
- Each 🔴 CRITICAL issue: +3 points
|
||||
- Each 🟡 MEDIUM issue: +1 point
|
||||
- Each 🟢 LOW issue: +0.5 points
|
||||
- Maximum score: 10
|
||||
|
||||
**Interpretation**:
|
||||
- 0-2: Low risk, production-ready
|
||||
- 3-5: Medium risk, fix before release
|
||||
- 6-8: High risk, must fix immediately
|
||||
- 9-10: Critical risk, do not ship
|
||||
|
||||
## Common Findings
|
||||
|
||||
From auditing 100+ production codebases:
|
||||
1. **60% missing lightweight migration options** (most common)
|
||||
2. **40% have N+1 query patterns** (second most common)
|
||||
3. **20% have thread-confinement violations** (most dangerous)
|
||||
4. **10% have hard-coded store deletion** (data loss risk)
|
||||
|
||||
## Testing Scenarios
|
||||
|
||||
After fixes, test these scenarios:
|
||||
```
|
||||
1. Schema Migration
|
||||
- Add new Core Data attribute
|
||||
- Build and run on device with existing data
|
||||
- Verify: App launches + data migrates + new attribute works
|
||||
|
||||
2. Thread-Safety
|
||||
- Enable Thread Sanitizer
|
||||
- Use Core Data from background queues
|
||||
- Verify: No thread-confinement warnings
|
||||
|
||||
3. Performance
|
||||
- Load 1000+ items in list
|
||||
- Scroll through all items
|
||||
- Verify: < 10 database queries total (not 1000+)
|
||||
|
||||
4. Production Simulation
|
||||
- Test on real device (not simulator)
|
||||
- Use production data size (1000+ records)
|
||||
- Monitor memory usage and query count
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
This audit scans for:
|
||||
- **5 categories** covering 90% of Core Data production issues
|
||||
- **3 CRITICAL patterns** that cause crashes or data loss
|
||||
- **2 MEDIUM patterns** that cause performance degradation
|
||||
|
||||
**Fix time**: Most issues take 5-20 minutes each. Total audit + fixes typically < 2 hours.
|
||||
|
||||
**When to run**: Before every App Store submission, after schema changes, or quarterly for technical debt tracking.
|
||||
3
.claude/skills/axiom-audit-core-data/agents/openai.yaml
Normal file
3
.claude/skills/axiom-audit-core-data/agents/openai.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
interface:
|
||||
display_name: "Audit Core Data"
|
||||
short_description: "The user mentions Core Data review, schema migration, production crashes, or data safety checking."
|
||||
Reference in New Issue
Block a user