Files
project-work/sources/holistic-rubric.md

3.5 KiB

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.