0ecd1ce4f1
Cluster C, milestone #94. BulkTagService.tag_gaps(image_ids, threshold) finds tags applied to >= threshold fraction of a visual neighbour set but not all of it (the '7 of 10 share Miku; these 3 don't' signal). Each gap carries the laggard image ids minus any TagSuggestionRejection rows, so apply-to-cluster never re-proposes a tag a neighbour dismissed. 100%-common tags and <2-image sets are excluded. New POST /api/images/cluster/tag-gaps. Tests: consensus found / common excluded / missing ids; rejected laggard excluded from missing; tag dropped when all laggards rejected; <2 images empty; route shape + bad input. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XCUHUGQLrBrkgyk1t49kpX