Skip to content

Phase Gate Hook

The phase-gate hook prevents out-of-order writes to ontology files by verifying the appropriate checkpoint has been approved before allowing file modifications.

Overview

Attribute Value
Hook Name phase-gate
Script hooks/scripts/phase-gate.py
Event PreToolUse
Matcher Write|Edit
Blocking Yes (when checkpoint not approved)
Timeout 5000ms

Purpose

The phase gate hook ensures:

  1. Workflow Order: Encoding cannot proceed without corpus approval
  2. Session Tracking: Active session must exist before writing ontology files
  3. Checkpoint Enforcement: Each phase requires explicit human approval

Configuration

In hooks/hooks.json:

{
  "PreToolUse": [
    {
      "matcher": "Write|Edit",
      "hooks": [
        {
          "type": "command",
          "command": "python ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/phase-gate.py \"$TOOL_INPUT\"",
          "timeout": 5000
        }
      ]
    }
  ]
}

Behavior

Allowed Operations

The hook allows writes when:

  1. File is NOT an ontology .lp file
  2. File is an ontology file AND required checkpoint is approved
{
  "continue": true,
  "message": "Phase gate: corpus-prep approved, write allowed"
}

Blocked: No Active Session

When no .mistaber-session.yaml exists:

{
  "continue": false,
  "message": "BLOCKED: No Active Encoding Session\n\nCannot write to ontology file: mistaber/ontology/corpus/yd_87/base.lp\n\nYou must start an encoding session first:\n1. Invoke the corpus-prep skill\n2. Complete corpus preparation\n3. Get human approval at checkpoint\n\nStart with: \"Prepare corpus for YD {siman}:{seif}\""
}

Blocked: Checkpoint Not Approved

When required checkpoint is not approved:

{
  "continue": false,
  "message": "BLOCKED: Checkpoint Not Approved\n\nCannot write to: mistaber/ontology/corpus/yd_87/seif_3.lp\n\nRequired checkpoint: corpus-prep\nCurrent status: pending_review\n\nThe encoding workflow requires human approval at each checkpoint.\nComplete the corpus-prep phase and get approval before proceeding."
}

File Pattern Detection

Ontology File Detection

def is_ontology_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) and
        "corpus" in str(path)
    )

Matches: - mistaber/ontology/corpus/yd_87/base.lp - mistaber/ontology/corpus/yd_88/seif_1.lp

Does NOT Match: - mistaber/ontology/worlds/mechaber.lp (worlds, not corpus) - tests/test_data/example.lp (not in ontology) - mistaber/ontology/corpus/manifest.yaml (not .lp)

Seif File Detection

def is_seif_file(file_path: str) -> bool:
    """Check if file is a seif encoding file."""
    path = Path(file_path)
    return (
        path.suffix == ".lp" and
        "seif_" in path.name
    )

Checkpoint Requirements

Checkpoint Mapping

def get_required_checkpoint(file_path: str) -> str | None:
    """Determine which checkpoint must be approved to write this file."""
    if is_seif_file(file_path):
        return "corpus-prep"  # Must have corpus-prep approved
    return None

Phase-to-Checkpoint Table

File Pattern Required Checkpoint
corpus/*/seif_*.lp corpus-prep
corpus/*/base.lp corpus-prep
Other .lp files None (allowed)

Implementation Details

Input Parsing

def parse_tool_input(tool_input: str) -> dict:
    """Parse tool input to extract file path."""
    try:
        data = json.loads(tool_input)
        return data
    except json.JSONDecodeError:
        # Try to extract file_path from string representation
        match = re.search(r'file_path["\s:]+([^\s"]+)', tool_input)
        if match:
            return {"file_path": match.group(1)}
        return {}

Session State Check

