@@ -58,6 +58,7 @@ describe("npm tag cleanup", () => {
5858 delete registry . get ( packageName ) [ tag ] ;
5959 } ,
6060 report : ( ) => { } ,
61+ wait : async ( ) => { } ,
6162 } ,
6263 } ;
6364 }
@@ -86,6 +87,35 @@ describe("npm tag cleanup", () => {
8687 expect ( registry . get ( "bailian-cli-core" ) ) . toEqual ( { latest : "2.3.0" } ) ;
8788 } ) ;
8889
90+ test ( "waits for stale registry reads without repeating deletion" , async ( ) => {
91+ const { registry, operations } = registryFixture ( ) ;
92+ const originalReadTags = operations . readTags ;
93+ const originalRemoveTag = operations . removeTag ;
94+ const staleTags = { ...registry . get ( "bailian-cli" ) } ;
95+ let deletionCount = 0 ;
96+ let staleReads = 0 ;
97+ operations . removeTag = async ( packageName , tag ) => {
98+ deletionCount += 1 ;
99+ await originalRemoveTag ( packageName , tag ) ;
100+ staleReads = 2 ;
101+ } ;
102+ operations . readTags = async ( packageName ) => {
103+ if ( staleReads > 0 ) {
104+ staleReads -= 1 ;
105+ return { ...staleTags } ;
106+ }
107+ return originalReadTags ( packageName ) ;
108+ } ;
109+ const results = await cleanupNpmTags (
110+ { packages : [ "bailian-cli" ] , tags : [ "skill" ] , dryRun : false } ,
111+ operations ,
112+ ) ;
113+ expect ( results [ 0 ] . status ) . toBe ( "deleted" ) ;
114+ expect ( deletionCount ) . toBe ( 1 ) ;
115+ expect ( staleReads ) . toBe ( 0 ) ;
116+ expect ( registry . get ( "bailian-cli" ) ) . toEqual ( { latest : "2.3.0" } ) ;
117+ } ) ;
118+
89119 test ( "an unreadable package aborts preflight before deleting from any package" , async ( ) => {
90120 const { registry, operations } = registryFixture ( ) ;
91121 const readTags = operations . readTags ;
@@ -105,9 +135,14 @@ describe("npm tag cleanup", () => {
105135 test ( "failed deletion verification is not reported as success" , async ( ) => {
106136 const { operations } = registryFixture ( ) ;
107137 operations . removeTag = async ( ) => { } ;
138+ const delays = [ ] ;
139+ operations . wait = async ( delay ) => {
140+ delays . push ( delay ) ;
141+ } ;
108142 await expect (
109143 cleanupNpmTags ( { packages : [ "bailian-cli" ] , tags : [ "skill" ] , dryRun : false } , operations ) ,
110144 ) . rejects . toThrow ( / s t i l l e x i s t s / i) ;
145+ expect ( delays ) . toEqual ( [ 1000 , 2000 , 4000 , 8000 ] ) ;
111146 } ) ;
112147
113148 test ( "direct callers cannot bypass latest and package protections" , async ( ) => {
0 commit comments