# LoopX Canary Pre-Merge Validation Gate: How Risk-Based Testing Protects Your Main Branch

> Discover how LoopX Canary uses risk-based testing for pre-merge validation gates, protecting your main branch with diff-hygiene checks, Python compilation, and smoke-suite canaries.

- Repository: [huangruiteng/loopx](https://github.com/huangruiteng/loopx)
- Tags: how-to-guide
- Published: 2026-09-04

---

**The LoopX Canary validation system is a multi-layered, tiered gate that runs diff-hygiene checks, Python compilation tests, surface classification, and relevance-filtered smoke-suite canaries before merging pull requests.**

The `huangruiteng/loopx` repository implements a sophisticated **LoopX Canary pre-merge validation gate** that prevents risky changes from reaching your main branch. This system automatically classifies code changes into logical surfaces, selects appropriate validation checks based on risk profiles, and produces a definitive merge decision—all configurable through `quick`, `standard`, and `deep` execution tiers.

## How the Canary Pre-Merge Gate Classifies Changes

At the heart of the LoopX Canary validation system is **surface classification**. The `classify_premerge_surfaces` function in [`loopx/canary/premerge.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/canary/premerge.py) (lines 70-105) maps changed files to high-level conceptual areas using token-based matching.

### Surface Token Groups

The classifier recognizes these primary surfaces through predefined token tuples:

- **`CONTROL_PLANE_TOKENS`** – Infrastructure and orchestration code
- **`CANARY_TOKENS`** – The canary system itself
- **`PUBLIC_BOUNDARY_TOKENS`** – Exposed APIs and public interfaces
- **`BENCHMARK_SENSITIVE_TOKENS`** – Performance-critical paths

Each surface may trigger additional **risk-profile canaries**. For example, changes to benchmark-sensitive surfaces automatically require manual review regardless of test outcomes.

### Risk Profile Assignment

When files match certain surface tokens, the system attaches risk profiles:

```python

# From loopx/canary/premerge.py - surface classification produces:

surfaces = {"control_plane", "public_boundary"}
risk_profiles = {"infrastructure_risk", "api_compatibility_risk"}
manual_holds = ["benchmark_sensitive"]  # Blocks self-merge

```

## The Three-Tier Execution Model

The LoopX Canary pre-merge validation gate operates at three configurable depths. These tiers control resource allocation and thoroughness through `PREMERGE_TIERS`, defined in [`loopx/canary/premerge.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/canary/premerge.py) (lines 18-23):

| Tier | Catalog Limit | Profile Limit | Deep Checks |
|------|---------------|---------------|-------------|
| **quick** | 3 checks | 0 | No |
| **standard** | 9 checks | 8 | No |
| **deep** | Unlimited | Unlimited | Yes |

The `_tier_limits` function (lines 51-57) enforces these boundaries during gate construction.

## Step-by-Step Gate Execution Flow

The `build_premerge_validation_gate` function ([`loopx/canary/premerge.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/canary/premerge.py), lines 16-27, 58-71) orchestrates the complete validation sequence:

### 1. Changed File Discovery

When invoked with `--from-git-diff`, the CLI command `_resolve_canary_changed_files` ([`loopx/cli_commands/canary.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/cli_commands/canary.py), lines 55-68) aggregates committed, staged, unstaged, and untracked changes:

```bash
loopx canary premerge --from-git-diff --tier standard

```

### 2. Direct Diff-Hygiene Checks

The `_diff_hygiene_checks` function (lines 60-86) runs three parallel `git diff --check` validations for whitespace errors and conflict markers across all diff states.

### 3. Python Compilation Validation

Changed `.py` files trigger `_py_compile_check` (lines 5-18), which executes `python -m py_compile` to catch syntax errors before they reach CI.

### 4. Catalog Canary Selection

`build_canary_smoke_suite_run` creates a synthetic smoke-suite limited by the tier's `catalog_limit`. This selects relevance-filtered checks from the interaction-pattern catalog based on your specific file changes—not a blanket test suite.

### 5. Risk-Profile Canary Execution

If surface classification produced any `risk_profiles`, a second bounded smoke-suite runs with the tier's `profile_limit`. This targets infrastructure, API compatibility, or other specialized validations.

### 6. Public-Boundary Security Scan

Files matching `PUBLIC_BOUNDARY_TOKENS` trigger `_public_boundary_changed_files_run` (lines 56-85). This executes `loopx check --scan-path` to verify no private secrets or internal material leaks into public interfaces.

### 7. Gate Status Aggregation

The `_gate_status` function (lines 29-45) collapses all results into a definitive verdict:

- **`passed`** – All checks successful, no manual holds
- **`failed`** – One or more validation failures
- **`manual_review_required`** – Benchmark-sensitive or other hold-triggering surfaces present
- **`no_changes`** – Empty diff detected

## Gate Payload Structure and Self-Merge Policy

The LoopX Canary validation system produces a structured `loopx_premerge_validation_gate_v0` payload containing:

```python
{
    "ok": True,  # Boolean summary of merge-readiness

    "gate": {
        "status": "passed",  # Core decision state

        "self_merge_allowed": True,  # Policy-derived permission

        "surfaces": ["control_plane"],
        "risk_profiles": ["infrastructure_risk"],
        "manual_holds": [],
        "failures": [],
        "warnings": []
    },
    "direct_checks": {...},
    "catalog_run": {...},
    "risk_profile_run": {...},
    "boundary_run": {...}
}

```

Self-merge is permitted **only when** `gate["status"] == "passed"` **and** `manual_holds` is empty. This policy is enforced in `_gate_status` (lines 54-58).

## Progress Reporting and CI Integration

The gate emits structured `canary_premerge_progress_v0` events for real-time observability:

- `premerge_started`
- `section_started` / `section_finished`
- `check_started` / `check_finished`
- `premerge_finished`

The CLI prints these to `stderr` via `_print_smoke_suite_progress` ([`loopx/cli_commands/canary.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/cli_commands/canary.py), lines 88-124).

### GitHub Actions Integration

```yaml
- name: Run LoopX pre-merge gate
  run: |
    loopx canary premerge --from-git-diff --tier standard \
      --no-progress --no-execute > gate.json

- name: Enforce gate decision
  run: |
    python - <<'PY'
    import json, sys
    data = json.load(open('gate.json'))
    if not data.get('ok'):
        print(f"Gate failed: {data['gate']['status']}")
        sys.exit(1)
    print(f"Gate passed, surfaces: {data['gate']['surfaces']}")
    PY

```

## Optional Change-Quality Receipt Verification

When `--goal-id` is provided, the gate enforces exact-scope policies through `verify_change_quality_receipt` and `apply_change_quality_verification` (lines 48-66). This verifies that:

1. The claimed goal ID exists in the registry
2. The change scope matches the receipt exactly
3. Quality thresholds are met

Invalid receipts can override the gate status to `failed` regardless of test results.

## Markdown Report Generation

The `render_premerge_validation_gate_markdown` function (lines 224-272) produces PR-ready output summarizing:

- Gate status with visual indicator
- Detected surfaces and risk profiles
- Direct check results with failure details
- Canary execution counts
- Manual hold explanations
- Recommended next actions

## Key Source Files in the Canary System

| File | Purpose |
|------|---------|
| [`loopx/canary/premerge.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/canary/premerge.py) | Core orchestration, classification, status calculation, rendering |
| [`loopx/cli_commands/canary.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/cli_commands/canary.py) | CLI entry point, argument parsing, progress callbacks, receipt wiring |
| [`loopx/canary/runner.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/canary/runner.py) | Catalog-based smoke-suite construction (`build_canary_smoke_suite_run`) |
| [`loopx/canary/planner.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/canary/planner.py) | Repository root detection, catalog loading, selection constants |
| [`loopx/capabilities/change_quality/receipt.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/capabilities/change_quality/receipt.py) | Exact-scope receipt verification implementation |
| [`loopx/contract.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/contract.py) | `scan_public_boundary` for security scanning |

## Summary

- **Surface classification** in `classify_premerge_surfaces` maps changes to `control_plane`, `public_boundary`, and other risk-relevant categories using token matching
- **Three execution tiers** (`quick`/`standard`/`deep`) control validation depth through configurable catalog and profile limits
- **Multi-layer validation** combines diff hygiene, Python compilation, relevance-filtered catalog canaries, risk-profile canaries, and public-boundary security scans
- **Gate status aggregation** in `_gate_status` produces `passed`, `failed`, `manual_review_required`, or `no_changes` with clear self-merge permissions
- **Change-quality receipt verification** enables exact-scope policy enforcement for regulated workflows
- **Structured progress events** and markdown rendering support both CI integration and human review

## Frequently Asked Questions

### What triggers a manual_review_required status in the LoopX Canary gate?

The `manual_review_required` status activates when surface classification detects files matching `BENCHMARK_SENSITIVE_TOKENS` or other hold-triggering patterns. Even if all tests pass, benchmark-sensitive changes require human approval before merge. This is enforced in `_gate_status` (lines 29-45) regardless of the execution tier.

### How does the quick tier differ from standard and deep validation?

The **quick tier** limits catalog canaries to 3 checks and disables risk-profile canaries entirely, making it ideal for rapid feedback in local development. **Standard tier** expands to 9 catalog checks and 8 profile checks. **Deep tier** removes all limits and enables deep checks—comprehensive validations that are too slow for routine use.

### Can I run the pre-merge gate without executing any tests?

Yes. Pass `--no-execute` to perform file discovery, surface classification, and gate construction without running canaries. This produces the full payload structure with empty `catalog_run` and `risk_profile_run` sections—useful for CI pipelines that need to inspect what *would* run before committing resources.

### Where does the LoopX Canary system check for secrets in public-facing code?

The `_public_boundary_changed_files_run` function ([`loopx/canary/premerge.py`](https://github.com/huangruiteng/loopx/blob/main/loopx/canary/premerge.py), lines 56-85) executes when changed files match `PUBLIC_BOUNDARY_TOKENS`. It invokes `loopx check --scan-path` to scan for private material, secrets, or internal-only content that may have leaked into public interfaces.