Skip to content

feat(recall): activate keyword candidates for natural-language recall - #117

Merged
Lyellr88 merged 2 commits into
MARM-mainfrom
release/v2.31.0
Jul 27, 2026
Merged

feat(recall): activate keyword candidates for natural-language recall#117
Lyellr88 merged 2 commits into
MARM-mainfrom
release/v2.31.0

Conversation

@Lyellr88

@Lyellr88 Lyellr88 commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Semantic recall now finds keyword candidates for ordinary questions. The FTS query builder space-joined every token, which SQLite FTS5 reads as an implicit AND, so a question only matched a memory containing every word. Measured on LoCoMo: 0 of 400 questions produced candidates, leaving the entire lexical layer dormant on natural-language recall.

The semantic lane now drops filler words and matches any remaining term. The exact/lexical lane keeps strict AND and is untouched, because its BM25 hits are returned without semantic reranking to clean up over-broad matches; test_exact_retrieval_lane.py passes unmodified as proof.

Benchmark (1,977 questions, 5,882 memories, top-5, keyword weight 0.0):
any-hit 53.0% -> 57.8%
all-hit 43.4% -> 47.8%
evidence recall 47.6% -> 52.1%
candidate coverage 0% -> 99.9% of queries
Largest gain on adversarial (39.7% -> 49.8%); multi-hop regressed
(39.3% -> 33.7%) because a keyword-filtered pool can drop a memory that
shares no wording with the question. FTS_CANDIDATE_LIMIT is the lever and
is now load-bearing: 99.4% of queries fill it to the default 50.

HYBRID_SEARCH_TEXT_WEIGHT defaults to 0.0 instead of 0.35. Widening makes the keyword term live on natural-language recall for the first time, and 0.35 was chosen while it never applied there. At 0.0 keyword matching narrows which memories are considered but does not reorder them, so no unvalidated ranking signal ships. An explicit env var still applies.

Also fixes: the protocol was never delivered on pip installs. marm_start, the protocol-injection middleware, and the STDIO lifecycle read PROTOCOL.md from a path outside the installed package, which is not in the wheel, so every pip install returned "PROTOCOL.md file not found". Docker and source checkouts were unaffected, hiding it. Root cause was two documentation copies with nothing enforcing which shipped; marm-mcp-server/marm-docs/ is removed and resources/marm-docs/ is the single in-package location, with the indexer and protocol readers sharing one resolver.

Recall debug logging no longer records query text at any of its four sites, only shape (term counts, mode, candidate counts).

New settings: FTS_QUERY_MODE (or_nostop|or|and), FTS_EXTRA_STOPWORDS. Both surface in marm-memory doctor under "Recall tuning".

Tests: 864 passed, 10 skipped. Verified in a clean pip install of the built wheel that both protocol files now read back non-empty.

Summary by CodeRabbit

  • New Features
    • Improved natural-language recall using broader keyword candidate matching.
    • Added keyword query tuning controls, including query mode and extra stopwords.
    • Added “Recall tuning” details to diagnostics.
  • Bug Fixes
    • Fixed protocol/document resource resolution for pip installs and ensured bundled docs loading is consistent.
  • Documentation
    • Updated configuration reference (including hybrid weight default) and clarified recall tuning/FAQ guidance.
    • Refreshed installation and version references to v2.31.0.
  • Tests
    • Expanded coverage for hybrid/FTS behavior and bundled documentation packaging.

Semantic recall now finds keyword candidates for ordinary questions. The
FTS query builder space-joined every token, which SQLite FTS5 reads as an
implicit AND, so a question only matched a memory containing every word.
Measured on LoCoMo: 0 of 400 questions produced candidates, leaving the
entire lexical layer dormant on natural-language recall.

The semantic lane now drops filler words and matches any remaining term.
The exact/lexical lane keeps strict AND and is untouched, because its BM25
hits are returned without semantic reranking to clean up over-broad
matches; test_exact_retrieval_lane.py passes unmodified as proof.

Benchmark (1,977 questions, 5,882 memories, top-5, keyword weight 0.0):
  any-hit         53.0% -> 57.8%
  all-hit         43.4% -> 47.8%
  evidence recall 47.6% -> 52.1%
  candidate coverage 0% -> 99.9% of queries
Largest gain on adversarial (39.7% -> 49.8%); multi-hop regressed
(39.3% -> 33.7%) because a keyword-filtered pool can drop a memory that
shares no wording with the question. FTS_CANDIDATE_LIMIT is the lever and
is now load-bearing: 99.4% of queries fill it to the default 50.

HYBRID_SEARCH_TEXT_WEIGHT defaults to 0.0 instead of 0.35. Widening makes
the keyword term live on natural-language recall for the first time, and
0.35 was chosen while it never applied there. At 0.0 keyword matching
narrows which memories are considered but does not reorder them, so no
unvalidated ranking signal ships. An explicit env var still applies.

Also fixes: the protocol was never delivered on pip installs. marm_start,
the protocol-injection middleware, and the STDIO lifecycle read PROTOCOL.md
from a path outside the installed package, which is not in the wheel, so
every pip install returned "PROTOCOL.md file not found". Docker and source
checkouts were unaffected, hiding it. Root cause was two documentation
copies with nothing enforcing which shipped; marm-mcp-server/marm-docs/ is
removed and resources/marm-docs/ is the single in-package location, with
the indexer and protocol readers sharing one resolver.

Recall debug logging no longer records query text at any of its four sites,
only shape (term counts, mode, candidate counts).

New settings: FTS_QUERY_MODE (or_nostop|or|and), FTS_EXTRA_STOPWORDS.
Both surface in `marm-memory doctor` under "Recall tuning".

Tests: 864 passed, 10 skipped. Verified in a clean pip install of the
built wheel that both protocol files now read back non-empty.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 380856aa-b042-4a3d-be95-f4b5732f1834

📥 Commits

Reviewing files that changed from the base of the PR and between cc1d4d3 and cff114d.

📒 Files selected for processing (2)
  • marm-mcp-server/marm_mcp_server/core/memory_utils.py
  • marm-mcp-server/tests/test_hybrid_search.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • marm-mcp-server/marm_mcp_server/core/memory_utils.py
  • marm-mcp-server/tests/test_hybrid_search.py

📝 Walkthrough

Walkthrough

This release bumps MARM to v2.31.0, consolidates documentation under packaged resources, adds configurable wide FTS recall behavior, exposes retrieval settings through doctor diagnostics, and updates related tests, documentation, links, and release metadata.

Changes

Release metadata and public documentation

