1515# limitations under the License.
1616#
1717
18- import hashlib
1918import time
2019from datetime import datetime
2120from typing import Annotated , Any , Dict , Tuple
@@ -85,7 +84,7 @@ def approve_deployment(
8584 )
8685
8786 # Generate model checksum for identification
88- model_id = run_id [: 8 ] # Use first 8 chars of run ID as model ID
87+ model_id = run_id # Use first 8 chars of run ID as model ID
8988
9089 # Approval criteria checks
9190 perf_ok = accuracy >= approval_thresholds .get ("accuracy" , 0.7 )
@@ -97,18 +96,16 @@ def approve_deployment(
9796
9897 # Create Slack message with enhanced pipeline context
9998 header_text = (
100- ":white_check_mark: *MODEL AUTO-APPROVED!*"
101- if all_ok
102- else ":warning: *HUMAN REVIEW REQUIRED*"
99+ "*MODEL AUTO-APPROVED*" if all_ok else "*HUMAN REVIEW REQUIRED*"
103100 )
104101
105102 blocks = [
106103 {
107104 "type" : "header" ,
108105 "text" : {
109106 "type" : "plain_text" ,
110- "text" : "💶 CreditScorer Model Approval" ,
111- "emoji" : True ,
107+ "text" : "Model Approval" ,
108+ "emoji" : False ,
112109 },
113110 },
114111 {"type" : "section" , "text" : {"type" : "mrkdwn" , "text" : header_text }},
@@ -119,7 +116,7 @@ def approve_deployment(
119116 {"type" : "mrkdwn" , "text" : f"*Pipeline:* { pipeline_name } " },
120117 {"type" : "mrkdwn" , "text" : f"*Model ID:* { model_id } " },
121118 {"type" : "mrkdwn" , "text" : f"*Stack:* { stack_name } " },
122- {"type" : "mrkdwn" , "text" : f"*Run ID:* { run_id [: 12 ] } ... " },
119+ {"type" : "mrkdwn" , "text" : f"*Run ID:* { run_id } " },
123120 ],
124121 },
125122 {"type" : "divider" },
@@ -128,19 +125,19 @@ def approve_deployment(
128125 "fields" : [
129126 {
130127 "type" : "mrkdwn" ,
131- "text" : f"{ '✅' if perf_ok else '❌' } *Accuracy= * { accuracy :.3f} " ,
128+ "text" : f"{ '✅' if perf_ok else '❌' } *Accuracy: * { accuracy :.3f} " ,
132129 },
133130 {
134131 "type" : "mrkdwn" ,
135- "text" : f"{ '✅' if risk_ok else '❌' } *Risk Score= * { risk_score :.3f} " ,
132+ "text" : f"{ '✅' if risk_ok else '❌' } *Risk Score: * { risk_score :.3f} " ,
136133 },
137134 {
138135 "type" : "mrkdwn" ,
139- "text" : f"{ '✅' if fairness_ok else '❌' } *F1= * { f1_score :.3f} " ,
136+ "text" : f"{ '✅' if fairness_ok else '❌' } *F1 Score: * { f1_score :.3f} " ,
140137 },
141138 {
142139 "type" : "mrkdwn" ,
143- "text" : f"*AUC= * { auc_roc :.3f} " ,
140+ "text" : f"*AUC: * { auc_roc :.3f} " ,
144141 },
145142 ],
146143 },
@@ -151,10 +148,6 @@ def approve_deployment(
151148 "type" : "mrkdwn" ,
152149 "text" : f"*Bias Check:* { '✅ No bias detected' if fairness_ok else f'❌ Max disparity: { max_disparity :.3f} ' } " ,
153150 },
154- {
155- "type" : "mrkdwn" ,
156- "text" : f"*Protected Attributes:* { len (fairness_metrics )} checked" ,
157- },
158151 ],
159152 },
160153 {
@@ -197,10 +190,50 @@ def approve_deployment(
197190 else :
198191 if alerter :
199192 try :
200- # Enhanced question with pipeline context
201- question = f"Should CreditScorer deploy model { model_id } from pipeline '{ pipeline_name } '? Reply with 'yes' or 'no'"
193+ # Simplified approval question with clearer formatting
194+ approval_blocks = [
195+ {
196+ "type" : "section" ,
197+ "text" : {
198+ "type" : "mrkdwn" ,
199+ "text" : "*Deployment Approval Required*" ,
200+ },
201+ },
202+ {"type" : "divider" },
203+ {
204+ "type" : "section" ,
205+ "fields" : [
206+ {
207+ "type" : "mrkdwn" ,
208+ "text" : f"*Model ID:* { model_id } " ,
209+ },
210+ {
211+ "type" : "mrkdwn" ,
212+ "text" : f"*Pipeline:* { pipeline_name } " ,
213+ },
214+ ],
215+ },
216+ {
217+ "type" : "context" ,
218+ "elements" : [
219+ {
220+ "type" : "mrkdwn" ,
221+ "text" : "_Override deployment? Reply with 'yes' or 'no'_" ,
222+ }
223+ ],
224+ },
225+ ]
226+
227+ approval_params = SlackAlerterParameters (
228+ blocks = approval_blocks
229+ )
230+
231+ # Use a more direct question for the alerter.ask function
232+ question = (
233+ f"Override deployment for pipeline '{ pipeline_name } '?"
234+ )
202235 print ("📱 Asking approval question in Slack..." )
203- response = alerter .ask (question )
236+ response = alerter .ask (question , params = approval_params )
204237 print (f"📱 Received Slack response: { response } " )
205238
206239 # Handle various response formats
@@ -252,10 +285,19 @@ def approve_deployment(
252285 "type" : "header" ,
253286 "text" : {
254287 "type" : "plain_text" ,
255- "text" : "💶 CreditScorer Deployment Confirmed" ,
256- "emoji" : True ,
288+ "text" : "Deployment Confirmed" ,
289+ "emoji" : False ,
257290 },
258291 },
292+ {
293+ "type" : "context" ,
294+ "elements" : [
295+ {
296+ "type" : "mrkdwn" ,
297+ "text" : "_CreditScorer_" ,
298+ }
299+ ],
300+ },
259301 {
260302 "type" : "section" ,
261303 "text" : {
@@ -286,7 +328,7 @@ def approve_deployment(
286328 "type" : "section" ,
287329 "text" : {
288330 "type" : "mrkdwn" ,
289- "text" : f"🚀 *Deployment will proceed automatically*\n _Model checksum: { run_id } _" ,
331+ "text" : f"*Deployment will proceed automatically*\n _Model checksum: { run_id } _" ,
290332 },
291333 },
292334 ]
@@ -295,7 +337,7 @@ def approve_deployment(
295337 blocks = confirmation_blocks
296338 )
297339 alerter .post (
298- "✅ CreditScorer model approved for deployment" ,
340+ "✅ Model approved for deployment" ,
299341 params = confirmation_params ,
300342 )
301343 print ("📱 Deployment confirmation sent to Slack" )
0 commit comments