mcp(stdio): restore the CurrentBranchInput narrowing on the eight local-branch tools - #10241
mcp(stdio): restore the CurrentBranchInput narrowing on the eight local-branch tools#10241phamngocquy wants to merge 1 commit into
Conversation
…al-branch tools Fixes JSONbored#10034
|
Caution 🛑 LoopOver review result - fixes requiredReview updated: 2026-07-31 14:20:26 UTC
Review summary Nits — 6 non-blocking
CI 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. Decision record
🟩 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.
|
❌ 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 |
|
LoopOver is closing this pull request on the maintainer's behalf (CI is failing (validate, validate-tests)). 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. |
Summary
packages/loopover-contract/src/tools/local-branch.ts:106widens the current-branch family's contractinput, and makes two previously-optional fields required:
The doc directly above it, at
packages/loopover-contract/src/tools/local-branch.ts:101, states theintended split:
The stdio server never got that narrowing.
registerStdioTool(
packages/loopover-mcp/bin/loopover-mcp.ts:897) advertises and enforcesoverrides?.input ?? contract.inputat line 923, and none of the eight tools whose contract input isLocalBranchAnalysisInputpasses an override. Only five overrides exist in the whole file(
loopover-mcp.ts:1604,:1618,:1630,:1780,:1893), and none of them is one of these:loopover_preflight_current_branchlocal-branch.ts:142loopover-mcp.ts:1661z.infer<typeof CurrentBranchInput>loopover_preview_current_branch_scorelocal-branch.ts:155loopover-mcp.ts:1679z.infer<typeof CurrentBranchInput>loopover_rank_local_next_actionslocal-branch.ts:168loopover-mcp.ts:1693z.infer<typeof CurrentBranchInput>loopover_explain_local_blockerslocal-branch.ts:181loopover-mcp.ts:1701z.infer<typeof CurrentBranchInput>loopover_remediation_planlocal-branch.ts:194loopover-mcp.ts:1717z.infer<typeof CurrentBranchInput>loopover_prepare_pr_packetlocal-branch.ts:207loopover-mcp.ts:1727z.infer<typeof CurrentBranchInput>loopover_draft_pr_bodylocal-branch.ts:251(DraftPrBodyInput = LocalBranchAnalysisInput.extend(...))loopover-mcp.ts:1738z.infer<typeof DraftPrBodyInput>loopover_agent_prepare_pr_packetlocal-branch.ts:222loopover-mcp.ts:1822z.infer<typeof CurrentBranchInput>This is a behaviour regression, not a latent inconsistency. Before the widening,
preflightCurrentBranchTool.inputwasCurrentBranchInput— verifiable withgit show c3b9a9b1f^:packages/loopover-contract/src/tools/local-branch.ts(line 99:input: CurrentBranchInput).CurrentBranchInput(local-branch.ts:70) makes both fields optional precisely because"both servers resolve it themselves -- the stdio server from its persisted session (or
LOOPOVER_LOGIN)".What breaks in practice:
loopover_preflight_current_branchwith{}— the ordinary "check the branchI am on" call, and the one the CLI's own guidance recommends at
loopover-mcp.ts:432and:453— is nowrejected by the MCP SDK with a
-32602for missingloginandrepoFullName, on a server whose handlerresolves both from the checkout and the active session and does not need either.
Nothing catches it.
checkInputNarrowing(
scripts/lib/validate-mcp/invariants.ts) only fails when the ADVERTISED input requires something thecontract does not — here advertised and contract are the same object, so it passes. And
test/contract/validate-mcp.test.ts:100synthesizes smoke arguments from the advertised schema, so thevalidator dutifully supplies
loginandrepoFullNameand the call succeeds.Deliverables
packages/loopover-contract/src/tools/local-branch.ts, derived fromLocalBranchAnalysisInput, whose JSON Schemarequiredarray contains neitherloginnorrepoFullName, and aloopover_draft_pr_bodyvariant of it that still declaresformat.registerStdioToolcall sites inpackages/loopover-mcp/bin/loopover-mcp.ts(lines 1661, 1679, 1693, 1701, 1717, 1727, 1738, 1822) pass that narrowing as the
{ input }override.test/unit/contract-registry.test.tsasserting that, for each of the eight tool names,the narrowing's
requiredarray is a subset ofLocalBranchAnalysisInput's and excludesloginand
repoFullName, and that every property the narrowing declares also exists on the contractentry's input (so
checkInputNarrowingstill passes).test/unit/mcp-cli-current-branch-input.test.ts(new file) that connects anin-process client to the stdio
serverexport (theInMemoryTransportpattern already used intest/contract/validate-mcp.test.ts:150), readstools/list, and asserts that the advertisedinputSchema.requiredfor all eight tool names contains neitherloginnorrepoFullName—named for this bug (
REGRESSION: the stdio branch tools must not demand a login the CLI resolves itself).All Deliverables above are required in a single PR. A PR that satisfies only some of them — for
example fixing
loopover_preflight_current_branchalone and leaving the other seven, or adding thenarrowing to the contract without wiring it into the registrations — does not resolve this issue.
Test plan
This repo enforces 99%+ Codecov patch coverage, branch-counted.
vitest.config.ts'scoverage.includecoverspackages/loopover-contract/src/**/*.ts(line 108) andpackages/loopover-mcp/bin/**/*.ts(line 120), so both touched paths are measured and gated.The narrowing declarations are plain schema constants with no branches;
registerStdioTool'soverrides?.input ?? contract.input(loopover-mcp.ts:923) is an existing??whose BOTH arms must beexercised — the eight new override call sites cover the left arm, and at least one existing
override-free registration must still be asserted to cover the right arm.
Fixes #10034