{"record":{"id":"75caacc4ff4aaf48","repo":"affaan-m/ECC","slug":"work-item-target-id-is-already-done-cannot-cla","errorCode":null,"errorMessage":"Work item ${target.id} is already done; cannot claim.","messagePattern":"Work item (.+?) is already done; cannot claim\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/control-pane/work-item-mutations.js","lineNumber":69,"sourceCode":"/**\n * Claim an unassigned work item for an agent or human. Sets the owner (and\n * optional assigneeKind) and moves the card to running unless an explicit\n * status is supplied. Returns { claimed, item } or { claimed: false, reason }.\n */\nfunction claimWorkItem(store, { id, owner, assigneeKind, sessionId, status } = {}) {\n  if (!owner) {\n    throw new Error('claim requires an owner.');\n  }\n  const kind = assigneeKind ? String(assigneeKind).toLowerCase() : null;\n  if (kind && !VALID_ASSIGNEE_KINDS.has(kind)) {\n    throw new Error(\"assigneeKind must be 'agent' or 'human'.\");\n  }\n  const target = selectClaimTarget(store, { id });\n  if (!target) {\n    return { claimed: false, reason: 'no-unassigned-open-items' };\n  }\n  if (!isOpenStatus(target.status)) {\n    throw new Error(`Work item ${target.id} is already done; cannot claim.`);\n  }\n  const metadata = { ...(target.metadata || {}) };\n  if (kind) {\n    metadata.assigneeKind = kind;\n  }\n  const item = store.upsertWorkItem({\n    ...target,\n    owner,\n    sessionId: sessionId ?? target.sessionId ?? null,\n    status: status ?? 'running',\n    metadata,\n    updatedAt: new Date().toISOString()\n  });\n  return { claimed: true, item };\n}\n\n/**\n * Move a work item to a kanban lane (ready | running | blocked | done).","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/control-pane/work-item-mutations.js#L51-L87","documentation":"claimWorkItem only claims items in an open status. If selectClaimTarget resolves a target whose status is not open (e.g. done), it throws 'Work item <id> is already done; cannot claim.' This prevents re-claiming completed work.","triggerScenarios":"Explicitly claiming an item by id whose status is done (or any non-open status); race where two agents try to claim and one already finished the item.","commonSituations":"Stale dashboard id claimed after the item was completed; re-running a claim script against a finished backlog; auto-pick returning nothing vs explicit id pointing at a done card.","solutions":["Verify the item's status via store.getWorkItemById(id) before claiming.","Pick a different, still-open work item — the item is finished and should not be re-claimed.","If the item genuinely needs more work, create a new follow-up work item instead of re-claiming the done one.","Refresh control-pane state; you may be looking at stale data."],"exampleFix":"// before\nclaimWorkItem(store, { id: 'item-7', owner: 'agent' }); // item-7 is done\n// after\nconst item = store.getWorkItemById('item-7');\nif (item && !isOpenStatus(item.status)) {\n  store.upsertWorkItem({ id: 'item-7-followup', title: 'Rework: ' + item.title, status: 'ready' });\n}\nclaimWorkItem(store, { id: 'item-7-followup', owner: 'agent' });","handlingStrategy":"try-catch","validationCode":"const item = store.getWorkItemById(id);\nif (item && !isOpenStatus(item.status)) throw new Error(`Skip ${id}: status ${item.status}`);","typeGuard":"function isClaimable(item) { return !!item && isOpenStatus(item.status); }","tryCatchPattern":"try { claimWorkItem(store, { id, owner }); } catch (e) {\n  if (e.message.includes('already done')) { /* pick next open item */ }\n  else throw e;\n}","preventionTips":["Filter to open-status items before presenting claim candidates.","Re-read item state immediately before claiming to narrow race windows.","Never re-claim done items — create follow-up items instead.","Refresh dashboard data before auto-claim runs."],"tags":["work-items","state","validation"],"backgroundTag":"invalid-state-transition","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}