# Cron Model Name Expiry — Fleet-Wide Audit Pattern (2026-08-13)

## Symptom

A cron job fails instantly; output file ends with:

```
## Error
RuntimeError: HTTP 404: Model not exist.
```

The job never starts — the failure is the first LLM call of the cron session.

## Root cause

The custom endpoint renamed a model (observed: `glm-5-2-260617` → `glm-5.2` on the
token-plan Aliyun endpoint). Jobs that hard-coded the old name break; jobs with
`model=None` inherit the main model and are IMMUNE.

## ⚠️ When ONE job fails this way, audit ALL jobs

The rename breaks every job that pinned the old name. Same session, two jobs broke
(A股策略图 08:30, then 美股晨报 09:30 — user asked "排查下其他定时任务是不是也有类似
的模型配置问题"). Audit procedure:

```python
import json
with open('/root/.hermes/cron/jobs.json') as f:
    data = json.load(f)
jobs = data.get('jobs', data if isinstance(data, list) else [])
for j in jobs:
    print(j.get('id'), '|', (j.get('name') or '')[:40],
          '| model:', j.get('model'), '| last_status:', j.get('last_status'))
```

Then fetch the live model list from the endpoint (`/models` with the Bearer key) and
compare every pinned `model` against it. Fix all stale names at once.

## Fix mechanics

- The `cronjob` tool's `update` action does NOT change the `model` field (and passing
  a placeholder `prompt` OVERWRITES the real prompt — see below). Edit
  `~/.hermes/cron/jobs.json` directly for the model field:

```python
import json
path = '/root/.hermes/cron/jobs.json'
with open(path) as f:
    data = json.load(f)
for j in data.get('jobs', []):
    if j.get('id', '').startswith('<job_id_prefix>'):
        j['model'] = '<new-model-name>'
with open(path, 'w') as f:
    json.dump(data, f, ensure_ascii=False, indent=2)
```

- After fixing, backfill today's missed run: `cronjob action=run job_id=...`.
- Verify `execution_success: true` in the response.

## Prompt recovery (if cronjob update clobbered it)

Recover from the latest output file `~/.hermes/cron/output/<job_id>/<latest>.md`:
extract text between `## Prompt` and `## Error` headings, strip the leading
`[IMPORTANT: You are running as a scheduled cron job...]` wrapper paragraphs (those
are injected at run time, not part of the stored prompt). The real prompt usually
starts at a line like "你是一个...助手". Re-apply via `cronjob action=update` with
the full recovered prompt.
