---
phase: 21-fix-image-input-deduplication
plan: 01
type: execute
---
Resolve duplicate image saving across input/generated images by unifying the hashing approach.
Purpose: Ensure the deduplication system consistently prevents duplicate files in the generations folder by using the same hashing algorithm everywhere.
Output: Consistent MD5 hashing across all image saving operations.
~/.claude/get-shit-done/workflows/execute-phase.md
~/.claude/get-shit-done/templates/summary.md
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
# Key source files:
@src/app/api/save-generation/route.ts
@src/utils/imageStorage.ts
# Prior phase with related hashing decision:
@.planning/phases/13-fix-duplicate-generations/13-01-SUMMARY.md
**Tech stack available:** Next.js 16, Zustand
**Established patterns:** MD5 content hashing for deduplication (Phase 13)
**Issues being addressed:**
1. ~~nano-banana-pro model generates without considering image inputs~~ - RESOLVED (no longer an issue)
2. Input and generated images have duplicate files despite different hashes - need consistent hashing approach
**Root cause:**
- imageStorage.ts uses position-based sampling hash while save-generation uses MD5 - these are incompatible
- Same image saved via different code paths gets different hashes
Task 1: Unify image hashing to MD5 across all save operations
src/utils/imageStorage.ts
Replace the position-based sampling hash in imageStorage.ts with MD5 content hashing (matching save-generation/route.ts pattern).
The current approach at line 209-211 uses a weak hash based on string length and sampled substrings:
```
const hash = `${folder}-${len}-${imageData.substring(50, 100)}-${imageData.substring(mid, mid + 50)}-${imageData.substring(Math.max(0, len - 50))}`;
```
This is problematic because:
1. Different hash method than save-generation API (MD5)
2. Same image can get different hashes if saved via different paths
3. Position-based sampling is weak for dedup (similar images may have same samples)
Replace with:
1. Import crypto at top: `import crypto from "crypto";`
2. Create helper: `function computeContentHash(data: string): string { return crypto.createHash("md5").update(data).digest("hex"); }`
3. Replace the hash computation: `const hash = `${folder}-${computeContentHash(imageData)}`;` (folder prefix still needed to separate inputs/generations)
WHY: MD5 is already used in save-generation (Phase 13 decision), provides reliable deduplication, and is fast enough for our use case.
Build succeeds with `npm run build`. TypeScript types check with no errors.
imageStorage.ts uses MD5 hashing, consistent with save-generation API. Same image saved twice gets same hash and is deduplicated.
Before declaring phase complete:
- [ ] `npm run build` succeeds without errors
- [ ] `npm test` passes all existing tests
- [ ] No TypeScript errors in modified files
- Task completed
- All verification checks pass
- Deduplication uses consistent MD5 hashing across all image save paths