def main():
    tool_input = sys.argv[1] if len(sys.argv) > 1 else "{}"
    data = parse_tool_input(tool_input)
    file_path = data.get("file_path", "")

    # Only check ontology .lp files
    if not is_ontology_file(file_path):
        return allow()

    # Check required checkpoint
    required_checkpoint = get_required_checkpoint(file_path)
    if required_checkpoint is None:
        return allow()

    # Load session state
    session = load_session_state()
    if session is None:
        return block_no_session(file_path)

    # Check checkpoint status
    checkpoints = session.get("checkpoints", {})
    checkpoint_data = checkpoints.get(required_checkpoint, {})
    status = checkpoint_data.get("status", "not_started")

    if status != "approved":
        return block_checkpoint_not_approved(file_path, required_checkpoint, status)

    # Checkpoint approved - allow the write
    return allow_with_message(f"Phase gate: {required_checkpoint} approved")

Session State Format

The hook reads checkpoint status from .mistaber-session.yaml:

checkpoints:
  corpus-prep:
    status: approved        # Required for ontology writes
    approved_by: human
    timestamp: 2026-01-25T10:30:00Z
  hll-encode:
    status: pending_review
  validate:
    status: not_started
  review:
    status: not_started

Status Values

Status Can Write? Description
approved Yes Checkpoint passed
pending_review No Awaiting approval
not_started No Phase not begun
in_progress No Phase executing

Error Messages

No Session

BLOCKED: No Active Encoding Session

Cannot write to ontology file: {file_path}

You must start an encoding session first:
1. Invoke the corpus-prep skill
2. Complete corpus preparation
3. Get human approval at checkpoint

Start with: "Prepare corpus for YD {siman}:{seif}"

Checkpoint Not Approved

BLOCKED: Checkpoint Not Approved

Cannot write to: {file_path}

Required checkpoint: {checkpoint}
Current status: {status}

The encoding workflow requires human approval at each checkpoint.
Complete the {checkpoint} phase and get approval before proceeding.

Workflow Enforcement

Enforced Order

graph LR
    A[Start] -->|No writes allowed| B[corpus-prep]
    B -->|Checkpoint 1| C{Approved?}
    C -->|No| B
    C -->|Yes| D[Ontology writes allowed]
    D --> E[hll-encode]

What Gets Blocked

Attempt Result
Write seif file without session BLOCKED
Write seif file with pending_review BLOCKED
Write seif file with approved ALLOWED
Write non-ontology file ALLOWED
Edit existing ontology file Uses same rules

Bypass Options

Bypass Not Recommended

The phase gate exists to ensure encoding quality. Bypassing is strongly discouraged.

Emergency Manual Override

If absolutely necessary, temporarily edit the session state:

# .mistaber-session.yaml
checkpoints:
  corpus-prep:
    status: approved  # Manually set

Or temporarily disable the hook in hooks.json.

Debugging

Manual Testing

# Test with non-ontology file
echo '{"file_path": "test.py"}' | \
  python mistaber-skills/hooks/scripts/phase-gate.py | jq .

# Test with ontology file (no session)
rm -f .mistaber-session.yaml
echo '{"file_path": "mistaber/ontology/corpus/yd_87/seif_1.lp"}' | \
  python mistaber-skills/hooks/scripts/phase-gate.py | jq .

# Test with approved checkpoint
cat > .mistaber-session.yaml << 'EOF'
checkpoints:
  corpus-prep:
    status: approved
EOF
echo '{"file_path": "mistaber/ontology/corpus/yd_87/seif_1.lp"}' | \
  python mistaber-skills/hooks/scripts/phase-gate.py | jq .

Common Issues

False Positive Blocks

Symptom: Legitimate write blocked.

Causes: - Session file corrupted - Wrong working directory - Checkpoint status not updated

Solutions:

cat .mistaber-session.yaml
# Verify checkpoint status is "approved"

File Pattern Not Matching

Symptom: Ontology file not detected.

Causes: - Different path structure - Missing "ontology" or "corpus" in path

Solutions: Check file path matches expected pattern:

"ontology" in path and "corpus" in path and path.endswith(".lp")