Step 2 of the snippet-merge milestone (#231). The dedup gate only PREVENTS
new near-duplicates; merge is the CURE for the ones already scattered.
- services/snippets.py: merge_snippets(user_id, target_id, source_ids) —
keep the target's scalar fields (name/when_to_use/signature/language/
code), union the sources' locations + extra tags onto it (so the survivor
carries every call site as a location), trash the sources (recoverable),
re-embed the survivor. Pure merge_snippet_fields() factored out for unit
testing. Returns (survivor_note, merged_ids).
- mcp/tools/snippets.py: merge_snippets(target_id, source_ids) tool (5th),
and a create_snippet dedup-path nudge toward merge over a forced copy.
- routes/snippets.py: POST /api/snippets/<id>/merge {source_ids} — share-
aware (can_write target + every source, rule #78) with a same-owner guard
(cross-owner merge is out of scope).
- plugin reusing-code skill + MCP _INSTRUCTIONS: point found-duplicates at
merge as the cure (rule #119 surfaces, not a Scribe rule). plugin.json
0.1.13 -> 0.1.14 in the same change (the #1040 marketplace-ship lesson).
- Tests: pure merge-helper union/dedup; MCP tool (requires a source,
survivor+merged_ids, not-found); route handler + 5-tool registration.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pa2EsuB54BuWQ8GfJq9c7t
Record reusable functions/components once so they surface via the existing
semantic search + title-first auto-inject, instead of re-solving as one-offs.
A snippet is a Note with note_type='snippet' (no schema change): note_type is
free-text, and semantic_search_notes never filters by type, so snippets join
the recall/auto-inject pool the moment they're embedded. Structured fields
(name/language/signature/location/when_to_use/code) are stored via a body
convention — title = "name — when to use" (what auto-inject surfaces), language
+ "snippet" as tags, templated markdown body — keeping storage swappable later
without changing the tool/UI contract.
- services/snippets.py: compose/parse helpers + create/get/list/update wrappers
over notes_svc (dedup + System association reused).
- mcp/tools/snippets.py: list_snippets / create_snippet / get_snippet /
update_snippet, registered in tools/__init__.py.
- unit tests for the serialize/parse round-trip and the MCP tool surface.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pa2EsuB54BuWQ8GfJq9c7t