# MSG-2026-04-13-stale-installer-versions

**From:** Chronicler #85  
**Date:** 2026-04-13  
**Priority:** HIGH — pending_calibration never triggers on live panel  
**Status:** OPEN

## Problem

The cron's detection chain has a fallback that reads `current_version` from the
existing DB row. For installer-method servers, this means stale full installer
filenames (e.g. `DeceasedCraft_Beta_DH_Edition_5.10.16`) persist indefinitely —
the cron finds them in the DB, uses them, and never reaches `pending_calibration`.

## Live Panel DB Evidence

```
DeceasedCraft:    current: DeceasedCraft_Beta_DH_Edition_5.10.16  ← stale filename
FTB Stoneblock:   current: FTB StoneBlock 4 1.10.0               ← stale filename
ATM10 Sky:        current: ATM10 To the Sky-2.0.2                ← stale filename
```

None of these are showing `pending_calibration` — they're all `update_available`
because the string comparison fails between the full filename and the clean
semver from the API.

## Root Cause

In `checkVersion()`, the DB fallback runs before pending_calibration:
```php
if (empty($currentVersion)) {
    $currentVersion = $existing->current_version ?? null;  // ← picks up stale value
}
// ...never reaches pending_calibration because $currentVersion is not empty
```

## The Fix

For `installer` detection method, the DB fallback should be skipped OR the
stale value should be validated before use.

**Option A (recommended):** For installer-method servers, only use DB value
if `current_file_id` is also set. If there's a current_version string but no
file_id, treat it as unvalidated and continue to Truth File / pending_calibration:

```php
if (empty($currentVersion)) {
    if ($method !== 'installer' || !empty($existing->current_file_id)) {
        $currentVersion = $existing->current_version ?? null;
        $currentFileId = $existing->current_file_id ?? null;
    }
}
```

**Option B:** Detect "dirty" version strings — if current_version contains
spaces or looks like a full filename (contains the modpack name), treat as
unvalidated.

Option A is cleaner and more reliable.

## Expected Behavior After Fix

- Servers with stale installer filenames → Truth File check → not found →
  `pending_calibration`
- Servers that have been calibrated (have `current_file_id`) → use DB value
  → normal comparison
- Servers where manifest.json was found → Truth File written → file ID
  comparison going forward

## Also — One Data Cleanup Needed

After the fix, existing stale rows need to be cleared so the cron re-evaluates
them. Either:
1. Add a one-time migration that nulls `current_version` where `current_file_id`
   is null and `detection_method = 'installer'`
2. Or document a manual SQL command Chronicler can run

---
*— Chronicler #85*
