fix(governance): add architectural enforcement for "ff" and "ffs" trigger words
Problem: Claude failed to recognize "ffs" code word despite inst_082 being active. Root cause: No architectural enforcement to check for trigger words on every user message. Solution: - Created .claude/hooks/trigger-word-checker.js that runs on UserPromptSubmit - Detects "ffs" → instructs to run framework-stats.js (inst_082) - Detects "ff " prefix → instructs to run framework-audit-response.js (inst_078) - Registered hook in .claude/settings.json Testing: ✅ "ffs" detection works correctly ✅ "ff " prefix detection works correctly ✅ Normal messages pass through silently Philosophy: Governance enforced architecturally, not by voluntary compliance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
4e5fc013af
commit
3009e4942f
3 changed files with 133 additions and 0 deletions
34
.claude/hooks/trigger-word-checker.js
Executable file
34
.claude/hooks/trigger-word-checker.js
Executable file
|
|
@ -0,0 +1,34 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Trigger Word Checker Hook
|
||||||
|
*
|
||||||
|
* Detects "ff" and "ffs" code words in user prompts and provides
|
||||||
|
* immediate instruction to Claude on how to handle them.
|
||||||
|
*
|
||||||
|
* This runs on EVERY user message to ensure triggers are never missed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const input = JSON.parse(process.argv[2] || '{}');
|
||||||
|
const userMessage = input.text || '';
|
||||||
|
|
||||||
|
// Normalize: trim whitespace, lowercase for matching
|
||||||
|
const normalized = userMessage.trim().toLowerCase();
|
||||||
|
|
||||||
|
// Check for "ffs" trigger (exact match or standalone word)
|
||||||
|
if (normalized === 'ffs' || /\bffs\b/.test(normalized)) {
|
||||||
|
console.log('\x1b[33m⚠️ CODE WORD DETECTED: "ffs"\x1b[0m');
|
||||||
|
console.log('\x1b[36mClaude MUST run: node scripts/framework-stats.js\x1b[0m');
|
||||||
|
console.log('\x1b[36mSee inst_082 and CLAUDE.md lines 66-88\x1b[0m');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for "ff" prefix trigger
|
||||||
|
if (normalized.startsWith('ff ')) {
|
||||||
|
console.log('\x1b[33m⚠️ CODE WORD DETECTED: "ff"\x1b[0m');
|
||||||
|
console.log('\x1b[36mClaude MUST run: node scripts/framework-audit-response.js --prompt "..." --type "boundary_question"\x1b[0m');
|
||||||
|
console.log('\x1b[36mSee inst_078 and CLAUDE.md lines 48-64\x1b[0m');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No trigger words found - continue normally
|
||||||
|
process.exit(0);
|
||||||
|
|
@ -11,6 +11,17 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"UserPromptSubmit": [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/trigger-word-checker.js",
|
||||||
|
"timeout": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
88
docs/TRIGGER_WORD_ENFORCEMENT.md
Normal file
88
docs/TRIGGER_WORD_ENFORCEMENT.md
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
# Trigger Word Enforcement Architecture
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
Claude failed to recognize "ffs" code word despite inst_082 being active. This was a **trigger recognition failure**, not a missing instruction issue.
|
||||||
|
|
||||||
|
## Root Cause
|
||||||
|
- inst_082 (ffs trigger) exists and is marked active: true
|
||||||
|
- inst_078 (ff trigger) exists and is marked active: true
|
||||||
|
- Both are HIGH persistence, SYSTEM quadrant
|
||||||
|
- scripts/framework-stats.js and scripts/framework-audit-response.js both exist
|
||||||
|
- **BUT**: No architectural enforcement to ensure Claude checks for trigger words on EVERY user message
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
Created `.claude/hooks/trigger-word-checker.js` that runs on every user prompt submission:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Detects:
|
||||||
|
// - "ffs" (exact match or word boundary) → framework-stats.js
|
||||||
|
// - "ff " (prefix) → framework-audit-response.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Registered in `.claude/settings.json`:
|
||||||
|
```json
|
||||||
|
"UserPromptSubmit": [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/trigger-word-checker.js",
|
||||||
|
"timeout": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. **User types "ffs"**
|
||||||
|
2. Hook runs BEFORE Claude processes the message
|
||||||
|
3. Hook outputs: `⚠️ CODE WORD DETECTED: "ffs"`
|
||||||
|
4. Hook provides instruction: `Claude MUST run: node scripts/framework-stats.js`
|
||||||
|
5. Claude sees the hook output and executes the command
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test ffs trigger
|
||||||
|
node .claude/hooks/trigger-word-checker.js '{"text":"ffs"}'
|
||||||
|
# Output: ⚠️ CODE WORD DETECTED: "ffs"
|
||||||
|
# Claude MUST run: node scripts/framework-stats.js
|
||||||
|
|
||||||
|
# Test ff trigger
|
||||||
|
node .claude/hooks/trigger-word-checker.js '{"text":"ff what are the boundary rules?"}'
|
||||||
|
# Output: ⚠️ CODE WORD DETECTED: "ff"
|
||||||
|
# Claude MUST run: node scripts/framework-audit-response.js --prompt "..." --type "boundary_question"
|
||||||
|
|
||||||
|
# Test normal message (no output)
|
||||||
|
node .claude/hooks/trigger-word-checker.js '{"text":"please fix the bug"}'
|
||||||
|
# (silent - no trigger detected)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Philosophy
|
||||||
|
**Governance is enforced architecturally, not documented.**
|
||||||
|
|
||||||
|
Relying on voluntary compliance (Claude remembering to check for triggers) = framework fade.
|
||||||
|
Architectural enforcement (hook that runs on EVERY message) = reliable governance.
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
- `.claude/hooks/trigger-word-checker.js` - New hook script
|
||||||
|
- `.claude/settings.json` - Registered UserPromptSubmit hook
|
||||||
|
|
||||||
|
## References
|
||||||
|
- inst_082: ffs trigger definition
|
||||||
|
- inst_078: ff trigger definition
|
||||||
|
- CLAUDE.md lines 48-64: ff documentation
|
||||||
|
- CLAUDE.md lines 66-88: ffs documentation
|
||||||
|
|
||||||
|
## Future Enhancements
|
||||||
|
If Claude Code doesn't support UserPromptSubmit hooks natively:
|
||||||
|
1. Add to session-init.js output as prominent reminder
|
||||||
|
2. Create a PreToolUse hook that checks user's last message
|
||||||
|
3. Add to system prompt injection if hook system insufficient
|
||||||
|
|
||||||
|
---
|
||||||
|
**Created**: 2025-10-25
|
||||||
|
**Issue**: Claude didn't recognize "ffs" code word
|
||||||
|
**Fix**: Architectural hook enforcement
|
||||||
Loading…
Add table
Reference in a new issue