@@ -73,6 +73,21 @@ const WORKSPACE_PAYLOAD = {
7373 billingAttribution : BILLING_ATTRIBUTION ,
7474}
7575
76+ const ORGANIZATION_PAYLOAD = {
77+ ...BASE_PAYLOAD ,
78+ billingScope : 'organization' as const ,
79+ actorUserId : 'organization-member' ,
80+ workspaceId : null ,
81+ organizationId : 'organization-1' ,
82+ billingAttribution : {
83+ ...BILLING_ATTRIBUTION ,
84+ actorUserId : 'organization-member' ,
85+ workspaceId : null ,
86+ organizationId : 'organization-1' ,
87+ billingEntity : { type : 'organization' as const , id : 'organization-1' } ,
88+ } ,
89+ }
90+
7691function mockQuotaExhaustion ( error : EmbeddingQuotaExhaustedError ) : void {
7792 mockProcessDocumentAsync . mockImplementation ( async ( ...args : unknown [ ] ) => {
7893 const attemptContext = args [ 6 ] as {
@@ -229,6 +244,36 @@ describe('knowledge processing worker', () => {
229244 )
230245 } )
231246
247+ it ( 'preserves organization ownership and billing attribution in the worker' , async ( ) => {
248+ await runDocumentProcessing ( structuredClone ( ORGANIZATION_PAYLOAD ) )
249+
250+ expect ( mockProcessDocumentAsync ) . toHaveBeenCalledWith (
251+ BASE_PAYLOAD . knowledgeBaseId ,
252+ BASE_PAYLOAD . documentId ,
253+ BASE_PAYLOAD . docData ,
254+ BASE_PAYLOAD . processingOptions ,
255+ {
256+ billingScope : 'organization' ,
257+ actorUserId : ORGANIZATION_PAYLOAD . actorUserId ,
258+ workspaceId : null ,
259+ organizationId : ORGANIZATION_PAYLOAD . organizationId ,
260+ billingAttribution : ORGANIZATION_PAYLOAD . billingAttribution ,
261+ } ,
262+ BASE_PAYLOAD . requestId ,
263+ expect . objectContaining ( {
264+ chargedAtDispatch : true ,
265+ processingQueuedAt : new Date ( BASE_PAYLOAD . processingQueuedAt ) ,
266+ } )
267+ )
268+ } )
269+
270+ it ( 'rejects an organization mismatch before document processing starts' , async ( ) => {
271+ await expect (
272+ runDocumentProcessing ( { ...ORGANIZATION_PAYLOAD , organizationId : 'organization-2' } )
273+ ) . rejects . toThrow ( 'Document processing organization does not match billing attribution' )
274+ expect ( mockProcessDocumentAsync ) . not . toHaveBeenCalled ( )
275+ } )
276+
232277 it ( 'rejects an actor mismatch before document processing starts' , async ( ) => {
233278 await expect (
234279 runDocumentProcessing ( {
0 commit comments