The bug
You: context 都 81% 了, 你在 handsoff 里没有 compact 啊!你什么时候 compact?
Auto-compact was NEVER firing on claude-opus-5. Ever. /goal loops just ran to 81%+ ctx while the supervisor sat silent.
Root cause
Verified in `~/.hive/chat-logs`: recent `claude-opus-5` `system:init` events dropped the `contextSize` field entirely. Now emit only:
```json
{"type":"system","subtype":"init","session_id":"...","model":"claude-opus-5"}
```
Handoff supervisor in handoff.ts read `event.contextSize`, got `undefined`, kept `h.contextSizeTokens = 0` (initial value). Then the auto-compact gate:
```ts
if (h && h.contextSizeTokens > 0 && h.lastInputTokens > 0) {
if (shouldTriggerAutoCompact(pct, ...)) tryAutoCompact(runId)
}
```
`contextSizeTokens > 0` always failed → `tryAutoCompact` was never called even once.
The renderer's ctx% bar had the same bug months ago but was fixed inline: if contextSize absent, infer from model name — haiku=200K, everything else=1M. That inference was never mirrored into the main-process supervisor. Classic main/renderer drift.
Fix
New shared helper `resolveContextSizeTokens(explicit, model)` in `src/shared/context-size.ts`:
- Prefer the explicit `contextSize` string when present
- Otherwise infer from model: `haiku → 200K`, everything else `→ 1M`
- Return 0 only when both are absent (supervisor bails cleanly)
Handoff supervisor now calls this helper. Single source of truth so main and renderer can't drift on this rule again.
Test
New `context-size-resolve.test.ts` with 9 pins:
- Explicit `'1M'`/`'200K'` honored
- `claude-opus-5` with no `contextSize` → 1M (the real-world fix)
- `claude-sonnet-5`, `claude-fable-5`, `claude-opus-4-7` → 1M
- `claude-haiku-*` → 200K (case-insensitive)
- Both absent → 0 (fail-safe)
- Malformed explicit + valid model → falls back to model
- End-to-end user scenario: `810_000 tokens / 1_000_000 = 0.81 > 0.70` threshold → `shouldTriggerAutoCompact` returns true
1222/1222 unit tests + TypeScript clean.
Install
Download DMG (`arm64` for Apple Silicon, plain for Intel), or click Check for Updates… in the app menu.
Unsigned; on first launch, right-click → Open.