@@ -18,10 +18,11 @@ function commit(cwd: string, file: string, content: string, message: string): st
1818 return runGit ( "rev-parse HEAD" , cwd ) ;
1919}
2020
21- function release ( name : string , commitSha : string | undefined , daysAgoCreated : number ) : Release {
21+ function release ( name : string , commitSha : string | undefined , daysAgoCreated : number , version ?: string ) : Release {
2222 return {
2323 id : `id-${ name } ` ,
2424 name,
25+ version,
2526 commitSha,
2627 createdAt : new Date ( Date . now ( ) - daysAgoCreated * 24 * 60 * 60 * 1000 ) . toISOString ( ) ,
2728 } ;
@@ -61,11 +62,11 @@ function buildRepo() {
6162
6263 // Back to main
6364 runGit ( "checkout -q main" , cwd ) ;
64- commit ( cwd , "f" , "2" , "m2" ) ;
65+ const m2 = commit ( cwd , "f" , "2" , "m2" ) ;
6566 const mainPrev = commit ( cwd , "f" , "3" , "m3 (1.71.0 release)" ) ;
6667 const mainHead = commit ( cwd , "f" , "4" , "m4 (1.72.0 HEAD)" ) ;
6768
68- return { cwd, hotfixSha, hotfixHead, mainPrev, mainHead } ;
69+ return { cwd, m1 , m2 , hotfixSha, hotfixHead, mainPrev, mainHead } ;
6970}
7071
7172describe ( "findBaseSha" , ( ) => {
@@ -127,6 +128,40 @@ describe("findBaseSha", () => {
127128 it ( "scenario F — empty list (first-ever sync): returns fallback" , ( ) => {
128129 expect ( findBaseSha ( [ ] , repo . mainHead , deps ) ) . toEqual ( { kind : "fallback" } ) ;
129130 } ) ;
131+
132+ it ( "scenario G — zombie ordering without a version match: picks the stale reachable candidate" , ( ) => {
133+ // Server-side recency ordering is the guard against stale started releases
134+ // appearing first; without a version match, the existing walk is preserved.
135+ const candidates = [
136+ release ( "stale started release" , repo . m1 , 21 ) ,
137+ release ( "newer completed release" , repo . mainPrev , 1 ) ,
138+ ] ;
139+ expect ( findBaseSha ( candidates , repo . mainHead , deps ) ) . toEqual ( { kind : "found" , sha : repo . m1 } ) ;
140+ } ) ;
141+
142+ it ( "scenario H — reachable version match: takes priority over an earlier reachable candidate" , ( ) => {
143+ const candidates = [
144+ release ( "stale started release" , repo . m1 , 21 ) ,
145+ release ( "newer completed release" , repo . mainPrev , 1 ) ,
146+ release ( "matching release" , repo . m2 , 2 , "1.72.0" ) ,
147+ ] ;
148+ expect ( findBaseSha ( candidates , repo . mainHead , deps , "1.72.0" ) ) . toEqual ( {
149+ kind : "found" ,
150+ sha : repo . m2 ,
151+ } ) ;
152+ } ) ;
153+
154+ it ( "scenario I — non-ancestor version match: falls back to the normal walk" , ( ) => {
155+ const candidates = [
156+ release ( "stale started release" , repo . m1 , 21 ) ,
157+ release ( "unreachable matching release" , repo . hotfixSha , 2 , "1.72.0" ) ,
158+ release ( "newer completed release" , repo . mainPrev , 1 ) ,
159+ ] ;
160+ expect ( findBaseSha ( candidates , repo . mainHead , deps , "1.72.0" ) ) . toEqual ( {
161+ kind : "found" ,
162+ sha : repo . m1 ,
163+ } ) ;
164+ } ) ;
130165} ) ;
131166
132167/**
0 commit comments