
optimize-readability-system
by leolovenet
unmangleJS is a human-readability heuristic JavaScript deobfuscator built on Babel + TypeScript, with a multi-pass processing model.
SKILL.md
name: optimize-readability-system description: "Interactive guide for tuning the unmangleJS Readability Scoring System(readability.ts) and Semantic Scoring System (semantic.ts). Use when Golden Set validation fails, when scoring heuristics need adjustment, or when improving obfuscation detection accuracy. Emphasizes experiment-driven development: run tests, analyze data, draw conclusions - never guess blindly."
Optimize Readability/Semantic Scoring System
Interactive guide for tuning the unmangleJS scoring systems.
Core Philosophy
"Do experiments, get data, draw conclusions. Don't guess blindly."
This is the golden rule for all optimization work.
System Overview
1. Semantic Scoring (src/utils/semantic.ts)
Analyzes names and structures for semantic meaning.
Key Functions:
scoreKeySemantic(key)- Score a single identifier (0-2.5 average)getSemanticThreshold(keyLength)- Get length-based threshold (1.0-1.5)isObjectSemantic()/isSubjectSemantic()- Judge semantic content
2. Readability Scoring (src/utils/readability.ts)
Decides whether to simplify AST subtrees.
7 Signals:
semantic-*(5 signals, veto: true) - Protect semantic contentcognitive-density- Cognitive load (0-1)linearity-violation- Linearity (0-1)
Decision Rules:
- Semantic Veto - One-vote veto power
- Dual Confirmation - cognitive < 0.4 AND linearity < 0.4
- Average Fallback - threshold: 0.5
3. Golden Set (tests/readability/golden/)
Constitutional test suite defining system values.
should-simplify.json- Obfuscated samples (must simplify)should-not-simplify.json- Semantic samples (must preserve)- Success metric: 100% pass rate (excluding
undecided)
When to Use This Skill
Scenario A: Golden Set Already Failing
Current state: Golden Set validation fails
Action: Use this skill directly to diagnose and fix
Scenario B: Adding New Samples
Current state: Golden Set passes, but found edge case
Action: Follow "Adding New Samples" flow below
Scenario C: New Sample Causes Failure
Current state: Golden Set passes → Add sample → Fails
Action: Use this skill starting from Step 2 (Analyze Failures)
Optimization Workflow
Step 1: Run Golden Set
npm test -- tests/readability/golden.test.ts
Expected: 50/50 passed (100%)
If failing → Continue to Step 2
Step 2: Analyze Failures
Use professional analysis tools (DO NOT write temporary scripts):
Tool 1: readability-analyzer.js
Purpose: Analyze code and output detailed readability scoring reports
Usage:
# Build first
npm run build
# Analyze a file
node tools/readability-analyzer.js <file>
# From stdin
echo 'const x = { a: 1 };' | node tools/readability-analyzer.js
# NEW: Filter by node type
node tools/readability-analyzer.js <file> --types SequenceExpression
node tools/readability-analyzer.js <file> -t seq,obj,cond # Multiple types
node tools/readability-analyzer.js --list-types # Show available types
Output:
- Part 1: Decision Summary (should simplify? yes/no, threshold check)
- Part 2: All Signals (cognitive-density, linearity-violation, semantic-*)
- Part 3: Veto Check (which signal triggered veto)
- Part 4: Decision Logic (which rules passed/failed)
When to use:
- Any Golden Set test failure
- Debugging
shouldSimplify()behavior - Understanding why veto was triggered
Tool 2: semantic-analyzer.js
Purpose: Analyze semantic structures (Object, Array, Function, Variable)
Usage:
npm run build
node tools/semantic-analyzer.js <file>
echo 'const obj = { a: 1 };' | node tools/semantic-analyzer.js
# NEW: Filter by node type
node tools/semantic-analyzer.js <file> --types ObjectExpression
node tools/semantic-analyzer.js <file> -t obj,arr,var # Multiple types
node tools/semantic-analyzer.js --list-types # Show available types
Supported Node Types:
- ObjectExpression - 4-part analysis
- ArrayExpression - 2-part analysis
- Function (Declaration/Expression/Arrow) - 2-part analysis
- VariableDeclarator - 2-part analysis (simple + destructuring)
When to use:
- Object/array/function/variable semantic analysis
- Debugging
isSubjectSemantic()behavior - Checking individual scores with dynamic thresholds
Step 3: Answer Key Questions
For each failing sample:
- Which signals are causing the wrong decision?
- Are semantic signals vetoing correctly?
- Is cognitive/linearity score appropriate?
- For semantic nodes: Are individual name scores correct?
Step 4: Form Hypothesis
Based on data, form a specific hypothesis.
Examples:
- "Short obfuscated names score too high because entropy threshold is too lenient"
- "Object linearity scores (0.9) prevent deletion, should be 0.3"
Step 5: Test with CLI
CRITICAL: Always test with real CLI behavior.
# Test obfuscated pattern
cat > tmp/test.js << 'EOF'
const _0x1 = { UoAwJ: "x", YXLlx: "y" };
EOF
./bin/unmanglejs.js tmp/test.js -p
# Expected: Object should be inlined
# Test semantic pattern
cat > tmp/test2.js << 'EOF'
const config = { UNKNOWN: 0, OK: 1 };
EOF
./bin/unmanglejs.js tmp/test2.js -p
# Expected: Object should be preserved
Interpret Results:
- Obfuscated code NOT transformed → False negative (too conservative)
- Semantic code IS transformed → False positive (too aggressive)
Step 6: Apply Minimal Fix
Change one thing at a time. Validate after each change.
Example fixes:
// Fix 1: Adjust entropy threshold
let threshold: number;
if (key.length <= 4) threshold = 2.5; // Very strict
else if (key.length <= 6) threshold = 3.0; // Strict
else threshold = 3.5; // Normal
// Fix 2: Add semantic shield check
if (t.isCallExpression(expr) && t.isIdentifier(expr.callee)) {
const score = scoreKeySemantic(expr.callee.name);
if (score.average >= 1.5) semanticCount++;
}
// Fix 3: Add obfuscation penalty
if (metrics.semanticRatio < 0.3 && metrics.distinctIdentifiers >= 2) {
score -= 0.3;
}
Step 7: Validate Full Suite
npm test
# Expected: All tests passing
Common Issues
Issue: Golden Set < 100% Pass Rate
Diagnosis:
- Run tools on failing samples
- Categorize: too conservative OR too aggressive
- Identify root cause
Common Fixes:
- Too conservative → Raise threshold, add penalties
- Too aggressive → Lower threshold, strengthen veto
Issue: Semantic Names Not Protected
Symptom: if(initialize(), validate()) gets flattened
Root Cause: Semantic shield missing pattern OR names score below threshold
Fix: Add missing pattern check (see Step 6 examples)
Issue: Short Obfuscated Names Score High
Symptom: { UoAwJ: "x" } scores 1.25 (semantic!)
Root Cause: Short names have naturally low entropy
Fix: Use stricter thresholds for short keys (see Step 6 examples)
Issue: Object Linearity Too High
Symptom: Objects score 0.9 linearity, preventing deletion
Fix: Object linearity shouldn't affect deletion
if (path.isObjectExpression()) {
return 0.3; // Low score = "linearity doesn't apply"
}
Issue: Pass Behavior Differs by Context
Symptom: for(a=1, b=2) behaves differently than if(a(), b())
Explanation: Some passes don't extract from certain parent contexts by design
Fix: Understand pass behavior first, don't assume uniform behavior
Golden Set Management
Adding New Samples
When you encounter a new edge case:
Step 1: Validate current state (100% pass)
Step 2: Test new sample with tools
npm run build
node tools/readability-analyzer.js tmp/new-sample.js
Step 3: Categorize
- Clearly obfuscated →
should-simplify.json - Clearly semantic →
should-not-simplify.json - Ambiguous → Mark as
"expected": "undecided"
Step 4: Add to appropriate file
cat >> tests/readability/golden/should-simplify.json << 'EOF'
{
"id": "descriptive-id",
"code": "const x = <obfuscated code>;",
"expected": true,
"invariant": false,
"reason": "obfuscated pattern description"
}
EOF
Step 5: Validate
npm test -- tests/readability/golden.test.ts
If tests pass: Done ✅
If tests fail: New sample revealed system defect → Use optimization workflow to fix
Invariant Levels
invariant: true- System-defining values, should never changeinvariant: false- Heuristic cases, can evolveexpected: "undecided"- Ambiguous boundary cases
Best Practices
1. Experiment-Driven Development
ALWAYS:
- Run tests first
- Use professional tools for analysis
- Identify specific failures
- Form hypothesis
- Test with CLI
- Apply minimal fix
- Validate all tests
NEVER:
- ❌ Guess what the issue might be
- ❌ Tune thresholds without data
- ❌ Write temporary scripts when tools are available
- ❌ Make broad changes for specific failures
2. Keep Tools in Sync
When modifying semantic.ts or readability.ts, update analysis tools:
- Adding new signals → Update
readability-analyzer.js - Adding new semantic functions → Update
semantic-analyzer.js - Changing thresholds → Update tool output and docs
Test tools after changes:
npm run build
echo 'const x = { a: 1 };' | node tools/semantic-analyzer.js
3. Minimal Diff Principle
- Change one thing at a time
- Validate after each change
- Keep changelog of what worked
Quick Reference
Key Files
Source:
src/utils/semantic.ts- Semantic scoringsrc/utils/readability.ts- Readability decision
Tests:
tests/readability/golden/*.json- Golden Set samplestests/readability/golden.test.ts- Validator
Tools:
tools/readability-analyzer.js- Readability analysistools/semantic-analyzer.js- Semantic analysis
Key Constants
// readability.ts
const DEFAULT_THRESHOLD = 0.5;
const COGNITIVE_CONFIRM = 0.4;
const LINEARITY_CONFIRM = 0.4;
// semantic.ts - Dynamic thresholds
function getSemanticThreshold(keyLength: number): number {
if (keyLength <= 3) return 1.0; // Very short
if (keyLength <= 5) return 1.25; // Short
if (keyLength <= 7) return 1.4; // Medium
return 1.5; // Standard
}
// semantic.ts - Fixed thresholds
const OBJECT_SEMANTIC_THRESHOLD = 1.4;
Common Commands
# Build (required before using tools)
npm run build
# Run Golden Set
npm test -- tests/readability/golden.test.ts
# Run all tests
npm test
# Analysis tools
node tools/readability-analyzer.js <file>
node tools/semantic-analyzer.js <file>
# With type filtering
node tools/readability-analyzer.js <file> -t seq,obj
node tools/semantic-analyzer.js <file> -t obj,arr,var
# List available types
node tools/readability-analyzer.js --list-types
node tools/semantic-analyzer.js --list-types
Tool Type Filters
readability-analyzer:
SequenceExpression(seq, sequence)ObjectExpression(obj, object)ConditionalExpression(cond, conditional)Identifier(id, identifier)
semantic-analyzer:
ObjectExpression(obj, object)ArrayExpression(arr, array)FunctionDeclaration(func-decl)FunctionExpression(func-expr)ArrowFunctionExpression(arrow)VariableDeclarator(var, variable)
Success Metrics
- Golden Set: 50/50 passed (100%)
- All tests: 976/976 passing
- Zero false positives (semantic protected)
- Minimal false negatives (obfuscated caught)
Summary
Golden Rule: Do experiments, get data, draw conclusions.
Key Principles:
- Always start with Golden Set validation
- Use professional tools for analysis
- Apply minimal, targeted fixes
- Validate with full test suite
- Keep tools in sync with implementation
Remember:
- The system is heuristic, not a correctness engine
- Golden Set is the constitution
- Veto provides precision, scoring provides recall
- Context matters - test in real scenarios
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon