{"record":{"id":"d13673dede6debcd","repo":"thedotmack/claude-mem","slug":"shadow-house","errorCode":"SHADOW_HOUSE","errorMessage":"SHADOW_HOUSE","messagePattern":"SHADOW_HOUSE","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/integrations/CcsAlignRulesWalker.ts","lineNumber":519,"sourceCode":"          detail: 'Top-of-prompt clock or \"current time is\" in a profile (house rule: no clock in prefix)',\n        });\n      }\n    }\n  }\n\n  // Seat-layer specific conflict detection (against house)\n  const shadowPatchesByFile = new Map<string, Set<string>>();\n\n  for (const entry of seat.entries) {\n    for (const line of entry.lines) {\n      const trimmed = line.trim();\n      if (trimmed.length === 0) continue;\n\n      // SHADOW_HOUSE: leaf line also at house (or starts with \"House rule\")\n      const shadow = detectShadowHouse(trimmed, houseLineSet);\n      if (shadow.isShadow) {\n        conflicts.push({\n          code: 'SHADOW_HOUSE',\n          layer: 'seat',\n          file: entry.file,\n          line: trimmed,\n          detail: shadow.matchedHouseLine\n            ? `Leaf duplicates house line: \"${shadow.matchedHouseLine}\"`\n            : 'Leaf starts with \"House rule\" — shadows the cascade',\n          houseMatch: shadow.matchedHouseLine,\n        });\n\n        if (!shadowPatchesByFile.has(entry.file)) {\n          shadowPatchesByFile.set(entry.file, new Set());\n        }\n        shadowPatchesByFile.get(entry.file)!.add(trimmed);\n      }\n\n      // DRIFT: leaf line is close-but-not-exact to a house line\n      if (!shadow.isShadow) {\n        const drift = detectDrift(trimmed, allHouseLines);","sourceCodeStart":501,"sourceCodeEnd":537,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/8bc631a71a487424b866756e43a6efa4574cc66b/src/services/integrations/CcsAlignRulesWalker.ts#L501-L537","documentation":"A conflict record emitted by CcsAlignRulesWalker.walkRules with code SHADOW_HOUSE: a leaf (seat-level) rule line duplicates, nearly verbatim, an existing house line or starts with 'House rule', shadowing the cascade. It is redundant at best and dangerous at worst — if the house line changes, the stale leaf copy keeps overriding it.","triggerScenarios":"walkRules finds a seat-layer line that detectShadowHouse matches against the house line set (exact duplicate) or that begins with the literal 'House rule'.","commonSituations":"A developer copied a house rule into their personal seat rules file 'just to be sure'; auto-merged configs reintroduced a line the house already covers; an old house line was demoted to seat level and now shadows its successor.","solutions":["Delete the duplicated line from the seat-level file — the house layer already provides it","If the seat needs a genuine exception, rewrite it as a delta rather than a copy of the house text","Re-run walkRules after editing to confirm SHADOW_HOUSE is cleared","Check git history of the flagged file to find which house line it was copied from"],"exampleFix":"// before (seat file)\nHouse rule: always run lint before commit\n// after\n(line removed — inherited from house layer)","handlingStrategy":"validation","validationCode":"const houseSet = new Set(houseLines.map(l => l.trim()));\nconst shadows = seatLines.filter(l => {\n  const t = l.trim();\n  return houseSet.has(t) || t.startsWith('House rule');\n});\nif (shadows.length) console.warn('seat lines shadow house:', shadows);","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Never copy house rules into seat-level files; inherit them from the cascade","Prefix seat-specific lines clearly so they are not mistaken for house text","Audit seat files after house rule changes for leftover copies"],"tags":["rules-walker","conflict-detection","duplication"],"backgroundTag":"schema-validation-failed","analyzedSha":"8bc631a71a487424b866756e43a6efa4574cc66b","analyzedAt":"2026-09-09T10:47:06.009Z","contentChangedAt":"2026-09-09T10:47:06.009Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}