Skip to content

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:

  1. Makor Attribution: All normative rules have source citations
  2. Valid Predicates: Only registered predicates are used
  3. Valid Worlds: Only defined worlds are referenced
  4. 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:

{
  "continue": true,
  "message": "Encoding guard: Validation passed\n   Rules: 5, Worlds: 3"
}

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:

VALID_WORLDS = {
    "base", "mechaber", "rema", "gra",
    "sefardi_yo", "ashk_mb", "ashk_ah"
}

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:

VALID_MADREGA = {"d_oraita", "d_rabanan", "minhag", "chumra"}

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
}