Skip to content

[GH-1102] Clean invalid episode_ids during ingestion - #1148

Merged
jealous merged 2 commits into
mainfrom
quickfix/1102
Feb 28, 2026
Merged

jealous merged 2 commits into
mainfrom
quickfix/1102

Conversation

@o-love

@o-love o-love commented Feb 27, 2026 •

Copy link
Copy Markdown
Contributor

Purpose of the change

Gracefully handle invalid episode_id entries discovered during semantic ingestion instead of crashing the pipeline. This is a quick fix for #1102 while the root cause of the invalid IDs is still being investigated.

Description

When _process_single_set fetches episode history, some episode_id references in the semantic store may point to episodes that no longer exist (returning None). Previously this raised a hard ValueError, halting the entire ingestion pipeline.

This change:

  • Filters out None results directly in the list comprehension, removing the redundant second filter.
  • Logs a warning (downgraded from error, since the service recovers) listing the invalid IDs and the affected set_id.
  • Deletes the invalid entries from semantic storage so they don't block future ingestion runs.
  • Preserves a debug_fail_loudly path that raises immediately in debug/test environments so the issue is still surfaced during development.
  • Adds two tests: one verifying the recovery path (delete + continue), and one verifying the raise behavior in debug mode.

Fixes/Closes

Related to #1102

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

  • Unit Test

Two new async pytest cases in tests/memmachine/semantic_memory/test_semantic_ingestion.py:

  • test_process_single_set_deletes_invalid_episode_ids — confirms invalid IDs are delisted and valid messages are still processed.
  • test_process_single_set_raises_in_debug_mode_for_invalid_ids — confirms ValueError is raised with debug_fail_loudly=True.

Checklist

  • I have signed the commit(s) within this pull request
  • My code follows the style guidelines of this project (See STYLE_GUIDE.md)
  • I have performed a self-review of my own code
  • I have commented my code
  • My changes generate no new warnings
  • I have added unit tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have checked my code and corrected any misspellings

Screenshots/Gifs

N/A

Further comments

This is an interim fix. The root cause of why invalid episode_id references end up in the semantic store is still under investigation. Once resolved, the recovery/deletion logic here will act as a safety net rather than the primary handling path.

Copilot AI 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.

Pull request overview

This PR addresses issue #1102 by making semantic ingestion resilient to dangling/invalid episode_id references in semantic storage, optionally failing loudly in debug mode.

Changes:

  • Filter out missing episodes during ingestion and collect invalid history_ids.
  • In non-debug mode, delete invalid history_ids from semantic storage instead of raising.
  • Add error logging and a debug-only exception path for faster investigation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 111 to +126
if len(none_h_ids) != 0:
raise ValueError(
"Failed to retrieve messages. Invalid episode_ids exist for set_id "
f"{set_id}: {none_h_ids}"
logger.error(
"Failed to retrieve messages. Invalid episode_ids exist for set_id %s, will delist following messages: %s",
set_id,
none_h_ids,
)
if self._debug_fail_loudly:
raise ValueError(
"Failed to retrieve messages due to invalide episode_ids"
)

try:
await self._semantic_storage.delete_history(
history_ids=none_h_ids,
)
except Exception:

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

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

There are existing tests for IngestionService, but this new behavior (deleting invalid history_ids from semantic storage and the _debug_fail_loudly branch) isn’t covered. Adding a test that seeds a set with one valid and one missing episode_id and asserts delete_history() is called (and that debug mode raises) would prevent regressions.

Copilot uses AI. Check for mistakes.
)
if self._debug_fail_loudly:
raise ValueError(
"Failed to retrieve messages due to invalide episode_ids"

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

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

The debug-mode ValueError message has a typo ("invalide") and drops the most useful context (set_id and the invalid episode_ids). Consider fixing the spelling and including set_id + none_h_ids in the exception text so debug runs remain actionable.

Suggested change
"Failed to retrieve messages due to invalide episode_ids"
f"Failed to retrieve messages for set_id {set_id} due to invalid episode_ids: {none_h_ids}"

Copilot uses AI. Check for mistakes.
Comment on lines +112 to +113
logger.error(
"Failed to retrieve messages. Invalid episode_ids exist for set_id %s, will delist following messages: %s",

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

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

This condition is handled by deleting the bad history references, so logging it at ERROR may be misleading operationally (it can trigger alerts despite the service recovering). Consider using WARNING (and/or clarifying the wording to indicate recovery) unless you intend to treat this as a hard failure.

Suggested change
logger.error(
"Failed to retrieve messages. Invalid episode_ids exist for set_id %s, will delist following messages: %s",
logger.warning(
"Failed to retrieve messages. Invalid episode_ids exist for set_id %s; delisting the following messages as recovery: %s",

Copilot uses AI. Check for mistakes.
Comment thread src/memmachine/semantic_memory/semantic_ingestion.py Outdated
@o-love
o-love marked this pull request as ready for review February 28, 2026 00:25
…nt filter, add tests

- Fix 'invalide' typo and include set_id + invalid IDs in ValueError message
- Change logger.error to logger.warning since service recovers by deleting
- Remove redundant raw_messages None filter (already filtered in comprehension)
- Add tests for delete_history recovery path and debug_fail_loudly raise
@jealous
jealous merged commit d08339b into main Feb 28, 2026
48 checks passed
@o-love
o-love deleted the quickfix/1102 branch February 28, 2026 01:05
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.

4 participants