Skip to content

fix: include social tier in deletion paths (#291) - #308

Open
sshekhar563 wants to merge 4 commits into
qbtrix:devfrom
sshekhar563:fix/issue-291-social-deletion
Open

fix: include social tier in deletion paths (#291)#308
sshekhar563 wants to merge 4 commits into
qbtrix:devfrom
sshekhar563:fix/issue-291-social-deletion

Conversation

@sshekhar563

Copy link
Copy Markdown
Collaborator

Problem

forget and forget_entity skip the social memory tier (#291).
All deletion paths iterate a hardcoded episodic → semantic → procedural
triad, ignoring social memories entirely.

Root Cause

When SocialStore was added in PR #41, the layer dispatch system
(_store_in_layer, _delete_in_layer, etc.) and serialization were wired
correctly, but 11 deletion/mutation functions in MemoryManager plus
Soul._forget_bulk() were never updated to include the social tier.

Fix

  1. Introduced MemoryManager._all_stores() — a single helper returning
    all four built-in stores as (name, store) tuples.
  2. Rewired forget(), forget_entity(), forget_before(), remove(),
    _find_entry_by_id(), forget_by_id(), purge_by_id(), count(),
    update_in_place(), set_retrieval_weight(), and supersede() to
    use the helper instead of hardcoded triad iteration.
  3. Updated Soul._forget_bulk() (v0.5.0 weight-decay path) to include
    social.

Files Changed

  • src/soul_protocol/runtime/memory/manager.py — primary fix + _all_stores() helper
  • src/soul_protocol/runtime/soul.py — fix _forget_bulk() weight-decay path
  • tests/test_gdpr_deletion.py — 10 new tests + 2 updated assertions

Testing

  • 67 tests pass (all related suites)
  • New tests verify: _find_entry_by_id finds social, forget/forget_entity/forget_before/purge_by_id all operate on social memories, round-trip persistence (save → awaken → forget → re-awaken), and audit trail coverage.
  • No regressions to existing deletion or memory tests.

Risk

Low. The fix is additive. The _all_stores() helper is 4 lines. No public
API changes. No RecallEngine changes.

Closes #291

@prakashUXtech prakashUXtech left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the strongest fail-without-fix evidence in the batch — 10 of your new tests fail on dev with correct root causes, including a real save → awaken → forget → re-awaken round-trip that asserts on persisted retrieval weight. And _all_stores() is the right shape: one list, twelve call sites, so a fifth tier is picked up everywhere automatically. Tracing it back to when SocialStore was added was good diagnosis.

Three things before merge, and the first is structural.

1. The branch is mis-stacked. fix/issue-291-social-deletion was cut from docs/drift-290, not from dev, but declares base: dev. Commit a62eff1 in this PR is byte-identical to #307's head — so merging #308 would land #290's documentation under the #291 title and leave #307 with nothing. Rebase onto origin/dev and drop a62eff1. (This is the third PR in this batch stacked on an unmerged sibling without declaring it — worth making a habit of git log --oneline origin/dev..HEAD before opening.)

2. The operator-facing surfaces still under-report social — the same false-assurance the issue is about, moved up a layer. soul forget --entity Alice now genuinely deletes social entries, but _tier_counts in cli/main.py omits social from the printed breakdown, so the operator sees nothing in social and concludes nothing was there. Same in the MCP forget tool's tiers, and forgetting a social id displays total: 1 with all three tier lists empty. If the point is that operators shouldn't wrongly believe data is gone, they equally shouldn't wrongly believe it was never there.

3. Soul._memory_lookup_sync still skips social — and its docstring says "Synchronous lookup across all built-in stores". That's the exact bug #291 names, in a function whose docstring now actively lies. It's what the provenance walker uses to resolve a cursor, so a chain walk silently stops at a social entry.

Two regressions the PR introduces:

soul status Total no longer adds up. count() now includes social, and it feeds memory_count, but the status panel prints only three tier rows. So you get Episodic 4 / Semantic 7 / Procedural 2 and then "Total 16" with five social memories invisible. Same shape in demo.py. count() wasn't in #291's scope — either add the Social row or revert that change.

count() re-arms the bug inside the helper meant to prevent it. It iterates _all_stores() and then throws the iteration away:

for _name, store in self._all_stores():
    if _name == "episodic":
        total += len(self._episodic._memories)
    elif _name == "semantic":
        ...

store is bound and never used, so a fifth tier added to _all_stores() falls through every branch and counts as zero, silently. SocialStore.count() exists — total += store.count() is what the surrounding comment already tells you to do.

Then: a CHANGELOG entry (this changes the forget* return shape — additive, but declare it); the soul.py header comment; v0.6.0 in two comments should be v0.5.0; four stale doc lines in api-reference.md and cli-reference.md that still list the three-tier result shape and supersede --type choices; and tests for update/supersede on a social id, since the issue named those and only purge is covered.

One for a follow-up issue: _all_stores() covers the four built-ins but not custom layers or the archival store, and BondRegistry still holds Alice's bond record after forget_entity("Alice") — strength, interaction count, bonded-at, persisted to the .soul. Until those close, "GDPR-complete" is overclaiming; worth a .. note:: in the docstring naming what isn't covered.

The core fix is genuinely correct — these are mechanical.

_forget_bulk(), forget(), forget_entity(), forget_before(), remove(),
_find_entry_by_id(), forget_by_id(), purge_by_id(), update_in_place(),
set_retrieval_weight(), supersede(), and count() now all iterate over
the social memory tier alongside episodic/semantic/procedural.

A new _all_stores() helper centralizes tier iteration so future tiers
are never silently skipped again.

Closes qbtrix#291
… count(), docs, tests (qbtrix#291)

- Rebase onto upstream/dev, drop stacked qbtrix#290 docs commit
- Add social to _tier_counts, forget --id reshape, soul status panel
- Fix _memory_lookup_sync to include social (provenance walker)
- Fix count() to use generic store.count() (add count() to all stores)
- Add social to MCP soul_forget/soul_health tiers
- Add social to supersede --type CLI choice
- Update stale 3-tier doc lines in api-reference.md and cli-reference.md
- Add CHANGELOG entry for qbtrix#291 (additive: social key in forget return)
- Add GDPR coverage-gap docstring to forget_entity
- Add tests: update/supersede on social IDs, _memory_lookup_sync social
@sshekhar563
sshekhar563 force-pushed the fix/issue-291-social-deletion branch from 67fba46 to a10b4b5 Compare August 10, 2026 10:19

@prakashUXtech prakashUXtech left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good pass — the mis-stacking is gone (the diff is now three commits, all #291), and most of the list is genuinely fixed. Confirmed: _memory_lookup_sync covers social with a test; all three operator surfaces now report it (_tier_counts, the forget --id reshape, and the MCP tool's tiers), plus supersede --type gained social as a bonus; count() is now a clean sum(store.count() for ...) so a fifth tier can't silently count zero; there are tests for update/supersede on a social id; and the CHANGELOG entry landed in the right section. I also mutation-tested the core: removing ("social", self._social) from _all_stores() turns 9 tests red, so the fix is genuinely pinned.

One correction to my own last review: the tier-table-with-Total panel is in soul inspect, not soul status. You fixed inspect correctly — my pointer was wrong.

Five small things left, and two of them are new:

New — MCP soul_health is now internally inconsistent. mcp/server.py:1564 still computes total = len(episodic) + len(semantic) + len(procedural) while the tiers dict at :1612 now reports social. A consumer summing the tiers won't get total. That's the same bug class you just fixed in inspect, re-created one file over.

New — the doc fix outran the code. docs/cli-reference.md:1610 now says soul health shows "episodic, semantic, procedural, social", but health_cmd still reads and prints three tiers. That's drift in the opposite direction, which is a bit ironic in this PR. I'd fix the code side rather than walk the doc back, since the MCP tool already reports social.

Then: demo.py:349-360 still lists three tier rows against a Total that now includes social; soul.py's header comment has no #291 entry; and v0.6.0 should be v0.5.0 in two comments (manager.py:1336, soul.py:2715) since the package is 0.5.0.dev0.

Two more worth knowing. Your forget_entity() reshape moved edges_removed to the front of the return dict — harmless for dict access, but it'll shift any golden JSON snapshot, and it isn't in the CHANGELOG. And health analytics on both surfaces still build all_mems from three tiers, so duplicate/low-importance/orphan detection never sees social entries — pre-existing rather than yours, but the same tier-blindness and worth a follow-up issue.

Cheap addition: nothing currently pins soul.memory_count including a social entry, which is exactly what regressed. One assertion would cover it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants