Repository: akuity/kargo

Issue:
Mark steps as skipped if "if" evaluates to false
# Checklist

* [x] I've searched the issue queue to verify this is not a duplicate feature request.
* [x] I've pasted the output of `kargo version`, if applicable.
* [x] I've pasted logs, if applicable.

# Proposed Feature
If a step as the an "if" statement and that evaluates to false then the step should me marked as skipped.  

# Motivation
Today the step is marked with a green check box which indicates it was successfully run.  That step hasn't actually been run but there is not indication of this in the UI.

![Image](https://github.com/user-attachments/assets/f46f60f9-ab28-422f-b3db-89e35f839924)

<!-- Please give examples of your use case. i.e. When would someone use this? -->

# Suggested Implementation

- I think you just need a different icon there at a minimum.  If you expand the step out there isn't a good indicator that it was skipped.  You can tell because there is no OUTPUT or CONFIG section but that is much too subtle.  It should be clear that the step was skipped.


Hints from issue comments:
@krancour: @Marvin9 I might need a hand with the UI side of this.@Marvin9: Sure @krancour Let me know whats the ideal way to extract the information that this step was skipped?

Solution patch:
diff --git a/api/v1alpha1/generated.pb.go b/api/v1alpha1/generated.pb.go
index 088d5cf5..a1850a2f 100644
--- a/api/v1alpha1/generated.pb.go
+++ b/api/v1alpha1/generated.pb.go
@@ -2134,282 +2134,282 @@ func init() {
 }
 
 var fileDescriptor_e26b7f7bbc391025 = []byte{
-	// 4386 bytes of a gzipped FileDescriptorProto
+	// 4387 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5c, 0x4d, 0x6c, 0x23, 0x47,
-	0x76, 0x9e, 0x26, 0x45, 0x4a, 0x7c, 0xd4, 0x6f, 0x8d, 0xc6, 0xd6, 0xca, 0xb1, 0x34, 0x69, 0x1b,
-	0x86, 0x1d, 0xdb, 0x54, 0x46, 0xe3, 0xb1, 0xc7, 0x33, 0xce, 0x04, 0x22, 0x35, 0x3f, 0x9a, 0xd5,
-	0x7a, 0x94, 0xa2, 0x3c, 0x5e, 0x8f, 0x3d, 0x98, 0x94, 0xc8, 0x12, 0xd9, 0x2b, 0xb2, 0x9b, 0xee,
-	0x6a, 0xca, 0xa3, 0x24, 0x48, 0x9c, 0x5f, 0x04, 0x49, 0x10, 0x18, 0xc8, 0x06, 0xde, 0x43, 0x82,
-	0x04, 0xc9, 0x69, 0xb1, 0x40, 0xae, 0x39, 0xe4, 0xe0, 0x43, 0x2e, 0x4e, 0xb2, 0x09, 0x8c, 0xcd,
-	0x21, 0x0e, 0xb0, 0x50, 0xd6, 0x5a, 0x20, 0xe7, 0x5c, 0x72, 0x19, 0x20, 0x40, 0x50, 0x3f, 0xdd,
-	0x5d, 0xdd, 0x6c, 0x8e, 0xd8, 0xd4, 0xcf, 0x0e, 0x7c, 0x93, 0xea, 0x55, 0x7d, 0xaf, 0xea, 0x55,
-	0xbd, 0x57, 0xef, 0xbd, 0x7a, 0x4d, 0x78, 0xad, 0x61, 0x79, 0xcd, 0xee, 0x56, 0xa9, 0xe6, 0xb4,
-	0x97, 0xc8, 0x4e, 0xd7, 0xf2, 0xf6, 0x96, 0x76, 0x88, 0xdb, 0x70, 0x96, 0x48, 0xc7, 0x5a, 0xda,
-	0xbd, 0x40, 0x5a, 0x9d, 0x26, 0xb9, 0xb0, 0xd4, 0xa0, 0x36, 0x75, 0x89, 0x47, 0xeb, 0xa5, 0x8e,
-	0xeb, 0x78, 0x0e, 0x7a, 0x3e, 0x1c, 0x55, 0x92, 0xa3, 0x4a, 0x62, 0x54, 0x89, 0x74, 0xac, 0x92,
-	0x3f, 0x6a, 0xfe, 0x55, 0x0d, 0xbb, 0xe1, 0x34, 0x9c, 0x25, 0x31, 0x78, 0xab, 0xbb, 0x2d, 0xfe,
-	0x13, 0xff, 0x88, 0xbf, 0x24, 0xe8, 0xfc, 0xad, 0x9d, 0xcb, 0xac, 0x64, 0x09, 0xce, 0xf4, 0xa1,
-	0x47, 0x6d, 0x66, 0x39, 0x36, 0x7b, 0x95, 0x74, 0x2c, 0x46, 0xdd, 0x5d, 0xea, 0x2e, 0x75, 0x76,
-	0x1a, 0x9c, 0xc6, 0xa2, 0x1d, 0x96, 0x76, 0x7b, 0xa6, 0x37, 0xff, 0x5a, 0x88, 0xd4, 0x26, 0xb5,
-	0xa6, 0x65, 0x53, 0x77, 0x2f, 0x1c, 0xde, 0xa6, 0x1e, 0x49, 0x1a, 0xb5, 0xd4, 0x6f, 0x94, 0xdb,
-	0xb5, 0x3d, 0xab, 0x4d, 0x7b, 0x06, 0xbc, 0x7e, 0xd8, 0x00, 0x56, 0x6b, 0xd2, 0x36, 0x89, 0x8f,
-	0x33, 0x3f, 0x80, 0xb3, 0x2b, 0x36, 0x69, 0xed, 0x31, 0x8b, 0xe1, 0xae, 0xbd, 0xe2, 0x36, 0xba,
-	0x6d, 0x6a, 0x7b, 0xe8, 0x3c, 0x8c, 0xd8, 0xa4, 0x4d, 0xe7, 0x8c, 0xf3, 0xc6, 0x8b, 0x85, 0xf2,
-	0xf8, 0xe7, 0xfb, 0x8b, 0x67, 0x0e, 0xf6, 0x17, 0x47, 0xde, 0x26, 0x6d, 0x8a, 0x05, 0x05, 0x3d,
-	0x07, 0xb9, 0x5d, 0xd2, 0xea, 0xd2, 0xb9, 0x8c, 0xe8, 0x32, 0xa1, 0xba, 0xe4, 0xee, 0xf2, 0x46,
-	0x2c, 0x69, 0xe6, 0xef, 0x66, 0x23, 0xf0, 0xdf, 0xa2, 0x1e, 0xa9, 0x13, 0x8f, 0xa0, 0x36, 0xe4,
-	0x5b, 0x64, 0x8b, 0xb6, 0xd8, 0x9c, 0x71, 0x3e, 0xfb, 0x62, 0x71, 0xf9, 0x7a, 0x69, 0x90, 0x4d,
-	0x2c, 0x25, 0x40, 0x95, 0xd6, 0x05, 0xce, 0x75, 0xdb, 0x73, 0xf7, 0xca, 0x93, 0x6a, 0x12, 0x79,
-	0xd9, 0x88, 0x15, 0x13, 0xf4, 0xdb, 0x06, 0x14, 0x89, 0x6d, 0x3b, 0x1e, 0xf1, 0xf8, 0x36, 0xcd,
-	0x65, 0x04, 0xd3, 0xdb, 0xc3, 0x33, 0x5d, 0x09, 0xc1, 0x24, 0xe7, 0xb3, 0x8a, 0x73, 0x51, 0xa3,
-	0x60, 0x9d, 0xe7, 0xfc, 0x9b, 0x50, 0xd4, 0xa6, 0x8a, 0xa6, 0x21, 0xbb, 0x43, 0xf7, 0xa4, 0x7c,
-	0x31, 0xff, 0x13, 0xcd, 0x46, 0x04, 0xaa, 0x24, 0x78, 0x25, 0x73, 0xd9, 0x98, 0xbf, 0x06, 0xd3,
-	0x71, 0x86, 0x69, 0xc6, 0x9b, 0x7f, 0x6a, 0xc0, 0xac, 0xb6, 0x0a, 0x4c, 0xb7, 0xa9, 0x4b, 0xed,
-	0x1a, 0x45, 0x4b, 0x50, 0xe0, 0x7b, 0xc9, 0x3a, 0xa4, 0xe6, 0x6f, 0xf5, 0x8c, 0x5a, 0x48, 0xe1,
-	0x6d, 0x9f, 0x80, 0xc3, 0x3e, 0xc1, 0xb1, 0xc8, 0x3c, 0xee, 0x58, 0x74, 0x9a, 0x84, 0xd1, 0xb9,
-	0x6c, 0xf4, 0x58, 0x6c, 0xf0, 0x46, 0x2c, 0x69, 0xe6, 0x03, 0xf8, 0x86, 0x3f, 0x9f, 0x4d, 0xda,
-	0xee, 0xb4, 0x88, 0x47, 0xc3, 0x49, 0x1d, 0x7e, 0xf4, 0xce, 0xc3, 0xc8, 0x8e, 0x65, 0xd7, 0xe3,
-	0xb3, 0xf8, 0xa6, 0x65, 0xd7, 0xb1, 0xa0, 0x98, 0x3b, 0x30, 0xb1, 0xd2, 0xe9, 0xb8, 0xce, 0x2e,
-	0xad, 0x57, 0x3d, 0xd2, 0xa0, 0xe8, 0x1e, 0x00, 0x51, 0x0d, 0x2b, 0x9e, 0x80, 0x2e, 0x2e, 0xff,
-	0x42, 0x49, 0xea, 0x4c, 0x49, 0xd7, 0x99, 0x52, 0x67, 0xa7, 0xc1, 0x1b, 0x58, 0x89, 0xab, 0x66,
-	0x69, 0xf7, 0x42, 0x69, 0xd3, 0x6a, 0xd3, 0xf2, 0xe4, 0xc1, 0xfe, 0x22, 0xac, 0x04, 0x08, 0x58,
-	0x43, 0x33, 0x7f, 0xc7, 0x80, 0x73, 0x2b, 0x6e, 0xc3, 0xa9, 0xac, 0xae, 0x74, 0x3a, 0xb7, 0x28,
-	0x69, 0x79, 0xcd, 0xaa, 0x47, 0xbc, 0x2e, 0x43, 0xd7, 0x20, 0xcf, 0xc4, 0x5f, 0x6a, 0x31, 0x2f,
-	0xf8, 0xe7, 0x53, 0xd2, 0x1f, 0xed, 0x2f, 0xce, 0x26, 0x0c, 0xa4, 0x58, 0x8d, 0x42, 0x2f, 0xc1,
-	0x68, 0x9b, 0x32, 0x46, 0x1a, 0xbe, 0xc4, 0xa7, 0x14, 0xc0, 0xe8, 0xb7, 0x64, 0x33, 0xf6, 0xe9,
-	0xe6, 0x3f, 0x67, 0x60, 0x2a, 0xc0, 0x52, 0xec, 0x4f, 0x60, 0x7b, 0xbb, 0x30, 0xde, 0xd4, 0x56,
-	0x28, 0x76, 0xb9, 0xb8, 0x7c, 0x75, 0x40, 0x4d, 0x4a, 0x12, 0x52, 0x79, 0x56, 0xb1, 0x19, 0xd7,
-	0x5b, 0x71, 0x84, 0x0d, 0x6a, 0x03, 0xb0, 0x3d, 0xbb, 0xa6, 0x98, 0x8e, 0x08, 0xa6, 0x6f, 0xa6,
-	0x64, 0x5a, 0x0d, 0x00, 0xca, 0x48, 0xb1, 0x84, 0xb0, 0x0d, 0x6b, 0x0c, 0xcc, 0xbf, 0x33, 0xe0,
-	0x6c, 0xc2, 0x38, 0xf4, 0x56, 0x6c, 0x3f, 0x9f, 0xef, 0xd9, 0x4f, 0xd4, 0x33, 0x2c, 0xdc, 0xcd,
-	0x57, 0x60, 0xcc, 0xa5, 0xbb, 0x16, 0xbf, 0x29, 0x94, 0x84, 0xa7, 0xd5, 0xf8, 0x31, 0xac, 0xda,
-	0x71, 0xd0, 0x03, 0xbd, 0x0c, 0x05, 0xff, 0x6f, 0x2e, 0xe6, 0x2c, 0x57, 0x26, 0xbe, 0x71, 0x7e,
-	0x57, 0x86, 0x43, 0xba, 0xf9, 0x5b, 0x90, 0xab, 0x34, 0x89, 0xeb, 0xf1, 0x13, 0xe3, 0xd2, 0x8e,
-	0xf3, 0x0e, 0x5e, 0x57, 0x53, 0x0c, 0x4e, 0x0c, 0x96, 0xcd, 0xd8, 0xa7, 0x0f, 0xb0, 0xd9, 0x2f,
-	0xc1, 0xe8, 0x2e, 0x75, 0xc5, 0x7c, 0xb3, 0x51, 0xb0, 0xbb, 0xb2, 0x19, 0xfb, 0x74, 0xf3, 0xdf,
-	0x0d, 0x98, 0x15, 0x33, 0x58, 0xb5, 0x58, 0xcd, 0xd9, 0xa5, 0xee, 0x1e, 0xa6, 0xac, 0xdb, 0x3a,
-	0xe6, 0x09, 0xad, 0xc2, 0x34, 0xa3, 0xed, 0x5d, 0xea, 0x56, 0x1c, 0x9b, 0x79, 0x2e, 0xb1, 0x6c,
-	0x4f, 0xcd, 0x6c, 0x4e, 0xf5, 0x9e, 0xae, 0xc6, 0xe8, 0xb8, 0x67, 0x04, 0x7a, 0x11, 0xc6, 0xd4,
-	0xb4, 0xf9, 0x51, 0xe2, 0x82, 0x1d, 0xe7, 0x7b, 0xa0, 0xd6, 0xc4, 0x70, 0x40, 0x35, 0xff, 0xdb,
-	0x80, 0x19, 0xb1, 0xaa, 0x6a, 0x77, 0x8b, 0xd5, 0x5c, 0xab, 0xc3, 0x0d, 0xf0, 0x93, 0xb8, 0xa4,
-	0x6b, 0x30, 0x59, 0xf7, 0x05, 0xbf, 0x6e, 0xb5, 0x2d, 0x4f, 0xe8, 0x48, 0xae, 0xfc, 0x94, 0xc2,
-	0x98, 0x5c, 0x8d, 0x50, 0x71, 0xac, 0xb7, 0xdc, 0xbe, 0x56, 0x97, 0x79, 0xd4, 0xdd, 0x70, 0x9d,
-	0xb6, 0xc3, 0xd7, 0xb9, 0x49, 0xd8, 0x0e, 0xfa, 0x55, 0x18, 0x6b, 0xab, 0x4b, 0x4f, 0x59, 0xcd,
-	0x5f, 0x1c, 0xcc, 0x6a, 0xde, 0xd9, 0xfa, 0x0e, 0xad, 0x79, 0xfc, 0xc2, 0x0c, 0xb5, 0x2d, 0x6c,
-	0xc3, 0x01, 0x2a, 0x7a, 0x0f, 0x46, 0x58, 0x87, 0xd6, 0x84, 0x88, 0x8a, 0xcb, 0x6f, 0x0c, 0xa6,
-	0xd4, 0x91, 0x49, 0x56, 0x3b, 0xb4, 0x16, 0xca, 0x96, 0xff, 0x87, 0x05, 0xa4, 0xf9, 0x9f, 0x06,
-	0xcc, 0x25, 0xad, 0x6a, 0xdd, 0x62, 0x1e, 0xfa, 0xa0, 0x67, 0x65, 0xa5, 0xc1, 0x56, 0xc6, 0x47,
-	0x8b, 0x75, 0x05, 0xda, 0xeb, 0xb7, 0x68, 0xab, 0x7a, 0x00, 0x39, 0xcb, 0xa3, 0x6d, 0xdf, 0xd5,
-	0xb8, 0x32, 0xd8, 0xb2, 0x92, 0x26, 0x1b, 0x5e, 0xa1, 0x6b, 0x1c, 0x10, 0x4b, 0x5c, 0xf3, 0x7d,
-	0x18, 0xaf, 0x74, 0x5d, 0x97, 0xda, 0x9e, 0xbc, 0xe0, 0xbe, 0x09, 0x39, 0x66, 0xd9, 0xca, 0xce,
-	0xa7, 0xbb, 0xdb, 0x0a, 0x1c, 0xbc, 0xca, 0x07, 0x63, 0x89, 0x61, 0xfe, 0x45, 0x16, 0xce, 0xfa,
-	0x27, 0x86, 0xd6, 0x57, 0x5c, 0xcf, 0xda, 0x26, 0x35, 0x8f, 0xa1, 0x3a, 0x8c, 0xd7, 0xc3, 0x66,
-	0x4f, 0x19, 0xe2, 0x34, 0xbc, 0x02, 0x63, 0xaf, 0xc1, 0x7b, 0x38, 0x82, 0x8a, 0xde, 0x85, 0x6c,
-	0xc3, 0xf2, 0x94, 0x67, 0x78, 0x79, 0x30, 0xc9, 0xdd, 0xb4, 0xe2, 0x96, 0xa7, 0x5c, 0x54, 0xac,
-	0xb2, 0x37, 0x2d, 0x0f, 0x73, 0x44, 0xb4, 0x05, 0x79, 0xab, 0x4d, 0x1a, 0x34, 0xe5, 0xae, 0xac,
-	0xf1, 0x31, 0x71, 0xf4, 0xc0, 0xd5, 0x14, 0x54, 0x86, 0x15, 0x32, 0xe7, 0x51, 0xe3, 0x16, 0x43,
-	0xda, 0xec, 0xc1, 0x77, 0x3e, 0xc1, 0x76, 0x86, 0x3c, 0x04, 0x95, 0x61, 0x85, 0x6c, 0x7e, 0x99,
-	0x81, 0xe9, 0x50, 0x7e, 0x15, 0xa7, 0xdd, 0xb6, 0x3c, 0x34, 0x0f, 0x19, 0xab, 0xae, 0x0c, 0x12,
-	0xa8, 0x81, 0x99, 0xb5, 0x55, 0x9c, 0xb1, 0xea, 0xe8, 0x05, 0xc8, 0x6f, 0xb9, 0xc4, 0xae, 0x35,
-	0x95, 0x21, 0x0a, 0x80, 0xcb, 0xa2, 0x15, 0x2b, 0x2a, 0x7a, 0x16, 0xb2, 0x1e, 0x69, 0x28, 0xfb,
-	0x13, 0xc8, 0x6f, 0x93, 0x34, 0x30, 0x6f, 0xe7, 0x86, 0x8f, 0x75, 0x85, 0x0e, 0x8b, 0x9d, 0xd7,
-	0x0c, 0x5f, 0x55, 0x36, 0x63, 0x9f, 0xce, 0x39, 0x92, 0xae, 0xd7, 0x74, 0xdc, 0xb9, 0x5c, 0x94,
-	0xe3, 0x8a, 0x68, 0xc5, 0x8a, 0xca, 0x5d, 0x94, 0x9a, 0x98, 0xbf, 0x47, 0xdd, 0xb9, 0x7c, 0xd4,
-	0x45, 0xa9, 0xf8, 0x04, 0x1c, 0xf6, 0x41, 0xf7, 0xa1, 0x58, 0x73, 0x29, 0xf1, 0x1c, 0x77, 0x95,
-	0x78, 0x74, 0x6e, 0x34, 0xf5, 0x09, 0x9c, 0xe2, 0x5e, 0x7a, 0x25, 0x84, 0xc0, 0x3a, 0x9e, 0xf9,
-	0xf7, 0x59, 0x98, 0x0b, 0x45, 0x2b, 0xf6, 0x36, 0xf4, 0x4c, 0x95, 0x78, 0x8c, 0x3e, 0xe2, 0x79,
-	0x01, 0xf2, 0x75, 0xab, 0x41, 0x99, 0x17, 0x97, 0xf2, 0xaa, 0x68, 0xc5, 0x8a, 0x8a, 0xfe, 0x20,
-	0x16, 0x8d, 0xe4, 0xc4, 0x41, 0xb9, 0x33, 0xd8, 0x41, 0xe9, 0x37, 0xb9, 0x21, 0x42, 0x12, 0xb4,
-	0x0c, 0xd0, 0xb0, 0x3c, 0x75, 0x69, 0xa9, 0x5d, 0x0f, 0x8c, 0xf5, 0xcd, 0x80, 0x82, 0xb5, 0x5e,
-	0xe8, 0x5d, 0x28, 0x08, 0x79, 0x0d, 0xa9, 0xff, 0xc2, 0x85, 0xa9, 0xf8, 0x00, 0x38, 0xc4, 0x3a,
-	0x72, 0x90, 0xf3, 0x3e, 0xa0, 0xeb, 0x0f, 0x3b, 0x2e, 0x65, 0xfc, 0xea, 0xbe, 0x4b, 0x5c, 0x8b,
-	0x6c, 0xb5, 0xe8, 0x71, 0xc5, 0xb1, 0x5f, 0x8c, 0xc0, 0xe8, 0x0d, 0x97, 0x5a, 0x8d, 0xa6, 0x77,
-	0x0a, 0x57, 0xe2, 0x73, 0x90, 0x23, 0x2d, 0x8b, 0x30, 0x71, 0xba, 0xb5, 0x29, 0xad, 0xf0, 0x46,
-	0x2c, 0x69, 0xe8, 0x7d, 0xc8, 0x3b, 0xae, 0xd5, 0xb0, 0xec, 0xb9, 0x82, 0x98, 0xc4, 0xc5, 0xc1,
-	0xce, 0x8f, 0x5a, 0xc5, 0x1d, 0x31, 0x34, 0x3c, 0xa2, 0xf2, 0x7f, 0xac, 0x20, 0xd1, 0x3d, 0x18,
-	0x95, 0x2a, 0xe7, 0x9b, 0xb1, 0xa5, 0x81, 0xcd, 0xb0, 0xd4, 0xda, 0xd0, 0x34, 0xc8, 0xff, 0x19,
-	0xf6, 0x01, 0x51, 0x35, 0xb0, 0xc2, 0x23, 0x02, 0xfa, 0xe5, 0x14, 0x56, 0xb8, 0xaf, 0xd9, 0xad,
-	0x06, 0x66, 0x37, 0x97, 0x06, 0x54, 0x18, 0xd6, 0x7e, 0x76, 0x96, 0x8b, 0x58, 0xb9, 0xfb, 0xf9,
-	0x21, 0x44, 0xac, 0x62, 0x8d, 0xc9, 0x68, 0x8c, 0xe0, 0x47, 0x03, 0xe6, 0x77, 0xb3, 0x30, 0xa3,
-	0x7a, 0x56, 0x9c, 0x56, 0x8b, 0xd6, 0x84, 0x6f, 0x29, 0xad, 0x78, 0x36, 0xd1, 0x8a, 0x5b, 0xbe,
-	0x4f, 0x21, 0x6f, 0xc6, 0x72, 0xaa, 0xd9, 0x84, 0x3c, 0x4a, 0xc2, 0x8f, 0x90, 0x36, 0x22, 0xd8,
-	0x25, 0xd5, 0x4b, 0x79, 0x17, 0xe8, 0xf7, 0x0d, 0x38, 0xbb, 0x4b, 0x5d, 0x6b, 0xdb, 0xaa, 0x09,
-	0x7d, 0xbc, 0x65, 0x31, 0xcf, 0x71, 0xf7, 0xd4, 0xbd, 0xf9, 0xfa, 0x60, 0x9c, 0xef, 0x6a, 0x00,
-	0x6b, 0xf6, 0xb6, 0x53, 0x7e, 0x46, 0x71, 0x3b, 0x7b, 0xb7, 0x17, 0x1a, 0x27, 0xf1, 0x9b, 0xef,
-	0x00, 0x84, 0xb3, 0x4d, 0x30, 0x07, 0xeb, 0xba, 0xf2, 0x0e, 0x3c, 0x31, 0x7f, 0xb1, 0xbe, 0xed,
-	0xd4, 0xcd, 0xc8, 0x67, 0x06, 0x14, 0x15, 0xfd, 0x14, 0xdc, 0x44, 0x1c, 0x75, 0x13, 0x5f, 0x4d,
-	0x35, 0xff, 0x3e, 0x9e, 0xa1, 0x0b, 0x13, 0x11, 0x25, 0x47, 0x97, 0x54, 0xba, 0x44, 0xda, 0xc0,
-	0x9f, 0xd7, 0xd3, 0x25, 0x8f, 0xf6, 0x17, 0x67, 0x22, 0x9d, 0xc3, 0x1c, 0xca, 0xe1, 0xb1, 0xcb,
-	0x95, 0xb1, 0xef, 0xfd, 0xf5, 0xe2, 0x99, 0x8f, 0x7f, 0x7c, 0xfe, 0x8c, 0xf9, 0x69, 0x16, 0xa6,
-	0xe3, 0x52, 0x1d, 0xc0, 0xf6, 0x86, 0x36, 0x6c, 0xec, 0x44, 0x6d, 0x58, 0xe6, 0xe4, 0x6c, 0x58,
-	0xf6, 0x24, 0x6c, 0xd8, 0xc8, 0xb1, 0xd9, 0x30, 0xf3, 0xdf, 0x0c, 0x98, 0x0c, 0x76, 0xe6, 0xc3,
-	0x2e, 0xf7, 0x3f, 0x42, 0xa9, 0x1b, 0xc7, 0x2f, 0xf5, 0x07, 0x30, 0xca, 0x9c, 0xae, 0x5b, 0x13,
-	0x4e, 0x36, 0x47, 0x7f, 0x2d, 0x9d, 0xd1, 0x94, 0x63, 0x35, 0xcf, 0x52, 0x36, 0x60, 0x1f, 0xd5,
-	0xfc, 0x2c, 0x13, 0x2c, 0x48, 0xd1, 0xa4, 0xe3, 0xe5, 0x72, 0xb7, 0x94, 0x2f, 0x68, 0x4c, 0x77,
-	0xbc, 0x78, 0x2b, 0x56, 0x54, 0x64, 0x0a, 0x7b, 0xee, 0xfb, 0xff, 0x85, 0x32, 0x28, 0xb3, 0x2c,
-	0x36, 0x41, 0x52, 0x50, 0x07, 0xa6, 0x5d, 0xfa, 0x61, 0xd7, 0x72, 0x69, 0xbd, 0xea, 0x90, 0x1d,
-	0xee, 0xb4, 0xa8, 0x24, 0xd7, 0x80, 0x7a, 0xbf, 0xda, 0x75, 0x85, 0x09, 0x2b, 0xcf, 0xf2, 0xd8,
-	0x1d, 0xc7, 0xb0, 0x70, 0x0f, 0x3a, 0x72, 0x60, 0x96, 0xec, 0x12, 0xab, 0x45, 0xb6, 0xac, 0x96,
-	0xe5, 0xed, 0x55, 0x3d, 0x97, 0x78, 0xb4, 0xb1, 0xa7, 0x5c, 0xec, 0xab, 0x6a, 0x2d, 0xb3, 0x2b,
-	0x09, 0x7d, 0x1e, 0xed, 0x2f, 0x3e, 0xa3, 0x64, 0x91, 0x44, 0xc6, 0x89, 0xc0, 0xe6, 0x7f, 0xe5,
-	0x02, 0x0b, 0xa1, 0xf2, 0x5a, 0xbf, 0x0e, 0xc5, 0x9a, 0x0c, 0x26, 0x5b, 0x7b, 0x6b, 0xb6, 0x3a,
-	0xd3, 0xab, 0x43, 0xdc, 0x76, 0xa5, 0x4a, 0x08, 0x13, 0xf3, 0x42, 0x35, 0x0a, 0xd6, 0xb9, 0xa1,
-	0x8f, 0x00, 0xa4, 0xe9, 0xa7, 0xf5, 0x35, 0x5b, 0xdd, 0x6d, 0x95, 0x61, 0x78, 0xdf, 0x0d, 0x50,
-	0x24, 0xeb, 0xc0, 0xc9, 0x0a, 0x09, 0x58, 0x63, 0xc5, 0x57, 0xed, 0x67, 0x71, 0x6f, 0x38, 0xae,
-	0x32, 0x12, 0x43, 0xad, 0x7a, 0x25, 0x84, 0x89, 0xfb, 0xde, 0x21, 0x05, 0xeb, 0xdc, 0xe6, 0x5d,
-	0x98, 0x8e, 0xcb, 0x2a, 0xe1, 0x7e, 0xbb, 0x15, 0xbd, 0xdf, 0x96, 0x07, 0xb4, 0x08, 0x5a, 0x62,
-	0x40, 0x7f, 0x47, 0x70, 0x61, 0x2a, 0x26, 0xa3, 0x04, 0x96, 0x6b, 0x51, 0x96, 0x17, 0xd3, 0xdc,
-	0xf5, 0x2a, 0xdb, 0xae, 0xf3, 0x64, 0x30, 0x1d, 0x97, 0xce, 0xb1, 0x31, 0x8d, 0xa4, 0xf8, 0xf5,
-	0x4b, 0xfc, 0x2f, 0x33, 0x50, 0x08, 0xcc, 0x78, 0x9a, 0x7c, 0x9d, 0x74, 0xbf, 0x32, 0x87, 0x04,
-	0xd1, 0xd9, 0x41, 0x82, 0xe8, 0x91, 0xfe, 0x41, 0xb4, 0x9f, 0xd3, 0xcf, 0x3f, 0x3e, 0xa7, 0xaf,
-	0x05, 0xd1, 0xa3, 0x83, 0x07, 0xd1, 0x63, 0x87, 0x07, 0xd1, 0xe6, 0xdf, 0x18, 0x80, 0x7a, 0x33,
-	0x26, 0x69, 0x04, 0x45, 0xe2, 0x97, 0xeb, 0xeb, 0x69, 0xc3, 0xd7, 0xc3, 0xee, 0x58, 0xf3, 0xb3,
-	0x1c, 0x4c, 0xdd, 0xb4, 0x86, 0x4e, 0xbd, 0x7a, 0xf0, 0xb4, 0x44, 0xaa, 0x52, 0xe5, 0xf8, 0x06,
-	0x96, 0x55, 0xee, 0xef, 0x15, 0x35, 0xf4, 0xe9, 0x4a, 0x72, 0xb7, 0x47, 0xfd, 0x49, 0xb8, 0x1f,
-	0xf4, 0xc0, 0x87, 0xe4, 0x2a, 0x4c, 0x30, 0xcf, 0xb5, 0x6a, 0x9e, 0x4c, 0xee, 0xb2, 0xb9, 0xa2,
-	0xb8, 0xb9, 0xce, 0xa9, 0xee, 0x13, 0x55, 0x9d, 0x88, 0xa3, 0x7d, 0x13, 0x73, 0xc6, 0x23, 0xa9,
-	0x73, 0xc6, 0x4b, 0x50, 0x20, 0xad, 0x96, 0xf3, 0xd1, 0x26, 0x69, 0x30, 0x95, 0xa5, 0x09, 0x4e,
-	0xcd, 0x8a, 0x4f, 0xc0, 0x61, 0x1f, 0x54, 0x02, 0xb0, 0x1a, 0xb6, 0xe3, 0x52, 0x31, 0x22, 0x2f,
-	0xae, 0x50, 0xf1, 0x2e, 0xb6, 0x16, 0xb4, 0x62, 0xad, 0x07, 0xaa, 0xc2, 0x39, 0xcb, 0x66, 0xb4,
-	0xd6, 0x75, 0x69, 0x75, 0xc7, 0xea, 0x6c, 0xae, 0x57, 0x85, 0x95, 0xd8, 0x13, 0xa7, 0x79, 0xac,
-	0xfc, 0xac, 0x62, 0x76, 0x6e, 0x2d, 0xa9, 0x13, 0x4e, 0x1e, 0x8b, 0x5e, 0x83, 0x71, 0xcb, 0xae,
-	0xb5, 0xba, 0x75, 0xba, 0x41, 0xbc, 0x26, 0x9b, 0x1b, 0x13, 0xd3, 0x98, 0x3e, 0xd8, 0x5f, 0x1c,
-	0x5f, 0xd3, 0xda, 0x71, 0xa4, 0x17, 0x1f, 0x45, 0x1f, 0x6a, 0xa3, 0x0a, 0xe1, 0xa8, 0xeb, 0x0f,
-	0xf5, 0x51, 0x7a, 0xaf, 0x84, 0xac, 0x3a, 0xa4, 0xca, 0xaa, 0xff, 0x20, 0x03, 0x79, 0xf9, 0xa8,
-	0x85, 0x2e, 0xc5, 0x5e, 0x8e, 0x9e, 0xed, 0x79, 0x39, 0x2a, 0x26, 0x3d, 0x00, 0x9a, 0x90, 0xb7,
-	0x18, 0xeb, 0x46, 0x3d, 0x96, 0x35, 0xd1, 0x82, 0x15, 0x45, 0x64, 0x1c, 0x1d, 0x7b, 0xdb, 0x6a,
-	0xa8, 0x74, 0xcc, 0x35, 0xcd, 0x4f, 0x09, 0x4b, 0x13, 0x1e, 0x04, 0xb5, 0x0b, 0xa1, 0xcb, 0x12,
-	0xe9, 0xc0, 0x7d, 0x97, 0xdb, 0xd5, 0x3b, 0x6f, 0x4b, 0x1e, 0x15, 0x81, 0x88, 0x15, 0x32, 0xe7,
-	0xe1, 0x74, 0xbd, 0x4e, 0xd7, 0x13, 0x07, 0xe5, 0x98, 0x78, 0xdc, 0x11, 0x88, 0x58, 0x21, 0x9b,
-	0x9f, 0x1a, 0x30, 0x25, 0x65, 0x50, 0x69, 0xd2, 0xda, 0x4e, 0xd5, 0xa3, 0x1d, 0x1e, 0x42, 0x74,
-	0x19, 0x65, 0xf1, 0x10, 0xe2, 0x1d, 0x46, 0x19, 0x16, 0x14, 0x6d, 0xf5, 0x99, 0x93, 0x5a, 0xbd,
-	0x79, 0x19, 0xb4, 0xcd, 0x11, 0xaf, 0xb2, 0xf2, 0x71, 0x52, 0x5e, 0x61, 0xd9, 0xd0, 0x08, 0xc9,
-	0x5e, 0x7b, 0xd8, 0xa7, 0x9b, 0x07, 0x19, 0xc8, 0x09, 0x2f, 0x3f, 0x8d, 0xe5, 0x8a, 0xa6, 0xe5,
-	0x32, 0x03, 0xa5, 0xe5, 0x0e, 0xc9, 0xdc, 0x86, 0xa9, 0xc9, 0x91, 0xc7, 0xa6, 0x26, 0x59, 0x52,
-	0x66, 0xf2, 0xad, 0x14, 0xc1, 0xcd, 0x30, 0x95, 0x11, 0x47, 0xcd, 0xfc, 0xfd, 0xd4, 0x80, 0xd9,
-	0xa4, 0x1c, 0x7d, 0x1a, 0x99, 0xbf, 0x02, 0x63, 0x9d, 0x16, 0xf1, 0xb6, 0x1d, 0xb7, 0x1d, 0x7f,
-	0x9b, 0xdd, 0x50, 0xed, 0x38, 0xe8, 0x81, 0x5c, 0x00, 0xd7, 0x0f, 0x73, 0xfd, 0x10, 0xf0, 0xda,
-	0xd1, 0xf2, 0xb7, 0xe1, 0x0e, 0x07, 0x4d, 0x0c, 0x6b, 0x5c, 0xcc, 0x3f, 0xce, 0xc1, 0x8c, 0x18,
-	0x32, 0xec, 0x85, 0x38, 0xcc, 0xb1, 0xea, 0xc0, 0x53, 0x22, 0x38, 0xed, 0xbd, 0x43, 0xe5, 0x49,
-	0xbb, 0xac, 0xc6, 0x3f, 0xb5, 0x96, 0xd8, 0xeb, 0x51, 0x5f, 0x0a, 0xee, 0x83, 0xdb, 0x7b, 0x31,
-	0xc2, 0xd7, 0xef, 0x62, 0xd4, 0x0f, 0xdb, 0xe8, 0xa1, 0x87, 0xad, 0xef, 0x35, 0x3a, 0x76, 0x84,
-	0x6b, 0xb4, 0xf7, 0x6a, 0x2b, 0xa4, 0xba, 0xda, 0xfe, 0x2a, 0x03, 0xa3, 0x1b, 0xae, 0x23, 0xde,
-	0x7a, 0x4e, 0x3e, 0x21, 0xfe, 0xce, 0x90, 0x6f, 0xc4, 0x1c, 0x4a, 0xda, 0x72, 0xf1, 0x46, 0x3c,
-	0x16, 0x7d, 0x1f, 0xd6, 0xf2, 0xbb, 0xd9, 0x34, 0x61, 0x87, 0x02, 0x3e, 0x24, 0xbf, 0xfb, 0x43,
-	0x03, 0x26, 0x22, 0x53, 0x78, 0x82, 0xdf, 0xd2, 0x63, 0x72, 0x4a, 0x7a, 0x4b, 0xff, 0x17, 0x03,
-	0x66, 0x22, 0x3d, 0x4f, 0x21, 0x3b, 0xfa, 0xed, 0x68, 0x76, 0xf4, 0xe2, 0x10, 0xeb, 0xe9, 0x93,
-	0x23, 0xfd, 0xb3, 0xf8, 0x6a, 0xf8, 0x4a, 0xd1, 0x6f, 0xc2, 0x4c, 0xc7, 0x7f, 0x7a, 0xdf, 0x70,
-	0x5a, 0x56, 0xcd, 0xa2, 0x7e, 0xb2, 0xfd, 0x52, 0xca, 0xba, 0x04, 0x31, 0x7c, 0xaf, 0xfc, 0x0d,
-	0xc5, 0x7d, 0x66, 0x23, 0x8e, 0x8b, 0x7b, 0x59, 0x89, 0xdc, 0xb3, 0x9a, 0xd5, 0x13, 0x9b, 0x7b,
-	0x56, 0xf3, 0xeb, 0x23, 0xd7, 0x1f, 0x19, 0x30, 0xae, 0xa9, 0x07, 0x43, 0x4d, 0x80, 0x8f, 0x88,
-	0x4b, 0x9b, 0x4e, 0xe0, 0xc6, 0x0d, 0x9c, 0x11, 0x7c, 0xd7, 0x1f, 0x27, 0x90, 0xc2, 0x93, 0x1f,
-	0xb4, 0x33, 0xac, 0x61, 0xa3, 0x6f, 0x6b, 0xc9, 0x3d, 0xa9, 0x5b, 0x03, 0x71, 0x11, 0xb9, 0x03,
-	0xc9, 0x41, 0xd7, 0x64, 0x2d, 0x25, 0x68, 0x7e, 0x3f, 0x13, 0x68, 0xb2, 0xca, 0x97, 0xd5, 0x00,
-	0x6a, 0x8e, 0x5d, 0xb7, 0xbc, 0xa0, 0x38, 0xab, 0xb8, 0xbc, 0x34, 0xd8, 0xd6, 0x54, 0xfc, 0x71,
-	0xe1, 0x82, 0x82, 0x26, 0x86, 0x35, 0x58, 0x74, 0xd1, 0xaf, 0xa4, 0x8c, 0x46, 0x0c, 0xb2, 0x92,
-	0xf2, 0xd1, 0xfe, 0xa2, 0x2f, 0x68, 0xbd, 0xb2, 0x32, 0x45, 0xc5, 0x20, 0xaa, 0x42, 0x8e, 0x9b,
-	0x2a, 0xbf, 0x9c, 0x6e, 0x39, 0xb5, 0xf1, 0x63, 0xaa, 0x72, 0x84, 0xff, 0x89, 0x25, 0x96, 0xf9,
-	0xb7, 0x19, 0x28, 0x04, 0x67, 0xfd, 0xd4, 0x6f, 0x86, 0x8b, 0x29, 0xb5, 0xb4, 0x9f, 0xb5, 0x43,
-	0xf7, 0x63, 0x37, 0x43, 0x5a, 0xf5, 0x3f, 0xe4, 0x6e, 0xf8, 0x47, 0x79, 0x37, 0xc8, 0xbe, 0xa7,
-	0xa0, 0xea, 0x9b, 0x51, 0x55, 0x5f, 0x4a, 0xb9, 0x9a, 0x3e, 0xca, 0xfe, 0x71, 0x06, 0xa6, 0x62,
-	0x06, 0x0f, 0x3d, 0x27, 0x0e, 0x55, 0xc3, 0x3f, 0xb4, 0xc1, 0x40, 0x95, 0xa2, 0x13, 0x34, 0xb4,
-	0xcb, 0x7d, 0xbc, 0xc0, 0xfb, 0x73, 0x5c, 0x25, 0xe4, 0x5f, 0x1a, 0xca, 0xc6, 0xfa, 0x20, 0xe5,
-	0x19, 0xe9, 0x1e, 0x6a, 0xb8, 0x38, 0xca, 0x06, 0x6d, 0xc0, 0x2c, 0xe9, 0x7a, 0x4e, 0x00, 0x70,
-	0xdd, 0x26, 0x5b, 0x2d, 0x2a, 0xf3, 0x7d, 0x63, 0xe5, 0x9f, 0x0b, 0x32, 0xed, 0x09, 0x7d, 0x70,
-	0xe2, 0x48, 0xf3, 0xfb, 0x06, 0x3c, 0xdd, 0x67, 0x3e, 0x03, 0x3c, 0x7f, 0xb5, 0x60, 0x42, 0x14,
-	0xa8, 0x07, 0x72, 0xf0, 0x4f, 0xf1, 0x60, 0x3b, 0xaf, 0x0f, 0x95, 0xab, 0x8f, 0x34, 0xe1, 0x28,
-	0xb8, 0xf9, 0xc3, 0x0c, 0xa0, 0x60, 0xae, 0x69, 0x5e, 0xe9, 0xee, 0xc3, 0xe8, 0xb6, 0x4c, 0x77,
-	0x1f, 0xed, 0x99, 0xb5, 0x5c, 0xd4, 0x5f, 0x9a, 0x7d, 0x4c, 0xf4, 0xde, 0xf1, 0xe8, 0x1a, 0xf4,
-	0xea, 0x19, 0xba, 0x07, 0xb0, 0x6d, 0xd9, 0x16, 0x6b, 0x0e, 0x59, 0xad, 0x22, 0x9c, 0xf8, 0x1b,
-	0x01, 0x02, 0xd6, 0xd0, 0xcc, 0x3f, 0xcf, 0x68, 0x3a, 0x2c, 0xdc, 0x87, 0x81, 0xce, 0xfe, 0x4b,
-	0x51, 0x61, 0x16, 0x7a, 0x9f, 0xe0, 0x03, 0xc1, 0xdc, 0x83, 0x91, 0x5d, 0xe2, 0xfa, 0xaf, 0x81,
-	0x03, 0x16, 0xc2, 0xf5, 0xd6, 0xc0, 0x84, 0x7b, 0x7a, 0x97, 0xb8, 0x0c, 0x0b, 0x4c, 0xee, 0x5a,
-	0x31, 0x8f, 0x76, 0xfc, 0xcb, 0x2b, 0xb5, 0xe1, 0xf4, 0x68, 0x47, 0x5f, 0x20, 0xed, 0x88, 0x1b,
-	0x80, 0x76, 0x98, 0xf9, 0xdd, 0x51, 0xcd, 0x2a, 0xa8, 0xfb, 0xf2, 0x36, 0xa0, 0x16, 0x61, 0xde,
-	0x2d, 0x62, 0xd7, 0xb9, 0x2e, 0xd1, 0x6d, 0x97, 0xb2, 0xa6, 0x8a, 0xcc, 0xe6, 0x15, 0x0a, 0x5a,
-	0xef, 0xe9, 0x81, 0x13, 0x46, 0xa1, 0x4b, 0xd1, 0x6b, 0x71, 0x31, 0x7e, 0x2d, 0x4e, 0x86, 0xfa,
-	0x38, 0xe4, 0xc5, 0xa8, 0x9d, 0xf7, 0xdc, 0x09, 0x9c, 0xf7, 0xdf, 0x80, 0x99, 0xed, 0x78, 0x4d,
-	0x86, 0xaa, 0x63, 0x7b, 0x63, 0xc8, 0x92, 0x8e, 0xf2, 0xb9, 0x83, 0xf0, 0x21, 0x3f, 0x6c, 0xc6,
-	0xbd, 0x8c, 0x90, 0xe3, 0x17, 0xf0, 0x8b, 0x24, 0x9b, 0xcc, 0x9f, 0x0e, 0xac, 0x73, 0xb1, 0xf4,
-	0x5c, 0xbc, 0x74, 0x5f, 0x42, 0xe2, 0x08, 0x83, 0x98, 0x0e, 0xe6, 0x8f, 0x53, 0x07, 0xd1, 0xa5,
-	0xe0, 0xdd, 0x92, 0x4f, 0x47, 0x84, 0xb0, 0xd9, 0x9e, 0x17, 0x47, 0x4e, 0xc2, 0x7a, 0x3f, 0xf4,
-	0x89, 0x01, 0xe7, 0xf8, 0x61, 0xbd, 0xfe, 0x90, 0xd6, 0xba, 0x5c, 0x2a, 0xfe, 0x77, 0x3d, 0x73,
-	0x45, 0x21, 0x8d, 0xab, 0x83, 0xba, 0x8e, 0x09, 0x10, 0x61, 0x3c, 0x9e, 0x48, 0xc6, 0xc9, 0x8c,
-	0xd1, 0x03, 0xe9, 0x8c, 0x51, 0x91, 0xee, 0x38, 0x7a, 0x16, 0x33, 0x70, 0xcc, 0xa4, 0xdd, 0xf1,
-	0xa8, 0xf9, 0x93, 0xac, 0x6e, 0xae, 0x06, 0xcb, 0xad, 0xde, 0x83, 0x11, 0x8f, 0xb0, 0x1d, 0xa5,
-	0x05, 0x6f, 0x0d, 0x51, 0x9a, 0x1d, 0xea, 0x82, 0x88, 0xbd, 0x45, 0x93, 0xc0, 0x44, 0xf3, 0x90,
-	0x21, 0x2c, 0xfe, 0xd2, 0xb6, 0xc2, 0x70, 0x86, 0x30, 0xf1, 0x0a, 0xb7, 0xad, 0x32, 0x23, 0xe1,
-	0x2b, 0xdc, 0x36, 0xce, 0x58, 0xdb, 0xe8, 0x3d, 0xc8, 0xb9, 0xd4, 0x73, 0xf7, 0x94, 0x35, 0xbf,
-	0x3c, 0x84, 0xe1, 0xc2, 0x7c, 0xbc, 0x14, 0x91, 0xf8, 0x13, 0x4b, 0xc4, 0xc0, 0xde, 0xe6, 0x4f,
-	0xc0, 0xde, 0x86, 0x69, 0xea, 0xec, 0x89, 0xa5, 0xa9, 0x7f, 0x60, 0x68, 0x17, 0x7c, 0xb0, 0x50,
-	0xf4, 0x0e, 0x8c, 0x7a, 0x56, 0x9b, 0x3a, 0x5d, 0x2f, 0x9d, 0x67, 0x19, 0x14, 0x32, 0x08, 0x33,
-	0xb6, 0x29, 0x21, 0xb0, 0x8f, 0x85, 0xae, 0xc1, 0x24, 0x75, 0x5d, 0xc7, 0xdd, 0x6c, 0x72, 0xb3,
-	0xec, 0xb4, 0xa4, 0x1b, 0x35, 0x11, 0x66, 0x90, 0xae, 0x47, 0xa8, 0x38, 0xd6, 0xdb, 0xcf, 0x8f,
-	0x7c, 0x5d, 0xbe, 0x35, 0x50, 0xf9, 0x91, 0x53, 0xfd, 0xc8, 0x60, 0xe8, 0xfc, 0xc8, 0xa1, 0x5f,
-	0x17, 0x7c, 0x00, 0x4f, 0x25, 0xeb, 0xf1, 0xb1, 0x7c, 0x9d, 0xf7, 0x4f, 0x71, 0x59, 0x09, 0xf7,
-	0xc9, 0x57, 0x3f, 0xe3, 0x24, 0xdd, 0x9d, 0xcc, 0x71, 0xbb, 0x3b, 0xae, 0xbe, 0x14, 0xf5, 0x2d,
-	0x23, 0xba, 0xaf, 0xce, 0x99, 0x91, 0xe6, 0xeb, 0xb8, 0x1e, 0x98, 0xbe, 0x67, 0xed, 0x5f, 0x0d,
-	0x38, 0x97, 0xd8, 0x3b, 0x90, 0x61, 0xe6, 0x24, 0x65, 0x68, 0x1c, 0xb7, 0x0c, 0xbf, 0x97, 0x81,
-	0x69, 0x4c, 0x3b, 0x4e, 0xe4, 0x65, 0x63, 0xc3, 0xff, 0x0a, 0x24, 0x45, 0x4c, 0x10, 0x2b, 0x17,
-	0x28, 0x8f, 0x46, 0x3e, 0xff, 0xe0, 0xea, 0xd2, 0xf6, 0x1d, 0xc0, 0x81, 0xd5, 0xbf, 0xe7, 0xcd,
-	0x45, 0xde, 0x1c, 0xf2, 0xf5, 0x46, 0x02, 0x72, 0x64, 0x51, 0x6e, 0xa7, 0x8c, 0xfb, 0x1b, 0x29,
-	0x0a, 0xf7, 0x7a, 0x91, 0x45, 0x33, 0x96, 0x80, 0xe6, 0xa7, 0x19, 0x90, 0xf1, 0xc3, 0x29, 0x58,
-	0xc7, 0x5f, 0x89, 0x58, 0xc7, 0xa5, 0x34, 0xf9, 0xb3, 0x7e, 0x79, 0x94, 0x78, 0x6c, 0x77, 0x21,
-	0x65, 0x52, 0xee, 0x31, 0x39, 0x94, 0x7f, 0x30, 0xa0, 0x20, 0xfa, 0x9d, 0x82, 0xa1, 0xdd, 0x88,
-	0x1a, 0xda, 0x97, 0x53, 0xac, 0xa2, 0x8f, 0x81, 0xfd, 0x9f, 0xac, 0x9a, 0x7d, 0x10, 0x39, 0x36,
-	0x89, 0x5b, 0x57, 0x21, 0x51, 0xa8, 0x25, 0xbc, 0x11, 0x4b, 0x5a, 0xa0, 0xdb, 0xa3, 0x27, 0xa0,
-	0xdb, 0xbf, 0x26, 0xab, 0x1e, 0x29, 0xf3, 0x68, 0xfd, 0x46, 0x10, 0xfb, 0x64, 0x53, 0x97, 0x6f,
-	0xaa, 0x12, 0xd3, 0xf0, 0xb9, 0x0d, 0xc7, 0x50, 0x71, 0x0f, 0x1f, 0x1e, 0x0f, 0x75, 0xe2, 0xc6,
-	0x4c, 0xc5, 0x09, 0x6f, 0x0c, 0x69, 0x39, 0x65, 0x3c, 0xd4, 0xd3, 0x8c, 0x7b, 0x19, 0xa1, 0x26,
-	0x8c, 0xeb, 0x85, 0xe7, 0xea, 0x9c, 0x2e, 0xa7, 0xaf, 0x70, 0x97, 0xd5, 0x24, 0x7a, 0x0b, 0x8e,
-	0x20, 0x9b, 0x7f, 0x62, 0x00, 0x84, 0xd9, 0x66, 0xbe, 0xe7, 0x35, 0xa7, 0x6b, 0xcb, 0x34, 0x40,
-	0x36, 0xdc, 0xf3, 0x0a, 0x6f, 0xc4, 0x92, 0xc6, 0xf5, 0x47, 0x06, 0x53, 0xea, 0x50, 0x5f, 0x48,
-	0x13, 0xa7, 0xc5, 0xb2, 0xda, 0xb2, 0x11, 0x2b, 0x40, 0x73, 0x3f, 0x0f, 0x45, 0x4d, 0xcf, 0x62,
-	0x39, 0xed, 0x89, 0x93, 0xc9, 0x69, 0x27, 0x27, 0x02, 0x8a, 0x43, 0x25, 0x02, 0x2e, 0x44, 0x13,
-	0x01, 0xcf, 0xc4, 0x13, 0x01, 0x52, 0xd8, 0x91, 0x24, 0x00, 0x83, 0x49, 0x15, 0x11, 0xfb, 0x1f,
-	0x34, 0xc8, 0xdc, 0xca, 0xd0, 0x71, 0x37, 0xe2, 0x8e, 0xee, 0x8d, 0x08, 0x24, 0x8e, 0xb1, 0xe0,
-	0x8e, 0xb2, 0x6a, 0xa9, 0x76, 0xdb, 0x6d, 0xe2, 0xee, 0xcd, 0x8d, 0x8b, 0x09, 0x07, 0x8e, 0xf2,
-	0x8d, 0x08, 0x15, 0xc7, 0x7a, 0xa3, 0x8d, 0xe0, 0x0c, 0xc8, 0x22, 0xf9, 0x57, 0xd2, 0x9c, 0x01,
-	0x19, 0x28, 0x44, 0xb7, 0x5e, 0xcf, 0x85, 0x14, 0x0e, 0xc9, 0x85, 0xdc, 0x06, 0xe4, 0x6c, 0x89,
-	0x90, 0xa4, 0x7e, 0x53, 0xfe, 0x72, 0x08, 0x57, 0x92, 0xbc, 0x38, 0xb2, 0xc1, 0x86, 0xdd, 0xe9,
-	0xe9, 0x81, 0x13, 0x46, 0x71, 0x23, 0xa3, 0xa2, 0xf0, 0x40, 0x33, 0x55, 0xde, 0x23, 0x6d, 0x14,
-	0x17, 0x86, 0x95, 0xa2, 0xc8, 0xba, 0x12, 0x43, 0xc5, 0x3d, 0x7c, 0xd0, 0x87, 0x30, 0xc1, 0x8f,
-	0x50, 0xc8, 0x18, 0x8e, 0xc8, 0x58, 0xe5, 0x5b, 0x35, 0x48, 0x1c, 0xe5, 0x60, 0xfe, 0x51, 0x16,
-	0x92, 0x73, 0x00, 0xe1, 0xf7, 0x5d, 0xc6, 0x63, 0xbe, 0xef, 0x7a, 0x17, 0x0a, 0xcc, 0x23, 0xae,
-	0xfc, 0xd0, 0x2e, 0x33, 0xdc, 0x87, 0x76, 0x55, 0x1f, 0x00, 0x87, 0x58, 0xb1, 0x84, 0x4c, 0xf6,
-	0x58, 0x13, 0x32, 0xcb, 0x00, 0x22, 0xcc, 0x13, 0x46, 0x4c, 0xdc, 0x66, 0x13, 0xa1, 0x4d, 0xb8,
-	0x1e, 0x50, 0xb0, 0xd6, 0x0b, 0x5d, 0x0e, 0x7c, 0x04, 0x59, 0x6b, 0x71, 0xbe, 0xa7, 0x34, 0x2e,
-	0x9e, 0xd2, 0x4b, 0xf8, 0x79, 0x8c, 0x43, 0x4a, 0x69, 0xcd, 0xff, 0xcb, 0x40, 0xc4, 0x36, 0xa3,
-	0x3f, 0x34, 0x60, 0x86, 0xc4, 0x7e, 0x83, 0xc4, 0x77, 0x6d, 0x7f, 0x39, 0xdd, 0x0f, 0xc3, 0xf4,
-	0xfc, 0x84, 0x49, 0xf8, 0xec, 0x1b, 0xef, 0xc2, 0x70, 0x2f, 0x53, 0xf4, 0x7b, 0x06, 0x9c, 0x25,
-	0xbd, 0x3f, 0x32, 0xa3, 0x36, 0xfd, 0xcd, 0xa1, 0x7f, 0xa5, 0xa6, 0xfc, 0xf4, 0xc1, 0xfe, 0x62,
-	0xd2, 0xcf, 0xef, 0xe0, 0x24, 0x76, 0xe8, 0x7d, 0x18, 0x21, 0x6e, 0xc3, 0xcf, 0x08, 0xa7, 0x67,
-	0xeb, 0xff, 0x76, 0x50, 0xe8, 0x60, 0xac, 0xb8, 0x0d, 0x86, 0x05, 0xa8, 0xf9, 0xe3, 0x2c, 0x4c,
-	0xc7, 0xbf, 0x07, 0x53, 0xd5, 0xd6, 0x23, 0x89, 0xd5, 0xd6, 0x5c, 0x47, 0xc4, 0x9b, 0x48, 0xfc,
-	0x1b, 0x48, 0xf1, 0xb4, 0x21, 0x69, 0x81, 0x8e, 0x88, 0xaf, 0x34, 0x72, 0x47, 0xd0, 0x11, 0xf1,
-	0x69, 0x46, 0x88, 0x85, 0x2e, 0x47, 0xef, 0x16, 0x33, 0x7e, 0xb7, 0xcc, 0xe8, 0x6b, 0x19, 0x36,
-	0xcf, 0xdc, 0x86, 0xa2, 0xb6, 0x0f, 0x4a, 0x13, 0xaf, 0xa4, 0x96, 0x7b, 0x78, 0xec, 0xa6, 0x64,
-	0x99, 0x5d, 0x48, 0xd1, 0xf1, 0x43, 0xbd, 0x17, 0xd2, 0x3a, 0x52, 0x22, 0x56, 0x88, 0x4b, 0x43,
-	0x33, 0xff, 0xc3, 0x80, 0x89, 0xc8, 0x27, 0x00, 0x9c, 0x9b, 0xff, 0xa9, 0xc5, 0xf0, 0x3f, 0xb8,
-	0x73, 0x37, 0x40, 0xc0, 0x1a, 0x1a, 0xfa, 0x0e, 0x14, 0x5b, 0x8e, 0xdd, 0xa0, 0xcc, 0xab, 0x3a,
-	0x64, 0x47, 0xe9, 0x49, 0xda, 0xac, 0xd6, 0xdc, 0xc1, 0xfe, 0xe2, 0xec, 0xba, 0x84, 0xa9, 0x38,
-	0xed, 0x4e, 0x8b, 0x7a, 0xf2, 0xa3, 0x1c, 0xac, 0x83, 0x8b, 0x07, 0xed, 0xa0, 0xe2, 0xe0, 0x49,
-	0x7d, 0xd0, 0x0e, 0x4b, 0x25, 0x8e, 0xf9, 0x41, 0x3b, 0x52, 0x83, 0x71, 0xc8, 0x83, 0x76, 0xd0,
-	0xf7, 0x89, 0x7d, 0xd0, 0x0e, 0x66, 0xd8, 0x27, 0x28, 0xfb, 0xdf, 0x8c, 0xb6, 0x8a, 0x68, 0x60,
-	0x96, 0x79, 0x4c, 0x60, 0xf6, 0x01, 0x8c, 0x59, 0xb6, 0x47, 0xdd, 0x5d, 0xd2, 0x52, 0x59, 0xe9,
-	0xb4, 0x67, 0x31, 0x58, 0xea, 0x9a, 0xc2, 0xc1, 0x01, 0x22, 0x6a, 0xc1, 0x39, 0xff, 0x15, 0xc7,
-	0xa5, 0x24, 0x7c, 0x67, 0x56, 0x15, 0x98, 0xaf, 0xfb, 0xcf, 0x0d, 0x37, 0x92, 0x3a, 0x3d, 0xea,
-	0x47, 0xc0, 0xc9, 0xa0, 0x88, 0xc1, 0x04, 0xd3, 0x32, 0x12, 0xfe, 0x8d, 0x38, 0xe0, 0x0b, 0x58,
-	0x3c, 0x89, 0xa3, 0x95, 0x6d, 0xea, 0xa0, 0x38, 0xca, 0xc3, 0xfc, 0xc4, 0x80, 0xc9, 0x68, 0xb5,
-	0xcf, 0xcf, 0x3c, 0x3a, 0xfa, 0x51, 0x16, 0xa6, 0x62, 0x87, 0x3f, 0x16, 0x21, 0x15, 0x4e, 0x33,
-	0x42, 0xca, 0x0f, 0x15, 0x21, 0x25, 0x3b, 0xef, 0x23, 0x43, 0x39, 0xef, 0x57, 0xa5, 0x03, 0xad,
-	0x0e, 0xd3, 0xda, 0xaa, 0xfa, 0xce, 0x28, 0xd8, 0xe0, 0x75, 0x9d, 0x88, 0xa3, 0x7d, 0x85, 0x87,
-	0x53, 0xef, 0xfd, 0x3d, 0x19, 0xe5, 0xfd, 0xbf, 0x99, 0xb6, 0x72, 0x3a, 0x00, 0x90, 0x1e, 0x4e,
-	0x02, 0x01, 0x27, 0xb1, 0x2b, 0xdf, 0xfe, 0xfc, 0xab, 0x85, 0x33, 0x5f, 0x7c, 0xb5, 0x70, 0xe6,
-	0xcb, 0xaf, 0x16, 0xce, 0x7c, 0x7c, 0xb0, 0x60, 0x7c, 0x7e, 0xb0, 0x60, 0x7c, 0x71, 0xb0, 0x60,
-	0x7c, 0x79, 0xb0, 0x60, 0xfc, 0xe4, 0x60, 0xc1, 0xf8, 0xe4, 0xa7, 0x0b, 0x67, 0xee, 0x3d, 0x3f,
-	0xc8, 0xaf, 0x50, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc8, 0x43, 0x98, 0xb9, 0xac, 0x52,
-	0x00, 0x00,
+	0x76, 0x9e, 0x26, 0x45, 0x4a, 0x7c, 0xd4, 0x6f, 0x8d, 0xc6, 0xd6, 0xca, 0xb1, 0x34, 0x69, 0x3b,
+	0x86, 0x1d, 0xdb, 0x54, 0x46, 0xe3, 0xb1, 0xc7, 0x33, 0xde, 0x09, 0x44, 0x6a, 0x7e, 0x34, 0xab,
+	0xf5, 0x28, 0x45, 0x79, 0xbc, 0x1e, 0x7b, 0x30, 0x29, 0x91, 0x25, 0xb2, 0x57, 0x64, 0x37, 0xdd,
+	0xd5, 0x94, 0x47, 0x49, 0x90, 0x38, 0xbf, 0x08, 0x90, 0x20, 0x31, 0x90, 0x0d, 0xbc, 0x87, 0x04,
+	0x09, 0x92, 0xd3, 0x62, 0x81, 0x5c, 0x73, 0xc8, 0xc1, 0x87, 0x5c, 0x9c, 0x64, 0x13, 0x18, 0x9b,
+	0x43, 0x1c, 0x60, 0xa1, 0xac, 0xb5, 0x40, 0xce, 0xb9, 0xe4, 0x32, 0x40, 0x80, 0xa0, 0x7e, 0xba,
+	0xbb, 0xba, 0xd9, 0x1c, 0xb1, 0xa9, 0x9f, 0x1d, 0xec, 0x4d, 0xaa, 0x57, 0xf5, 0xbd, 0xaa, 0x57,
+	0xf5, 0x5e, 0xbd, 0xf7, 0xea, 0x35, 0xe1, 0xb5, 0x86, 0xe5, 0x35, 0xbb, 0x5b, 0xa5, 0x9a, 0xd3,
+	0x5e, 0x22, 0x3b, 0x5d, 0xcb, 0xdb, 0x5b, 0xda, 0x21, 0x6e, 0xc3, 0x59, 0x22, 0x1d, 0x6b, 0x69,
+	0xf7, 0x02, 0x69, 0x75, 0x9a, 0xe4, 0xc2, 0x52, 0x83, 0xda, 0xd4, 0x25, 0x1e, 0xad, 0x97, 0x3a,
+	0xae, 0xe3, 0x39, 0xe8, 0xf9, 0x70, 0x54, 0x49, 0x8e, 0x2a, 0x89, 0x51, 0x25, 0xd2, 0xb1, 0x4a,
+	0xfe, 0xa8, 0xf9, 0x57, 0x35, 0xec, 0x86, 0xd3, 0x70, 0x96, 0xc4, 0xe0, 0xad, 0xee, 0xb6, 0xf8,
+	0x4f, 0xfc, 0x23, 0xfe, 0x92, 0xa0, 0xf3, 0xb7, 0x76, 0x2e, 0xb3, 0x92, 0x25, 0x38, 0xd3, 0x87,
+	0x1e, 0xb5, 0x99, 0xe5, 0xd8, 0xec, 0x55, 0xd2, 0xb1, 0x18, 0x75, 0x77, 0xa9, 0xbb, 0xd4, 0xd9,
+	0x69, 0x70, 0x1a, 0x8b, 0x76, 0x58, 0xda, 0xed, 0x99, 0xde, 0xfc, 0x6b, 0x21, 0x52, 0x9b, 0xd4,
+	0x9a, 0x96, 0x4d, 0xdd, 0xbd, 0x70, 0x78, 0x9b, 0x7a, 0x24, 0x69, 0xd4, 0x52, 0xbf, 0x51, 0x6e,
+	0xd7, 0xf6, 0xac, 0x36, 0xed, 0x19, 0xf0, 0xfa, 0x61, 0x03, 0x58, 0xad, 0x49, 0xdb, 0x24, 0x3e,
+	0xce, 0xfc, 0x00, 0xce, 0xae, 0xd8, 0xa4, 0xb5, 0xc7, 0x2c, 0x86, 0xbb, 0xf6, 0x8a, 0xdb, 0xe8,
+	0xb6, 0xa9, 0xed, 0xa1, 0xf3, 0x30, 0x62, 0x93, 0x36, 0x9d, 0x33, 0xce, 0x1b, 0x2f, 0x16, 0xca,
+	0xe3, 0x9f, 0xef, 0x2f, 0x9e, 0x39, 0xd8, 0x5f, 0x1c, 0x79, 0x9b, 0xb4, 0x29, 0x16, 0x14, 0xf4,
+	0x1c, 0xe4, 0x76, 0x49, 0xab, 0x4b, 0xe7, 0x32, 0xa2, 0xcb, 0x84, 0xea, 0x92, 0xbb, 0xcb, 0x1b,
+	0xb1, 0xa4, 0x99, 0xbf, 0x9b, 0x8d, 0xc0, 0x7f, 0x93, 0x7a, 0xa4, 0x4e, 0x3c, 0x82, 0xda, 0x90,
+	0x6f, 0x91, 0x2d, 0xda, 0x62, 0x73, 0xc6, 0xf9, 0xec, 0x8b, 0xc5, 0xe5, 0xeb, 0xa5, 0x41, 0x36,
+	0xb1, 0x94, 0x00, 0x55, 0x5a, 0x17, 0x38, 0xd7, 0x6d, 0xcf, 0xdd, 0x2b, 0x4f, 0xaa, 0x49, 0xe4,
+	0x65, 0x23, 0x56, 0x4c, 0xd0, 0x6f, 0x1b, 0x50, 0x24, 0xb6, 0xed, 0x78, 0xc4, 0xe3, 0xdb, 0x34,
+	0x97, 0x11, 0x4c, 0x6f, 0x0f, 0xcf, 0x74, 0x25, 0x04, 0x93, 0x9c, 0xcf, 0x2a, 0xce, 0x45, 0x8d,
+	0x82, 0x75, 0x9e, 0xf3, 0x6f, 0x42, 0x51, 0x9b, 0x2a, 0x9a, 0x86, 0xec, 0x0e, 0xdd, 0x93, 0xf2,
+	0xc5, 0xfc, 0x4f, 0x34, 0x1b, 0x11, 0xa8, 0x92, 0xe0, 0x95, 0xcc, 0x65, 0x63, 0xfe, 0x1a, 0x4c,
+	0xc7, 0x19, 0xa6, 0x19, 0x6f, 0xfe, 0x89, 0x01, 0xb3, 0xda, 0x2a, 0x30, 0xdd, 0xa6, 0x2e, 0xb5,
+	0x6b, 0x14, 0x2d, 0x41, 0x81, 0xef, 0x25, 0xeb, 0x90, 0x9a, 0xbf, 0xd5, 0x33, 0x6a, 0x21, 0x85,
+	0xb7, 0x7d, 0x02, 0x0e, 0xfb, 0x04, 0xc7, 0x22, 0xf3, 0xb8, 0x63, 0xd1, 0x69, 0x12, 0x46, 0xe7,
+	0xb2, 0xd1, 0x63, 0xb1, 0xc1, 0x1b, 0xb1, 0xa4, 0x99, 0x0f, 0xe0, 0x6b, 0xfe, 0x7c, 0x36, 0x69,
+	0xbb, 0xd3, 0x22, 0x1e, 0x0d, 0x27, 0x75, 0xf8, 0xd1, 0x3b, 0x0f, 0x23, 0x3b, 0x96, 0x5d, 0x8f,
+	0xcf, 0xe2, 0x1b, 0x96, 0x5d, 0xc7, 0x82, 0x62, 0xee, 0xc0, 0xc4, 0x4a, 0xa7, 0xe3, 0x3a, 0xbb,
+	0xb4, 0x5e, 0xf5, 0x48, 0x83, 0xa2, 0x7b, 0x00, 0x44, 0x35, 0xac, 0x78, 0x02, 0xba, 0xb8, 0xfc,
+	0x8b, 0x25, 0xa9, 0x33, 0x25, 0x5d, 0x67, 0x4a, 0x9d, 0x9d, 0x06, 0x6f, 0x60, 0x25, 0xae, 0x9a,
+	0xa5, 0xdd, 0x0b, 0xa5, 0x4d, 0xab, 0x4d, 0xcb, 0x93, 0x07, 0xfb, 0x8b, 0xb0, 0x12, 0x20, 0x60,
+	0x0d, 0xcd, 0xfc, 0x1d, 0x03, 0xce, 0xad, 0xb8, 0x0d, 0xa7, 0xb2, 0xba, 0xd2, 0xe9, 0xdc, 0xa2,
+	0xa4, 0xe5, 0x35, 0xab, 0x1e, 0xf1, 0xba, 0x0c, 0x5d, 0x83, 0x3c, 0x13, 0x7f, 0xa9, 0xc5, 0xbc,
+	0xe0, 0x9f, 0x4f, 0x49, 0x7f, 0xb4, 0xbf, 0x38, 0x9b, 0x30, 0x90, 0x62, 0x35, 0x0a, 0xbd, 0x04,
+	0xa3, 0x6d, 0xca, 0x18, 0x69, 0xf8, 0x12, 0x9f, 0x52, 0x00, 0xa3, 0xdf, 0x94, 0xcd, 0xd8, 0xa7,
+	0x9b, 0xff, 0x9c, 0x81, 0xa9, 0x00, 0x4b, 0xb1, 0x3f, 0x81, 0xed, 0xed, 0xc2, 0x78, 0x53, 0x5b,
+	0xa1, 0xd8, 0xe5, 0xe2, 0xf2, 0xd5, 0x01, 0x35, 0x29, 0x49, 0x48, 0xe5, 0x59, 0xc5, 0x66, 0x5c,
+	0x6f, 0xc5, 0x11, 0x36, 0xa8, 0x0d, 0xc0, 0xf6, 0xec, 0x9a, 0x62, 0x3a, 0x22, 0x98, 0xbe, 0x99,
+	0x92, 0x69, 0x35, 0x00, 0x28, 0x23, 0xc5, 0x12, 0xc2, 0x36, 0xac, 0x31, 0x30, 0xff, 0xce, 0x80,
+	0xb3, 0x09, 0xe3, 0xd0, 0x5b, 0xb1, 0xfd, 0x7c, 0xbe, 0x67, 0x3f, 0x51, 0xcf, 0xb0, 0x70, 0x37,
+	0x5f, 0x81, 0x31, 0x97, 0xee, 0x5a, 0xfc, 0xa6, 0x50, 0x12, 0x9e, 0x56, 0xe3, 0xc7, 0xb0, 0x6a,
+	0xc7, 0x41, 0x0f, 0xf4, 0x32, 0x14, 0xfc, 0xbf, 0xb9, 0x98, 0xb3, 0x5c, 0x99, 0xf8, 0xc6, 0xf9,
+	0x5d, 0x19, 0x0e, 0xe9, 0xe6, 0x6f, 0x41, 0xae, 0xd2, 0x24, 0xae, 0xc7, 0x4f, 0x8c, 0x4b, 0x3b,
+	0xce, 0x3b, 0x78, 0x5d, 0x4d, 0x31, 0x38, 0x31, 0x58, 0x36, 0x63, 0x9f, 0x3e, 0xc0, 0x66, 0xbf,
+	0x04, 0xa3, 0xbb, 0xd4, 0x15, 0xf3, 0xcd, 0x46, 0xc1, 0xee, 0xca, 0x66, 0xec, 0xd3, 0xcd, 0x7f,
+	0x37, 0x60, 0x56, 0xcc, 0x60, 0xd5, 0x62, 0x35, 0x67, 0x97, 0xba, 0x7b, 0x98, 0xb2, 0x6e, 0xeb,
+	0x98, 0x27, 0xb4, 0x0a, 0xd3, 0x8c, 0xb6, 0x77, 0xa9, 0x5b, 0x71, 0x6c, 0xe6, 0xb9, 0xc4, 0xb2,
+	0x3d, 0x35, 0xb3, 0x39, 0xd5, 0x7b, 0xba, 0x1a, 0xa3, 0xe3, 0x9e, 0x11, 0xe8, 0x45, 0x18, 0x53,
+	0xd3, 0xe6, 0x47, 0x89, 0x0b, 0x76, 0x9c, 0xef, 0x81, 0x5a, 0x13, 0xc3, 0x01, 0xd5, 0xfc, 0x6f,
+	0x03, 0x66, 0xc4, 0xaa, 0xaa, 0xdd, 0x2d, 0x56, 0x73, 0xad, 0x0e, 0x37, 0xc0, 0x4f, 0xe2, 0x92,
+	0xae, 0xc1, 0x64, 0xdd, 0x17, 0xfc, 0xba, 0xd5, 0xb6, 0x3c, 0xa1, 0x23, 0xb9, 0xf2, 0x53, 0x0a,
+	0x63, 0x72, 0x35, 0x42, 0xc5, 0xb1, 0xde, 0x72, 0xfb, 0x5a, 0x5d, 0xe6, 0x51, 0x77, 0xc3, 0x75,
+	0xda, 0x0e, 0x5f, 0xe7, 0x26, 0x61, 0x3b, 0xe8, 0x57, 0x61, 0xac, 0xad, 0x2e, 0x3d, 0x65, 0x35,
+	0x7f, 0x69, 0x30, 0xab, 0x79, 0x67, 0xeb, 0xdb, 0xb4, 0xe6, 0xf1, 0x0b, 0x33, 0xd4, 0xb6, 0xb0,
+	0x0d, 0x07, 0xa8, 0xe8, 0x3d, 0x18, 0x61, 0x1d, 0x5a, 0x13, 0x22, 0x2a, 0x2e, 0xbf, 0x31, 0x98,
+	0x52, 0x47, 0x26, 0x59, 0xed, 0xd0, 0x5a, 0x28, 0x5b, 0xfe, 0x1f, 0x16, 0x90, 0xe6, 0x7f, 0x1a,
+	0x30, 0x97, 0xb4, 0xaa, 0x75, 0x8b, 0x79, 0xe8, 0x83, 0x9e, 0x95, 0x95, 0x06, 0x5b, 0x19, 0x1f,
+	0x2d, 0xd6, 0x15, 0x68, 0xaf, 0xdf, 0xa2, 0xad, 0xea, 0x01, 0xe4, 0x2c, 0x8f, 0xb6, 0x7d, 0x57,
+	0xe3, 0xca, 0x60, 0xcb, 0x4a, 0x9a, 0x6c, 0x78, 0x85, 0xae, 0x71, 0x40, 0x2c, 0x71, 0xcd, 0xf7,
+	0x61, 0xbc, 0xd2, 0x75, 0x5d, 0x6a, 0x7b, 0xf2, 0x82, 0xfb, 0x06, 0xe4, 0x98, 0x65, 0x2b, 0x3b,
+	0x9f, 0xee, 0x6e, 0x2b, 0x70, 0xf0, 0x2a, 0x1f, 0x8c, 0x25, 0x86, 0xf9, 0x17, 0x59, 0x38, 0xeb,
+	0x9f, 0x18, 0x5a, 0x5f, 0x71, 0x3d, 0x6b, 0x9b, 0xd4, 0x3c, 0x86, 0xea, 0x30, 0x5e, 0x0f, 0x9b,
+	0x3d, 0x65, 0x88, 0xd3, 0xf0, 0x0a, 0x8c, 0xbd, 0x06, 0xef, 0xe1, 0x08, 0x2a, 0x7a, 0x17, 0xb2,
+	0x0d, 0xcb, 0x53, 0x9e, 0xe1, 0xe5, 0xc1, 0x24, 0x77, 0xd3, 0x8a, 0x5b, 0x9e, 0x72, 0x51, 0xb1,
+	0xca, 0xde, 0xb4, 0x3c, 0xcc, 0x11, 0xd1, 0x16, 0xe4, 0xad, 0x36, 0x69, 0xd0, 0x94, 0xbb, 0xb2,
+	0xc6, 0xc7, 0xc4, 0xd1, 0x03, 0x57, 0x53, 0x50, 0x19, 0x56, 0xc8, 0x9c, 0x47, 0x8d, 0x5b, 0x0c,
+	0x69, 0xb3, 0x07, 0xdf, 0xf9, 0x04, 0xdb, 0x19, 0xf2, 0x10, 0x54, 0x86, 0x15, 0xb2, 0xf9, 0x65,
+	0x06, 0xa6, 0x43, 0xf9, 0x55, 0x9c, 0x76, 0xdb, 0xf2, 0xd0, 0x3c, 0x64, 0xac, 0xba, 0x32, 0x48,
+	0xa0, 0x06, 0x66, 0xd6, 0x56, 0x71, 0xc6, 0xaa, 0xa3, 0x17, 0x20, 0xbf, 0xe5, 0x12, 0xbb, 0xd6,
+	0x54, 0x86, 0x28, 0x00, 0x2e, 0x8b, 0x56, 0xac, 0xa8, 0xe8, 0x59, 0xc8, 0x7a, 0xa4, 0xa1, 0xec,
+	0x4f, 0x20, 0xbf, 0x4d, 0xd2, 0xc0, 0xbc, 0x9d, 0x1b, 0x3e, 0xd6, 0x15, 0x3a, 0x2c, 0x76, 0x5e,
+	0x33, 0x7c, 0x55, 0xd9, 0x8c, 0x7d, 0x3a, 0xe7, 0x48, 0xba, 0x5e, 0xd3, 0x71, 0xe7, 0x72, 0x51,
+	0x8e, 0x2b, 0xa2, 0x15, 0x2b, 0x2a, 0x77, 0x51, 0x6a, 0x62, 0xfe, 0x1e, 0x75, 0xe7, 0xf2, 0x51,
+	0x17, 0xa5, 0xe2, 0x13, 0x70, 0xd8, 0x07, 0xdd, 0x87, 0x62, 0xcd, 0xa5, 0xc4, 0x73, 0xdc, 0x55,
+	0xe2, 0xd1, 0xb9, 0xd1, 0xd4, 0x27, 0x70, 0x8a, 0x7b, 0xe9, 0x95, 0x10, 0x02, 0xeb, 0x78, 0xe6,
+	0xdf, 0x67, 0x61, 0x2e, 0x14, 0xad, 0xd8, 0xdb, 0xd0, 0x33, 0x55, 0xe2, 0x31, 0xfa, 0x88, 0xe7,
+	0x05, 0xc8, 0xd7, 0xad, 0x06, 0x65, 0x5e, 0x5c, 0xca, 0xab, 0xa2, 0x15, 0x2b, 0x2a, 0xfa, 0x83,
+	0x58, 0x34, 0x92, 0x13, 0x07, 0xe5, 0xce, 0x60, 0x07, 0xa5, 0xdf, 0xe4, 0x86, 0x08, 0x49, 0xd0,
+	0x32, 0x40, 0xc3, 0xf2, 0xd4, 0xa5, 0xa5, 0x76, 0x3d, 0x30, 0xd6, 0x37, 0x03, 0x0a, 0xd6, 0x7a,
+	0xa1, 0x77, 0xa1, 0x20, 0xe4, 0x35, 0xa4, 0xfe, 0x0b, 0x17, 0xa6, 0xe2, 0x03, 0xe0, 0x10, 0xeb,
+	0xc8, 0x41, 0xce, 0xfb, 0x80, 0xae, 0x3f, 0xec, 0xb8, 0x94, 0xf1, 0xab, 0xfb, 0x2e, 0x71, 0x2d,
+	0xb2, 0xd5, 0xa2, 0xc7, 0x15, 0xc7, 0x7e, 0x31, 0x02, 0xa3, 0x37, 0x5c, 0x6a, 0x35, 0x9a, 0xde,
+	0x29, 0x5c, 0x89, 0xcf, 0x41, 0x8e, 0xb4, 0x2c, 0xc2, 0xc4, 0xe9, 0xd6, 0xa6, 0xb4, 0xc2, 0x1b,
+	0xb1, 0xa4, 0xa1, 0xf7, 0x21, 0xef, 0xb8, 0x56, 0xc3, 0xb2, 0xe7, 0x0a, 0x62, 0x12, 0x17, 0x07,
+	0x3b, 0x3f, 0x6a, 0x15, 0x77, 0xc4, 0xd0, 0xf0, 0x88, 0xca, 0xff, 0xb1, 0x82, 0x44, 0xf7, 0x60,
+	0x54, 0xaa, 0x9c, 0x6f, 0xc6, 0x96, 0x06, 0x36, 0xc3, 0x52, 0x6b, 0x43, 0xd3, 0x20, 0xff, 0x67,
+	0xd8, 0x07, 0x44, 0xd5, 0xc0, 0x0a, 0x8f, 0x08, 0xe8, 0x97, 0x53, 0x58, 0xe1, 0xbe, 0x66, 0xb7,
+	0x1a, 0x98, 0xdd, 0x5c, 0x1a, 0x50, 0x61, 0x58, 0xfb, 0xd9, 0x59, 0x2e, 0x62, 0xe5, 0xee, 0xe7,
+	0x87, 0x10, 0xb1, 0x8a, 0x35, 0x26, 0xa3, 0x31, 0x82, 0x1f, 0x0d, 0x98, 0xdf, 0xc9, 0xc2, 0x8c,
+	0xea, 0x59, 0x71, 0x5a, 0x2d, 0x5a, 0x13, 0xbe, 0xa5, 0xb4, 0xe2, 0xd9, 0x44, 0x2b, 0x6e, 0xf9,
+	0x3e, 0x85, 0xbc, 0x19, 0xcb, 0xa9, 0x66, 0x13, 0xf2, 0x28, 0x09, 0x3f, 0x42, 0xda, 0x88, 0x60,
+	0x97, 0x54, 0x2f, 0xe5, 0x5d, 0xa0, 0xdf, 0x37, 0xe0, 0xec, 0x2e, 0x75, 0xad, 0x6d, 0xab, 0x26,
+	0xf4, 0xf1, 0x96, 0xc5, 0x3c, 0xc7, 0xdd, 0x53, 0xf7, 0xe6, 0xeb, 0x83, 0x71, 0xbe, 0xab, 0x01,
+	0xac, 0xd9, 0xdb, 0x4e, 0xf9, 0x19, 0xc5, 0xed, 0xec, 0xdd, 0x5e, 0x68, 0x9c, 0xc4, 0x6f, 0xbe,
+	0x03, 0x10, 0xce, 0x36, 0xc1, 0x1c, 0xac, 0xeb, 0xca, 0x3b, 0xf0, 0xc4, 0xfc, 0xc5, 0xfa, 0xb6,
+	0x53, 0x37, 0x23, 0x9f, 0x19, 0x50, 0x54, 0xf4, 0x53, 0x70, 0x13, 0x71, 0xd4, 0x4d, 0x7c, 0x35,
+	0xd5, 0xfc, 0xfb, 0x78, 0x86, 0x2e, 0x4c, 0x44, 0x94, 0x1c, 0x5d, 0x52, 0xe9, 0x12, 0x69, 0x03,
+	0x7f, 0x5e, 0x4f, 0x97, 0x3c, 0xda, 0x5f, 0x9c, 0x89, 0x74, 0x0e, 0x73, 0x28, 0x87, 0xc7, 0x2e,
+	0x57, 0xc6, 0xbe, 0xfb, 0xd7, 0x8b, 0x67, 0x3e, 0xfe, 0xd1, 0xf9, 0x33, 0xe6, 0xa7, 0x59, 0x98,
+	0x8e, 0x4b, 0x75, 0x00, 0xdb, 0x1b, 0xda, 0xb0, 0xb1, 0x13, 0xb5, 0x61, 0x99, 0x93, 0xb3, 0x61,
+	0xd9, 0x93, 0xb0, 0x61, 0x23, 0xc7, 0x66, 0xc3, 0xcc, 0x7f, 0x33, 0x60, 0x32, 0xd8, 0x99, 0x0f,
+	0xbb, 0xdc, 0xff, 0x08, 0xa5, 0x6e, 0x1c, 0xbf, 0xd4, 0x1f, 0xc0, 0x28, 0x73, 0xba, 0x6e, 0x4d,
+	0x38, 0xd9, 0x1c, 0xfd, 0xb5, 0x74, 0x46, 0x53, 0x8e, 0xd5, 0x3c, 0x4b, 0xd9, 0x80, 0x7d, 0x54,
+	0xf3, 0xb3, 0x4c, 0xb0, 0x20, 0x45, 0x93, 0x8e, 0x97, 0xcb, 0xdd, 0x52, 0xbe, 0xa0, 0x31, 0xdd,
+	0xf1, 0xe2, 0xad, 0x58, 0x51, 0x91, 0x29, 0xec, 0xb9, 0xef, 0xff, 0x17, 0xca, 0xa0, 0xcc, 0xb2,
+	0xd8, 0x04, 0x49, 0x41, 0x1d, 0x98, 0x76, 0xe9, 0x87, 0x5d, 0xcb, 0xa5, 0xf5, 0xaa, 0x43, 0x76,
+	0xb8, 0xd3, 0xa2, 0x92, 0x5c, 0x03, 0xea, 0xfd, 0x6a, 0xd7, 0x15, 0x26, 0xac, 0x3c, 0xcb, 0x63,
+	0x77, 0x1c, 0xc3, 0xc2, 0x3d, 0xe8, 0xc8, 0x81, 0x59, 0xb2, 0x4b, 0xac, 0x16, 0xd9, 0xb2, 0x5a,
+	0x96, 0xb7, 0x57, 0xf5, 0x5c, 0xe2, 0xd1, 0xc6, 0x9e, 0x72, 0xb1, 0xaf, 0xaa, 0xb5, 0xcc, 0xae,
+	0x24, 0xf4, 0x79, 0xb4, 0xbf, 0xf8, 0x8c, 0x92, 0x45, 0x12, 0x19, 0x27, 0x02, 0x9b, 0xff, 0x95,
+	0x0b, 0x2c, 0x84, 0xca, 0x6b, 0xfd, 0x3a, 0x14, 0x6b, 0x32, 0x98, 0x6c, 0xed, 0xad, 0xd9, 0xea,
+	0x4c, 0xaf, 0x0e, 0x71, 0xdb, 0x95, 0x2a, 0x21, 0x4c, 0xcc, 0x0b, 0xd5, 0x28, 0x58, 0xe7, 0x86,
+	0x3e, 0x02, 0x90, 0xa6, 0x9f, 0xd6, 0xd7, 0x6c, 0x75, 0xb7, 0x55, 0x86, 0xe1, 0x7d, 0x37, 0x40,
+	0x91, 0xac, 0x03, 0x27, 0x2b, 0x24, 0x60, 0x8d, 0x15, 0x5f, 0xb5, 0x9f, 0xc5, 0xbd, 0xe1, 0xb8,
+	0xca, 0x48, 0x0c, 0xb5, 0xea, 0x95, 0x10, 0x26, 0xee, 0x7b, 0x87, 0x14, 0xac, 0x73, 0x9b, 0x77,
+	0x61, 0x3a, 0x2e, 0xab, 0x84, 0xfb, 0xed, 0x56, 0xf4, 0x7e, 0x5b, 0x1e, 0xd0, 0x22, 0x68, 0x89,
+	0x01, 0xfd, 0x1d, 0xc1, 0x85, 0xa9, 0x98, 0x8c, 0x12, 0x58, 0xae, 0x45, 0x59, 0x5e, 0x4c, 0x73,
+	0xd7, 0xab, 0x6c, 0xbb, 0xce, 0x93, 0xc1, 0x74, 0x5c, 0x3a, 0xc7, 0xc6, 0x34, 0x92, 0xe2, 0xd7,
+	0x2f, 0xf1, 0xbf, 0xcc, 0x40, 0x21, 0x30, 0xe3, 0x69, 0xf2, 0x75, 0xd2, 0xfd, 0xca, 0x1c, 0x12,
+	0x44, 0x67, 0x07, 0x09, 0xa2, 0x47, 0xfa, 0x07, 0xd1, 0x7e, 0x4e, 0x3f, 0xff, 0xf8, 0x9c, 0xbe,
+	0x16, 0x44, 0x8f, 0x0e, 0x1e, 0x44, 0x8f, 0x1d, 0x1e, 0x44, 0x9b, 0x7f, 0x63, 0x00, 0xea, 0xcd,
+	0x98, 0xa4, 0x11, 0x14, 0x89, 0x5f, 0xae, 0xaf, 0xa7, 0x0d, 0x5f, 0x0f, 0xbb, 0x63, 0xcd, 0xcf,
+	0x72, 0x30, 0x75, 0xd3, 0x1a, 0x3a, 0xf5, 0xea, 0xc1, 0xd3, 0x12, 0xa9, 0x4a, 0x95, 0xe3, 0x1b,
+	0x58, 0x56, 0xb9, 0xbf, 0x57, 0xd4, 0xd0, 0xa7, 0x2b, 0xc9, 0xdd, 0x1e, 0xf5, 0x27, 0xe1, 0x7e,
+	0xd0, 0x03, 0x1f, 0x92, 0xab, 0x30, 0xc1, 0x3c, 0xd7, 0xaa, 0x79, 0x32, 0xb9, 0xcb, 0xe6, 0x8a,
+	0xe2, 0xe6, 0x3a, 0xa7, 0xba, 0x4f, 0x54, 0x75, 0x22, 0x8e, 0xf6, 0x4d, 0xcc, 0x19, 0x8f, 0xa4,
+	0xce, 0x19, 0x2f, 0x41, 0x81, 0xb4, 0x5a, 0xce, 0x47, 0x9b, 0xa4, 0xc1, 0x54, 0x96, 0x26, 0x38,
+	0x35, 0x2b, 0x3e, 0x01, 0x87, 0x7d, 0x50, 0x09, 0xc0, 0x6a, 0xd8, 0x8e, 0x4b, 0xc5, 0x88, 0xbc,
+	0xb8, 0x42, 0xc5, 0xbb, 0xd8, 0x5a, 0xd0, 0x8a, 0xb5, 0x1e, 0xa8, 0x0a, 0xe7, 0x2c, 0x9b, 0xd1,
+	0x5a, 0xd7, 0xa5, 0xd5, 0x1d, 0xab, 0xb3, 0xb9, 0x5e, 0x15, 0x56, 0x62, 0x4f, 0x9c, 0xe6, 0xb1,
+	0xf2, 0xb3, 0x8a, 0xd9, 0xb9, 0xb5, 0xa4, 0x4e, 0x38, 0x79, 0x2c, 0x7a, 0x0d, 0xc6, 0x2d, 0xbb,
+	0xd6, 0xea, 0xd6, 0xe9, 0x06, 0xf1, 0x9a, 0x6c, 0x6e, 0x4c, 0x4c, 0x63, 0xfa, 0x60, 0x7f, 0x71,
+	0x7c, 0x4d, 0x6b, 0xc7, 0x91, 0x5e, 0x7c, 0x14, 0x7d, 0xa8, 0x8d, 0x2a, 0x84, 0xa3, 0xae, 0x3f,
+	0xd4, 0x47, 0xe9, 0xbd, 0x12, 0xb2, 0xea, 0x90, 0x2a, 0xab, 0xfe, 0xfd, 0x0c, 0xe4, 0xe5, 0xa3,
+	0x16, 0xba, 0x14, 0x7b, 0x39, 0x7a, 0xb6, 0xe7, 0xe5, 0xa8, 0x98, 0xf4, 0x00, 0x68, 0x42, 0xde,
+	0x62, 0xac, 0x1b, 0xf5, 0x58, 0xd6, 0x44, 0x0b, 0x56, 0x14, 0x91, 0x71, 0x74, 0xec, 0x6d, 0xab,
+	0xa1, 0xd2, 0x31, 0xd7, 0x34, 0x3f, 0x25, 0x2c, 0x4d, 0x78, 0x10, 0xd4, 0x2e, 0x84, 0x2e, 0x4b,
+	0xa4, 0x03, 0xf7, 0x5d, 0x6e, 0x57, 0xef, 0xbc, 0x2d, 0x79, 0x54, 0x04, 0x22, 0x56, 0xc8, 0x9c,
+	0x87, 0xd3, 0xf5, 0x3a, 0x5d, 0x4f, 0x1c, 0x94, 0x63, 0xe2, 0x71, 0x47, 0x20, 0x62, 0x85, 0x6c,
+	0x7e, 0x6a, 0xc0, 0x94, 0x94, 0x41, 0xa5, 0x49, 0x6b, 0x3b, 0x55, 0x8f, 0x76, 0x78, 0x08, 0xd1,
+	0x65, 0x94, 0xc5, 0x43, 0x88, 0x77, 0x18, 0x65, 0x58, 0x50, 0xb4, 0xd5, 0x67, 0x4e, 0x6a, 0xf5,
+	0xe6, 0x65, 0xd0, 0x36, 0x47, 0xbc, 0xca, 0xca, 0xc7, 0x49, 0x79, 0x85, 0x65, 0x43, 0x23, 0x24,
+	0x7b, 0xed, 0x61, 0x9f, 0x6e, 0x1e, 0x64, 0x20, 0x27, 0xbc, 0xfc, 0x34, 0x96, 0x2b, 0x9a, 0x96,
+	0xcb, 0x0c, 0x94, 0x96, 0x3b, 0x24, 0x73, 0x1b, 0xa6, 0x26, 0x47, 0x1e, 0x9b, 0x9a, 0x64, 0x49,
+	0x99, 0xc9, 0xb7, 0x52, 0x04, 0x37, 0xc3, 0x54, 0x46, 0x1c, 0x35, 0xf3, 0xf7, 0x13, 0x03, 0x66,
+	0x93, 0x72, 0xf4, 0x69, 0x64, 0xfe, 0x0a, 0x8c, 0x75, 0x5a, 0xc4, 0xdb, 0x76, 0xdc, 0x76, 0xfc,
+	0x6d, 0x76, 0x43, 0xb5, 0xe3, 0xa0, 0x07, 0x72, 0x01, 0x5c, 0x3f, 0xcc, 0xf5, 0x43, 0xc0, 0x6b,
+	0x47, 0xcb, 0xdf, 0x86, 0x3b, 0x1c, 0x34, 0x31, 0xac, 0x71, 0x31, 0xff, 0x28, 0x07, 0x33, 0x62,
+	0xc8, 0xb0, 0x17, 0xe2, 0x30, 0xc7, 0xaa, 0x03, 0x4f, 0x89, 0xe0, 0xb4, 0xf7, 0x0e, 0x95, 0x27,
+	0xed, 0xb2, 0x1a, 0xff, 0xd4, 0x5a, 0x62, 0xaf, 0x47, 0x7d, 0x29, 0xb8, 0x0f, 0x6e, 0xef, 0xc5,
+	0x08, 0x3f, 0x7b, 0x17, 0xa3, 0x7e, 0xd8, 0x46, 0x0f, 0x3d, 0x6c, 0x7d, 0xaf, 0xd1, 0xb1, 0x23,
+	0x5c, 0xa3, 0xbd, 0x57, 0x5b, 0x21, 0xd5, 0xd5, 0xf6, 0x57, 0x19, 0x18, 0xdd, 0x70, 0x1d, 0xf1,
+	0xd6, 0x73, 0xf2, 0x09, 0xf1, 0x77, 0x86, 0x7c, 0x23, 0xe6, 0x50, 0xd2, 0x96, 0x8b, 0x37, 0xe2,
+	0xb1, 0xe8, 0xfb, 0xb0, 0x96, 0xdf, 0xcd, 0xa6, 0x09, 0x3b, 0x14, 0xf0, 0x21, 0xf9, 0xdd, 0x1f,
+	0x18, 0x30, 0x11, 0x99, 0xc2, 0x13, 0xfc, 0x96, 0x1e, 0x93, 0x53, 0xd2, 0x5b, 0xfa, 0xbf, 0x18,
+	0x30, 0x13, 0xe9, 0x79, 0x0a, 0xd9, 0xd1, 0x6f, 0x45, 0xb3, 0xa3, 0x17, 0x87, 0x58, 0x4f, 0x9f,
+	0x1c, 0xe9, 0x9f, 0xc5, 0x57, 0xc3, 0x57, 0x8a, 0x7e, 0x13, 0x66, 0x3a, 0xfe, 0xd3, 0xfb, 0x86,
+	0xd3, 0xb2, 0x6a, 0x16, 0xf5, 0x93, 0xed, 0x97, 0x52, 0xd6, 0x25, 0x88, 0xe1, 0x7b, 0xe5, 0xaf,
+	0x29, 0xee, 0x33, 0x1b, 0x71, 0x5c, 0xdc, 0xcb, 0x4a, 0xe4, 0x9e, 0xd5, 0xac, 0x9e, 0xd8, 0xdc,
+	0xb3, 0x9a, 0x5f, 0x1f, 0xb9, 0xfe, 0xd0, 0x80, 0x71, 0x4d, 0x3d, 0x18, 0x6a, 0x02, 0x7c, 0x44,
+	0x5c, 0xda, 0x74, 0x02, 0x37, 0x6e, 0xe0, 0x8c, 0xe0, 0xbb, 0xfe, 0x38, 0x81, 0x14, 0x9e, 0xfc,
+	0xa0, 0x9d, 0x61, 0x0d, 0x1b, 0x7d, 0x4b, 0x4b, 0xee, 0x49, 0xdd, 0x1a, 0x88, 0x8b, 0xc8, 0x1d,
+	0x48, 0x0e, 0xba, 0x26, 0x6b, 0x29, 0x41, 0xf3, 0x7b, 0x99, 0x40, 0x93, 0x55, 0xbe, 0xac, 0x06,
+	0x50, 0x73, 0xec, 0xba, 0xe5, 0x05, 0xc5, 0x59, 0xc5, 0xe5, 0xa5, 0xc1, 0xb6, 0xa6, 0xe2, 0x8f,
+	0x0b, 0x17, 0x14, 0x34, 0x31, 0xac, 0xc1, 0xa2, 0x8b, 0x7e, 0x25, 0x65, 0x34, 0x62, 0x90, 0x95,
+	0x94, 0x8f, 0xf6, 0x17, 0x7d, 0x41, 0xeb, 0x95, 0x95, 0x29, 0x2a, 0x06, 0x51, 0x15, 0x72, 0xdc,
+	0x54, 0xf9, 0xe5, 0x74, 0xcb, 0xa9, 0x8d, 0x1f, 0x53, 0x95, 0x23, 0xfc, 0x4f, 0x2c, 0xb1, 0xcc,
+	0xbf, 0xcd, 0x40, 0x21, 0x38, 0xeb, 0xa7, 0x7e, 0x33, 0x5c, 0x4c, 0xa9, 0xa5, 0xfd, 0xac, 0x1d,
+	0xba, 0x1f, 0xbb, 0x19, 0xd2, 0xaa, 0xff, 0x21, 0x77, 0xc3, 0x3f, 0xca, 0xbb, 0x41, 0xf6, 0x3d,
+	0x05, 0x55, 0xdf, 0x8c, 0xaa, 0xfa, 0x52, 0xca, 0xd5, 0xf4, 0x51, 0xf6, 0x8f, 0x33, 0x30, 0x15,
+	0x33, 0x78, 0xe8, 0x39, 0x71, 0xa8, 0x1a, 0xfe, 0xa1, 0x0d, 0x06, 0xaa, 0x14, 0x9d, 0xa0, 0xa1,
+	0x5d, 0xee, 0xe3, 0x05, 0xde, 0x9f, 0xe3, 0x2a, 0x21, 0x7f, 0x7d, 0x28, 0x1b, 0xeb, 0x83, 0x94,
+	0x67, 0xa4, 0x7b, 0xa8, 0xe1, 0xe2, 0x28, 0x1b, 0xb4, 0x01, 0xb3, 0xa4, 0xeb, 0x39, 0x01, 0xc0,
+	0x75, 0x9b, 0x6c, 0xb5, 0xa8, 0xcc, 0xf7, 0x8d, 0x95, 0x7f, 0x2e, 0xc8, 0xb4, 0x27, 0xf4, 0xc1,
+	0x89, 0x23, 0xcd, 0xef, 0x19, 0xf0, 0x74, 0x9f, 0xf9, 0x0c, 0xf0, 0xfc, 0xd5, 0x82, 0x09, 0x51,
+	0xa0, 0x1e, 0xc8, 0xc1, 0x3f, 0xc5, 0x83, 0xed, 0xbc, 0x3e, 0x54, 0xae, 0x3e, 0xd2, 0x84, 0xa3,
+	0xe0, 0xe6, 0x0f, 0x32, 0x80, 0x82, 0xb9, 0xa6, 0x79, 0xa5, 0xbb, 0x0f, 0xa3, 0xdb, 0x32, 0xdd,
+	0x7d, 0xb4, 0x67, 0xd6, 0x72, 0x51, 0x7f, 0x69, 0xf6, 0x31, 0xd1, 0x7b, 0xc7, 0xa3, 0x6b, 0xd0,
+	0xab, 0x67, 0xe8, 0x1e, 0xc0, 0xb6, 0x65, 0x5b, 0xac, 0x39, 0x64, 0xb5, 0x8a, 0x70, 0xe2, 0x6f,
+	0x04, 0x08, 0x58, 0x43, 0x33, 0xff, 0x3c, 0xa3, 0xe9, 0xb0, 0x70, 0x1f, 0x06, 0x3a, 0xfb, 0x2f,
+	0x45, 0x85, 0x59, 0xe8, 0x7d, 0x82, 0x0f, 0x04, 0x73, 0x0f, 0x46, 0x76, 0x89, 0xeb, 0xbf, 0x06,
+	0x0e, 0x58, 0x08, 0xd7, 0x5b, 0x03, 0x13, 0xee, 0xe9, 0x5d, 0xe2, 0x32, 0x2c, 0x30, 0xb9, 0x6b,
+	0xc5, 0x3c, 0xda, 0xf1, 0x2f, 0xaf, 0xd4, 0x86, 0xd3, 0xa3, 0x1d, 0x7d, 0x81, 0xb4, 0x23, 0x6e,
+	0x00, 0xda, 0x61, 0xe6, 0x77, 0x46, 0x35, 0xab, 0xa0, 0xee, 0xcb, 0xdb, 0x80, 0x5a, 0x84, 0x79,
+	0xb7, 0x88, 0x5d, 0xe7, 0xba, 0x44, 0xb7, 0x5d, 0xca, 0x9a, 0x2a, 0x32, 0x9b, 0x57, 0x28, 0x68,
+	0xbd, 0xa7, 0x07, 0x4e, 0x18, 0x85, 0x2e, 0x45, 0xaf, 0xc5, 0xc5, 0xf8, 0xb5, 0x38, 0x19, 0xea,
+	0xe3, 0x90, 0x17, 0xa3, 0x76, 0xde, 0x73, 0x27, 0x70, 0xde, 0x7f, 0x03, 0x66, 0xb6, 0xe3, 0x35,
+	0x19, 0xaa, 0x8e, 0xed, 0x8d, 0x21, 0x4b, 0x3a, 0xca, 0xe7, 0x0e, 0xc2, 0x87, 0xfc, 0xb0, 0x19,
+	0xf7, 0x32, 0x42, 0x8e, 0x5f, 0xc0, 0x2f, 0x92, 0x6c, 0x32, 0x7f, 0x3a, 0xb0, 0xce, 0xc5, 0xd2,
+	0x73, 0xf1, 0xd2, 0x7d, 0x09, 0x89, 0x23, 0x0c, 0x62, 0x3a, 0x98, 0x3f, 0x4e, 0x1d, 0x44, 0x97,
+	0x82, 0x77, 0x4b, 0x3e, 0x1d, 0x11, 0xc2, 0x66, 0x7b, 0x5e, 0x1c, 0x39, 0x09, 0xeb, 0xfd, 0xd0,
+	0x27, 0x06, 0x9c, 0xe3, 0x87, 0xf5, 0xfa, 0x43, 0x5a, 0xeb, 0x72, 0xa9, 0xf8, 0xdf, 0xf5, 0xcc,
+	0x15, 0x85, 0x34, 0xae, 0x0e, 0xea, 0x3a, 0x26, 0x40, 0x84, 0xf1, 0x78, 0x22, 0x19, 0x27, 0x33,
+	0x46, 0x0f, 0xa4, 0x33, 0x46, 0x45, 0xba, 0xe3, 0xe8, 0x59, 0xcc, 0xc0, 0x31, 0x93, 0x76, 0xc7,
+	0xa3, 0xe6, 0x8f, 0xb3, 0xba, 0xb9, 0x1a, 0x2c, 0xb7, 0x7a, 0x0f, 0x46, 0x3c, 0xc2, 0x76, 0x94,
+	0x16, 0xbc, 0x35, 0x44, 0x69, 0x76, 0xa8, 0x0b, 0x22, 0xf6, 0x16, 0x4d, 0x02, 0x13, 0xcd, 0x43,
+	0x86, 0xb0, 0xf8, 0x4b, 0xdb, 0x0a, 0xc3, 0x19, 0xc2, 0xc4, 0x2b, 0xdc, 0xb6, 0xca, 0x8c, 0x84,
+	0xaf, 0x70, 0xdb, 0x38, 0x63, 0x6d, 0xa3, 0xf7, 0x20, 0xe7, 0x52, 0xcf, 0xdd, 0x53, 0xd6, 0xfc,
+	0xf2, 0x10, 0x86, 0x0b, 0xf3, 0xf1, 0x52, 0x44, 0xe2, 0x4f, 0x2c, 0x11, 0x03, 0x7b, 0x9b, 0x3f,
+	0x01, 0x7b, 0x1b, 0xa6, 0xa9, 0xb3, 0x27, 0x96, 0xa6, 0xfe, 0xbe, 0xa1, 0x5d, 0xf0, 0xc1, 0x42,
+	0xd1, 0x3b, 0x30, 0xea, 0x59, 0x6d, 0xea, 0x74, 0xbd, 0x74, 0x9e, 0x65, 0x50, 0xc8, 0x20, 0xcc,
+	0xd8, 0xa6, 0x84, 0xc0, 0x3e, 0x16, 0xba, 0x06, 0x93, 0xd4, 0x75, 0x1d, 0x77, 0xb3, 0xc9, 0xcd,
+	0xb2, 0xd3, 0x92, 0x6e, 0xd4, 0x44, 0x98, 0x41, 0xba, 0x1e, 0xa1, 0xe2, 0x58, 0x6f, 0x3f, 0x3f,
+	0xf2, 0xb3, 0xf2, 0xad, 0x81, 0xca, 0x8f, 0x9c, 0xea, 0x47, 0x06, 0x43, 0xe7, 0x47, 0x0e, 0xfd,
+	0xba, 0xe0, 0x03, 0x78, 0x2a, 0x59, 0x8f, 0x8f, 0xe5, 0xeb, 0xbc, 0x7f, 0x8a, 0xcb, 0x4a, 0xb8,
+	0x4f, 0xbe, 0xfa, 0x19, 0x27, 0xe9, 0xee, 0x64, 0x8e, 0xdb, 0xdd, 0x71, 0xf5, 0xa5, 0xa8, 0x6f,
+	0x19, 0xd1, 0x7d, 0x75, 0xce, 0x8c, 0x34, 0x5f, 0xc7, 0xf5, 0xc0, 0xf4, 0x3d, 0x6b, 0xff, 0x6a,
+	0xc0, 0xb9, 0xc4, 0xde, 0x81, 0x0c, 0x33, 0x27, 0x29, 0x43, 0xe3, 0xb8, 0x65, 0xf8, 0xdd, 0x0c,
+	0x4c, 0x63, 0xda, 0x71, 0x22, 0x2f, 0x1b, 0x1b, 0xfe, 0x57, 0x20, 0x29, 0x62, 0x82, 0x58, 0xb9,
+	0x40, 0x79, 0x34, 0xf2, 0xf9, 0x07, 0x57, 0x97, 0xb6, 0xef, 0x00, 0x0e, 0xac, 0xfe, 0x3d, 0x6f,
+	0x2e, 0xf2, 0xe6, 0x90, 0xaf, 0x37, 0x12, 0x90, 0x23, 0x8b, 0x72, 0x3b, 0x65, 0xdc, 0xdf, 0x48,
+	0x51, 0xb8, 0xd7, 0x8b, 0x2c, 0x9a, 0xb1, 0x04, 0x34, 0x3f, 0xcd, 0x80, 0x8c, 0x1f, 0x4e, 0xc1,
+	0x3a, 0xfe, 0x4a, 0xc4, 0x3a, 0x2e, 0xa5, 0xc9, 0x9f, 0xf5, 0xcb, 0xa3, 0xc4, 0x63, 0xbb, 0x0b,
+	0x29, 0x93, 0x72, 0x8f, 0xc9, 0xa1, 0xfc, 0x83, 0x01, 0x05, 0xd1, 0xef, 0x14, 0x0c, 0xed, 0x46,
+	0xd4, 0xd0, 0xbe, 0x9c, 0x62, 0x15, 0x7d, 0x0c, 0xec, 0xff, 0x64, 0xd5, 0xec, 0x83, 0xc8, 0xb1,
+	0x49, 0xdc, 0xba, 0x0a, 0x89, 0x42, 0x2d, 0xe1, 0x8d, 0x58, 0xd2, 0x02, 0xdd, 0x1e, 0x3d, 0x01,
+	0xdd, 0xfe, 0x35, 0x59, 0xf5, 0x48, 0x99, 0x47, 0xeb, 0x37, 0x82, 0xd8, 0x27, 0x9b, 0xba, 0x7c,
+	0x53, 0x95, 0x98, 0x86, 0xcf, 0x6d, 0x38, 0x86, 0x8a, 0x7b, 0xf8, 0xf0, 0x78, 0xa8, 0x13, 0x37,
+	0x66, 0x2a, 0x4e, 0x78, 0x63, 0x48, 0xcb, 0x29, 0xe3, 0xa1, 0x9e, 0x66, 0xdc, 0xcb, 0x08, 0x35,
+	0x61, 0x5c, 0x2f, 0x3c, 0x57, 0xe7, 0x74, 0x39, 0x7d, 0x85, 0xbb, 0xac, 0x26, 0xd1, 0x5b, 0x70,
+	0x04, 0xd9, 0xfc, 0x63, 0x03, 0x20, 0xcc, 0x36, 0xf3, 0x3d, 0xaf, 0x39, 0x5d, 0x5b, 0xa6, 0x01,
+	0xb2, 0xe1, 0x9e, 0x57, 0x78, 0x23, 0x96, 0x34, 0xae, 0x3f, 0x32, 0x98, 0x52, 0x87, 0xfa, 0x42,
+	0x9a, 0x38, 0x2d, 0x96, 0xd5, 0x96, 0x8d, 0x58, 0x01, 0x9a, 0xfb, 0x79, 0x28, 0x6a, 0x7a, 0x16,
+	0xcb, 0x69, 0x4f, 0x9c, 0x4c, 0x4e, 0x3b, 0x39, 0x11, 0x50, 0x1c, 0x2a, 0x11, 0x70, 0x21, 0x9a,
+	0x08, 0x78, 0x26, 0x9e, 0x08, 0x90, 0xc2, 0x8e, 0x24, 0x01, 0x18, 0x4c, 0xaa, 0x88, 0xd8, 0xff,
+	0xa0, 0x41, 0xe6, 0x56, 0x86, 0x8e, 0xbb, 0x11, 0x77, 0x74, 0x6f, 0x44, 0x20, 0x71, 0x8c, 0x05,
+	0x77, 0x94, 0x55, 0x4b, 0xb5, 0xdb, 0x6e, 0x13, 0x77, 0x6f, 0x6e, 0x5c, 0x4c, 0x38, 0x70, 0x94,
+	0x6f, 0x44, 0xa8, 0x38, 0xd6, 0x1b, 0x6d, 0x04, 0x67, 0x40, 0x16, 0xc9, 0xbf, 0x92, 0xe6, 0x0c,
+	0xc8, 0x40, 0x21, 0xba, 0xf5, 0x7a, 0x2e, 0xa4, 0x70, 0x48, 0x2e, 0xe4, 0x36, 0x20, 0x67, 0x4b,
+	0x84, 0x24, 0xf5, 0x9b, 0xf2, 0x97, 0x43, 0xb8, 0x92, 0xe4, 0xc5, 0x91, 0x0d, 0x36, 0xec, 0x4e,
+	0x4f, 0x0f, 0x9c, 0x30, 0x8a, 0x1b, 0x19, 0x15, 0x85, 0x07, 0x9a, 0xa9, 0xf2, 0x1e, 0x69, 0xa3,
+	0xb8, 0x30, 0xac, 0x14, 0x45, 0xd6, 0x95, 0x18, 0x2a, 0xee, 0xe1, 0x83, 0x3e, 0x84, 0x09, 0x7e,
+	0x84, 0x42, 0xc6, 0x70, 0x44, 0xc6, 0x2a, 0xdf, 0xaa, 0x41, 0xe2, 0x28, 0x07, 0xf3, 0x4f, 0xb3,
+	0x90, 0x9c, 0x03, 0x08, 0xbf, 0xef, 0x32, 0x1e, 0xf3, 0x7d, 0xd7, 0xbb, 0x50, 0x60, 0x1e, 0x71,
+	0xe5, 0x87, 0x76, 0x99, 0xe1, 0x3e, 0xb4, 0xab, 0xfa, 0x00, 0x38, 0xc4, 0x8a, 0x25, 0x64, 0xb2,
+	0xc7, 0x9a, 0x90, 0x59, 0x06, 0x10, 0x61, 0x9e, 0x30, 0x62, 0xe2, 0x36, 0x9b, 0x08, 0x6d, 0xc2,
+	0xf5, 0x80, 0x82, 0xb5, 0x5e, 0xe8, 0xeb, 0x81, 0x8f, 0x20, 0x6b, 0x2d, 0x7e, 0xa1, 0xa7, 0x34,
+	0xee, 0x6c, 0xc4, 0x89, 0x8c, 0xe5, 0x78, 0x07, 0xaf, 0xa7, 0x35, 0xff, 0x2f, 0x03, 0x11, 0x03,
+	0x8d, 0xfe, 0xd0, 0x80, 0x19, 0x12, 0xfb, 0x21, 0x12, 0xdf, 0xbf, 0xfd, 0xe5, 0x74, 0xbf, 0x0e,
+	0xd3, 0xf3, 0x3b, 0x26, 0xe1, 0xdb, 0x6f, 0xbc, 0x0b, 0xc3, 0xbd, 0x4c, 0xd1, 0xef, 0x19, 0x70,
+	0x96, 0xf4, 0xfe, 0xd2, 0x8c, 0xda, 0xf9, 0x37, 0x87, 0xfe, 0xa9, 0x9a, 0xf2, 0xd3, 0x07, 0xfb,
+	0x8b, 0x49, 0xbf, 0xc1, 0x83, 0x93, 0xd8, 0xa1, 0xf7, 0x61, 0x84, 0xb8, 0x0d, 0x3f, 0x2d, 0x9c,
+	0x9e, 0xad, 0xff, 0x03, 0x42, 0xa1, 0x97, 0xb1, 0xe2, 0x36, 0x18, 0x16, 0xa0, 0xe6, 0x8f, 0xb2,
+	0x30, 0x1d, 0xff, 0x28, 0x4c, 0x95, 0x5c, 0x8f, 0x24, 0x96, 0x5c, 0x73, 0x45, 0x11, 0x0f, 0x23,
+	0xf1, 0x0f, 0x21, 0xc5, 0xfb, 0x86, 0xa4, 0x05, 0x8a, 0x22, 0x3e, 0xd5, 0xc8, 0x1d, 0x41, 0x51,
+	0xc4, 0xf7, 0x19, 0x21, 0x16, 0xba, 0x1c, 0xbd, 0x60, 0xcc, 0xf8, 0x05, 0x33, 0xa3, 0xaf, 0x65,
+	0xd8, 0x64, 0x73, 0x1b, 0x8a, 0xda, 0x3e, 0x28, 0x75, 0xbc, 0x92, 0x5a, 0xee, 0xe1, 0xb1, 0x9b,
+	0x92, 0xb5, 0x76, 0x21, 0x45, 0xc7, 0x0f, 0x95, 0x5f, 0x48, 0xeb, 0x48, 0xd9, 0x58, 0x21, 0x2e,
+	0x0d, 0xcd, 0xfc, 0x0f, 0x03, 0x26, 0x22, 0xdf, 0x01, 0x70, 0x6e, 0xfe, 0xf7, 0x16, 0xc3, 0xff,
+	0xea, 0xce, 0xdd, 0x00, 0x01, 0x6b, 0x68, 0xe8, 0xdb, 0x50, 0x6c, 0x39, 0x76, 0x83, 0x32, 0xaf,
+	0xea, 0x90, 0x1d, 0xa5, 0x27, 0x69, 0x53, 0x5b, 0x73, 0x07, 0xfb, 0x8b, 0xb3, 0xeb, 0x12, 0xa6,
+	0xe2, 0xb4, 0x3b, 0x2d, 0xea, 0xc9, 0x2f, 0x73, 0xb0, 0x0e, 0x2e, 0x5e, 0xb5, 0x83, 0xb2, 0x83,
+	0x27, 0xf5, 0x55, 0x3b, 0xac, 0x97, 0x38, 0xe6, 0x57, 0xed, 0x48, 0x21, 0xc6, 0x21, 0xaf, 0xda,
+	0x41, 0xdf, 0x27, 0xf6, 0x55, 0x3b, 0x98, 0x61, 0x9f, 0xc8, 0xec, 0x7f, 0x33, 0xda, 0x2a, 0xa2,
+	0xd1, 0x59, 0xe6, 0x31, 0xd1, 0xd9, 0x07, 0x30, 0x66, 0xd9, 0x1e, 0x75, 0x77, 0x49, 0x4b, 0xa5,
+	0xa6, 0xd3, 0x9e, 0xc5, 0x60, 0xa9, 0x6b, 0x0a, 0x07, 0x07, 0x88, 0xa8, 0x05, 0xe7, 0xfc, 0xa7,
+	0x1c, 0x97, 0x92, 0xf0, 0xb1, 0x59, 0x95, 0x61, 0xbe, 0xee, 0xbf, 0x39, 0xdc, 0x48, 0xea, 0xf4,
+	0xa8, 0x1f, 0x01, 0x27, 0x83, 0x22, 0x06, 0x13, 0x4c, 0x4b, 0x4b, 0xf8, 0x37, 0xe2, 0x80, 0xcf,
+	0x60, 0xf1, 0x4c, 0x8e, 0x56, 0xbb, 0xa9, 0x83, 0xe2, 0x28, 0x0f, 0xf3, 0x13, 0x03, 0x26, 0xa3,
+	0x25, 0x3f, 0x3f, 0xf5, 0x10, 0xe9, 0x87, 0x59, 0x98, 0x8a, 0x1d, 0xfe, 0x58, 0x98, 0x54, 0x38,
+	0xcd, 0x30, 0x29, 0x3f, 0x54, 0x98, 0x94, 0xec, 0xc1, 0x8f, 0x0c, 0xe5, 0xc1, 0x5f, 0x95, 0x5e,
+	0xb4, 0x3a, 0x4c, 0x6b, 0xab, 0xea, 0x63, 0xa3, 0x60, 0x83, 0xd7, 0x75, 0x22, 0x8e, 0xf6, 0x15,
+	0x1e, 0x4e, 0xbd, 0xf7, 0x47, 0x65, 0x54, 0x08, 0xf0, 0x66, 0xda, 0xf2, 0xe9, 0x00, 0x40, 0x7a,
+	0x38, 0x09, 0x04, 0x9c, 0xc4, 0xae, 0x7c, 0xfb, 0xf3, 0xaf, 0x16, 0xce, 0x7c, 0xf1, 0xd5, 0xc2,
+	0x99, 0x2f, 0xbf, 0x5a, 0x38, 0xf3, 0xf1, 0xc1, 0x82, 0xf1, 0xf9, 0xc1, 0x82, 0xf1, 0xc5, 0xc1,
+	0x82, 0xf1, 0xe5, 0xc1, 0x82, 0xf1, 0xe3, 0x83, 0x05, 0xe3, 0x93, 0x9f, 0x2c, 0x9c, 0xb9, 0xf7,
+	0xfc, 0x20, 0x3f, 0x45, 0xf9, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0xee, 0x12, 0xe4, 0x1c, 0xb1,
+	0x52, 0x00, 0x00,
 }
 
 func (m *AnalysisRunArgument) Marshal() (dAtA []byte, err error) {
@@ -20009,7 +20009,7 @@ func (m *StepExecutionMetadata) Unmarshal(dAtA []byte) error {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			m.Status = PromotionPhase(dAtA[iNdEx:postIndex])
+			m.Status = PromotionStepStatus(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
 		case 6:
 			if wireType != 2 {
diff --git a/api/v1alpha1/promotion_types.go b/api/v1alpha1/promotion_types.go
index 1f8ba97e..8bcf2b14 100644
--- a/api/v1alpha1/promotion_types.go
+++ b/api/v1alpha1/promotion_types.go
@@ -25,7 +25,8 @@ const (
 	// PromotionPhaseSucceeded denotes a Promotion that has been successfully
 	// executed.
 	PromotionPhaseSucceeded PromotionPhase = "Succeeded"
-	// PromotionPhaseFailed denotes a Promotion that has failed
+	// PromotionPhaseFailed denotes a Promotion that has failed, usually for
+	// non-technical reasons.
 	PromotionPhaseFailed PromotionPhase = "Failed"
 	// PromotionPhaseErrored denotes a Promotion that has failed for technical
 	// reasons. Further information about the failure can be found in the
@@ -36,6 +37,33 @@ const (
 	PromotionPhaseAborted PromotionPhase = "Aborted"
 )
 
+type PromotionStepStatus string
+
+const (
+	// PromotionStepStatusRunning denotes a PromotionStep that is currently
+	// "running." This does not necessarily indicate that the step is ACTIVELY
+	// running, but rather that it has not yet completed. It may, for instance, be
+	// waiting on some external event to occur and will check again on the next
+	// reconciliation attempt.
+	PromotionStepStatusRunning PromotionStepStatus = "Running"
+	// PromotionStepStatusSucceeded denotes a PromotionStep that has completed
+	// successfully.
+	PromotionStepStatusSucceeded PromotionStepStatus = "Succeeded"
+	// PromotionStepStatusFailed denotes a PromotionStep that has failed, usually
+	// for non-technical reasons.
+	PromotionStepStatusFailed PromotionStepStatus = "Failed"
+	// PromotionStepStatusErrored denotes a Promotion that has failed for technical
+	// reasons. Further information about the failure can be found in the
+	// Promotion's status.
+	PromotionStepStatusErrored PromotionStepStatus = "Errored"
+	// PromotionStepStatusAborted denotes a PromotionStep that was aborted because
+	// the Promotion to which it belongs was aborted.
+	PromotionStepStatusAborted PromotionStepStatus = "Aborted"
+	// PromotionStepStatusSkipped denotes a PromotionStep that was skipped for any
+	// reason and immediately yielded execution to the next PromotionStep.
+	PromotionStepStatusSkipped PromotionStepStatus = "Skipped"
+)
+
 // IsTerminal returns true if the PromotionPhase is a terminal one.
 func (p *PromotionPhase) IsTerminal() bool {
 	switch *p {
@@ -335,7 +363,7 @@ type StepExecutionMetadata struct {
 	// ErrorCount tracks consecutive failed attempts to execute the step.
 	ErrorCount uint32 `json:"errorCount,omitempty" protobuf:"varint,4,opt,name=errorCount"`
 	// Status is the high-level outcome of the step.
-	Status PromotionPhase `json:"status,omitempty" protobuf:"bytes,5,opt,name=status"`
+	Status PromotionStepStatus `json:"status,omitempty" protobuf:"bytes,5,opt,name=status"`
 	// Message is a display message about the step, including any errors.
 	Message string `json:"message,omitempty" protobuf:"bytes,6,opt,name=message"`
 }
diff --git a/internal/controller/promotions/promotions.go b/internal/controller/promotions/promotions.go
index 733e6021..c16c6778 100644
--- a/internal/controller/promotions/promotions.go
+++ b/internal/controller/promotions/promotions.go
@@ -619,13 +619,24 @@ func (r *reconciler) terminatePromotion(
 	}
 
 	newStatus := promo.Status.DeepCopy()
+
+	now := &metav1.Time{Time: time.Now()}
+
+	// If a step was running, mark the step as aborted.
+	if newStatus.Phase == kargoapi.PromotionPhaseRunning &&
+		int64(len(newStatus.StepExecutionMetadata)) == promo.Status.CurrentStep+1 &&
+		promo.Status.StepExecutionMetadata[promo.Status.CurrentStep].Status == kargoapi.PromotionStepStatusRunning {
+		newStatus.StepExecutionMetadata[promo.Status.CurrentStep].Status = kargoapi.PromotionStepStatusAborted
+		newStatus.StepExecutionMetadata[promo.Status.CurrentStep].FinishedAt = now
+	}
+
 	newStatus.Phase = kargoapi.PromotionPhaseAborted
 	if actor != "" {
 		newStatus.Message = fmt.Sprintf("Promotion terminated by %s", actor)
 	} else {
 		newStatus.Message = "Promotion terminated per user request"
 	}
-	newStatus.FinishedAt = &metav1.Time{Time: time.Now()}
+	newStatus.FinishedAt = now
 
 	if err := kubeclient.PatchStatus(ctx, r.kargoClient, promo, func(status *kargoapi.PromotionStatus) {
 		*status = *newStatus
diff --git a/internal/promotion/runner/builtin/argocd_updater.go b/internal/promotion/runner/builtin/argocd_updater.go
index d3d65304..ac1837f4 100644
--- a/internal/promotion/runner/builtin/argocd_updater.go
+++ b/internal/promotion/runner/builtin/argocd_updater.go
@@ -124,11 +124,11 @@ func (a *argocdUpdater) Run(
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
 	if err := a.validate(stepCtx.Config); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 	cfg, err := promotion.ConfigToStruct[builtin.ArgoCDUpdateConfig](stepCtx.Config)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not convert config into %s config: %w", a.Name(), err)
 	}
 	return a.run(ctx, stepCtx, cfg)
@@ -146,7 +146,7 @@ func (a *argocdUpdater) run(
 	stepCfg builtin.ArgoCDUpdateConfig,
 ) (promotion.StepResult, error) {
 	if a.argocdClient == nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, errors.New(
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, errors.New(
 			"Argo CD integration is disabled on this controller; cannot update " +
 				"Argo CD Application resources",
 		)
@@ -169,7 +169,7 @@ func (a *argocdUpdater) run(
 		}
 		app, err := a.getAuthorizedApplicationFn(ctx, stepCtx, appKey)
 		if err != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 				"error getting Argo CD Application %q in namespace %q: %w",
 				appKey.Name, appKey.Namespace, err,
 			)
@@ -197,7 +197,7 @@ func (a *argocdUpdater) run(
 				if phase == "" {
 					// If we do not have a phase, we cannot continue processing
 					// this update by waiting.
-					return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+					return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 				}
 				// Log the error as a warning, but continue to the next update.
 				logger.Info(err.Error())
@@ -205,7 +205,7 @@ func (a *argocdUpdater) run(
 			if phase.Failed() {
 				// Record the reason for the failure if available.
 				if app.Status.OperationState != nil {
-					return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+					return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 						"Argo CD Application %q in namespace %q failed with: %s",
 						app.Name,
 						app.Namespace,
@@ -214,7 +214,7 @@ func (a *argocdUpdater) run(
 				}
 				// If the update failed, we can short-circuit. This is
 				// effectively "fail fast" behavior.
-				return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, nil
+				return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, nil
 			}
 			// If we get here, we can continue to the next update.
 			continue
@@ -233,7 +233,7 @@ func (a *argocdUpdater) run(
 			app,
 		)
 		if err != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 				"error building desired sources for Argo CD Application %q in namespace %q: %w",
 				app.Name, app.Namespace, err,
 			)
@@ -246,7 +246,7 @@ func (a *argocdUpdater) run(
 			app,
 			desiredSources,
 		); err != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 				"error syncing Argo CD Application %q in namespace %q: %w",
 				app.Name, app.Namespace, err,
 			)
@@ -255,9 +255,9 @@ func (a *argocdUpdater) run(
 		updateResults = append(updateResults, argocd.OperationRunning)
 	}
 
-	aggregatedStatus := a.operationPhaseToPromotionStatus(updateResults...)
+	aggregatedStatus := a.operationPhaseToPromotionStepStatus(updateResults...)
 	if aggregatedStatus == "" {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 			"could not determine promotion step status from operation phases: %v",
 			updateResults,
 		)
@@ -794,9 +794,9 @@ func (a *argocdUpdater) buildHelmParamChangesForAppSource(
 	return changes
 }
 
-func (a *argocdUpdater) operationPhaseToPromotionStatus(
+func (a *argocdUpdater) operationPhaseToPromotionStepStatus(
 	phases ...argocd.OperationPhase,
-) kargoapi.PromotionPhase {
+) kargoapi.PromotionStepStatus {
 	if len(phases) == 0 {
 		return ""
 	}
@@ -805,11 +805,11 @@ func (a *argocdUpdater) operationPhaseToPromotionStatus(
 
 	switch phases[0] {
 	case argocd.OperationRunning, argocd.OperationTerminating:
-		return kargoapi.PromotionPhaseRunning
+		return kargoapi.PromotionStepStatusRunning
 	case argocd.OperationFailed, argocd.OperationError:
-		return kargoapi.PromotionPhaseErrored
+		return kargoapi.PromotionStepStatusErrored
 	case argocd.OperationSucceeded:
-		return kargoapi.PromotionPhaseSucceeded
+		return kargoapi.PromotionStepStatusSucceeded
 	default:
 		return ""
 	}
diff --git a/internal/promotion/runner/builtin/file_copier.go b/internal/promotion/runner/builtin/file_copier.go
index 4dbd2edd..20bb1edc 100644
--- a/internal/promotion/runner/builtin/file_copier.go
+++ b/internal/promotion/runner/builtin/file_copier.go
@@ -51,13 +51,13 @@ func (f *fileCopier) Run(
 ) (promotion.StepResult, error) {
 	// Validate the configuration against the JSON Schema.
 	if err := validate(f.schemaLoader, gojsonschema.NewGoLoader(stepCtx.Config), f.Name()); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 
 	// Convert the configuration into a typed object.
 	cfg, err := promotion.ConfigToStruct[builtin.CopyConfig](stepCtx.Config)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not convert config into %s config: %w", f.Name(), err)
 	}
 
@@ -72,19 +72,19 @@ func (f *fileCopier) run(
 	// Secure join the paths to prevent path traversal attacks.
 	inPath, err := securejoin.SecureJoin(stepCtx.WorkDir, cfg.InPath)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not secure join inPath %q: %w", cfg.InPath, err)
 	}
 	outPath, err := securejoin.SecureJoin(stepCtx.WorkDir, cfg.OutPath)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not secure join outPath %q: %w", cfg.OutPath, err)
 	}
 
 	// Load the ignore rules.
 	matcher, err := f.loadIgnoreRules(inPath, cfg.Ignore)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("failed to load ignore rules: %w", err)
 	}
 
@@ -102,10 +102,10 @@ func (f *fileCopier) run(
 		},
 	}
 	if err = copy.Copy(inPath, outPath, opts); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("failed to copy %q to %q: %w", cfg.InPath, cfg.OutPath, err)
 	}
-	return promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, nil
+	return promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, nil
 }
 
 // loadIgnoreRules loads the ignore rules from the given string. The rules are
diff --git a/internal/promotion/runner/builtin/file_deleter.go b/internal/promotion/runner/builtin/file_deleter.go
index 229eb9b8..298a02d4 100644
--- a/internal/promotion/runner/builtin/file_deleter.go
+++ b/internal/promotion/runner/builtin/file_deleter.go
@@ -42,13 +42,13 @@ func (f *fileDeleter) Run(
 ) (promotion.StepResult, error) {
 	// Validate the configuration against the JSON Schema.
 	if err := validate(f.schemaLoader, gojsonschema.NewGoLoader(stepCtx.Config), f.Name()); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 
 	// Convert the configuration into a typed object.
 	cfg, err := promotion.ConfigToStruct[builtin.DeleteConfig](stepCtx.Config)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not convert config into %s config: %w", f.Name(), err)
 	}
 
@@ -62,24 +62,24 @@ func (f *fileDeleter) run(
 ) (promotion.StepResult, error) {
 	absPath, err := f.resolveAbsPath(stepCtx.WorkDir, cfg.Path)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not secure join path %q: %w", cfg.Path, err)
 	}
 
 	symlink, err := f.isSymlink(absPath)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 
 	if symlink {
 		if f.ignoreNotExist(cfg.Strict, os.Remove(absPath)) != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 		}
 	} else {
 		// Secure join the paths to prevent path traversal.
 		pathToDelete, err := securejoin.SecureJoin(stepCtx.WorkDir, cfg.Path)
 		if err != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 				fmt.Errorf("could not secure join path %q: %w", cfg.Path, err)
 		}
 
@@ -87,12 +87,12 @@ func (f *fileDeleter) run(
 			cfg.Strict,
 			removePath(pathToDelete),
 		); err != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 				fmt.Errorf("failed to delete %q: %w", cfg.Path, sanitizePathError(err, stepCtx.WorkDir))
 		}
 	}
 
-	return promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, nil
+	return promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, nil
 }
 
 // isSymlink checks if a path is a symlink.
diff --git a/internal/promotion/runner/builtin/git_cloner.go b/internal/promotion/runner/builtin/git_cloner.go
index 6e386141..edc07ba1 100644
--- a/internal/promotion/runner/builtin/git_cloner.go
+++ b/internal/promotion/runner/builtin/git_cloner.go
@@ -65,11 +65,11 @@ func (g *gitCloner) Run(
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
 	if err := g.validate(stepCtx.Config); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 	cfg, err := promotion.ConfigToStruct[builtin.GitCloneConfig](stepCtx.Config)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not convert config into %s config: %w", g.Name(), err)
 	}
 	return g.run(ctx, stepCtx, cfg)
@@ -93,7 +93,7 @@ func (g *gitCloner) run(
 		cfg.RepoURL,
 	)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error getting credentials for %s: %w", cfg.RepoURL, err)
 	}
 	if creds != nil {
@@ -115,7 +115,7 @@ func (g *gitCloner) run(
 		},
 	)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error cloning %s: %w", cfg.RepoURL, err)
 	}
 	for _, checkout := range cfg.Checkout {
@@ -124,7 +124,7 @@ func (g *gitCloner) run(
 		case checkout.Branch != "":
 			ref = checkout.Branch
 			if err = ensureRemoteBranch(repo, ref, checkout.Create); err != nil {
-				return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+				return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 					fmt.Errorf("error ensuring existence of remote branch %s: %w", ref, err)
 			}
 		case checkout.Commit != "":
@@ -134,7 +134,7 @@ func (g *gitCloner) run(
 		}
 		path, err := securejoin.SecureJoin(stepCtx.WorkDir, checkout.Path)
 		if err != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 				"error joining path %s with work dir %s: %w",
 				checkout.Path, stepCtx.WorkDir, err,
 			)
@@ -143,7 +143,7 @@ func (g *gitCloner) run(
 			path,
 			&git.AddWorkTreeOptions{Ref: ref},
 		); err != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 				"error adding work tree %s to repo %s: %w",
 				checkout.Path, cfg.RepoURL, err,
 			)
@@ -152,7 +152,7 @@ func (g *gitCloner) run(
 	// Note: We do NOT defer repo.Close() because we want to keep the repository
 	// around on the FS for subsequent promotion steps to use. The Engine will
 	// handle all work dir cleanup.
-	return promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, nil
+	return promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, nil
 }
 
 // ensureRemoteBranch checks for the existence of a remote branch. If the remote
diff --git a/internal/promotion/runner/builtin/git_commiter.go b/internal/promotion/runner/builtin/git_commiter.go
index d5b907b8..b8aecffd 100644
--- a/internal/promotion/runner/builtin/git_commiter.go
+++ b/internal/promotion/runner/builtin/git_commiter.go
@@ -41,11 +41,11 @@ func (g *gitCommitter) Run(
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
 	if err := g.validate(stepCtx.Config); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 	cfg, err := promotion.ConfigToStruct[builtin.GitCommitConfig](stepCtx.Config)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not convert config into %s config: %w", g.Name(), err)
 	}
 	return g.run(ctx, stepCtx, cfg)
@@ -63,23 +63,23 @@ func (g *gitCommitter) run(
 ) (promotion.StepResult, error) {
 	path, err := securejoin.SecureJoin(stepCtx.WorkDir, cfg.Path)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 			"error joining path %s with work dir %s: %w",
 			cfg.Path, stepCtx.WorkDir, err,
 		)
 	}
 	workTree, err := git.LoadWorkTree(path, nil)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error loading working tree from %s: %w", cfg.Path, err)
 	}
 	if err = workTree.AddAll(); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error adding all changes to working tree: %w", err)
 	}
 	hasDiffs, err := workTree.HasDiffs()
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error checking for diffs in working tree: %w", err)
 	}
 	if hasDiffs {
@@ -94,17 +94,17 @@ func (g *gitCommitter) run(
 			}
 		}
 		if err = workTree.Commit(cfg.Message, commitOpts); err != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 				fmt.Errorf("error committing to working tree: %w", err)
 		}
 	}
 	commitID, err := workTree.LastCommitID()
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error getting last commit ID: %w", err)
 	}
 	return promotion.StepResult{
-		Status: kargoapi.PromotionPhaseSucceeded,
+		Status: kargoapi.PromotionStepStatusSucceeded,
 		Output: map[string]any{stateKeyCommit: commitID},
 	}, nil
 }
