- Engineering
Voice agent shutdown: stop audio, finish owned work
Voice agent shutdown needs separate media and post-call lifecycles. Handle cancellation, late recordings, retries, and process drain.
- Author
Udit Goenka- Published
- Reading time
- 24 min

TL;DR: Voice agent shutdown should stop caller-dependent audio and generation, reconcile in-flight business actions, and preserve explicitly authorized post-call work through durable jobs. Treat call completion, recording readiness, task settlement, and process exit as separate events with separate owners and deadlines.
The caller hangs up, but a speech task keeps running. A recording callback arrives after the application has deleted its call state, or a CRM write commits after the worker assumes cancellation meant failure.
These failures share a missing lifecycle contract. "The call ended" describes a participant or provider state; it does not prove that every media resource stopped, every business operation settled, every artifact became available, or every background process exited.
This guide defines those boundaries and a practical shutdown sequence. It builds on interruption-safe turn ownership, durable workflow execution, and a complete call trace, without claiming any private product implementation.
Published: November 9, 2026. Last updated: November 9, 2026. Runtime examples are vendor-neutral, synthetic, and designed for local validation; no production shutdown benchmark or live customer observation is presented.
Table of contents
- Define which lifecycle ended
- Classify work by its owner
- Design an idempotent shutdown sequence
- Use cancellation without losing business truth
- Settle post-call work independently
- Drain processes and deployments
- Test shutdown under races
- Measure resource release and settlement
- Apply the contract to supported product surfaces
- Frequently asked questions
- Make one end condition unambiguous
Define which lifecycle ended
Call completion, participant departure, media shutdown, artifact readiness, and business settlement are distinct facts. A reliable system records each fact at the boundary where it is observed instead of compressing everything into a single done flag.
A caller can leave a conference while another participant remains. A browser can close while the server still has a retained connection, and a provider can report a terminal call state before a recording has finished processing.
The business task has another lifecycle. An appointment change may already be committed, still in flight, rejected, or unresolved when the media ends, so hanging up must not invent a business outcome.
Start with a lifecycle map for one supported call route. Identify the participant whose departure ends live interaction, the resource owner responsible for media cleanup, and the independent worker responsible for durable follow-up.
A useful model separates interaction, media, operations, and artifacts. The interaction moves to ended when the relevant participant contract ends; media moves to closed after resources are released; operations settle through receipts; artifacts become ready or unavailable under their own processing contract.
Those states can advance independently. An ended interaction with a pending recording is ordinary, while an ended interaction with continued microphone capture may be a defect depending on the declared participant contract.
Avoid assuming that a terminal provider event identifies the exact audible end. The final audio a participant heard can differ from the time your webhook handler received a completion event.
The latency instrumentation guide explains how clock domains and transport observations affect claims about audible behavior. Shutdown measurements need the same care when you report residual audio or resource release times.
Define post-call work by permission and input scope. Summarizing an authorized retained transcript is different from continuing to listen on a live media path after the caller has departed.
If the application intentionally keeps a conference open for staff, name that mode and its participants explicitly. Do not hide a continuing live session behind the generic phrase "post-call processing," because the privacy and operational boundaries differ.
A hangup reason is useful context, not a complete policy decision. Normal departure, failed connection, application timeout, and process shutdown can require different final outcomes while sharing the same cleanup primitives.
Your final record should preserve uncertainty. interaction_ended with operation_unknown is honest and recoverable, while call_successful inferred from a normal hangup can conceal an unresolved business write.
Classify work by its owner
Every long-lived task should have an owner and a declared response to interaction end. That classification prevents a broad cancellation sweep from destroying required post-call work and prevents unowned tasks from continuing indefinitely.
Live capture, playback, turn detection, speech recognition, response generation, and speculative reads usually depend on an active participant. Their useful work ends when that participant contract ends, subject to bounded cleanup or protocol finalization.
An external business command has a different owner. Once accepted by the owning service, it must be reconciled even if the coroutine that sent it is canceled or the caller disappears.
Recording finalization and outcome publication may belong to durable post-call processing. They should not depend on a live WebSocket or an in-memory reference held by the conversational worker.
A diagnostic tail or metrics poller belongs to the process or inspection session that started it. If it has no active owner after shutdown, it is leaked work even if it consumes little CPU.
| Work category | Stop on relevant participant departure | May continue after call | Required completion evidence |
|---|---|---|---|
| Microphone capture and caller playback | ✓ | ✗ Unless a separately declared session remains | Track or device released; output fenced |
| Turn-level generation | ✓ | ✗ Its output has no live destination | Task canceled or completed and stale output rejected |
| Read-only speculative tool work | ✓ Usually | Depends on explicit reuse policy | Cancellation observed or bounded result discarded |
| Accepted business write | ✗ Do not infer reversal | ✓ Reconcile independently | Owning service receipt or unresolved-operation record |
| Recording processing | ✗ Independent artifact lifecycle | ✓ Under authorized retention policy | Ready, unavailable, or failed artifact state |
| Outcome delivery job | ✗ Durable responsibility | ✓ With bounded retries | Acknowledged delivery or owned failure queue |
| Diagnostic polling process | ✓ When its owner ends | ✗ Unowned tails should exit | Observable process exit |
The table states recommended ownership rules for the proposed design. It does not assert that every vendor automatically applies those rules or that all post-call processing is permitted in every deployment.
Keep cancellation scopes aligned with those owners. A per-turn task group should contain work that becomes stale together, while durable jobs should be committed outside that volatile scope before the interaction worker exits.
Do not create a background task merely to escape cancellation. An untracked task can still disappear on process exit, retain sensitive resources, or fail without anyone observing its exception.
Python's asyncio task documentation explains task cancellation and warns against swallowing CancelledError in structured-concurrency components. That behavior supports a clear task ownership tree, but durable execution still requires storage outside the process.
Use the application's existing queue and job conventions when available. The missing requirement is explicit ownership and recovery, not a new shutdown framework.
The warm handoff guide adds an important participant case: automation can leave while a human and caller continue. Ending the automated participant must not accidentally terminate a conference whose remaining participants still own a valid session.
Design an idempotent shutdown sequence
An idempotent shutdown sequence can run more than once without reviving audio, duplicating final outcomes, or losing work. This is necessary because local disconnects, provider callbacks, timeouts, and process signals can all report overlapping end conditions.
First, record that the interaction is ending and prevent new conversational work. Use a generation or session fence so late tasks cannot schedule speech, tools, or another response after the stop decision.
Next, stop capture and playback through the owning media interface. Closing a control socket alone may not release a device, stop an audio source, clear a playback queue, or end a remote participant.
For browser capture, the Media Capture and Streams specification defines MediaStreamTrack.stop(). Apply the appropriate track and source ownership rules rather than assuming that hiding a call dialog releases every microphone track.
Then cancel participant-bound asynchronous tasks and await their cleanup within a deadline. cancel() requests cancellation; observing task completion is the evidence that the task has reacted and released its owned resources.
Reconcile in-flight operations separately. Record which commands are confirmed committed, rejected, not dispatched, or unknown, and preserve a durable recovery path for the unknown group.
Persist final interaction state and enqueue authorized post-call work. The relevant durable write should occur before losing the process state needed to construct the job, but the job itself should not need the live media connection.
Finally, close remaining call-owned transports, release references, and report cleanup status. If a step times out, expose the resource and owner that remain unresolved instead of returning an unconditional success.
Diagram source (Mermaid)
flowchart TD
A[End condition observed] -->|Fence new work| B[Interaction ending]
B -->|Stop owned media| C[Capture and playback closed]
B -->|Cancel volatile tasks| D[Turn tasks settled]
B -->|Classify pending commands| E[Operation reconciliation]
C -->|Persist terminal fact| F[Interaction ended]
D -->|Observe cleanup| F
E -->|Durable unresolved record| G[Post-call jobs]
F -->|Enqueue authorized work| G
G -->|Receipt or owned failure| H[Settlement complete]
The steps can overlap where their dependencies permit, but their invariants should remain explicit. For example, canceling generation and closing playback can proceed together after the output fence is active.
Use a single shutdown owner per call. Other components can signal an end condition, while the owner deduplicates the request and coordinates cleanup through shared state.
A durable shutdown identity can also deduplicate outcome publication. Multiple end events should produce one logical final interaction record, with later artifact updates attached independently rather than another invented call completion.
Be careful with exception handling. Cleanup should run when normal work fails, and a failure in one cleanup step should not prevent the application from attempting other independent releases.
Record partial cleanup honestly. If playback stopped but a remote leg could not be confirmed closed, the system has reached a safer state but still needs reconciliation rather than a blanket assertion that all resources are gone.

