Skip to content

feat(memory): wire ContradictionDetector into soul note (#231 follow-up) #239

@prakashUXtech

Description

@prakashUXtech

Background

Soul.note() shipped in #233 (Phase 1) and the soul remember deprecation work landed in #236 (Phase 2). One acceptance criterion from #231 is still open: contradiction detection on the dedup path.

The runtime method accepts a detect_contradictions: bool | None = None parameter (defaults to True for semantic, False for the other tiers), but the implementation at src/soul_protocol/runtime/soul.py:1497-1498 is a TODO:

# TODO: wire ContradictionDetector — see issue #231 follow-up.
_ = detect_contradictions  # currently unused; reserved for follow-up.

A working ContradictionDetector already exists at src/soul_protocol/runtime/memory/contradiction.py:123 and is wired into MemoryManager.observe() (the cognitive pipeline). The remaining work is to expose it on the note() path.

Scope

  • When note() runs the dedup pipeline and the action is CREATE (the content is novel, not a SKIP/MERGE), pass the new entry through the existing ContradictionDetector.
  • If a contradiction is detected against an existing semantic fact, supersede the old fact with the new one (set old.superseded_by = new.id, mirror new.supersedes = old.id, record prediction_error per the Memory updates: brain-aligned primitive set (supersede + confirm + update + weight-decay forget) #192 memory-update primitives).
  • Respect the detect_contradictions parameter. The default (True for semantic, False elsewhere) stays.
  • Return the supersede in the result dict so callers can branch on it. Suggested shape: extend the existing return with "contradicted_id": str | None alongside the existing action / id / existing_id / similarity fields.

Acceptance

  • A semantic note() call that contradicts an existing fact returns {"action": "CREATE", "contradicted_id": "<old>", ...} and the old fact carries superseded_by
  • The same call with detect_contradictions=False skips the check and returns contradicted_id: None
  • Procedural / social tiers default-off behaviour preserved
  • New tests cover: clean CREATE (no contradiction), CREATE with contradiction → supersede, opt-out via detect_contradictions=False, the existing SKIP/MERGE paths unchanged
  • CHANGELOG entry under ## [Unreleased] / ### Memory update primitives

Out of scope

  • Refactoring ContradictionDetector itself. Whatever shape it has in MemoryManager.observe() is what note() should reuse.
  • New CLI flags. The existing --no-contradictions flag on soul note already maps cleanly to detect_contradictions=False (currently plumbed but a no-op).

Notes for mentees

Phase 1 of #231 left # TODO: wire ContradictionDetector as an explicit marker in the runtime, and the corresponding --no-contradictions CLI flag was plumbed without a backing implementation. Both will start working once this lands. Touches: runtime/soul.py (the TODO), the existing ContradictionDetector usage in manager.py (for the call shape), cli/main.py (verify the flag now actually has an effect), tests in tests/test_cli/ and tests/test_memory/ for the dedup-with-contradiction paths.

Tracking: closes the final acceptance item from #231.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions