fix(FN-352): address no-commit review feedback
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
---
|
||||
"@fusion/engine": patch
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
Classify harmless temporary merge worktree cleanup failures after `git worktree prune`/porcelain inspection while keeping still-registered worktree leaks visible in merger diagnostics.
|
||||
|
||||
@@ -2368,6 +2368,8 @@ export interface Task {
|
||||
sourceMessageId?: string;
|
||||
sourceParentTaskId?: string;
|
||||
sourceMetadata?: Record<string, unknown>;
|
||||
/** Reconstructed task prompt content when available on in-memory execution tasks. */
|
||||
prompt?: string;
|
||||
/** Explicitly assigned user ID for task-user linking. Used during review handoff to indicate
|
||||
* which user should review the task. The sentinel value "requesting-user" indicates the
|
||||
* user who created or steered the task. */
|
||||
|
||||
@@ -191,6 +191,48 @@ Atlas Notes task-board artifacts only:
|
||||
expect(store.handoffToReview).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("FN-350 refuses contradictory implementation plus coordination fallback prompts", async () => {
|
||||
const prompt = `# Task: FN-350 - Route Ready Swift Tasks to Executor Owner
|
||||
|
||||
## Review Level: 1 (Plan Only)
|
||||
|
||||
**Assessment:** This is a coordination/routing task that should not change product source.
|
||||
|
||||
## Mission
|
||||
Implement the source fix if possible, or record the intentional block if no safe candidate exists. Do not change product source.
|
||||
|
||||
## File Scope
|
||||
|
||||
- FN-350 task document \`docs\` via \`fn_task_document_write\`
|
||||
|
||||
## Steps
|
||||
|
||||
### Step 1: Decide
|
||||
- [x] Decision recorded.
|
||||
`;
|
||||
const { store, tool } = await setup({
|
||||
id: "FN-350",
|
||||
title: "Route Ready Swift Tasks to Executor Owner",
|
||||
description: "Coordination/routing task with task-document evidence only.",
|
||||
prompt,
|
||||
branch: "fusion/fn-350",
|
||||
noCommitsExpected: undefined,
|
||||
steps: [{ name: "Decide", status: "done" as const }],
|
||||
});
|
||||
mockedExecSync.mockImplementation((cmd: string) => {
|
||||
if (cmd.includes("rev-parse --show-toplevel")) return Buffer.from("/repo/.worktrees/swift-falcon\n");
|
||||
if (cmd.includes("rev-parse --abbrev-ref HEAD")) return Buffer.from("fusion/fn-350\n");
|
||||
if (cmd.includes("rev-list --count")) return Buffer.from("0\n");
|
||||
if (cmd.includes("rev-parse HEAD")) return Buffer.from("def456\n");
|
||||
return Buffer.from("");
|
||||
});
|
||||
|
||||
const result = await tool.execute("id", {});
|
||||
|
||||
expect(result.content[0].text).toContain("fn_task_done refused: no_commits");
|
||||
expect(store.moveTask).toHaveBeenCalledWith("FN-350", "todo", { preserveProgress: true });
|
||||
});
|
||||
|
||||
it("FN-4114 still refuses source-changing implementation tasks with zero commits and no explicit no-commit contract", async () => {
|
||||
const implementationPrompt = `# Task: FN-4114 - Implement source change
|
||||
|
||||
|
||||
@@ -257,7 +257,11 @@ function promptLooksCoordinationOnly(prompt: string): boolean {
|
||||
const assessment = prompt.match(/^\*\*Assessment:\*\*\s*([^\n]+)/im)?.[1] ?? "";
|
||||
const coordinationText = `${titleMatch}\n${mission}\n${assessment}`.toLowerCase();
|
||||
const hasCoordinationIntent = /\b(coordination|routing|route|handoff|assign(?:ment)?|owner|triage|select exactly one|record (?:the )?intentional block)\b/.test(coordinationText);
|
||||
const hasImplementationDirective = /\b(implement|fix|add|change|modify|refactor|build|create|delete|remove)\b/.test(mission.toLowerCase()) && !/record (?:the )?intentional block/.test(mission.toLowerCase());
|
||||
const missionLower = mission.toLowerCase()
|
||||
.replace(/do\s+not\s+(?:edit|modify|change)\s+(?:product\s+)?source/g, "")
|
||||
.replace(/should\s+not\s+change\s+(?:product\s+)?source/g, "")
|
||||
.replace(/must\s+not\s+(?:edit|modify|change)\s+(?:product\s+)?(?:source|code)/g, "");
|
||||
const hasImplementationDirective = /\b(implement|fix|add|change|modify|refactor|build|create|delete|remove)\b/.test(missionLower);
|
||||
return hasCoordinationIntent && !hasImplementationDirective;
|
||||
}
|
||||
|
||||
@@ -268,13 +272,13 @@ function promptFileScopeIsBoardOnly(prompt: string): boolean {
|
||||
const sourcePathPattern = /(?:^|[\s`'"(])(?:packages|src|source|sources|app|apps|lib|libs|components|scripts|docs|\.github|config|test|tests|__tests__)\//m;
|
||||
const sourceExtensionPattern = /\.(?:ts|tsx|js|jsx|mjs|cjs|swift|kt|java|py|go|rs|rb|php|cs|cpp|c|h|hpp|json|ya?ml|toml|mdx?|css|scss|html|sql|sh)\b/m;
|
||||
if (sourcePathPattern.test(normalized) || sourceExtensionPattern.test(normalized)) return false;
|
||||
const allowedBoardOnlyPattern = /\b(task[- ]?board|board task|task document|task documents|task metadata|task logs|fusion task tools|fn_task_|\.fusion\/tasks|attachments?)\b/;
|
||||
const allowedBoardOnlyPattern = /(?:^|[^\w/])(?:task[- ]?board|board task|task document|task documents|task metadata|task logs|fusion task tools|fn_task_[\w-]*|\.fusion\/tasks|attachments?)(?=$|[^\w/-])/;
|
||||
return allowedBoardOnlyPattern.test(normalized);
|
||||
}
|
||||
|
||||
function getNoCommitEligibilityReason(task: Task): "explicit noCommitsExpected=true" | "prompt-derived coordination-only no-source scope" | null {
|
||||
if (task.noCommitsExpected === true) return "explicit noCommitsExpected=true";
|
||||
const rawPrompt = (task as { prompt?: unknown }).prompt;
|
||||
const rawPrompt = task.prompt;
|
||||
const prompt = typeof rawPrompt === "string" ? rawPrompt : "";
|
||||
if (!prompt.trim()) return null;
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user