completeRoutineExecution was reading from the DB outside the per-routine
lock then calling recordRun which acquires the lock internally. This
allowed concurrent operations on the same routine to hit SQLite
simultaneously. Inlined the logic inside a single withRoutineLock call
so the read and write are serialized.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The RoutineRunner and RoutineScheduler were written against a different
interface than what RoutineStore actually implements, causing TypeError
crashes as soon as any routine became due. This adds the missing
agentId/catchUpLimit fields to the Routine type and DB schema, adds
startRoutineExecution/completeRoutineExecution/cancelRoutineExecution
methods to RoutineStore, and fixes all property name mismatches
(lastExecutedAt→lastRunAt, trigger.cron→trigger.cronExpression,
policy value alignment) in the runner, scheduler, and tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>