Skip to content

fix(mcp): cap recent_activity rows with explicit truncation footer#785

Merged
phernandez merged 2 commits intomainfrom
fix/recent-activity-display-cap
May 3, 2026
Merged

fix(mcp): cap recent_activity rows with explicit truncation footer#785
phernandez merged 2 commits intomainfrom
fix/recent-activity-display-cap

Conversation

@groksrc
Copy link
Copy Markdown
Member

@groksrc groksrc commented May 3, 2026

Summary

Fixes #784. The project-mode formatter in recent_activity previously hardcoded a display cap of 5 entities and 5 relations, but the heading and the trailing "Activity Summary" line both reported the true total returned by the API. The result was a misleading silent truncation — e.g. a heading reading "Recent Notes & Documents (9)" with only 5 rows below it and no signal that 4 had been dropped.

This PR keeps the cap-as-readability-guardrail intent but makes it explicit:

  • Raises the cap to 10 (matches the default page_size) via a new module constant _PROJECT_OUTPUT_DISPLAY_CAP.
  • When the cap is hit, appends an explicit …and N more on this page (raise page_size to display all) line so the truncation is visible to the caller.
  • Below the cap, behavior is unchanged.

The same pattern is applied to both entities and relations in _format_project_output. Observation grouping (which has its own bespoke caps for category/example counts) is intentionally untouched in this PR — it's a separate design call.

Test plan

  • uv run pytest tests/mcp/test_tool_recent_activity.py — 17 passed.
  • Two new regression tests added:
    • test_recent_activity_format_project_output_renders_all_entities_and_relations — below-cap path: every row is rendered, no truncation footer.
    • test_recent_activity_format_project_output_caps_with_explicit_truncation — above-cap path: body truncated to _PROJECT_OUTPUT_DISPLAY_CAP, headings still report true totals, footer present with correct hidden counts.
  • uv run ruff check — clean on changed files.
  • uv run ruff format — applied.
  • uv run ty check src/basic_memory/mcp/tools/recent_activity.py — passes.

🤖 Generated with Claude Code

The project-mode formatter previously hardcoded a display cap of 5
entities and 5 relations, but the heading and the "Activity Summary"
line both reported the true count returned by the API. The result was a
misleading silent truncation: e.g. a heading of "Recent Notes &
Documents (9)" with only 5 rows below it and no signal that 4 had been
dropped.

This raises the cap to 10 (matching the default page_size) and, when
the cap is hit, appends an explicit "…and N more on this page (raise
page_size to display all)" line so the truncation is visible to the
caller. Below the cap, behavior is unchanged.

Adds two regression tests covering both the below-cap (no footer) and
above-cap (footer present, body truncated to cap) paths.

Closes #784

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Drew Cain <groksrc@gmail.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ef18845c84

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

lines.append(f" • {title}{folder}")
if len(entities) > _PROJECT_OUTPUT_DISPLAY_CAP:
hidden = len(entities) - _PROJECT_OUTPUT_DISPLAY_CAP
lines.append(f" …and {hidden} more on this page (raise page_size to display all)")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Fix misleading truncation footer guidance

The new footer text says users can “raise page_size to display all,” but truncation is controlled by _PROJECT_OUTPUT_DISPLAY_CAP, not page_size. In calls like recent_activity(page_size=50), the API can return more than 10 rows while _format_project_output still renders only 10, so increasing page_size will never reveal the hidden rows and the instruction is incorrect. This creates a user-visible dead-end in project-mode output whenever page_size exceeds the display cap.

Useful? React with 👍 / 👎.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 3, 2026

Claude finished @groksrc's task in 1m 26s —— View job


PR Review: fix(mcp): cap recent_activity rows with explicit truncation footer

  • Gather context and understand the PR
  • Read changed files
  • Review against Basic Memory team checklist
  • Post final review

Summary

The fix correctly addresses the silent truncation problem from #784: the old code showed 5 rows while the heading claimed the true total, with no indication anything was hidden. The approach — a named constant, explicit footer — is sound. Two issues need attention before merging.


Issues

🔴 P1 — Truncation footer gives incorrect advice

recent_activity.py:519 and recent_activity.py:556:

lines.append(f"  …and {hidden} more on this page (raise page_size to display all)")

Codex flagged this and it's correct. _PROJECT_OUTPUT_DISPLAY_CAP is a display-side limit independent of page_size. When a caller passes page_size=50, the API returns up to 50 results but the formatter still caps rendering at 10. Telling the user to "raise page_size" is a dead end — raising page_size to 50 already won't help.

Two options:

Option A — Drop the separate display cap entirely. Since page_size already controls how many results come back from the API, the formatter can just render everything it receives. The heading count and body will always agree, which is exactly the bug this PR is fixing.

Option B — Keep the cap but fix the footer message. If the cap is intentional (keeping LLM context compact), the message should reflect how to actually get more rows:

lines.append(f"  ...and {hidden} more on this page (call again with a smaller page_size or filter by type to see remaining items)")

Option A is simpler and removes a confusing two-layer pagination system. Option B keeps the readability guardrail but needs an accurate message. Either way, the current text is misleading and should not ship as-is.

Fix this →


🟡 P2 — Unicode character violates CLAUDE.md compatibility guideline

recent_activity.py:519, recent_activity.py:556, and both new test assertions:

lines.append(f"  …and {hidden} more on this page ...")

CLAUDE.md explicitly states: "Avoid using emojis and unicode characters in console and log output." The (U+2026 HORIZONTAL ELLIPSIS) is a multi-byte unicode character. Use plain ASCII ... instead:

lines.append(f"  ...and {hidden} more on this page ...")

