@@ -81,17 +81,16 @@ async function inspectBackendRelease(api, referenceHash) {
8181 const initial = await api . deployments ( ) ;
8282 const traffic = initial ?. deployments ?. [ 0 ] ?. versions ;
8383 if ( Array . isArray ( traffic ) && traffic . length <= 10 && traffic . every ( v => uuid ( v ?. version_id ) && Number . isFinite ( v ?. percentage ) ) )
84- result . traffic = traffic . map ( v => ( { version_prefix : v . version_id . slice ( 0 , 8 ) , percentage :v . percentage } ) ) ;
84+ result . traffic = traffic . map ( ( v , index ) => ( { slot : index + 1 , percentage :v . percentage } ) ) ;
8585 const prior = activeIdentity ( initial ) ;
86- result . active = { deployment_prefix : prior . deployment . slice ( 0 , 8 ) , version_prefix : prior . version . slice ( 0 , 8 ) } ;
86+ result . single_active_version = true ;
8787 stage = 'version_list' ;
8888 const listed = versions ( await api . versions ( ) ) ;
8989 result . active_listed = listed . includes ( prior . version ) ;
9090 result . active_is_latest = listed [ 0 ] === prior . version ;
9191 stage = 'module' ;
9292 const bytes = readModule ( await api . betaVersion ( prior . version ) , prior . version ) ;
93- result . module_sha256 = createHash ( 'sha256' ) . update ( bytes ) . digest ( 'hex' ) ;
94- result . module_matches_reference = result . module_sha256 === referenceHash ;
93+ result . module_matches_reference = hash ( bytes ) === referenceHash ;
9594 stage = 'configuration' ;
9695 const live = readConfiguration ( await api . scriptVersion ( prior . version ) , prior . version ) ;
9796 const runtime = live . script_runtime ;
@@ -109,19 +108,33 @@ async function inspectBackendRelease(api, referenceHash) {
109108 stage = 'recheck' ;
110109 if ( JSON . stringify ( activeIdentity ( await api . deployments ( ) ) ) !== JSON . stringify ( prior ) ||
111110 JSON . stringify ( versions ( await api . versions ( ) ) ) !== JSON . stringify ( listed ) ) throw Error ( 'active_drift' ) ;
112- return { result :{ ...result , ok :true } , version :prior . version } ;
111+ return { result :{ ...result , ok :true , active_identity_unchanged : true } , version :prior . version } ;
113112 } catch {
114113 return { result :{ ...result , ok :false , stage} } ;
115114 }
116115}
117116
118- export async function preflight ( api ) {
117+ export function readRollbackTargets ( git ) {
118+ const workflow = git ( 'show' , 'HEAD:.github/workflows/deploy-strategy-switch-console.yml' ) ;
119+ const fixed = workflow . split ( ' - name: Restore fixed pre-release Worker version' ) ;
120+ if ( fixed . length !== 2 ) throw Error ( 'rollback_policy' ) ;
121+ const target = pattern => {
122+ const matches = [ ...fixed [ 1 ] . matchAll ( pattern ) ] ;
123+ if ( matches . length !== 1 || ! uuid ( matches [ 0 ] [ 1 ] ) ) throw Error ( 'rollback_policy' ) ;
124+ return matches [ 0 ] [ 1 ] ;
125+ } ;
126+ return {
127+ fixed :[ target ( / c o n s t t a r g e t = p r o c e s s \. e n v \. R O L L B A C K _ V E R S I O N \| \| ' ( [ ^ ' ] + ) ' ; / g) ,
128+ target ( / c o n s t f e 1 1 = t a r g e t = = = ' ( [ ^ ' ] + ) ' ; / g) ] ,
129+ fixedSuccessor :target ( / c o n s t d a i l y R e s t o r e = t a r g e t = = = ' ( [ ^ ' ] + ) ' ; / g) ,
130+ } ;
131+ }
132+ export async function preflight ( api , rollbackTargets = { fixed :[ ] , fixedSuccessor :null } ) {
119133 const { result, version} = await inspectBackendRelease ( api , POLICY . before ) ;
120134 if ( ! result . ok ) return result ;
121- // Only the first two fixed rollback targets can follow an arbitrary deployment.
122- // The daily restore target requires an unrelated fixed successor deployment.
123- const route = [ '2beea000-cce5-43a5-9255-9724f7318e83' , 'c8dc4852-fa9d-4d14-bca3-7941587a494f' ] . includes ( version )
124- ? 'fixed_target' : version === '06043e24-f8c9-4129-8c59-abb9957217bf' ? 'fixed_successor_only' : 'no_matching_target' ;
135+ // The daily restore target requires a specific, unrelated successor deployment.
136+ const route = rollbackTargets . fixed . includes ( version ) ? 'fixed_target'
137+ : version === rollbackTargets . fixedSuccessor ? 'fixed_successor_only' : 'no_matching_target' ;
125138 return { ...result , source :POLICY . source , candidate_sha256 :POLICY . candidate , reference_sha256 :POLICY . before ,
126139 rollback :{ route, prior_version_readable :true , write_rehearsed :false ,
127140 eligible_after_release :route === 'fixed_target' && result . active_listed && result . module_matches_reference && result . configuration . migration_tag_present } ,
@@ -140,7 +153,7 @@ async function main() {
140153 evidence . source !== POLICY . source || evidence . tree !== POLICY . tree || evidence . frontendBlob !== POLICY . frontendBlob )
141154 throw Error ( 'provenance' ) ;
142155 if ( action === 'preflight' ) {
143- const result = await preflight ( createPreflightApi ( ) ) ;
156+ const result = await preflight ( createPreflightApi ( ) , readRollbackTargets ( git ) ) ;
144157 console . log ( JSON . stringify ( result ) ) ;
145158 if ( ! result . ok ) process . exitCode = 1 ;
146159 return ;
0 commit comments