{"record":{"id":"70e62f9ff600df4c","repo":"ruvnet/ruflo","slug":"anchor-task-task-id-requires-non-empty-string-l","errorCode":null,"errorMessage":"anchor task ${task.id} requires non-empty string labels","messagePattern":"anchor task (.+?) requires non-empty string labels","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/services/harness-project-anchor.ts","lineNumber":108,"sourceCode":"  };\n  if (parsed.schemaVersion && parsed.schemaVersion !== PROJECT_ANCHOR_SCHEMA) {\n    throw new Error(`unsupported flywheel anchor schema: ${parsed.schemaVersion}`);\n  }\n  if (!Array.isArray(parsed.tasks) || parsed.tasks.length < 4) {\n    throw new Error('project flywheel anchor requires at least 4 labelled tasks');\n  }\n  const ids = new Set<string>();\n  for (const [index, task] of parsed.tasks.entries()) {\n    if (!task || typeof task.id !== 'string' || !/^[A-Za-z0-9._-]{1,128}$/.test(task.id)) {\n      throw new Error(`invalid anchor task id at index ${index}`);\n    }\n    if (ids.has(task.id)) throw new Error(`duplicate anchor task id: ${task.id}`);\n    ids.add(task.id);\n    if (typeof task.q !== 'string' || task.q.trim().length === 0) {\n      throw new Error(`anchor task ${task.id} has no query`);\n    }\n    if (!Array.isArray(task.labels) || task.labels.length === 0 || task.labels.some((label) => typeof label !== 'string' || !label.trim())) {\n      throw new Error(`anchor task ${task.id} requires non-empty string labels`);\n    }\n  }\n  return { version: parsed.version ?? 'project-anchor-v1', tasks: parsed.tasks };\n}\n\nfunction toSelection(\n  path: string,\n  expectedHash: string,\n): FlywheelAnchorSelection {\n  const parsed = parseTasks(path);\n  const actualHash = humanEvalHash(parsed.tasks);\n  if (actualHash !== normalizeHash(expectedHash)) {\n    throw new Error(`project flywheel anchor hash mismatch (got ${actualHash}, pinned ${normalizeHash(expectedHash)})`);\n  }\n  return {\n    version: parsed.version,\n    anchorRef: actualHash,\n    source: 'project',","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/ruvnet/ruflo/blob/2602b642d92234c710ffbe96bfb33007d481ceab/v3/@claude-flow/cli/src/services/harness-project-anchor.ts#L90-L126","documentation":"Every anchor task must have a `labels` array containing at least one non-blank string (every entry checked with trim). Labels are the expected-results ground truth the human-relevance delta is computed from; a missing, empty, or malformed labels array invalidates the whole measurement, so the file is rejected.","triggerScenarios":"`labels` absent, not an array (`labels: \"api\"`), an empty array, or an array containing blank or non-string entries such as `[\"\", \" \"]` or `[1]`.","commonSituations":"Hand-authored anchors forgetting the labels key; single-label shorthand written as a bare string; CSV exports producing empty cells as empty strings.","solutions":["Give each task a non-empty array of expected-result strings (e.g. relevant file paths or keywords)","Wrap bare-string labels in an array: `labels: \"src/api.ts\"` becomes `labels: [\"src/api.ts\"]`","Filter out blank entries when generating the file"],"exampleFix":"// before\n{ \"id\": \"t1\", \"q\": \"...\", \"labels\": \"src/api.ts\" }\n\n// after\n{ \"id\": \"t1\", \"q\": \"...\", \"labels\": [\"src/api.ts\", \"src/routes/api.ts\"] }","handlingStrategy":"type-guard","validationCode":"function labelsFilled(tasks: Array<{ id: string; labels?: unknown }>): string[] {\n  return tasks\n    .filter((t) => !Array.isArray(t.labels) || t.labels.length === 0 || t.labels.some((l) => typeof l !== 'string' || !l.trim()))\n    .map((t) => t.id);\n}","typeGuard":"interface TaskLike { id?: unknown; q?: unknown; labels?: unknown; }\n\nfunction hasLabels(task: unknown): task is TaskLike & { labels: string[] } {\n  const l = (task as TaskLike)?.labels;\n  return Array.isArray(l) && l.length > 0 && l.every((x) => typeof x === 'string' && x.trim().length > 0);\n}\n\n// Usage: const bad = tasks.filter((t) => !hasLabels(t)).map((t) => t.id);","tryCatchPattern":"try {\n  return loadEffectiveFlywheelAnchor(root, opts);\n} catch (e) {\n  if (e instanceof Error && /anchor task .+ requires non-empty string labels$/.test(e.message)) {\n    const id = e.message.match(/anchor task (.+) requires/)?.[1];\n    throw new Error(`Task '${id}' needs labels: ['expected/file.ts', ...] — expected results for the query.`);\n  }\n  throw e;\n}","preventionTips":["Always emit labels as an array of non-empty strings, even for a single expected result","Filter empty CSV cells out of label lists at generation time","Include label presence in anchor-file linting"],"tags":["schema","validation","anchor","required-field"],"backgroundTag":"schema-validation-failed","analyzedSha":"2602b642d92234c710ffbe96bfb33007d481ceab","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}