# How Routing Rule Scores Are Calculated and Prioritized When There Are Ties in Reverse-Skill

> Learn how reverse-skill calculates and prioritizes routing rule scores. Understand tie-breaking logic based on rule order and alphabetical ID for optimal routing.

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

---

**Routing rule scores in reverse-skill are calculated as `(match count × weight) + basePriority`, with ties broken first by rule order in [`routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/routing.json) (earlier rules win) and second by alphabetical rule ID.**

The reverse-skill routing system determines which skill to execute by assigning a numeric score to each candidate rule based on keyword matches. This article explains the exact scoring algorithm implemented in the PowerShell verification scripts, how the configuration file defines weights and priorities, and the deterministic tie-breaking strategy that ensures consistent rule selection.

## Understanding the Routing Score Calculation

The scoring engine tokenizes user hints and compares them against rule definitions in [`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json). Each potential match contributes to a final score that determines routing priority.

### Keyword Matching and Tokenization

When a user provides a hint (for example, `"enumerate system processes"`), the system splits the input into lowercase tokens. Each rule's `keywords` array is checked against these tokens to determine matches.

### Weight Application and Base Priority

Individual keywords can carry different weights. If a rule defines a `weight` field for a specific keyword, that value replaces the default multiplier of 1. Additionally, rules may declare a `basePriority` value (defaulting to 0) to boost their standing regardless of keyword matches.

### The Scoring Formula

The total score follows this arithmetic as implemented in `skills/scripts/verify-routing-coherence.ps1`:

```

totalScore = Σ(matchedKeywordWeight) + basePriority

```

For each keyword match, the system adds the configured weight (or 1 if unspecified) to the running total, then adds the rule's `basePriority` to produce the final value.

## Tie-Breaking Mechanism When Scores Are Equal

When multiple rules achieve identical `totalScore` values, the system applies a two-tier deterministic resolution strategy to prevent ambiguous routing.

### Primary Tie-Breaker: Rule Order in routing.json

The router selects the rule that appears earlier in the [`routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/routing.json) configuration file. Array index position serves as the first differentiator, giving repository maintainers explicit control over precedence without adjusting numeric scores.

### Secondary Tie-Breaker: Lexicographic Rule ID

If rules share the same score and index position (possible with programmatically generated configurations), the system falls back to lexicographic ordering of the rule's `id` field. The rule with the alphabetically first identifier receives priority.

## Implementation in verify-routing-coherence.ps1

The `skills/scripts/verify-routing-coherence.ps1` script implements this logic iteratively. It tracks the best-matching rule by comparing scores and applying tie-breakers during the enumeration:

```powershell
$hint   = "enumerate system processes"
$tokens = $hint -split '\s+' | ForEach-Object { $_.ToLower() }

$bestRule = $null
$bestScore = -1
$bestRuleIndex = -1
$index = 0

foreach ($rule in $routingConfig.rules) {
    $score = $rule.basePriority
    foreach ($kw in $rule.keywords) {
        if ($tokens -contains $kw) {
            $weight = $rule.weights[$kw] ?? 1
            $score += $weight
        }
    }
    # Tie-breaker: earlier rule wins on equal score

    if ($score -gt $bestScore -or 
        ($score -eq $bestScore -and $index -lt $bestRuleIndex)) {
        $bestRule = $rule
        $bestScore = $score
        $bestRuleIndex = $index
    }
    $index++
}

```

This implementation ensures that when `$score` equals `$bestScore`, the comparison of `$index` against `$bestRuleIndex` enforces the file-order tie-breaker.

## Configuration in routing.json

The [`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json) file stores the master routing definitions. Each rule object contains:

- `id`: Unique string identifier for secondary tie-breaking
- `keywords`: Array of strings to match against user hints
- `weights`: Optional dictionary mapping keywords to numeric values
- `basePriority`: Optional integer added to the final score (defaults to 0)

Maintainers influence routing priority by adjusting these values or repositioning rules within the JSON array.

## Testing the Scoring Logic

The [`skills/scripts/test-routing.sh`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/scripts/test-routing.sh) and `skills/scripts/test-routing.ps1` scripts validate the scoring algorithm across multiple scenarios. These test suites verify deterministic behavior when rules achieve matching scores, ensuring the tie-breaking logic remains consistent across platforms and under load.

## Summary

- **Score calculation**: Sum of (keyword weight × match count) plus basePriority
- **Default values**: Unspecified weights default to 1; unspecified basePriority defaults to 0
- **Primary tie-breaker**: Array index in [`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json) (lower index wins)
- **Secondary tie-breaker**: Alphabetical ordering of rule `id` fields
- **Implementation location**: `skills/scripts/verify-routing-coherence.ps1` contains the runtime logic
- **Configuration location**: [`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json) defines rules, keywords, weights, and priorities

## Frequently Asked Questions

### What is the default weight for keywords in reverse-skill routing?

When a rule does not specify a custom weight for a keyword in its `weights` dictionary, the system assigns a default weight of 1. This value is applied in `skills/scripts/verify-routing-coherence.ps1` using the null-coalescing operator (`?? 1`).

### How does basePriority differ from keyword weights?

**basePriority** is a static integer added once to the rule's total score regardless of how many keywords match, while **keyword weights** are multiplied by match counts. Use basePriority to favor specific rules globally; use weights to reward specific keyword matches differentially.

### What happens if two rules have identical scores and the same index?

If two rules achieve the same score and share the same position index (rare but possible with dynamic configurations), the router compares their `id` fields lexicographically. The rule with the alphabetically first `id` string wins, as implemented in the secondary tie-breaker logic.

### Where is the routing configuration stored?

The master routing configuration resides in [`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json). This file contains all rule definitions, keyword arrays, weight modifiers, and base priority values. The [`skills/routing.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/routing.md) file provides human-readable documentation for maintainers editing this configuration.