Layer / File(s) Summary
Release metadata and public documentation
CHANGELOG.md, README.md, docs/*, marm-mcp-server/*, .github/ISSUE_TEMPLATE/*
Version references are updated to v2.31.0, FAQ links point to docs/FAQ.md, and FTS tuning settings are documented. Temporary Locomo benchmark backups are ignored.

Packaged documentation consolidation

Layer / File(s) Summary
Packaged documentation consolidation
marm-mcp-server/marm_mcp_server/utils/*, services/documentation.py, resources/marm-docs/*, tests/test_bundled_docs.py, scripts/*, skills/*, AGENTS.md
Documentation and protocol readers resolve the packaged resources/marm-docs directory; legacy documentation paths are removed or updated, with packaging and synchronization tests revised.

Configurable wide FTS recall

Layer / File(s) Summary
Configurable wide FTS recall
marm-mcp-server/marm_mcp_server/config/settings.py, core/*, tests/test_hybrid_search.py
Adds validated FTS query modes and extra stopwords, changes semantic candidate construction to support OR-based queries, sets the hybrid text-weight default to 0.0, and expands recall and session-scoping tests.

Recall diagnostics and doctor output

Layer / File(s) Summary
Recall diagnostics and doctor output
marm-mcp-server/marm_mcp_server/services/runtime_status.py, services/cli_output.py
Doctor status now returns retrieval tuning values, and CLI output renders them under a “Recall tuning” section.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Copy link
Copy Markdown

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: cc1d4d3819

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return None

if FTS_QUERY_MODE == "or_nostop":
kept = [t for t in tokens if t.lower() not in _FTS_STOPWORDS]

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 Preserve ambiguous proper nouns when removing stopwords

Avoid lowercasing every token before stopword removal, because several listed stopwords are also common proper nouns or acronyms (May, Will, US, IT). For example, What happened in May? becomes an FTS query for only "happened"; if any unrelated memory contains that generic word, the nonempty candidate pool prevents the semantic fallback and excludes a relevant memory such as The launch is scheduled for May. Preserve case-significant tokens or remove ambiguous terms from the built-in stopword set so the new filter does not regress these queries.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@marm-mcp-server/tests/test_bundled_docs.py`:
- Around line 23-33: Restore byte-for-byte source-to-package assertions in
test_docs_live_inside_the_package for FAQ.md, PROTOCOL.md, and PROTOCOL-LITE.md,
while retaining the existing package-location and expected-file checks. Resync
the FAQ content at docs/FAQ.md:153 into
marm-mcp-server/marm_mcp_server/resources/marm-docs/FAQ.md; no other direct
change is required at the test site beyond restoring those comparisons.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 811b2706-f9fe-4258-91e2-07f39a2e38d7

📥 Commits

Reviewing files that changed from the base of the PR and between 498e16b and cc1d4d3.

📒 Files selected for processing (40)
  • .github/ISSUE_TEMPLATE/bug_report.yml
  • .github/ISSUE_TEMPLATE/config.yml
  • .gitignore
  • AGENTS.md
  • CHANGELOG.md
  • CONTRIBUTING.md
  • README.md
  • docs/FAQ.md
  • docs/INSTALL-DOCKER.md
  • docs/INSTALL-LINUX.md
  • docs/INSTALL-PLATFORMS.md
  • docs/INSTALL-WINDOWS.md
  • docs/TECHNICAL-OVERVIEW.md
  • marm-mcp-server/Dockerfile
  • marm-mcp-server/README.md
  • marm-mcp-server/docker-compose.yml
  • marm-mcp-server/marm-docs/FAQ.md
  • marm-mcp-server/marm-docs/PROTOCOL-LITE.md
  • marm-mcp-server/marm-docs/PROTOCOL.md
  • marm-mcp-server/marm-docs/README.md
  • marm-mcp-server/marm_mcp_server/__init__.py
  • marm-mcp-server/marm_mcp_server/config/settings.py
  • marm-mcp-server/marm_mcp_server/core/memory.py
  • marm-mcp-server/marm_mcp_server/core/memory_recall.py
  • marm-mcp-server/marm_mcp_server/core/memory_utils.py
  • marm-mcp-server/marm_mcp_server/resources/marm-docs/FAQ.md
  • marm-mcp-server/marm_mcp_server/resources/marm-docs/README.md
  • marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md
  • marm-mcp-server/marm_mcp_server/server.py
  • marm-mcp-server/marm_mcp_server/services/cli_output.py
  • marm-mcp-server/marm_mcp_server/services/documentation.py
  • marm-mcp-server/marm_mcp_server/services/runtime_status.py
  • marm-mcp-server/marm_mcp_server/utils/helpers.py
  • marm-mcp-server/pyproject.toml
  • marm-mcp-server/server.json
  • marm-mcp-server/tests/test_bundled_docs.py
  • marm-mcp-server/tests/test_hybrid_search.py
  • scripts/find-tools.py
  • scripts/find-versions.py
  • skills/marm-init/SKILL.md
💤 Files with no reviewable changes (4)
  • marm-mcp-server/marm-docs/PROTOCOL.md
  • marm-mcp-server/marm-docs/FAQ.md
  • marm-mcp-server/marm-docs/PROTOCOL-LITE.md
  • marm-mcp-server/marm-docs/README.md
📜 Review details
🧰 Additional context used
📓 Path-based instructions (12)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

Keep changes surgical: modify only what the task requires, match existing style, and preserve behavior during refactors.

Files:

  • marm-mcp-server/docker-compose.yml
  • marm-mcp-server/marm_mcp_server/server.py
  • docs/TECHNICAL-OVERVIEW.md
  • docs/INSTALL-PLATFORMS.md
  • docs/INSTALL-WINDOWS.md
  • marm-mcp-server/pyproject.toml
  • CONTRIBUTING.md
  • docs/FAQ.md
  • docs/INSTALL-DOCKER.md
  • marm-mcp-server/marm_mcp_server/resources/marm-docs/FAQ.md
  • skills/marm-init/SKILL.md
  • marm-mcp-server/marm_mcp_server/core/memory.py
  • marm-mcp-server/marm_mcp_server/__init__.py
  • marm-mcp-server/marm_mcp_server/services/cli_output.py
  • marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md
  • marm-mcp-server/Dockerfile
  • docs/INSTALL-LINUX.md
  • marm-mcp-server/marm_mcp_server/utils/helpers.py
  • marm-mcp-server/marm_mcp_server/core/memory_utils.py
  • marm-mcp-server/server.json
  • CHANGELOG.md
  • marm-mcp-server/marm_mcp_server/core/memory_recall.py
  • marm-mcp-server/marm_mcp_server/services/runtime_status.py
  • marm-mcp-server/README.md
  • scripts/find-tools.py
  • marm-mcp-server/marm_mcp_server/resources/marm-docs/README.md
  • marm-mcp-server/marm_mcp_server/services/documentation.py
  • marm-mcp-server/tests/test_hybrid_search.py
  • AGENTS.md
  • README.md
  • marm-mcp-server/tests/test_bundled_docs.py
  • scripts/find-versions.py
  • marm-mcp-server/marm_mcp_server/config/settings.py
marm-mcp-server/{pyproject.toml,server.json,Dockerfile,docker-compose.yml,marm_mcp_server/__init__.py,marm_mcp_server/config/settings.py,marm_mcp_server/server.py,README.md,marm_mcp_server/resources/marm-docs/README.md}

📄 CodeRabbit inference engine (AGENTS.md)

When bumping the version, update every listed version source, identifier, label, docstring, README heading, and installation-document header; audit with python scripts/find-versions.py. Use SemVer: MAJOR for breaking changes, MINOR for new tools, parameters, or features, and PATCH for fixes or documentation updates.

Files:

  • marm-mcp-server/docker-compose.yml
  • marm-mcp-server/marm_mcp_server/server.py
  • marm-mcp-server/pyproject.toml
  • marm-mcp-server/marm_mcp_server/__init__.py
  • marm-mcp-server/Dockerfile
  • marm-mcp-server/server.json
  • marm-mcp-server/README.md
  • marm-mcp-server/marm_mcp_server/resources/marm-docs/README.md
  • marm-mcp-server/marm_mcp_server/config/settings.py
marm-mcp-server/marm_mcp_server/server.py

📄 CodeRabbit inference engine (AGENTS.md)

HTTP MCP tools must be registered in MCP_TOOL_OPERATIONS; tools not in this whitelist do not exist over HTTP.

Files:

  • marm-mcp-server/marm_mcp_server/server.py
marm-mcp-server/marm_mcp_server/{server.py,server_stdio.py,services/stdio_graph_tools.py}

📄 CodeRabbit inference engine (AGENTS.md)

HTTP and STDIO transports must remain in exact behavioral parity; never fork tool behavior between transports.

Files:

  • marm-mcp-server/marm_mcp_server/server.py
marm-mcp-server/marm_mcp_server/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

marm-mcp-server/marm_mcp_server/**/*.py: All memory writes must use the serialized asynchronous write queue; do not add bypass write paths.
marm_log_entry must dual-write a log_entries row and semantic memory, while semantic-store failure must never fail the log write.
Graph and concept failures must never break the seven core memory tools.
marm_smart_recall must keep primary memory ranking authoritative; graph enrichment is bounded, read-only, fail-open, and trimmed before primary results when enforcing response limits.
Use one lazily loaded, lock-serialized fastembed encoder with 512 dimensions; writes must succeed when the encoder is unavailable.
Never share database connections between the memory SQLite database and the isolated concept-graph database.
Prefer the smallest solution; avoid speculative abstractions and unnecessary configuration flags, and extract modules only at real boundaries.
Use minimal comments only for non-obvious rationale; never add comments that narrate the next line.

