Skip to content

test: verify MCP and CLI compatibility and integrations - #34

Merged
krishna916 merged 16 commits into
mainfrom
feature/issue-25-mcp-cli-compatibility
Jul 30, 2026
Merged

test: verify MCP and CLI compatibility and integrations#34
krishna916 merged 16 commits into
mainfrom
feature/issue-25-mcp-cli-compatibility

Conversation

@krishna916

@krishna916 krishna916 commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Closes #25

Summary

  • Added disposable, isolated agent verification runtimes with arbitrary CWDs and explicit RELAY_DB_PATH.
  • Added built-process MCP and CLI clients with strict JSON/protocol capture, stderr separation, timeout handling, and transport-only normalization.
  • Added MCP/CLI parity coverage for captures, reads, duplicates, warnings, lifecycle mutations, no-ops, errors, malformed sessions, restart persistence, and shared HTTP/MCP/CLI database paths.
  • Hardened canonical skill and vendor-wrapper validation against policy drift, unsafe removal guidance, machine paths, and non-canonical MCP entry points.
  • Added agent integration verification evidence, including manual Codex/Claude checklists and limitations.
  • Added a local PR #34 remediation tracker.

Automated 16-scenario matrix

  1. MCP capture -> CLI retrieval — PASS
  2. CLI capture -> MCP retrieval — PASS
  3. List/get DTO fields and ordering — PASS
  4. Session-ID isolation — PASS
  5. Completed and archived session review — PASS
  6. Missing session behavior — PASS
  7. Malformed session behavior — PASS
  8. Duplicate candidates, warnings, and match reasons — PASS
  9. Edit parity — PASS
  10. Triage/start/complete/archive parity — PASS
  11. No-op metadata and timestamps — PASS
  12. Validation, transition, archived, not-found, and locked-database storage-error parity — PASS
  13. CLI JSON schema and exit codes — PASS
  14. One database across HTTP, MCP, and CLI — PASS
  15. Skill and vendor-wrapper drift — PASS
  16. Configuration-driven integration removal preserves data — PASS

Validation

  • corepack pnpm install --frozen-lockfile completed with pnpm 10.2.0.
  • corepack pnpm verify passed from a clean generated-output state beginning with dist/ deleted.
  • Full coverage: 39 test files, 512 tests passed.
  • Coverage: 88.74% statements, 81.34% branches, 88.94% functions, 90.90% lines.
  • Direct ESLint, TypeScript, Prettier, Node/web builds, repository asset validation, and the high-severity audit gate passed.
  • The locked-database parity test initialized MCP first, held BEGIN IMMEDIATE on the shared disposable database, ran built CLI/MCP writes concurrently, and verified equal normalized STORAGE_ERROR contracts, CLI exit code 5, and sanitized external output.
  • Focused issue Add MCP and CLI compatibility, contract, and end-to-end verification #25 suites passed: MCP/CLI parity 25, agent workflow 3, and database-path parity 2.
  • Automation uses fresh disposable databases and does not invoke external LLMs or touch real client configuration/default data.

Client validation status

  • Codex live smoke test: unverified; the installed executable returned Windows Access is denied for codex --version.
  • Claude Code live smoke test: unverified; claude and claude-code were unavailable.
  • Manual client checklist and explicit human-review gates are documented. No client configuration was changed.

Draft PR only; do not merge.

Summary by CodeRabbit

  • Documentation

    • Added end-to-end verification evidence covering MCP and CLI workflows, compatibility, limitations, and data preservation.
    • Clarified integration removal guidance so client configuration can be removed without affecting stored SQLite data.
    • Updated behavioral guidance for capture and session review workflows.
  • Bug Fixes

    • Improved validation of integration assets, canonical skills, configuration paths, and removal instructions.
    • Ensured test and coverage commands build the application before running.
  • Tests

    • Added comprehensive MCP/CLI parity coverage for persistence, sessions, errors, storage failures, and shared database paths.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@krishna916, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 29 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 934f4bc4-244c-4ef7-9ae9-b3f37b5b91b6

📥 Commits

Reviewing files that changed from the base of the PR and between c4aa0c0 and c80145c.

📒 Files selected for processing (8)
  • scripts/validate-agent-integration-assets.ts
  • tests/integration/agent-workflow-e2e.test.ts
  • tests/integration/mcp-cli-parity.test.ts
  • tests/support/cli-test-process.ts
  • tests/support/external-contract-normalizers.ts
  • tests/unit/scripts/validate-agent-integration-assets.test.ts
  • tests/unit/support/external-contract-normalizers.test.ts
  • tests/unit/support/mcp-test-client.test.ts
