Skip to content

fix(mcp): MCP_harden inline review follow-ups - #187

Merged
tonythethompson merged 24 commits into
mainfrom
fix/mcp-harden-inline-followups
Aug 8, 2026
Merged

tonythethompson merged 24 commits into
mainfrom
fix/mcp-harden-inline-followups

Conversation

@tonythethompson

@tonythethompson tonythethompson commented Aug 8, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Bound OLIVE_JOB_SETUP_STUB wait loops with a finite timeout (default 120s, overridable via OLIVE_JOB_SETUP_STUB_TIMEOUT_MS) and fail the job on expiration
  • Reclaim empty/malformed Studio config smoke locks without busy-spinning on failed unlink; use rmdirSync for empty .olive-studio cleanup
  • Map SIGHUP to exit code 129 in agent smoke; extend lock ownership and resolvePython preference tests
  • Mock spawn/fs in idempotency tests, drain detached MCP setup, and assert hold-1/hold-2/fp-only registry reuse

Skipped (still not valid)

  • state.test.ts import reorder: vitest requires vi.mock before importing modules that load the mocked dependency; current order after vi.hoisted/vi.mock is correct

Test plan

  • pnpm exec vitest run src/lib/__tests__/resolvePython.test.ts src/lib/__tests__/studioConfigSmokeLock.test.ts src/lib/__tests__/studioConfigSnapshot.test.ts
  • pnpm exec vitest run src/server/services/olive/jobRunner.idempotency.test.ts --config vitest.server.config.ts
  • CI green on PR

Made with Cursor

Review in cubic

Bound stub setup waits, reclaim malformed smoke locks without busy-spin, use rmdir for empty config dirs, and harden idempotency tests against real spawn/fs side effects.

Co-authored-by: Cursor <cursoragent@cursor.com>

@sourcery-ai sourcery-ai 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.

Sorry @tonythethompson, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Aug 8, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

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

Next review available in: 41 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2f56cbb7-f450-45b3-bdde-5cd1aa3bdad6

📥 Commits

Reviewing files that changed from the base of the PR and between de08c25 and a14699d.

📒 Files selected for processing (4)
  • scripts/mcp-agent-smoke.mjs
  • scripts/studioConfigSmokeLock.mjs
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
  • src/server/services/olive/jobRunner.stubSetup.test.ts
📝 Walkthrough

Walkthrough

The PR hardens MCP smoke execution, Studio lock publication and reclamation, configuration cleanup, Python resolution coverage, and Olive job setup and idempotency tests.

Changes

Smoke and lock hardening

Layer / File(s) Summary
Atomic lock publication and reclamation
scripts/studioConfigSmokeLock.mjs, src/lib/__tests__/studioConfigSmokeLock.test.ts
Lock acquisition publishes complete PID contents with hard-linking or platform-specific fallbacks. It delays malformed-lock reclamation, reclaims dead valid-PID locks, validates ownership, and covers publication races and grace periods.
Directory cleanup and smoke execution
scripts/studioConfigSnapshot.mjs, scripts/studioConfigSmokeLock.mjs, src/lib/__tests__/studioConfigSmokeLock.test.ts, scripts/mcp-agent-smoke.mjs
Configuration cleanup uses rmdirSync. The MCP smoke script installs a pinned mcporter once and invokes its CLI through Node with shell: false. SIGHUP returns exit code 129.
Python resolution coverage
src/lib/__tests__/resolvePython.test.ts
Tests verify python3 precedence, UTF-8 version checks, and no python invocation when python3 is available.
Vite import resolution
vite.config.ts
The ANY_DOT_VENV_DIR import includes the .ts extension.

Olive job lifecycle

Layer / File(s) Summary
Setup-stub timeout handling
src/server/services/olive/jobRunner.ts, src/server/services/olive/jobRunner.stubSetup.test.ts
The setup stub applies OLIVE_JOB_SETUP_STUB_TIMEOUT_MS, defaults invalid or non-positive values to 120 seconds, and returns HTTP 504 after timeout. Tests verify failure, logging, finalization, overrides, and the UI response.
Tracked asynchronous idempotency tests
src/server/services/olive/jobRunner.idempotency.test.ts
Tests mock process and filesystem operations, track detached setup, drain pending jobs during teardown, and validate keyed-job creation and fingerprint-only reuse.

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

Possibly related issues

  • tonythethompson/Olive-Studio#186 — The PR changes the MCP smoke and Olive job policy areas described by the issue.

Possibly related PRs

🚥 Pre-merge checks | ✅ 8
✅ Passed checks (8 passed)
Check name Status Explanation
Title check ✅ Passed The title identifies MCP hardening, which is a central objective of the changeset.
Description check ✅ Passed The description directly summarizes the timeout, lock, MCP invocation, and test changes in the pull request.
Docstring Coverage ✅ Passed Docstring coverage is 69.23% which is sufficient. The required threshold is 60.00%.
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.
Pipeline Stage Enum Ordering ✅ Passed The full PR diff and PR-tip source contain no SessionWorkflowStage enum, stage members, or related comparisons; enum-ordering checks are not applicable.
Gpu/Cpu Runtime Boundary ✅ Passed The PR changes no files under inference/ and no CPU/GPU requirements files; it also introduces no boundary-sensitive runtime changes.
Managed Host Restart Safety ✅ Passed The PR diff contains no managed-host target files or symbols and no restart, lease, busy-state, or provider-readiness changes; the check is not applicable.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mcp-harden-inline-followups
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/mcp-harden-inline-followups

Warning

Review ran into problems

🔥 Problems

Linked repositories: Public OSS repositories can only analyze public repositories installed in this organization. Analyzed tonythethompson/QuickShell, tonythethompson/numan, tonythethompson/dependency-chain-substrate, skipped Trackdubllc/Trackdub.


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.

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

fix(mcp): harden MCP smoke locks and stubbed Olive job setup

🐞 Bug fix 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Add a finite timeout to stubbed Olive job setup and fail on expiration.
• Reclaim malformed Studio config smoke locks without busy-spinning; safely remove empty dirs.
• Harden MCP idempotency tests by mocking spawn/fs and draining detached setup before cleanup.
Diagram

