{"record":{"id":"56194bb2cc3c0a14","repo":"affaan-m/ECC","slug":"harness-capability-root-is-out-of-sync-for-target","errorCode":null,"errorMessage":"Harness capability root is out of sync for target ${declaredScope.targetId}","messagePattern":"Harness capability root is out of sync for target (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/harness-capabilities.js","lineNumber":281,"sourceCode":"  if (new Set(catalogTargetIds).size !== catalogTargetIds.length) {\n    throw new Error('Harness capability catalog contains duplicate install target ids');\n  }\n\n  const supported = [...SUPPORTED_INSTALL_TARGETS].sort();\n  const registered = adapters.map(adapter => adapter.target).sort();\n  const catalogued = [...catalogTargetIds].sort();\n  if (\n    JSON.stringify(catalogued) !== JSON.stringify(supported)\n    || JSON.stringify(catalogued) !== JSON.stringify(registered)\n  ) {\n    throw new Error('Harness capability catalog is out of sync with install targets');\n  }\n\n  for (const harness of HARNESS_CAPABILITIES) {\n    for (const declaredScope of harness.scopes) {\n      const adapter = adapterByTarget.get(declaredScope.targetId);\n      if (!adapter || expectedRootForAdapter(adapter) !== declaredScope.root) {\n        throw new Error(\n          `Harness capability root is out of sync for target ${declaredScope.targetId}`\n        );\n      }\n    }\n  }\n}\n\nvalidateCatalog();\n\nfunction listHarnessCapabilities() {\n  return HARNESS_CAPABILITIES.slice();\n}\n\nfunction listGuidedHarnesses() {\n  return GUIDED_HARNESS_IDS.map(id => LOOKUP.get(id));\n}\n\nfunction getHarnessCapability(value) {","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/affaan-m/ECC/blob/d8409a4b0813771235555e32e3d8046a73988bfa/scripts/lib/harness-capabilities.js#L263-L299","documentation":"The third require-time validation: every harness scope declares a display root (like './.cursor' or '~/.config/opencode'), and validateCatalog recomputes the expected root from the scope's adapter — home adapters get a '~/...' prefix, project adapters get './...' plus the OS-normalized relative path — and requires an exact string match. A moved directory, changed prefix, or Windows path separator produces this mismatch at module load.","triggerScenarios":"An adapter's resolved install root changes (directory moved or its kind flips between home and project) while the harness entry's scopes[].root still holds the old literal string; or the root was written with backslashes / wrong prefix.","commonSituations":"Refactoring an adapter to install into a different folder; porting roots between home-scoped and project-scoped targets; editing the declared root string by hand and introducing a typo; path separator differences when validating on Windows.","solutions":["Recompute the correct value: for the offending targetId, run the same logic as expectedRootForAdapter (prefix from adapter.kind, then path.relative(baseRoot, adapter.resolveRoot(...)) with backslashes converted to '/')","Paste that exact string into the harness's scopes[].root declaration","Keep roots computed rather than hand-maintained where possible so they cannot drift","Re-require the module to confirm the whole validateCatalog() chain passes"],"exampleFix":"// before\n{ targetId: 'cursor', root: '~/.cursor' }   // adapter is project-scoped\n\n// after\n{ targetId: 'cursor', root: './.cursor' }","handlingStrategy":"validation","validationCode":"// CI guard: declared scope roots must equal recomputed roots\nconst caps = require('./scripts/lib/harness-capabilities.js');\nconst { listInstallTargetAdapters } = require('./scripts/lib/install-targets');\n// recompute like expectedRootForAdapter does and compare, e.g.:\n// prefix = adapter.kind === 'home' ? '~/' : './';\n// expected = prefix + path.relative(baseRoot, adapter.resolveRoot(...)).replace(/\\\\/g, '/');\n// assert declaredScope.root === expected for every scope","typeGuard":null,"tryCatchPattern":null,"preventionTips":["After touching any adapter's install root, re-require harness-capabilities.js locally before pushing","Prefer deriving scope roots from adapters over hand-maintained literals","Normalize path separators to '/' and use the correct ~/ vs ./ prefix for adapter kind"],"tags":["internal-invariant","paths","catalog","module-load","developer-error"],"backgroundTag":"path-mismatch","analyzedSha":"d8409a4b0813771235555e32e3d8046a73988bfa","analyzedAt":"2026-08-26T12:15:34.022Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}