# How the Reverse-Skill Routing Algorithm Prioritizes Keywords and Resolves Conflicts Between Multiple Matching Rules

> Learn how the reverse-skill routing algorithm prioritizes keywords with regex scoring and resolves rule conflicts. Discover its tie-breaking and fallback mechanisms for efficient routing.

- Repository: [ZhaoXu/reverse-skill](https://github.com/zhaoxuya520/reverse-skill)
- Tags: internals
- Published: 2026-08-15

---

**The reverse-skill routing algorithm prioritizes keywords by scoring regex matches and resolves conflicts between multiple matching rules by selecting the highest-scoring route, breaking ties via the order defined in the `priority` array, and falling back to `R0` when no matches occur.**

The `zhaoxuya520/reverse-skill` repository implements a deterministic routing system driven by a single JSON configuration. Understanding how this **routing algorithm prioritizes keywords and resolves conflicts between multiple matching rules** is essential for customizing the skill selector or debugging unexpected route selections in [`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json).

## Keyword Matching and Scoring Logic

Each route (R1 through R40) defines a list of keyword objects. When a user query arrives, the algorithm evaluates every route against three pattern types to calculate a cumulative **score**.

### The must Pattern

Every `must` regex that matches the user query adds a **hit** to that route’s candidate set【/__modal/volumes/vo-cSqLfqnnIwYXEonuEJnnZa/repos/github.com/zhaoxuya520/reverse-skill/main/skills/config/routing.json#L6-L7】. The total number of successful hits becomes the score for that route. A higher score indicates greater relevance to the query.

### Exclusion and mustAll Modifiers

Two optional modifiers refine the matching logic:

- **`exclude`**: If this pattern matches the query, the hit is removed from the route’s score, even if `must` matched.
- **`mustAll`**: Requires every sub-pattern in the set to be present in the query. If any sub-pattern fails, the hit is discarded.

These modifiers ensure that partial matches or unwanted keyword collisions do not inflate a route’s score.

## Priority-Based Conflict Resolution

When multiple routes achieve positive scores, the algorithm uses a two-tier resolution strategy: score first, priority second.

### Handling Ties with the Priority Array

After scoring completes, the algorithm walks the `priority` array from top to bottom【/__modal/volumes/vo-cSqLfqnnIwYXEonuEJnnZa/repos/github.com/zhaoxuya520/reverse-skill/main/skills/config/routing.json#L10-L14】. The route with the **highest score** is selected. If several routes share the same highest score, the one appearing **earlier** in the `priority` list wins (the "first-winner" rule).

This deterministic ordering prevents ambiguous routing and allows explicit control over which skills take precedence when queries match multiple patterns.

### Real-World Conflict Example

Consider a query containing both "apk" and "js reverse":

- **R1** (APK reverse) receives a hit from the `apk` keyword【/__modal/volumes/vo-cSqLfqnnIwYXEonuEJnnZa/repos/github.com/zhaoxuya520/reverse-skill/main/skills/config/routing.json#L14-L18】, achieving a score of 1.
- **R3** (JS/frontend reverse) receives a hit from the `js reverse` keyword【/__modal/volumes/vo-cSqLfqnnIwYXEonuEJnnZa/repos/github.com/zhaoxuya520/reverse-skill/main/skills/config/routing.json#L30-L34】, also achieving a score of 1.

Because the scores tie, the `priority` list (defined as `R4`, `R1`, `R2`, `R3`...) decides the winner. The algorithm selects **R1** because it appears earlier than **R3** in the array【/__modal/volumes/vo-cSqLfqnnIwYXEonuEJnnZa/repos/github.com/zhaoxuya520/reverse-skill/main/skills/config/routing.json#L11-L13】.

## Fallback Mechanism

If **no** route receives any hit (score = 0), the algorithm does not return a null result. Instead, it falls back to the route identified by `fallbackId` (`R0`)【/__modal/volumes/vo-cSqLfqnnIwYXEonuEJnnZa/repos/github.com/zhaoxuya520/reverse-skill/main/skills/config/routing.json#L5-L6】, ensuring a graceful default behavior when queries match no defined keywords.

## Implementation in PowerShell

The matching logic resides in `skills/scripts/master-route.ps1`, which loads [`routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/routing.json) and executes the scoring algorithm. The `skills/scripts/verify-routing-coherence.ps1` script validates that the `priority` list and route definitions remain synchronized during configuration changes.

A simplified version of the scoring logic follows:

```powershell

# Load routing table

$routing = Get-Content routing.json | ConvertFrom-Json

# 1️⃣ Score each route

foreach ($id in $routing.routes.Keys) {
    $route = $routing.routes[$id]
    $score = 0
    foreach ($kw in $route.keywords) {
        if ($query -match $kw.must) {
            if ($kw.exclude -and $query -match $kw.exclude) { continue }
            if ($kw.mustAll) {
                $allMatch = $true
                foreach ($sub in $kw.mustAll) { 
                    if (-not ($query -match $sub)) { $allMatch = $false } 
                }
                if (-not $allMatch) { continue }
            }
            $score++
        }
    }
    $route.score = $score
}

# 2️⃣ Choose the best route

$best = $null
$maxScore = -1
foreach ($id in $routing.priority) {
    $route = $routing.routes[$id]
    if ($route.score -gt $maxScore) {
        $best = $route
        $maxScore = $route.score
    } elseif ($route.score -eq $maxScore -and $best -eq $null) {
        # first in priority wins on tie

        $best = $route
    }
}

# 3️⃣ Fallback if nothing matched

if ($maxScore -le 0) { 
    $best = $routing.routes[$routing.fallbackId] 
}

# Result

$best.skill   # e.g. "apk-reverse/SKILL.md"

```

## Summary

- **Scoring**: Routes accumulate points based on `must` regex matches, modified by `exclude` and `mustAll` patterns defined in [`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json).
- **Conflict Resolution**: Highest score wins; ties are broken by order in the `priority` array (earlier wins).
- **Fallback**: Route `R0` (defined by `fallbackId`) handles queries with zero matches.
- **Validation**: `verify-routing-coherence.ps1` ensures the priority list and route definitions stay in sync.

## Frequently Asked Questions

### What happens when two routes have identical scores?

The algorithm selects the route that appears **earlier** in the `priority` array. This "first-winner" rule ensures deterministic routing when multiple rules match equally well, as implemented in `master-route.ps1`.

### How does the `exclude` pattern work in the routing JSON?

If a query matches both a `must` pattern and its corresponding `exclude` pattern, the hit is discarded and does not contribute to the route’s score. This prevents false positives when keywords appear in unintended contexts.

### What is the purpose of `verify-routing-coherence.ps1`?

This script validates that the `priority` array and route definitions in [`routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/routing.json) remain synchronized. It catches configuration errors where a route ID might be missing from the priority list or vice versa before runtime.

### Can I assign different weights to different keywords?

No. According to the source code in `master-route.ps1`, each successful match (after applying modifiers) contributes exactly **one** point to the route’s score. To prioritize certain keywords, you must place their containing routes earlier in the `priority` array rather than assigning numerical weights.