# Execution Duration ## Running State Main owns reply timing independently of the visible conversation or task panel. Acquiring a reply lease starts a segment after the request task has been created. Manual context compression uses a maintenance lease and creates no clock. Nested subagents and stable schedule parents are excluded; their work is already inside the top-level reply interval. Background and channel requests use the same lease. Task transitions away from `running` close the segment, including `paused`, `queued`, `waiting_approval`, completion, failure and cancellation. Resuming a leased request opens another segment. Repeated `running` notifications leave the original segment intact. Abort closes timing immediately, even when runtime cleanup is still pending. Releasing a lease prevents subsequent task updates from restarting its clock. Concurrent replies contribute their durations independently. Remote requests measure Main's observed running state. The existing committed terminal checkpoint closes their timing; event persistence, replay deduplication and Agent ACK order are unchanged. Disconnection/recovery gaps are incomplete. This duration does not claim to measure autonomous execution while the desktop is disconnected. Application exit closes observed detached remote intervals without cancelling the remote operation and marks the remaining duration unknown. ## Storage Schema 59 adds `execution_timing`: one row per timed request with its project, conversation, task-card owner, accumulated milliseconds, optional running start, and incomplete flag. Scope indexes keep snapshots separate from large task and message payloads. A schedule run copies the stable task association already stored in `parent_task_id`; repeated runs aggregate under that card. Task deletion cascades to its timing row. Only state transitions write timing. Tokens, tools, display ticks and snapshot reads do not update it. Startup drops any unclosed segment and marks it incomplete, retaining previously accumulated time. It never counts application downtime or uses recovery timestamps as execution endpoints. Migration marks existing conversations and visible task cards incomplete without reconstructing their past duration. Imported legacy conversation snapshots are also incomplete. No timing query reads historical messages, tools or task events. The same migration adds `messages_summary_idx ON messages(conversation_id, sequence, role, created_at)` for conversation summaries. It performs no history conversion or `VACUUM`. ## Contract `window.goodbuddy.tasks.getExecutionStats(input)` invokes `tasks:execution-stats`. Input accepts exactly one UUID scope: `{ conversationId }` or `{ projectId }`. Main validates the scope and trusted sender, then reads the small timing rows synchronously. The old evidence query, cache, reader and statistics worker are removed. ```ts interface ExecutionStats { durationMs: number // closed segments plus open segments through asOf runningCount: number // open segments in this scope incomplete: boolean asOf: number // Main epoch milliseconds taskDurations: Array<{ id: string durationMs: number runningCount: number incomplete: boolean }> } ``` Conversation snapshots have an empty `taskDurations` array. Historical request counts are no longer part of this API. `onExecutionStatsChanged(listener)` returns an unsubscribe function. Main sends `tasks:execution-stats-changed` after timing transitions or history deletion; synchronous changes are coalesced into one notification. The renderer subscribes before fetching its current conversation and project snapshots and refreshes on notifications. It discards superseded responses and clears failed scopes. The UI adds `max(0, now - asOf) * runningCount` locally once per second while an open segment exists, including the corresponding per-card calculation. Hidden panels unsubscribe and fetch fresh snapshots when reopened. There is no five-second statistics polling, message-count revision trigger, or tick-time IPC. Main timing continues while the panel is hidden or another conversation is selected. ## Validation `assistant-execution-stats.test.ts` exercises real SQLite state transitions, restart interruption, remote checkpoints/replay, schedule ownership, scope isolation, deletion, schema migration and read-only snapshots. It verifies that snapshot SQL never reads messages or task events. IPC tests cover trusted scope validation and production lease completion, failure and abort; preload tests cover the subscription bridge. Hook tests verify local ticking without polling, hidden panels, stale responses, and failed reads. ## Custom Task Creation The dialog defaults to the current conversation and immediate execution. Content is required; an empty name uses the first 120 characters of whitespace-normalized content. App supplies other local conversations in the current project and also allows creating a new conversation. Scheduled creation retains once/daily/weekly recurrence and requires a future timestamp, checked by both App and Main IPC. `ScheduleCreateInput.runImmediately` is an optional creation command, not a stored schedule field. It is valid only for `recurrence: 'once'`. `createSchedule` creates the conversation (if needed), task, disabled schedule, pending schedule run and conversation queue item in one SQLite transaction. Queue insertion failure rolls back all of them. Disabling automatic scheduling prevents timer ticks from adding another occurrence; pending/running queue state still determines task status. The create IPC handler publishes the queue change and wakes the existing conversation queue pump. App does not follow creation with `runNow`. Execution uses the existing readiness and conversation serialization rules. A runtime failure belongs to the created task; it does not reject creation or create another task. Refresh failures after a successful creation are notifications, not a reason to retry creation. No schema migration or preload changes are required for this creation command. `schedule-creation.test.ts` verifies transaction rollback and timer non-duplication with real SQLite. IPC tests exercise that database through the production queue and ordinary run handler with a controlled runtime, including failed execution. App creation tests cover destination selection, time validation, and failure handling.