forked from molecule-ai/molecule-core
Two stalls in cycle 132 traced to the same root cause: activity_logs INSERTs were wedging on invalid UTF-8 bytes (observed: 0xe2 0x80 0x2e) and the surrounding DB operations had no deadlines, so a single stuck transaction blocked wg.Wait() in tick() and stalled the whole scheduler until a container restart. Root cause: truncate() did byte-slicing without UTF-8 boundary checks. A prompt containing U+2026 (`…` = 0xe2 0x80 0xa6) at byte ~197 was sliced at maxLen-3, producing the trailing fragment 0xe2 0x80 followed by '.' (0x2e) from the "..." suffix — Postgres rejects this as invalid UTF-8 for jsonb, holds the transaction open, and the INSERT never returns. Fix: - truncate(): UTF-8 safe — backs up to a rune boundary via utf8.RuneStart - sanitizeUTF8(): new helper applied to every agent-produced string before it crosses the DB boundary (prompt, error detail, schedule name) - dbQueryTimeout = 10s on every scheduler DB call: - tick() due-schedules query - capacity-check queries in fireSchedule - empty-run counter UPDATE / reset - activity_logs INSERTs (fireSchedule + recordSkipped) - recordSkipped bookkeeping UPDATE - Bookkeeping writes use context.Background() parent (F1089 pattern) so fireTimeout / shutdown cancellation can't silently skip the UPDATE. Regression tests lock in the 0xe2 0x80 0x2e wedge: truncate() is verified UTF-8-valid and never produces that byte sequence even when input contains a multi-byte rune at the cut position. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| scheduler_test.go | ||
| scheduler.go | ||