{"record":{"id":"2f4d4ceadd9f0bd8","repo":"affaan-m/ECC","slug":"claude-scope-and-hook-options-require-claude-to-be","errorCode":null,"errorMessage":"Claude scope and hook options require Claude to be selected.","messagePattern":"Claude scope and hook options require Claude to be selected\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/multi-harness-setup.js","lineNumber":29,"sourceCode":"const VALID_CLAUDE_SCOPES = new Set(['user', 'project', 'local']);\nconst VALID_CLAUDE_HOOKS = new Set(['off', 'minimal', 'standard', 'strict']);\nconst VALID_PROFILES = new Set(['minimal', 'core', 'developer', 'security', 'research', 'full']);\n\nfunction catalogHelpers() {\n  return require('./harness-capabilities');\n}\n\nfunction normalizeGuidedInstallRequest(input = {}) {\n  const { normalizeHarnessSelection } = catalogHelpers();\n  const harnesses = normalizeHarnessSelection(input.harnesses || []);\n  if (harnesses.length === 0) {\n    throw new Error('Choose at least one guided harness: Claude, Codex, or Kimi.');\n  }\n\n  const includesClaude = harnesses.includes('claude');\n  const includesKimi = harnesses.includes('kimi');\n  if (!includesClaude && (input.claudeScope !== undefined || input.claudeHooks !== undefined)) {\n    throw new Error('Claude scope and hook options require Claude to be selected.');\n  }\n  if (!includesKimi && input.profile !== undefined) {\n    throw new Error('The managed install profile requires Kimi to be selected.');\n  }\n\n  const claudeScope = includesClaude ? (input.claudeScope || 'user') : undefined;\n  const claudeHooks = includesClaude ? (input.claudeHooks || 'standard') : undefined;\n  const profile = includesKimi ? (input.profile || 'core') : undefined;\n  if (claudeScope && !VALID_CLAUDE_SCOPES.has(claudeScope)) {\n    throw new Error(`Invalid Claude scope: ${claudeScope}`);\n  }\n  if (claudeHooks && !VALID_CLAUDE_HOOKS.has(claudeHooks)) {\n    throw new Error(`Invalid Claude hooks preference: ${claudeHooks}`);\n  }\n  if (profile && !VALID_PROFILES.has(profile)) {\n    throw new Error(`Invalid Kimi install profile: ${profile}`);\n  }\n","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/multi-harness-setup.js#L11-L47","documentation":"normalizeGuidedInstallRequest validates guided-install options against the selected harness set. Claude-specific options (claudeScope, claudeHooks) are only meaningful when 'claude' is in the harnesses list, so passing them while Claude is not selected throws this error to prevent silently ignored options. It is a strict option-consistency guard, not a value validation.","triggerScenarios":"Calling the guided install request API (via request -> normalizeGuidedInstallRequest) with harnesses that exclude 'claude' while setting input.claudeScope or input.claudeHooks to any value including undefined check catches any presence (defined value).","commonSituations":"Programmatic installs where a shared config object always carries claudeScope/claudeHooks but the harness list was trimmed to codex/kimi; CLI flag defaults injected even when --claude was not passed; refactoring harness selection to a subset without pruning Claude options.","solutions":["Add 'claude' to the harnesses array in the request, or","Remove/omit the claudeScope and claudeHooks options when Claude is not selected","Build the options object conditionally so Claude-only keys are only set when Claude is selected"],"exampleFix":"// before\nrunSetup({ harnesses: ['codex'], claudeScope: 'project' })\n// after\nrunSetup({ harnesses: ['codex'] })\n// or\nrunSetup({ harnesses: ['codex', 'claude'], claudeScope: 'project' })","handlingStrategy":"validation","validationCode":"const claudeSelected = harnesses.includes('claude')\nif (!claudeSelected && (input.claudeScope !== undefined || input.claudeHooks !== undefined)) {\n  throw new Error('Pass claudeScope/claudeHooks only when Claude is selected')\n}","typeGuard":"const canUseClaudeOptions = (input) => Array.isArray(input.harnesses) && input.harnesses.includes('claude')","tryCatchPattern":"try {\n  const normalized = normalizeGuidedInstallRequest(input)\n} catch (err) {\n  if (err.message.includes('Claude scope and hook options')) {\n    const { claudeScope, claudeHooks, ...rest } = input\n    return normalizeGuidedInstallRequest(rest)\n  }\n  throw err\n}","preventionTips":["Build request objects conditionally per selected harness instead of reusing a fixed config shape","Validate the harness/option pairing in CLI arg parsing before calling the API","Keep harness selection and its options together in one validated schema"],"tags":["validation","config","guided-install"],"backgroundTag":"conflicting-config-options","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}