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:
committed by
gsxdsm
parent
7a5739faea
commit
b2ca02f743
@@ -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 () => {
|
||||
|
||||
@@ -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",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
};
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user