diff --git a/internal/promotion/runner/builtin/git_pr_opener.go b/internal/promotion/runner/builtin/git_pr_opener.go
index 9e59ae3d..90901d29 100644
--- a/internal/promotion/runner/builtin/git_pr_opener.go
+++ b/internal/promotion/runner/builtin/git_pr_opener.go
@@ -16,15 +16,15 @@ import (
 	"github.com/akuity/kargo/pkg/promotion"
 	"github.com/akuity/kargo/pkg/x/promotion/runner/builtin"
 
-	_ "github.com/akuity/kargo/internal/gitprovider/azure"  // Azure provider registration
+	_ "github.com/akuity/kargo/internal/gitprovider/azure"     // Azure provider registration
 	_ "github.com/akuity/kargo/internal/gitprovider/bitbucket" // Bitbucket provider registration
-	_ "github.com/akuity/kargo/internal/gitprovider/gitea"  // Gitea provider registration
-	_ "github.com/akuity/kargo/internal/gitprovider/github" // GitHub provider registration
-	_ "github.com/akuity/kargo/internal/gitprovider/gitlab" // GitLab provider registration
+	_ "github.com/akuity/kargo/internal/gitprovider/gitea"     // Gitea provider registration
+	_ "github.com/akuity/kargo/internal/gitprovider/github"    // GitHub provider registration
+	_ "github.com/akuity/kargo/internal/gitprovider/gitlab"    // GitLab provider registration
 )
 
 // stateKeyPRNumber is the key used to store the PR number in the shared State.
