v0.15.6 — think() reports the conflicts it wrote
Patch release. think()'s conflicts_found counted two of the three code paths that persist conflicts, so a real, stored conflict was reported as zero — the number every caller reads, every example prints, and every integration logs.
db.record("Sarah works at Google")
db.record("Sarah works at Meta")
db.think()["conflicts_found"] # 0.15.5 -> 0 0.15.6 -> 1
len(db.get_conflicts()) # 1 1"Acme is based in Boston." / "...Denver." always reported 1 correctly, because it travels the claim path — which was counted. That difference is why the two documented examples looked incoherent side by side.
The fix
conflicts_found is now the delta across the whole cycle rather than the sum of two scans, so it means "rows this think() persisted" and stays correct when a fourth writer is added. Phase 1's redundancy check — learned substitution categories — was persisting conflicts through create_conflict and returning only its triggers, before the counter was even computed.
Verified on the real path
The in-tree test cannot reach the path that caused this: it uses the bundled 64-dim embedder, and the redundancy path gates on ≥0.85 embedding similarity. So the wheel was built from the merge and the original repro run against the 256-dim default embedder, with a regression sweep confirming the claim path is unchanged, unrelated memories still report 0, and repeated think() calls stay idempotent.
Not changed
IDENTITY_CATEGORIES still contains only cloud_providers, so llm_providers maps to Preference rather than IdentityFact. Where someone works is arguably an identity fact; that is a separate decision, tracked with #142.
Closes #142.