feat(FN-4813): complete docs, settings, and verification updates

Fusion-Task-Id: FN-4813
Fusion-Task-Lineage: 846893a5-2afa-4817-8f64-8c444d2fd713
This commit is contained in:
Fusion (runfusion.ai)
2026-05-16 17:27:44 -07:00
committed by gsxdsm
parent 7a5739faea
commit b2ca02f743
8 changed files with 41 additions and 18 deletions

View File

@@ -1848,14 +1848,14 @@ describe("AgentStore", () => {
});
it("checkoutTask acquires a lease and stamps lease metadata", async () => {
const updated = await store.checkoutTask(holderId, taskId, { nodeId: "node-a", runId: "run-1", leaseEpoch: 2 });
const updated = await store.checkoutTask(holderId, taskId, { nodeId: "node-a", runId: "run-1", leaseEpoch: 0 });
expect(updated.checkedOutBy).toBe(holderId);
expect(updated.checkedOutAt).toBeDefined();
expect(updated.checkoutNodeId).toBe("node-a");
expect(updated.checkoutRunId).toBe("run-1");
expect(updated.checkoutLeaseRenewedAt).toBeDefined();
expect(updated.checkoutLeaseEpoch).toBe(2);
expect(updated.checkoutLeaseEpoch).toBeGreaterThanOrEqual(1);
const persisted = await taskStore.getTask(taskId);
expect(persisted?.checkedOutBy).toBe(holderId);
@@ -1863,29 +1863,31 @@ describe("AgentStore", () => {
expect(persisted?.checkoutNodeId).toBe("node-a");
expect(persisted?.checkoutRunId).toBe("run-1");
expect(persisted?.checkoutLeaseRenewedAt).toBeDefined();
expect(persisted?.checkoutLeaseEpoch).toBe(2);
expect(persisted?.checkoutLeaseEpoch).toBe(updated.checkoutLeaseEpoch);
});
it("checkoutTask is idempotent for same agent/node/epoch and renews lease timestamp", async () => {
const first = await store.checkoutTask(holderId, taskId, { nodeId: "node-a", runId: "run-1", leaseEpoch: 2 });
const first = await store.checkoutTask(holderId, taskId, { nodeId: "node-a", runId: "run-1", leaseEpoch: 0 });
await new Promise((resolve) => setTimeout(resolve, 5));
const second = await store.checkoutTask(holderId, taskId, { nodeId: "node-a", runId: "run-2", leaseEpoch: 2 });
const second = await store.checkoutTask(holderId, taskId, {
nodeId: "node-a",
runId: "run-2",
leaseEpoch: first.checkoutLeaseEpoch ?? 0,
});
expect(second.checkedOutBy).toBe(holderId);
expect(second.checkedOutAt).toBe(first.checkedOutAt);
expect(second.checkoutNodeId).toBe("node-a");
expect(second.checkoutRunId).toBe("run-2");
expect(second.checkoutLeaseEpoch).toBe(2);
expect(second.checkoutLeaseEpoch).toBe(first.checkoutLeaseEpoch);
expect(second.checkoutLeaseRenewedAt).not.toBe(first.checkoutLeaseRenewedAt);
});
it("checkoutTask updates epoch for same holder when lease epoch increases", async () => {
await store.checkoutTask(holderId, taskId, { nodeId: "node-a", runId: "run-1", leaseEpoch: 1 });
const bumped = await store.checkoutTask(holderId, taskId, { nodeId: "node-a", runId: "run-2", leaseEpoch: 3 });
expect(bumped.checkedOutBy).toBe(holderId);
expect(bumped.checkoutLeaseEpoch).toBe(3);
expect(bumped.checkoutRunId).toBe("run-2");
it("checkoutTask rejects renewal attempts with a mismatched epoch", async () => {
await store.checkoutTask(holderId, taskId, { nodeId: "node-a", runId: "run-1", leaseEpoch: 0 });
await expect(
store.checkoutTask(holderId, taskId, { nodeId: "node-a", runId: "run-2", leaseEpoch: 3 }),
).rejects.toBeInstanceOf(CheckoutConflictError);
});
it("checkoutTask throws CheckoutConflictError when already held by another agent", async () => {

View File

@@ -226,7 +226,12 @@ describe("settings key parity", () => {
it("only intentional shared keys appear in both global and project scopes", () => {
const projectKeySet = new Set(PROJECT_SETTINGS_KEYS as readonly string[]);
const overlap = (GLOBAL_SETTINGS_KEYS as readonly string[]).filter((key) => projectKeySet.has(key));
expect(overlap).toEqual(["taskTokenBudget", "githubTrackingDefaultRepo", "worktrunk"]);
expect(overlap).toEqual([
"taskTokenBudget",
"githubTrackingDefaultRepo",
"worktrunk",
"owningNodeHandoffPolicy",
]);
});
});

View File

@@ -846,7 +846,15 @@ export interface TaskLogEntry {
runContext?: RunMutationContext;
}
export type ActivityEventType = "task:created" | "task:moved" | "task:updated" | "task:deleted" | "task:merged" | "task:failed" | "settings:updated";
export type ActivityEventType =
| "task:created"
| "task:moved"
| "task:updated"
| "task:deleted"
| "task:merged"
| "task:failed"
| "settings:updated"
| "project:isolation-transition";
export interface ActivityLogEntry {
id: string;

View File

@@ -10,7 +10,6 @@ const baseTask: Task = {
steps: [],
currentStep: 0,
log: [],
prompt: "",
createdAt: "2026-01-01T00:00:00.000Z",
updatedAt: "2026-01-01T00:00:00.000Z",
};

View File

@@ -32,7 +32,6 @@ describe("MeshLeaseManager owning-node handoff integration", () => {
async function seedLease(ownerNodeId: string): Promise<void> {
await taskStore.updateTask(taskId, {
column: "in-progress",
checkedOutBy: "agent-1",
checkedOutAt: "2026-05-01T00:00:00.000Z",
checkoutLeaseRenewedAt: "2026-05-01T00:00:00.000Z",

View File

@@ -1029,7 +1029,9 @@ export class Scheduler {
}
}
const nodeHealth = this.options.nodeHealthMonitor.getNodeHealth(effectiveNode.nodeId);
const nodeHealth = effectiveNode.nodeId
? this.options.nodeHealthMonitor.getNodeHealth(effectiveNode.nodeId)
: undefined;
const decision = applyUnavailableNodePolicy({
effectiveNode,
nodeHealth,