Files:

  • marm-mcp-server/marm_mcp_server/server.py
  • marm-mcp-server/marm_mcp_server/core/memory.py
  • marm-mcp-server/marm_mcp_server/__init__.py
  • marm-mcp-server/marm_mcp_server/services/cli_output.py
  • marm-mcp-server/marm_mcp_server/utils/helpers.py
  • marm-mcp-server/marm_mcp_server/core/memory_utils.py
  • marm-mcp-server/marm_mcp_server/core/memory_recall.py
  • marm-mcp-server/marm_mcp_server/services/runtime_status.py
  • marm-mcp-server/marm_mcp_server/services/documentation.py
  • marm-mcp-server/marm_mcp_server/config/settings.py
marm-mcp-server/{marm_mcp_server/endpoints/**/*.py,marm_mcp_server/server.py,marm_mcp_server/server_stdio.py,server.json,scripts/find-tools.py}

📄 CodeRabbit inference engine (AGENTS.md)

When adding or removing an MCP tool, update the endpoint implementation, HTTP route and whitelist, STDIO registration or wrapper, server.json, and CANONICAL_TOOLS. Also update complete tool-list documentation and tests for both transports, then run python scripts/find-tools.py and require every surface to report OK.

Files:

  • marm-mcp-server/marm_mcp_server/server.py
  • marm-mcp-server/server.json
**/*.py

⚙️ CodeRabbit configuration file

**/*.py: Prioritize runtime correctness, async/concurrency safety, SQLite transaction safety, auth/rate-limit behavior, release-breaking packaging issues, and MCP protocol compatibility.

Files:

  • marm-mcp-server/marm_mcp_server/server.py
  • marm-mcp-server/marm_mcp_server/core/memory.py
  • marm-mcp-server/marm_mcp_server/__init__.py
  • marm-mcp-server/marm_mcp_server/services/cli_output.py
  • marm-mcp-server/marm_mcp_server/utils/helpers.py
  • marm-mcp-server/marm_mcp_server/core/memory_utils.py
  • marm-mcp-server/marm_mcp_server/core/memory_recall.py
  • marm-mcp-server/marm_mcp_server/services/runtime_status.py
  • scripts/find-tools.py
  • marm-mcp-server/marm_mcp_server/services/documentation.py
  • marm-mcp-server/tests/test_hybrid_search.py
  • marm-mcp-server/tests/test_bundled_docs.py
  • scripts/find-versions.py
  • marm-mcp-server/marm_mcp_server/config/settings.py
**/*.md

⚙️ CodeRabbit configuration file

**/*.md: Only flag documentation issues that are materially wrong, misleading for installation/release behavior, or inconsistent with live MCP behavior. Skip style, phrasing, formatting, and wording preferences.

Files:

  • docs/TECHNICAL-OVERVIEW.md
  • docs/INSTALL-PLATFORMS.md
  • docs/INSTALL-WINDOWS.md
  • CONTRIBUTING.md
  • docs/FAQ.md
  • docs/INSTALL-DOCKER.md
  • marm-mcp-server/marm_mcp_server/resources/marm-docs/FAQ.md
  • skills/marm-init/SKILL.md
  • marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md
  • docs/INSTALL-LINUX.md
  • CHANGELOG.md
  • marm-mcp-server/README.md
  • marm-mcp-server/marm_mcp_server/resources/marm-docs/README.md
  • AGENTS.md
  • README.md
