{"record":{"id":"f520839d4dc2dc01","repo":"jackwener/OpenCLI","slug":"slock-task-status-returned-task-expectedid-with","errorCode":null,"errorMessage":"Slock task-status returned task ${expectedId} without taskStatus.","messagePattern":"Slock task-status returned task (.+?) without taskStatus\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/slock/task-status.js","lineNumber":87,"sourceCode":"        taskStatus: task.taskStatus,\n        assigneeId: t.claimedById ?? t.assigneeId ?? null,\n        taskNumber: t.taskNumber ?? null,\n      };\n    });\n  },\n});\n\nfunction assertTaskMutationIdentity(t, expectedId, expectedStatus) {\n  const taskId = t?.id;\n  if (!taskId) {\n    throw new CommandExecutionError(`Slock task-status succeeded without returning task id ${expectedId}; refusing to report a status row.`);\n  }\n  if (taskId !== expectedId) {\n    throw new CommandExecutionError(`Slock task-status returned task id ${taskId}, expected ${expectedId}.`);\n  }\n  const taskStatus = t.taskStatus ?? t.status;\n  if (!taskStatus) {\n    throw new CommandExecutionError(`Slock task-status returned task ${expectedId} without taskStatus.`);\n  }\n  if (taskStatus !== expectedStatus) {\n    throw new CommandExecutionError(`Slock task-status returned status ${taskStatus}, expected ${expectedStatus}.`);\n  }\n  return { taskId, taskStatus };\n}\n","sourceCodeStart":69,"sourceCodeEnd":94,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/task-status.js#L69-L94","documentation":"assertTaskMutationIdentity requires the returned task to carry a status (reading `t.taskStatus ?? t.status`). This throw fires when the task object has a matching id but no status field, so the command has nothing to render in its status row. It guards against API payloads that omit the status on success.","triggerScenarios":"task-status succeeds with the correct task id but the payload lacks both `taskStatus` and `status` (partial projection, sparse PATCH response, or a response shape like {id, title} from a different endpoint version).","commonSituations":"API downgrade/upgrade where the status field was renamed; calling against a proxy that strips fields; mocking a task endpoint with an incomplete fixture.","solutions":["Log the raw task object to confirm which fields the API actually returns.","Update to matching client/server versions so the status field is present.","If the API legitimately omits status, fall back to a follow-up GET /tasks/:id to fetch it.","Fix any mocked/stubbed fixture to include `taskStatus`."],"exampleFix":"// before\nreturn { kind: 'ok', task: { id: task.id } };\n// after\nreturn { kind: 'ok', task: { id: task.id, taskStatus: task.status ?? 'unknown' } };","handlingStrategy":"type-guard","validationCode":"const t = await fetchTask(id);\nif (!('taskStatus' in t) && !('status' in t)) await refetchFullTask(id);","typeGuard":"function hasTaskStatus(t) { return typeof t?.taskStatus === 'string' || typeof t?.status === 'string'; }","tryCatchPattern":"try {\n  const rows = await cli.run(['task-status', id]);\n} catch (e) {\n  if (String(e.message).includes('without taskStatus')) {\n    const full = await cli.run(['task-read', id]); // fallback fetch\n  } else throw e;\n}","preventionTips":["Ensure fixtures/mocks include taskStatus","Prefer full task GETs over sparse projections when you need status","Check API changelogs for renamed fields"],"tags":["contract-drift","missing-field","task-status"],"backgroundTag":"api-response-contract-drift","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}