From 17636199d630f5fec95d288cb053f9a8d87911de Mon Sep 17 00:00:00 2001 From: ciscoRankush Date: Wed, 11 Mar 2026 14:12:18 +0530 Subject: [PATCH 1/2] chore: add spec-drift detection commands and pre-commit hook Add automated SDD documentation drift detection tooling: - /spec-drift: full scan command for validating all ai-docs against source code - /spec-drift-changed: incremental scan for changed files only - Pre-commit hook to block commits when ai-docs drift is unverified Co-Authored-By: Claude Opus 4.6 --- .claude/commands/spec-drift-changed.md | 161 ++++++++++++++++++++ .claude/commands/spec-drift.md | 199 +++++++++++++++++++++++++ .claude/hooks/check-ai-docs-drift.sh | 49 ++++++ 3 files changed, 409 insertions(+) create mode 100644 .claude/commands/spec-drift-changed.md create mode 100644 .claude/commands/spec-drift.md create mode 100755 .claude/hooks/check-ai-docs-drift.sh diff --git a/.claude/commands/spec-drift-changed.md b/.claude/commands/spec-drift-changed.md new file mode 100644 index 000000000..6455ebdeb --- /dev/null +++ b/.claude/commands/spec-drift-changed.md @@ -0,0 +1,161 @@ +# Spec Drift Detection — Changed Files Only + +Validate ai-docs affected by any staged/unstaged changes — whether the changes are to ai-docs themselves OR to source code that has corresponding ai-docs. Lightweight mode for pre-commit validation. + +## Step 1: Find All Changed Files + +Run these commands to find all changed files (staged and unstaged): + +```bash +# Get both staged and unstaged changed files +(git diff --name-only HEAD 2>/dev/null; git diff --name-only --cached 2>/dev/null) | sort -u +``` + +## Step 2: Identify ai-docs That Need Validation + +From the changed files, build TWO lists: + +### List A: Changed ai-docs files +Filter for files matching `ai-docs/*.md`. These docs changed directly and need validation. + +### List B: Source code files with corresponding ai-docs +For each changed source file under `packages/contact-center/` (excluding ai-docs files themselves): +1. Walk up the file's directory path +2. Check if any ancestor directory contains an `ai-docs/` folder +3. If yes, that `ai-docs/` folder needs validation against the updated source code + +Use this to discover ai-docs folders: +```bash +find packages/contact-center -type d -name "ai-docs" +``` + +Build a mapping like: +``` +Changed source file → ai-docs to validate +packages/contact-center/store/src/store.ts → packages/contact-center/store/ai-docs/ +packages/contact-center/task/src/widgets/CallControl/CallControl.tsx → packages/contact-center/task/ai-docs/widgets/CallControl/ +packages/contact-center/cc-components/src/SomeComponent.tsx → packages/contact-center/cc-components/ai-docs/ +``` + +For task widget source files, map to the widget-specific ai-docs: +- `packages/contact-center/task/src/widgets/CallControl/*` → `packages/contact-center/task/ai-docs/widgets/CallControl/` +- `packages/contact-center/task/src/widgets/IncomingTask/*` → `packages/contact-center/task/ai-docs/widgets/IncomingTask/` +- `packages/contact-center/task/src/widgets/OutdialCall/*` → `packages/contact-center/task/ai-docs/widgets/OutdialCall/` +- `packages/contact-center/task/src/widgets/TaskList/*` → `packages/contact-center/task/ai-docs/widgets/TaskList/` + +**Deduplicate**: If multiple source files map to the same ai-docs folder, validate that folder only once. + +### Combine Lists A and B +The final set of ai-docs folders to validate is the union of: +- Folders containing files from List A +- Folders identified from List B + +If NEITHER list has entries, report: **"No ai-docs affected by current changes — nothing to check."** and stop. + +## Step 3: Validate Affected ai-docs + +For each ai-docs folder that needs validation, spawn an Explore agent with this prompt: + +``` +You are validating SDD documentation accuracy against source code. + +SOURCE OF TRUTH (actual code): {source_code_directory} +DOCS TO VALIDATE: {ai_docs_folder} (all .md files in this folder) + +CHANGED SOURCE FILES (if any): {list of changed source files in this package} +CHANGED DOC FILES (if any): {list of changed ai-docs files} + +Read every markdown file in the ai-docs folder. For each document, check these 7 categories: + +1. FILE TREE: Read any documented file/directory trees. Glob the actual directory. Report missing/extra files. + +2. METHOD/API SIGNATURES: For every method documented, read the actual source and verify: name, params, param types, return type, modifiers. Flag any mismatch. Pay special attention to methods in changed source files — new methods may be missing from docs, or changed signatures may not be reflected. + +3. TYPE DEFINITIONS: For every type/enum/interface documented, find the actual definition in source. Compare name, fields, field types, enum values. Check if changed source files introduced new types not yet documented. + +4. EVENT NAMES: For every event constant or observable referenced, verify it exists in source with the exact name. For MobX: verify @observable/@computed/@action decorators. For React: verify prop callback names. Check if changed source files added new events not yet documented. + +5. ARCHITECTURE PATTERNS: Verify claims about MobX store patterns, React component patterns, singleton vs factory, component hierarchy, store injection. + +6. LINK VALIDATION: For every relative link [text](path), verify the target exists on disk. + +7. CODE EXAMPLES: For every code block, verify API names, method names, parameter names, import paths, MobX patterns are correct. + +For each finding, report: +- File: (path) +- Line/Section: (approximate line or section heading) +- Category: (1-7) +- Severity: Blocking / Important / Medium / Minor + - Blocking = wrong API that would cause runtime errors if an AI agent follows the docs + - Important = wrong params/types that would cause compilation errors + - Medium = incomplete or stale info (e.g., new methods/types/events missing from docs) + - Minor = broken links, cosmetic issues +- What doc says: (quoted) +- What code actually has: (evidence with file:line) +- Suggested fix: (exact replacement text) +``` + +Run all agents in parallel if multiple ai-docs folders are affected. + +## Step 4: Consolidate and Report + +Present findings in this format: + +```markdown +## Spec Drift Report — Changed Files +Generated: {date} +Trigger: {source code changes / ai-docs changes / both} +ai-docs folders checked: {list} + +### Changed Source Files +{list of changed source files and their mapped ai-docs folder} + +### Changed ai-docs Files +{list of changed ai-docs files, or "None"} + +### Summary + +| ai-docs Folder | Findings | Blocking | Important | Medium | Minor | +|----------------|----------|----------|-----------|--------|-------| +| ... | | | | | | + +### Blocking Findings +... + +### Important Findings +... + +### Medium Findings +... + +### Minor Findings +... + +### Actionable Fixes by File +(grouped by file path, each with exact old text -> new text) +``` + +## Step 5: Create Verification Marker + +After presenting the validation report (regardless of findings), create a verification marker so the pre-commit hook allows the commit: + +```bash +# Hash ALL staged contact-center files — must match the hook's hash logic exactly +STAGED_CC=$(git diff --cached --name-only 2>/dev/null | grep "^packages/contact-center/" | sort) +if [ -n "$STAGED_CC" ]; then + HASH=$(echo "$STAGED_CC" | shasum | cut -d' ' -f1) + touch "/tmp/.spec-drift-verified-${HASH}" + echo "Verification marker created: /tmp/.spec-drift-verified-${HASH}" +fi +``` + +Report to the user: "Verification marker created. The pre-commit hook will allow the next commit for these staged files." + +## Rules + +- Do NOT auto-fix anything — report findings only +- Always read actual source code to verify — never assume +- Use the Task tool with `subagent_type: "Explore"` for checker agents +- Run agents in parallel when multiple folders are affected +- Always create the verification marker at the end, even if there are findings (the developer decides whether to fix or commit as-is) +- The marker hash MUST match the hook's hash computation — both hash ALL staged `packages/contact-center/` files sorted alphabetically diff --git a/.claude/commands/spec-drift.md b/.claude/commands/spec-drift.md new file mode 100644 index 000000000..48a65f23a --- /dev/null +++ b/.claude/commands/spec-drift.md @@ -0,0 +1,199 @@ +# Spec Drift Detection — Full Scan + +Run a comprehensive validation of all SDD ai-docs against actual source code. Deploys a parallel agent team to catch documentation drift across 7 categories. + +## Step 1: Auto-Discovery + +Detect repo type and discover all ai-docs: + +1. **Repo detection**: This is ccWidgets — `packages/contact-center/` exists (no `@webex` scope) +2. **Root AGENTS.md**: `AGENTS.md` (repo root) +3. **Framework docs**: `ai-docs/` (README, RULES, patterns/*, templates/*) +4. **Package-level ai-docs**: Glob for `packages/contact-center/**/ai-docs/` to find all ai-docs folders +5. **Samples ai-docs**: Check `widgets-samples/**/ai-docs/` as well + +For each ai-docs folder found, identify its corresponding source code directory (the parent directory of `ai-docs/`). + +Build an inventory like: +``` +ai-docs folder → source directory +packages/contact-center/store/ai-docs/ → packages/contact-center/store/src/ +packages/contact-center/cc-components/ai-docs/ → packages/contact-center/cc-components/src/ +packages/contact-center/cc-widgets/ai-docs/ → packages/contact-center/cc-widgets/src/ +packages/contact-center/station-login/ai-docs/ → packages/contact-center/station-login/src/ +packages/contact-center/task/ai-docs/widgets/CallControl/ → packages/contact-center/task/src/widgets/CallControl/ +packages/contact-center/task/ai-docs/widgets/IncomingTask/ → packages/contact-center/task/src/widgets/IncomingTask/ +packages/contact-center/task/ai-docs/widgets/OutdialCall/ → packages/contact-center/task/src/widgets/OutdialCall/ +packages/contact-center/task/ai-docs/widgets/TaskList/ → packages/contact-center/task/src/widgets/TaskList/ +packages/contact-center/user-state/ai-docs/ → packages/contact-center/user-state/src/ +packages/contact-center/ui-logging/ai-docs/ → packages/contact-center/ui-logging/src/ +packages/contact-center/test-fixtures/ai-docs/ → packages/contact-center/test-fixtures/src/ +widgets-samples/cc/samples-cc-react-app/ai-docs/ → widgets-samples/cc/samples-cc-react-app/src/ +... (discover all that exist on the current branch) +``` + +## Step 2: Spawn Checker Agents in Parallel + +Use the Task tool to spawn agents. **All agents run in parallel.** + +### Per-Package Checker Agents (one per ai-docs folder) + +For EACH ai-docs folder discovered, spawn one Explore agent with this prompt: + +``` +You are validating SDD documentation accuracy. + +SOURCE OF TRUTH (actual code): {source_code_directory} +DOCS TO VALIDATE: {ai_docs_folder} + +Read every markdown file in the ai-docs folder. For each document, check these 7 categories: + +### Category 1: FILE TREE +Read any documented file/directory trees in the docs. Glob the actual directory. Report: +- Files listed in docs but missing on disk +- Files on disk but missing from docs +- Wrong nesting or directory structure + +### Category 2: METHOD/API SIGNATURES +For every method, function, or API endpoint documented: +- Read the actual source file +- Verify: method name, parameter names, parameter types, return type, access modifiers (public/private/static) +- Check if method actually exists in the documented file +- Flag any param that is documented but doesn't exist, or exists but isn't documented + +### Category 3: TYPE DEFINITIONS +For every type, enum, interface, or constant documented: +- Find the actual definition in source (check package-level types files and shared types) +- Compare: name, fields/members, field types, enum values +- Flag missing fields, wrong types, renamed types + +### Category 4: EVENT NAMES +For every event constant or observable referenced: +- Find the actual definition in source +- Verify the exact name matches +- For MobX observables: verify @observable, @computed, @action decorators match docs +- For React events: verify prop callback names match + +### Category 5: ARCHITECTURE PATTERNS +For claims about architectural patterns, verify: +- MobX store patterns: Are @observable, @action, @computed correctly documented? +- React component patterns: Are props, state, lifecycle methods correct? +- Singleton vs factory: Is the instantiation pattern correct? +- Component hierarchy: Are parent-child relationships correct? +- Store injection patterns: Are MobX store injections accurately described? + +### Category 6: LINK VALIDATION +For every relative markdown link [text](path): +- Resolve the path relative to the document's location +- Verify the target file exists on disk +- For anchor links (#section), verify the heading exists in the target + +### Category 7: CODE EXAMPLES +For every inline code block or code snippet: +- Verify API names, method names, parameter names are correct +- Verify import paths are valid +- Check that documented usage patterns match actual API signatures +- Verify MobX patterns use correct decorators and patterns + +## Output Format + +For each finding, report: +- **File**: (path to the ai-docs file with the issue) +- **Line/Section**: (approximate line number or section heading) +- **Category**: (1-7 from above) +- **Severity**: + - Blocking = wrong API that would cause runtime errors if AI agent follows the docs + - Important = wrong params/types that would cause compilation errors + - Medium = incomplete or stale info that would cause confusion + - Minor = broken links, cosmetic issues +- **What doc says**: (quoted text from the doc) +- **What code actually has**: (evidence from source, with file path and line) +- **Suggested fix**: (exact replacement text) + +If no issues found in a category, state "No issues found" for that category. +``` + +### Framework Agent + +Spawn one additional Explore agent for root-level framework validation: + +``` +Validate the root-level SDD framework documents for ccWidgets: + +1. **Root AGENTS.md** (repo root AGENTS.md): + - Package Routing Table: Every package listed must exist on disk at the documented path + - Every actual package directory under packages/contact-center/ should be listed + - Task classification types must be consistent with template directories that exist + - Quick Start Workflow steps must reference files that exist + +2. **ai-docs/RULES.md**: + - Test commands: Verify documented commands are correct + - Naming conventions: Verify claims against actual code + - Pattern references: All referenced patterns should exist + +3. **ai-docs/README.md**: + - File tree must match actual ai-docs directory structure + - All referenced documents must exist + +4. **ai-docs/patterns/*.md** (mobx-patterns, react-patterns, testing-patterns, typescript-patterns): + - Each pattern file's code examples must match actual source conventions + - MobX patterns must match actual decorator usage in stores + - React patterns must match actual component patterns + - Test patterns must reference correct commands and configs + +5. **ai-docs/templates/**: + - Cross-references to AGENTS.md sections must be valid + - Referenced file paths in templates must exist + - Workflow steps must be internally consistent + +For each finding, report: +- **File**: (path) +- **Line/Section**: (section heading or line) +- **Category**: (1-7: File Tree, Method/API, Type Definition, Event Name, Architecture Pattern, Link Validation, Code Example) +- **Severity**: Blocking / Important / Medium / Minor +- **What doc says**: (quoted) +- **What code actually has**: (evidence with file:line) +- **Suggested fix**: (replacement text) +``` + +## Step 3: Consolidate Results + +After ALL agents complete, consolidate into this report format: + +```markdown +## Spec Drift Report — ccWidgets +Generated: {date} +Scanned: {N} ai-docs folders, {M} documents + +### Summary + +| ai-docs Folder | Findings | Blocking | Important | Medium | Minor | +|----------------|----------|----------|-----------|--------|-------| +| (each folder) | | | | | | +| framework | | | | | | +| **Total** | **N** | | | | | + +### Blocking Findings +(must fix — wrong APIs that would cause runtime errors if AI agent follows the docs) + +### Important Findings +(wrong params, signatures, types — would cause compilation errors) + +### Medium Findings +(incomplete info, stale file trees — would cause confusion) + +### Minor Findings +(broken links, cosmetic issues) + +### Actionable Fixes by File +(grouped by file path, each with exact old text -> new text) +``` + +## Rules + +- Do NOT auto-fix anything — report findings only +- Always read actual source code to verify — never assume +- Use the Task tool with `subagent_type: "Explore"` for all checker agents +- Run all agents in parallel for speed +- If an ai-docs folder has no corresponding source directory, flag it as a Category 1 (File Tree) finding +- Count findings by severity in the summary table diff --git a/.claude/hooks/check-ai-docs-drift.sh b/.claude/hooks/check-ai-docs-drift.sh new file mode 100755 index 000000000..aaef3c881 --- /dev/null +++ b/.claude/hooks/check-ai-docs-drift.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# PreToolUse hook: Block git commit if contact-center code/docs changed without spec-drift verification +# +# Flow: +# 1. Read stdin to get the Bash command (JSON at tool_input.command) +# 2. If command is NOT git commit -> exit 0 (allow immediately) +# 3. Check if ANY staged files are under packages/contact-center/ +# 4. If none -> exit 0 (allow) +# 5. Check for verification marker (created by /spec-drift-changed) +# 6. If marker exists -> delete it, exit 0 (allow, one-time pass) +# 7. If no marker -> exit 2 (BLOCK, instruct to run /spec-drift-changed) + +CC_PKG="packages/contact-center" + +# Read tool input from stdin (JSON with tool_input.command) +INPUT=$(cat) +COMMAND=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_input',{}).get('command',''))" 2>/dev/null) + +# Only gate git commit commands +case "$COMMAND" in + git\ commit*) ;; # Continue to check + *) exit 0 ;; # Not a commit, allow immediately +esac + +# Get staged files under the contact-center package +STAGED_CC=$(git diff --cached --name-only 2>/dev/null | grep "^${CC_PKG}/") + +if [ -z "$STAGED_CC" ]; then + exit 0 # No contact-center files staged, allow commit +fi + +# Compute hash of all staged contact-center files +HASH=$(echo "$STAGED_CC" | sort | shasum | cut -d' ' -f1) +MARKER="/tmp/.spec-drift-verified-${HASH}" + +if [ -f "$MARKER" ]; then + rm -f "$MARKER" # One-time use + exit 0 # Verified, allow commit +fi + +# Block the commit +echo "BLOCKED: contact-center files are staged but ai-docs have not been verified for spec drift." +echo "" +echo "Staged contact-center files:" +echo "$STAGED_CC" | sed 's/^/ - /' +echo "" +echo "Run /spec-drift-changed to validate ai-docs against source code before committing." +echo "The command will check documentation accuracy and create a verification marker." +exit 2 # Exit code 2 = blocking error in Claude Code hooks From 3cf0a3f6e5094239882d59ea802ebbc8dc4b600d Mon Sep 17 00:00:00 2001 From: Rankush Kumar Date: Mon, 23 Mar 2026 12:43:06 +0530 Subject: [PATCH 2/2] fix: address review comments on spec-drift tooling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Register hook in settings.json (was dead code without it) - Fail-closed when python3 unavailable or JSON parse fails - Use content-based hash (git diff --cached) instead of path-only hash - Don't consume marker in PreToolUse — invalidated naturally by content changes - Precise case pattern to avoid matching git commit-tree - Add shasum/sha256sum portability fallback - Fix "Task tool" → "Agent tool" references in command files - Add agent timeout handling rule - Add staged-only content note for verification marker - Make widget path mappings dynamic instead of hardcoded - Label inventory as example - Document advisory-only nature of verification Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/commands/spec-drift-changed.md | 25 +++++++++-------- .claude/commands/spec-drift.md | 7 +++-- .claude/hooks/check-ai-docs-drift.sh | 39 +++++++++++++++++--------- .claude/settings.json | 10 +++++++ 4 files changed, 54 insertions(+), 27 deletions(-) create mode 100644 .claude/settings.json diff --git a/.claude/commands/spec-drift-changed.md b/.claude/commands/spec-drift-changed.md index 6455ebdeb..be63b7b6c 100644 --- a/.claude/commands/spec-drift-changed.md +++ b/.claude/commands/spec-drift-changed.md @@ -37,11 +37,10 @@ packages/contact-center/task/src/widgets/CallControl/CallControl.tsx → package packages/contact-center/cc-components/src/SomeComponent.tsx → packages/contact-center/cc-components/ai-docs/ ``` -For task widget source files, map to the widget-specific ai-docs: -- `packages/contact-center/task/src/widgets/CallControl/*` → `packages/contact-center/task/ai-docs/widgets/CallControl/` -- `packages/contact-center/task/src/widgets/IncomingTask/*` → `packages/contact-center/task/ai-docs/widgets/IncomingTask/` -- `packages/contact-center/task/src/widgets/OutdialCall/*` → `packages/contact-center/task/ai-docs/widgets/OutdialCall/` -- `packages/contact-center/task/src/widgets/TaskList/*` → `packages/contact-center/task/ai-docs/widgets/TaskList/` +For task widget source files, map to the widget-specific ai-docs dynamically: +- `packages/contact-center/task/src/widgets/{WidgetName}/*` → `packages/contact-center/task/ai-docs/widgets/{WidgetName}/` (if the ai-docs folder exists) + +This covers all current and future widgets (e.g., CallControl, IncomingTask, OutdialCall, TaskList, and any new widgets added later). **Deduplicate**: If multiple source files map to the same ai-docs folder, validate that folder only once. @@ -140,22 +139,26 @@ ai-docs folders checked: {list} After presenting the validation report (regardless of findings), create a verification marker so the pre-commit hook allows the commit: ```bash -# Hash ALL staged contact-center files — must match the hook's hash logic exactly -STAGED_CC=$(git diff --cached --name-only 2>/dev/null | grep "^packages/contact-center/" | sort) +# Hash staged content (not just paths) — must match the hook's hash logic exactly +CC_PKG="packages/contact-center" +STAGED_CC=$(git diff --cached --name-only 2>/dev/null | grep "^${CC_PKG}/") if [ -n "$STAGED_CC" ]; then - HASH=$(echo "$STAGED_CC" | shasum | cut -d' ' -f1) + HASH=$(git diff --cached -- "$CC_PKG" | (shasum 2>/dev/null || sha256sum) | cut -d' ' -f1) touch "/tmp/.spec-drift-verified-${HASH}" echo "Verification marker created: /tmp/.spec-drift-verified-${HASH}" fi ``` +> **Note:** The verification marker covers only currently **staged** content. If you modify and re-stage files after verification, the content hash changes and you will need to re-run `/spec-drift-changed`. + Report to the user: "Verification marker created. The pre-commit hook will allow the next commit for these staged files." ## Rules - Do NOT auto-fix anything — report findings only - Always read actual source code to verify — never assume -- Use the Task tool with `subagent_type: "Explore"` for checker agents +- Use the Agent tool with `subagent_type: "Explore"` for checker agents - Run agents in parallel when multiple folders are affected -- Always create the verification marker at the end, even if there are findings (the developer decides whether to fix or commit as-is) -- The marker hash MUST match the hook's hash computation — both hash ALL staged `packages/contact-center/` files sorted alphabetically +- If an agent does not return within a reasonable time, note it as "Timed out — manual review needed" in the report and continue with available results +- Always create the verification marker at the end, even if there are findings — this tool is **advisory**: the developer decides whether to fix or commit as-is +- The marker hash MUST match the hook's hash computation — both use `git diff --cached` content (not just file paths) diff --git a/.claude/commands/spec-drift.md b/.claude/commands/spec-drift.md index 48a65f23a..1d5a834c1 100644 --- a/.claude/commands/spec-drift.md +++ b/.claude/commands/spec-drift.md @@ -14,7 +14,7 @@ Detect repo type and discover all ai-docs: For each ai-docs folder found, identify its corresponding source code directory (the parent directory of `ai-docs/`). -Build an inventory like: +Build an inventory (example — actual results will vary based on current branch): ``` ai-docs folder → source directory packages/contact-center/store/ai-docs/ → packages/contact-center/store/src/ @@ -34,7 +34,7 @@ widgets-samples/cc/samples-cc-react-app/ai-docs/ → widgets-sa ## Step 2: Spawn Checker Agents in Parallel -Use the Task tool to spawn agents. **All agents run in parallel.** +Use the Agent tool to spawn agents. **All agents run in parallel.** ### Per-Package Checker Agents (one per ai-docs folder) @@ -193,7 +193,8 @@ Scanned: {N} ai-docs folders, {M} documents - Do NOT auto-fix anything — report findings only - Always read actual source code to verify — never assume -- Use the Task tool with `subagent_type: "Explore"` for all checker agents +- Use the Agent tool with `subagent_type: "Explore"` for all checker agents - Run all agents in parallel for speed +- If an agent does not return within a reasonable time, note it as "Timed out — manual review needed" in the report and continue with available results - If an ai-docs folder has no corresponding source directory, flag it as a Category 1 (File Tree) finding - Count findings by severity in the summary table diff --git a/.claude/hooks/check-ai-docs-drift.sh b/.claude/hooks/check-ai-docs-drift.sh index aaef3c881..1c667d691 100755 --- a/.claude/hooks/check-ai-docs-drift.sh +++ b/.claude/hooks/check-ai-docs-drift.sh @@ -3,23 +3,37 @@ # # Flow: # 1. Read stdin to get the Bash command (JSON at tool_input.command) -# 2. If command is NOT git commit -> exit 0 (allow immediately) -# 3. Check if ANY staged files are under packages/contact-center/ -# 4. If none -> exit 0 (allow) -# 5. Check for verification marker (created by /spec-drift-changed) -# 6. If marker exists -> delete it, exit 0 (allow, one-time pass) -# 7. If no marker -> exit 2 (BLOCK, instruct to run /spec-drift-changed) +# 2. If python3 unavailable or JSON parse fails -> exit 2 (fail-closed) +# 3. If command is NOT git commit -> exit 0 (allow immediately) +# 4. Check if ANY staged files are under packages/contact-center/ +# 5. If none -> exit 0 (allow) +# 6. Check for verification marker (created by /spec-drift-changed) +# 7. If marker exists -> exit 0 (allow — marker stays until content changes) +# 8. If no marker -> exit 2 (BLOCK, instruct to run /spec-drift-changed) CC_PKG="packages/contact-center" +# Ensure python3 is available +if ! command -v python3 >/dev/null 2>&1; then + echo "ERROR: python3 is required for the spec-drift pre-commit hook but was not found." + echo "Install python3 or remove this hook from .claude/settings.json to proceed." + exit 2 +fi + # Read tool input from stdin (JSON with tool_input.command) INPUT=$(cat) COMMAND=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_input',{}).get('command',''))" 2>/dev/null) -# Only gate git commit commands +# Fail-closed: if we couldn't parse the command, block rather than silently allow +if [ -z "$COMMAND" ]; then + echo "ERROR: Could not parse tool input. Blocking commit as a safety measure." + exit 2 +fi + +# Only gate git commit commands (precise match to avoid catching git commit-tree, etc.) case "$COMMAND" in - git\ commit*) ;; # Continue to check - *) exit 0 ;; # Not a commit, allow immediately + "git commit"|git\ commit\ *) ;; # Continue to check + *) exit 0 ;; # Not a commit, allow immediately esac # Get staged files under the contact-center package @@ -29,13 +43,12 @@ if [ -z "$STAGED_CC" ]; then exit 0 # No contact-center files staged, allow commit fi -# Compute hash of all staged contact-center files -HASH=$(echo "$STAGED_CC" | sort | shasum | cut -d' ' -f1) +# Compute hash from staged content (not just paths) to detect re-staged changes +HASH=$(git diff --cached -- "$CC_PKG" | (shasum 2>/dev/null || sha256sum) | cut -d' ' -f1) MARKER="/tmp/.spec-drift-verified-${HASH}" if [ -f "$MARKER" ]; then - rm -f "$MARKER" # One-time use - exit 0 # Verified, allow commit + exit 0 # Verified, allow commit (marker stays — invalidated naturally when content changes) fi # Block the commit diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 000000000..1a0518cfd --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,10 @@ +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [".claude/hooks/check-ai-docs-drift.sh"] + } + ] + } +}