fix(HAI-018): complete Step 1 — fix server-side error handling in GET /tasks/:id

- Route now returns 404 only for ENOENT, 500 for transient errors
- store.getTask() retries once after 50ms on non-ENOENT failures
- Added route tests for success, 404, and 500 cases
- Updated vitest config to include src/**/*.test.* files
This commit is contained in:
Dustin Byrne
2026-03-25 21:30:18 -04:00
parent 60be31927f
commit d452aeb0c1
5 changed files with 132 additions and 5 deletions

View File

@@ -118,10 +118,29 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
return task;
}
/**
* Read a task's JSON and prompt content.
*
* Retries once after a short delay on non-ENOENT errors to handle
* transient read failures caused by concurrent `writeFile` calls
* (e.g. partial JSON from a non-atomic write during executor updates).
*/
async getTask(id: string): Promise<TaskDetail> {
const dir = this.taskDir(id);
const data = await readFile(join(dir, "task.json"), "utf-8");
const task = JSON.parse(data) as Task;
const taskPath = join(dir, "task.json");
let task: Task;
try {
const data = await readFile(taskPath, "utf-8");
task = JSON.parse(data) as Task;
} catch (err: any) {
// If the file doesn't exist, propagate immediately (true 404)
if (err.code === "ENOENT") throw err;
// Transient error (e.g. partial read / JSON parse failure) — retry once
await new Promise((r) => setTimeout(r, 50));
const data = await readFile(taskPath, "utf-8");
task = JSON.parse(data) as Task;
}
let prompt = "";
const promptPath = join(dir, "PROMPT.md");