Skip to content

Ensure read-after-write consistency and cache invalidation in MCP#59

Merged
Looted merged 5 commits intomasterfrom
develop
Mar 12, 2026
Merged

Ensure read-after-write consistency and cache invalidation in MCP#59
Looted merged 5 commits intomasterfrom
develop

Conversation

@Looted
Copy link
Copy Markdown
Owner

@Looted Looted commented Mar 12, 2026

No description provided.

Looted added 2 commits March 12, 2026 08:12
Ensure cache invalidation after mutations to avoid stale reads in interactive MCP sessions.

Includes:
- Cache invalidation in packages/cli/src/prolog.ts to ensure read-after-write consistency
- Regression and unit tests that cover the bug in packages/mcp/tests/tools/crud.test.ts and documentation/tests/e2e/packed/mcp-protocol-regression.test.ts
- ADR-015 documenting the design decision and tradeoffs (documentation/adr/ADR-015.md)
- Changesets-driven version and changelog updates for packages/cli and packages/mcp (packages/*/CHANGELOG.md, packages/*/package.json)

Refs: #58
Copilot AI review requested due to automatic review settings March 12, 2026 08:10
Copy link
Copy Markdown

Copilot AI left a comment

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 read-after-write consistency issues in long-lived MCP sessions by ensuring cached Prolog query results are invalidated after successful mutations, and adds regression coverage to prevent stale reads from returning after upserts/deletes.

Changes:

  • Invalidate PrologProcess query cache after successful non-cacheable (mutation) goals in interactive mode.
  • Add CRUD and packed E2E regression tests that exercise create/read/update/read and delete/read consistency in a single MCP process.
  • Bump kibi-cli / kibi-mcp versions and update CI/publish workflows.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/mcp/tests/tools/crud.test.ts Adds CRUD regression coverage for immediate read-after-upsert and delete/query consistency.
packages/mcp/package.json Bumps MCP version and updates kibi-cli dependency.
packages/mcp/CHANGELOG.md Documents the cache invalidation fix and dependency update.
packages/cli/src/prolog.ts Implements interactive-mode cache invalidation after successful non-cacheable goals.
packages/cli/package.json Bumps CLI version.
packages/cli/CHANGELOG.md Documents the cache invalidation fix and new regression coverage.
documentation/tests/e2e/packed/mcp-protocol-regression.test.ts Adds packed E2E regression test for cache invalidation across upsert/delete.
documentation/symbols.yaml Updates generated symbol coordinates metadata.
documentation/adr/ADR-015.md Adds ADR documenting the cache invalidation decision and verification strategy.
.github/workflows/publish.yml Updates action versions used during publish workflow.
.github/workflows/ci.yml Adds a workflow_dispatch option to skip tests and updates action versions.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread packages/cli/src/prolog.ts Outdated
Comment on lines 292 to 295
if (!cacheable) {
this.invalidateCache();
}
if (cacheable) {
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

Cache invalidation is currently gated solely on the cacheable flag computed from the original goalKey. In interactive mode, query(string[]) is rewritten into a parenthesized batch goal (e.g. (kb_assert_entity(...), kb_save)), which isCacheableGoal() will treat as cacheable (since it no longer starts with kb_assert_/kb_save), so successful batched mutations can avoid both invalidateCache() and proper non-caching. Consider marking any batch goal as non-cacheable (or computing cacheability per sub-goal and treating the batch as non-cacheable if any sub-goal is non-cacheable) to preserve read-after-write consistency for batched writes in Node interactive sessions.

Suggested change
if (!cacheable) {
this.invalidateCache();
}
if (cacheable) {
// Treat any batch goal as non-cacheable to preserve read-after-write consistency.
const isBatchGoal =
Array.isArray(goalKey) ||
/^\s*\([^)]*,/.test(normalizedGoal);
const shouldCache = cacheable && !isBatchGoal;
if (!shouldCache) {
this.invalidateCache();
}
if (shouldCache) {

Copilot uses AI. Check for mistakes.
Comment on lines +237 to +244
it("should invalidate query cache after kb_upsert and kb_delete mutations", async () => {
const proc = spawn("node", [sandbox.kibiMcpBin], {
cwd: sandbox.repoDir,
env: sandbox.env,
stdio: ["pipe", "pipe", "pipe"],
});
await new Promise((r) => setTimeout(r, 500));

Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

If any assertion in this test fails, the spawned MCP server process may never be stopped (since stopProcess(proc) is only reached at the end). That can leak child processes and make the test suite hang/flaky. Wrap the test body in try/finally and always call await stopProcess(proc) in the finally block (optionally also draining stdout/stderr).

Copilot uses AI. Check for mistakes.
@Looted
Copy link
Copy Markdown
Owner Author

Looted commented Mar 12, 2026

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 12, 2026

@Looted I've opened a new pull request, #60, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits March 12, 2026 08:22
…leanup

Co-authored-by: Looted <6255880+Looted@users.noreply.github.com>
Fix batch goal cache mis-classification and test process leak in MCP interactive sessions
@Looted Looted merged commit f653e61 into master Mar 12, 2026
5 checks passed
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