The test assertions use the same character and need updating too (tests/mcp/test_tool_recent_activity.py:400, test_tool_recent_activity.py:401).

Fix this →


🔵 Minor — Unrelated reformatting in the diff

The diff includes two reformats of pre-existing multi-line calls to single lines (resolve_project_parameter at line ~197 and get_project_client at line ~312). These are unrelated to the fix. CLAUDE.md says "Minimize diffs" — keeping these as multi-line was fine and reverting reduces noise for future reviewers.


Checklist

Area Status Notes
Coding conventions Decision-point comments follow Trigger/Why/Outcome format
Python 3.12+ types No new type annotations needed
100-char line limit Within limits
Unit tests Two solid regression tests for below-cap and above-cap paths
Integration tests N/A — no new MCP tool endpoints
Test coverage Both paths fully tested
No DB migrations No schema changes
No hardcoded secrets Clean
Unicode in output U+2026 introduced, use ... instead
Footer accuracy page_size guidance is incorrect given the two-layer cap design

The underlying fix is correct and the test structure is solid. Resolve the two issues above and this is good to go.

Address review feedback on #785. Replaces the 10-row display cap (and its
truncation footer) with no cap at all — `page_size` is now the single knob
controlling how many rows come back, so the heading count and body row count
always agree. This is the #784 fix without the two-layer pagination system the
first pass introduced.

The rejected truncation footer told callers to "raise page_size to display all",
which was misleading: `_PROJECT_OUTPUT_DISPLAY_CAP` was display-only, independent
of `page_size`, so raising it didn't help. Dropping the cap removes the entire
class of confusion.

Also drops the test for the removed cap behavior; widens the renders-all test to
15 entities / 12 relations to comfortably exceed the old hardcoded `[:5]` slice.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Drew Cain <groksrc@gmail.com>
@groksrc
Copy link
Copy Markdown
Member Author

groksrc commented May 3, 2026

Pushed 6b348df addressing the review.

P1 (footer message) — went with Option A: dropped _PROJECT_OUTPUT_DISPLAY_CAP entirely. The cap was a display-only limit independent of page_size, so any footer message would either be misleading or duplicate what Activity Summary already says. With page_size as the single knob, heading count and body row count always agree — which was the actual ask in #784.

P2 (unicode ) — resolved: the truncation footer is gone, so the characters in source/tests went with it. No remaining U+2026 in the diff.

Minor (unrelated reformatting): kept the format-driven changes. They're not unrelated — main isn't currently ruff-formatted, and just check runs ruff format, which collapses resolve_project_parameter(...) and get_project_client(...) onto single lines because they fit within the 100-char limit. Any edit to this file that goes through the standard format pass produces the same delta. Adding # fmt: off to keep the multi-line form would be worse than letting ruff own the call shape.

Test changes: the cap-behavior test was removed (no cap to test). The renders-all test was widened to 15 entities / 12 relations (comfortably above the old hardcoded [:5]) and now also asserts heading counts match body counts.

uv run pytest tests/mcp/test_tool_recent_activity.py — 16 passed.
uv run ruff check / ruff format --check / ty check — clean.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 3, 2026

Claude finished @groksrc's task in 1m 45s —— View job


PR Review: fix(mcp): cap recent_activity rows with explicit truncation footer (follow-up)

  • Gather context and understand the PR
  • Read changed files (latest commit 6b348df)
  • Review against Basic Memory team checklist
  • Post final review

Summary

The follow-up commit fully addresses both P1 and P2 from the prior review. Option A (drop the cap entirely) was the right call — it eliminates the two-layer pagination system and makes page_size the single source of truth, which is exactly what #784 asked for. The implementation is clean and minimal.


Changes Reviewed

src/basic_memory/mcp/tools/recent_activity.py

  • entities[:5]entities (line 496) — all API-returned entities now render.
  • relations[:5]relations (line 529) — all API-returned relations now render.
  • _PROJECT_OUTPUT_DISPLAY_CAP constant: fully absent from the file — confirmed with grep.
  • New comment (lines 491–493) explains the regression and the rationale clearly.
  • Unicode in output: no new non-ASCII characters introduced in user-visible strings. The only new non-ASCII byte is an em dash in a code comment (), which is fine.
  • Ruff-format single-line collapses for resolve_project_parameter and get_project_client: these are format-driven and would recur on any edit — keeping them is correct.

tests/mcp/test_tool_recent_activity.py

  • test_recent_activity_format_project_output_renders_all_entities_and_relations: 15 entities + 12 relations — comfortably above the old [:5] and any plausible re-introduced cap. Asserts every title appears in output and that heading counts match body row counts. This is exactly the right regression test.
  • Cap test removed (no cap behavior to test) — test count 17 → 16, consistent with groksrc's report.

Checklist

Area Status Notes
Coding conventions Comment follows Trigger/Why/Outcome pattern
Python 3.12+ types No new annotations needed
100-char line limit Within limits
No commented-out code Clean
Unit tests Solid regression test covering both below-cap path (now: all-rows path)
Integration tests N/A — no new endpoints
100% test coverage Both entity and relation render paths covered
No DB migrations No schema changes
No hardcoded secrets Clean
Unicode in output No new unicode in user-visible strings
Footer accuracy Footer removed entirely — heading count always matches body
Observation caps Intentionally out of scope; pre-existing [:10]/[:5]/[:2] caps untouched

All issues from the prior review are resolved. This is good to merge.

@phernandez phernandez merged commit 0a72d81 into main May 3, 2026
25 checks passed
@phernandez phernandez deleted the fix/recent-activity-display-cap branch May 3, 2026 22:43
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.

recent_activity formatter hardcodes display cap of 5, ignoring page_size

2 participants