Stop classifying Recall bot-detection timeouts as NOT_RECORDED in call-recorder (#23812)

Removes the two `timeout_exceeded_only_bots_detected_*` sub codes from
`NOT_RECORDED_RECALL_SUB_CODES`, so a bot-detection leave is handled
like any other call ending (`call_ended` -> PROCESSING -> artifact
import -> COMPLETED).

These sub codes are leave reasons, not capture verdicts. Bot detection
only fires when participants are present (otherwise `noone_joined` fires
first), and any participant starts the recording, so a bot-detection
ending virtually always has a real recording behind it. It is also the
app's own configured exit path whenever a third-party notetaker
(Fireflies, Otter) lingers after the humans leave, since a lingering bot
keeps `everyone_left_timeout` from ever firing. Classifying it as
NOT_RECORDED stamped successfully recorded calls as failures and skipped
artifact import; bots in the production Recall workspace end with this
sub code near-daily.


<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/23812?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
This commit is contained in:
nitin
2026-08-05 19:24:42 +05:30
committed by GitHub
parent 45cbdef930
commit 4137a1f9fc
3 changed files with 48 additions and 3 deletions
@@ -1,6 +1,6 @@
{
"name": "@twentyhq/call-recorder",
"version": "1.7.0",
"version": "1.7.1",
"license": "MIT",
"engines": {
"node": "^24.5.0",
@@ -2,8 +2,6 @@
export const NOT_RECORDED_RECALL_SUB_CODES: readonly string[] = [
'meeting_not_started',
'timeout_exceeded_noone_joined',
'timeout_exceeded_only_bots_detected_using_participant_names',
'timeout_exceeded_only_bots_detected_using_participant_events',
'timeout_exceeded_waiting_room',
'call_ended_by_platform_waiting_room_timeout',
'bot_kicked_from_waiting_room',
@@ -323,6 +323,53 @@ describe('handleRecallWebhook', () => {
]);
});
it('treats a bot-detection timeout as a normal call ending', async () => {
const client = new FakeCoreApiClient([
{
id: 'call-recording-1',
status: 'RECORDING',
externalBotId: 'recall-bot-1',
},
]);
const result = await handleRecallWebhook({
client: client as unknown as CoreApiClient,
body: {
event: 'bot.status_change',
data: {
bot: {
id: 'recall-bot-1',
metadata: {
twentyWorkspaceId: WORKSPACE_ID,
twentyCallRecordingId: 'call-recording-1',
},
},
status: {
code: 'call_ended',
sub_code:
'timeout_exceeded_only_bots_detected_using_participant_names',
},
},
},
});
expect(result).toEqual({
status: 'updated',
event: 'bot.status_change',
callRecordingId: 'call-recording-1',
callRecordingStatus: 'PROCESSING',
});
expect(client.mutations).toEqual([
{
id: 'call-recording-1',
data: {
status: 'PROCESSING',
externalBotId: 'recall-bot-1',
},
},
]);
});
it('ignores a no-capture sub code on a non-terminal status code', async () => {
const client = new FakeCoreApiClient([
{