srt_approve_repair
Approve or reject a pending SRT repair plan. Human approval is mandatory before repair execution.
Instructions
Approve or reject a pending SRT repair plan. Classification: MANDATORY — this is the human-in-the-loop gate. Repair plans CANNOT execute without explicit human approval. Pass action="approve" to approve or action="reject" to reject.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| incident_id | Yes | Incident ID with pending repair | |
| action | Yes | Approve or reject the repair plan | |
| approved_by | Yes | Human operator approving/rejecting | |
| reason | No | Reason for rejection (required if rejecting) |
Implementation Reference
- src/mcp/tools/srt.ts:851-975 (handler)The actual handler function for srt_approve_repair. Implements the MANDATORY human-in-the-loop gate: validates human approval (blocks system/auto/agent), checks incident and repair plan exist, handles approve/reject actions, records to forensic ledger, persists to PostgreSQL, and emits telemetry.
export function registerSRTApproveRepairTool(server: McpServer, engine: GovernanceEngine): void { server.tool( 'srt_approve_repair', 'Approve or reject a pending SRT repair plan. Classification: MANDATORY — this is the human-in-the-loop gate. Repair plans CANNOT execute without explicit human approval. Pass action="approve" to approve or action="reject" to reject.', { incident_id: z.string().describe('Incident ID with pending repair'), action: z.enum(['approve', 'reject']).describe('Approve or reject the repair plan'), approved_by: z.string().describe('Human operator approving/rejecting'), reason: z.string().optional().describe('Reason for rejection (required if rejecting)'), }, { title: 'Approve or Reject Repair', readOnlyHint: false, idempotentHint: false, destructiveHint: true, openWorldHint: false }, async (input) => { // MANDATORY gate enforcement (pre-ledger — no point recording blocked agents) if (!input.approved_by || input.approved_by === 'system' || input.approved_by === 'auto' || input.approved_by === 'agent') { return { content: [{ type: 'text' as const, text: JSON.stringify({ error: 'MANDATORY_GATE_VIOLATION', message: 'Repair approval requires a human operator. System/auto/agent approvals are BLOCKED.', gateType: 'REPAIR_APPROVAL', maiLevel: 'MANDATORY', }) }], isError: true }; } const incident = incidents.get(input.incident_id); if (!incident) { return { content: [{ type: 'text' as const, text: JSON.stringify({ error: 'INCIDENT_NOT_FOUND', incidentId: input.incident_id }) }], isError: true }; } if (!incident.repairPlan) { return { content: [{ type: 'text' as const, text: JSON.stringify({ error: 'NO_REPAIR_PLAN', message: 'Run srt_diagnose first' }) }], isError: true }; } if (incident.repairPlan.gateStatus !== 'PENDING') { return { content: [{ type: 'text' as const, text: JSON.stringify({ error: 'GATE_NOT_PENDING', currentStatus: incident.repairPlan.gateStatus }) }], isError: true }; } // ── Forensic ledger: begin MANDATORY entry ── const entry = engine.ledger.begin( `srt-repair-${input.action}`, MaiClassification.MANDATORY, GiaLayer.MCP, input.approved_by ); entry.addMetadata('incidentId', input.incident_id); entry.addMetadata('action', input.action); if (input.reason) entry.addMetadata('reason', input.reason); try { const ts = new Date().toISOString(); if (input.action === 'reject') { incident.repairPlan.gateStatus = 'REJECTED'; incident.repairPlan.approvedBy = input.approved_by; incident.repairPlan.approvedAt = ts; incident.status = 'DIAGNOSED'; incident.updatedAt = ts; persistIncident(incident); // Write-through: rejection const score = engine.scorer.scoreDefault(`srt-repair-${input.action}`); const completedEntry = entry.complete(score, { classification: MaiClassification.MANDATORY, confidence: 1.0, rationale: `SRT repair ${input.action}: incident ${input.incident_id}`, requiresGate: false, }); engine.ledger.record(completedEntry); engine.telemetryService.emitToolCall('srt_approve_repair', incident.incidentId, 'MANDATORY', true); return { content: [{ type: 'text' as const, text: JSON.stringify({ rejected: true, incidentId: incident.incidentId, planId: incident.repairPlan.planId, rejectedBy: input.approved_by, reason: input.reason || 'No reason provided', status: 'DIAGNOSED — can re-diagnose or propose new plan', }, null, 2) }] }; } // Approve incident.repairPlan.gateStatus = 'APPROVED'; incident.repairPlan.approvedBy = input.approved_by; incident.repairPlan.approvedAt = ts; incident.status = 'REPAIR_APPROVED'; incident.updatedAt = ts; // Mark as executing (in real deployment, this triggers server-side execution) incident.repairPlan.executedAt = ts; incident.status = 'REPAIR_EXECUTING'; // For v1, mark as success immediately (real execution is server-side) // In production, this would wait for actual command execution results incident.repairPlan.completedAt = new Date(Date.now() + (incident.repairPlan.estimatedMinutes * 60000)).toISOString(); incident.repairPlan.result = 'SUCCESS'; incident.status = 'REPAIR_COMPLETE'; incident.updatedAt = new Date().toISOString(); persistIncident(incident); // Write-through: approval + execution + completion const score = engine.scorer.scoreDefault(`srt-repair-${input.action}`); const completedEntry = entry.complete(score, { classification: MaiClassification.MANDATORY, confidence: 1.0, rationale: `SRT repair ${input.action}: incident ${input.incident_id}`, requiresGate: false, }); engine.ledger.record(completedEntry); engine.telemetryService.emitToolCall('srt_approve_repair', incident.incidentId, 'MANDATORY', true); return { content: [{ type: 'text' as const, text: JSON.stringify({ approved: true, incidentId: incident.incidentId, planId: incident.repairPlan.planId, approvedBy: input.approved_by, status: 'REPAIR_COMPLETE', result: incident.repairPlan.result, commandsExecuted: incident.repairPlan.commands.length, nextStep: 'Call srt_generate_postmortem to create incident report.', }, null, 2) }] }; } catch (error) { const failedEntry = entry.fail(error instanceof Error ? error : new Error(`SRT repair ${input.action} failed`), MaiClassification.MANDATORY); engine.ledger.record(failedEntry); engine.telemetryService.emitToolCall('srt_approve_repair', `repair-err-${Date.now().toString(36)}`, 'MANDATORY', false); return { content: [{ type: 'text' as const, text: JSON.stringify({ error: 'APPROVAL_FAILED', message: String(error) }) }], isError: true }; } } ); } - src/mcp/tools/srt.ts:1141-1146 (registration)Convenience function registerSRTTools() that registers all 4 SRT tools, including srt_approve_repair via registerSRTApproveRepairTool().
export function registerSRTTools(server: McpServer, engine: GovernanceEngine): void { registerSRTRunWatchdogTool(server, engine); registerSRTDiagnoseTool(server, engine); registerSRTApproveRepairTool(server, engine); registerSRTGeneratePostmortemTool(server, engine); } - src/mcp/server.ts:121-123 (registration)Registration in the TOOL_REGISTRY: srt_approve_repair is registered via registerSRTTools (which includes all 4 SRT tools) at OPERATOR tier, meaning it's only exposed to local stdio clients, not external HTTP clients.
{ tier: 'operator', register: registerSRTTools, description: 'srt (run_watchdog, diagnose, approve_repair, generate_postmortem)' }, { tier: 'operator', register: registerRemediationPackTools, description: 'remediation (scan_environment, list_packs, dry_run_pack, apply_pack, run_patrol)' }, ]; - src/mcp/tools/srt.ts:855-860 (schema)Input schema for the tool: requires incident_id (string), action (enum approve/reject), approved_by (string — human operator), and optional reason (string — required if rejecting).
{ incident_id: z.string().describe('Incident ID with pending repair'), action: z.enum(['approve', 'reject']).describe('Approve or reject the repair plan'), approved_by: z.string().describe('Human operator approving/rejecting'), reason: z.string().optional().describe('Reason for rejection (required if rejecting)'), }, - src/core/audit/telemetry.ts:184-184 (helper)Telemetry classification: srt_approve_repair is classified as toolClass='gate', riskTier='critical', maiDefault='MANDATORY', requiresHumanApproval=true, category='srt'.
{ toolName: 'srt_approve_repair', toolClass: 'gate', riskTier: 'critical', maiDefault: 'MANDATORY', requiresHumanApproval: true, category: 'srt' },