fix(KB-186): add ID-based tiebreaker to sort comparators for stable ordering
- Add numeric ID tiebreaker to TaskStore.listTasks() when createdAt timestamps match - Add same tiebreaker to InlineCreateCard and TaskDetailModal dependency dropdown sorts - Add store-sort integration test verifying ascending ID order with identical timestamps - Add InlineCreateCard tests for identical-timestamp dropdown ordering and search filtering - Add TaskDetailModal test for identical-timestamp dependency dropdown ordering
This commit is contained in:
55
packages/core/src/__tests__/store-sort.test.ts
Normal file
55
packages/core/src/__tests__/store-sort.test.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||
import { TaskStore } from "../store.js";
|
||||
import { rm } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { mkdtempSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
|
||||
function makeTmpDir(): string {
|
||||
return mkdtempSync(join(tmpdir(), "kb-store-sort-test-"));
|
||||
}
|
||||
|
||||
describe("TaskStore.listTasks() sort order", () => {
|
||||
let rootDir: string;
|
||||
let store: TaskStore;
|
||||
|
||||
beforeEach(async () => {
|
||||
rootDir = makeTmpDir();
|
||||
store = new TaskStore(rootDir);
|
||||
await store.init();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
store.stopWatching();
|
||||
await rm(rootDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("returns tasks with identical createdAt in ascending ID order", async () => {
|
||||
// Create three tasks — they may get the same createdAt if created fast enough
|
||||
const t1 = await store.createTask({ description: "Task one" });
|
||||
const t2 = await store.createTask({ description: "Task two" });
|
||||
const t3 = await store.createTask({ description: "Task three" });
|
||||
|
||||
// Force identical createdAt by rewriting the task.json files
|
||||
const { readFile, writeFile } = await import("node:fs/promises");
|
||||
const tasksDir = join(rootDir, ".kb", "tasks");
|
||||
const sameTimestamp = "2026-06-01T00:00:00Z";
|
||||
|
||||
for (const t of [t1, t2, t3]) {
|
||||
const jsonPath = join(tasksDir, t.id, "task.json");
|
||||
const data = JSON.parse(await readFile(jsonPath, "utf-8"));
|
||||
data.createdAt = sameTimestamp;
|
||||
data.updatedAt = sameTimestamp;
|
||||
await writeFile(jsonPath, JSON.stringify(data, null, 2));
|
||||
}
|
||||
|
||||
const tasks = await store.listTasks();
|
||||
const ids = tasks.map((t) => t.id);
|
||||
|
||||
// Should be ascending by numeric ID portion
|
||||
const nums = ids.map((id) => parseInt(id.slice(id.lastIndexOf("-") + 1), 10));
|
||||
for (let i = 1; i < nums.length; i++) {
|
||||
expect(nums[i]).toBeGreaterThan(nums[i - 1]);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user