📝 Walkthrough

Walkthrough

Adds isolated MCP/CLI test infrastructure, broad adapter parity and persistence coverage, stricter canonical skill and integration-asset validation, verification records, and build-before-test scripts.

Changes

Agent integration verification

Layer / File(s) Summary
Test harness and external contracts
tests/fixtures/contracts/agent-workflow.ts, tests/support/*, tests/unit/support/*
Adds disposable runtime, CLI and MCP process helpers, normalized external contracts, workflow fixtures, and lifecycle/output tests.
Adapter parity and persistence flows
tests/integration/agent-workflow-e2e.test.ts, tests/integration/database-path-parity.test.ts, tests/integration/mcp-cli-parity.test.ts
Tests cross-adapter capture, retrieval, mutations, session isolation, persistence, shared database paths, error parity, exit codes, and output non-leakage.
Canonical skills and integration-asset validation
scripts/validate-agent-integration-assets.ts, tests/unit/scripts/*, skills/*, integrations/*, tests/fixtures/agent-integrations/valid/integrations/*
Validates canonical skill content, MCP entrypoints, vendor policy wording, and removal guidance that preserves SQLite data.
Verification evidence and test execution wiring
docs/agent-integration-verification.md, docs/superpowers/plans/..., docs/superpowers/tasks/..., package.json
Records verification scenarios and outcomes, updates the evidence template and review tracker, and builds Node artifacts before tests and coverage runs.

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

Possibly related issues

  • krishna916/relay issue 2 — Covers the broader Epic 2 MCP/CLI integration, shared-contract, skill, session, and parity objectives implemented and verified here.

Possibly related PRs

  • krishna916/relay#31: Introduces the source-checkout CLI adapter contract exercised by the new MCP/CLI parity tests.
  • krishna916/relay#32: Adds the canonical skills and integration asset structure enforced by the new validators.
  • krishna916/relay#33: Adds the agent-integration asset validator and documentation assets extended by this change.

Sequence Diagram(s)

sequenceDiagram
  participant MCPClient
  participant RelayCLI
  participant HTTPAdapter
  participant SQLiteDatabase
  MCPClient->>SQLiteDatabase: Capture task
  RelayCLI->>SQLiteDatabase: Edit and retrieve task
  HTTPAdapter->>SQLiteDatabase: Verify shared persisted state
  MCPClient->>SQLiteDatabase: Retrieve task after restart
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Most scope items are covered, but the PR still states Codex and Claude Code live validation is unverified, so the linked verification goal is not fully satisfied. Complete and record the manual Codex and Claude Code clean-checkout validations, or keep the PR incomplete until those checks are done.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the PR’s main focus on MCP/CLI compatibility and integration verification.
Out of Scope Changes check ✅ Passed The changes align with the issue scope and supporting remediation tasks; no clearly unrelated feature work stands out.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/issue-25-mcp-cli-compatibility

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.

@krishna916 krishna916 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Review verdict: Changes requested

Critical — pnpm verify cannot pass from a clean checkout

The new built-process tests execute dist/mcp/main.js and dist/cli/main.js, but the authoritative verify script still runs pnpm test:coverage before pnpm build. Since dist/ is gitignored, a clean checkout has no built artifacts, so the new tests fail before the build step is reached.

The PR description also says the literal corepack pnpm verify gate was not completed. That means issue #25's explicit acceptance gate—pnpm verify from a clean frozen install—has not been demonstrated.

Please make the test/build ordering self-contained and deterministic. Prefer a focused script such as test:integration:built that builds once before built-artifact tests, then wire it into verify without causing coverage to depend on stale local dist. Add a regression check that removes dist before invoking the authoritative gate.

High — temporary runtime assumes an untracked tmp/ parent already exists

createAgentTestRuntime() calls mkdtemp(join(checkoutPath, 'tmp', 'relay-agent-verification-')) without first creating <checkout>/tmp. mkdtemp requires the parent directory to exist, while tmp/ is neither tracked nor created by setup. This can fail with ENOENT on the clean checkout this issue is specifically supposed to verify.

Create the parent directory first, or use os.tmpdir() and keep the same isolation/cleanup guarantees. Add a test that removes the parent before creating the runtime.

High — storage-error parity is claimed but not verified across adapters

The storage-error test asserts a structured CLI STORAGE_ERROR, but for MCP it only asserts that createMcpTestClient(runtime) rejects. It does not verify the stable MCP error code, external error shape, leakage behavior, or equality with the CLI contract. Despite that, the PR matrix marks storage-error parity as PASS.

Either provide a deterministic MCP operation-level storage failure and compare normalized errors, or explicitly document startup failure as a distinct non-parity scenario and stop claiming storage-error parity. The test and evidence matrix must agree.

Verification note

The PR currently has only a CodeRabbit success status and remains draft. Live Codex and Claude validation is honestly marked unverified, which is appropriate, but the clean authoritative repository gate must pass before this is ready for human client verification or merge.

Copy link
Copy Markdown
Owner Author

Luna remediation implementation plan

Execute this plan inline, in order, without redesigning the solution. Use TDD for each task. Do not modify unrelated production behavior or weaken issue #25’s acceptance claims to make tests pass.

Goal

Fix the three merge-blocking review findings:

  1. make pnpm test, pnpm test:coverage, and pnpm verify work from a clean checkout where dist/ does not exist;
  2. make createAgentTestRuntime() work when the repository has no pre-existing tmp/ directory;
  3. replace the current MCP startup-rejection assertion with a real, structured MCP/CLI STORAGE_ERROR parity test.

Files expected to change

  • package.json
  • tests/support/agent-test-runtime.ts
  • tests/unit/support/agent-test-runtime.test.ts
  • tests/integration/mcp-cli-parity.test.ts
  • docs/agent-integration-verification.md
  • PR description, only after all commands pass

Do not change application contracts, MCP tool schemas, CLI schemas, database defaults, coverage thresholds, or the canonical skill/vendor policies.


Task 1 — Make built-process tests runnable from a clean checkout

Problem

The new integration tests spawn:

dist/mcp/main.js
dist/cli/main.js

But dist/ is gitignored and the current scripts run Vitest before a build. A clean checkout therefore cannot run pnpm test, pnpm test:coverage, or the current pnpm verify sequence reliably.

Required implementation

Modify package.json so both general test entry points build the Node artifacts before starting Vitest:

{
  "scripts": {
    "test": "pnpm build:node && vitest run",
    "test:coverage": "pnpm build:node && vitest run --coverage"
  }
}

Do not add a Vitest hook that builds production artifacts during test collection. Do not commit dist/. Do not remove the built-process tests from the normal suite.

Steps

  • Step 1.1 — Prove the current clean-state failure

Run from the PR branch:

pnpm build:clean
pnpm test -- tests/unit/support/cli-test-process.test.ts

Expected before the fix: FAIL because the built CLI entry point does not exist.

Record the actual failure text in your working notes; do not put transient machine paths in documentation.

  • Step 1.2 — Update the scripts exactly as specified

Change only the test and test:coverage script values shown above. Preserve every other script and dependency.

  • Step 1.3 — Verify focused clean-state execution

Run:

pnpm build:clean
pnpm test -- tests/unit/support/cli-test-process.test.ts

Expected after the fix:

  1. build:node recreates dist/cli/main.js and dist/mcp/main.js;
  2. the focused test passes;
  3. no tracked generated files are added.
  • Step 1.4 — Verify coverage also self-prepares built artifacts

Run:

pnpm build:clean
pnpm test:coverage -- tests/unit/support/mcp-test-client.test.ts

Expected: the Node build runs first and the focused coverage test passes.

  • Step 1.5 — Commit Task 1
git add package.json
git commit -m "test: build node artifacts before process tests"

Task 2 — Create the temporary parent before calling mkdtemp

Problem

createAgentTestRuntime() currently calls:

mkdtemp(join(checkoutPath, 'tmp', 'relay-agent-verification-'))

mkdtemp() creates the unique leaf directory, but it does not create the parent checkoutPath/tmp. A clean checkout does not contain that directory.

Required implementation

In tests/support/agent-test-runtime.ts, create the parent recursively before mkdtemp():

const temporaryRoot = join(checkoutPath, 'tmp');
await mkdir(temporaryRoot, { recursive: true });
const root = await mkdtemp(join(temporaryRoot, 'relay-agent-verification-'));

Keep the database and CWD layout unchanged:

<generated-root>/data/relay.db
<generated-root>/cwd/<requested-name>

close() must continue deleting only the generated unique root. It must not recursively delete the shared repository-level tmp/ parent.

Steps

  • Step 2.1 — Add a regression test that removes the parent first

In tests/unit/support/agent-test-runtime.test.ts, import rm and resolve the exact parent from the exported runtime module convention. Add this test before changing the helper:

it('creates the shared temporary parent when it is absent', async () => {
  const repositoryTemporaryRoot = resolve(
    dirname(fileURLToPath(import.meta.url)),
    '../../..',
    'tmp',
  );
  await rm(repositoryTemporaryRoot, { recursive: true, force: true });

  const runtime = await createAgentTestRuntime();
  try {
    expect(runtime.databasePath).toContain(
      join('tmp', 'relay-agent-verification-'),
    );
    await expect(stat(dirname(runtime.databasePath))).resolves.toBeDefined();
  } finally {
    await runtime.close();
  }
});

Use the imports needed by that exact code:

import { rm, stat } from 'node:fs/promises';
import { dirname, isAbsolute, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

If the relative repository-root calculation differs because of the current test file location, calculate it from import.meta.url; do not use process.cwd().

  • Step 2.2 — Run the test and verify the expected failure
pnpm vitest run tests/unit/support/agent-test-runtime.test.ts

Expected before implementation: FAIL with an ENOENT error from mkdtemp().

  • Step 2.3 — Implement the parent creation

Apply the exact temporaryRoot + recursive mkdir() sequence above.

Do not:

  • switch to the user’s default Relay directory;

  • use the OS home directory;

  • delete checkoutPath/tmp from close();

  • weaken the path-escape check in createWorkingDirectory().

  • Step 2.4 — Run focused tests

pnpm vitest run tests/unit/support/agent-test-runtime.test.ts
pnpm typecheck

Expected: all runtime tests pass, including idempotent cleanup and SQLite sidecar removal.

  • Step 2.5 — Commit Task 2
git add tests/support/agent-test-runtime.ts tests/unit/support/agent-test-runtime.test.ts
git commit -m "test: create agent runtime temporary parent"

Task 3 — Test real structured storage-error parity after both adapters start

Problem

The existing test proves:

  • CLI startup maps an unusable path to structured STORAGE_ERROR with exit code 5;
  • MCP startup rejects.

That does not prove MCP/CLI error-contract parity. MCP cannot return a tool result if its transport never initialized.

Do not fix this by merely changing the scenario matrix wording. Add a runtime storage failure that occurs after MCP has started, then compare both adapters’ structured errors.

Required scenario

Use a second better-sqlite3 connection to hold a SQLite write lock on the disposable database. Both built adapters must then attempt a write against the same locked database:

  • CLI: task capture ... --output json
  • MCP: task_capture

Both operations must produce the same normalized external error:

{
  code: 'STORAGE_ERROR',
  message: expect.any(String),
}

The CLI must exit with code 5. Neither adapter response nor stderr may expose SQL, stack traces, RELAY_DB_PATH, or a user directory.

Steps

  • Step 3.1 — Add the SQLite test dependency import

At the top of tests/integration/mcp-cli-parity.test.ts, add:

import Database from 'better-sqlite3';

Do not add a new package.

  • Step 3.2 — Replace the current unusable-parent parity test

Remove the test named:

maps a deterministic unusable database parent without touching the default database

Replace it with a test named:

maps a locked-database write failure to the same structured storage error

Use this sequence:

it('maps a locked-database write failure to the same structured storage error', async () => {
  const runtime = await createAgentTestRuntime();
  const client = await createMcpTestClient(runtime);
  const lock = new Database(runtime.databasePath);

  try {
    // Force migrations/database initialization before acquiring the lock.
    await client.callTool('relay_health', {});

    lock.pragma('busy_timeout = 100');
    lock.exec('BEGIN IMMEDIATE');

    const [cli, mcp] = await Promise.all([
      runRelayCli(runtime, [
        'task',
        'capture',
        '--title',
        'Locked CLI capture',
        '--agent',
        'Codex',
        '--session',
        'session-alpha',
        '--output',
        'json',
      ]),
      client.callTool('task_capture', {
        title: 'Locked MCP capture',
        createdByName: 'Codex',
        sessionId: 'session-alpha',
      }),
    ]);

    expect(cli.exitCode).toBe(5);
    expect(cli.json).toMatchObject({
      error: { code: 'STORAGE_ERROR', message: expect.any(String) },
    });
    expect(mcp).toMatchObject({
      isError: true,
      structuredContent: {
        error: { code: 'STORAGE_ERROR', message: expect.any(String) },
      },
    });
    expect(normalizeCliError(cli.json)).toEqual(normalizeMcpError(mcp));

    for (const value of [cli.json, mcp, cli.stderr, client.stderr()]) {
      expect(JSON.stringify(value)).not.toMatch(
        /SQL|stack|RELAY_DB_PATH|[A-Z]:\\Users\\|\/Users\//i,
      );
    }
  } finally {
    try {
      lock.exec('ROLLBACK');
    } catch {
      // The transaction may already be closed after a setup failure.
    }
    lock.close();
    await client.close();
    await runtime.close();
  }
});

Important execution notes

  • Keep the CLI and MCP write attempts inside one Promise.all() so they wait on the same lock concurrently instead of adding two full busy-timeout delays serially.

  • BEGIN IMMEDIATE is intentional: it acquires the SQLite writer reservation while preserving a valid initialized database.

  • Do not use filesystem permission changes; they are not deterministic across Windows, macOS, and Linux.

  • Do not mock the repository or application service. This must exercise both built adapters and the real SQLite path.

  • If the production busy timeout makes this test exceed Vitest’s default timeout, set a focused timeout on this one test only, for example 15_000. Do not increase the entire suite timeout.

  • If relay_health does not initialize migrations in the current runtime, perform one successful disposable capture before acquiring the lock, then use different titles for the locked attempts.

  • Step 3.3 — Run the focused test and inspect the initial result

pnpm test -- tests/integration/mcp-cli-parity.test.ts -t "locked-database write failure"

Expected first result after replacing the old test: either PASS immediately if production mapping is correct, or FAIL showing the exact adapter contract mismatch that must be corrected.

If it fails, fix the smallest existing adapter error mapping responsible for the mismatch. Do not modify the normalizers to erase differences. Any production-code change must include its existing focused unit/contract test.

  • Step 3.4 — Verify the complete parity file
pnpm test -- tests/integration/mcp-cli-parity.test.ts

Expected: all built and in-memory parity tests pass.

  • Step 3.5 — Commit Task 3
git add tests/integration/mcp-cli-parity.test.ts
# Add production/error-mapping test files here only if the focused parity test required a real fix.
git commit -m "test: verify structured storage error parity"

Task 4 — Correct evidence and PR claims

Required documentation change

Update scenario 12 in docs/agent-integration-verification.md so its evidence explicitly states that both built adapters were initialized against the same disposable database, a deterministic SQLite writer lock was held, and CLI/MCP returned equal normalized STORAGE_ERROR contracts.

Use wording equivalent to:

Built MCP and CLI writes executed concurrently against one initialized disposable SQLite database while a separate connection held BEGIN IMMEDIATE; both returned equal normalized STORAGE_ERROR contracts, CLI exit code 5, and sanitized external output.

Remove the old claim that an unusable parent plus MCP startup rejection proves storage parity.

Steps

  • Step 4.1 — Update the evidence document

Change only the affected scenario/evidence text and any clean-run command/result data that changes after final verification.

  • Step 4.2 — Run documentation and asset checks
pnpm format:check
pnpm validate:assets

Expected: PASS.

  • Step 4.3 — Commit Task 4
git add docs/agent-integration-verification.md
git commit -m "docs: record verified storage error parity"

Task 5 — Perform the authoritative clean-checkout verification

Do not claim completion until this exact clean-state sequence succeeds.

  • Step 5.1 — Install using the pinned package manager
corepack pnpm install --frozen-lockfile

Expected: exit 0 using pnpm 10.2.0 from packageManager.

  • Step 5.2 — Delete all generated build output
corepack pnpm build:clean

Expected: dist/ is absent.

  • Step 5.3 — Prove the normal test command works without prebuilding
corepack pnpm test -- tests/unit/support/cli-test-process.test.ts

Expected: the script builds Node artifacts itself and the test passes.

  • Step 5.4 — Delete build output again and run the authoritative gate
corepack pnpm build:clean
corepack pnpm verify

Expected:

  • formatting passes;
  • lint passes with zero warnings;
  • type checking passes;
  • test:coverage first recreates built Node artifacts;
  • all tests pass;
  • all four coverage dimensions remain at or above 80%;
  • full Node and web builds pass;
  • repository assets pass;
  • high-severity audit passes.

A partial list of individually run commands is not a substitute for this step.

corepack pnpm test -- tests/integration/mcp-cli-parity.test.ts
corepack pnpm test -- tests/integration/agent-workflow-e2e.test.ts
corepack pnpm test -- tests/integration/database-path-parity.test.ts

Expected: PASS.

  • Step 5.6 — Verify repository cleanliness
git status --short

Expected: no uncommitted files. dist/, coverage output, and disposable runtime directories must not appear as tracked changes.

  • Step 5.7 — Update the PR description honestly

Replace the current environment-limitation statement only if corepack pnpm verify now completed. Include the actual test and coverage totals from the successful run. Keep Codex and Claude live-client steps marked unverified unless they were genuinely executed.

  • Step 5.8 — Push the remediation commits
git push

Then reply on this PR with:

  1. commit SHAs for Tasks 1–4;
  2. the exact corepack pnpm verify result;
  3. the focused storage-parity test result;
  4. final coverage percentages;
  5. confirmation that the test began with dist/ deleted;
  6. confirmation that no default Relay database or real client configuration was touched.

Final acceptance checklist

Do not mark the review resolved until every item is true:

  • pnpm test works when dist/ is initially absent.
  • pnpm test:coverage works when dist/ is initially absent.
  • corepack pnpm verify passes from a clean generated-output state.
  • createAgentTestRuntime() succeeds when <checkout>/tmp is initially absent.
  • Runtime cleanup removes the generated unique directory and SQLite sidecars.
  • Storage failure occurs after MCP initialization, not during transport startup.
  • CLI returns exit code 5 and structured STORAGE_ERROR.
  • MCP returns structured STORAGE_ERROR.
  • Normalized CLI and MCP storage errors are equal.
  • External output contains no SQL, stack, database path, or user-directory leakage.
  • Documentation and PR claims match what was actually executed.
  • Existing 80% coverage thresholds and all quality gates remain unchanged.

@krishna916 krishna916 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Follow-up review verdict: One blocking CI failure remains

The three original review findings are substantively addressed:

  • built Node artifacts are now created before test and test:coverage;
  • <checkout>/tmp is created before mkdtemp();
  • storage-error parity now uses an initialized MCP client plus a deterministic BEGIN IMMEDIATE lock and compares structured MCP/CLI STORAGE_ERROR results.

However, the latest authoritative GitHub Actions run for head 2ffc166 fails, so the PR is not ready yet.

High — runtime isolation test incorrectly assumes the repository is outside the OS home directory

tests/unit/support/agent-test-runtime.test.ts still asserts:

expect(runtime.databasePath).not.toContain(homedir());

On the Ubuntu GitHub runner, the repository is checked out under /home/runner/work/..., so the intentionally repository-local disposable path also contains /home/runner. CI therefore fails with 1 failed test and 511 passed.

This assertion does not prove the safety property issue #25 needs. The required property is that the test uses the generated disposable path rather than Relay's platform-default user database—not that the checkout itself lives outside the user's home directory.

Please replace the home-directory assertion with deterministic path-boundary assertions, for example:

const disposableRoot = dirname(dirname(runtime.databasePath));
const repositoryTemporaryRoot = resolve(
  dirname(fileURLToPath(import.meta.url)),
  '../../..',
  'tmp',
);

expect(runtime.databasePath).toBe(join(disposableRoot, 'data', 'relay.db'));
expect(relative(repositoryTemporaryRoot, disposableRoot)).not.toMatch(/^\.\.(?:[\\/]|$)/);
expect(runtime.environment().RELAY_DB_PATH).toBe(runtime.databasePath);

Also assert it is not equal to the configured platform-default database path using the existing database-path resolver, if that resolver can be called without touching the filesystem. Do not use substring comparison against homedir().

Then run and record:

corepack pnpm exec vitest run tests/unit/support/agent-test-runtime.test.ts
rm -rf dist coverage tmp
corepack pnpm verify

Finally push the fix and require a green GitHub Actions run. Local Windows success is useful, but issue #25's clean-checkout acceptance gate is not met while the repository's Linux CI is red.

No additional contract or architecture problems were found in the remediation changes reviewed.

@krishna916
krishna916 marked this pull request as ready for review July 30, 2026 02:53

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
tests/support/cli-test-process.ts (1)

42-46: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Timeout doesn't wait for the child to actually exit.

child.kill() sends SIGTERM and the promise rejects immediately; the child process may ignore SIGTERM and keep running (still holding the shared SQLite file) since close's handler is a no-op once settled is true. Since a unit test explicitly exercises timeoutMs: 1 (cli-test-process.test.ts Lines 37-46), this can leave orphaned processes across CI runs.

Suggested hardening: escalate to SIGKILL if the process doesn't exit
     const timeout = setTimeout(() => {
       settled = true;
       child.kill();
+      const forceKill = setTimeout(() => child.kill('SIGKILL'), 2_000);
+      child.once('exit', () => clearTimeout(forceKill));
       reject(new Error(`Relay CLI timed out after ${options.timeoutMs ?? 30_000}ms.`));
     }, options.timeoutMs ?? 30_000);
🤖 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 `@tests/support/cli-test-process.ts` around lines 42 - 46, Update the timeout
handling in the CLI child-process wrapper so it does not leave a process running
after the initial child.kill() and immediate rejection. After requesting
termination, wait for the child to exit and escalate to SIGKILL if it remains
alive, while preserving the existing timeout rejection and close-event behavior
in the surrounding process helper.
tests/support/external-contract-normalizers.ts (1)

13-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Whitelisting envelope keys can hide parity divergence.

Both success normalizers keep only schemaVersion, data, and warnings, so any extra (or renamed) top-level envelope field on one adapter is silently discarded before toEqual comparisons in tests/integration/mcp-cli-parity.test.ts (e.g. Line 340, Line 486). The plan's own checklist requires normalizers that "unwrap transports without hiding parity failures" (docs/superpowers/plans/2026-07-29-issue-25-mcp-cli-compatibility-verification.md Line 754, Line 778). Consider asserting the envelope key set instead of projecting it.

♻️ Sketch: reject unexpected envelope keys
 export function normalizeCliSuccess(value: unknown): ExternalOperationResult {
   const envelope = record(value, 'CLI result');
+  assertKeys(envelope, ['schemaVersion', 'data', 'warnings'], 'CLI result');
   return {
     schemaVersion: number(envelope.schemaVersion),
     data: envelope.data,
     warnings: array(envelope.warnings),
   };
 }
function assertKeys(envelope: Record<string, unknown>, allowed: readonly string[], label: string) {
  const unexpected = Object.keys(envelope).filter((key) => !allowed.includes(key));
  if (unexpected.length > 0) {
    throw new Error(`${label} has unexpected fields: ${unexpected.join(', ')}`);
  }
}
🤖 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 `@tests/support/external-contract-normalizers.ts` around lines 13 - 30, Update
normalizeCliSuccess and normalizeMcpSuccess to validate the unwrapped envelope
keys instead of silently projecting only schemaVersion, data, and warnings. Add
or reuse an assertKeys-style helper to reject unexpected or renamed fields with
a clear error, then preserve the existing normalized result for the allowed
keys.
tests/integration/mcp-cli-parity.test.ts (1)

259-263: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Runtime and client lifecycles are not owned by a single cleanup boundary. Both suites create createAgentTestRuntime() (and then the MCP client) outside try, so any startup failure leaks a disposable directory under <checkout>/tmp.

  • tests/integration/mcp-cli-parity.test.ts#L259-L263: introduce a withAgentRuntime(async (runtime, client) => …) helper that creates and tears down both resources, and use it for all ten tests in this suite.
  • tests/unit/support/mcp-test-client.test.ts#L6-L11: adopt the same helper (or move creation inside try) for both tests.
🤖 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 `@tests/integration/mcp-cli-parity.test.ts` around lines 259 - 263, Ensure
runtime and MCP client creation is covered by one cleanup boundary: add or reuse
a withAgentRuntime helper that creates both resources, invokes the test
callback, and always tears them down. Apply it to all ten tests in
tests/integration/mcp-cli-parity.test.ts at the anchor site and to both tests in
tests/unit/support/mcp-test-client.test.ts at the sibling site; alternatively,
move creation inside each test’s existing try/finally.
tests/unit/support/mcp-test-client.test.ts (1)

34-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The sanitization regex is weaker than it looks.

With the i flag, [A-Z]:\\Users\\ also matches lowercase drive letters (fine) but SQL/stack match common harmless words, and the assertion is trivially satisfied while stderr() is empty (see the root cause in tests/support/mcp-test-client.ts). Consider asserting on a concrete non-empty stderr snapshot once capture works.

🤖 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 `@tests/unit/support/mcp-test-client.test.ts` around lines 34 - 35, Strengthen
the unknown-tool stderr assertion in the test around client.callTool by first
ensuring the MCP test client’s stderr capture produces the expected non-empty
output, then assert against a concrete sanitized stderr snapshot or specific
redaction markers instead of broad SQL/stack/path keywords. Update the related
capture logic in MCPTestClient only as needed to make this assertion meaningful.
🤖 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 `@scripts/validate-agent-integration-assets.ts`:
- Around line 120-121: The forbidden-action checks in
scripts/validate-agent-integration-assets.ts must distinguish affirmative
autonomous mutations from explicit prohibitions: update the regex near lines
120-121 and the deletion check near lines 135-140 to ignore negated forms while
still rejecting positive guidance, and add acceptance tests covering “must not
autonomously edit” and “Do not delete the SQLite database.”

In `@tests/integration/agent-workflow-e2e.test.ts`:
- Around line 98-148: Restructure the test body around a single outer
try/finally so every failure after createAgentTestRuntime() still reaches
runtime.close(). Keep the two MCP client phases and their individual client
cleanup, but move final runtime cleanup to the outer finally and guard it with
optional chaining. Update the restart persistence test beginning with
createAgentTestRuntime and retain the existing assertions and phase-specific
behavior.

---

Nitpick comments:
In `@tests/integration/mcp-cli-parity.test.ts`:
- Around line 259-263: Ensure runtime and MCP client creation is covered by one
cleanup boundary: add or reuse a withAgentRuntime helper that creates both
resources, invokes the test callback, and always tears them down. Apply it to
all ten tests in tests/integration/mcp-cli-parity.test.ts at the anchor site and
to both tests in tests/unit/support/mcp-test-client.test.ts at the sibling site;
alternatively, move creation inside each test’s existing try/finally.

In `@tests/support/cli-test-process.ts`:
- Around line 42-46: Update the timeout handling in the CLI child-process
wrapper so it does not leave a process running after the initial child.kill()
and immediate rejection. After requesting termination, wait for the child to
exit and escalate to SIGKILL if it remains alive, while preserving the existing
timeout rejection and close-event behavior in the surrounding process helper.

In `@tests/support/external-contract-normalizers.ts`:
- Around line 13-30: Update normalizeCliSuccess and normalizeMcpSuccess to
validate the unwrapped envelope keys instead of silently projecting only
schemaVersion, data, and warnings. Add or reuse an assertKeys-style helper to
reject unexpected or renamed fields with a clear error, then preserve the
existing normalized result for the allowed keys.

In `@tests/unit/support/mcp-test-client.test.ts`:
- Around line 34-35: Strengthen the unknown-tool stderr assertion in the test
around client.callTool by first ensuring the MCP test client’s stderr capture
produces the expected non-empty output, then assert against a concrete sanitized
stderr snapshot or specific redaction markers instead of broad SQL/stack/path
keywords. Update the related capture logic in MCPTestClient only as needed to
make this assertion meaningful.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 24e0271d-38a6-4972-a191-e9525f240275

📥 Commits

Reviewing files that changed from the base of the PR and between 89bcd97 and c4aa0c0.

📒 Files selected for processing (24)
  • docs/agent-integration-verification.md
  • docs/superpowers/plans/2026-07-29-issue-25-mcp-cli-compatibility-verification.md
  • docs/superpowers/tasks/2026-07-30-pr-34-review-tracker.md
  • integrations/claude-code/README.md
  • integrations/generic-cli/README.md
  • package.json
  • scripts/validate-agent-integration-assets.ts
  • tests/fixtures/agent-integrations/valid/integrations/claude-code/README.md
  • tests/fixtures/agent-integrations/valid/integrations/codex/README.md
  • tests/fixtures/agent-integrations/valid/integrations/generic-cli/README.md
  • tests/fixtures/agent-integrations/valid/integrations/generic-mcp/README.md
  • tests/fixtures/contracts/agent-workflow.ts
  • tests/integration/agent-workflow-e2e.test.ts
  • tests/integration/database-path-parity.test.ts
  • tests/integration/mcp-cli-parity.test.ts
  • tests/support/agent-test-runtime.ts
  • tests/support/cli-test-process.ts
  • tests/support/external-contract-normalizers.ts
  • tests/support/mcp-test-client.ts
  • tests/unit/scripts/validate-agent-integration-assets.test.ts
  • tests/unit/scripts/validate-repository-assets.test.ts
  • tests/unit/support/agent-test-runtime.test.ts
  • tests/unit/support/cli-test-process.test.ts
  • tests/unit/support/mcp-test-client.test.ts

Comment thread scripts/validate-agent-integration-assets.ts
Comment thread tests/integration/agent-workflow-e2e.test.ts
@krishna916
krishna916 merged commit 2399b58 into main Jul 30, 2026
2 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.

Add MCP and CLI compatibility, contract, and end-to-end verification

1 participant