-// 
+//
 // Deprecated: Use `pr.id` instead.
 //
 // TODO: Remove in v1.7.0
@@ -58,11 +58,11 @@ func (g *gitPROpener) Run(
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
 	if err := g.validate(stepCtx.Config); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 	cfg, err := promotion.ConfigToStruct[builtin.GitOpenPRConfig](stepCtx.Config)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not convert config into git-open-pr config: %w", err)
 	}
 	return g.run(ctx, stepCtx, cfg)
@@ -88,7 +88,7 @@ func (g *gitPROpener) run(
 		cfg.RepoURL,
 	)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error getting credentials for %s: %w", cfg.RepoURL, err)
 	}
 	if creds != nil {
@@ -111,7 +111,7 @@ func (g *gitPROpener) run(
 		},
 	)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error cloning %s: %w", cfg.RepoURL, err)
 	}
 	defer repo.Close()
@@ -127,7 +127,7 @@ func (g *gitPROpener) run(
 	}
 	gitProvider, err := gitprovider.New(cfg.RepoURL, gpOpts)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error creating git provider service: %w", err)
 	}
 
@@ -140,13 +140,13 @@ func (g *gitPROpener) run(
 		cfg.TargetBranch,
 	)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error determining if pull request already exists: %w", err)
 	}
 
 	if pr != nil && (pr.Open || pr.Merged) { // Excludes PR that is both closed AND unmerged
 		return promotion.StepResult{
-			Status: kargoapi.PromotionPhaseSucceeded,
+			Status: kargoapi.PromotionStepStatusSucceeded,
 			Output: map[string]any{
 				"pr": map[string]any{
 					"id":  pr.Number,
@@ -166,7 +166,7 @@ func (g *gitPROpener) run(
 	// that may involve creating a new branch and committing to it.
 	commitMsg, err := repo.CommitMessage(sourceBranch)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 			"error getting commit message from head of branch %s: %w",
 			sourceBranch, err,
 		)
@@ -177,7 +177,7 @@ func (g *gitPROpener) run(
 		cfg.TargetBranch,
 		cfg.CreateTargetBranch,
 	); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 			"error ensuring existence of remote branch %s: %w",
 			cfg.TargetBranch, err,
 		)
@@ -210,11 +210,11 @@ func (g *gitPROpener) run(
 			Labels:      cfg.Labels,
 		},
 	); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error creating pull request: %w", err)
 	}
 	return promotion.StepResult{
-		Status: kargoapi.PromotionPhaseSucceeded,
+		Status: kargoapi.PromotionStepStatusSucceeded,
 		Output: map[string]any{
 			"pr": map[string]any{
 				"id":  pr.Number,
diff --git a/internal/promotion/runner/builtin/git_pr_waiter.go b/internal/promotion/runner/builtin/git_pr_waiter.go
index de6146dc..0a865db0 100644
--- a/internal/promotion/runner/builtin/git_pr_waiter.go
+++ b/internal/promotion/runner/builtin/git_pr_waiter.go
@@ -49,11 +49,11 @@ func (g *gitPRWaiter) Run(
 	stepCtx *promoPkg.StepContext,
 ) (promoPkg.StepResult, error) {
 	if err := g.validate(stepCtx.Config); err != nil {
-		return promoPkg.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promoPkg.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 	cfg, err := promoPkg.ConfigToStruct[builtin.GitWaitForPRConfig](stepCtx.Config)
 	if err != nil {
-		return promoPkg.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promoPkg.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not convert config into git-wait-for-pr config: %w", err)
 	}
 	return g.run(ctx, stepCtx, cfg)
@@ -77,7 +77,7 @@ func (g *gitPRWaiter) run(
 		cfg.RepoURL,
 	)
 	if err != nil {
-		return promoPkg.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promoPkg.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error getting credentials for %s: %w", cfg.RepoURL, err)
 	}
 	if creds != nil {
@@ -99,25 +99,25 @@ func (g *gitPRWaiter) run(
 	}
 	gitProv, err := gitprovider.New(cfg.RepoURL, gpOpts)
 	if err != nil {
-		return promoPkg.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promoPkg.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error creating git provider service: %w", err)
 	}
 
 	pr, err := gitProv.GetPullRequest(ctx, cfg.PRNumber)
 	if err != nil {
-		return promoPkg.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promoPkg.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error getting pull request %d: %w", cfg.PRNumber, err)
 	}
 
 	if pr.Open {
-		return promoPkg.StepResult{Status: kargoapi.PromotionPhaseRunning}, nil
+		return promoPkg.StepResult{Status: kargoapi.PromotionStepStatusRunning}, nil
 	}
 	if !pr.Merged {
-		return promoPkg.StepResult{Status: kargoapi.PromotionPhaseFailed},
+		return promoPkg.StepResult{Status: kargoapi.PromotionStepStatusFailed},
 			&promotion.TerminalError{Err: fmt.Errorf("pull request %d was closed without being merged", cfg.PRNumber)}
 	}
 	return promoPkg.StepResult{
-		Status: kargoapi.PromotionPhaseSucceeded,
+		Status: kargoapi.PromotionStepStatusSucceeded,
 		Output: map[string]any{stateKeyCommit: pr.MergeCommitSHA},
 	}, nil
 }
diff --git a/internal/promotion/runner/builtin/git_pusher.go b/internal/promotion/runner/builtin/git_pusher.go
index 3f774d98..6fc0f2d4 100644
--- a/internal/promotion/runner/builtin/git_pusher.go
+++ b/internal/promotion/runner/builtin/git_pusher.go
@@ -53,11 +53,11 @@ func (g *gitPushPusher) Run(
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
 	if err := g.validate(stepCtx.Config); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 	cfg, err := promotion.ConfigToStruct[builtin.GitPushConfig](stepCtx.Config)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not convert config into git-push config: %w", err)
 	}
 	return g.run(ctx, stepCtx, cfg)
@@ -78,7 +78,7 @@ func (g *gitPushPusher) run(
 	// credentials and, if found, reload the work tree with the credentials.
 	path, err := securejoin.SecureJoin(stepCtx.WorkDir, cfg.Path)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 			"error joining path %s with work dir %s: %w",
 			cfg.Path, stepCtx.WorkDir, err,
 		)
@@ -86,7 +86,7 @@ func (g *gitPushPusher) run(
 	loadOpts := &git.LoadWorkTreeOptions{}
 	workTree, err := git.LoadWorkTree(path, loadOpts)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error loading working tree from %s: %w", cfg.Path, err)
 	}
 	creds, err := g.credsDB.Get(
@@ -96,7 +96,7 @@ func (g *gitPushPusher) run(
 		workTree.URL(),
 	)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error getting credentials for %s: %w", workTree.URL(), err)
 	}
 	if creds != nil {
@@ -107,7 +107,7 @@ func (g *gitPushPusher) run(
 		}
 	}
 	if workTree, err = git.LoadWorkTree(path, loadOpts); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error loading working tree from %s: %w", cfg.Path, err)
 	}
 	pushOpts := &git.PushOptions{
@@ -129,7 +129,7 @@ func (g *gitPushPusher) run(
 		// because we will want to return the branch that was pushed to, but we
 		// don't want to mess with the options any further.
 		if pushOpts.TargetBranch, err = workTree.CurrentBranch(); err != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 				fmt.Errorf("error getting current branch: %w", err)
 		}
 	}
@@ -169,20 +169,20 @@ func (g *gitPushPusher) run(
 		if git.IsMergeConflict(err) {
 			// Special case: A merge conflict requires manual resolution and no amount
 			// of retries will fix that.
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseFailed},
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusFailed},
 				&promotion.TerminalError{Err: err}
 		}
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error pushing commits to remote: %w", err)
 	}
 
 	commitID, err := workTree.LastCommitID()
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error getting last commit ID: %w", err)
 	}
 	return promotion.StepResult{
-		Status: kargoapi.PromotionPhaseSucceeded,
+		Status: kargoapi.PromotionStepStatusSucceeded,
 		Output: map[string]any{
 			stateKeyBranch: pushOpts.TargetBranch,
 			stateKeyCommit: commitID,
diff --git a/internal/promotion/runner/builtin/git_tree_clearer.go b/internal/promotion/runner/builtin/git_tree_clearer.go
index bf90e5ea..037a6ce4 100644
--- a/internal/promotion/runner/builtin/git_tree_clearer.go
+++ b/internal/promotion/runner/builtin/git_tree_clearer.go
@@ -38,11 +38,11 @@ func (g *gitTreeClearer) Run(
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
 	if err := g.validate(stepCtx.Config); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 	cfg, err := promotion.ConfigToStruct[builtin.GitClearConfig](stepCtx.Config)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not convert config into %s config: %w", g.Name(), err)
 	}
 	return g.run(ctx, stepCtx, cfg)
@@ -60,26 +60,26 @@ func (g *gitTreeClearer) run(
 ) (promotion.StepResult, error) {
 	p, err := securejoin.SecureJoin(stepCtx.WorkDir, cfg.Path)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 			"error joining path %s with work dir %s: %w",
 			cfg.Path, stepCtx.WorkDir, err,
 		)
 	}
 	workTree, err := git.LoadWorkTree(p, nil)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error loading working tree from %s: %w", cfg.Path, err)
 	}
 	// workTree.Clear() won't remove any files that aren't indexed. This is a bit
 	// of a hack to ensure that we don't have any untracked files in the working
 	// tree so that workTree.Clear() will remove everything.
 	if err = workTree.AddAll(); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error adding all files to working tree at %s: %w", cfg.Path, err)
 	}
 	if err = workTree.Clear(); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error clearing working tree at %s: %w", cfg.Path, err)
 	}
