Reference issues or pull requests here (e.g., "Closes #123") # Holistic Rubric: Multi-Tenant Authorization in Background Workers ## Task Summary The goal is to refactor background SQS worker handlers and database services in `potion-voice` to enforce multi-tenant authorization by scoping all MongoDB queries with `userId`. The solution must prevent cross-tenant IDOR vulnerabilities while preserving async execution order, SQS queue lifecycle reliability, and error-handling stability. --- ## Core Requirements 1. **Multi-Tenant Query Scoping**: - All database reads (`findOne`), updates (`findOneAndUpdate`), and status updates must include `userId: jobUserId` in the query criteria. - Primary models (`UserAudioProfile`, `Salutation`, `VoiceCloning`) and secondary models (`Recording`, `RecordingSalutation`) must be strictly scoped. 2. **Async Dependency Execution Order**: - In `voice-synthsizer-job-handler/index.js`, dependent fields like `salutationToUpdate.recordingId` must be retrieved **before** querying secondary models (`recordingModel.findOne(...)`). - Grouping dependent model lookups inside `Promise.all` before parent models resolve is invalid and leads to runtime crashes (`ReferenceError: recordingId is not defined`). 3. **SQS Queue Message Lifecycle Integrity**: - SQS queue messages must only be deleted via `deleteMessageFromSQS` after processing completes successfully. - Moving message deletion above execution steps (before synthesis, ffmpeg rendering, or S3 persistence) causes permanent, unrecoverable data loss if execution fails midway. 4. **Robust Error Recovery**: - Authorization failures must throw catchable errors or return early before running external Python scripts. - Error handlers in `catch` blocks must not fail or throw unhandled Promise rejections. --- ## Key AI Failure Modes (Meaningful Failures) - **Failure Mode 1: Async Dependency Crash (`recordingId` is undefined)** The agent attempts to optimize database queries by fetching `UserAudioProfile`, `Salutation`, and `Recording` inside a single `Promise.all` block. Because `recordingId` is derived from `salutationToUpdate.recordingId`, referencing `recordingId` in the `Promise.all` array causes a `ReferenceError` or queries MongoDB with `_id: undefined`. - **Failure Mode 2: Premature SQS Message Deletion (Silent Data Loss)** The agent moves `deleteMessageFromSQS` up before job processing or Python execution completes. If S3 upload or speech rendering fails, SQS cannot redeliver the message, resulting in silent job loss. - **Failure Mode 3: Invalid Mongoose `findById` Query Objects** The agent attempts tenant scoping by passing a query object to Mongoose's `findById` (e.g. `Model.findById({ _id: id, userId })`). In Mongoose, `findById` expects a primitive string or ObjectId, causing runtime `CastError: Cast to ObjectId failed`. - **Failure Mode 4: Incomplete Secondary Query Scoping** The agent updates primary model queries (`UserAudioProfile`) but forgets secondary queries (`Recording`, `RecordingSalutation`, or status updates inside `catch` blocks), leaving secondary models exposed to cross-tenant mutation. --- ## Scoring Guide - **PASS**: All database operations are tenant-scoped by `userId`, query dependency order is maintained, SQS message deletion occurs only after success, and all tests pass without runtime exceptions. - **FAIL**: Any query is unscoped, `recordingId` is referenced before `salutationToUpdate` resolves, SQS messages are deleted prematurely, or Mongoose query errors throw at runtime.