@@ -193,6 +193,7 @@ import { SCENARIO_MAX_BRANCH_REF_CHARS, SCENARIO_MAX_LINKED_ISSUE_NUMBERS, SCENA
193193import { loadUpstreamStatus } from "../upstream/ruleset" ;
194194import {
195195 authoritativeGateOverride ,
196+ deleteLiveOverride ,
196197 listOverrideAudit ,
197198 loadOverride ,
198199 loadShadowOverride ,
@@ -242,6 +243,16 @@ const selftuneOverrideAuditShape = {
242243 limit : z . number ( ) . int ( ) . positive ( ) . optional ( ) ,
243244} ;
244245
246+ // (#8660) write-side mirror of DELETE /v1/repos/:owner/:repo/selftune/overrides. `confirm` is the required
247+ // confirmation field this destructive reset must carry, matching the sibling maintainer-mutation tools'
248+ // deliberate action params (loopover_set_agent_paused's `paused`, loopover_set_action_autonomy's action/level)
249+ // and the REST route's own "an optional body is treated as a confirmation of the override being cleared" intent.
250+ const clearSelftuneOverrideShape = {
251+ owner : z . string ( ) . min ( 1 ) ,
252+ repo : z . string ( ) . min ( 1 ) ,
253+ confirm : z . literal ( true ) ,
254+ } ;
255+
245256const windowOnlyShape = {
246257 windowDays : z . number ( ) . int ( ) . positive ( ) . optional ( ) ,
247258} ;
@@ -1100,6 +1111,12 @@ const selftuneOverrideAuditOutputSchema = {
11001111 audit : z . array ( z . unknown ( ) ) . optional ( ) ,
11011112} ;
11021113
1114+ // (#8660) confirmation shape for the write-side clear: mirrors the REST route's { repoFullName, cleared: true }.
1115+ const clearSelftuneOverrideOutputSchema = {
1116+ repoFullName : z . string ( ) . optional ( ) ,
1117+ cleared : z . boolean ( ) . optional ( ) ,
1118+ } ;
1119+
11031120// #5825 - maintainer-authenticated skipped-PR audit trail, mirroring GET /v1/app/skipped-pr-audit's
11041121// filters (all optional: a bare call returns the caller's own repo-scoped feed). No owner/repo shape
11051122// here on purpose: unlike ownerRepoShape tools this report can legitimately span every repo the caller
@@ -1978,6 +1995,7 @@ export const MCP_TOOL_CATEGORIES: Record<string, McpToolCategory> = {
19781995 loopover_get_outcome_calibration : "maintainer" ,
19791996 loopover_get_gate_precision : "maintainer" ,
19801997 loopover_get_selftune_override_audit : "maintainer" ,
1998+ loopover_clear_selftune_override : "maintainer" ,
19811999 loopover_get_skipped_pr_audit : "maintainer" ,
19822000 loopover_get_fleet_analytics : "maintainer" ,
19832001 loopover_get_recommendation_quality : "maintainer" ,
@@ -2255,6 +2273,20 @@ export class LoopoverMcp {
22552273 async ( input ) => this . toolResult ( await this . getSelftuneOverrideAudit ( input ) ) ,
22562274 ) ;
22572275
2276+ // (#8660) write-side counterpart to loopover_get_selftune_override_audit: the missing MCP mirror of
2277+ // DELETE /v1/repos/:owner/:repo/selftune/overrides. Maintainer-manage access required, same as the other
2278+ // maintainer-mutation tools (loopover_set_agent_paused/loopover_set_action_autonomy/loopover_decide_pending_action).
2279+ register (
2280+ "loopover_clear_selftune_override" ,
2281+ {
2282+ description :
2283+ "Clear a repo's LIVE self-tune gate override (the operator's \"reset to config base\" control), mirroring DELETE /v1/repos/:owner/:repo/selftune/overrides. Requires confirm:true; the automatic self-tune promote path is untouched. Maintainer access required." ,
2284+ inputSchema : clearSelftuneOverrideShape ,
2285+ outputSchema : clearSelftuneOverrideOutputSchema ,
2286+ } ,
2287+ async ( input ) => this . toolResult ( await this . clearSelftuneOverride ( input ) ) ,
2288+ ) ;
2289+
22582290 register (
22592291 "loopover_get_skipped_pr_audit" ,
22602292 {
@@ -4140,6 +4172,20 @@ export class LoopoverMcp {
41404172 } ;
41414173 }
41424174
4175+ // (#8660) MCP surface for DELETE /v1/repos/:owner/:repo/selftune/overrides. Uses the same maintainer-MANAGE
4176+ // gate as the sibling write tools (loopover_set_agent_paused/loopover_set_action_autonomy) — stricter than the
4177+ // audit tool's read gate — and calls the exact deleteLiveOverride the REST route already uses, returning the
4178+ // route's { repoFullName, cleared: true } shape. Branch-free: `confirm` is enforced by the input schema.
4179+ private async clearSelftuneOverride ( input : z . infer < z . ZodObject < typeof clearSelftuneOverrideShape > > ) : Promise < ToolPayload > {
4180+ const fullName = `${ input . owner } /${ input . repo } ` ;
4181+ await this . requireRepoManageAccess ( fullName ) ;
4182+ await deleteLiveOverride ( this . env as unknown as StorageEnv , fullName ) ;
4183+ return {
4184+ summary : `Cleared the live self-tune gate override for ${ fullName } .` ,
4185+ data : { repoFullName : fullName , cleared : true } ,
4186+ } ;
4187+ }
4188+
41434189 // #5825 - repo-scope resolution for the skipped-PR audit tool. Mirrors skippedPrAuditRepoScope in
41444190 // src/api/routes.ts (same underlying loadControlPanelRoleSummary/loadControlPanelAccessScope calls,
41454191 // same maintainer/owner/operator role gate, same "no filter -> caller's own scoped repos" fallback),
0 commit comments