#!/usr/bin/env node /** * Prohibited Terms Scanner - Enforces inst_016, inst_017, inst_018 * * Scans files for prohibited language that violates governance rules */ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); // inst_017: Prohibited absolute assurance terms const PROHIBITED_ABSOLUTE_TERMS = [ /\bguarantee(s|d)?\b/i, /\bensures?\s+(100%|complete|total|absolute)/i, /\beliminates?\s+all\b/i, /\bcompletely\s+(prevents?|eliminates?|removes?)\b/i, /\bnever\s+fails?\b/i, /\b100%\s+(safe|secure|reliable|accurate)\b/i, /\babsolutely\s+(prevents?|guarantees?)\b/i ]; // inst_018: Prohibited maturity claims without evidence const PROHIBITED_MATURITY_CLAIMS = [ /\b(production-ready|battle-tested|enterprise-proven)\b/i, /\bvalidated\s+by\s+\d+\s+(companies|organizations|teams)\b/i, /\bwidely\s+adopted\b/i, /\bmarket\s+(leader|validated)\b/i, /\bcustomer\s+base\s+of\b/i ]; // inst_016: Requires citation or [NEEDS VERIFICATION] const STATS_PATTERNS = [ /\d+%\s+(improvement|increase|reduction|faster|better)/i, /\d+x\s+(faster|better|more)/i, /ROI\s+of\s+\d+/i, /reduces?\s+(cost|time|effort)\s+by\s+\d+/i ]; function checkFile(filePath) { const content = fs.readFileSync(filePath, 'utf8'); const lines = content.split('\n'); const violations = []; lines.forEach((line, idx) => { const lineNum = idx + 1; // Check inst_017: Absolute assurance terms PROHIBITED_ABSOLUTE_TERMS.forEach(pattern => { if (pattern.test(line)) { violations.push({ file: filePath, line: lineNum, type: 'inst_017', severity: 'HIGH', text: line.trim(), rule: 'Prohibited absolute assurance term detected' }); } }); // Check inst_018: Maturity claims PROHIBITED_MATURITY_CLAIMS.forEach(pattern => { if (pattern.test(line)) { violations.push({ file: filePath, line: lineNum, type: 'inst_018', severity: 'HIGH', text: line.trim(), rule: 'Prohibited maturity claim without evidence' }); } }); // Check inst_016: Statistics without citation STATS_PATTERNS.forEach(pattern => { if (pattern.test(line)) { // Check if line has citation or [NEEDS VERIFICATION] if (!line.includes('[') && !line.includes('(source:') && !line.includes('Citation:')) { violations.push({ file: filePath, line: lineNum, type: 'inst_016', severity: 'MEDIUM', text: line.trim(), rule: 'Statistic without citation or [NEEDS VERIFICATION] marker' }); } } }); }); return violations; } function scanFiles(files) { const allViolations = []; files.forEach(file => { if (!fs.existsSync(file)) return; // Skip instruction-history.json (contains prohibited term DEFINITIONS, not violations) if (file.includes('instruction-history.json')) return; // Only scan text files (markdown, HTML, text) const ext = path.extname(file).toLowerCase(); if (!['.md', '.html', '.txt', '.json'].includes(ext)) return; const violations = checkFile(file); allViolations.push(...violations); }); return allViolations; } function main() { const args = process.argv.slice(2); let files = []; if (args.length === 0) { // Scan staged git files try { const staged = execSync('git diff --cached --name-only --diff-filter=ACM', { encoding: 'utf8' }); files = staged.trim().split('\n').filter(f => f.length > 0); } catch (err) { console.error('Not in a git repository or no staged files'); process.exit(0); } } else { files = args; } if (files.length === 0) { console.log('āœ… No files to scan'); process.exit(0); } console.log(`\nšŸ” Scanning ${files.length} file(s) for prohibited terms...\n`); const violations = scanFiles(files); if (violations.length === 0) { console.log('āœ… No prohibited terms detected\n'); process.exit(0); } // Report violations console.log(`āŒ Found ${violations.length} violation(s):\n`); console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'); violations.forEach(v => { console.log(`${v.severity === 'HIGH' ? 'šŸ”“' : '🟔'} ${v.file}:${v.line}`); console.log(` Rule: ${v.type} - ${v.rule}`); console.log(` Text: ${v.text.substring(0, 80)}${v.text.length > 80 ? '...' : ''}`); console.log(''); }); console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'); console.log('Fix violations before committing/deploying:\n'); console.log(' inst_016: Add citation or [NEEDS VERIFICATION] to statistics'); console.log(' inst_017: Replace absolute terms with evidence-based language'); console.log(' inst_018: Remove maturity claims or add documented evidence\n'); process.exit(1); } main();