-	return promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, nil
+	return promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, nil
 }
diff --git a/internal/promotion/runner/builtin/helm_chart_updater.go b/internal/promotion/runner/builtin/helm_chart_updater.go
index b1edfb9b..7aad0d99 100644
--- a/internal/promotion/runner/builtin/helm_chart_updater.go
+++ b/internal/promotion/runner/builtin/helm_chart_updater.go
@@ -58,7 +58,7 @@ func (h *helmChartUpdater) Run(
 	ctx context.Context,
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
-	failure := promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}
+	failure := promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}
 
 	if err := h.validate(stepCtx.Config); err != nil {
 		return failure, err
@@ -85,7 +85,7 @@ func (h *helmChartUpdater) run(
 ) (promotion.StepResult, error) {
 	absChartPath, err := securejoin.SecureJoin(stepCtx.WorkDir, cfg.Path)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("failed to join path %q: %w", cfg.Path, err)
 	}
 
@@ -93,34 +93,34 @@ func (h *helmChartUpdater) run(
 	chartDependencies, err := readChartDependencies(chartFilePath)
 	if err != nil {
 		return promotion.StepResult{
-			Status: kargoapi.PromotionPhaseErrored,
+			Status: kargoapi.PromotionStepStatusErrored,
 		}, fmt.Errorf("failed to load chart dependencies from %q: %w", chartFilePath, err)
 	}
 
 	changes, err := h.processChartUpdates(cfg, chartDependencies)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 
 	if err = intyaml.SetStringsInFile(chartFilePath, changes); err != nil {
 		return promotion.StepResult{
-			Status: kargoapi.PromotionPhaseErrored,
+			Status: kargoapi.PromotionStepStatusErrored,
 		}, fmt.Errorf("failed to update chart dependencies in %q: %w", chartFilePath, err)
 	}
 
 	helmHome, err := os.MkdirTemp("", "helm-chart-update-")
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("failed to create temporary Helm home directory: %w", err)
 	}
 	defer os.RemoveAll(helmHome)
 
 	newVersions, err := h.updateDependencies(ctx, stepCtx, helmHome, absChartPath, chartDependencies)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 
-	result := promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}
+	result := promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}
 	if commitMsg := h.generateCommitMessage(cfg.Path, newVersions); commitMsg != "" {
 		result.Output = map[string]any{
 			"commitMessage": commitMsg,
diff --git a/internal/promotion/runner/builtin/helm_template_runner.go b/internal/promotion/runner/builtin/helm_template_runner.go
index 4b7dc256..9c7ef7ac 100644
--- a/internal/promotion/runner/builtin/helm_template_runner.go
+++ b/internal/promotion/runner/builtin/helm_template_runner.go
@@ -56,7 +56,7 @@ func (h *helmTemplateRunner) Run(
 	ctx context.Context,
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
-	failure := promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}
+	failure := promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}
 
 	// Validate the configuration against the JSON Schema
 	if err := validate(
@@ -83,44 +83,44 @@ func (h *helmTemplateRunner) run(
 ) (promotion.StepResult, error) {
 	composedValues, err := h.composeValues(stepCtx.WorkDir, cfg)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("failed to compose values: %w", err)
 	}
 
 	chartRequested, err := h.loadChart(stepCtx.WorkDir, cfg.Path)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("failed to load chart from %q: %w", cfg.Path, err)
 	}
 
 	if err = h.checkDependencies(chartRequested); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("missing chart dependencies: %w", err)
 	}
 
 	absOutPath, err := securejoin.SecureJoin(stepCtx.WorkDir, cfg.OutPath)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("failed to join path %q: %w", cfg.OutPath, err)
 	}
 
 	install, err := h.newInstallAction(cfg, stepCtx.Project, absOutPath)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("failed to initialize Helm action config: %w", err)
 	}
 
 	rls, err := install.RunWithContext(ctx, chartRequested, composedValues)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("failed to render chart: %w", err)
 	}
 
 	if err = h.writeOutput(cfg, rls, absOutPath); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("failed to write rendered chart: %w", err)
 	}
