refactor(store): rename LogEntry/WorkflowRun/ThreadRoundRow ts → timestamp
- Rename logs & workflow_runs table column ts → timestamp (breaking, no migration) - Update all SQL, types, mocks, CLI output, and tests - Integration tests use mkdtempSync to avoid stale DB conflicts Fixes #113
This commit is contained in:
@@ -41,7 +41,7 @@ describe("LogStore — crash recovery helpers (Phase 3)", () => {
|
||||
payload: JSON.stringify({ triggerPayload: payload }),
|
||||
timestamp: 1000,
|
||||
},
|
||||
{ runId: "run-1", workflow: "my-wf", status: "started", ts: 1000 },
|
||||
{ runId: "run-1", workflow: "my-wf", status: "started", timestamp: 1000 },
|
||||
);
|
||||
|
||||
const result = store.getTriggerPayload("run-1");
|
||||
@@ -57,7 +57,7 @@ describe("LogStore — crash recovery helpers (Phase 3)", () => {
|
||||
payload: null,
|
||||
timestamp: 1000,
|
||||
},
|
||||
{ runId: "run-2", workflow: "my-wf", status: "started", ts: 1000 },
|
||||
{ runId: "run-2", workflow: "my-wf", status: "started", timestamp: 1000 },
|
||||
);
|
||||
|
||||
expect(store.getTriggerPayload("run-2")).toBeNull();
|
||||
@@ -148,7 +148,7 @@ describe("LogStore — crash recovery helpers (Phase 3)", () => {
|
||||
payload: JSON.stringify({ triggerPayload: {} }),
|
||||
timestamp: 1000,
|
||||
},
|
||||
{ runId: "run-6", workflow: "my-wf", status: "started", ts: 1000 },
|
||||
{ runId: "run-6", workflow: "my-wf", status: "started", timestamp: 1000 },
|
||||
);
|
||||
store.append({
|
||||
source: "workflow",
|
||||
|
||||
@@ -30,7 +30,7 @@ describe("LogStore — workflow_runs", () => {
|
||||
runId: "run-1",
|
||||
workflow: "cleanup",
|
||||
status: "started",
|
||||
ts: 1000,
|
||||
timestamp: 1000,
|
||||
};
|
||||
|
||||
const entry = store.upsertWorkflowRun(
|
||||
@@ -47,23 +47,23 @@ describe("LogStore — workflow_runs", () => {
|
||||
expect(stored?.runId).toBe("run-1");
|
||||
expect(stored?.workflow).toBe("cleanup");
|
||||
expect(stored?.status).toBe("started");
|
||||
expect(stored?.ts).toBe(1000);
|
||||
expect(stored?.timestamp).toBe(1000);
|
||||
});
|
||||
|
||||
it("updates existing workflow_runs row on upsert (status transition)", () => {
|
||||
store.upsertWorkflowRun(
|
||||
{ source: "workflow", type: "started", refId: "run-2", payload: null, timestamp: 1000 },
|
||||
{ runId: "run-2", workflow: "cleanup", status: "started", ts: 1000 },
|
||||
{ runId: "run-2", workflow: "cleanup", status: "started", timestamp: 1000 },
|
||||
);
|
||||
|
||||
store.upsertWorkflowRun(
|
||||
{ source: "workflow", type: "completed", refId: "run-2", payload: null, timestamp: 2000 },
|
||||
{ runId: "run-2", workflow: "cleanup", status: "completed", ts: 2000 },
|
||||
{ runId: "run-2", workflow: "cleanup", status: "completed", timestamp: 2000 },
|
||||
);
|
||||
|
||||
const stored = store.getWorkflowRun("run-2");
|
||||
expect(stored?.status).toBe("completed");
|
||||
expect(stored?.ts).toBe(2000);
|
||||
expect(stored?.timestamp).toBe(2000);
|
||||
|
||||
// Both log entries should be present (event sourcing)
|
||||
const logs = store.query({ refId: "run-2" });
|
||||
@@ -71,15 +71,15 @@ describe("LogStore — workflow_runs", () => {
|
||||
});
|
||||
|
||||
it("the log entries act as source of truth for event history", () => {
|
||||
for (const [type, status, ts] of [
|
||||
for (const [type, status, timestamp] of [
|
||||
["queued", "queued", 1000],
|
||||
["started", "started", 1001],
|
||||
["step_complete", "started", 1002],
|
||||
["completed", "completed", 1005],
|
||||
] as const) {
|
||||
store.upsertWorkflowRun(
|
||||
{ source: "workflow", type, refId: "run-3", payload: null, timestamp: ts },
|
||||
{ runId: "run-3", workflow: "cleanup", status, ts },
|
||||
{ source: "workflow", type, refId: "run-3", payload: null, timestamp },
|
||||
{ runId: "run-3", workflow: "cleanup", status, timestamp },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -98,16 +98,16 @@ describe("LogStore — workflow_runs", () => {
|
||||
it("returns the latest state after multiple upserts", () => {
|
||||
store.upsertWorkflowRun(
|
||||
{ source: "workflow", type: "queued", refId: "run-4", payload: null, timestamp: 100 },
|
||||
{ runId: "run-4", workflow: "code-review", status: "queued", ts: 100 },
|
||||
{ runId: "run-4", workflow: "code-review", status: "queued", timestamp: 100 },
|
||||
);
|
||||
store.upsertWorkflowRun(
|
||||
{ source: "workflow", type: "started", refId: "run-4", payload: null, timestamp: 200 },
|
||||
{ runId: "run-4", workflow: "code-review", status: "started", ts: 200 },
|
||||
{ runId: "run-4", workflow: "code-review", status: "started", timestamp: 200 },
|
||||
);
|
||||
|
||||
const run = store.getWorkflowRun("run-4");
|
||||
expect(run?.status).toBe("started");
|
||||
expect(run?.ts).toBe(200);
|
||||
expect(run?.timestamp).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -115,19 +115,19 @@ describe("LogStore — workflow_runs", () => {
|
||||
beforeEach(() => {
|
||||
store.upsertWorkflowRun(
|
||||
{ source: "workflow", type: "queued", refId: "r1", payload: null, timestamp: 100 },
|
||||
{ runId: "r1", workflow: "cleanup", status: "queued", ts: 100 },
|
||||
{ runId: "r1", workflow: "cleanup", status: "queued", timestamp: 100 },
|
||||
);
|
||||
store.upsertWorkflowRun(
|
||||
{ source: "workflow", type: "started", refId: "r2", payload: null, timestamp: 200 },
|
||||
{ runId: "r2", workflow: "cleanup", status: "started", ts: 200 },
|
||||
{ runId: "r2", workflow: "cleanup", status: "started", timestamp: 200 },
|
||||
);
|
||||
store.upsertWorkflowRun(
|
||||
{ source: "workflow", type: "completed", refId: "r3", payload: null, timestamp: 300 },
|
||||
{ runId: "r3", workflow: "cleanup", status: "completed", ts: 300 },
|
||||
{ runId: "r3", workflow: "cleanup", status: "completed", timestamp: 300 },
|
||||
);
|
||||
store.upsertWorkflowRun(
|
||||
{ source: "workflow", type: "failed", refId: "r4", payload: null, timestamp: 400 },
|
||||
{ runId: "r4", workflow: "deploy", status: "queued", ts: 400 },
|
||||
{ runId: "r4", workflow: "deploy", status: "queued", timestamp: 400 },
|
||||
);
|
||||
});
|
||||
|
||||
@@ -164,9 +164,9 @@ describe("LogStore — workflow_runs", () => {
|
||||
expect(store.getActiveWorkflowRuns("nonexistent")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("returns runs ordered by ts ascending", () => {
|
||||
it("returns runs ordered by timestamp ascending", () => {
|
||||
const active = store.getActiveWorkflowRuns();
|
||||
expect(active[0].ts).toBeLessThan(active[1].ts);
|
||||
expect(active[0].timestamp).toBeLessThan(active[1].timestamp);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -177,7 +177,7 @@ describe("LogStore — workflow_runs", () => {
|
||||
const runId = `run-${status}`;
|
||||
store.upsertWorkflowRun(
|
||||
{ source: "workflow", type: status, refId: runId, payload: null, timestamp: 1 },
|
||||
{ runId, workflow: "test", status, ts: 1 },
|
||||
{ runId, workflow: "test", status, timestamp: 1 },
|
||||
);
|
||||
expect(store.getWorkflowRun(runId)?.status).toBe(status);
|
||||
},
|
||||
|
||||
@@ -86,14 +86,14 @@ export type WorkflowRun = {
|
||||
runId: string;
|
||||
workflow: string;
|
||||
status: WorkflowRunStatus;
|
||||
ts: number;
|
||||
timestamp: number;
|
||||
};
|
||||
|
||||
/** One role-produced workflow-message row with 1-based round index (ROW_NUMBER over role messages only). */
|
||||
export type ThreadRoundRow = {
|
||||
round: number;
|
||||
logId: number;
|
||||
ts: number;
|
||||
timestamp: number;
|
||||
message: { role: string; content: string; meta: unknown; timestamp: number };
|
||||
};
|
||||
|
||||
@@ -131,7 +131,7 @@ export type LogStore = {
|
||||
*/
|
||||
getActiveWorkflowRuns: (workflowName?: string) => WorkflowRun[];
|
||||
/**
|
||||
* Get all workflow runs regardless of status, sorted by ts descending.
|
||||
* Get all workflow runs regardless of status, sorted by timestamp descending.
|
||||
* Optionally filter by workflow name.
|
||||
*/
|
||||
getAllWorkflowRuns: (workflowName: string | null) => WorkflowRun[];
|
||||
@@ -195,7 +195,7 @@ CREATE TABLE IF NOT EXISTS workflow_runs (
|
||||
run_id TEXT PRIMARY KEY,
|
||||
workflow TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
ts INTEGER NOT NULL
|
||||
timestamp INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_workflow_runs_status ON workflow_runs(status);
|
||||
@@ -342,11 +342,11 @@ export function createLogStore(dbPath: string): LogStore {
|
||||
);
|
||||
|
||||
const upsertWorkflowRunStmt = sqlite.prepare(
|
||||
"INSERT OR REPLACE INTO workflow_runs (run_id, workflow, status, ts) VALUES (@runId, @workflow, @status, @ts)",
|
||||
"INSERT OR REPLACE INTO workflow_runs (run_id, workflow, status, timestamp) VALUES (@runId, @workflow, @status, @timestamp)",
|
||||
);
|
||||
|
||||
const getWorkflowRunStmt = sqlite.prepare(
|
||||
"SELECT run_id, workflow, status, ts FROM workflow_runs WHERE run_id = ?",
|
||||
"SELECT run_id, workflow, status, timestamp FROM workflow_runs WHERE run_id = ?",
|
||||
);
|
||||
|
||||
const getTriggerPayloadStmt = sqlite.prepare(
|
||||
@@ -386,19 +386,19 @@ export function createLogStore(dbPath: string): LogStore {
|
||||
);
|
||||
|
||||
const getActiveWorkflowRunsStmt = sqlite.prepare(
|
||||
"SELECT run_id, workflow, status, ts FROM workflow_runs WHERE status IN ('queued', 'started') ORDER BY ts ASC",
|
||||
"SELECT run_id, workflow, status, timestamp FROM workflow_runs WHERE status IN ('queued', 'started') ORDER BY timestamp ASC",
|
||||
);
|
||||
|
||||
const getActiveWorkflowRunsByNameStmt = sqlite.prepare(
|
||||
"SELECT run_id, workflow, status, ts FROM workflow_runs WHERE status IN ('queued', 'started') AND workflow = ? ORDER BY ts ASC",
|
||||
"SELECT run_id, workflow, status, timestamp FROM workflow_runs WHERE status IN ('queued', 'started') AND workflow = ? ORDER BY timestamp ASC",
|
||||
);
|
||||
|
||||
const getAllWorkflowRunsStmt = sqlite.prepare(
|
||||
"SELECT run_id, workflow, status, ts FROM workflow_runs ORDER BY ts DESC",
|
||||
"SELECT run_id, workflow, status, timestamp FROM workflow_runs ORDER BY timestamp DESC",
|
||||
);
|
||||
|
||||
const getAllWorkflowRunsByNameStmt = sqlite.prepare(
|
||||
"SELECT run_id, workflow, status, ts FROM workflow_runs WHERE workflow = ? ORDER BY ts DESC",
|
||||
"SELECT run_id, workflow, status, timestamp FROM workflow_runs WHERE workflow = ? ORDER BY timestamp DESC",
|
||||
);
|
||||
|
||||
const minLogTsStmt = sqlite.prepare("SELECT MIN(timestamp) AS m FROM logs");
|
||||
@@ -422,7 +422,7 @@ export function createLogStore(dbPath: string): LogStore {
|
||||
runId: run.runId,
|
||||
workflow: run.workflow,
|
||||
status: run.status,
|
||||
ts: run.ts,
|
||||
timestamp: run.timestamp,
|
||||
});
|
||||
return { ...entry, id: Number(info.lastInsertRowid) };
|
||||
});
|
||||
@@ -506,14 +506,14 @@ export function createLogStore(dbPath: string): LogStore {
|
||||
|
||||
function getWorkflowRun(runId: string): WorkflowRun | null {
|
||||
const row = getWorkflowRunStmt.get(runId) as
|
||||
| { run_id: string; workflow: string; status: string; ts: number }
|
||||
| { run_id: string; workflow: string; status: string; timestamp: number }
|
||||
| undefined;
|
||||
if (row === undefined) return null;
|
||||
return {
|
||||
runId: row.run_id,
|
||||
workflow: row.workflow,
|
||||
status: validateWorkflowRunStatus(row.status),
|
||||
ts: row.ts,
|
||||
timestamp: row.timestamp,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -522,12 +522,12 @@ export function createLogStore(dbPath: string): LogStore {
|
||||
workflowName !== undefined
|
||||
? getActiveWorkflowRunsByNameStmt.all(workflowName)
|
||||
: getActiveWorkflowRunsStmt.all()
|
||||
) as Array<{ run_id: string; workflow: string; status: string; ts: number }>;
|
||||
) as Array<{ run_id: string; workflow: string; status: string; timestamp: number }>;
|
||||
return rows.map((r) => ({
|
||||
runId: r.run_id,
|
||||
workflow: r.workflow,
|
||||
status: validateWorkflowRunStatus(r.status),
|
||||
ts: r.ts,
|
||||
timestamp: r.timestamp,
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -536,12 +536,12 @@ export function createLogStore(dbPath: string): LogStore {
|
||||
workflowName !== null
|
||||
? getAllWorkflowRunsByNameStmt.all(workflowName)
|
||||
: getAllWorkflowRunsStmt.all()
|
||||
) as Array<{ run_id: string; workflow: string; status: string; ts: number }>;
|
||||
) as Array<{ run_id: string; workflow: string; status: string; timestamp: number }>;
|
||||
return rows.map((r) => ({
|
||||
runId: r.run_id,
|
||||
workflow: r.workflow,
|
||||
status: validateWorkflowRunStatus(r.status),
|
||||
ts: r.ts,
|
||||
timestamp: r.timestamp,
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -657,7 +657,7 @@ export function createLogStore(dbPath: string): LogStore {
|
||||
if (row.payload === null) continue;
|
||||
const message = parseRoundPayload(row.payload, row.timestamp);
|
||||
if (message !== null) {
|
||||
out.push({ round: row.rn, logId: row.id, ts: row.timestamp, message });
|
||||
out.push({ round: row.rn, logId: row.id, timestamp: row.timestamp, message });
|
||||
}
|
||||
}
|
||||
return out;
|
||||
|
||||
Reference in New Issue
Block a user