feat(mcp): register plan-DAG tools + local scorer in packages/loopover-mcp - #6490
feat(mcp): register plan-DAG tools + local scorer in packages/loopover-mcp#6490galuis116 wants to merge 3 commits into
Conversation
…r-mcp The miner-auto-dev profile's recommendedTools listed loopover_run_local_scorer/loopover_build_plan/loopover_plan_status/ loopover_record_step_result/loopover_predict_gate, but none were registered as local stdio tools -- only the string literals existed. - loopover_run_local_scorer: computeLocalScorerTokens imported directly from @loopover/engine (already exported), same pattern as the existing loopover_check_slop_risk/loopover_lint_pr_text pure in-process tools. - loopover_build_plan / loopover_plan_status / loopover_record_step_result: the plan-DAG state machine (src/services/plan-dag.ts) was never extracted to @loopover/engine's export map, so it's hand-duplicated here following the same MAINTAIN_ACTION_CLASSES/AUTONOMY_LEVELS precedent this file already uses for exactly this situation. Pure + stateless -- no DB, no network access. - loopover_predict_gate: cannot be pure-local (needs live repo/issue/ PR/manifest data only the server can assemble). Proxies to the existing POST /v1/local/branch-analysis route, which already computes predictedGate via buildPredictedGateVerdict -- the same logic the remote tool uses -- and returns it as a top-level field. No new backend endpoint needed. Metadata-only input (no git required), unlike the branch-analysis tools that shell out to git. Along the way, found and fixed a stale, non-symlinked packages/loopover-mcp/node_modules/@loopover/engine directory shadowing the correct root-level workspace symlink, which was breaking the CLI's own subpath imports (unrelated to this change -- confirmed pre-existing via git stash). Added test/unit/mcp-cli-plan-scorer-tools.test.ts (15 tests) covering all 5 tools' success + rejection paths, and a localBranchAnalysisStatus fixture-server option + predictedGate field on localBranchAnalysisFixture in test/unit/support/mcp-cli-harness.ts to test loopover_predict_gate's API-failure path, mirroring the existing intakeStatus pattern. Closes JSONbored#6150
JSONbored#6150 registered loopover_run_local_scorer, loopover_build_plan, loopover_plan_status, loopover_record_step_result, and loopover_predict_gate, taking the total loopover_-prefixed stdio tool count from 55 to 60. mcp-tool-rename-aliases.test.ts hardcodes this count as a regression guard against silent alias/registration drift; update it to match.
Both tests create a fake repo literally named "JSONbored/gittensory"
(the default self-repo identity test/helpers/d1.ts's createTestEnv()
uses) but never mock fetch, so the repo-settings resolver's manifest
loader fell through to a REAL network request to the real, live
JSONbored/gittensory GitHub repo's .loopover.yml. That real manifest
now carries autonomy: { merge: auto, ... } (JSONbored#773),
so the live-fetched content silently overrode the DB-only settings
these two tests exist to verify -- unrelated to and unaffected by this
branch's own diff, confirmed by reproducing the identical failure via
`git stash` and again in a clean upstream/main worktree.
Mock fetch to 404 (matching this file's established pattern for
network-adjacent tests) and keep the LOOPOVER_DRIFT_ISSUE_REPO
override the sibling tests in this file already use, so the fixture
repo name no longer collides with the real self-repo's live config or
its bundled fallback.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
❌ 1 Tests Failed:
View the top 1 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
|
Caution 🛑 LoopOver review result - reject/close recommendedReview updated: 2026-07-16 11:11:38 UTC
Review summary Blockers
Nits — 5 non-blocking
Why this is blocked
📋 Copy for AI agents — paste into your coding agentCI checks failing
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
|
LoopOver is closing this pull request on the maintainer's behalf (CI is failing (validate, validate-code, validate-tests (6), validate-tests (2), validate-tests (5)); AI reviewers agree on a likely critical defect: test/unit/backfill.test.ts's LOOPOVER_DRIFT_ISSUE_REPO override + vi.stubGlobal("fetch", …) changes are unrelated to the stated #6150 scope (MCP tool registration) and are not mentioned anywhere in the PR description — this is undisclosed scope creep bundled into a feature PR and should be split into its own PR tied to its own issue.). This is an automated maintenance action — to pursue this change, please open a new pull request with the issues resolved. Closed PRs may be analyzed later to improve review accuracy, but they are not automatically reopened or re-reviewed. |
Closes #6150
Summary
src/mcp/server.tsregistersloopover_run_local_scorer,loopover_build_plan,loopover_plan_status,loopover_record_step_result, andloopover_predict_gateon the remote server, andpackages/loopover-mcp/bin/loopover-mcp.js'sminer-auto-devprofile listed all five inrecommendedTools— but none were actually registered as local stdio tools, only the string literals existed. A contributor relying on the local server for this profile couldn't invoke any of them.loopover_run_local_scorer:computeLocalScorerTokensimported directly from@loopover/engine(already exported at the package root) — same pattern as the existingloopover_check_slop_risk/loopover_lint_pr_textpure in-process tools. Pure, deterministic, no repo/network access.loopover_build_plan/loopover_plan_status/loopover_record_step_result: the plan-DAG state machine (src/services/plan-dag.ts) was never extracted to@loopover/engine's export map, so there's nothing to import — hand-duplicated here following the exact same precedent this file already uses forMAINTAIN_ACTION_CLASSES/AUTONOMY_LEVELSwhen the published package's export map doesn't cover something. Pure + stateless (no DB, no network) — the harness runs each step and callsloopover_record_step_resultto report it back.loopover_predict_gate: cannot be pure-local — it needs live repo/issue/PR/manifest data only the server can assemble (env.DB-backed). Proxies to the existingPOST /v1/local/branch-analysisroute, which already computespredictedGateviabuildPredictedGateVerdict(the identical logic the remote tool uses) and returns it as a top-level response field — no new backend endpoint needed. Uses a metadata-only input shape (no git/workspace context), unlike the sibling branch-analysis tools that shell out to git.Note on re-open
This resubmits #6462, which was auto-closed by red CI. That failure was two pre-existing, unrelated regressions in
mainat the time — not caused by this diff — both now fixed as part of this branch (see below) and rebased onto currentmain:test/unit/mcp-tool-rename-aliases.test.tshardcodes the exact count of registeredloopover_-prefixed stdio tools as a regression guard; this PR's 5 new tools take that count from 55 to 60, so the guard's three hardcoded assertions needed updating (own diff's consequence — this part was already in feat(mcp): register plan-DAG tools + local scorer in packages/loopover-mcp #6462).test/unit/backfill.test.tshad two tests that create a fixture repo literally namedJSONbored/gittensory(the default self-repo identitycreateTestEnv()uses) without mockingfetch. A very recent, unrelatedmaincommit (feat(agent): autonomy-levels framework (observe→…→auto) #773) gave the realJSONbored/gittensoryrepo's live.loopover.ymlgenuineautonomy: { merge: auto, ... }config — so these two tests' un-mockedfetchcalls now hit that real, live manifest over the network and inherit its autonomy instead of the DB-only settings they're meant to test. Confirmed unrelated to this PR by reproducing the identical failure in an isolatedgit worktreeof cleanupstream/main. Fixed by mockingfetch(matching this file's own established pattern) and scoping the fixture's self-repo override away from the real repo name, same as several sibling tests in the same file already do.Incidental fix
While testing, found
packages/loopover-mcp/node_modules/@loopover/enginewas a stale, non-symlinked directory shadowing the correct root-level workspace symlink, breaking the CLI's own@loopover/engine/signals/slopetc. subpath imports — confirmed pre-existing and unrelated to this change viagit stashcomparison against a clean checkout. Removed it; the root symlink resolves correctly.Scope
type(scope): short summaryConventional Commit format.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Validation
git diff --checknpm run actionlintnpm run typecheck(root) — reliably OOMs on this shared sandbox regardless of what changed (reproduced repeatedly this session).packages/loopover-mcpis plain JS with its ownnpm run build(node --checkacross every lib/bin file) — ran it directly and it passes clean, and confirmed via direct execution thatloopover-mcp --helpandloopover-mcp tools --json(listing all 60 tools, count verified) both run without error.npm run test:coverage— not run repo-wide (same OOM risk). Ran the full MCP CLI test suite (30 files, 230 tests) plusmcp-tool-rename-aliases.test.tsandbackfill.test.tsin full (137 tests) after rebasing onto currentmain— all passing.test/unit/mcp-cli-plan-scorer-tools.test.ts(15 new tests) covers registration + success/rejection paths for all 5 tools, including the API-failure path forloopover_predict_gate.npm run test:workers— N/A, no Worker-facing code changed (this is the local CLI, notsrc/).npm run build:mcp/npm run test:mcp-pack— both run directly and pass clean.npm run ui:openapi:check/ui:lint/ui:typecheck/ui:build— N/A, noapps/loopover-uichanges.npm audit --audit-level=moderate— 0 vulnerabilities.localBranchAnalysisStatusfixture-server option added totest/unit/support/mcp-cli-harness.ts, mirroring the existingintakeStatuspattern.If any required check was skipped, explain why:
npm run typecheck/npm run test:coverage: reliably OOMs on this shared sandbox under memory pressure from concurrent sessions, independent of the diff. Substituted withpackages/loopover-mcp's own build (clean), direct CLI execution confirming all 5 tools register and respond correctly, and the broader test suites listed above, all passing.Safety
/v1/local/branch-analysisroute).UI Evidencesection below with screenshots. — N/A, no visible UI change (CLI tool registration only).CHANGELOG.mduntouched.Notes
loopover_build_plan/loopover_plan_status/loopover_record_step_result's hand-duplicated plan-DAG logic inloopover-mcp.jsis a deliberate architectural choice, not an oversight: this file already documents (in theMAINTAIN_ACTION_CLASSES/AUTONOMY_LEVELScomment block) that it resolves@loopover/enginethrough the published package, whose export map exposes only a curated set of subpaths — widening that public API is a separate, larger decision than "register these 5 tools locally," so this follows the existing precedent rather than introducing a new one.