FN-5780: inherit source GitHub tracking when refining tasks
Preserve GitHub linking intent when creating refinement tasks from completed work. - Set refinement `githubTracking` from the source task state during `refineTask` - Opt out refinements when the source task is unlinked or explicitly disabled - Carry forward `enabled` and optional `repoOverride` for linked sources without copying source issue metadata - Add store-level tests covering unlinked, disabled, linked, and issue-only source tracking states - Document refinement GitHub tracking inheritance behavior in task-management docs - Add a patch changeset for `@runfusion/fusion` Files changed: .changeset/fn-5780-refine-github-tracking.md | 5 ++ docs/task-management.md | 1 + packages/core/src/__tests__/store-ops.test.ts | 71 +++++++++++++++++++++++++++ packages/core/src/store.ts | 12 +++++ 4 files changed, 89 insertions(+) Fusion-Task-Id: FN-5780 Fusion-Task-Lineage: 88c1ce01-6efd-48c1-bbdd-704a821055d7
This commit is contained in:
@@ -511,6 +511,77 @@ describe("TaskStore", () => {
|
||||
expect(refined.status).toBeUndefined();
|
||||
});
|
||||
|
||||
it("opts out github tracking when source has no githubTracking", async () => {
|
||||
const task = await store.createTask({ description: "Original task" });
|
||||
await store.moveTask(task.id, "todo");
|
||||
await store.moveTask(task.id, "in-progress");
|
||||
await store.moveTask(task.id, "in-review");
|
||||
await store.moveTask(task.id, "done");
|
||||
|
||||
const refined = await store.refineTask(task.id, "Need improvements");
|
||||
|
||||
expect(refined.githubTracking?.enabled).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps github tracking disabled when source is explicitly disabled", async () => {
|
||||
const task = await store.createTask({ description: "Original task" });
|
||||
await store.updateGithubTracking(task.id, { enabled: false });
|
||||
await store.moveTask(task.id, "todo");
|
||||
await store.moveTask(task.id, "in-progress");
|
||||
await store.moveTask(task.id, "in-review");
|
||||
await store.moveTask(task.id, "done");
|
||||
|
||||
const refined = await store.refineTask(task.id, "Need improvements");
|
||||
|
||||
expect(refined.githubTracking?.enabled).toBe(false);
|
||||
});
|
||||
|
||||
it("inherits enabled and repoOverride without copying linked issue", async () => {
|
||||
const task = await store.createTask({ description: "Original task" });
|
||||
await store.updateGithubTracking(task.id, {
|
||||
enabled: true,
|
||||
repoOverride: "owner/repo",
|
||||
issue: {
|
||||
number: 12,
|
||||
url: "https://github.com/owner/repo/issues/12",
|
||||
title: "Tracked",
|
||||
state: "open",
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
await store.moveTask(task.id, "todo");
|
||||
await store.moveTask(task.id, "in-progress");
|
||||
await store.moveTask(task.id, "in-review");
|
||||
await store.moveTask(task.id, "done");
|
||||
|
||||
const refined = await store.refineTask(task.id, "Need improvements");
|
||||
|
||||
expect(refined.githubTracking).toEqual({ enabled: true, repoOverride: "owner/repo" });
|
||||
expect(refined.githubTracking?.issue).toBeUndefined();
|
||||
});
|
||||
|
||||
it("treats linked issue without enabled flag as linked for refinement", async () => {
|
||||
const task = await store.createTask({ description: "Original task" });
|
||||
await store.updateGithubTracking(task.id, {
|
||||
issue: {
|
||||
number: 99,
|
||||
url: "https://github.com/owner/repo/issues/99",
|
||||
title: "Tracked",
|
||||
state: "open",
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
await store.moveTask(task.id, "todo");
|
||||
await store.moveTask(task.id, "in-progress");
|
||||
await store.moveTask(task.id, "in-review");
|
||||
await store.moveTask(task.id, "done");
|
||||
|
||||
const refined = await store.refineTask(task.id, "Need improvements");
|
||||
|
||||
expect(refined.githubTracking?.enabled).toBe(true);
|
||||
expect(refined.githubTracking?.issue).toBeUndefined();
|
||||
});
|
||||
|
||||
it("creates PROMPT.md for the refinement", async () => {
|
||||
const task = await store.createTask({ description: "Original task" });
|
||||
await store.moveTask(task.id, "todo");
|
||||
|
||||
@@ -4210,6 +4210,17 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
const removed = extractTaskIdTokens(`Refinement: ${sourceLabel}`).filter((token) => token !== newId.toUpperCase());
|
||||
storeLog.log(`[title-id-drift] normalized title for ${newId}: removed=[${removed.join(",")}]`);
|
||||
}
|
||||
const sourceGithubLinked = sourceTask.githubTracking?.enabled === true || Boolean(sourceTask.githubTracking?.issue);
|
||||
// FN-5780: refinement should inherit source linking intent so unlinked tasks stay opted out from auto-create defaults.
|
||||
const refinementGithubTracking = sourceGithubLinked
|
||||
? {
|
||||
enabled: true,
|
||||
...(sourceTask.githubTracking?.repoOverride
|
||||
? { repoOverride: sourceTask.githubTracking.repoOverride }
|
||||
: {}),
|
||||
}
|
||||
: { enabled: false };
|
||||
|
||||
const newTask: Task = {
|
||||
id: newId,
|
||||
lineageId: generateTaskLineageId(),
|
||||
@@ -4220,6 +4231,7 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
dependencies: [id],
|
||||
sourceType: "task_refine",
|
||||
sourceParentTaskId: id,
|
||||
githubTracking: refinementGithubTracking,
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
log: [{ timestamp: now, action: `Created as refinement of ${id}` }],
|
||||
|
||||
Reference in New Issue
Block a user