Use cancellation without losing business truth
Cancellation controls local work; it does not guarantee reversal of remote effects. That distinction is the most important rule when a caller hangs up during a tool operation.
A local HTTP request can be canceled after the server commits a change but before the response arrives. Treat the result as unknown until the owning system supplies a receipt or a supported reconciliation query establishes the outcome.
The workflow enforcement guide describes stable operation identities and confirmation binding. Preserve those identifiers through shutdown so the recovery worker can determine which authorized action needs settlement.
Do not retry every canceled write automatically. A retry is safe only under the target service's idempotency or reconciliation contract, and the retry must preserve the same business operation identity.
Stripe's idempotency reference provides one concrete service-specific retry contract. It illustrates the need to read the destination's rules; it is not evidence that every webhook endpoint or CRM update has equivalent behavior.
Read-only work can usually be abandoned more freely, but still release its connections and memory. A provider SDK may continue work underneath a canceled coroutine, so test the concrete client rather than inferring behavior from the language's cancellation API.
Threaded work deserves separate attention. Canceling the coroutine waiting on a blocking thread does not necessarily stop the thread's thread operation, and a shutdown deadline must account for that ownership difference.
Use cooperative cancellation inside loops. Long-running audio or polling loops should check their stop signal between bounded units of work rather than waiting forever on an operation that has no timeout.
Cleanup belongs in finally blocks or equivalent ownership constructs. Avoid swallowing cancellation as an ordinary recoverable service error, because doing so can restart a loop after the application has decided to end it.
The following runnable Python example validates one narrow behavior: both participant-bound tasks settle their cleanup when shutdown requests cancellation. Save it as shutdown_check.py and run python3 shutdown_check.py with Python 3.11 or later; no provider SDK or network connection is involved.
import asyncio
async def owned_worker(name, started, cleaned):
started.set()
try:
await asyncio.Event().wait()
finally:
cleaned.add(name)
async def main():
cleaned = set()
starts = [asyncio.Event(), asyncio.Event()]
tasks = [
asyncio.create_task(owned_worker(name, ready, cleaned))
for name, ready in zip(("capture", "generation"), starts)
]
await asyncio.gather(*(ready.wait() for ready in starts))
for task in tasks:
task.cancel()
results = await asyncio.gather(*tasks, return_exceptions=True)
assert cleaned == {"capture", "generation"}
assert all(isinstance(result, asyncio.CancelledError) for result in results)
assert all(task.done() for task in tasks)
print("owned shutdown checks passed")
asyncio.run(main())
The explicit start events make the test deterministic. Canceling a task before its coroutine begins would not prove that its finally cleanup ran after acquiring resources, so the fixture waits until both workers have entered their owned scope.
This example is intentionally limited. Production code needs bounded cleanup deadlines, error reporting, actual media release, and durable operation reconciliation, none of which can be established by a synthetic task that owns no external resource.
Do not use shielding as a substitute for durable work. A shielded coroutine still depends on its process and event loop, so it cannot guarantee that a recording job or business settlement survives a crash.
When cleanup exceeds its deadline, classify the failure. A task that ignored cancellation, a socket that never closed, and an external command with an unknown result need different recovery actions.

Canceling the local request leaves an external write unresolved until authoritative evidence settles it.
Settle post-call work independently
Post-call processing needs its own durable input, authorization, retry policy, and completion state. The live call worker should hand over that responsibility explicitly rather than keeping a media session alive while a summary or CRM update runs.
Define the job input from the minimum authorized artifacts. A summary job may need a retained transcript and task metadata, while a recording job may only need an artifact reference and access scope.
Do not assume every artifact is ready at interaction end. Recording generation, upload, transcription finalization, and quality analysis can have separate readiness signals and failure modes.
Twilio's recording resource documentation describes recording states and callbacks independently of call handling. The general design lesson is to model artifacts by their own contract, while checking the actual provider fields and statuses used by your application.
Store the call's terminal state even when artifact work is pending. An operator should be able to see that the conversation ended while a recording remains unavailable, rather than waiting for one overloaded status to change.
When a recording-ready event arrives, update the artifact state and release jobs that depend on it. A duplicate event should be idempotent, and a late event should not recreate deleted media or restart the conversational agent.
The retention policy needs precedence. If an authorized deletion request removed the recording and its dependent data, a late callback must not resurrect the artifact merely because a worker still has its reference.
Represent deletion intent durably enough to reject late reconstruction. A tombstone or equivalent state can establish that absence is intentional rather than a missing row that the callback handler should repair.
Post-call outputs need versioning when inputs can change. A summary created from an interim transcript should not silently replace a later summary based on the final transcript without a revision and provenance rule.
Keep business outcome publication separate from model-written summaries. A summary can describe the conversation, but an appointment service receipt establishes whether the requested appointment changed.
The outcome metrics guide explains why sentiment, apparent agreement, and normal call completion cannot substitute for verified task success. Post-call processing should preserve those evidence classes rather than blending them into a favorable label.
Retries need an end condition. Define the maximum useful retry window, failure queue owner, and operator action for jobs that cannot obtain their inputs or deliver their outputs.
Avoid a single retry policy for everything. An unavailable recording may warrant waiting for an artifact signal, while a permission error or intentionally deleted input should stop retries and record a terminal explanation.
The data boundaries guide helps map where retained artifacts and job outputs live. A closed call does not imply that provider storage, your queue payload, application logs, and the business system share a deletion or retention lifecycle.
Drain processes and deployments
Process shutdown is a separate lifecycle from call shutdown. A deployment can ask a worker to exit while active calls still exist, and the application must stop accepting new work before it decides how to handle those calls.
Begin drain by removing the worker from the intake path. That may involve readiness, queue consumption, connection acceptance, or a provider routing control, depending on the architecture.
Keep the distinction between existing and new sessions. A draining worker can preserve an active call within its permitted grace period while refusing new calls, rather than starting more work that it cannot finish.
Choose an explicit maximum drain duration. Long conversations, stalled providers, and unresponsive tools can otherwise keep a deployment alive indefinitely.
Kubernetes documents pod termination as a grace-period process that can eventually force container termination. Your application must fit its own drain and cleanup sequence inside the actual deployment contract rather than assuming unlimited time after a signal.
Budget the time deliberately. Stop intake, settle or transfer active interaction ownership, persist unresolved operations and post-call jobs, close resources, and leave room for the process to exit before the platform's hard deadline.
Do not make a critical durable write the last operation before the deadline. If the process is killed during that write, your recovery path may lack the very state it needed to resume safely.
Signals need an owner too. Python's runner documentation describes keyboard interruption handling around the main task; service deployment signals and framework-specific hooks still need explicit wiring and testing.
A diagnostic command should also stop when its inspection session ends. Polling loops, log tails, temporary tunnels, and local test servers are process resources, even when they are outside the main call worker.
Track processes started for testing. Record their command, process identity, port, and working directory, then stop the owned process when its test or worktree ends rather than starting another copy on a different port.
Only stop processes you own. A broad name-based kill can terminate another developer's server or a production helper, so inspect the concrete process and ownership before cleanup.
The regression harness should include process exit as an assertion. A test suite that passes its conversational checks but leaves live call legs or pollers behind has not verified complete lifecycle behavior.
Plan crash recovery separately from graceful drain. A hard process loss skips cleanup, so active-session state, operation identities, and queued post-call responsibilities must be recoverable without relying on the old worker's final log line.