marm-mcp-server/marm_mcp_server/resources/marm-docs/{FAQ,PROTOCOL,PROTOCOL-LITE}.md

📄 CodeRabbit inference engine (AGENTS.md)

Packaged FAQ.md, PROTOCOL.md, and PROTOCOL-LITE.md must remain exact copies of their corresponding files under docs/; resync with the prescribed cp command after edits.

Files:

  • marm-mcp-server/marm_mcp_server/resources/marm-docs/FAQ.md
marm-mcp-server/marm_mcp_server/resources/marm-docs/**

📄 CodeRabbit inference engine (AGENTS.md)

Only documentation under resources/marm-docs/ is packaged in the wheel and served or indexed; do not rely on copies outside that package directory.

Files:

  • marm-mcp-server/marm_mcp_server/resources/marm-docs/FAQ.md
  • marm-mcp-server/marm_mcp_server/resources/marm-docs/README.md
marm-mcp-server/tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

marm-mcp-server/tests/**/*.py: Run tests with pytest from marm-mcp-server/; use real FastAPI endpoints and SQLite, mocking only when it meaningfully speeds tests while retaining at least 95% behavioral fidelity.
Every new MARM Console API route requires at least one happy-path FastAPI response-contract test with the MCP adapter stubbed.
Do not write existence-check or coded-to-pass tests; prefer deep tests exercising real paths, and use pytest.mark.skip only for genuinely unavailable dependencies.

Files:

  • marm-mcp-server/tests/test_hybrid_search.py
  • marm-mcp-server/tests/test_bundled_docs.py
