feat(FN-3056): merge fusion/fn-3056

This merge ships several feature and infrastructure improvements across the codebase. Task title validation is strengthened in triage with stricter rejection of malformed titles and preference for prompt-declared titles (FN-3056), while task creation now preserves priority settings (FN-3210). The Mi

Fusion-Task-Id: FN-3056
This commit is contained in:
Fusion
2026-05-02 11:37:15 -07:00
committed by gsxdsm
parent 9c45d2410b
commit 6b4f28a1fb
11 changed files with 205 additions and 11 deletions

View File

@@ -270,15 +270,13 @@ describe("ai-summarize", () => {
expect(sanitizeTitle("\n\n hello world \nignored")).toBe("hello world");
});
it("strips chatty markdown reply (FN-3057 incident shape)", () => {
const raw =
"Created **FN-3058** with the full spec. Let me know if you want changes.";
// First line is the whole thing — sanitizer should strip the markdown bold
// and trailing period; truncation happens at MAX_TITLE_LENGTH (60).
const out = sanitizeTitle(raw)!;
expect(out).not.toContain("**");
expect(out.length).toBeLessThanOrEqual(60);
expect(out.startsWith("Created FN-3058")).toBe(true);
it("rejects task-creation confirmation prose (FN-3056 regression)", () => {
expect(
sanitizeTitle("Created task **FN-3058** in the triage column. Here's a summary."),
).toBeNull();
expect(
sanitizeTitle("Created **FN-3058** with the full spec"),
).toBeNull();
});
it("strips quotes, backticks, leading bullets", () => {

View File

@@ -9075,6 +9075,24 @@ Task with acceptance criteria
expect(updatedTask.title).toBe("AI Title");
});
it("should ignore malformed confirmation-prose generated titles", async () => {
const mockOnSummarize = vi
.fn()
.mockResolvedValue("Created task **FN-9999** in the triage column. Here's a summary.");
const task = await store.createTask(
{ description: "a".repeat(201) },
{ onSummarize: mockOnSummarize, settings: { autoSummarizeTitles: true } }
);
expect(task.title).toBeUndefined();
await new Promise((resolve) => setTimeout(resolve, 10));
const updatedTask = await store.getTask(task.id);
expect(updatedTask.title).toBeUndefined();
});
it("should handle onSummarize returning null", async () => {
const mockOnSummarize = vi.fn().mockResolvedValue(null);