Files
PaperClipAI/server
DottaandPaperclip e1ba77f067 fix(server): schedule live voice recovery from session changes and deadlines (#17576)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Voice calls retain durable session state and provider identities.
> - The chat maintenance timer scans live voice sessions even when no
call exists.
> - Session writes, saved expiry and active-call inspection deadlines
identify real work.
> - This pull request moves live-session recovery to the shared
coordinator.
> - Idle session recovery becomes quiet without losing exact-call
cleanup or current authorization checks.

## Linked Issues or Issue Description

Refs #17572. This PR is stacked on receiver discovery. It owns only live
voice session recovery. Reply delivery, inbound admission cleanup,
inbound history retention and call reports remain separate migration
slices.

**What happened?**
The one-second chat maintenance lane reads voice settings and scans live
sessions even when an instance has no calls or only terminal history.

**What did you expect?**
Reconstruct live calls on startup. Wake on committed session or
configuration changes. Inspect active calls and retry cleanup at actual
deadlines. Stop querying when no live obligation remains.

**Steps to reproduce**
Start an instance with no live voice sessions. Let startup settle. The
old maintenance method continues to read settings and session inventory
every chat maintenance pass.

## What Changed

- Add a voice-owned bounded deadline reader and scoped worker on the
existing coordinator. Retain concurrent writes across pages and reset
partial scans on restart. No tables or migrations are added.
- Separate generic connection health observations from configuration
changes. Existing receiver and command consumers retain their
notifications. Voice eligibility and provider operations remain in the
voice owner.
- Signal existing session transactions and configuration/feature
changes. Keep provider calls outside database transactions. Standalone
session writes use one small transaction helper.
- Preserve saved expiry, the two-minute unknown-creation grace,
active-call authorization and missed-hangup inspection, and
exact-provider cleanup. Recovery never creates a provider call.
- Retry transient authority lookup failures instead of treating them as
confirmed revocation.
- Fence expiration against a provider identity bound after discovery. A
late known call remains eligible for cleanup.
- Preserve work through rollback, drain, restart, concurrent refresh,
backoff and shutdown. Page inventory and rotate bounded batches across
companies.
- Leave the four other voice maintenance duties in the periodic lane.
- Document producer coverage and the supported writer contract in
`doc/idle-voice-session-recovery.md` and the dated audit.

## Verification

Published head: `f0b2e3cc22a18e7d08b10d4fc02aae4a19a52f30`. Receiver
#17572 has landed in master at
`dce004259394486f6361d0c0dd5a33a5272acc0a`. This normal merge reconciles
squash ancestry; the complete 22-file voice recovery patch is
byte-for-byte identical to the reviewed and tested `ad79c7e805` patch,
while all unrelated master changes are preserved. The PR now targets
master. Fresh exact-head CI and Greptile are running; interrupted
Ponytail turns are not completed verdicts under the maintainer’s
clarified merge policy, and an actual failing verdict still blocks.

- **210 distinct targeted cases pass on the current repair**: 19
complete recovery lifecycle cases and 191 complete voice-store,
coordinator, batching, startup and hostname cases. Production server
typecheck and build pass. Later edits record evidence only.
- CI `40633667141` on prior head `1b6323c164` failed the feature-change
assertion with `34050 < 25000`; its verification aggregate also failed.
The test now disables automatically advancing fake time, drives 20
controlled scheduler turns and requires all 205 calls to close before an
unrelated inspection deadline can mask a lost wake. Removing generation
replay fails with missing closures. The repair does not benchmark
database/host speed or raise the elapsed-time bound.
- A real committed exact-call regression reproduces wildcard-backoff
starvation. The worker keeps the broad retry but processes independent
exact hints and cached due calls. Each check reloads current state and
authority. Failed exact scopes remain fenced. Removing wildcard
isolation fails the intended assertion; a successful broad retry then
leaves the worker SQL-quiet. Full-row and lean queries now share the
state/scope/cursor predicate.
- Earlier acceptance on `712f3862b5` passed 725 distinct targeted cases.
Its measurements remain useful history: five real metadata writes and
one health check over 205 future calls selected 1,230 rows before the
inventory repair and zero afterward, without changing the saved
deadline. Those older test counts are not added to the current 210-case
count.
- Both external voice fixtures self-migrate; the current full
voice-store run uses a separate initially empty database. Earlier
fixture/method/observer failures, source mutations and partial edit
attempts remain in the [current
audit](https://github.com/paperclipai/paperclip/blob/ad79c7e805367fc7e2df3ea53c942ca6c7d27365/doc/plans/2026-10-25-voice-maintenance-sleep-audit.md#wildcard-failure-and-deterministic-generation-acceptance-october-28).
Source is restored after guarded mutations.
- Older CI `40632057899` failed because its trusted policy script was
absent from the checkout, while build separately received a runner
shutdown signal. E2E shards succeeded but their aggregate failed on
policy. The current checkout includes the landed policy tooling and its
checker/tests pass locally. The shutdown cause is unproven; neither old
failed run is counted as passing. Earlier full-local attempts stopped on
embedded PostgreSQL setup failures and did not pass.
- Fresh exact-head Greptile, security and all CI must pass before merge.
A completed failing Ponytail verdict blocks; an interrupted turn without
a verdict does not. No full current local repository matrix, live
provider acceptance, multi-writer support, Cloud wake, host suspension
or savings is claimed.

## Risks

- Process-local hints cover the existing active writer and shared
clients. Independent SQL writers or another replica need explicit wake
integration.
- Membership, task binding, phone preferences and other authority inputs
remain checked on the existing 30-second active-call inspection deadline
and on use. This is not an instant cleanup guarantee for every authority
mutation.
- Unknown creation retains its existing maximum-duration grace. Cleanup
failures retain retries. A provider request is never replayed merely
because its creation response is unknown.
- Genuine configuration changes retain bounded reconstruction. Metadata
writes can probe parent eligibility, while health-only observations
leave voice recovery quiet. Paging state is process-local and
reconstructs from durable rows after restart.
- Active calls, the other voice maintenance owners and connector
transports remain real obligations. This does not expand Cloud alarm
coverage, relax sleep eligibility or prove deployed suspension.
- The receiver and Discord parents have landed. Current-master
compatibility and exact-head CI and Greptile remain merge gates.

## Model Used

OpenAI GPT-6 via Codex, with repository inspection, reasoning, code
execution and test tools. The runtime does not expose a more specific
deployment identifier or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either linked existing issues or described the issue in-PR
following the relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
ticket identifier
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 07:38:48 -05:00
..