-	return promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, nil
+	return promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, nil
 }
 
 // composeValues composes the values from the given values files and set values.
diff --git a/internal/promotion/runner/builtin/http_requester.go b/internal/promotion/runner/builtin/http_requester.go
index 77233f4d..71183011 100644
--- a/internal/promotion/runner/builtin/http_requester.go
+++ b/internal/promotion/runner/builtin/http_requester.go
@@ -51,11 +51,11 @@ func (h *httpRequester) Run(
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
 	if err := h.validate(stepCtx.Config); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 	cfg, err := promotion.ConfigToStruct[builtin.HTTPConfig](stepCtx.Config)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not convert config into http config: %w", err)
 	}
 	return h.run(ctx, stepCtx, cfg)
@@ -73,54 +73,54 @@ func (h *httpRequester) run(
 ) (promotion.StepResult, error) {
 	req, err := h.buildRequest(cfg)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error building HTTP request: %w", err)
 	}
 	client, err := h.getClient(cfg)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error creating HTTP client: %w", err)
 	}
 	resp, err := client.Do(req)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error sending HTTP request: %w", err)
 	}
 	defer resp.Body.Close()
 	env, err := h.buildExprEnv(ctx, resp)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error building expression context from HTTP response: %w", err)
 	}
 	success, err := h.wasRequestSuccessful(cfg, resp.StatusCode, env)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error evaluating success criteria: %w", err)
 	}
 	failure, err := h.didRequestFail(cfg, resp.StatusCode, env)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("error evaluating failure criteria: %w", err)
 	}
 	switch {
 	case success && !failure:
 		outputs, err := h.buildOutputs(cfg.Outputs, env)
 		if err != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 				fmt.Errorf("error extracting outputs from HTTP response: %w", err)
 		}
 		return promotion.StepResult{
-			Status: kargoapi.PromotionPhaseSucceeded,
+			Status: kargoapi.PromotionStepStatusSucceeded,
 			Output: outputs,
 		}, nil
 	case failure:
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseFailed},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusFailed},
 			&promotion.TerminalError{Err: fmt.Errorf(
 				"HTTP (%d) response met failure criteria",
 				resp.StatusCode,
 			)}
 	default:
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseRunning}, nil
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusRunning}, nil
 	}
 }
 
