{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/services/reducer/index.ts"],"sourcesContent":["import {\n  DELETED_STATUS,\n  type DepToken,\n  isDelegationActive,\n  type Task,\n  type TaskAction,\n  type TaskDocument,\n  type TaskItemMutation,\n  type TaskMutationParams,\n  type TaskStatus,\n  type UpsertItemOutcome,\n} from '../../models/task';\nimport { detectCycle } from '../../models/taskGraph';\nimport { isTransitionValid } from '../invariants';\n\n/** Default board capacity when a caller does not provide a configured limit. */\nconst DEFAULT_REDUCER_MAX_TASKS = 15;\n\n/** Bounds the work one call can do, and with it the size of one committed write. */\nexport const MAX_UPSERT_ITEMS = 100;\n\n/**\n * A ref must start with a letter, which makes it structurally unconfusable with\n * a stringified id. That is why resolving a dependency token is just a `typeof`\n * check with no coercion heuristics.\n */\nexport const REF_PATTERN = /^[A-Za-z][A-Za-z0-9_-]{0,31}$/;\n\n/**\n * Reducer outcome. Closed tagged union: adding an action requires extending\n * this union and the response formatter, which the compiler enforces.\n *\n * `upsert` carries one outcome per request item. It is returned even when every\n * item failed — `error` is reserved for whole-call faults — so the tool layer\n * still has the per-item messages to report.\n */\nexport type Op =\n  | { kind: 'upsert'; items: UpsertItemOutcome[]; applied: number; failed: number }\n  | { kind: 'delete'; id: number; subject: string }\n  | { kind: 'list'; statusFilter?: TaskStatus; includeDeleted: boolean }\n  | { kind: 'get'; task: Task }\n  | { kind: 'clear'; count: number }\n  | { kind: 'error'; message: string };\n\nexport interface ApplyResult {\n  document: TaskDocument;\n  op: Op;\n}\n\n/** Actions the reducer owns. `assign`/`cancel` are handled by the delegation manager. */\nexport type ReducerAction = Exclude<TaskAction, 'assign' | 'cancel'>;\n\n/**\n * Does this op represent state that must reach disk?\n *\n * The exhaustive switch is the point: a future `Op` variant cannot be added\n * without declaring its persistence intent, so nothing silently starts or stops\n * bumping `rev`.\n */\nexport function isCommittingOp(op: Op): boolean {\n  switch (op.kind) {\n    case 'error':\n    case 'list':\n    case 'get':\n      return false;\n    case 'upsert':\n      return op.items.some((item) => item.kind === 'created' || item.kind === 'updated');\n    case 'delete':\n    case 'clear':\n      return true;\n  }\n}\n\n/** Joined per-item failures, for the thrown error when an upsert applied nothing. */\nexport function formatUpsertFailure(op: Extract<Op, { kind: 'upsert' }>): string {\n  return op.items\n    .filter((item) => item.kind === 'failed')\n    .map((item) => `item[${item.index}]: ${item.message}`)\n    .join('\\n');\n}\n\n/** The single item's outcome, for callers that only ever send a batch of one. */\nexport function singleItemOutcome(op: Op): UpsertItemOutcome | undefined {\n  return op.kind === 'upsert' ? op.items[0] : undefined;\n}\n\nfunction errorResult(document: TaskDocument, message: string): ApplyResult {\n  return { document, op: { kind: 'error', message } };\n}\n\nfunction sameNumberList(a: number[] | undefined, b: number[] | undefined): boolean {\n  const x = a ?? [];\n  const y = b ?? [];\n  return x.length === y.length && x.every((value, index) => value === y[index]);\n}\n\nfunction sameRecord(a: Record<string, unknown> | undefined, b: Record<string, unknown> | undefined): boolean {\n  return JSON.stringify(a ?? null) === JSON.stringify(b ?? null);\n}\n\n/**\n * Did this update change anything? A no-effect update (status re-set to its\n * current value, fields re-sent unchanged) reports \"No change\" rather than\n * \"Updated #N\" — without the distinction a model can loop re-issuing the same\n * call believing it never landed.\n */\nfunction taskChanged(before: Task, after: Task): boolean {\n  return (\n    before.subject !== after.subject ||\n    before.status !== after.status ||\n    before.description !== after.description ||\n    before.activeForm !== after.activeForm ||\n    before.owner !== after.owner ||\n    !sameNumberList(before.blockedBy, after.blockedBy) ||\n    !sameRecord(before.metadata, after.metadata)\n  );\n}\n\nfunction withTasks(document: TaskDocument, tasks: Task[], nextId = document.nextId): TaskDocument {\n  return { ...document, tasks, nextId };\n}\n\n/** Merge incoming metadata over a base; a `null` value deletes its key. */\nfunction mergeMetadata(\n  base: Record<string, unknown> | undefined,\n  incoming: Record<string, unknown>,\n): Record<string, unknown> | undefined {\n  const merged: Record<string, unknown> = { ...base };\n  for (const [key, value] of Object.entries(incoming)) {\n    if (value === null) delete merged[key];\n    else merged[key] = value;\n  }\n  return Object.keys(merged).length ? merged : undefined;\n}\n\n/** Copy the optional scalar fields an item may set onto a task, in place. */\nfunction assignScalars(target: Task, item: TaskItemMutation): void {\n  if (item.subject !== undefined) target.subject = item.subject;\n  if (item.description !== undefined) target.description = item.description;\n  if (item.activeForm !== undefined) target.activeForm = item.activeForm;\n  if (item.owner !== undefined) target.owner = item.owner;\n  if (item.metadata !== undefined) {\n    const merged = mergeMetadata(target.metadata, item.metadata);\n    if (merged === undefined) delete target.metadata;\n    else target.metadata = merged;\n  }\n}\n\n/**\n * Working state threaded item to item, so entry N observes every effect of\n * entries 1..N-1. `refIds` and `failedRefs` are what make the cascade work:\n * refs resolve backward only, so an entry that names a failed sibling is always\n * processed after the failure that killed it.\n */\ninterface UpsertContext {\n  tasks: Task[];\n  nextId: number;\n  maxTasks: number;\n  refIds: Map<string, number>;\n  failedRefs: Map<string, number>;\n}\n\ntype Resolved = { ok: true; id: number } | { ok: false; message: string };\n\nfunction resolveDep(context: UpsertContext, field: string, token: DepToken): Resolved {\n  if (typeof token === 'number') return { ok: true, id: token };\n  if (!REF_PATTERN.test(token)) {\n    return { ok: false, message: `${field}: \"${token}\" is not a valid ref; pass an existing task id as a number` };\n  }\n  const id = context.refIds.get(token);\n  if (id !== undefined) return { ok: true, id };\n  const failedAt = context.failedRefs.get(token);\n  if (failedAt !== undefined) {\n    return { ok: false, message: `${field}: ref \"${token}\" refers to item[${failedAt}], which failed` };\n  }\n  return {\n    ok: false,\n    message: `${field}: unknown ref \"${token}\" — a ref must be declared by an earlier entry in the same call`,\n  };\n}\n\ntype ItemResult = { ok: true; outcome: UpsertItemOutcome } | { ok: false; message: string };\n\nfunction fail(message: string): ItemResult {\n  return { ok: false, message };\n}\n\n/** Structural checks that apply to every entry, whichever kind it is. */\nfunction checkShape(context: UpsertContext, item: TaskItemMutation): string | undefined {\n  if (item.ref !== undefined) {\n    if (item.id !== undefined) return 'ref is only valid when creating a task; drop the id, or drop the ref';\n    if (!REF_PATTERN.test(item.ref)) {\n      return `ref \"${item.ref}\" is invalid: a ref must start with a letter and contain only letters, digits, - or _`;\n    }\n    const owner = context.refIds.get(item.ref) !== undefined || context.failedRefs.has(item.ref);\n    if (owner) return `duplicate ref \"${item.ref}\": it was already declared by an earlier entry`;\n  }\n  return undefined;\n}\n\nfunction applyCreateItem(context: UpsertContext, item: TaskItemMutation, index: number, now: string): ItemResult {\n  if (item.subject === undefined) return fail('subject is required when the entry has no id');\n  if (!item.subject.trim()) return fail('subject must not be blank');\n  if (item.addBlockedBy !== undefined || item.removeBlockedBy !== undefined) {\n    return fail('addBlockedBy / removeBlockedBy are only for an entry with an id; a new task uses blockedBy');\n  }\n  // A task created as a tombstone is invisible to every view and can never\n  // leave `deleted`, so it would be a write-only black hole.\n  if (item.status === DELETED_STATUS) {\n    return fail('cannot create a task with status deleted; create it, then use action delete');\n  }\n\n  const taskCount = context.tasks.filter((task) => task.status !== DELETED_STATUS).length;\n  if (taskCount >= context.maxTasks) {\n    return fail(`task limit of ${context.maxTasks} reached; delete completed tasks first before creating new tasks`);\n  }\n\n  const blockedBy: number[] = [];\n  for (const token of item.blockedBy ?? []) {\n    const resolved = resolveDep(context, 'blockedBy', token);\n    if (!resolved.ok) return fail(resolved.message);\n    const dep = context.tasks.find((task) => task.id === resolved.id);\n    if (!dep) return fail(`blockedBy: #${resolved.id} not found`);\n    if (dep.status === DELETED_STATUS) return fail(`blockedBy: #${resolved.id} is deleted`);\n    if (!blockedBy.includes(resolved.id)) blockedBy.push(resolved.id);\n  }\n\n  // No cycle check is needed: the id is freshly allocated, so nothing already\n  // in the document can point at it yet.\n  const created: Task = {\n    id: context.nextId,\n    subject: item.subject,\n    status: item.status ?? 'pending',\n    createdAt: now,\n    updatedAt: now,\n  };\n  assignScalars(created, item);\n  if (blockedBy.length) created.blockedBy = blockedBy;\n\n  context.nextId += 1;\n  context.tasks.push(created);\n  if (item.ref) context.refIds.set(item.ref, created.id);\n\n  return {\n    ok: true,\n    outcome: {\n      index,\n      kind: 'created',\n      id: created.id,\n      subject: created.subject,\n      status: created.status,\n      ...(item.ref ? { ref: item.ref } : {}),\n      ...(blockedBy.length ? { blockedBy } : {}),\n    },\n  };\n}\n\nfunction applyUpdateItem(context: UpsertContext, item: TaskItemMutation, index: number, now: string): ItemResult {\n  const id = item.id as number;\n  const at = context.tasks.findIndex((task) => task.id === id);\n  if (at === -1) return fail(`#${id} not found`);\n  if (item.blockedBy !== undefined) {\n    return fail('blockedBy is only for a new entry; use addBlockedBy / removeBlockedBy on an entry that has an id');\n  }\n\n  const hasMutation =\n    item.subject !== undefined ||\n    item.description !== undefined ||\n    item.activeForm !== undefined ||\n    item.status !== undefined ||\n    item.owner !== undefined ||\n    item.metadata !== undefined ||\n    Boolean(item.addBlockedBy?.length) ||\n    Boolean(item.removeBlockedBy?.length);\n  if (!hasMutation) {\n    return fail(\n      'nothing to change: provide at least one of subject, description, activeForm, status, owner, metadata, addBlockedBy, or removeBlockedBy',\n    );\n  }\n\n  const current = context.tasks[at];\n\n  // The Task Space overlay commits free text from an inline editor, so a blank\n  // subject reaches the reducer as a real update rather than as a missing\n  // field. Persisting it would leave an unidentifiable row.\n  if (item.subject !== undefined && !item.subject.trim()) return fail('subject must not be blank');\n\n  let newStatus = current.status;\n  if (item.status !== undefined) {\n    if (!isTransitionValid(current.status, item.status)) {\n      return fail(`illegal transition ${current.status} -> ${item.status}`);\n    }\n    newStatus = item.status;\n  }\n\n  let newBlockedBy = current.blockedBy ? [...current.blockedBy] : [];\n  for (const token of item.removeBlockedBy ?? []) {\n    const resolved = resolveDep(context, 'removeBlockedBy', token);\n    if (!resolved.ok) return fail(resolved.message);\n    // Removing an id that is not there is a well-defined no-op, so unlike the\n    // add path this deliberately skips the existence check.\n    newBlockedBy = newBlockedBy.filter((dep) => dep !== resolved.id);\n  }\n  for (const token of item.addBlockedBy ?? []) {\n    const resolved = resolveDep(context, 'addBlockedBy', token);\n    if (!resolved.ok) return fail(resolved.message);\n    if (resolved.id === id) return fail(`cannot block #${id} on itself`);\n    const dep = context.tasks.find((task) => task.id === resolved.id);\n    if (!dep) return fail(`addBlockedBy: #${resolved.id} not found`);\n    if (dep.status === DELETED_STATUS) return fail(`addBlockedBy: #${resolved.id} is deleted`);\n    if (!newBlockedBy.includes(resolved.id)) newBlockedBy.push(resolved.id);\n  }\n\n  const updated: Task = { ...current, status: newStatus };\n  assignScalars(updated, item);\n  if (newBlockedBy.length) updated.blockedBy = newBlockedBy;\n  else delete updated.blockedBy;\n\n  // The candidate is written before the check because `detectCycle` unions the\n  // node's stored edges with the ones passed in: checking against the old array\n  // would resurrect an edge `removeBlockedBy` just stripped and reject a\n  // remove+add that legitimately breaks a cycle.\n  const candidate = [...context.tasks];\n  candidate[at] = updated;\n  if (item.addBlockedBy?.length && detectCycle(candidate, id, newBlockedBy)) {\n    return fail('addBlockedBy would create a cycle in the blockedBy graph');\n  }\n\n  const changed = taskChanged(current, updated);\n  if (changed) updated.updatedAt = now;\n  context.tasks = candidate;\n\n  return {\n    ok: true,\n    outcome: changed\n      ? { index, kind: 'updated', id, fromStatus: current.status, toStatus: newStatus }\n      : { index, kind: 'unchanged', id, status: newStatus },\n  };\n}\n\n/**\n * Apply every entry in request order, threading the document.\n *\n * Each entry lands completely or not at all: a create whose dependencies fail\n * is not kept dependency-free, because handing back an unblocked task the\n * caller asked to be blocked is a lie it may immediately act on.\n */\nfunction applyUpsert(document: TaskDocument, items: TaskItemMutation[], now: string, maxTasks: number): ApplyResult {\n  const context: UpsertContext = {\n    tasks: [...document.tasks],\n    nextId: document.nextId,\n    maxTasks,\n    refIds: new Map(),\n    failedRefs: new Map(),\n  };\n  const outcomes: UpsertItemOutcome[] = [];\n  let applied = 0;\n\n  for (const [index, item] of items.entries()) {\n    const shapeError = checkShape(context, item);\n    const result = shapeError\n      ? fail(shapeError)\n      : item.id === undefined\n        ? applyCreateItem(context, item, index, now)\n        : applyUpdateItem(context, item, index, now);\n\n    if (result.ok) {\n      outcomes.push(result.outcome);\n      applied += 1;\n      continue;\n    }\n    // A ref whose owner failed must not read as a typo to the entries that\n    // depend on it, so the dead ref is recorded rather than left unknown.\n    if (item.ref && REF_PATTERN.test(item.ref) && !context.refIds.has(item.ref)) {\n      context.failedRefs.set(item.ref, index);\n    }\n    outcomes.push({\n      index,\n      kind: 'failed',\n      message: result.message,\n      ...(item.id === undefined ? {} : { id: item.id }),\n      ...(item.ref ? { ref: item.ref } : {}),\n    });\n  }\n\n  return {\n    // Nothing applied means nothing to write: returning the original object by\n    // reference keeps the caller's write-skip path identical to a hard error.\n    document: applied > 0 ? withTasks(document, context.tasks, context.nextId) : document,\n    op: { kind: 'upsert', items: outcomes, applied, failed: outcomes.length - applied },\n  };\n}\n\n/**\n * Pure reducer: (document, action, params) -> (document, op).\n *\n * All validation is in-line: structural guards plus state-aware checks\n * (transition legality, dangling or deleted blockedBy, self-block, cycles,\n * in-flight delegations). The caller owns persistence and formatting.\n */\nexport function applyTaskMutation(\n  document: TaskDocument,\n  action: ReducerAction,\n  params: TaskMutationParams,\n  now: string = new Date().toISOString(),\n  maxTasks = DEFAULT_REDUCER_MAX_TASKS,\n): ApplyResult {\n  switch (action) {\n    case 'upsert': {\n      const items = params.tasks;\n      if (!Array.isArray(items) || items.length === 0) {\n        return errorResult(\n          document,\n          'upsert requires a non-empty tasks array, e.g. {\"action\":\"upsert\",\"tasks\":[{\"subject\":\"Write tests\"}]}',\n        );\n      }\n      if (items.length > MAX_UPSERT_ITEMS) {\n        return errorResult(\n          document,\n          `upsert accepts at most ${MAX_UPSERT_ITEMS} entries per call (received ${items.length})`,\n        );\n      }\n      return applyUpsert(document, items, now, maxTasks);\n    }\n\n    case 'list': {\n      return {\n        document,\n        op: {\n          kind: 'list',\n          includeDeleted: params.includeDeleted === true,\n          ...(params.status !== undefined ? { statusFilter: params.status } : {}),\n        },\n      };\n    }\n\n    case 'get': {\n      if (params.id === undefined) return errorResult(document, 'id required for get');\n      const task = document.tasks.find((candidate) => candidate.id === params.id);\n      if (!task) return errorResult(document, `#${params.id} not found`);\n      return { document, op: { kind: 'get', task } };\n    }\n\n    case 'delete': {\n      if (params.id === undefined) return errorResult(document, 'id required for delete');\n      const index = document.tasks.findIndex((task) => task.id === params.id);\n      if (index === -1) return errorResult(document, `#${params.id} not found`);\n      const current = document.tasks[index];\n      if (current.status === DELETED_STATUS) return errorResult(document, `#${current.id} is already deleted`);\n      if (isDelegationActive(current)) {\n        return errorResult(document, `#${current.id} has a running delegation — cancel it before deleting`);\n      }\n\n      const tasks = [...document.tasks];\n      tasks[index] = { ...current, status: DELETED_STATUS, updatedAt: now };\n      return {\n        document: withTasks(document, tasks),\n        op: { kind: 'delete', id: current.id, subject: current.subject },\n      };\n    }\n\n    case 'clear': {\n      const active = document.tasks.filter(isDelegationActive);\n      if (active.length > 0) {\n        const ids = active.map((task) => `#${task.id}`).join(', ');\n        return errorResult(document, `cannot clear while delegations are running (${ids}) — cancel them first`);\n      }\n      const count = document.tasks.length;\n      return {\n        document: withTasks(document, [], 1),\n        op: { kind: 'clear', count },\n      };\n    }\n  }\n}\n"],"mappings":"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"}