Persist recoverable responsibilities before resource release and process exit within the deployment grace period.
Test shutdown under races
Shutdown tests should inject end conditions at the boundaries where ownership changes. A single successful hangup test does not cover a disconnect during generation, a late recording callback, or a write that commits while cancellation is in flight.
Build deterministic event fixtures first. Each fixture defines initial state, the end signal, subsequent late events, expected terminal states, allowed durable jobs, and prohibited resource creation.
Test an end signal twice. The second copy must not reopen media, enqueue another logical final outcome, or duplicate a follow-up action.
Test audio after the output fence. Deliver a delayed synthesis chunk and assert that no playback occurs, then deliver an old turn's completion event and assert that it does not advance the current state.
Test caller departure during a business write. Simulate both a rejected write and a committed write whose response was lost, and verify that the application records the difference through reconciliation instead of assuming cancellation means rollback.
Test artifact ordering. Deliver call completion before recording readiness, recording readiness before your completion handler runs, and repeated readiness events; the same final artifact and outcome state should emerge under the provider's supported contract.
Test deletion races. Delete the authorized artifact, then deliver an old ready event and assert that the deleted content is not fetched, retained, or recreated.
Test process drain with active calls. Stop intake, start the drain deadline, and verify which sessions finish, which receive a defined termination path, and which operations move to durable reconciliation.
Keep live tests consented and isolated. Use dedicated destinations and synthetic business resources so a cleanup defect cannot leave a real customer waiting or mutate a production appointment.
The SIP troubleshooting guide adds media-specific assertions. A provider terminal event is useful, but the test should also inspect whether RTP, browser tracks, or application audio queues remain active where those observations are available.
Use an independent watchdog for the test process itself. If the application ignores shutdown, a bounded harness should collect diagnostics, report failure, and stop only the processes and call resources that the test owns.
Do not discard failures because they occur after the conversation ended. Post-call data loss, duplicate notifications, and retained capture are user-impacting defects even when the final spoken sentence sounded correct.