diff --git a/internal/promotion/runner/builtin/json_parser.go b/internal/promotion/runner/builtin/json_parser.go
index 3cdd0981..cae2e4ff 100644
--- a/internal/promotion/runner/builtin/json_parser.go
+++ b/internal/promotion/runner/builtin/json_parser.go
@@ -38,7 +38,7 @@ func (jp *jsonParser) Run(
 	ctx context.Context,
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
-	failure := promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}
+	failure := promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}
 
 	if err := jp.validate(stepCtx.Config); err != nil {
 		return failure, err
@@ -62,7 +62,7 @@ func (jp *jsonParser) run(
 	stepCtx *promotion.StepContext,
 	cfg builtin.JSONParseConfig,
 ) (promotion.StepResult, error) {
-	failure := promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}
+	failure := promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}
 
 	if cfg.Path == "" {
 		return failure, fmt.Errorf("JSON file path cannot be empty")
@@ -83,7 +83,7 @@ func (jp *jsonParser) run(
 	}
 
 	return promotion.StepResult{
-		Status: kargoapi.PromotionPhaseSucceeded,
+		Status: kargoapi.PromotionStepStatusSucceeded,
 		Output: extractedValues,
 	}, nil
 }
diff --git a/internal/promotion/runner/builtin/json_updater.go b/internal/promotion/runner/builtin/json_updater.go
index bd060f15..48c0ca76 100644
--- a/internal/promotion/runner/builtin/json_updater.go
+++ b/internal/promotion/runner/builtin/json_updater.go
@@ -39,7 +39,7 @@ func (j *jsonUpdater) Run(
 	ctx context.Context,
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
-	failure := promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}
+	failure := promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}
 
 	if err := j.validate(stepCtx.Config); err != nil {
 		return failure, err
@@ -63,11 +63,11 @@ func (j *jsonUpdater) run(
 	stepCtx *promotion.StepContext,
 	cfg builtin.JSONUpdateConfig,
 ) (promotion.StepResult, error) {
-	result := promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}
+	result := promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}
 
 	if len(cfg.Updates) > 0 {
 		if err := j.updateFile(stepCtx.WorkDir, cfg.Path, cfg.Updates); err != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 				fmt.Errorf("JSON file update failed: %w", err)
 		}
 
diff --git a/internal/promotion/runner/builtin/kustomize_builder.go b/internal/promotion/runner/builtin/kustomize_builder.go
index a7afc25f..8841d3c8 100644
--- a/internal/promotion/runner/builtin/kustomize_builder.go
+++ b/internal/promotion/runner/builtin/kustomize_builder.go
@@ -52,7 +52,7 @@ func (k *kustomizeBuilder) Run(
 	_ context.Context,
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
-	failure := promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}
+	failure := promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}
 
 	// Validate the configuration against the JSON Schema.
 	if err := validate(k.schemaLoader, gojsonschema.NewGoLoader(stepCtx.Config), k.Name()); err != nil {
@@ -75,29 +75,29 @@ func (k *kustomizeBuilder) run(
 	// Create a "chrooted" filesystem for the kustomize build.
 	fs, err := securefs.MakeFsOnDiskSecureBuild(stepCtx.WorkDir)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 
 	// Build the manifests.
 	rm, err := kustomizeBuild(fs, filepath.Join(stepCtx.WorkDir, cfg.Path), cfg.Plugin)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 
 	// Prepare the output path.
 	outPath, err := securejoin.SecureJoin(stepCtx.WorkDir, cfg.OutPath)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 
 	// Write the built manifests to the output path.
 	if err := k.writeResult(rm, outPath); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, fmt.Errorf(
 			"failed to write built manifests to %q: %w", cfg.OutPath,
 			sanitizePathError(err, stepCtx.WorkDir),
 		)
 	}
-	return promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, nil
+	return promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, nil
 }
 
 func (k *kustomizeBuilder) writeResult(rm resmap.ResMap, outPath string) error {
diff --git a/internal/promotion/runner/builtin/kustomize_image_setter.go b/internal/promotion/runner/builtin/kustomize_image_setter.go
index 816a9d36..c581833a 100644
--- a/internal/promotion/runner/builtin/kustomize_image_setter.go
+++ b/internal/promotion/runner/builtin/kustomize_image_setter.go
@@ -55,7 +55,7 @@ func (k *kustomizeImageSetter) Run(
 	ctx context.Context,
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
-	failure := promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}
+	failure := promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}
 
 	if err := k.validate(stepCtx.Config); err != nil {
 		return failure, err
@@ -83,7 +83,7 @@ func (k *kustomizeImageSetter) run(
 	// Find the Kustomization file.
 	kusPath, err := findKustomization(stepCtx.WorkDir, cfg.Path)
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not discover kustomization file: %w", err)
 	}
 
@@ -97,15 +97,15 @@ func (k *kustomizeImageSetter) run(
 		targetImages, err = k.buildTargetImagesAutomatically(ctx, stepCtx)
 	}
 	if err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 
 	// Update the Kustomization file with the new images.
 	if err = updateKustomizationFile(kusPath, targetImages); err != nil {
-		return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 
-	result := promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}
+	result := promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}
 	if commitMsg := k.generateCommitMessage(cfg.Path, targetImages); commitMsg != "" {
 		result.Output = map[string]any{
 			"commitMessage": commitMsg,
diff --git a/internal/promotion/runner/builtin/output_composer.go b/internal/promotion/runner/builtin/output_composer.go
index 7755dfe3..2c958159 100644
--- a/internal/promotion/runner/builtin/output_composer.go
+++ b/internal/promotion/runner/builtin/output_composer.go
@@ -58,13 +58,13 @@ func (c *outputComposer) Run(
 ) (promoPkg.StepResult, error) {
 	// Validate the configuration against the JSON Schema.
 	if err := validate(c.schemaLoader, gojsonschema.NewGoLoader(stepCtx.Config), c.Name()); err != nil {
-		return promoPkg.StepResult{Status: kargoapi.PromotionPhaseErrored}, err
+		return promoPkg.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err
 	}
 
 	// Convert the configuration into a typed object.
 	cfg, err := promoPkg.ConfigToStruct[builtin.ComposeOutput](stepCtx.Config)
 	if err != nil {
-		return promoPkg.StepResult{Status: kargoapi.PromotionPhaseErrored},
+		return promoPkg.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 			fmt.Errorf("could not convert config into %s config: %w", c.Name(), err)
 	}
 
@@ -75,7 +75,7 @@ func (c *outputComposer) run(
 	cfg builtin.ComposeOutput,
 ) (promoPkg.StepResult, error) {
 	return promoPkg.StepResult{
-		Status: kargoapi.PromotionPhaseSucceeded,
+		Status: kargoapi.PromotionStepStatusSucceeded,
 		Output: maps.Clone(cfg),
 	}, nil
 }
diff --git a/internal/promotion/runner/builtin/yaml_parser.go b/internal/promotion/runner/builtin/yaml_parser.go
index 1dd04157..65f3d207 100644
--- a/internal/promotion/runner/builtin/yaml_parser.go
+++ b/internal/promotion/runner/builtin/yaml_parser.go
@@ -38,7 +38,7 @@ func (yp *yamlParser) Run(
 	ctx context.Context,
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
-	failure := promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}
+	failure := promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}
 
 	if err := yp.validate(stepCtx.Config); err != nil {
 		return failure, err
@@ -62,7 +62,7 @@ func (yp *yamlParser) run(
 	stepCtx *promotion.StepContext,
 	cfg builtin.YAMLParseConfig,
 ) (promotion.StepResult, error) {
-	failure := promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}
+	failure := promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}
 
 	if cfg.Path == "" {
 		return failure, fmt.Errorf("YAML file path cannot be empty")
@@ -83,7 +83,7 @@ func (yp *yamlParser) run(
 	}
 
 	return promotion.StepResult{
-		Status: kargoapi.PromotionPhaseSucceeded,
+		Status: kargoapi.PromotionStepStatusSucceeded,
 		Output: extractedValues,
 	}, nil
 }
diff --git a/internal/promotion/runner/builtin/yaml_updater.go b/internal/promotion/runner/builtin/yaml_updater.go
index 44aa0884..9950a095 100644
--- a/internal/promotion/runner/builtin/yaml_updater.go
+++ b/internal/promotion/runner/builtin/yaml_updater.go
@@ -38,7 +38,7 @@ func (y *yamlUpdater) Run(
 	ctx context.Context,
 	stepCtx *promotion.StepContext,
 ) (promotion.StepResult, error) {
-	failure := promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}
+	failure := promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}
 
 	if err := y.validate(stepCtx.Config); err != nil {
 		return failure, err
@@ -71,10 +71,10 @@ func (y *yamlUpdater) run(
 		}
 	}
 
-	result := promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}
+	result := promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}
 	if len(updates) > 0 {
 		if err := y.updateFile(stepCtx.WorkDir, cfg.Path, updates); err != nil {
-			return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+			return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 				fmt.Errorf("values file update failed: %w", err)
 		}
 
diff --git a/internal/promotion/simple_engine.go b/internal/promotion/simple_engine.go
index 9b005d76..217474e0 100644
--- a/internal/promotion/simple_engine.go
+++ b/internal/promotion/simple_engine.go
@@ -151,12 +151,7 @@ func (e *simpleEngine) executeSteps(
 				HealthChecks:          healthChecks,
 			}, fmt.Errorf("error checking if step %d should be skipped: %w", i, err)
 		} else if skip {
-			// TODO(hidde): We should probably set the status to skipped here,
-			// but this would require step specific phases (opposed to the
-			// promotion wide phases we have now). We should revisit this when
-			// we dive into the other engine related changes (e.g. improved
-			// failure handling).
-			stepExecMeta.Status = kargoapi.PromotionPhaseSucceeded
+			stepExecMeta.Status = kargoapi.PromotionStepStatusSkipped
 			continue
 		}
 
