Encoding Guard Hook¶
The encoding-guard hook validates HLL (Halachic Logic Language) content before allowing writes to ontology files, ensuring all rules have proper makor attribution and valid syntax.
Overview¶
| Attribute | Value |
|---|---|
| Hook Name | encoding-guard |
| Script | hooks/scripts/encoding-guard.py |
| Event | PreToolUse |
| Matcher | Write |
| Blocking | Yes (when validation fails) |
| Timeout | 5000ms |
Purpose¶
The encoding guard ensures:
- Makor Attribution: All normative rules have source citations
- Valid Predicates: Only registered predicates are used
- Valid Worlds: Only defined worlds are referenced
- Syntax Correctness: Basic ASP syntax validation
Configuration¶
In hooks/hooks.json:
{
"PreToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "python ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/encoding-guard.py \"$TOOL_INPUT\"",
"timeout": 5000
}
]
}
]
}
Behavior¶
Validation Passed¶
When all checks pass:
Validation Failed¶
When issues are found:
{
"continue": false,
"message": "BLOCKED: HLL Encoding Validation Failed\n\nFile: mistaber/ontology/corpus/yd_87/base.lp\n\nIssues Found:\n - Rule 'r_bb_dag_sakana' uses normative predicate but has no makor\n - Unknown world referenced: 'mechaver'\n\nPlease fix these issues before writing the file.\n\nEncoding Requirements:\n- All normative rules must have @makor attribution\n- All worlds must be valid (base, mechaber, rema, etc.)\n- All predicates must exist in the registry"
}
Validation Checks¶
1. Normative Predicate Makor Check¶
Rules using normative predicates must have makor attribution:
Normative Predicates:
| Predicate | Arity | Description |
|---|---|---|
issur |
3 | Prohibition |
heter |
2 | Permission |
chiyuv |
3 | Obligation |
sakana |
1 | Danger |
Implementation:
NORMATIVE_PREDICATES = {
"issur": 3,
"heter": 2,
"chiyuv": 3,
"sakana": 1,
}
def check_normative_predicates(content: str) -> list[str]:
"""Check that normative predicates have associated makor."""
issues = []
for pred, arity in NORMATIVE_PREDICATES.items():
pattern = rf'asserts\([^,]+,\s*{pred}\([^)]+\)\)'
matches = re.findall(pattern, content)
if matches:
rules = extract_rules_from_content(content)
makor_rules = extract_makor_rules(content)
for rule in rules:
if rule not in makor_rules:
issues.append(
f"Rule '{rule}' uses normative predicate but has no makor"
)
return issues
Example:
% BLOCKED - no makor
rule(r_bb_dag_sakana).
asserts(mechaber, sakana(M)) :- is_dag_chalav_mixture(M).
% ALLOWED - has makor
rule(r_bb_dag_sakana).
makor(r_bb_dag_sakana, sa("yd:87:3")).
asserts(mechaber, sakana(M)) :- is_dag_chalav_mixture(M).
2. World Validation¶
All referenced worlds must be in the valid set:
Valid Worlds:
Implementation:
def validate_worlds(content: str) -> list[str]:
"""Validate that all referenced worlds exist."""
issues = []
used_worlds = extract_used_worlds(content)
for world in used_worlds:
if world not in VALID_WORLDS:
issues.append(f"Unknown world referenced: '{world}'")
return issues
def extract_used_worlds(content: str) -> set[str]:
"""Extract worlds referenced in asserts/override predicates."""
pattern = r'(?:asserts|override)\(([a-z_]+),'
return set(re.findall(pattern, content))
Example:
% BLOCKED - typo in world name
asserts(mechaver, sakana(M)) :- ... % Should be 'mechaber'
% ALLOWED - valid world
asserts(mechaber, sakana(M)) :- ...
3. Madrega Validation¶
Madrega levels must be valid:
Valid Levels:
4. Syntax Validation¶
Basic ASP syntax is checked:
def validate_syntax(content: str) -> list[str]:
"""Basic syntax validation."""
issues = []
lines = content.split('\n')
for i, line in enumerate(lines, 1):
line = line.strip()
# Skip comments and empty lines
if not line or line.startswith('%'):
continue
# Skip includes and show directives
if line.startswith('#'):
continue
# Check for common syntax errors
# (Implementation details)
return issues
File Filtering¶
Only Ontology Files¶
The hook only validates .lp files in the ontology:
def is_ontology_lp_file(file_path: str) -> bool:
"""Check if file is an ontology .lp file."""
path = Path(file_path)
return (
path.suffix == ".lp" and
"ontology" in str(path)
)
Validated:
- mistaber/ontology/corpus/yd_87/base.lp
- mistaber/ontology/worlds/mechaber.lp
Not Validated:
- tests/test_data/example.lp
- mistaber/dsl/examples/demo.lp
Rule Extraction¶
Extract Rule IDs¶
def extract_rules_from_content(content: str) -> list[str]:
"""Extract rule IDs declared in content."""
pattern = r'rule\(([a-z_0-9]+)\)'
return re.findall(pattern, content)
Extract Makor Rules¶
def extract_makor_rules(content: str) -> set[str]:
"""Extract rule IDs that have makor declarations."""
pattern = r'makor\(([a-z_0-9]+),'
return set(re.findall(pattern, content))
Extract Madrega Rules¶
def extract_madrega_rules(content: str) -> set[str]:
"""Extract rule IDs that have madrega declarations."""
pattern = r'madrega\(([a-z_0-9]+),'
return set(re.findall(pattern, content))
Error Messages¶
Missing Makor¶
BLOCKED: HLL Encoding Validation Failed
File: mistaber/ontology/corpus/yd_87/base.lp
Issues Found:
- Rule 'r_bb_dag_sakana' uses normative predicate but has no makor
Please fix these issues before writing the file.
Encoding Requirements:
- All normative rules must have @makor attribution
- All worlds must be valid (base, mechaber, rema, etc.)
- All predicates must exist in the registry
Unknown World¶
BLOCKED: HLL Encoding Validation Failed
File: mistaber/ontology/worlds/mechaber.lp
Issues Found:
- Unknown world referenced: 'mechaver'
Please fix these issues before writing the file.
Multiple Issues¶
BLOCKED: HLL Encoding Validation Failed
File: mistaber/ontology/corpus/yd_87/base.lp
Issues Found:
- Rule 'r_bb_dag_sakana' uses normative predicate but has no makor
- Rule 'r_bb_achiila' uses normative predicate but has no makor
- Unknown world referenced: 'mechaver'
- Unknown world referenced: 'rema_world'
Please fix these issues before writing the file.
Implementation Flow¶
graph TD
A[Write Tool Called] --> B{Is ontology .lp?}
B -->|No| C[Allow Write]
B -->|Yes| D[Parse Content]
D --> E[Check Normative Predicates]
E --> F[Check World References]
F --> G[Check Syntax]
G --> H{Issues Found?}
H -->|No| I[Allow Write]
H -->|Yes| J[Block with Message]
Valid Content Example¶
% mistaber/ontology/corpus/yd_87/base.lp
% This content passes all validation
% Rule declaration
rule(r_bb_dag_sakana).
% Makor attribution (required for normative predicates)
makor(r_bb_dag_sakana, sa("yd:87:3")).
% Madrega level
madrega(r_bb_dag_sakana, sakana).
% Scope declaration
scope(r_bb_dag_sakana, mechaber).
% The rule itself (uses valid world 'mechaber')
asserts(mechaber, sakana(M)) :-
is_dag_chalav_mixture(M).
Debugging¶
Manual Testing¶
# Test valid content
cat > /tmp/test.lp << 'EOF'
rule(r_test).
makor(r_test, sa("yd:1:1")).
asserts(base, issur(X, Y, Z)) :- test(X).
EOF
echo '{"file_path": "mistaber/ontology/corpus/yd_1/test.lp", "content": "'"$(cat /tmp/test.lp)"'"}' | \
python mistaber-skills/hooks/scripts/encoding-guard.py | jq .
# Test invalid content (missing makor)
cat > /tmp/test.lp << 'EOF'
rule(r_test).
asserts(base, issur(X, Y, Z)) :- test(X).
EOF
echo '{"file_path": "mistaber/ontology/corpus/yd_1/test.lp", "content": "'"$(cat /tmp/test.lp)"'"}' | \
python mistaber-skills/hooks/scripts/encoding-guard.py | jq .
Check Specific Validation¶
# Check what rules are extracted
python3 << 'EOF'
import re
content = '''
rule(r_bb_dag_sakana).
rule(r_bb_achiila).
'''
pattern = r'rule\(([a-z_0-9]+)\)'
print("Rules:", re.findall(pattern, content))
EOF
Common Issues¶
False Positive: Rule Not Normative¶
Symptom: Rule blocked but isn't using normative predicate.
Solution: Check if rule uses asserts with normative predicate. Definition rules may not need makor.
World Name Typo¶
Symptom: "Unknown world" for valid world.
Solution: Check spelling against VALID_WORLDS set. Common typos:
- mechaver -> mechaber
- rema_world -> rema
Content Not Detected¶
Symptom: Validation not running.
Solution: Verify file path contains "ontology" and ends with ".lp".
Extending the Hook¶
Adding New Predicates¶
To add a new normative predicate:
NORMATIVE_PREDICATES = {
"issur": 3,
"heter": 2,
"chiyuv": 3,
"sakana": 1,
"new_predicate": 2, # Add here
}
Adding New Worlds¶
To add a new valid world:
VALID_WORLDS = {
"base", "mechaber", "rema", "gra",
"sefardi_yo", "ashk_mb", "ashk_ah",
"new_world", # Add here
}
Related Documentation¶
- Hooks Overview - All hooks
- Phase Gate - Workflow enforcement
- HLL Language Reference - HLL syntax
- Predicate Registry - Available predicates