{"record":{"id":"5b1f1d052254abf7","repo":"thedotmack/claude-mem","slug":"deny-allow","errorCode":"DENY_ALLOW","errorMessage":"DENY_ALLOW","messagePattern":"DENY_ALLOW","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/integrations/CcsAlignRulesWalker.ts","lineNumber":555,"sourceCode":"        const drift = detectDrift(trimmed, allHouseLines);\n        if (drift.isDrift) {\n          conflicts.push({\n            code: 'DRIFT',\n            layer: 'seat',\n            file: entry.file,\n            line: trimmed,\n            detail: drift.matchedHouseLine\n              ? `House text may have changed; leaf still has old wording. House: \"${drift.matchedHouseLine}\"`\n              : 'Possible drift from house text',\n          });\n        }\n      }\n\n      // DENY_ALLOW: check seat line against house+project lines\n      const denyAllow = detectDenyAllow(trimmed, houseProjectLines);\n      if (denyAllow.isDenyAllow) {\n        conflicts.push({\n          code: 'DENY_ALLOW',\n          layer: 'seat',\n          file: entry.file,\n          line: trimmed,\n          detail: denyAllow.detail,\n        });\n      }\n    }\n  }\n\n  // Project-layer deny/allow (against house)\n  for (const entry of project.entries) {\n    for (const line of entry.lines) {\n      const trimmed = line.trim();\n      if (trimmed.length === 0) continue;\n\n      const denyAllow = detectDenyAllow(trimmed, allHouseLines);\n      if (denyAllow.isDenyAllow) {\n        conflicts.push({","sourceCodeStart":537,"sourceCodeEnd":573,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/8bc631a71a487424b866756e43a6efa4574cc66b/src/services/integrations/CcsAlignRulesWalker.ts#L537-L573","documentation":"A conflict record emitted by CcsAlignRulesWalker.walkRules with code DENY_ALLOW at the seat layer: detectDenyAllow found a seat-level line whose deny/allow semantics contradict a house or project line — e.g. seat denies something the house explicitly allows (or vice versa), so the cascade becomes ambiguous or silently overridden.","triggerScenarios":"walkRules processes a seat-layer line that detectDenyAllow matches against the combined house+project line set with conflicting allow/deny polarity.","commonSituations":"A seat file forbids a tool the project config allows ('never run rm -rf' vs project 'allow shell commands'); team changed house policy from deny to allow while personal seat rules still deny.","solutions":["Decide the intended polarity and align the seat line with house+project (edit or delete the seat line)","If the seat denial is intentional, move the exception up to project/house level so the layers agree","Reword to scope the deny narrowly (specific command) so it no longer contradicts the broad allow","Re-run walkRules to verify DENY_ALLOW is resolved"],"exampleFix":"// before (seat file)\nNever use Bash.\n// after\n(line removed, or narrowed:)\nOnly use Bash for git and test commands.","handlingStrategy":"validation","validationCode":"const denyRe = /^(never|do not|don't|disallow)\\b/i;\nconst allowRe = /^(always|you may|allow|feel free)\\b/i;\nfunction contradicts(leaf: string, base: string[]): boolean {\n  const t = leaf.trim().toLowerCase();\n  return base.some(b => {\n    const bt = b.trim().toLowerCase();\n    return (denyRe.test(t) && allowRe.test(bt)) || (allowRe.test(t) && denyRe.test(bt));\n  });\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Keep deny/allow policy in one layer; use seat files only for additions","State policy positively and scope narrowly to avoid polarity conflicts","Review seat/project rules against house policy during onboarding changes"],"tags":["rules-walker","conflict-detection","permissions"],"backgroundTag":"conflicting-config-options","analyzedSha":"8bc631a71a487424b866756e43a6efa4574cc66b","analyzedAt":"2026-09-09T10:47:06.009Z","contentChangedAt":"2026-09-09T10:47:06.009Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}