# aphoria-error-mapping

## AUDIT (2026-02-06)

**Pattern:** Inconsistent `.map_err()` patterns across Aphoria codebase

**Analysis:**
Found 152 `.map_err()` calls across 4 patterns:

| Pattern | Count | Action |
|---------|-------|--------|
| A - Context-aware `format!()` | 55 | ✅ Keep as standard |
| B - Direct `.to_string()` | 35 | ❌ Replace with A |
| C - Bare `format!()` (returns String) | 11 | ❌ Replace with A |
| D - Custom closure logic | 43 | ⚠️ Keep for structured errors |

**Standard Pattern (A):**
```rust
some_op().map_err(|e| AphoriaError::Variant(format!(
    "Failed to do X at Y: {}",
    e
)))?;
```

**Anti-Pattern (B):**
```rust
some_op().map_err(|e| AphoriaError::Variant(e.to_string()))?;
// Loses context: what operation? what was the file/path?
```

**Files to fix (by priority):**

1. `episteme/local/store.rs` - 13 Pattern B instances
2. `episteme/local/mod.rs` - 4 Pattern B instances
3. `walker/mod.rs`, `walker/git.rs` - 4 Pattern B instances
4. `policy.rs`, `policy_ops.rs` - 6 Pattern B instances
5. `corpus/rfc/mod.rs`, `owasp/mod.rs` - 3 Pattern B instances
6. `episteme/aliases.rs`, `drift.rs` - 5 Pattern B instances
7. `hosted.rs` - 11 Pattern C instances

**Total changes needed:** 46 instances

## FIX (2026-02-06)

- [x] `episteme/local/store.rs` - Fixed 13 Pattern B instances:
  - serialize_assertion → "Failed to serialize claim/observation/authoritative assertion"
  - journal.append → "Failed to append to WAL"
  - journal.force_sync → "Failed to sync WAL"
  - ingestor.process_pending → "Failed to process ingestion"
  - get_by_predicate → "Failed to fetch predicate index"
- [x] `episteme/local/mod.rs` - Fixed 4 Pattern B instances:
  - Journal::open → "Failed to open WAL at {path}"
  - HybridStore::open → "Failed to open store at {path}"
  - Ingestor::new → "Failed to create ingestor"
  - load_or_generate_key → "Failed to load/generate signing key at {path}"
- [x] `walker/mod.rs` + `git.rs` - Fixed 2 Pattern B instances:
  - directory entry → "Failed to read directory entry"
  - git diff → "Failed to execute git diff command"
- [x] `policy.rs` + `policy_ops.rs` - Fixed 7 Pattern B instances:
  - write/read policy file with path context
  - cache file creation with path context
  - assertion serialization with subject context
  - alias import with alias names
- [x] `episteme/aliases.rs` + `drift.rs` - Fixed 4 Pattern B instances:
  - get_canonical → with code_path context
  - set_alias → with both paths context
  - list_all_aliases → with operation description
  - get_by_predicate → with operation description
- [x] `hosted.rs` - Fixed Pattern C (11 instances → AphoriaError::Hosted):
  - Changed return types from `Result<T, String>` to `Result<T, AphoriaError>`
  - All HTTP errors now use `AphoriaError::Hosted(format!(...))`
- [x] `corpus/rfc/mod.rs` + `owasp/mod.rs` - Already using context-aware patterns:
  - Uses structured error variants with rfc/sheet context

**Remaining:** 1 instance in policy.rs:206 - intentionally ignores error (signature validation)

## ENFORCE (2026-02-06)

Added to `.claude/skills/aphoria-dev/skill.md`:
- **Do Not #12:** "Use generic `.map_err(|e| AphoriaError::X(e.to_string()))`. Always include operation context in error messages."
- **ALWAYS:** "Use context-aware error mapping: `.map_err(|e| AphoriaError::X(format!("Failed to Y: {e}")))`"

## COMPLETE (2026-02-06)

**Before:** 46 Pattern B/C instances
**After:** 1 intentional exception (signature validation)
**Fixed:** 45 instances across 10 files