@@ -185,8 +180,9 @@ func (e *simpleEngine) executeSteps(
 		}
 
 		switch result.Status {
-		case kargoapi.PromotionPhaseErrored, kargoapi.PromotionPhaseFailed,
-			kargoapi.PromotionPhaseRunning, kargoapi.PromotionPhaseSucceeded:
+		case kargoapi.PromotionStepStatusErrored, kargoapi.PromotionStepStatusFailed,
+			kargoapi.PromotionStepStatusRunning, kargoapi.PromotionStepStatusSucceeded,
+			kargoapi.PromotionStepStatusSkipped: // Step runners can self-determine they should be skipped
 		default:
 			// Deal with statuses that no step should have returned.
 			stepExecMeta.FinishedAt = ptr.To(metav1.Now())
@@ -201,16 +197,16 @@ func (e *simpleEngine) executeSteps(
 
 		// Reconcile status and err...
 		if err != nil {
-			if stepExecMeta.Status != kargoapi.PromotionPhaseFailed {
+			if stepExecMeta.Status != kargoapi.PromotionStepStatusFailed {
 				// All states other than Errored and Failed should be mutually exclusive
 				// with a hard error. If we got to here, a step has violated this
 				// assumption. We will prioritize the error over the status and change
 				// the status to Errored.
-				stepExecMeta.Status = kargoapi.PromotionPhaseErrored
+				stepExecMeta.Status = kargoapi.PromotionStepStatusErrored
 			}
 			// Let the hard error take precedence over the message.
 			stepExecMeta.Message = err.Error()
-		} else if result.Status == kargoapi.PromotionPhaseErrored {
+		} else if result.Status == kargoapi.PromotionStepStatusErrored {
 			// A nil err should be mutually exclusive with an Errored status. If we
 			// got to here, a step has violated this assumption. We will prioritize
 			// the Errored status over the nil error and create an error.
@@ -225,7 +221,7 @@ func (e *simpleEngine) executeSteps(
 		// err.
 
 		switch {
-		case stepExecMeta.Status == kargoapi.PromotionPhaseSucceeded:
+		case stepExecMeta.Status == kargoapi.PromotionStepStatusSucceeded:
 			// Best case scenario: The step succeeded.
 			stepExecMeta.FinishedAt = ptr.To(metav1.Now())
 			if healthCheck := result.HealthCheck; healthCheck != nil {
@@ -236,7 +232,7 @@ func (e *simpleEngine) executeSteps(
 			// This is an unrecoverable error.
 			stepExecMeta.FinishedAt = ptr.To(metav1.Now())
 			return Result{
-				Status:                stepExecMeta.Status,
+				Status:                kargoapi.PromotionPhaseErrored,
 				CurrentStep:           i,
 				StepExecutionMetadata: stepExecMetas,
 				State:                 state,
@@ -328,13 +324,9 @@ func (e *simpleEngine) executeStep(
 ) (promotion.StepResult, error) {
 	stepCtx, err := e.prepareStepContext(ctx, promoCtx, step, workDir, state)
 	if err != nil {
-		// TODO(krancour): We're not yet distinguishing between retryable and
-		// non-retryable errors. When we start to do this, failure to prepare the
-		// step context (likely due to invalid configuration) should be considered
-		// non-retryable.
 		return promotion.StepResult{
-			Status: kargoapi.PromotionPhaseErrored,
-		}, err
+			Status: kargoapi.PromotionStepStatusErrored,
+		}, &promotion.TerminalError{Err: err}
 	}
 
 	result, err := runner.Run(ctx, stepCtx)
diff --git a/pkg/promotion/promotion.go b/pkg/promotion/promotion.go
index b2f3fefc..8bea327d 100644
--- a/pkg/promotion/promotion.go
+++ b/pkg/promotion/promotion.go
@@ -81,7 +81,7 @@ type StepContext struct {
 // process executed by a StepRunner.
 type StepResult struct {
 	// Status is the high-level outcome of a Step executed by a StepRunner.
-	Status kargoapi.PromotionPhase
+	Status kargoapi.PromotionStepStatus
 	// Message is an optional message that provides additional context about the
 	// outcome of a Step executed by a StepRunner.
 	Message string
diff --git a/ui/src/features/common/promotion-directive-step-status/promotion-step-status.ts b/ui/src/features/common/promotion-directive-step-status/promotion-step-status.ts
new file mode 100644
index 00000000..c3c1bf44
--- /dev/null
+++ b/ui/src/features/common/promotion-directive-step-status/promotion-step-status.ts
@@ -0,0 +1,8 @@
+export enum PromotionStepStatus {
+  RUNNING = 'Running',
+  SUCCEEDED = 'Succeeded',
+  FAILED = 'Failed',
+  ERRORED = 'Errored',
+  ABORTED = 'Aborted',
+  SKIPPED = 'Skipped'
+}
diff --git a/ui/src/features/common/promotion-directive-step-status/utils.test.ts b/ui/src/features/common/promotion-directive-step-status/utils.test.ts
deleted file mode 100644
index 0823ca10..00000000
--- a/ui/src/features/common/promotion-directive-step-status/utils.test.ts
+++ /dev/null
@@ -1,191 +0,0 @@
-import { expect, test } from 'vitest';
-
-import { PromotionStatus } from '@ui/gen/api/v1alpha1/generated_pb';
-import { PlainMessage } from '@ui/utils/connectrpc-utils';
-
-import { PromotionStatusPhase } from '../promotion-status/utils';
-
-import { getPromotionDirectiveStepStatus, PromotionDirectiveStepStatus } from './utils';
-
-test('getPromotionDirectiveStepStatus', () => {
-  const promotionStatus = (phase: PromotionStatusPhase, currentStep: number) =>
-    ({
-      phase,
-      currentStep: BigInt(currentStep)
-    }) satisfies Partial<PlainMessage<PromotionStatus>> as PromotionStatus;
-
-  const suite: Record<
-    PromotionDirectiveStepStatus,
-    Array<{
-      step: number;
-      promotionStatus: {
-        currentStep: number;
-        phase: PromotionStatusPhase;
-      };
-    }>
-  > = {
-    [PromotionDirectiveStepStatus.RUNNING]: [
-      {
-        step: 0,
-        promotionStatus: {
-          phase: PromotionStatusPhase.RUNNING,
-          currentStep: 0
-        }
-      },
-      {
-        step: 100000,
-        promotionStatus: {
-          phase: PromotionStatusPhase.RUNNING,
-          currentStep: 100000
-        }
-      }
-    ],
-    [PromotionDirectiveStepStatus.FAILED]: [
-      {
-        step: 5,
-        promotionStatus: {
-          phase: PromotionStatusPhase.FAILED,
-          currentStep: 5
-        }
-      },
-      {
-        step: 111,
-        promotionStatus: {
-          phase: PromotionStatusPhase.FAILED,
-          currentStep: 111
-        }
-      },
-      {
-        step: 1353,
-        promotionStatus: {
-          phase: PromotionStatusPhase.ERRORED,
-          currentStep: 1353
-        }
-      },
-      {
-        step: 1241243,
-        promotionStatus: {
-          phase: PromotionStatusPhase.FAILED,
-          currentStep: 1241243
-        }
-      }
-    ],
-    [PromotionDirectiveStepStatus.SUCCESS]: [
-      {
-        step: 1,
-        promotionStatus: {
-          phase: PromotionStatusPhase.SUCCEEDED,
-          currentStep: 100
-        }
-      },
-      {
-        step: 1,
-        promotionStatus: {
-          phase: PromotionStatusPhase.SUCCEEDED,
-          currentStep: 1
-        }
-      },
-      {
-        step: 1,
-        promotionStatus: {
-          phase: PromotionStatusPhase.RUNNING,
-          currentStep: 100
-        }
-      },
-      {
-        step: 123123,
-        promotionStatus: {
-          phase: PromotionStatusPhase.RUNNING,
-          currentStep: 123124
-        }
-      },
-      {
-        step: 12,
-        promotionStatus: {
-          phase: PromotionStatusPhase.FAILED,
-          currentStep: 1231
-        }
-      },
-      {
-        step: 12,
-        promotionStatus: {
-          phase: PromotionStatusPhase.ERRORED,
-          currentStep: 15
-        }
-      },
-      {
-        step: 11,
-        promotionStatus: {
-          phase: PromotionStatusPhase.ABORTED,
-          currentStep: 15
-        }
-      }
-    ],
-    [PromotionDirectiveStepStatus.WONT_RUN]: [
-      {
-        step: 15,
-        promotionStatus: {
-          currentStep: 10,
-          phase: PromotionStatusPhase.ERRORED
-        }
-      },
-      {
-        step: 15,
-        promotionStatus: {
-          currentStep: 10,
-          phase: PromotionStatusPhase.RUNNING
-        }
-      },
-      {
-        step: 1111,
-        promotionStatus: {
-          currentStep: 111,
-          phase: PromotionStatusPhase.FAILED
-        }
-      },
-      {
-        step: 20,
-        promotionStatus: {
-          currentStep: 2,
-          phase: PromotionStatusPhase.PENDING
-        }
-      },
-      {
-        step: 0,
-        promotionStatus: {
-          currentStep: 0,
-          phase: PromotionStatusPhase.PENDING
-        }
-      },
-      {
-        step: 0,
-        promotionStatus: {
-          currentStep: 0,
-          phase: PromotionStatusPhase.ABORTED
-        }
-      },
-      {
-        step: 100,
-        promotionStatus: {
-          currentStep: 90,
-          phase: PromotionStatusPhase.ABORTED
-        }
-      }
-    ]
-  };
-
-  for (const [expectedStatus, testCases] of Object.entries(suite)) {
-    for (const testCase of testCases) {
-      expect(
-        PromotionDirectiveStepStatus[
-          getPromotionDirectiveStepStatus(
-            testCase.step,
-            promotionStatus(testCase.promotionStatus.phase, testCase.promotionStatus.currentStep)
-          )
-        ],
-        // @ts-expect-error really not sure why but its working...
-        `when promotion phase is in ${testCase.promotionStatus.phase} state and promotion current step is ${testCase.promotionStatus.currentStep}, step ${testCase.step} must be in ${PromotionDirectiveStepStatus[expectedStatus]}`
-      ).toBe(PromotionDirectiveStepStatus[+expectedStatus]);
-    }
-  }
-});
diff --git a/ui/src/features/common/promotion-directive-step-status/utils.ts b/ui/src/features/common/promotion-directive-step-status/utils.ts
index 29d4ea92..0ac71d8b 100644
--- a/ui/src/features/common/promotion-directive-step-status/utils.ts
+++ b/ui/src/features/common/promotion-directive-step-status/utils.ts
@@ -1,11 +1,13 @@
-import { PromotionStatusPhase } from '@ui/features/common/promotion-status/utils';
 import { PromotionStatus } from '@ui/gen/api/v1alpha1/generated_pb';
 
+import { PromotionStepStatus } from './promotion-step-status';
+
 // UI concludes from Promotion's status data
 export enum PromotionDirectiveStepStatus {
   RUNNING,
   FAILED,
   SUCCESS,
+  SKIPPED,
   WONT_RUN // because previous step failed
 }
 
@@ -13,31 +15,21 @@ export const getPromotionDirectiveStepStatus = (
   stepNumber: number,
   promotionStatus?: PromotionStatus
 ) => {
-  let currentStep = 0;
-
-  // there will always be some value of currentStep
-  // this is just for type saftey
-  if (promotionStatus?.currentStep) {
-    currentStep = Number(promotionStatus.currentStep);
-  }
-
-  if (stepNumber < currentStep) {
-    // assumes that controller successfully ran this step
-    return PromotionDirectiveStepStatus.SUCCESS;
-  }
+  const promotionStepStatus = promotionStatus?.stepExecutionMetadata?.[stepNumber]
+    ?.status as PromotionStepStatus;
 
-  if (stepNumber === currentStep) {
-    switch (promotionStatus?.phase) {
-      case PromotionStatusPhase.RUNNING:
-        return PromotionDirectiveStepStatus.RUNNING;
-      case PromotionStatusPhase.ERRORED:
-      case PromotionStatusPhase.FAILED:
-        return PromotionDirectiveStepStatus.FAILED;
-      case PromotionStatusPhase.SUCCEEDED:
-        return PromotionDirectiveStepStatus.SUCCESS;
-    }
+  switch (promotionStepStatus) {
+    case PromotionStepStatus.RUNNING:
+      return PromotionDirectiveStepStatus.RUNNING;
+    case PromotionStepStatus.SKIPPED:
+      return PromotionDirectiveStepStatus.SKIPPED;
+    case PromotionStepStatus.SUCCEEDED:
+      return PromotionDirectiveStepStatus.SUCCESS;
+    case PromotionStepStatus.ABORTED:
+    case PromotionStepStatus.ERRORED:
+    case PromotionStepStatus.FAILED:
+      return PromotionDirectiveStepStatus.FAILED;
   }
 
-  // if step number is > current step, no matter which state promotion is in, the given step number "has not" run yet or "will not" depends on the promotion phase but that doesn't matter....YET
   return PromotionDirectiveStepStatus.WONT_RUN;
 };
diff --git a/ui/src/features/stage/promotion-details-modal.tsx b/ui/src/features/stage/promotion-details-modal.tsx
index bd8dbc34..266230bf 100644
--- a/ui/src/features/stage/promotion-details-modal.tsx
+++ b/ui/src/features/stage/promotion-details-modal.tsx
@@ -1,6 +1,7 @@
 import { toJson } from '@bufbuild/protobuf';
 import { useMutation } from '@connectrpc/connect-query';
 import {
+  faBan,
   faCheck,
   faCircleNotch,
   faCog,
@@ -76,6 +77,7 @@ const Step = ({
   const progressing = result === PromotionDirectiveStepStatus.RUNNING;
   const success = result === PromotionDirectiveStepStatus.SUCCESS;
   const failed = result === PromotionDirectiveStepStatus.FAILED;
+  const skipped = result === PromotionDirectiveStepStatus.SKIPPED;
 
   const opts: SegmentedOptions<string> = [];
 
@@ -133,6 +135,7 @@ const Step = ({
           {progressing && <FontAwesomeIcon spin icon={faCircleNotch} />}
           {success && <FontAwesomeIcon icon={faCheck} className='text-green-500' />}
           {failed && <FontAwesomeIcon icon={faTimes} className='text-red-500' />}
+          {skipped && <FontAwesomeIcon icon={faBan} />}
         </Flex>
         <Flex className={'w-full'} align='center'>
           <span className='font-semibold text-base '>{meta.spec.identifier}</span>



Test patch:
diff --git a/internal/controller/promotions/promotions_test.go b/internal/controller/promotions/promotions_test.go
index b2fc49e7..fe2bfdd8 100644
--- a/internal/controller/promotions/promotions_test.go
+++ b/internal/controller/promotions/promotions_test.go
@@ -361,7 +361,41 @@ func Test_reconciler_terminatePromotion(t *testing.T) {
 				require.NoError(t, err)
 				require.Equal(t, kargoapi.PromotionPhaseAborted, promo.Status.Phase)
 				require.Contains(t, promo.Status.Message, "terminated")
-				require.NotNil(t, now, promo.Status.FinishedAt)
+				require.NotNil(t, promo.Status.FinishedAt)
+
+				require.Len(t, recorder.Events, 1)
+				event := <-recorder.Events
+				require.Equal(t, kargoapi.EventReasonPromotionAborted, event.Reason)
+			},
+		},
+		{
+			name: "terminates running promotion",
+			promo: &kargoapi.Promotion{
+				ObjectMeta: metav1.ObjectMeta{
+					CreationTimestamp: now,
+					Name:              "fake-promo",
+					Namespace:         "fake-namespace",
+				},
+				Spec: kargoapi.PromotionSpec{
+					Stage: "fake-stage",
+				},
+				Status: kargoapi.PromotionStatus{
+					Phase:       kargoapi.PromotionPhaseRunning,
+					CurrentStep: 0,
+					StepExecutionMetadata: []kargoapi.StepExecutionMetadata{{
+						StartedAt: &now,
+						Status:    kargoapi.PromotionStepStatusRunning,
+					}},
+				},
+			},
+			assertions: func(t *testing.T, recorder *fakeevent.EventRecorder, promo *kargoapi.Promotion, err error) {
+				require.NoError(t, err)
+				require.Equal(t, kargoapi.PromotionPhaseAborted, promo.Status.Phase)
+				require.Contains(t, promo.Status.Message, "terminated")
+				require.NotNil(t, promo.Status.FinishedAt)
+
+				require.Equal(t, kargoapi.PromotionStepStatusAborted, promo.Status.StepExecutionMetadata[0].Status)
+				require.NotNil(t, promo.Status.StepExecutionMetadata[0].FinishedAt)
 
 				require.Len(t, recorder.Events, 1)
 				event := <-recorder.Events
@@ -384,7 +418,7 @@ func Test_reconciler_terminatePromotion(t *testing.T) {
 				require.NoError(t, err)
 				require.Equal(t, kargoapi.PromotionPhaseAborted, promo.Status.Phase)
 				require.Contains(t, promo.Status.Message, "terminated")
-				require.NotNil(t, now, promo.Status.FinishedAt)
+				require.NotNil(t, promo.Status.FinishedAt)
 
 				require.Len(t, recorder.Events, 1)
 				event := <-recorder.Events
diff --git a/internal/promotion/runner/builtin/argocd_updater_test.go b/internal/promotion/runner/builtin/argocd_updater_test.go
index 07895dae..c9d51d66 100644
--- a/internal/promotion/runner/builtin/argocd_updater_test.go
+++ b/internal/promotion/runner/builtin/argocd_updater_test.go
@@ -346,7 +346,7 @@ func Test_argoCDUpdater_run(t *testing.T) {
 			runner:  &argocdUpdater{},
 			stepCfg: builtin.ArgoCDUpdateConfig{},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
-				require.Equal(t, kargoapi.PromotionPhaseErrored, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusErrored, res.Status)
 				require.ErrorContains(
 					t, err, "Argo CD integration is disabled on this controller",
 				)
@@ -368,7 +368,7 @@ func Test_argoCDUpdater_run(t *testing.T) {
 				Apps: []builtin.ArgoCDAppUpdate{{}},
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
-				require.Equal(t, kargoapi.PromotionPhaseErrored, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusErrored, res.Status)
 				require.ErrorContains(t, err, "error getting Argo CD Application")
 				require.ErrorContains(t, err, "something went wrong")
 			},
@@ -396,7 +396,7 @@ func Test_argoCDUpdater_run(t *testing.T) {
 				Apps: []builtin.ArgoCDAppUpdate{{}},
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
-				require.Equal(t, kargoapi.PromotionPhaseErrored, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusErrored, res.Status)
 				require.ErrorContains(t, err, "something went wrong")
 			},
 		},
@@ -438,7 +438,7 @@ func Test_argoCDUpdater_run(t *testing.T) {
 				Apps: []builtin.ArgoCDAppUpdate{{}},
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
-				require.Equal(t, kargoapi.PromotionPhaseRunning, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusRunning, res.Status)
 				require.NoError(t, err)
 			},
 		},
@@ -465,7 +465,7 @@ func Test_argoCDUpdater_run(t *testing.T) {
 				Apps: []builtin.ArgoCDAppUpdate{{}},
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
-				require.Equal(t, kargoapi.PromotionPhaseRunning, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusRunning, res.Status)
 				require.NoError(t, err)
 			},
 		},
@@ -492,7 +492,7 @@ func Test_argoCDUpdater_run(t *testing.T) {
 				Apps: []builtin.ArgoCDAppUpdate{{}},
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
-				require.Equal(t, kargoapi.PromotionPhaseRunning, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusRunning, res.Status)
 				require.NoError(t, err)
 			},
 		},
@@ -526,7 +526,7 @@ func Test_argoCDUpdater_run(t *testing.T) {
 				Apps: []builtin.ArgoCDAppUpdate{{}},
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
-				require.Equal(t, kargoapi.PromotionPhaseErrored, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusErrored, res.Status)
 				require.ErrorContains(t, err, "error building desired sources for Argo CD Application")
 				require.ErrorContains(t, err, "something went wrong")
 			},
@@ -569,7 +569,7 @@ func Test_argoCDUpdater_run(t *testing.T) {
 				Apps: []builtin.ArgoCDAppUpdate{{}},
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
-				require.Equal(t, kargoapi.PromotionPhaseErrored, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusErrored, res.Status)
 				require.ErrorContains(t, err, "error syncing Argo CD Application")
 				require.ErrorContains(t, err, "something went wrong")
 			},
@@ -623,7 +623,7 @@ func Test_argoCDUpdater_run(t *testing.T) {
 				Apps: []builtin.ArgoCDAppUpdate{{}, {}},
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
-				require.Equal(t, kargoapi.PromotionPhaseErrored, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusErrored, res.Status)
 				require.NoError(t, err)
 			},
 		},
@@ -650,7 +650,7 @@ func Test_argoCDUpdater_run(t *testing.T) {
 				Apps: []builtin.ArgoCDAppUpdate{{}},
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
-				require.Equal(t, kargoapi.PromotionPhaseErrored, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusErrored, res.Status)
 				require.ErrorContains(t, err, "could not determine promotion step status")
 			},
 		},
@@ -677,7 +677,7 @@ func Test_argoCDUpdater_run(t *testing.T) {
 				Apps: []builtin.ArgoCDAppUpdate{{}},
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
-				require.Equal(t, kargoapi.PromotionPhaseSucceeded, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusSucceeded, res.Status)
 				require.NoError(t, err)
 			},
 		},
diff --git a/internal/promotion/runner/builtin/file_copier_test.go b/internal/promotion/runner/builtin/file_copier_test.go
index 52e62fcf..3464e8dc 100644
--- a/internal/promotion/runner/builtin/file_copier_test.go
+++ b/internal/promotion/runner/builtin/file_copier_test.go
@@ -40,7 +40,7 @@ func Test_fileCopier_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				outPath := filepath.Join(workDir, "output.txt")
 				b, err := os.ReadFile(outPath)
@@ -72,7 +72,7 @@ func Test_fileCopier_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				outDir := filepath.Join(workDir, "output")
 
@@ -110,7 +110,7 @@ func Test_fileCopier_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				outDir := filepath.Join(workDir, "output")
 
@@ -148,7 +148,7 @@ func Test_fileCopier_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				outDir := filepath.Join(workDir, "output")
 
@@ -184,7 +184,7 @@ func Test_fileCopier_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				outDir := filepath.Join(workDir, "output")
 
@@ -221,7 +221,7 @@ func Test_fileCopier_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				outDir := filepath.Join(workDir, "output")
 
@@ -245,7 +245,7 @@ func Test_fileCopier_run(t *testing.T) {
 				InPath: "input.txt",
 			},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
-				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 				require.ErrorContains(t, err, "failed to copy")
 			},
 		},
diff --git a/internal/promotion/runner/builtin/file_deleter_test.go b/internal/promotion/runner/builtin/file_deleter_test.go
index 3c04c49d..2a65744e 100644
--- a/internal/promotion/runner/builtin/file_deleter_test.go
+++ b/internal/promotion/runner/builtin/file_deleter_test.go
@@ -36,7 +36,7 @@ func Test_fileDeleter_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				_, statError := os.Stat("input.txt")
 				assert.True(t, os.IsNotExist(statError))
@@ -55,7 +55,7 @@ func Test_fileDeleter_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				_, statErr := os.Stat(filepath.Join(workDir, "dirToDelete"))
 				assert.True(t, os.IsNotExist(statErr))
@@ -72,7 +72,7 @@ func Test_fileDeleter_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 			},
 		},
 		{
@@ -86,7 +86,7 @@ func Test_fileDeleter_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 			},
 		},
 		{
@@ -110,7 +110,7 @@ func Test_fileDeleter_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				_, statErr := os.Stat(filepath.Join(workDir, "input", "input.txt"))
 				assert.NoError(t, statErr)
@@ -141,7 +141,7 @@ func Test_fileDeleter_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				require.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				_, statErr := os.Stat(filepath.Join(workDir, "foo", "file.txt"))
 				assert.Error(t, statErr)
diff --git a/internal/promotion/runner/builtin/git_cloner_test.go b/internal/promotion/runner/builtin/git_cloner_test.go
index eb0c7c3e..1de8be55 100644
--- a/internal/promotion/runner/builtin/git_cloner_test.go
+++ b/internal/promotion/runner/builtin/git_cloner_test.go
@@ -252,7 +252,7 @@ func Test_gitCloner_run(t *testing.T) {
 		},
 	)
 	require.NoError(t, err)
-	require.Equal(t, kargoapi.PromotionPhaseSucceeded, res.Status)
+	require.Equal(t, kargoapi.PromotionStepStatusSucceeded, res.Status)
 	require.DirExists(t, filepath.Join(stepCtx.WorkDir, "src"))
 	// The checked out master branch should have the content we know is in the
 	// test remote's master branch.
diff --git a/internal/promotion/runner/builtin/git_commiter_test.go b/internal/promotion/runner/builtin/git_commiter_test.go
index 4cc3e44a..7743319c 100644
--- a/internal/promotion/runner/builtin/git_commiter_test.go
+++ b/internal/promotion/runner/builtin/git_commiter_test.go
@@ -200,7 +200,7 @@ func Test_gitCommitter_run(t *testing.T) {
 		},
 	)
 	require.NoError(t, err)
-	require.Equal(t, kargoapi.PromotionPhaseSucceeded, res.Status)
+	require.Equal(t, kargoapi.PromotionStepStatusSucceeded, res.Status)
 	expectedCommit, err := workTree.LastCommitID()
 	require.NoError(t, err)
 	actualCommit, ok := res.Output[stateKeyCommit]
diff --git a/internal/promotion/runner/builtin/git_pr_waiter_test.go b/internal/promotion/runner/builtin/git_pr_waiter_test.go
index 7b33054d..4f78cc24 100644
--- a/internal/promotion/runner/builtin/git_pr_waiter_test.go
+++ b/internal/promotion/runner/builtin/git_pr_waiter_test.go
@@ -120,7 +120,7 @@ func Test_gitPRWaiter_run(t *testing.T) {
 			assertions: func(t *testing.T, res promoPkg.StepResult, err error) {
 				require.ErrorContains(t, err, "error getting pull request")
 				require.ErrorContains(t, err, "something went wrong")
-				require.Equal(t, kargoapi.PromotionPhaseErrored, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusErrored, res.Status)
 			},
 		},
 		{
@@ -137,7 +137,7 @@ func Test_gitPRWaiter_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, res promoPkg.StepResult, err error) {
 				require.NoError(t, err)
-				require.Equal(t, kargoapi.PromotionPhaseRunning, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusRunning, res.Status)
 			},
 		},
 		{
@@ -156,7 +156,7 @@ func Test_gitPRWaiter_run(t *testing.T) {
 			assertions: func(t *testing.T, res promoPkg.StepResult, err error) {
 				require.ErrorContains(t, err, "closed without being merged")
 				require.True(t, promotion.IsTerminal(err))
-				require.Equal(t, kargoapi.PromotionPhaseFailed, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusFailed, res.Status)
 			},
 		},
 		{
@@ -174,7 +174,7 @@ func Test_gitPRWaiter_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, res promoPkg.StepResult, err error) {
 				require.NoError(t, err)
-				require.Equal(t, kargoapi.PromotionPhaseSucceeded, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusSucceeded, res.Status)
 			},
 		},
 	}
diff --git a/internal/promotion/runner/builtin/git_tree_clearer_test.go b/internal/promotion/runner/builtin/git_tree_clearer_test.go
index d34edfc3..32e98852 100644
--- a/internal/promotion/runner/builtin/git_tree_clearer_test.go
+++ b/internal/promotion/runner/builtin/git_tree_clearer_test.go
@@ -120,7 +120,7 @@ func Test_gitTreeOverwriter_run(t *testing.T) {
 		},
 	)
 	require.NoError(t, err)
-	require.Equal(t, kargoapi.PromotionPhaseSucceeded, res.Status)
+	require.Equal(t, kargoapi.PromotionStepStatusSucceeded, res.Status)
 
 	// Make sure old files are gone
 	_, err = os.Stat(filepath.Join(workTree.Dir(), "original.txt"))
diff --git a/internal/promotion/runner/builtin/helm_chart_updater_test.go b/internal/promotion/runner/builtin/helm_chart_updater_test.go
index 1b6751db..f414b508 100644
--- a/internal/promotion/runner/builtin/helm_chart_updater_test.go
+++ b/internal/promotion/runner/builtin/helm_chart_updater_test.go
@@ -228,7 +228,7 @@ func Test_helmChartUpdater_run(t *testing.T) {
 			assertions: func(t *testing.T, tempDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
 				assert.Equal(t, promotion.StepResult{
-					Status: kargoapi.PromotionPhaseSucceeded,
+					Status: kargoapi.PromotionStepStatusSucceeded,
 					Output: map[string]any{
 						"commitMessage": `Updated chart dependencies for testchart
 
diff --git a/internal/promotion/runner/builtin/helm_template_runner_test.go b/internal/promotion/runner/builtin/helm_template_runner_test.go
index cbd6819a..ae9f0768 100644
--- a/internal/promotion/runner/builtin/helm_template_runner_test.go
+++ b/internal/promotion/runner/builtin/helm_template_runner_test.go
@@ -51,7 +51,7 @@ data:
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				require.NoError(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				outPath := filepath.Join(workDir, "output.yaml")
 				require.FileExists(t, outPath)
@@ -97,7 +97,7 @@ data:
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				require.NoError(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				outPath := filepath.Join(workDir, "output.yaml")
 				require.FileExists(t, outPath)
@@ -144,7 +144,7 @@ data:
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				require.NoError(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				outPath := filepath.Join(workDir, "output.yaml")
 				require.FileExists(t, outPath)
@@ -189,7 +189,7 @@ data:
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				require.NoError(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				outPath := filepath.Join(workDir, "output", "test-chart")
 				require.DirExists(t, outPath)
@@ -215,7 +215,7 @@ data:
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				require.ErrorContains(t, err, "failed to compose values")
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 
 				require.NoFileExists(t, filepath.Join(workDir, "output.yaml"))
 			},
@@ -227,7 +227,7 @@ data:
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				require.ErrorContains(t, err, "failed to load chart")
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 
 				require.NoFileExists(t, filepath.Join(workDir, "output.yaml"))
 			},
@@ -250,7 +250,7 @@ dependencies:
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				require.ErrorContains(t, err, "missing chart dependencies")
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 
 				require.NoFileExists(t, filepath.Join(workDir, "output.yaml"))
 			},
@@ -268,7 +268,7 @@ version: 0.1.0`,
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				require.ErrorContains(t, err, "failed to initialize Helm action config")
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 
 				require.NoFileExists(t, filepath.Join(workDir, "output.yaml"))
 			},
@@ -294,7 +294,7 @@ data:
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				require.ErrorContains(t, err, "failed to render chart")
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 
 				require.NoFileExists(t, filepath.Join(workDir, "output.yaml"))
 			},
@@ -319,7 +319,7 @@ metadata:
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				require.ErrorContains(t, err, "failed to write rendered chart")
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 
 				require.NoFileExists(t, filepath.Join(workDir, "output.yaml"))
 			},
diff --git a/internal/promotion/runner/builtin/http_requester_test.go b/internal/promotion/runner/builtin/http_requester_test.go
index 293960f4..4f8e0877 100644
--- a/internal/promotion/runner/builtin/http_requester_test.go
+++ b/internal/promotion/runner/builtin/http_requester_test.go
@@ -249,7 +249,7 @@ func Test_httpRequester_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
 				require.NoError(t, err)
-				require.Equal(t, kargoapi.PromotionPhaseSucceeded, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusSucceeded, res.Status)
 				require.Equal(
 					t,
 					map[string]any{
@@ -282,7 +282,7 @@ func Test_httpRequester_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
 				require.NoError(t, err)
-				require.Equal(t, kargoapi.PromotionPhaseSucceeded, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusSucceeded, res.Status)
 				require.Equal(
 					t,
 					map[string]any{
@@ -315,7 +315,7 @@ func Test_httpRequester_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
 				require.NoError(t, err)
-				require.Equal(t, kargoapi.PromotionPhaseSucceeded, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusSucceeded, res.Status)
 				require.Equal(
 					t,
 					map[string]any{
@@ -337,7 +337,7 @@ func Test_httpRequester_run(t *testing.T) {
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
 				require.ErrorContains(t, err, "HTTP (404) response met failure criteria")
 				require.True(t, promotion.IsTerminal(err))
-				require.Equal(t, kargoapi.PromotionPhaseFailed, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusFailed, res.Status)
 			},
 		},
 		{
@@ -350,7 +350,7 @@ func Test_httpRequester_run(t *testing.T) {
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
 				require.ErrorContains(t, err, "HTTP (200) response met failure criteria")
 				require.True(t, promotion.IsTerminal(err))
-				require.Equal(t, kargoapi.PromotionPhaseFailed, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusFailed, res.Status)
 			},
 		},
 		{
@@ -364,7 +364,7 @@ func Test_httpRequester_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, res promotion.StepResult, err error) {
 				require.NoError(t, err)
-				require.Equal(t, kargoapi.PromotionPhaseRunning, res.Status)
+				require.Equal(t, kargoapi.PromotionStepStatusRunning, res.Status)
 			},
 		},
 	}
diff --git a/internal/promotion/runner/builtin/json_parser_test.go b/internal/promotion/runner/builtin/json_parser_test.go
index e56c3a55..c8c1fb1b 100644
--- a/internal/promotion/runner/builtin/json_parser_test.go
+++ b/internal/promotion/runner/builtin/json_parser_test.go
@@ -158,7 +158,7 @@ func Test_jsonParser_run(t *testing.T) {
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
 				assert.Equal(t, promotion.StepResult{
-					Status: kargoapi.PromotionPhaseSucceeded,
+					Status: kargoapi.PromotionStepStatusSucceeded,
 					Output: map[string]any{
 						"appVersion":    "1.0.0",
 						"featureStatus": false,
@@ -181,7 +181,7 @@ func Test_jsonParser_run(t *testing.T) {
 			files: map[string]string{"config.json": `{ "app": { "version": "1.0.0" }}`},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 				assert.Contains(t, err.Error(), "failed to extract outputs")
 			},
 		},
@@ -204,7 +204,7 @@ func Test_jsonParser_run(t *testing.T) {
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
 				assert.Equal(t, promotion.StepResult{
-					Status: kargoapi.PromotionPhaseErrored,
+					Status: kargoapi.PromotionStepStatusErrored,
 				}, result)
 				assert.Contains(t, err.Error(), "outputs is required")
 			},
@@ -225,7 +225,7 @@ func Test_jsonParser_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 				assert.Contains(t, err.Error(), "could not parse JSON file")
 			},
 		},
@@ -239,7 +239,7 @@ func Test_jsonParser_run(t *testing.T) {
 			files: map[string]string{},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 				assert.Contains(t, err.Error(), "JSON file path cannot be empty")
 			},
 		},
@@ -252,7 +252,7 @@ func Test_jsonParser_run(t *testing.T) {
 			files: map[string]string{},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 				assert.Contains(t, err.Error(), "no such file or directory")
 			},
 		},
@@ -285,7 +285,7 @@ func Test_jsonParser_run(t *testing.T) {
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
 				assert.Equal(t, promotion.StepResult{
-					Status: kargoapi.PromotionPhaseSucceeded,
+					Status: kargoapi.PromotionStepStatusSucceeded,
 					Output: map[string]any{
 						"appVersion": "2.0.1",
 						"isEnabled":  true,
diff --git a/internal/promotion/runner/builtin/json_updater_test.go b/internal/promotion/runner/builtin/json_updater_test.go
index 88eb17e5..f29c013c 100644
--- a/internal/promotion/runner/builtin/json_updater_test.go
+++ b/internal/promotion/runner/builtin/json_updater_test.go
@@ -320,7 +320,7 @@ func Test_jsonUpdater_run(t *testing.T) {
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
 				assert.Equal(t, promotion.StepResult{
-					Status: kargoapi.PromotionPhaseSucceeded,
+					Status: kargoapi.PromotionStepStatusSucceeded,
 					Output: map[string]any{
 						"commitMessage": "Updated config.json\n\n" +
 							"- app.version: \"1.0.1\"\n" +
@@ -348,7 +348,7 @@ func Test_jsonUpdater_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 				assert.Contains(t, err.Error(), "JSON file update failed")
 			},
 		},
@@ -371,7 +371,7 @@ func Test_jsonUpdater_run(t *testing.T) {
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
 				assert.Equal(t, promotion.StepResult{
-					Status: kargoapi.PromotionPhaseSucceeded,
+					Status: kargoapi.PromotionStepStatusSucceeded,
 				}, result)
 				content, err := os.ReadFile(path.Join(workDir, "config.json"))
 				require.NoError(t, err)
@@ -440,7 +440,7 @@ func Test_jsonUpdater_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, result.Status)
 				content, err := os.ReadFile(path.Join(workDir, "config.json"))
 				require.NoError(t, err)
 				assert.JSONEq(t, `{"threshold": 425}`, string(content))
@@ -462,7 +462,7 @@ func Test_jsonUpdater_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, result.Status)
 				content, err := os.ReadFile(path.Join(workDir, "config.json"))
 				require.NoError(t, err)
 				assert.JSONEq(t, `{"features": {"existingFeature": false}}`, string(content))
diff --git a/internal/promotion/runner/builtin/kustomize_builder_test.go b/internal/promotion/runner/builtin/kustomize_builder_test.go
index f63ae36b..836a6c61 100644
--- a/internal/promotion/runner/builtin/kustomize_builder_test.go
+++ b/internal/promotion/runner/builtin/kustomize_builder_test.go
@@ -46,7 +46,7 @@ metadata:
 			},
 			assertions: func(t *testing.T, dir string, result promotion.StepResult, err error) {
 				require.NoError(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				assert.FileExists(t, filepath.Join(dir, "output.yaml"))
 				b, err := os.ReadFile(filepath.Join(dir, "output.yaml"))
@@ -97,7 +97,7 @@ replicaCount: 3`), 0o600))
 			},
 			assertions: func(t *testing.T, dir string, result promotion.StepResult, err error) {
 				require.NoError(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				assert.FileExists(t, filepath.Join(dir, "output.yaml"))
 				b, err := os.ReadFile(filepath.Join(dir, "output.yaml"))
@@ -133,7 +133,7 @@ metadata:
 			},
 			assertions: func(t *testing.T, dir string, result promotion.StepResult, err error) {
 				require.NoError(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result)
 
 				assert.DirExists(t, filepath.Join(dir, "output"))
 				b, err := os.ReadFile(filepath.Join(dir, "output", "deployment-test-deployment.yaml"))
@@ -150,7 +150,7 @@ metadata:
 			},
 			assertions: func(t *testing.T, dir string, result promotion.StepResult, err error) {
 				require.ErrorContains(t, err, "no such file or directory")
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 
 				assert.NoFileExists(t, filepath.Join(dir, "output.yaml"))
 			},
@@ -166,7 +166,7 @@ metadata:
 			},
 			assertions: func(t *testing.T, dir string, result promotion.StepResult, err error) {
 				require.ErrorContains(t, err, "invalid Kustomization")
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 
 				assert.NoFileExists(t, filepath.Join(dir, "output.yaml"))
 			},
diff --git a/internal/promotion/runner/builtin/kustomize_image_setter_test.go b/internal/promotion/runner/builtin/kustomize_image_setter_test.go
index 98045bc1..2882a699 100644
--- a/internal/promotion/runner/builtin/kustomize_image_setter_test.go
+++ b/internal/promotion/runner/builtin/kustomize_image_setter_test.go
@@ -197,7 +197,7 @@ kind: Kustomization
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				require.NoError(t, err)
 				assert.Equal(t, promotion.StepResult{
-					Status: kargoapi.PromotionPhaseSucceeded,
+					Status: kargoapi.PromotionStepStatusSucceeded,
 					Output: map[string]any{
 						"commitMessage": "Updated . to use new image\n\n- nginx:1.21.0",
 					},
@@ -236,7 +236,7 @@ kind: Kustomization
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				require.NoError(t, err)
 				assert.Equal(t, promotion.StepResult{
-					Status: kargoapi.PromotionPhaseSucceeded,
+					Status: kargoapi.PromotionStepStatusSucceeded,
 					Output: map[string]any{
 						"commitMessage": "Updated . to use new images\n\n- nginx@sha256:123\n- redis:6.2.5",
 					},
@@ -260,7 +260,7 @@ kind: Kustomization
 			stepCtx: &promotion.StepContext{Project: testNamespace},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				require.ErrorContains(t, err, "could not discover kustomization file:")
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 			},
 		},
 	}
diff --git a/internal/promotion/runner/builtin/yaml_parser_test.go b/internal/promotion/runner/builtin/yaml_parser_test.go
index 6821e529..e9fcd48e 100644
--- a/internal/promotion/runner/builtin/yaml_parser_test.go
+++ b/internal/promotion/runner/builtin/yaml_parser_test.go
@@ -156,7 +156,7 @@ features:
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
 				assert.Equal(t, promotion.StepResult{
-					Status: kargoapi.PromotionPhaseSucceeded,
+					Status: kargoapi.PromotionStepStatusSucceeded,
 					Output: map[string]any{
 						"appVersion":    "1.0.0",
 						"featureStatus": false,
@@ -184,7 +184,7 @@ app:
 			},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 				assert.Contains(t, err.Error(), "failed to extract outputs")
 			},
 		},
@@ -206,7 +206,7 @@ app:
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
 				assert.Equal(t, promotion.StepResult{
-					Status: kargoapi.PromotionPhaseErrored,
+					Status: kargoapi.PromotionStepStatusErrored,
 				}, result)
 				assert.Contains(t, err.Error(), "outputs is required")
 			},
@@ -227,7 +227,7 @@ app:
 			},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 				assert.Contains(t, err.Error(), "could not parse empty YAML file")
 			},
 		},
@@ -241,7 +241,7 @@ app:
 			files: map[string]string{},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 				assert.Contains(t, err.Error(), "YAML file path cannot be empty")
 			},
 		},
@@ -255,7 +255,7 @@ app:
 			files: map[string]string{},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 				assert.Contains(t, err.Error(), "no such file or directory")
 			},
 		},
@@ -285,7 +285,7 @@ config:
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
 				assert.Equal(t, promotion.StepResult{
-					Status: kargoapi.PromotionPhaseSucceeded,
+					Status: kargoapi.PromotionStepStatusSucceeded,
 					Output: map[string]any{
 						"appVersion": "2.0.1",
 						"isEnabled":  true,
diff --git a/internal/promotion/runner/builtin/yaml_updater_test.go b/internal/promotion/runner/builtin/yaml_updater_test.go
index 6f203bf4..8d88d4b7 100644
--- a/internal/promotion/runner/builtin/yaml_updater_test.go
+++ b/internal/promotion/runner/builtin/yaml_updater_test.go
@@ -143,7 +143,7 @@ func Test_yamlUpdater_run(t *testing.T) {
 			assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
 				assert.Equal(t, promotion.StepResult{
-					Status: kargoapi.PromotionPhaseSucceeded,
+					Status: kargoapi.PromotionStepStatusSucceeded,
 					Output: map[string]any{
 						"commitMessage": "Updated values.yaml\n\n- image.tag: \"fake-tag\"",
 					},
@@ -166,7 +166,7 @@ func Test_yamlUpdater_run(t *testing.T) {
 			},
 			assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) {
 				assert.Error(t, err)
-				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, result)
+				assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result)
 				assert.Contains(t, err.Error(), "values file update failed")
 			},
 		},
diff --git a/internal/promotion/simple_engine_test.go b/internal/promotion/simple_engine_test.go
index f2a1a6bb..b6476767 100644
--- a/internal/promotion/simple_engine_test.go
+++ b/internal/promotion/simple_engine_test.go
@@ -71,7 +71,7 @@ func TestSimpleEngine_Promote(t *testing.T) {
 				assert.ErrorContains(t, err, "met error threshold")
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
 				assert.Len(t, result.StepExecutionMetadata, 1)
-				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.StepExecutionMetadata[0].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
 				assert.Contains(t, result.StepExecutionMetadata[0].Message, context.Canceled.Error())
 			},
 		},
@@ -105,13 +105,13 @@ func TestSimpleEngine_Promote(t *testing.T) {
 			testRegistry.register(
 				&mockStepRunner{
 					name:      "success-step",
-					runResult: promotion.StepResult{Status: kargoapi.PromotionPhaseSucceeded},
+					runResult: promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded},
 				},
 			)
 			testRegistry.register(
 				&mockStepRunner{
 					name:      "error-step",
-					runResult: promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+					runResult: promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 					runErr:    errors.New("something went wrong"),
 				},
 			)
@@ -121,7 +121,7 @@ func TestSimpleEngine_Promote(t *testing.T) {
 					runFunc: func(ctx context.Context, _ *promotion.StepContext) (promotion.StepResult, error) {
 						cancel() // Cancel context immediately
 						<-ctx.Done()
-						return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, ctx.Err()
+						return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, ctx.Err()
 					},
 				},
 			)
@@ -181,7 +181,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				// Verify the result contains metadata from both steps
 				assert.Len(t, result.StepExecutionMetadata, 2)
 				for _, metadata := range result.StepExecutionMetadata {
-					assert.Equal(t, kargoapi.PromotionPhaseSucceeded, metadata.Status)
+					assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, metadata.Status)
 					assert.NotNil(t, metadata.StartedAt)
 					assert.NotNil(t, metadata.FinishedAt)
 				}
@@ -212,12 +212,13 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				// Verify the result contains metadata from all steps
 				assert.Len(t, result.StepExecutionMetadata, 3)
 				for _, metadata := range result.StepExecutionMetadata {
-					assert.Equal(t, kargoapi.PromotionPhaseSucceeded, metadata.Status)
 					switch metadata.Alias {
 					case "step2":
+						assert.Equal(t, kargoapi.PromotionStepStatusSkipped, metadata.Status)
 						assert.Nil(t, metadata.StartedAt)
 						assert.Nil(t, metadata.FinishedAt)
 					default:
+						assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, metadata.Status)
 						assert.NotNil(t, metadata.StartedAt)
 						assert.NotNil(t, metadata.FinishedAt)
 					}
@@ -258,7 +259,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				assert.Len(t, result.StepExecutionMetadata, 2)
 				// We're not bothering with assertions on the dummy metadata for the 0
 				// step.
-				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.StepExecutionMetadata[1].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, result.StepExecutionMetadata[1].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[1].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[1].FinishedAt)
 
@@ -281,10 +282,10 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
 				assert.Equal(t, int64(1), result.CurrentStep)
 				assert.Len(t, result.StepExecutionMetadata, 2)
-				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.StepExecutionMetadata[0].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
-				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.StepExecutionMetadata[1].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[1].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[1].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[1].FinishedAt)
 				assert.Contains(t, result.StepExecutionMetadata[1].Message, "something went wrong")
@@ -309,10 +310,10 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
 				assert.Equal(t, int64(1), result.CurrentStep)
 				assert.Len(t, result.StepExecutionMetadata, 2)
-				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.StepExecutionMetadata[0].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
-				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.StepExecutionMetadata[1].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[1].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[1].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[1].FinishedAt)
 				assert.Contains(t, result.StepExecutionMetadata[1].Message, "something went wrong")
@@ -340,7 +341,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				assert.Equal(t, kargoapi.PromotionPhaseRunning, result.Status)
 				assert.Equal(t, int64(0), result.CurrentStep)
 				assert.Len(t, result.StepExecutionMetadata, 1)
-				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.StepExecutionMetadata[0].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.Nil(t, result.StepExecutionMetadata[0].FinishedAt)
 				assert.Equal(t, uint32(1), result.StepExecutionMetadata[0].ErrorCount)
@@ -372,7 +373,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
 				assert.Equal(t, int64(0), result.CurrentStep)
 				assert.Len(t, result.StepExecutionMetadata, 1)
-				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.StepExecutionMetadata[0].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
 				assert.Equal(t, uint32(1), result.StepExecutionMetadata[0].ErrorCount)
@@ -402,7 +403,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
 				assert.Equal(t, int64(0), result.CurrentStep)
 				assert.Len(t, result.StepExecutionMetadata, 1)
-				assert.Equal(t, kargoapi.PromotionPhaseRunning, result.StepExecutionMetadata[0].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusRunning, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
 			},
@@ -415,7 +416,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				assert.Equal(t, kargoapi.PromotionPhaseRunning, result.Status)
 				assert.Equal(t, int64(0), result.CurrentStep)
 				assert.Len(t, result.StepExecutionMetadata, 1)
-				assert.Equal(t, kargoapi.PromotionPhaseRunning, result.StepExecutionMetadata[0].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusRunning, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.Nil(t, result.StepExecutionMetadata[0].FinishedAt)
 			},
@@ -428,7 +429,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
 				assert.Equal(t, int64(0), result.CurrentStep)
 				assert.Len(t, result.StepExecutionMetadata, 1)
-				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.StepExecutionMetadata[0].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
 				assert.Contains(t, result.StepExecutionMetadata[0].Message, context.Canceled.Error())
 			},
 		},
@@ -438,7 +439,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				&mockStepRunner{
 					name: ComposeOutputStepKind,
 					runResult: promotion.StepResult{
-						Status: kargoapi.PromotionPhaseSucceeded,
+						Status: kargoapi.PromotionStepStatusSucceeded,
 						Output: map[string]any{"test": "value"},
 					},
 				},
@@ -452,7 +453,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status)
 				assert.Equal(t, int64(0), result.CurrentStep)
 				assert.Len(t, result.StepExecutionMetadata, 1)
-				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.StepExecutionMetadata[0].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
 				assert.Equal(t, promotion.State{
@@ -473,7 +474,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				&mockStepRunner{
 					name: ComposeOutputStepKind,
 					runResult: promotion.StepResult{
-						Status: kargoapi.PromotionPhaseSucceeded,
+						Status: kargoapi.PromotionStepStatusSucceeded,
 						Output: map[string]any{"test": "value"},
 					},
 				},
@@ -487,7 +488,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status)
 				assert.Equal(t, int64(0), result.CurrentStep)
 				assert.Len(t, result.StepExecutionMetadata, 1)
-				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.StepExecutionMetadata[0].Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
 				assert.Equal(t, promotion.State{
@@ -510,24 +511,24 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				&mockStepRunner{
 					name: "success-step",
 					runResult: promotion.StepResult{
-						Status: kargoapi.PromotionPhaseSucceeded,
+						Status: kargoapi.PromotionStepStatusSucceeded,
 						Output: map[string]any{"key": "value"},
 					},
 				},
 				&mockStepRunner{
 					name: "running-step",
 					runResult: promotion.StepResult{
-						Status: kargoapi.PromotionPhaseRunning,
+						Status: kargoapi.PromotionStepStatusRunning,
 					},
 				},
 				&mockStepRunner{
 					name:      "error-step",
-					runResult: promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+					runResult: promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 					runErr:    errors.New("something went wrong"),
 				},
 				&mockStepRunner{
 					name:      "terminal-error-step",
-					runResult: promotion.StepResult{Status: kargoapi.PromotionPhaseErrored},
+					runResult: promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored},
 					runErr:    &promotion.TerminalError{Err: errors.New("something went wrong")},
 				},
 				&mockStepRunner{
@@ -535,7 +536,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 					runFunc: func(ctx context.Context, _ *promotion.StepContext) (promotion.StepResult, error) {
 						cancel()
 						<-ctx.Done()
-						return promotion.StepResult{Status: kargoapi.PromotionPhaseErrored}, ctx.Err()
+						return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, ctx.Err()
 					},
 				},
 			}
@@ -567,12 +568,12 @@ func TestSimpleEngine_executeStep(t *testing.T) {
 			runner: &mockStepRunner{
 				name: "success-step",
 				runResult: promotion.StepResult{
-					Status: kargoapi.PromotionPhaseSucceeded,
+					Status: kargoapi.PromotionStepStatusSucceeded,
 				},
 			},
 			assertions: func(t *testing.T, result promotion.StepResult, err error) {
 				assert.NoError(t, err)
-				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, result.Status)
 			},
 		},
 		{
@@ -581,14 +582,14 @@ func TestSimpleEngine_executeStep(t *testing.T) {
 			runner: &mockStepRunner{
 				name: "error-step",
 				runResult: promotion.StepResult{
-					Status: kargoapi.PromotionPhaseErrored,
+					Status: kargoapi.PromotionStepStatusErrored,
 				},
 				runErr: errors.New("something went wrong"),
 			},
 			assertions: func(t *testing.T, result promotion.StepResult, err error) {
 				assert.ErrorContains(t, err, "failed to run step \"error-step\"")
 				assert.ErrorContains(t, err, "something went wrong")
-				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
+				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.Status)
 			},
 		},
 	}