Skip to content

test(api): add recent activity hydration regression coverage#716

Merged
phernandez merged 1 commit intomainfrom
codex/recent-activity-hydration-test
Apr 3, 2026
Merged

test(api): add recent activity hydration regression coverage#716
phernandez merged 1 commit intomainfrom
codex/recent-activity-hydration-test

Conversation

@phernandez
Copy link
Copy Markdown
Member

Summary

  • add regression tests for batched recent_activity hydration in to_graph_context()
  • prove entities, observations, and relations share one find_by_ids(...) lookup
  • verify empty context results skip entity hydration entirely

Why

Issue #710 described an N+1 lookup pattern in recent_activity hydration. The batching logic is already present on main, so this PR adds regression coverage to make sure that behavior stays in place.

Refs #710.

Test plan

  • uv run pytest -q tests/api/v2/test_search_hydration.py tests/api/v2/test_memory_hydration.py tests/api/v2/test_utils_telemetry.py

Signed-off-by: phernandez <paul@basicmachines.co>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

Claude finished @phernandez's task in 2m 23s —— View job


PR Review: test(api): add recent activity hydration regression coverage

  • Gather context (PR metadata, changed files)
  • Read the new test file (tests/api/v2/test_memory_hydration.py)
  • Read relevant source files (api/v2/utils.py, context_service.py, search.py)
  • Review against team checklist
  • Post final review

Summary

This PR adds clean regression coverage for the N+1 fix from #710. The test structure mirrors the existing test_search_hydration.py and correctly verifies both the batching invariant and the hydrated data.

Code Quality Checklist

Item Status Notes
Follows coding conventions (CLAUDE.md) Consistent style, good section headers
Python 3.12+ type annotations from __future__ import annotations, proper hints
100-char line length No violations observed
No commented-out code
Unit tests for new logic Two tests with distinct scenarios
Edge case coverage Empty results path tested
100% coverage maintained PR only adds tests, no new uncovered production code
No hardcoded secrets
No emojis/unicode in output
Windows-compatible paths N/A No os.path comparisons
DB changes / Alembic N/A No schema changes
MCP / architecture concerns N/A Pure unit test

Review Observations

The good:

  1. SpyEntityRepository pattern (line 45-54) — clean duck-typed spy that mirrors SpyEntityService in test_search_hydration.py. Consistent with established test conventions.

  2. Batch assertion is precise (line 158-159) — assert len(repo.calls) == 1 followed by assert set(repo.calls[0]) == {1, 2, 3} verifies both the call count (eliminates N+1) and that all three entity types (entity, observation parent, relation from/to) contribute IDs to the single lookup. This is the right invariant to lock down.

  3. Data hydration correctness is also verified (lines 161-175) — not just the call count but the actual populated fields (external_id, entity_external_id, from_entity, to_entity_external_id). This prevents silent regressions where the batch fires but data is wired incorrectly.

  4. SearchItemType is str, Enum — passing type="entity" string literals in _make_row compares correctly to SearchItemType.ENTITY in production code. No test brittleness here.

Minor observations (no blockers):

  1. root_id=11 for child_observation and peer_entity (lines 108, 121) — 11 is the ID of child_observation itself, used as the grouping key for the second ContextResultItem. This is valid since root_id is just a grouping anchor, but it's a subtle choice. A brief inline comment would help future readers understand why the grouping key is 11 (the observation's own ID) rather than an entity ID.

  2. SpyEntityRepository does not inherit EntityRepositoryto_graph_context is typed entity_repository: EntityRepository, so pyright would flag the test call at line 156. This follows the same pattern as SpyEntityService, so it's consistent with project convention, but worth noting if type-checking tests becomes a goal.

  3. _make_row defaults.update(kwargs) ordering (line 41) — kwargs override defaults, which is the correct behavior. Just confirming: this means callers must pass created_at via kwargs if they want to override the default datetime.now(). The tests all pass created_at=now via kwargs.pop("created_at", ...) → but wait, created_at is popped from kwargs first and then placed into defaults. That means passing created_at=now in _make_row(created_at=now, ...) correctly controls the timestamp. ✓

Verdict

Approve. The tests are well-structured, clearly express their intent, and lock down the right invariants for the N+1 fix. No functional issues found.

@phernandez phernandez marked this pull request as ready for review April 3, 2026 22:28
@phernandez phernandez merged commit 6f207c2 into main Apr 3, 2026
9 checks passed
@phernandez phernandez deleted the codex/recent-activity-hydration-test branch April 3, 2026 22:30
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.

1 participant