async function performRoomProgression()

in projects/deliberation_at_scale/packages/orchestrator/src/tasks/updateRoomProgression.ts [64:209]


async function performRoomProgression(room: Room, payload: UpdateRoomProgressionPayload, helpers: Helpers) {
    const { roomId, jobKey } = payload;

    // guard: check if the room is valid
    if (!roomId || !room) {
        return Promise.reject(`Could not update progression because the room was not found. Room ID: ${roomId}`);
    }

    const currentRoomStatus: RoomStatus = room?.status_type ?? 'safe';
    const currentLayerIndex = progressionTopology.layers.findIndex((topologyLayer) => {
        return topologyLayer.roomStatus === currentRoomStatus;
    }) ?? 0;
    const currentLayer = progressionTopology?.layers?.[currentLayerIndex];

    // guard: make sure the layer is valid
    if (!currentLayer) {
        return Promise.reject(`Could not update progression topology layer could not be found. Room ID: ${roomId}, room status: ${currentRoomStatus}.`);
    }

    const currentLayerId = currentLayer.id;
    const currentEnrichments = currentLayer?.enrichments ?? [];
    const progressionTaskBaseContext: ProgressionTasksBaseContext = {
        progressionLayerId: currentLayerId,
        roomId,
        helpers,
    };

    helpers.logger.info(`Running update progression task for room ${roomId} in progression layer ${currentLayerId}.`);

    // trigger the enrichments that should be triggered before verification
    await triggerEnrichments({
        enrichments: currentEnrichments,
        progressionTaskBaseContext,
        executionTypes: ['alwaysBeforeVerification'],
        helpers,
    });

    const verificationResult = await triggerVerifications({
        currentLayer,
        currentLayerIndex,
        helpers,
        progressionTaskBaseContext,
    });

    if (!verificationResult) {
        helpers.logger.info(`Not all progression verifications passed for room ${roomId} for unknown reasons.`);
        return;
    }

    const { completedModeratorTaskTuples, failedProgressionTaskIds = [] } = verificationResult;
    const hasFailedtasks = failedProgressionTaskIds.length > 0;
    const hasFailedVerifications = completedModeratorTaskTuples?.some((completedModeratorTaskTuple) => {
        try {
            const { moderation } = completedModeratorTaskTuple;
            const parsedResult = moderation?.result as unknown as VerificationFunctionCompletionResult;
            const isFailed = parsedResult?.verified === false;

            return isFailed;
        } catch (error) {
            // empty
        }

        return false;
    });

    // guard: if one verification has failed we cannot proceed to the next progression
    if (hasFailedVerifications || hasFailedtasks) {
        helpers.logger.info(`Not all progression verifications are verfified ${roomId}: ${JSON.stringify(failedProgressionTaskIds)}.`);

        // trigger the enrichments that should be triggered when verification failed
        await triggerEnrichments({
            enrichments: currentEnrichments,
            progressionTaskBaseContext,
            executionTypes: ['onNotVerified', 'alwaysAfterVerification'],
            helpers,
        });
        return;
    }

    helpers.logger.info(`All verifications passed for ${roomId} in progression layer ${currentLayerId}!`);

    const nextLayer = progressionTopology.layers?.[currentLayerIndex + 1];

    // trigger the enrichments that should be triggered when verification passed
    // NOTE: this is done before a room update progression, because changing the status
    // impacts the execution and filtering of the enrichments
    await triggerEnrichments({
        enrichments: currentEnrichments,
        progressionTaskBaseContext,
        executionTypes: ['onVerified', 'alwaysAfterVerification'],
        helpers,
    });

    // guard: check if there is a next layer
    if (!nextLayer) {
        return;
    }

    const hasFailedMinAttemptTasks = await checkTasksForMinAttempts({
        roomId,
        layer: currentLayer,
        helpers,
    });

    // guard: skip when not all tasks were done a minimum amount of times
    if (hasFailedMinAttemptTasks) {
        helpers.logger.info(`Not all progression tasks in layer ${currentLayerId} were done a minimum amount of times ${roomId}!`);
        return;
    }

    const nextLayerId = nextLayer.id;
    helpers.logger.info(`The next progression layer is ${nextLayerId} for room ${roomId}.`);

    // progress to the new status
    if (ENABLE_ROOM_PROGRESSION) {
        const roomProgressionJobKey = getModerationJobKeyForRoomProgression(roomId, nextLayerId);
        await Promise.allSettled([
            supabaseClient.from("moderations").insert({
                type: 'updateRoomProgression',
                job_key: roomProgressionJobKey,
                statement: `The room progressed from ${currentLayerId} to the next layer ${nextLayerId}`,
                target_type: 'room',
                room_id: roomId,
                result: JSON.stringify({
                    currentLayerId,
                    nextLayerId,
                }),
                completed_at: dayjs().toISOString(),
            }),
            updateRoomStatus({
                roomId,
                roomStatus: nextLayer.roomStatus,
                helpers,
            }),
            helpers.addJob("updateRoomProgression", payload, {
                jobKey,
            }),
            PRINT_ROOM_PROGRESSION && sendBotMessage({
                roomId,
                content: `[DEBUG] The room progressed from ${currentLayerId} to the next layer ${nextLayerId}`,
            })
        ]);
    } else {
        helpers.logger.info('Skipping progression, because we are in testing mode.');
    }
}