fix(gsd): set completed_at when reconciling task status to complete
reconcileSliceTasks called updateTaskStatus without a completedAt timestamp, leaving tasks.completed_at NULL for all tasks completed via the file-existence reconcile path. Closes #4129 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6ba83c83c2
commit
365b36d96a
2 changed files with 43 additions and 1 deletions
|
|
@ -684,7 +684,7 @@ async function reconcileSliceTasks(
|
|||
const summaryPath = resolveTaskFile(basePath, milestoneId, sliceId, t.id, "SUMMARY");
|
||||
if (summaryPath && existsSync(summaryPath)) {
|
||||
try {
|
||||
updateTaskStatus(milestoneId, sliceId, t.id, "complete");
|
||||
updateTaskStatus(milestoneId, sliceId, t.id, "complete", new Date().toISOString());
|
||||
logWarning("reconcile", `task ${milestoneId}/${sliceId}/${t.id} status reconciled from "${t.status}" to "complete" (#2514)`, { mid: milestoneId, sid: sliceId, tid: t.id });
|
||||
reconciled = true;
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Regression test for #4129: tasks.completed_at stays NULL when status is
|
||||
* reconciled to 'complete' via the file-existence path in state.ts.
|
||||
*
|
||||
* Root cause: reconcileSliceTasks called
|
||||
* updateTaskStatus(milestoneId, sliceId, t.id, "complete")
|
||||
* without a completedAt timestamp, so the column stays NULL.
|
||||
*
|
||||
* Fix: pass new Date().toISOString() as the 5th argument.
|
||||
*/
|
||||
|
||||
import { describe, test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join, dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const stateSource = readFileSync(join(__dirname, "..", "state.ts"), "utf-8");
|
||||
|
||||
describe("completed-at reconcile (#4129)", () => {
|
||||
test("reconcileSliceTasks passes a completedAt timestamp when setting status to complete", () => {
|
||||
// Before the fix, state.ts had:
|
||||
// updateTaskStatus(milestoneId, sliceId, t.id, "complete")
|
||||
// which leaves completed_at NULL in the DB.
|
||||
// After the fix, a timestamp must be passed as the 5th argument.
|
||||
assert.doesNotMatch(
|
||||
stateSource,
|
||||
/updateTaskStatus\(\s*milestoneId\s*,\s*sliceId\s*,\s*t\.id\s*,\s*["']complete["']\s*\)/,
|
||||
"updateTaskStatus must not be called without a completedAt timestamp when reconciling tasks to 'complete' (#4129)",
|
||||
);
|
||||
});
|
||||
|
||||
test("reconcileSliceTasks passes new Date().toISOString() as the completedAt argument", () => {
|
||||
// Positive assertion: the fixed call must include a timestamp.
|
||||
assert.match(
|
||||
stateSource,
|
||||
/updateTaskStatus\(\s*milestoneId\s*,\s*sliceId\s*,\s*t\.id\s*,\s*["']complete["']\s*,\s*new Date\(\)\.toISOString\(\)\s*\)/,
|
||||
"reconcileSliceTasks must pass new Date().toISOString() as completedAt when setting task status to 'complete' (#4129)",
|
||||
);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue