# Rapid-Fire Config Write Collision

## The Problem

Writing `~/.hermes/config.yaml` multiple times in quick succession can cause the path watcher to **silently miss intermediate writes**. The switch log shows gaps — one config state is simply never processed.

## Root Causes

Two independent mechanisms cause this:

### 1. Same-mtime collision
Linux `mtime` has second granularity on most filesystems (including ext4). If two writes happen within the same wall-clock second, the second write has the same mtime as the first. The path watcher (`hermes-config.path`, which uses `inotify` + `PathModified`) may coalesce events, causing it to see only one modification event for two writes.

### 2. Flock exclusion
`auto-model-switch.py` acquires an exclusive `flock` on `~/.hermes/.model-switch.lock` before doing any work. If a config write arrives while the previous switch is still in progress (model loading, health polling), the lock prevents concurrent invocation — the second write's trigger simply drops.

## Symptom

- The switch log has a gap: e.g. a `cloud→35b` entry, then the next entry is `cloud` (a later write) — the `35b→9b` write was never processed
- Running `systemctl is-active llama-server-9b.service` shows `inactive` even though a config write targeted it
- VRAM / config state disagrees with what the written config should have produced

## Real-World Example (May 13, 2026)

During automated testing of 5 sequential switches:
```
Test writes: cloud→35b → 35b→9b → 9b→gemma4 → gemma4→cloud → cloud→35b
             ↑20s gap↑    ↑15s gap↑   ↑2s gap↑     ↑20s gap↑

Switch log shows:
  cloud→35b  ✅ (Already on - warm model)
  35b→9b     ✅ (Started 9b, API ready in 13s)
  (gap — gemma4 write missed)
  cloud      ✅ (no service to swap)
  cloud→35b  ✅ (Stopped 9b, Started 35b)
```

The `9b→gemma4` write was missed because:
1. The 9b switch completed at T+33s
2. The gemma4 config was written at T+35s (same second as 9b's health poll finished? or lock still held?)
3. The cloud config was written at T+37s (2 seconds later)
4. The watcher only saw the T+37s write → skipped gemma4

## Prevention

### Primary fix
Always switch models via Hermes chat `/model` command. The gateway writes atomically and the path watcher fires once.

### For manual testing
When writing config.yaml directly for testing, add a minimum **3-second delay between writes** AND ensure the previous switch has completed before writing the next config.

### Detection
After a sequence of writes, verify against the switch log:
```bash
tail -20 ~/.hermes/logs/model-switch.log
```
Every expected config target should have a corresponding entry. Missing entries = swallowed writes.

### Verification
After suspicious-switching, run the four-way alignment audit from `local-model-switch-optimization` Core Technique #6 to detect which layer drifted.
