@@ -173,6 +173,51 @@ describe("MailboxDO", () => {
173173 expect ( elsewhere [ 0 ] . subject ) . toBe ( "Elsewhere" ) ;
174174 } ) ;
175175
176+ it ( "scopes thread search to the address, even when another address matches" , async ( ) => {
177+ // A thread on a *different* address whose sender matches the search term.
178+ // If the email_id filter and the OR'd LIKE clauses were not parenthesized,
179+ // this would leak into the searched address's results.
180+ await mailbox . ingestInbound (
181+ inbound ( {
182+ emailId : "email-other" ,
183+ subject : "Unrelated subject" ,
184+ fromEmail : "alice@example.com" ,
185+ } )
186+ ) ;
187+ const { threadId : mine } = await mailbox . ingestInbound (
188+ inbound ( { subject : "Quarterly report" , fromEmail : "alice@example.com" } )
189+ ) ;
190+ // A second thread on our address that should NOT match "alice".
191+ await mailbox . ingestInbound (
192+ inbound ( { subject : "Nothing to see" , fromEmail : "bob@example.com" } )
193+ ) ;
194+
195+ // Match by sender — only our address's matching thread is returned.
196+ const bySender = await mailbox . listThreads ( EMAIL_ID , 100 , 0 , "alice" ) ;
197+ expect ( bySender . map ( ( t ) => t . id ) ) . toEqual ( [ mine ] ) ;
198+
199+ // Match by subject — same isolation.
200+ const bySubject = await mailbox . listThreads ( EMAIL_ID , 100 , 0 , "report" ) ;
201+ expect ( bySubject . map ( ( t ) => t . id ) ) . toEqual ( [ mine ] ) ;
202+
203+ // The other address can still find its own thread by the same sender.
204+ const other = await mailbox . listThreads ( "email-other" , 100 , 0 , "alice" ) ;
205+ expect ( other ) . toHaveLength ( 1 ) ;
206+ expect ( other [ 0 ] . subject ) . toBe ( "Unrelated subject" ) ;
207+ } ) ;
208+
209+ it ( "treats typed LIKE wildcards as literals in search" , async ( ) => {
210+ const { threadId : literal } = await mailbox . ingestInbound (
211+ inbound ( { subject : "50% off sale" } )
212+ ) ;
213+ await mailbox . ingestInbound ( inbound ( { subject : "plain subject" } ) ) ;
214+
215+ // "%" must match a literal percent sign, not act as a wildcard (which
216+ // would otherwise also return "plain subject").
217+ const results = await mailbox . listThreads ( EMAIL_ID , 100 , 0 , "50%" ) ;
218+ expect ( results . map ( ( t ) => t . id ) ) . toEqual ( [ literal ] ) ;
219+ } ) ;
220+
176221 it ( "lists and fetches attachments scoped to a thread" , async ( ) => {
177222 const messageId = uuidv7 ( ) ;
178223 const attachmentId = uuidv7 ( ) ;
0 commit comments