Assert the authenticated tenant owns a memory id, returning it for use.
404 — never 403 — on a foreign id: the run router's rule, for the same
reason. A 403 would confirm that another tenant's threadId EXISTS, turning
every read path into an existence oracle over ids a caller can guess (a
resourceId is business identity — an email, a user id — so guessing is the
expected case, not a stretch).
This is the ONLY thing between a foreign threadId and its history — nothing
downstream re-checks. Mastra's recall filters by resourceId only when the
caller passes one (if (resourceId) query += ' AND resourceId = ?'), and core
ships recall sites that pass a threadId alone, so a foreign thread recalls in
FULL past this point (pinned in do-runner/memory-recall-tenancy.test.ts). Call
it on EVERY memory read path; there is no second line.
tenant.ownsMemoryId is exact because the tenant-ID pattern
excludes '' from tenant ids, so 'acme' can never own 'acmecorp...'
(do-runner/path-safe-id.ts).
Assert the authenticated tenant owns a memory id, returning it for use. 404 — never 403 — on a foreign id: the run router's rule, for the same reason. A 403 would confirm that another tenant's threadId EXISTS, turning every read path into an existence oracle over ids a caller can guess (a resourceId is business identity — an email, a user id — so guessing is the expected case, not a stretch).
This is the ONLY thing between a foreign threadId and its history — nothing downstream re-checks. Mastra's recall filters by
resourceIdonly when the caller passes one (if (resourceId) query += ' AND resourceId = ?'), and core ships recall sites that pass a threadId alone, so a foreign thread recalls in FULL past this point (pinned in do-runner/memory-recall-tenancy.test.ts). Call it on EVERY memory read path; there is no second line.tenant.ownsMemoryIdis exact because the tenant-ID pattern excludes '' from tenant ids, so 'acme' can never own 'acmecorp...' (do-runner/path-safe-id.ts).