@@ -405,7 +405,7 @@ describe("Prompts", () => {
405405 expect ( screen . getByRole ( "button" , { name : / m o r e o p t i o n s f o r t r a n s l a t e / i } ) ) . toBeInTheDocument ( ) ;
406406 } ) ;
407407
408- it ( "restores the deleted prompt row when the DELETE request fails" , async ( ) => {
408+ it ( "reconciles with the server and restores the row when the DELETE fails and the prompt survives " , async ( ) => {
409409 const user = userEvent . setup ( ) ;
410410 const prompts : Prompt [ ] = [
411411 createMockPrompt ( {
@@ -424,6 +424,9 @@ describe("Prompts", () => {
424424 } ) ,
425425 ] ;
426426
427+ // The DELETE fails and the prompt is NOT removed server-side (a pre-commit
428+ // failure), so the post-failure refetch still returns it and the row
429+ // reappears.
427430 server . use (
428431 http . get ( "/prompts" , ( ) => HttpResponse . json ( prompts ) ) ,
429432 http . delete ( "/prompts/prompt-1" , ( ) =>
@@ -447,14 +450,75 @@ describe("Prompts", () => {
447450 const dialog = await screen . findByRole ( "dialog" ) ;
448451 await user . click ( within ( dialog ) . getByRole ( "button" , { name : / ^ d e l e t e $ / i } ) ) ;
449452
450- // The optimistic removal is rolled back, so the row reappears.
453+ // The optimistic removal is reconciled against server truth, so the row
454+ // reappears because the prompt still exists.
451455 await waitFor ( ( ) => {
452456 expect (
453457 screen . getByRole ( "button" , { name : / m o r e o p t i o n s f o r s u m m a r i z e / i } ) ,
454458 ) . toBeInTheDocument ( ) ;
455459 } ) ;
456460 } ) ;
457461
462+ it ( "does not resurrect a prompt when the DELETE reports an error but the row is already gone" , async ( ) => {
463+ const user = userEvent . setup ( ) ;
464+ // Simulates a post-commit failure: PromptService.delete_prompt() commits
465+ // the removal, then a later step (notification/cache invalidation) fails
466+ // and the endpoint returns an error. The server no longer has the prompt,
467+ // so reconciling must NOT restore it.
468+ let remaining : Prompt [ ] = [
469+ createMockPrompt ( {
470+ id : "prompt-1" ,
471+ name : "summarize" ,
472+ displayName : "Summarize document" ,
473+ gatewayId : "gw-github" ,
474+ gatewaySlug : "gh-repo-tasks" ,
475+ } ) ,
476+ createMockPrompt ( {
477+ id : "prompt-2" ,
478+ name : "translate" ,
479+ displayName : "Translate document" ,
480+ gatewayId : "gw-github" ,
481+ gatewaySlug : "gh-repo-tasks" ,
482+ } ) ,
483+ ] ;
484+
485+ server . use (
486+ http . get ( "/prompts" , ( ) => HttpResponse . json ( remaining ) ) ,
487+ http . delete ( "/prompts/prompt-1" , ( ) => {
488+ // Row is committed as deleted, but the request still errors out.
489+ remaining = remaining . filter ( ( p ) => p . id !== "prompt-1" ) ;
490+ return HttpResponse . json ( { detail : "Post-commit hook failed" } , { status : 500 } ) ;
491+ } ) ,
492+ ) ;
493+
494+ renderWithProviders ( < Prompts /> ) ;
495+
496+ await waitFor ( ( ) => {
497+ expect ( screen . getByText ( "gh-repo-tasks" ) ) . toBeInTheDocument ( ) ;
498+ } ) ;
499+
500+ await user . click ( screen . getByRole ( "button" , { name : "More options for gh-repo-tasks" } ) ) ;
501+ await user . click ( await screen . findByRole ( "menuitem" , { name : "View details" } ) ) ;
502+ await user . click ( await screen . findByRole ( "tab" , { name : / d e f i n i t i o n / i } ) ) ;
503+
504+ await user . click ( await screen . findByRole ( "button" , { name : / m o r e o p t i o n s f o r s u m m a r i z e / i } ) ) ;
505+ await user . click ( await screen . findByRole ( "menuitem" , { name : "Delete" } ) ) ;
506+
507+ const dialog = await screen . findByRole ( "dialog" ) ;
508+ await user . click ( within ( dialog ) . getByRole ( "button" , { name : / ^ d e l e t e $ / i } ) ) ;
509+
510+ // The drawer stays open with the surviving sibling, and the deleted prompt
511+ // is not brought back by the failure path.
512+ await waitFor ( ( ) => {
513+ expect (
514+ screen . getByRole ( "button" , { name : / m o r e o p t i o n s f o r t r a n s l a t e / i } ) ,
515+ ) . toBeInTheDocument ( ) ;
516+ } ) ;
517+ expect (
518+ screen . queryByRole ( "button" , { name : / m o r e o p t i o n s f o r s u m m a r i z e / i } ) ,
519+ ) . not . toBeInTheDocument ( ) ;
520+ } ) ;
521+
458522 it ( "collapses gateway-less prompts into a single REST prompts card" , async ( ) => {
459523 const prompts : Prompt [ ] = [
460524 createMockPrompt ( {
0 commit comments