**/tests/**

⚙️ CodeRabbit configuration file

**/tests/**: Focus on tests that are flaky, non-isolated, incorrectly asserting behavior, or missing coverage for a changed high-risk path. Skip minor naming, comments, and layout preferences.

Files:

  • marm-mcp-server/tests/test_hybrid_search.py
  • marm-mcp-server/tests/test_bundled_docs.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Lyellr88/marm-memory

Timestamp: 2026-07-27T09:19:09.498Z
Learning: Never commit changes without an explicit user request.
🪛 SkillSpector (2.3.11)
skills/marm-init/SKILL.md

[info] 58: [RP1] null: pip install without ==version installs the latest release, which could include malicious changes.

Remediation: Pin the version: pip install package==1.2.3

(MCP Rug Pull (RP1))


[warning] 60: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Remediation: Pin the image: image:tag or image@sha256:abc123

(MCP Rug Pull (RP1))


[warning] 189: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Remediation: Pin the image: image:tag or image@sha256:abc123

(MCP Rug Pull (RP1))


[warning] 7: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.

(Agent Snooping (AS3))

marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md

[info] 58: [RP1] null: pip install without ==version installs the latest release, which could include malicious changes.

Remediation: Pin the version: pip install package==1.2.3

(MCP Rug Pull (RP1))


[warning] 60: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Remediation: Pin the image: image:tag or image@sha256:abc123

(MCP Rug Pull (RP1))


[warning] 189: [RP1] null: Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Remediation: Pin the image: image:tag or image@sha256:abc123

(MCP Rug Pull (RP1))


[warning] 7: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.

(Agent Snooping (AS3))

🔇 Additional comments (36)
marm-mcp-server/marm_mcp_server/config/settings.py (1)

41-62: LGTM!

Also applies to: 147-147, 253-261, 291-302

marm-mcp-server/marm_mcp_server/core/memory_utils.py (1)

14-15: LGTM!

Also applies to: 95-152

marm-mcp-server/marm_mcp_server/core/memory.py (1)

51-51: LGTM!

marm-mcp-server/marm_mcp_server/core/memory_recall.py (1)

12-20: LGTM!

Also applies to: 56-56, 176-176, 210-210, 223-231, 352-352

marm-mcp-server/tests/test_hybrid_search.py (1)

1-1: LGTM!

Also applies to: 54-159, 747-752, 815-892

marm-mcp-server/marm_mcp_server/services/runtime_status.py (1)

21-24: LGTM!

Also applies to: 226-234

marm-mcp-server/marm_mcp_server/services/cli_output.py (2)

102-104: 🎯 Functional Correctness | ⚡ Quick win

"Ignored words added" is misleading outside or_nostop mode.

FTS_EXTRA_STOPWORDS only affects filtering when fts_query_mode is or_nostop (see _wide_fts_query in memory_utils.py); in and/or modes these words are never dropped. The doctor output prints the "Ignored words added" line whenever the set is non-empty, irrespective of mode, misrepresenting actual behavior during debugging — the exact scenario this diagnostics section exists to prevent.

🩹 Proposed fix
         extra = retrieval.get("fts_extra_stopwords") or []
-        if extra:
+        if extra and retrieval.get("fts_query_mode") == "or_nostop":
             print(f"  Ignored words added: {', '.join(extra)}")
+        elif extra:
+            print(f"  Extra stopwords configured (no effect in {retrieval.get('fts_query_mode')!r} mode): {', '.join(extra)}")

91-101: LGTM!

marm-mcp-server/marm_mcp_server/resources/marm-docs/FAQ.md (1)

153-153: LGTM!

docs/INSTALL-WINDOWS.md (1)

5-5: LGTM!

Also applies to: 297-297

.github/ISSUE_TEMPLATE/config.yml (1)

10-10: LGTM!

CONTRIBUTING.md (1)

323-323: LGTM!

.gitignore (1)

135-135: LGTM!

AGENTS.md (1)

28-28: LGTM!

Also applies to: 37-42, 52-52

marm-mcp-server/marm_mcp_server/resources/marm-docs/README.md (1)

1-1: LGTM!

Also applies to: 950-952, 1091-1091

marm-mcp-server/marm_mcp_server/utils/helpers.py (1)

5-17: LGTM!

Also applies to: 19-22, 35-35

marm-mcp-server/marm_mcp_server/services/documentation.py (1)

12-12: LGTM!

Also applies to: 48-56, 78-81

marm-mcp-server/marm_mcp_server/resources/skills/marm-init/SKILL.md (1)

77-77: LGTM!

CHANGELOG.md (1)

5-29: LGTM!

README.md (1)

8-8: LGTM!

Also applies to: 984-986, 1125-1125, 1171-1171

docs/INSTALL-DOCKER.md (1)

5-5: LGTM!

docs/INSTALL-LINUX.md (1)

5-5: LGTM!

Also applies to: 323-323

docs/INSTALL-PLATFORMS.md (1)

1-1: LGTM!

skills/marm-init/SKILL.md (1)

77-77: 🩺 Stability & Availability

Verify this fallback works outside the repository root.

The new value is a repository-relative path, not a package-resource lookup. If the skill runs from an installed/distributed location or a different working directory, offline protocol loading will still fail. Confirm the skill is always executed from the repository root or switch this fallback to package-aware resolution.

Source: Coding guidelines

scripts/find-tools.py (1)

46-55: LGTM!

scripts/find-versions.py (1)

51-51: LGTM!

Also applies to: 113-117

marm-mcp-server/tests/test_bundled_docs.py (1)

23-55: 🩺 Stability & Availability

Verify this regression runs against a built wheel.

These tests validate whichever marm_mcp_server the test process imports; a source checkout can pass even if package-data configuration omits the markdown files. Ensure CI installs a clean wheel before running this test, as required for the pip-install regression.

docs/TECHNICAL-OVERVIEW.md (1)

3-3: LGTM!

marm-mcp-server/Dockerfile (1)

76-76: LGTM!

marm-mcp-server/README.md (1)

10-10: LGTM!

Also applies to: 984-986, 1125-1125, 1171-1171

marm-mcp-server/docker-compose.yml (1)

8-8: LGTM!

Also applies to: 21-21

marm-mcp-server/marm_mcp_server/__init__.py (1)

17-20: LGTM!

marm-mcp-server/pyproject.toml (1)

7-7: LGTM!

marm-mcp-server/server.json (1)

6-6: LGTM!

Also applies to: 20-25

marm-mcp-server/marm_mcp_server/server.py (1)

8-8: LGTM!

.github/ISSUE_TEMPLATE/bug_report.yml (1)

9-9: LGTM!

Comment on lines +23 to +33
def test_docs_live_inside_the_package():
"""The resolved docs dir must be under the installed package, not beside it.

Anything outside `marm_mcp_server/` is not packaged and breaks on pip.
"""
package_root = Path(helpers.__file__).resolve().parent.parent
resolved = helpers.docs_dir()

SOURCE_DOCS = Path(__file__).resolve().parents[1] / "marm-docs"
PACKAGED_DOCS = (
Path(documentation.__file__).resolve().parent.parent / "resources" / "marm-docs"
)
assert resolved is not None, "packaged marm-docs directory is missing"
assert package_root in resolved.parents
assert {p.name for p in resolved.glob("*.md")} == EXPECTED_DOCS

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve the source/package documentation contract.

The test no longer detects stale packaged documentation, while this FAQ source edit must be mirrored into the packaged copy used at runtime.

  • marm-mcp-server/tests/test_bundled_docs.py#L23-L33: restore byte-for-byte checks for FAQ.md, PROTOCOL.md, and PROTOCOL-LITE.md.
  • docs/FAQ.md#L153-L153: resync marm-mcp-server/marm_mcp_server/resources/marm-docs/FAQ.md.
📍 Affects 2 files
  • marm-mcp-server/tests/test_bundled_docs.py#L23-L33 (this comment)
  • docs/FAQ.md#L153-L153
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@marm-mcp-server/tests/test_bundled_docs.py` around lines 23 - 33, Restore
byte-for-byte source-to-package assertions in test_docs_live_inside_the_package
for FAQ.md, PROTOCOL.md, and PROTOCOL-LITE.md, while retaining the existing
package-location and expected-file checks. Resync the FAQ content at
docs/FAQ.md:153 into marm-mcp-server/marm_mcp_server/resources/marm-docs/FAQ.md;
no other direct change is required at the test site beyond restoring those
comparisons.

Source: Coding guidelines

The stopword list dropped words that also carry a content sense, and the
FTS5 tokenizer is case-insensitive ("porter ascii"), so a listed word loses
that meaning for every query -- there is no case-preserving check that would
help. "What happened in May?" searched only for "happened", and because any
non-empty candidate pool suppresses the full semantic scan, a memory reading
"The launch is scheduled for May" became unreachable rather than lower-ranked.

Removes modals (may/will/can/could/would/should/might/must), content verbs
(get/got/give/want/need/know/think/tell/say/said), the acronym collision
"us", and contraction fragments (won/don/didn/doesn/isn/aren/wasn/weren).
"won" was the worst of these: included as the "won't" remnant, it discarded
the victory sense outright.

Omitting them costs little because BM25 already discounts frequent terms by
inverse document frequency, so a mid-frequency word ranks low on its own
instead of swamping the candidate pool. "it"/"its" stay listed despite the
"IT" collision: the pronoun is common enough that keeping it as a search
term would flood the 50-slot pool, which costs more than the acronym sense.

LoCoMo re-run on the same corpus, changing only this list:
  any-hit         57.8% -> 57.9%
  all-hit         47.8% -> 48.1%
  evidence recall 52.1% -> 52.4%
  candidate coverage unchanged at 99.9%
Deltas are within single-run noise; the corpus has few proper-noun queries,
so it confirms no cost rather than demonstrating the correctness gain.

Reported by Codex on PR #117.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Lyellr88
Lyellr88 merged commit 2b6cfd0 into MARM-main Jul 27, 2026
7 checks passed
@Lyellr88
Lyellr88 deleted the release/v2.31.0 branch July 28, 2026 07:46
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