graph TD
  A["mcp-agent-smoke.mjs"] --> B["studioConfigSmokeLock.mjs"] --> F[("Filesystem")]
  A --> C["studioConfigSnapshot.mjs"] --> F
  D["jobRunner.ts"] --> E["Job Registry"]
  G{{"OLIVE_JOB_SETUP_STUB_TIMEOUT_MS"}} --> D

  subgraph Legend
    direction LR
    _file["Script/Module"] ~~~ _db[("State/Store")] ~~~ _ext{{"Config/Env"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use Promise.race(timeout) helper for stub wait
  • ➕ Centralizes timeout behavior and reduces bespoke loop logic
  • ➕ Easier to unit test timeout boundary conditions
  • ➖ Still needs periodic polling unless job emits cancellation/finalization events
  • ➖ Adds a helper/util surface area if one doesn't already exist
2. Event-driven setup completion instead of polling registry state
  • ➕ Avoids polling loops and reduces CPU wakeups in both prod and tests
  • ➕ Cleaner lifecycle semantics for detached setup tasks
  • ➖ Requires wider refactor of job state transitions/notification plumbing
  • ➖ Higher risk change than a targeted hardening follow-up

Recommendation: Keep the PR’s approach: bounding the stub wait with an env-configurable timeout and hardening lock reclaim behavior are low-risk, targeted fixes appropriate for an inline follow-up. Consider introducing a small shared timeout helper later to standardize similar polling loops, but an event-driven refactor is likely out of scope for this fix PR.

Files changed (7) +149 / -31

Bug fix (4) +33 / -10
mcp-agent-smoke.mjsMap SIGHUP to a conventional exit code +1/-0

Map SIGHUP to a conventional exit code

• Adds explicit handling for SIGHUP to return exit code 129. This aligns smoke exit behavior with common signal-to-exit conventions.

scripts/mcp-agent-smoke.mjs

studioConfigSmokeLock.mjsReclaim malformed locks without busy-spin; use rmdirSync for empty dirs +10/-7

Reclaim malformed locks without busy-spin; use rmdirSync for empty dirs

• Treats empty/malformed lock bodies as reclaimable and only skips poll sleep when unlink succeeds, preventing tight-loop spinning on failed reclaim. Switches empty '.olive-studio' cleanup from rmSync to rmdirSync and updates dependency injection accordingly.

scripts/studioConfigSmokeLock.mjs

studioConfigSnapshot.mjsUse rmdirSync when removing an empty config directory +9/-2

Use rmdirSync when removing an empty config directory

• Imports rmdirSync and uses it to remove the config directory when smoke created it solely for a patch. Keeps the cleanup best-effort (ignores missing/not-empty errors).

scripts/studioConfigSnapshot.mjs

jobRunner.tsBound stubbed Olive job setup wait with a configurable timeout +13/-1

Bound stubbed Olive job setup wait with a configurable timeout

• Adds a finite deadline for OLIVE_JOB_SETUP_STUB wait loops (default 120s, overridable via OLIVE_JOB_SETUP_STUB_TIMEOUT_MS). On expiry, marks the job failed and logs a timeout message before continuing cleanup.

src/server/services/olive/jobRunner.ts

Tests (3) +116 / -21
resolvePython.test.tsAdd coverage for python3 preference when both candidates exist +21/-0

Add coverage for python3 preference when both candidates exist

• Adds a test asserting resolvePython prefers 'python3' over 'python' when both are executable on PATH. Verifies spawnSync call ordering to avoid unnecessary fallback checks.

src/lib/tests/resolvePython.test.ts

studioConfigSmokeLock.test.tsExtend lock ownership coverage and update rmdir-based cleanup test +10/-2

Extend lock ownership coverage and update rmdir-based cleanup test

• Adds assertions that release() does not unlink a lock owned by a different PID, then confirms owned release clears it. Updates the directory cleanup test to inject and verify rmdirSync behavior for busy/non-empty dirs.

src/lib/tests/studioConfigSmokeLock.test.ts

jobRunner.idempotency.test.tsIsolate MCP idempotency tests from real spawn/fs and drain detached setup +85/-19

Isolate MCP idempotency tests from real spawn/fs and drain detached setup

• Introduces child_process mocking (including spawn), spies on fs mkdir/write to prevent side effects, and tracks fire-and-forget setup to drain before afterEach clears the registry. Tightens assertions around hold-1/hold-2 and fingerprint-only reuse semantics.

src/server/services/olive/jobRunner.idempotency.test.ts

@greptile-apps

greptile-apps Bot commented Aug 8, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This follow-up hardens MCP smoke execution, lock ownership and cleanup, setup-stub timeouts, and related tests.

  • Installs and invokes the pinned mcporter CLI without Windows argument re-parsing.
  • Reworks Studio configuration lock publication, stale-owner reclamation, and empty-directory cleanup.
  • Bounds stub setup waits and expands signal, Python resolution, lock, and idempotency coverage.

Confidence Score: 4/5

The PR does not yet appear safe to merge because interrupted fallback publication can leave the smoke lock permanently unrecoverable.

The earlier incomplete reclaim-mutex failure remains reachable when hard-link publication falls back to a direct exclusive write: interruption can leave an incomplete final-path body, and current recovery explicitly refuses to remove it, causing every later smoke acquisition to time out.

Files Needing Attention: scripts/studioConfigSmokeLock.mjs

Important Files Changed

Filename Overview
scripts/studioConfigSmokeLock.mjs Replaces direct lock creation with temp-file publication and serialized reclamation, but the fallback can still leave an unrecoverable incomplete lock after interruption.
scripts/mcp-agent-smoke.mjs Adds isolated mcporter installation, direct Node CLI invocation, and explicit SIGHUP exit handling.
scripts/studioConfigSnapshot.mjs Uses non-recursive directory removal when cleaning up a newly created Studio configuration directory.
src/server/services/olive/jobRunner.ts Bounds setup-stub waiting with a configurable timeout and reports expiration as job failure.
src/lib/tests/studioConfigSmokeLock.test.ts Substantially expands lock contention, publication fallback, reclamation, and cleanup coverage.
src/server/services/olive/jobRunner.idempotency.test.ts Strengthens idempotency coverage with controlled process and filesystem behavior.
src/server/services/olive/jobRunner.stubSetup.test.ts Covers setup-stub timeout and completion behavior.
vite.config.ts Updates test configuration supporting the expanded smoke and job-runner tests.

Reviews (18): Last reviewed commit: "fix(mcp): never age-reclaim incomplete s..." | Re-trigger Greptile

Comment thread scripts/studioConfigSmokeLock.mjs Outdated

@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: 5ee7ab58fe

ℹ️ 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".

Comment thread scripts/studioConfigSmokeLock.mjs Outdated
@qodo-code-review

qodo-code-review Bot commented Aug 8, 2026 •

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Empty lock reclaim race ✓ Resolved 🐞 Bug ≡ Correctness
Description
acquireStudioConfigSmokeLock now unlinks the lock when the body is empty/malformed, but the lock
is created (openSync('wx')) before the PID is written, so another process can observe an empty file
and reclaim it while the creator still believes it holds the lock. This can defeat mutual exclusion
and allow overlapping smokes to concurrently mutate/restore .olive-studio/config.json.
Code

scripts/studioConfigSmokeLock.mjs[R92-95]

+        const reclaimable = !Number.isFinite(holder) || !alive(holder);
+        if (reclaimable) {
          try {
            unlink(lockPath);
Relevance

●●● Strong

Repo often accepts fixes for subtle concurrency/race conditions; no close rejection precedent found.

PR-#73
PR-#75

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The lock creation and PID publication are separate operations, so an empty lock file is observable.
The new reclaim condition explicitly unlinks when PID parsing is non-finite, enabling a contender to
delete a just-created lock before its owner writes the PID. The lock is relied on to serialize smoke
config mutation, so losing exclusivity is harmful.

scripts/studioConfigSmokeLock.mjs[65-72]
scripts/studioConfigSmokeLock.mjs[88-99]
scripts/mcp-agent-smoke.mjs[391-401]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`acquireStudioConfigSmokeLock()` treats non-finite/empty lock bodies as immediately reclaimable and unlinks the file. Because the lock file is created with `openSync(lockPath, "wx")` and only then populated with the PID via `writeFileSync(fd, ...)`, there is a real window where the file exists but is empty. A contending process can read during that window, parse `NaN`, and unlink the lock path, allowing both processes to proceed.

### Issue Context
This lock is used by `scripts/mcp-agent-smoke.mjs` to serialize config snapshot/patch/restore. Breaking exclusivity can lead to clobbered restores or mixed policy patches.

### Fix Focus Areas
- scripts/studioConfigSmokeLock.mjs[65-99]

### Suggested fix approach
Pick one of these safe protocols:
1) **Grace-period reclaim for malformed locks (recommended minimal change):**
  - If `holder` is non-finite (empty/malformed), *do not* unlink immediately.
  - Stat the lock file (`statSync(lockPath).mtimeMs`) and only consider it reclaimable if it is older than a small threshold (e.g. `Math.max(1000, pollMs * 4)`) to avoid unlinking a freshly-created-but-not-yet-written lock.
  - Keep the existing reclaim for finite-but-dead PIDs.

2) **Use an atomic publication protocol:**
  - Write PID to a temp file, then atomically publish via `linkSync`/`rename` in a way that does not expose an empty lock at the final path. (Avoid plain `rename` if it can overwrite an existing lock.)

After the change, add/adjust a unit test to simulate: Process A creates lock file but PID write is delayed; Process B sees empty body; B must *not* reclaim until after grace period.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context used
✅ Compliance rules (platform): 87 rules
✅ REVIEW.md
Review mode: ⚖️ Balanced: Downgraded extended -> standard: change is below the extended eligibility bar (hunks 19/18, lines 180/200; both must reach the floor). Router rationale: This behavioral PR spans runtime job timeout, lock reclamation, signal handling, and substantial concurrency/idempotency test changes across 7 files with 19 independent edit sites, making multiple subtle defects plausible.

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread scripts/studioConfigSmokeLock.mjs Outdated
@qodo-code-review

Copy link
Copy Markdown
Contributor

Qodo Fixer

✅ Committed (1) · ☑ Fixed (1)

Grey Divider

Commits pushed directly to this PR — no separate fix PR opened.

Process — 1 fixed
  • ☑ Fixed: Empty lock reclaim race

Create the Studio config smoke lock with O_EXCL write of the owner PID so waiters never see a live empty body from this publisher, and only reclaim aged malformed locks after a publish grace window.

Co-authored-by: Cursor <cursoragent@cursor.com>
greptile-apps[bot]
greptile-apps Bot previously approved these changes Aug 8, 2026

@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: 3

🤖 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/studioConfigSmokeLock.mjs`:
- Around line 93-105: The lock-body classification around malformed and
reclaimable in studioConfigSmokeLock must treat partial numeric PID contents as
incomplete while the writer may still be publishing. Validate that the parsed
PID exactly matches the complete numeric body rather than accepting parseInt
prefixes, and apply the existing publish grace window to incomplete numeric
bodies before reclaiming; add a regression test covering a partial numeric PID
body.

In `@src/server/services/olive/jobRunner.idempotency.test.ts`:
- Line 3: Update the test setup and teardown around the detached setup task and
settled helper to track every created job ID, then cancel or finalize each stub
job through the supported lifecycle path in afterEach. Await each job’s
finishedAt before clearing jobRegistry or restoring mocks, enforce the teardown
deadline, and fail teardown if any job remains unfinished.

In `@src/server/services/olive/jobRunner.ts`:
- Around line 316-329: Add deterministic timer-controlled coverage for the
setup-stub timeout flow around the job runner’s timeout logic, including an
invalid or non-positive OLIVE_JOB_SETUP_STUB_TIMEOUT_MS value to verify the
120-second fallback. Assert the job becomes failed, the timeout log is emitted,
and finalizeJob sets finishedAt; run lint, typecheck, and the required server
smoke checks before completion.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b91dafca-5e8c-480a-b090-f1d135442e12

📥 Commits

Reviewing files that changed from the base of the PR and between da1866b and ffd9d35.

📒 Files selected for processing (7)
  • scripts/mcp-agent-smoke.mjs
  • scripts/studioConfigSmokeLock.mjs
  • scripts/studioConfigSnapshot.mjs
  • src/lib/__tests__/resolvePython.test.ts
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
  • src/server/services/olive/jobRunner.idempotency.test.ts
  • src/server/services/olive/jobRunner.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • tonythethompson/QuickShell (manual)
  • tonythethompson/numan (manual)
  • tonythethompson/dependency-chain-substrate (manual)
📜 Review details
⏰ Context from checks skipped due to timeout. (5)
  • GitHub Check: Greptile Review
  • GitHub Check: docker-build
  • GitHub Check: python-tests
  • GitHub Check: validate
  • GitHub Check: olive-pass-availability
🧰 Additional context used
📓 Path-based instructions (7)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

Do not implement the listed backburner AI providers unless explicitly requested; prefer Custom or OpenAI-compatible providers for OpenAI-shaped hosts.

Files:

  • scripts/mcp-agent-smoke.mjs
  • src/lib/__tests__/resolvePython.test.ts
  • src/server/services/olive/jobRunner.ts
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
  • scripts/studioConfigSnapshot.mjs
  • scripts/studioConfigSmokeLock.mjs
  • src/server/services/olive/jobRunner.idempotency.test.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

src/**/*.{ts,tsx}: Match existing naming, file layout, and TypeScript patterns in src/.
Put shared recipe logic in src/lib/, especially pipelineValidation.ts, oliveRecipeBuilder.ts, and recipePipeline.ts.

src/**/*.{ts,tsx}: Keep validation logic in shared libraries rather than duplicating it in UI cell helpers or inspectors.
Split the InputEnvironmentPanel, IHVIntegrationPanel, and ExecutionWorkspace mega-panels into feature folders with colocated hooks and tests.
Keep server and UI AI provider catalogs synchronized, preferably through a shared provider ID list or synchronization test; register new providers in both catalogs.
Add test coverage for recipe-graph/, passCatalog, oliveRecipeHub, jobHistoryStore, and vramEstimate, and strengthen component tests for the large panels.

src/**/*.{ts,tsx}: All UI state mutations must go through commitUiStateUpdate in src/lib/pipelineValidation.ts so invariants are enforced; use usePipelineState() for state access and replaceState for recipe imports or preset loads.
Avoid export * barrel imports; import directly from the actual module file to preserve Vite tree-shaking and component-test isolation.

Follow the React performance guidance in docs/REACT_BEST_PRACTICES.md, especially eliminating waterfalls, avoiding barrel imports, and deferring non-critical third-party libraries.

Files:

  • src/lib/__tests__/resolvePython.test.ts
  • src/server/services/olive/jobRunner.ts
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
  • src/server/services/olive/jobRunner.idempotency.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx,js,jsx}: Place imports at the top of modules; use inline imports only for a documented circular dependency.
Run linting and ensure typecheck-related CI checks pass before submitting changes.
For UI or server changes, manually smoke-test development startup, recipe loading/building, validation banners, and live execution when execution behavior is touched.

Use the project's React 19, Vite, Express, and Tauri 2 stack conventions for frontend and server TypeScript/JavaScript code.

Files:

  • src/lib/__tests__/resolvePython.test.ts
  • src/server/services/olive/jobRunner.ts
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
  • src/server/services/olive/jobRunner.idempotency.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

When working with React 19 or Vite 8 APIs, consult current Context7 documentation instead of assuming conventions from earlier major versions.

Files:

  • src/lib/__tests__/resolvePython.test.ts
  • src/server/services/olive/jobRunner.ts
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
  • src/server/services/olive/jobRunner.idempotency.test.ts
src/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use the unit-test configuration for src/lib/ unit tests and keep unit tests compatible with Vitest.

Files:

  • src/lib/__tests__/resolvePython.test.ts
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
  • src/server/services/olive/jobRunner.idempotency.test.ts
src/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not trigger real Olive optimization runs in tests or CI; use CPU-only recipe building, JSON export, and validation flows instead.

Files:

  • src/lib/__tests__/resolvePython.test.ts
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
  • src/server/services/olive/jobRunner.idempotency.test.ts
src/server/services/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Keep server-side business logic in services, including AI providers, Olive job/virtual-environment handling, and related service modules.

Files:

  • src/server/services/olive/jobRunner.ts
  • src/server/services/olive/jobRunner.idempotency.test.ts
🔍 Remote MCP DeepWiki, GitHub Copilot

Additional review context

  • The current PR is #187, open against MCP_harden, with 7 changed files and +164/-31. Its listed targeted tests passed locally, but CI was still unchecked in the PR description.

  • OLIVE_JOB_SETUP_STUB now accepts only finite positive timeout values; invalid, zero, or negative values fall back to 120 seconds. The loop polls every 200 ms, marks the job failed, logs the timeout, cleans artifacts, and finalizes it.

  • The stub timeout path has no dedicated assertion in the changed tests; the idempotency tests instead track and drain detached setup tasks.

  • Lock reclamation now:

    • Reclaims finite dead-PID locks immediately.
    • Gives malformed/empty locks a grace period of max(1000, pollMs * 4) based on statSync().mtimeMs.
    • Sleeps normally if unlink fails, avoiding a reclaim busy-spin.
    • Uses non-recursive rmdirSync for empty directory cleanup.
  • The new lock tests cover ownership-preserving release and rmdirSync, but do not cover the newly added malformed-lock grace-period behavior.

  • Earlier review tools identified the empty-lock race caused by openSync("wx") creating the file before writing its PID. Those review threads are now marked outdated/resolved after the grace-period fix.

  • At retrieval time, validate, security, python-tests, docker-build, olive-pass-availability, and Greptile checks were still running; only the auto-merge check had completed successfully.

  • DeepWiki could not provide repository context because neither the requested Babel-Player repository nor Olive-Studio was indexed.

🔇 Additional comments (11)
src/lib/__tests__/resolvePython.test.ts (1)

60-79: LGTM!

scripts/studioConfigSmokeLock.mjs (3)

11-12: LGTM!

Also applies to: 39-39, 55-55


106-114: LGTM!


131-136: LGTM!

src/lib/__tests__/studioConfigSmokeLock.test.ts (2)

56-61: LGTM!


111-116: LGTM!

scripts/studioConfigSnapshot.mjs (1)

6-13: LGTM!

Also applies to: 125-125

scripts/mcp-agent-smoke.mjs (2)

612-612: LGTM!


609-613: 📐 Maintainability & Code Quality

Verify required CI checks before merge.

The PR reports that CI is unchecked. Run linting and all typecheck-related CI checks before merge.

As per coding guidelines: “Run linting and ensure typecheck-related CI checks pass before submitting changes.”

Sources: Coding guidelines, MCP tools

src/server/services/olive/jobRunner.idempotency.test.ts (2)

5-20: LGTM!

Also applies to: 40-45


221-234: LGTM!

Comment thread scripts/studioConfigSmokeLock.mjs Outdated
Comment thread src/server/services/olive/jobRunner.idempotency.test.ts Outdated
Comment thread src/server/services/olive/jobRunner.ts
Write the owner PID to a temp file, then hard-link it to the lock path so waiters never see an empty final lock, with exclusive wx fallback when links are unsupported and grace reclaim for aged empty bodies.

Co-authored-by: Cursor <cursoragent@cursor.com>
@greptile-apps
greptile-apps Bot dismissed their stale review August 8, 2026 08:20

Dismissed because a newer commit was pushed; Greptile will re-review the current head.

greptile-apps[bot]
greptile-apps Bot previously approved these changes Aug 8, 2026
Base automatically changed from MCP_harden to main August 8, 2026 08:28
Comment thread src/lib/__tests__/studioConfigSmokeLock.test.ts Outdated
@greptile-apps
greptile-apps Bot dismissed their stale review August 8, 2026 08:30

Dismissed because a newer commit was pushed; Greptile will re-review the current head.

greptile-apps[bot]
greptile-apps Bot previously approved these changes Aug 8, 2026
Require exact `<pid>\n` lock bodies before reclaim/release, cancel and await finishedAt for tracked jobs in idempotency teardown, and cover stub setup timeout fallback with fake timers.

Co-authored-by: Cursor <cursoragent@cursor.com>
@greptile-apps
greptile-apps Bot dismissed their stale review August 8, 2026 08:32

Dismissed because a newer commit was pushed; Greptile will re-review the current head.

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/studioConfigSmokeLock.mjs (1)

137-151: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Partial numeric PID bodies still bypass the grace window.

Line 138 uses Number.parseInt, which accepts a numeric prefix. A torn body "12345\n" read as "12" parses to a finite 12. malformed is then false, so the grace window at lines 144-151 never applies, and a dead PID 12 reclaims the lock immediately.

publishLockFile no longer produces torn bodies, so this now applies to legacy locks and external writers only. The classification is still wrong. Require a complete numeric body before you trust the PID.

🛡️ Proposed fix for the classification
         const current = read(lockPath, "utf8");
-        const holder = Number.parseInt(String(current).trim().split(/\r?\n/)[0] ?? "", 10);
+        const firstLine = String(current).trim().split(/\r?\n/)[0] ?? "";
+        // Require a complete numeric body. A torn write such as "12" from
+        // "12345\n" must not be trusted as a finished PID.
+        const complete = /^\d+$/.test(firstLine) && String(current).endsWith("\n");
+        const holder = complete ? Number.parseInt(firstLine, 10) : Number.NaN;
         // Fresh empty/malformed bodies can mean a concurrent publisher has not
         // finished yet (or a crash left an empty legacy lock). Only reclaim
         // after publishGraceMs. Finite dead PIDs reclaim immediately.
         const malformed = !Number.isFinite(holder);

Note: release() at line 126 uses the same prefix parse. Keep both parsers in one shared helper so they cannot diverge.

🤖 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 `@scripts/studioConfigSmokeLock.mjs` around lines 137 - 151, Replace the
prefix-based PID parsing in the shared lock-PID parsing logic used by both the
classification flow and release() with complete-body validation, so partial or
otherwise malformed numeric bodies are treated as malformed and remain subject
to publishGraceMs. Introduce or reuse one helper for both call sites, preserving
immediate reclamation only for fully parsed finite dead PIDs.
🤖 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 `@src/lib/__tests__/studioConfigSmokeLock.test.ts`:
- Around line 36-41: Add a test alongside the existing studio lock tests that
configures unlinkSync to throw an EPERM error for the lock path, injects a
mocked sleep function, and invokes acquireStudioConfigSmokeLock with the
existing filesystem and polling options until acquisition fails. Assert the
operation rejects and sleep is called, covering the failed-unlink polling path.
- Around line 132-151: Update the aged-lock test around
acquireStudioConfigSmokeLock so its mocked clock advances during sleep, matching
the grace-window test pattern. Replace the constant now value with mutable time
and have the sleep stub advance it, while preserving the initial timestamp and
reclaim scenario so a regression reaches the deadline and rejects instead of
hanging.
- Around line 156-186: Update the “falls back to exclusive write when hardlinks
are unsupported” test to create its filesystem mocks through makeFs, overriding
only linkSync to throw ENOTSUP. Preserve the existing lock assertions, and add
the same temporary-residue cleanup assertion used by the link-path test around
line 62.

---

Outside diff comments:
In `@scripts/studioConfigSmokeLock.mjs`:
- Around line 137-151: Replace the prefix-based PID parsing in the shared
lock-PID parsing logic used by both the classification flow and release() with
complete-body validation, so partial or otherwise malformed numeric bodies are
treated as malformed and remain subject to publishGraceMs. Introduce or reuse
one helper for both call sites, preserving immediate reclamation only for fully
parsed finite dead PIDs.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b8262d66-3abe-446c-a52f-a7d4ddffb83d

📥 Commits

Reviewing files that changed from the base of the PR and between ffd9d35 and 89e08ab.

📒 Files selected for processing (2)
  • scripts/studioConfigSmokeLock.mjs
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • tonythethompson/QuickShell (manual)
  • tonythethompson/numan (manual)
  • tonythethompson/dependency-chain-substrate (manual)
📜 Review details
⏰ Context from checks skipped due to timeout. (6)
  • GitHub Check: olive-pass-availability
  • GitHub Check: validate
  • GitHub Check: security
  • GitHub Check: python-tests
  • GitHub Check: docker-build
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (6)
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

src/**/*.{ts,tsx}: Match existing naming, file layout, and TypeScript patterns in src/.
Put shared recipe logic in src/lib/, especially pipelineValidation.ts, oliveRecipeBuilder.ts, and recipePipeline.ts.

src/**/*.{ts,tsx}: Keep validation logic in shared libraries rather than duplicating it in UI cell helpers or inspectors.
Split the InputEnvironmentPanel, IHVIntegrationPanel, and ExecutionWorkspace mega-panels into feature folders with colocated hooks and tests.
Keep server and UI AI provider catalogs synchronized, preferably through a shared provider ID list or synchronization test; register new providers in both catalogs.
Add test coverage for recipe-graph/, passCatalog, oliveRecipeHub, jobHistoryStore, and vramEstimate, and strengthen component tests for the large panels.

src/**/*.{ts,tsx}: All UI state mutations must go through commitUiStateUpdate in src/lib/pipelineValidation.ts so invariants are enforced; use usePipelineState() for state access and replaceState for recipe imports or preset loads.
Avoid export * barrel imports; import directly from the actual module file to preserve Vite tree-shaking and component-test isolation.

Follow the React performance guidance in docs/REACT_BEST_PRACTICES.md, especially eliminating waterfalls, avoiding barrel imports, and deferring non-critical third-party libraries.

Files:

  • src/lib/__tests__/studioConfigSmokeLock.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx,js,jsx}: Place imports at the top of modules; use inline imports only for a documented circular dependency.
Run linting and ensure typecheck-related CI checks pass before submitting changes.
For UI or server changes, manually smoke-test development startup, recipe loading/building, validation banners, and live execution when execution behavior is touched.

Use the project's React 19, Vite, Express, and Tauri 2 stack conventions for frontend and server TypeScript/JavaScript code.

Files:

  • src/lib/__tests__/studioConfigSmokeLock.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

When working with React 19 or Vite 8 APIs, consult current Context7 documentation instead of assuming conventions from earlier major versions.

Files:

  • src/lib/__tests__/studioConfigSmokeLock.test.ts
src/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use the unit-test configuration for src/lib/ unit tests and keep unit tests compatible with Vitest.

Files:

  • src/lib/__tests__/studioConfigSmokeLock.test.ts
src/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not trigger real Olive optimization runs in tests or CI; use CPU-only recipe building, JSON export, and validation flows instead.

Files:

  • src/lib/__tests__/studioConfigSmokeLock.test.ts
**/*

📄 CodeRabbit inference engine (AGENTS.md)

Do not implement the listed backburner AI providers unless explicitly requested; prefer Custom or OpenAI-compatible providers for OpenAI-shaped hosts.

Files:

  • src/lib/__tests__/studioConfigSmokeLock.test.ts
  • scripts/studioConfigSmokeLock.mjs
🔍 Remote MCP DeepWiki, GitHub Copilot

Additional review context

  • Issue #186 explicitly targets hardening Studio config cleanup, MCP smoke locking, job policy, and idempotency behavior.
  • The lock implementation atomically publishes PID contents via hard-linking, with exclusive-write fallback; malformed locks use statSync().mtimeMs and a grace period, while dead finite-PID locks are reclaimed immediately.
  • resetJobRegistry() cancels active setup jobs, terminates child processes, cleans artifacts, detaches listeners, stops metrics timers, and clears idempotency indexes—relevant to the detached setup-test teardown.
  • Idempotency semantics explicitly allow a keyed submission to adopt an active fingerprint-only MCP job, while distinct keyed jobs remain separate; failed/cancelled jobs are retryable.
  • Current PR checks are not complete: validate, security, Python tests, Docker build, Olive pass availability, and Greptile remain in progress; CodeFactor and auto-merge checks succeeded.
  • DeepWiki could not provide repository context because tonythethompson/Olive-Studio is not indexed.
🔇 Additional comments (8)
scripts/studioConfigSmokeLock.mjs (5)

6-8: LGTM!


32-67: LGTM!


110-132: LGTM!


152-166: LGTM!


82-88: 📐 Maintainability & Code Quality

All injected dependencies are declared in the deps JSDoc.

src/lib/__tests__/studioConfigSmokeLock.test.ts (3)

75-93: LGTM!


95-130: LGTM!


44-63: 📐 Maintainability & Code Quality

Test already covers the release behavior described by the name.

The test calls lock.release() for both a foreign PID and an owned PID, then asserts that only the owned lock is cleared there.

Comment thread src/lib/__tests__/studioConfigSmokeLock.test.ts
Comment thread src/lib/__tests__/studioConfigSmokeLock.test.ts Outdated
Comment thread src/lib/__tests__/studioConfigSmokeLock.test.ts Outdated
Comment thread scripts/studioConfigSmokeLock.mjs Outdated
tonythethompson and others added 2 commits August 8, 2026 01:34
Assert acquisition keeps polling when a reclaimable lock cannot be unlinked, so failed reclaim cannot busy-spin without sleep.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drive the hardlink-unsupported path through the shared store mocks and assert temp residue is cleaned after exclusive write fallback.

Co-authored-by: Cursor <cursoragent@cursor.com>
tonythethompson and others added 2 commits August 8, 2026 01:51
Clear lockPath.reclaim when its owner is dead or the body is aged incomplete so a crashed reclaimer cannot pin later smoke runs until manual cleanup.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sleep only until the stub timeout deadline on the final poll, cancel tracked jobs and advance one fake-timer poll before finalize fallback in stub tests, and assert 500ms timeouts fire after +1ms past 499ms.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread scripts/studioConfigSmokeLock.mjs Outdated
Only dead complete reclaim PIDs may clear the gate, and reclaimers must still own lockPath.reclaim immediately before unlinking the main lock or releasing the mutex.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread scripts/studioConfigSmokeLock.mjs Outdated
Empty or malformed lockPath.reclaim markers left by a crash mid-write are cleared once publishGraceMs elapses, while fresh incomplete markers and live complete PIDs stay protected and gate ownership is still re-verified.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread scripts/studioConfigSmokeLock.mjs Outdated
Make lockPath.reclaim appear with a complete PID body atomically so age-clear of incomplete orphans cannot strip a live reclaim publisher mid-gate.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread scripts/studioConfigSmokeLock.mjs
Avoid streaming wx writes to the final lock pathname so a delayed reclaim
gate publish cannot expose an incomplete body that peers age-clear.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread scripts/studioConfigSmokeLock.mjs Outdated
Satisfy tsc --noEmit in CI lint: the vitest mock used string paths while
acquireStudioConfigSmokeLock expects Node PathLike for copyFileSync.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread scripts/studioConfigSmokeLock.mjs Outdated
tonythethompson and others added 2 commits August 8, 2026 02:28
Avoid npx+cmd shell spawning so --args JSON keeps its quotes; cmd was
stripping them and breaking submit_optimization_job on Windows.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread scripts/studioConfigSmokeLock.mjs Outdated
copyFileSync can expose a partial body at the final path; rename moves an
already-complete temp so reclaimers never age-clear a live publish mid-copy.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread scripts/studioConfigSmokeLock.mjs Outdated
When hardlinks fail, keep Windows rename (exclusive) but use exclusive wx
writes on POSIX so rename cannot replace another process's lock file.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread scripts/studioConfigSmokeLock.mjs

@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: 6

🤖 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/mcp-agent-smoke.mjs`:
- Around line 254-265: Extract the shared CLI resolution, config-augmented
argument construction, and banner logging currently duplicated in
runMcporterSync and callToolAsync into a reusable helper. Update both functions
to call that helper, preserving the existing arguments, config flag, and log
format while ensuring future changes apply consistently.
- Around line 68-110: Update ensureMcporterCli to avoid the predictable shared
tmpdir prefix: create a unique per-run installation directory with mkdtempSync,
or use a trusted repository-local cache with appropriate ownership validation.
Ensure concurrent runs cannot observe a partially installed CLI, and preserve
the existing install verification and mcporterCliPath caching behavior.

In `@scripts/studioConfigSmokeLock.mjs`:
- Around line 211-229: Update tryAcquireReclaimGate and the corresponding guard
at the later call site to reflect exception-based control flow: remove the
unconditional boolean return and eliminate both constant-result checks, allowing
publishLockFile exceptions to propagate while preserving the existing success
path.
- Around line 98-106: The fallback in scripts/studioConfigSmokeLock.mjs at lines
98-106 must use exclusive write semantics on every platform: remove the
Windows-specific rename path or guard renameSync with an existence check, while
preserving the write(lockPath, body, { flag: "wx" }) behavior. In
src/lib/__tests__/studioConfigSmokeLock.test.ts at lines 30-42, update the
filesystem mock so rename overwrites an existing destination and adjust the
Windows fallback test to verify a live peer lock is not stolen.

In `@src/lib/__tests__/studioConfigSmokeLock.test.ts`:
- Around line 237-264: Update the aged-incomplete reclaim test around
acquireStudioConfigSmokeLock so the mocked clock advances whenever sleep is
called, allowing timeout-based loops to terminate if acquisition regresses. Keep
sleep asynchronous while advancing the value returned by now beyond the
deadline, and preserve the existing recovery assertions.

In `@src/server/services/olive/jobRunner.stubSetup.test.ts`:
- Around line 152-159: Update the pending-settlement check in the test around
pending.then so both fulfillment and rejection callbacks set settled = true.
Attach a rejection handler to the derived promise as well, preventing an
unhandled rejection while preserving the assertion that the request remains
unsettled before the deadline.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f9279bf2-339c-4604-9df4-f9bd5a951d72

📥 Commits

Reviewing files that changed from the base of the PR and between 70f8a8f and de08c25.

📒 Files selected for processing (6)
  • scripts/mcp-agent-smoke.mjs
  • scripts/studioConfigSmokeLock.mjs
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
  • src/server/services/olive/jobRunner.stubSetup.test.ts
  • src/server/services/olive/jobRunner.ts
  • vite.config.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • tonythethompson/QuickShell (manual)
  • tonythethompson/numan (manual)
  • tonythethompson/dependency-chain-substrate (manual)
📜 Review details
⏰ Context from checks skipped due to timeout. (6)
  • GitHub Check: Greptile Review
  • GitHub Check: security
  • GitHub Check: docker-build
  • GitHub Check: olive-pass-availability
  • GitHub Check: python-tests
  • GitHub Check: validate
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx,js,jsx}: Place imports at the top of modules; use inline imports only for a documented circular dependency.
Run linting and ensure typecheck-related CI checks pass before submitting changes.
For UI or server changes, manually smoke-test development startup, recipe loading/building, validation banners, and live execution when execution behavior is touched.

Use the project's React 19, Vite, Express, and Tauri 2 stack conventions for frontend and server TypeScript/JavaScript code.

Files:

  • vite.config.ts
  • src/server/services/olive/jobRunner.stubSetup.test.ts
  • src/server/services/olive/jobRunner.ts
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

When working with React 19 or Vite 8 APIs, consult current Context7 documentation instead of assuming conventions from earlier major versions.

Files:

  • vite.config.ts
  • src/server/services/olive/jobRunner.stubSetup.test.ts
  • src/server/services/olive/jobRunner.ts
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
**/*

📄 CodeRabbit inference engine (AGENTS.md)

Do not implement the listed backburner AI providers unless explicitly requested; prefer Custom or OpenAI-compatible providers for OpenAI-shaped hosts.

Files:

  • vite.config.ts
  • src/server/services/olive/jobRunner.stubSetup.test.ts
  • src/server/services/olive/jobRunner.ts
  • scripts/mcp-agent-smoke.mjs
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
  • scripts/studioConfigSmokeLock.mjs
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

src/**/*.{ts,tsx}: Match existing naming, file layout, and TypeScript patterns in src/.
Put shared recipe logic in src/lib/, especially pipelineValidation.ts, oliveRecipeBuilder.ts, and recipePipeline.ts.

src/**/*.{ts,tsx}: Keep validation logic in shared libraries rather than duplicating it in UI cell helpers or inspectors.
Split the InputEnvironmentPanel, IHVIntegrationPanel, and ExecutionWorkspace mega-panels into feature folders with colocated hooks and tests.
Keep server and UI AI provider catalogs synchronized, preferably through a shared provider ID list or synchronization test; register new providers in both catalogs.
Add test coverage for recipe-graph/, passCatalog, oliveRecipeHub, jobHistoryStore, and vramEstimate, and strengthen component tests for the large panels.

src/**/*.{ts,tsx}: All UI state mutations must go through commitUiStateUpdate in src/lib/pipelineValidation.ts so invariants are enforced; use usePipelineState() for state access and replaceState for recipe imports or preset loads.
Avoid export * barrel imports; import directly from the actual module file to preserve Vite tree-shaking and component-test isolation.

Follow the React performance guidance in docs/REACT_BEST_PRACTICES.md, especially eliminating waterfalls, avoiding barrel imports, and deferring non-critical third-party libraries.

Files:

  • src/server/services/olive/jobRunner.stubSetup.test.ts
  • src/server/services/olive/jobRunner.ts
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
src/server/services/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Keep server-side business logic in services, including AI providers, Olive job/virtual-environment handling, and related service modules.

Files:

  • src/server/services/olive/jobRunner.stubSetup.test.ts
  • src/server/services/olive/jobRunner.ts
src/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use the unit-test configuration for src/lib/ unit tests and keep unit tests compatible with Vitest.

Files:

  • src/server/services/olive/jobRunner.stubSetup.test.ts
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
src/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not trigger real Olive optimization runs in tests or CI; use CPU-only recipe building, JSON export, and validation flows instead.

Files:

  • src/server/services/olive/jobRunner.stubSetup.test.ts
  • src/lib/__tests__/studioConfigSmokeLock.test.ts
🪛 ast-grep (0.45.0)
src/lib/__tests__/studioConfigSmokeLock.test.ts

[warning] 281-281: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.writeFileSync(p, body, opts as never)
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(detect-non-literal-fs-filename-typescript)

🔍 Remote MCP DeepWiki, GitHub Copilot

Additional review context

  • Issue #186 explicitly targets MCP smoke hardening and Olive job policy/idempotency cleanup.
  • Related PR #28 established the surrounding lifecycle behavior: setup cancellation, registry cleanup, SSE terminal handling, and artifact reclamation.
  • Related PR #171 introduced the MCP agent smoke path and job-control flow; this PR substantially extends that smoke with policy denial, concurrent idempotent submissions, cancellation, and cleanup checks.
  • The current implementation’s documented contract is:
    • MCP jobs are the only jobs indexed for idempotency.
    • Same keys reuse jobs; fingerprint-only jobs can later be adopted by keyed submissions.
    • Distinct keys create distinct jobs.
    • Failed/cancelled jobs are retryable.
    • UI jobs must not be exposed through agent routes or absorbed by MCP fingerprint reuse.
  • Agent capability defaults are conservative: inspection is enabled, submission/cancellation are disabled unless policy or environment overrides enable them. Agent routes are loopback-gated, and artifact paths are redacted unless explicitly opted into.
  • The smoke test deliberately uses OLIVE_JOB_SETUP_STUB=1, so it exercises policy, status, cancellation, and idempotency without spawning a real Olive optimization.
  • DeepWiki could not provide repository architecture context because tonythethompson/Olive-Studio is not indexed.
🔇 Additional comments (14)
vite.config.ts (1)

8-8: LGTM!

scripts/studioConfigSmokeLock.mjs (4)

56-64: LGTM!


146-169: LGTM!


247-265: LGTM!


289-304: LGTM!

Also applies to: 369-388

src/lib/__tests__/studioConfigSmokeLock.test.ts (4)

145-201: LGTM!


203-235: LGTM!


266-311: LGTM!


516-567: LGTM!

scripts/mcp-agent-smoke.mjs (2)

116-134: LGTM!


74-74: 🩺 Stability & Availability

No change needed for the mcporter CLI path. The pinned mcporter@0.13.0 package declares bin.mcporter as dist/cli.js, so this hard-coded path matches the package entry map.

			> Likely an incorrect or invalid review comment.
src/server/services/olive/jobRunner.ts (2)

316-346: Complete the required validation before merge.

The PR context reports CI as unchecked. Run lint, typecheck-related checks, and the required server smoke tests before submission.

As per coding guidelines, “Run linting and ensure typecheck-related CI checks pass before submitting changes.” As per coding guidelines, “For UI or server changes, manually smoke-test development startup, recipe loading/building, validation banners, and live execution when execution behavior is touched.”

Source: Coding guidelines


316-346: LGTM!

src/server/services/olive/jobRunner.stubSetup.test.ts (1)

55-66: LGTM!

Also applies to: 97-97, 117-123, 125-151, 160-172

Comment thread scripts/mcp-agent-smoke.mjs
Comment thread scripts/mcp-agent-smoke.mjs Outdated
Comment thread scripts/studioConfigSmokeLock.mjs Outdated
Comment thread scripts/studioConfigSmokeLock.mjs Outdated
Comment thread src/lib/__tests__/studioConfigSmokeLock.test.ts Outdated
Comment thread src/server/services/olive/jobRunner.stubSetup.test.ts
Use per-run mkdtemp for mcporter install, DRY invocation helpers, exclusive
wx on all hardlink-fail platforms, void reclaim-gate helpers, and tighten
related unit tests (clock advance, rejection-safe settled check).

Co-authored-by: Cursor <cursoragent@cursor.com>
A paused wx publisher can leave a partial final-path body past any grace
window; age-clearing it lets a peer steal exclusivity. Only reclaim complete
dead PIDs; smokers wait out timeoutMs for incomplete leftovers.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tonythethompson
tonythethompson merged commit 02fe68f into main Aug 8, 2026
12 checks passed
@tonythethompson
tonythethompson deleted the fix/mcp-harden-inline-followups branch August 8, 2026 11:05
@linear-code

linear-code Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

OLI-73

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