Measure resource release and settlement
Measure shutdown with several explicit clocks. Interaction-end to output fence, output-fence to last accepted audio, interaction-end to media release, and interaction-end to durable settlement describe different properties.
Publish each boundary with its observation source. Server task completion is not proof of device release, and receipt of a remote callback is not proof of the exact moment a participant stopped hearing audio.
Report incomplete observations. If the browser does not expose a reliable final playback timestamp, label the metric as a server-side or client-event approximation rather than calling it audible shutdown latency.
Track resource counts before and after repeated trials. Open media tracks, sockets, retained call objects, active tasks, queue jobs, and process handles can reveal accumulation that a single-call test misses.
Use stable concurrency and call-route cohorts. A shutdown issue that appears only with several active calls can disappear in a sequential smoke test, and a browser route can release resources differently from a SIP route.
Measure settlement age separately from live cleanup. A recording that legitimately arrives later should not inflate the media-release metric, but it should count toward artifact readiness and post-call processing latency.
Unknown operations need a visible queue and age distribution. An average settlement time can look healthy while a small set of unresolved writes waits indefinitely without an owner.
The cost-per-success model should include retained call legs, unnecessary inference after hangup, failed job retries, and operator reconciliation time. The bill can expose lifecycle defects that conversational quality metrics miss.
Avoid attributing every residual provider charge to a leak. Billing granularity, minimum durations, and delayed usage reporting can also explain differences, so reconcile the actual billing contract with observed resource behavior.
Set acceptance criteria from your workflow and infrastructure budget. This article does not prescribe a universal cleanup deadline because participant needs, provider contracts, and deployment grace periods differ.
When reporting a benchmark, include test count, versions, route, concurrency, cold or warm conditions, injected failures, and the number of runs that never settled. Excluding timeouts from the timing distribution hides the most important shutdown failures.

