{"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":"exception","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/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/multi-harness-setup.js#L11-L47","documentation":"Claude-specific options (claudeScope, claudeHooks) are only meaningful when 'claude' is in the selected harnesses. normalizeGuidedInstallRequest checks includesClaude first and refuses the combination otherwise, because applying Claude scope/hook settings without installing Claude would silently no-op or, worse, mutate an unrelated harness's config. This is a fail-fast coherence check on the request shape.","triggerScenarios":"Calling normalizeGuidedInstallRequest with input.claudeScope or input.claudeHooks set to any value (including undefined-explicit) while input.harnesses does not include 'claude'. Common when a caller threads through stale defaults or builds the request from a template that always sets claudeScope.","commonSituations":"A UI form that always submits claudeScope/claudeHooks fields even when Claude is unchecked; copy-pasted request objects from a prior Claude install; a wrapper that sets defaults unconditionally; passing { claudeHooks: undefined } explicitly (the check uses !== undefined, so explicit undefined still trips it in some code paths — but null is fine).","solutions":["Either add 'claude' to harnesses, or remove the claudeScope/claudeHooks fields from the input.","When building the request programmatically, only set claudeScope/claudeHooks conditionally: if (harnesses.includes('claude')) request.claudeScope = scope.","Audit the calling code for stale defaults that always populate these fields.","Prefer omitting the key entirely over setting it to undefined."],"exampleFix":"// before\nnormalizeGuidedInstallRequest({ harnesses: ['codex'], claudeScope: 'user' }); // throws\n// after (option A: drop the option)\nnormalizeGuidedInstallRequest({ harnesses: ['codex'] });\n// after (option B: add claude)\nnormalizeGuidedInstallRequest({ harnesses: ['codex', 'claude'], claudeScope: 'user' });","handlingStrategy":"validation","validationCode":"function buildClaudeOptions(input = {}) {\n  const harnesses = input.harnesses || [];\n  const opts = { harnesses };\n  if (harnesses.includes('claude')) {\n    if (input.claudeScope !== undefined) opts.claudeScope = input.claudeScope;\n    if (input.claudeHooks !== undefined) opts.claudeHooks = input.claudeHooks;\n  }\n  return opts;\n}\n// use buildClaudeOptions before normalizeGuidedInstallRequest","typeGuard":null,"tryCatchPattern":"try { normalizeGuidedInstallRequest(input); }\ncatch (error) {\n  if (/Claude scope and hook options require Claude/i.test(error.message)) {\n    console.error('Either add \\'claude\\' to harnesses or drop claudeScope/claudeHooks.');\n    return;\n  }\n  throw error;\n}","preventionTips":["Only set claudeScope/claudeHooks when 'claude' is in harnesses.","Omit unused option keys rather than passing undefined explicitly.","Build the request object conditionally to avoid stale defaults.","Validate coherence between harnesses and harness-specific options before calling normalize."],"tags":["multi-harness-setup","validation","configuration","installer"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}