refactor(entities): relocate consolidation out of indexer + add fuzzy gate
Extract `consolidate_segment_entities` out of `think/indexer/journal.py`
into `think/entities/consolidation.py` as `consolidate_detected_entities`.
Insert a `find_matching_entity` gate (threshold 85) before any new slug
is written, and route all writes through `save_journal_entity` instead
of a direct `atomic_write`. Remove the implicit call from `scan_journal`
so it is pure with respect to `journal/entities/` state. Expose the
operation as `sol call entities consolidate [--full]`.
Also relocates `is_noise_entity` + `_NOISE_ENTITY_RE` to
`think/entities/core.py` so the new module does not cross into
`think.indexer`, and updates `apps/graph/routes.py` to follow.
This closes V1 in the layer-hygiene allowlist. Historical duplicates
(8 Jeremie-variant entities on the live journal) are NOT cleaned up
here — a separate merge pass will handle them.
Regression coverage: `test_scan_journal_is_pure_wrt_entity_state` in
`tests/test_journal_index.py` seeds a detection file and snapshots
`journal/entities/` across two full scans. Five unit/CLI tests in
`tests/test_entities_consolidation.py` cover create, fuzzy-skip,
unrelated-create, idempotence, and CLI dispatch.
Parent plan: vpe/workspace/plan-bundle-a-entity-write-ownership.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>