Skip to content

Commit 9057fa0

Browse files
rootroot
authored andcommitted
feat(history): expose terminal outcome MCP tool
1 parent d4f32de commit 9057fa0

2 files changed

Lines changed: 35 additions & 2 deletions

File tree

universal-refiner/src/core/server.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,20 @@ Output ONLY the JSON array. If no gaps, return [].`,
309309
description: "Lists review-gated lesson and prompt-template candidates for the current repository.",
310310
inputSchema: { type: "object", properties: {} }
311311
},
312+
{
313+
name: "record_terminal_outcome",
314+
description: "Records one evidence-backed terminal goal outcome and an optional review-gated lesson candidate.",
315+
inputSchema: {
316+
type: "object",
317+
properties: {
318+
goal_id: { type: "string" },
319+
status: { type: "string", enum: ["completed", "failed", "cancelled", "blocked", "budget_exhausted"] },
320+
evidence: { type: "array", items: { type: "string" }, minItems: 1 },
321+
summary: { type: "string" }
322+
},
323+
required: ["goal_id", "status", "evidence", "summary"]
324+
}
325+
},
312326
{
313327
name: "review_lesson",
314328
description: "Approves or rejects a proposed lesson before it can influence future prompts.",
@@ -552,6 +566,19 @@ Output ONLY the JSON array. If no gaps, return [].`,
552566
const candidates = this.eventStore.getLearningCandidates(this.repository.id);
553567
return { content: [{ type: "text", text: JSON.stringify(candidates) }] };
554568
}
569+
case "record_terminal_outcome": {
570+
const outcome = z.object({
571+
goal_id: z.string().min(1),
572+
status: z.enum(["completed", "failed", "cancelled", "blocked", "budget_exhausted"]),
573+
evidence: z.array(z.string().min(1)).min(1),
574+
summary: z.string().min(1),
575+
}).parse(request.params.arguments);
576+
const recorded = this.eventStore.recordTerminalOutcome({
577+
...outcome,
578+
repo_id: this.repository.id,
579+
});
580+
return { content: [{ type: "text", text: JSON.stringify({ recorded, goal_id: outcome.goal_id }) }] };
581+
}
555582
case "review_lesson": {
556583
const { id, approved } = z.object({ id: z.string(), approved: z.boolean() }).parse(request.params.arguments);
557584
const changed = this.eventStore.reviewLesson(this.repository.id, id, approved);

universal-refiner/tests/acceptance/mcp-tools.acceptance.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ describe("MCP all-tool acceptance", () => {
4141
const names = listResponse.tools.map(tool => tool.name);
4242

4343
expect(new Set(names).size).toBe(names.length);
44-
expect(names).toHaveLength(19);
44+
expect(names).toHaveLength(20);
4545
for (const tool of listResponse.tools) {
4646
expect(tool.description.length).toBeGreaterThan(10);
4747
expect(tool.inputSchema.type).toBe("object");
@@ -142,6 +142,12 @@ describe("MCP all-tool acceptance", () => {
142142
discover_rules: {},
143143
approve_rule: { id: "missing-rule" },
144144
list_learning_candidates: {},
145+
record_terminal_outcome: {
146+
goal_id: "acceptance-goal",
147+
status: "completed",
148+
evidence: ["cas://evidence/acceptance"],
149+
summary: "Acceptance outcome",
150+
},
145151
review_lesson: { id: "pending-lesson", approved: true },
146152
review_template: { id: "pending-template", approved: true },
147153
ingest_pattern: { id: "pattern", category: "quality", description: "Verify changes." },
@@ -163,5 +169,5 @@ describe("MCP all-tool acceptance", () => {
163169
await expect(dispatch({ params: { name: tool.name, arguments: args[tool.name] } }))
164170
.resolves.toHaveProperty("content");
165171
}
166-
});
172+
}, 15_000);
167173
});

0 commit comments

Comments
 (0)