# How reverse-skill Handles Multiple Keyword Matches for Routing: Complete Scoring Algorithm Explained

> Discover how reverse-skill handles multiple keyword matches using its scoring algorithm. Learn how hits and priority lists determine route selection for efficient routing.

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

---

**reverse-skill uses a scoring-based routing system where every keyword match adds a "hit" to a route's candidate score, and ties are broken by a configurable priority list.**

The reverse-skill project implements a deterministic router that resolves ambiguous user hints by weighing multiple keyword matches against each other. This article explains exactly how the scoring algorithm works, how ties are resolved, and how to debug routing decisions using the source code in `zhaoxuya520/reverse-skill`.

## Keyword-Based Routing Configuration

All routing logic in reverse-skill is defined in **[`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json)**, the single source of truth for route definitions. Each route contains a `keywords` array where every object specifies matching conditions:

| Field | Purpose |
|-------|---------|
| `must` | Regex that **must** appear in the hint for the rule to match |
| `mustAll` | Array of regexes where **all** must match simultaneously |
| `exclude` | Regex that **must not** appear (immediate disqualification) |
| `note` | Human-readable documentation (ignored by the router) |

Consider this excerpt from the APK reverse route (`R1`) at lines 14-18 of [`routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/routing.json):

```json
{
  "id": "R1",
  "name": "APK Reverse",
  "keywords": [
    { "must": "apk", "note": "Android package keyword" },
    { "must": "jadx|apktool|baksmali", "note": "APK tool mentions" }
  ]
}

```

## The Scoring Algorithm for Multiple Matches

When `master-route.ps1` receives a hint, it executes a five-step scoring process:

1. **Scan all routes** and evaluate every keyword object against the hint
2. **Increment hit count** — each successful rule adds exactly one hit to that route's candidate score
3. **Build candidate set** — collect all routes with at least one hit
4. **Select primary route** by:
   - Choosing the route with the **highest hit count**
   - Breaking ties using the **`priority` array** — the route appearing **earliest** wins
5. **Fallback to `R0`** if no route receives any hits

The scoring metadata is documented at lines 5-6 of [`routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/routing.json): "每条关键字规则命中后计入候选集" (each keyword rule hit is counted toward the candidate set).

## Priority Array: The Tiebreaker

When two or more routes share the same hit count, the router consults the `priority` array at lines 308-313:

```json
"priority": [
  "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8",
  "R9", "R10", "R11", "R12", "R13", "R14", "R15"
]

```

This explicit ordering ensures **deterministic routing** even with ambiguous hints.

## Practical Examples

### Single Route Match

```powershell
.\skills\scripts\master-route.ps1 -Hint "apk jadx reverse root detect"

```

The hint contains `apk`, matching `R1`'s first keyword rule, and `jadx`, matching its second. No other route scores higher. Result: **R1** is PRIMARY.

### Competing Routes with Equal Scores

```powershell
.\skills\scripts\master-route.ps1 -Hint "apk jadx and graphql api security"

```

- `R1` (APK reverse): 1 hit — matches `apk`
- `R12` (API security): 1 hit — matches `graphql`

Both routes tie with one hit. The priority array lists `R1` before `R12`, so **R1 becomes PRIMARY** while `R12` remains in the candidate set.

### Complex Multi-Condition Rule

```bash
bash skills/scripts/master-route.sh "jailbreak ipa iOS reverse"

```

This satisfies `R2`'s (Mobile reverse) `mustAll` rule: `jailbreak` must appear together with any token from `ios|iphone|ipad|mobile|objection|ipa`. The router selects **R2** as PRIMARY.

### Inspecting Candidate Scores

```powershell
.\skills\scripts\master-route.ps1 -Hint "nmap sqlmap reverse" -Verbose

```

Verbose output reveals the scoring breakdown:

```

[INFO] Candidate routes:
  R11 – 2 hits (nmap, sqlmap)
  R0  – 1 hit (reverse)
[INFO] Primary route: R11 (higher score)

```

`R11` (Network/Infra reverse) wins with two keyword matches versus `R0`'s one.

## Source Files and Their Roles

| File | Function | Key Implementation |
|------|----------|------------------|
| [`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json) | Central routing definition | Keyword rules, `priority` array, `fallbackId` |
| `skills/scripts/master-route.ps1` | PowerShell routing entry point | Scoring algorithm, candidate selection |
| [`skills/scripts/master-route.sh`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/scripts/master-route.sh) | Bash wrapper | Calls Python backend with identical logic |
| [`skills/MASTER-ROUTING.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/MASTER-ROUTING.md) | Documentation | Priority table and routing concepts |
| `skills/scripts/verify-routing-coherence.ps1` | Validation | JSON structure and priority consistency checks |
| `skills/scripts/test-routing.ps1` | Regression suite | 162 automated routing tests |

## Summary

- **Every keyword match counts**: Each satisfied rule adds one hit to a route's score
- **Highest score wins**: The route with the most hits becomes PRIMARY
- **Priority array breaks ties**: Earlier entries win when scores are equal
- **Deterministic fallback**: `R0` handles hints with no matches via `fallbackId`
- **Single configuration**: All behavior is controlled through [`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json)

## Frequently Asked Questions

### How does reverse-skill handle hints that match zero routes?

The router falls back to the route specified by `fallbackId`, which defaults to `R0` (General reverse). This ensures every hint produces a valid routing decision even without keyword matches.

### Can a single hint trigger multiple rules within the same route?

Yes. If a hint satisfies multiple keyword objects in one route's `keywords` array, each successful match increments that route's hit count. This allows fine-grained confidence scoring rather than binary matching.

### What happens if the priority array is modified?

The router respects the updated order immediately on the next execution. The `verify-routing-coherence.ps1` script validates that all route IDs in `priority` match existing routes and that no duplicates exist.

### How can I debug why a particular route was selected?

Run `master-route.ps1` with the `-Verbose` flag. This displays the complete candidate set with per-route hit counts and explicitly states which priority tiebreaker was applied if needed.