[harness] TaskUpdate/TaskCreate report success while dropping the metadata merge or applying only one field when the task store is busy

Status Open
Reported on v2.1.281
Maintainer reply None cached
Activity 1 comment · opened Sep 28, 2026

Finding. The task tools (TaskCreate / TaskUpdate) can report success while the write does not persist, or persists only partly, when the session's task store is busy (several subagents running, a script reading the store on a timer, the lead issuing updates in quick succession). Two shapes measured in one afternoon: (a) TaskUpdate with metadata: {root: true, ...} returned "Updated task metadata" for nine tasks; a test an hour later found three of them WITHOUT the key while six had it; re-issuing the same update persisted. (b) A TaskUpdate carrying subject, description and metadata together returned "Updated task #N subject" -- only the subject applied; the metadata was absent on re-read and had to be re-sent alone. The tool result gives no partial-apply signal and no version/etag, so the caller cannot tell a lost write from a landed one without re-reading.

Evidence. 2026-09-28 13:1xZ: TaskUpdate root=true on nine tasks (all "Updated"); 14:16Z: a guard test found three of them with metadata.root absent; 14:2xZ re-applied, persisted. 15:1xZ: one TaskUpdate(subject, description, metadata) -> "Updated task #N subject"; 15:2xZ the same guard found the task unmapped; a metadata-only TaskUpdate persisted. The store is one JSON file per task; six worktree subagents were running; an external script reads the directory on a timer.

Minimal reproduction. Two writers on one task within a second (a TaskUpdate and an external read/rewrite of the same file), then TaskGet: the second writer's fields win on the whole file. Or: one TaskUpdate with subject + description + metadata on a task whose file changed since the tool last read it.

Ask. (1) Read-modify-write under a lock on the task file with a verify-after-write; a mismatch is an error result, never "Updated". (2) A partial-apply result naming the fields applied ("subject applied; metadata NOT applied: conflict"). (3) A version field (or mtime/etag) on TaskGet so a caller can send an expected version and get a conflict instead of a silent overwrite.

Environment: Claude Code desktop app (Windows 11), version 2.1.281, in-process task tools with worktree subagents, Fable 5.1 as the lead session.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