@@ -177,3 +177,32 @@ describe('protocol.duplicatePackage (ADR-0070 D4)', () => {
177177 expect ( calls . some ( ( c : any ) => / i o j n _ / . test ( c . name ) ) ) . toBe ( false ) ; // no un-renamed leftovers
178178 } ) ;
179179} ) ;
180+
181+ describe ( 'protocol.reassignOrphanedMetadata (ADR-0070 D5)' , ( ) => {
182+ it ( 'rebinds package-less orphans (null / "" / sys_metadata) into the target base; leaves owned rows' , async ( ) => {
183+ const rows = [
184+ { id : 'r1' , type : 'object' , name : 'loose_a' , package_id : null } ,
185+ { id : 'r2' , type : 'view' , name : 'loose_v' , package_id : 'sys_metadata' } ,
186+ { id : 'r3' , type : 'object' , name : 'blank' , package_id : '' } ,
187+ { id : 'r4' , type : 'object' , name : 'owned' , package_id : 'app.existing' } ,
188+ ] ;
189+ const update = vi . fn ( async ( ) => ( { id : 'x' } ) ) ;
190+ const engine = { find : vi . fn ( async ( ) => rows ) , update } ;
191+ const protocol = new ObjectStackProtocolImplementation ( engine as never ) ;
192+ const res = await protocol . reassignOrphanedMetadata ( { targetPackageId : 'app.home' } ) ;
193+
194+ expect ( res ) . toMatchObject ( { success : true , reassignedCount : 3 , targetPackageId : 'app.home' } ) ;
195+ const movedIds = update . mock . calls . map ( ( c : any ) => c [ 2 ] . where . id ) ;
196+ expect ( movedIds ) . toEqual ( [ 'r1' , 'r2' , 'r3' ] ) ; // the 3 orphans, not the owned r4
197+ expect ( update ) . toHaveBeenCalledWith ( 'sys_metadata' , { package_id : 'app.home' } , { where : { id : 'r1' } } ) ;
198+ expect ( res . reassigned . some ( ( x ) => x . name === 'owned' ) ) . toBe ( false ) ;
199+ } ) ;
200+
201+ it ( 'no orphans → reassignedCount 0, success false' , async ( ) => {
202+ const engine = { find : vi . fn ( async ( ) => [ { id : 'r1' , type : 'object' , name : 'x' , package_id : 'app.a' } ] ) , update : vi . fn ( ) } ;
203+ const protocol = new ObjectStackProtocolImplementation ( engine as never ) ;
204+ const res = await protocol . reassignOrphanedMetadata ( { targetPackageId : 'app.home' } ) ;
205+ expect ( res ) . toMatchObject ( { success : false , reassignedCount : 0 } ) ;
206+ expect ( ( engine . update as any ) ) . not . toHaveBeenCalled ( ) ;
207+ } ) ;
208+ } ) ;
0 commit comments