{"record":{"id":"745df4db44f2d31e","repo":"ruvnet/ruflo","slug":"repository-harness-descriptor-requires-a-non-empty","errorCode":null,"errorMessage":"repository harness descriptor requires a non-empty harnessId","messagePattern":"repository harness descriptor requires a non-empty harnessId","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/harness/contract.ts","lineNumber":196,"sourceCode":"  'message-acknowledgement',\n  'run-evidence',\n  'exact-source-state',\n  'release-decisions',\n]);\n\n/**\n * Convert an older descriptor to the safe v1 reference baseline.\n *\n * Unknown and authority-bearing capabilities are ignored. A legacy descriptor\n * can never self-assert enforce or release authority through this compatibility\n * function. A separately verified external adapter is required for that.\n */\nexport function normalizeHarnessDescriptor(\n  input: HarnessDescriptor | LegacyHarnessDescriptor,\n): InMemoryReferenceHarnessDescriptor {\n  const harnessId = input.harnessId ?? ('name' in input ? input.name : undefined);\n  if (typeof harnessId !== 'string' || harnessId.trim().length === 0) {\n    throw new Error('repository harness descriptor requires a non-empty harnessId');\n  }\n\n  const requested = Array.isArray(input.capabilities) ? input.capabilities : [];\n  const capabilities: Array<Exclude<HarnessCapability, 'release-decisions'>> = [...new Set(\n    requested.filter((value): value is HarnessCapability => (\n      CAPABILITIES.has(value as HarnessCapability)\n      && value !== 'release-decisions'\n    )),\n  )] as Array<Exclude<HarnessCapability, 'release-decisions'>>;\n  capabilities.sort();\n\n  return {\n    contractVersion: 1,\n    harnessId: harnessId.trim(),\n    mode: 'observe',\n    capabilities,\n    advisory: true,\n    assurance: 'in-memory-reference',","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/harness/contract.ts#L178-L214","documentation":"normalizeHarnessDescriptor accepts either a modern HarnessDescriptor (harnessId) or a legacy descriptor (name) and downgrades it to the safe v1 baseline. The id resolution (input.harnessId ?? input.name) must yield a non-empty trimmed string; undefined, '', or whitespace-only values throw. The function deliberately strips 'release-decisions' and unknown capabilities — this error is purely about the missing identifier.","triggerScenarios":"Passing a descriptor with neither harnessId nor name; harnessId set to '' or '   '; a legacy shape whose name key was removed; a spread of defaults that overwrites harnessId with an empty string.","commonSituations":"Loading harness descriptors from JSON configs where the key was renamed from name to harnessId and older files lack the new field; optional-chaining chains producing undefined; YAML parsers turning an empty value into ''.","solutions":["Set harnessId to a stable non-empty identifier on the descriptor","For legacy descriptors, populate the name field — it is accepted as the id","Validate descriptors right after deserialization and before calling normalizeHarnessDescriptor so failures carry file/field context"],"exampleFix":"// before\nconst descriptor = { capabilities: ['coordination'] }; // no harnessId or name\nnormalizeHarnessDescriptor(descriptor); // throws\n\n// after\nconst descriptor = { harnessId: 'my-harness', capabilities: ['coordination'] };\n// or the legacy shape:\nconst legacy = { name: 'my-harness', capabilities: ['coordination'] };","handlingStrategy":"validation","validationCode":"function hasHarnessIdentifier(d: Partial<{ harnessId: string; name: string }>): boolean {\n  const id = d.harnessId ?? d.name;\n  return typeof id === 'string' && id.trim().length > 0;\n}","typeGuard":"function isDescriptorWithId(d: unknown): d is { harnessId: string } | { name: string } {\n  if (typeof d !== 'object' || d === null) return false;\n  const rec = d as Record<string, unknown>;\n  const id = rec.harnessId ?? rec.name;\n  return typeof id === 'string' && id.trim().length > 0;\n}","tryCatchPattern":"Catch around normalizeHarnessDescriptor during config load and report the source file/key of the offending descriptor; fail startup rather than defaulting the id, since a blank id would make harness sessions unaddressable.","preventionTips":["Validate descriptors immediately after JSON/YAML deserialization","Make harnessId required in your own schema (with name as a legacy alias) so TypeScript catches omissions","Watch for spreads of default objects that can overwrite harnessId with ''"],"tags":["harness","contract","validation","legacy-migration"],"backgroundTag":"missing-required-argument","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}