Media release, business settlement, and artifact readiness have distinct evidence and timing boundaries.
Make recovery state visible to the next owner
A useful shutdown report is also a restart input. The next worker should be able to identify the ended interaction, the cleanup steps already attempted, the external operations still unresolved, and the jobs that were durably handed over without parsing free-form log messages.
Store the recovery state before releasing its volatile owner. If the old process disappears, another worker can claim the unresolved record under a lease or transactional update, reconcile the destination, and record a terminal result without reviving the original conversation.
Lease expiration does not prove an external operation failed. It only allows a new owner to investigate or continue under the operation's existing identity, so the recovery worker must still respect the target service's duplicate and reconciliation rules.
Keep the human escalation route concrete. A failed settlement job should include the operation reference, last known state, allowed next actions, and an operational owner, while protected conversational material remains available only through an authorized lookup.
This prevents a common reporting error: closing an alert because the call is over while the business responsibility is still open. Interaction termination is useful evidence about media, but it cannot satisfy a task whose completion depends on an external receipt.
For repeated failures, group by mechanism before adjusting deadlines. A canceled coroutine that never exits, a recording that never becomes ready, and a downstream update with no idempotency contract will not all improve because the application waits longer.
Retain enough diagnostic context to reproduce the mechanism with synthetic fixtures. Record the lifecycle stage, runtime version, call route, and event ordering, then remove identifiers and content that are not needed to understand the failure.
Review the recovery queue during deployment validation. A release can appear healthy under live-call metrics while leaving older responsibilities stranded because a new worker no longer understands their stored schema or policy version.
Apply the contract to supported product surfaces
Use the product's documented events as observations, then connect them to your application's independent state. Do not infer private shutdown mechanics from the presence of an API field or a dashboard status.
The current 60db Agent documentation describes browser hangup or closing the dialog as ending that call. The tools and webhooks event contract includes call completion or failure and a later recording.ready event, so downstream processing should keep recording readiness independent of call termination.
Those documented behaviors are application contracts, not a measured guarantee about every resource or internal task. Qualify the route and workspace available to you, then test the observations your application needs.
For a browser evaluation, verify that your client releases its own media references and does not continue to enqueue audio after hangup. The managed call ending does not excuse leaks in a custom wrapper or operator console.
For a streaming application, assign ownership of the client connection, audio capture, playback, and transfer behavior to your application where the contract requires it. Closing one transport should trigger your own cleanup path rather than relying on a hidden provider assumption.
For telephone routes, reconcile the final call state and any supported provider or carrier events. A test should distinguish the relevant participant leaving from an entire conference ending, especially when a human handoff retains other participants.
Do not require generally available inbound calling as the only test route. Availability can depend on workspace and environment gates, so use supported, authorized routes and record those limits in the test report.
Keep event authentication and duplicate handling at the application boundary. The workflow enforcement guide discusses request validation and business authorization, which remain necessary for post-call updates as well as live tools.
A product evaluation should end with a boundary map rather than a vague pass label. Record what the platform owns, what your client owns, which events establish each state, and which failures require operator recovery.
Frequently asked questions
What should stop immediately when a caller hangs up?
Stop new participant-dependent conversation work and fence stale output, then release owned capture and playback resources. External business operations and authorized post-call jobs need separate reconciliation rather than indiscriminate cancellation.
Does call completion mean every artifact is ready?
No. Recordings, transcripts, and derived analysis can follow independent readiness contracts, so retain separate artifact states and release dependent jobs only when their required inputs are available.
What is the difference between cancellation and rollback?
Cancellation asks local work to stop. Rollback reverses a transaction under a supported business or database contract; canceling a network request does not prove that a remote write was reversed or never committed.
Why should shutdown be idempotent?
Several end signals can describe the same interaction, including local disconnect, provider completion, and process drain. Repeating cleanup should preserve terminal state without reopening audio or duplicating final business effects.
Can I cancel every task in the event loop?
That is unsafe when the loop also owns durable jobs, shared services, or other calls. Cancel tasks through explicit ownership scopes and preserve independent operations that still need settlement.
Is task.cancel() enough to prove cleanup finished?
No. It requests cancellation; observe the task's completion and cleanup result within a bounded deadline before claiming that its resources were released.
Why should cancellation exceptions normally propagate?
Structured concurrency uses cancellation to coordinate task lifetime. Swallowing cancellation can keep loops running or interfere with task-group behavior, so cleanup should run while the cancellation signal remains meaningful.
Does shielding guarantee post-call work survives?
No. Shielding can affect cancellation propagation inside a live process, but it does not make work durable across process loss or provide a retry owner after a crash.
How should a write be handled after hangup?
Preserve its operation identity and reconcile the owning service's result. Whether authorization remains valid for dispatch after departure must be defined by the workflow rather than inferred from the disconnected media state.
Can post-call analysis keep listening to a conference?
Only as a separately declared live-participant mode with its own permission and lifecycle contract. Processing retained artifacts and continuing live capture are different activities and should never share an ambiguous label.
What if recording readiness arrives after deletion?
Honor the durable deletion intent and prevent the late event from recreating retained content. Callback handlers need a deletion-aware state rule rather than treating every missing artifact as a recovery opportunity.
How do I avoid duplicate final outcome events?
Use a stable interaction identity and idempotent terminal-state publication. Attach later artifact updates separately, and verify the actual delivery and retry contract for each event mechanism.
How long should graceful shutdown wait?
Choose a deadline that fits the user workflow, provider behavior, and deployment grace period. Reserve time for durable state and process exit, and report work that could not settle before the deadline.
What should happen during a deployment drain?
Stop new intake, handle existing calls under an explicit deadline, persist unresolved responsibilities, and close owned resources. A crash-recovery path is still needed because forced termination can skip graceful cleanup.
Should a diagnostic poller stop with the call?
It should stop when the inspection session or process that owns it ends. Diagnostic work that has no remaining owner can leak processes, sockets, or API traffic even after the conversational test has passed.
How do I test stale audio after shutdown?
Inject audio from an earlier generation after the output fence is active. Assert that the client or playback owner rejects it, rather than only checking that the server stopped generating new text.
Which metrics reveal shutdown leaks?
Track resource counts, cleanup deadlines, residual audio, unsettled-operation age, and orphaned jobs or processes. Repeated-call trials are useful because slow accumulation can remain invisible in a single smoke test.
Does a provider charge after hangup prove a leak?
No. Reconcile billing granularity, delayed usage reporting, and retained participant behavior with the actual contract before attributing the charge to a cleanup defect.
Can I use this article as a product guarantee?
No. It proposes a lifecycle design and validation plan; product-specific behavior must come from current documentation and authorized experiments against the route and workspace you use.
What is the first shutdown test to add?
End a synthetic call while generation and a read task are active, then assert no late playback and observable cleanup. Add an in-flight write and late recording event as separate cases once those responsibilities are modeled.
Make one end condition unambiguous
Reliable shutdown starts by naming what ended and who owns what remains. The caller's interaction, live media, external business operations, stored artifacts, and process lifetime each need an explicit terminal condition.
Implement an idempotent cleanup owner, reject stale output before releasing resources, and persist responsibilities that must outlive the call. Treat uncertain external writes as reconciliation work and recording readiness as an independent artifact event.
Start with one supported call route and inject a hangup during active work. Prove that audio stops, owned tasks settle, late events remain harmless, and post-call responsibilities survive a process restart without retaining a live participant by accident.
For 60db Agent, map the documented call and recording events to that application contract. Run the consented lifecycle test with synthetic business resources and preserve the observed limits alongside the passing assertions.
