How the routing.json Priority Array Determines PRIMARY Skill Selection

The priority array in routing.json serves as a deterministic tie-breaker that selects the PRIMARY skill when multiple routes achieve identical keyword match scores, with earlier positions in the array indicating higher precedence.

The reverse-skill repository implements a rule-based routing system to dispatch reverse-engineering tasks to specialized handlers. Central to this architecture is skills/config/routing.json, which defines keyword matching rules, a fallbackId, and the ordered priority array that resolves competition between equally-scored candidates.

The PRIMARY Selection Algorithm

The routing engine implemented in skills/scripts/master-route.ps1 executes a three-phase selection process that transforms user hints into deterministic skill assignments.

Phase 1: Keyword Scoring and Candidate Generation

Each route defined in the routes object contains a keywords array with inclusion and exclusion patterns. The engine iterates through every route and increments a score for each matching rule. According to lines 5-7 of routing.json, this process builds a candidate set where each route ID maps to its accumulated match count.

Phase 2: Tie-Breaking with the Priority Array

When multiple routes share the maximum score, the router consults the top-level priority array (lines 24-29) to break the deadlock. This ordered list of route IDs functions as a precedence hierarchy; the router selects the first route ID appearing in the priority array among the tied candidates. This ensures that even with overlapping keyword patterns, the system produces a single, predictable PRIMARY assignment.

Phase 3: Fallback Assignment

If no keyword rules match the input hint, the candidate set remains empty. In this scenario, the router immediately returns the fallbackId specified in meta.scoring (typically "R0"), ensuring the system always has a valid skill to execute.

Implementation in master-route.ps1

The PowerShell entry point skills/scripts/master-route.ps1 materializes this logic by loading the configuration, calculating scores, and applying the priority-based tie-breaker:


# Load routing configuration from repository root

$cfg = Get-Content -Raw -Path "$PSScriptRoot/../config/routing.json" | ConvertFrom-Json

# 1. Score each route based on keyword matches

$scores = @{}
foreach ($id in $cfg.routes.Keys) {
    $score = 0
    foreach ($kw in $cfg.routes[$id].keywords) {
        if ($Hint -match $kw.must -and -not ($Hint -match $kw.exclude)) {
            $score++
        }
    }
    $scores[$id] = $score
}

# 2. Identify highest-scoring candidates

$maxScore = ($scores.Values | Measure-Object -Maximum).Maximum
$candidates = $scores.GetEnumerator() |
              Where-Object { $_.Value -eq $maxScore } |
              Select-Object -ExpandProperty Key

# 3. Resolve ties using priority order; fallback if no matches

$primary = $cfg.priority | Where-Object { $candidates -contains $_ } | Select-Object -First 1
if (-not $primary) { $primary = $cfg.meta.fallbackId }

# 4. Load the selected skill definition

$skillPath = Join-Path $PSScriptRoot ".." $cfg.routes[$primary].skill

This implementation strictly follows the algorithm documented in the configuration metadata: it respects the priority array only after establishing score parity, and respects the fallbackId only when the candidate set is empty.

Routing Configuration Structure

The routing.json file schema separates concerns between scoring rules and precedence ordering:

{
  "meta": {
    "scoring": "每条关键字规则命中后计入候选集;按 priority 数组顺序取『命中分数最高』的为 PRIMARY;分数并列时 priority 靠前者胜出;未命中任何规则时回退 fallbackId。",
    "fallbackId": "R0"
  },
  "priority": ["R4", "R1", "R2", "R3"],
  "routes": {
    "R1": {
      "skill": "skills/core/apk.yml",
      "keywords": [{"must": "apk", "exclude": ""}]
    },
    "R4": {
      "skill": "skills/core/ios.yml", 
      "keywords": [{"must": "ipa|ios", "exclude": "android"}]
    }
  }
}

The meta.scoring field explicitly documents that when scores are equal, the route appearing earlier in the priority array wins. This separation allows operators to adjust routing precedence without modifying complex keyword regex patterns.

Summary

  • The priority array determines tie-breaking precedence only after keyword scoring identifies multiple candidates with identical maximum scores.
  • Routes appearing earlier in the priority list possess higher authority; the router selects the first matching candidate from this ordered list.
  • When no keywords match, the system defaults to the fallbackId specified in meta.scoring within routing.json.
  • The master-route.ps1 script implements this logic deterministically, ensuring predictable skill selection even with ambiguous input hints.
  • Validation scripts like verify-routing-coherence.ps1 ensure the priority array remains synchronized with documentation.

Frequently Asked Questions

What happens if two routes tie in score but only one appears in the priority array?

The route listed in the priority array wins; if both appear, the one with the lower array index (earlier position) is selected. Routes absent from the priority array cannot become PRIMARY unless they uniquely achieve the highest score without ties, though the fallback mechanism still applies if they are the explicit fallbackId.

Can the priority order be changed without modifying keyword rules?

Yes. The priority array operates independently of the scoring mechanism. Reordering route IDs in this list immediately changes tie-breaking behavior without affecting how individual routes accumulate keyword match scores, allowing non-invasive routing adjustments.

Where is the fallback skill defined when no keywords match?

The fallback route ID is defined in routing.json under the meta.fallbackId property, conventionally set to "R0". This ID must correspond to a valid key in the routes object, as implemented in master-route.ps1.

How does the system validate routing configuration changes?

The repository includes verify-routing-coherence.ps1, which cross-references the priority array against the human-readable table in MASTER-ROUTING.md and validates that all referenced route IDs exist, preventing runtime errors due to configuration drift.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →