diff --git a/proto/policy.proto b/proto/policy.proto
index 158ec1f395c6202fbec05b273aa78d1aab99121d..fb362e0d0a730603aba29e456244a2b6b9927e22 100644
--- a/proto/policy.proto
+++ b/proto/policy.proto
@@ -50,6 +50,7 @@ message PolicyRuleId {
 
 message PolicyRuleState {
   PolicyRuleStateEnum policyRuleState = 1;
+  string policyRuleStateMessage = 2;
 }
 
 // Basic policy rule attributes
diff --git a/src/policy/src/main/java/eu/teraflow/policy/PolicyServiceImpl.java b/src/policy/src/main/java/eu/teraflow/policy/PolicyServiceImpl.java
index cc2bed0ee49cb8e7a369424bbd81969b214c5e19..44959e3da8f6d217c585b3a404bed2ba2e159670 100644
--- a/src/policy/src/main/java/eu/teraflow/policy/PolicyServiceImpl.java
+++ b/src/policy/src/main/java/eu/teraflow/policy/PolicyServiceImpl.java
@@ -66,25 +66,35 @@ public class PolicyServiceImpl implements PolicyService {
     private static final String INVALID_MESSAGE = "%s is invalid.";
     private static final String VALID_MESSAGE = "%s is valid.";
     private static final PolicyRuleState INSERTED_POLICYRULE_STATE =
-            new PolicyRuleState(PolicyRuleStateEnum.POLICY_INSERTED);
+            new PolicyRuleState(
+                    PolicyRuleStateEnum.POLICY_INSERTED, "Successfully set to INSERTED STATE");
     private static final PolicyRuleState VALIDATED_POLICYRULE_STATE =
-            new PolicyRuleState(PolicyRuleStateEnum.POLICY_VALIDATED);
-    private static final PolicyRuleState FAILED_POLICYRULE_STATE =
-            new PolicyRuleState(PolicyRuleStateEnum.POLICY_FAILED);
+            new PolicyRuleState(
+                    PolicyRuleStateEnum.POLICY_VALIDATED, "Successfully transitioned to VALIDATED STATE");
     private static final PolicyRuleState PROVISIONED_POLICYRULE_STATE =
-            new PolicyRuleState(PolicyRuleStateEnum.POLICY_PROVISIONED);
+            new PolicyRuleState(
+                    PolicyRuleStateEnum.POLICY_PROVISIONED,
+                    "Successfully transitioned from VALIDATED to PROVISIONED STATE");
     private static final PolicyRuleState ACTIVE_POLICYRULE_STATE =
-            new PolicyRuleState(PolicyRuleStateEnum.POLICY_ACTIVE);
+            new PolicyRuleState(
+                    PolicyRuleStateEnum.POLICY_ACTIVE,
+                    "Successfully transitioned from PROVISIONED to ACTIVE STATE");
     private static final PolicyRuleState ENFORCED_POLICYRULE_STATE =
-            new PolicyRuleState(PolicyRuleStateEnum.POLICY_ENFORCED);
+            new PolicyRuleState(
+                    PolicyRuleStateEnum.POLICY_ENFORCED,
+                    "Successfully transitioned from ACTIVE to ENFORCED STATE");
     private static final PolicyRuleState INEFFECTIVE_POLICYRULE_STATE =
-            new PolicyRuleState(PolicyRuleStateEnum.POLICY_INEFFECTIVE);
+            new PolicyRuleState(
+                    PolicyRuleStateEnum.POLICY_INEFFECTIVE,
+                    "Transitioned from ENFORCED to INEFFECTIVE state");
     private static final PolicyRuleState EFFECTIVE_POLICYRULE_STATE =
-            new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE);
+            new PolicyRuleState(
+                    PolicyRuleStateEnum.POLICY_EFFECTIVE,
+                    "Successfully transitioned from ENFORCED to EFFECTIVE state");
     private static final PolicyRuleState UPDATED_POLICYRULE_STATE =
-            new PolicyRuleState(PolicyRuleStateEnum.POLICY_UPDATED);
+            new PolicyRuleState(PolicyRuleStateEnum.POLICY_UPDATED, "Successfully set to UPDATED STATE");
     private static final PolicyRuleState REMOVED_POLICYRULE_STATE =
-            new PolicyRuleState(PolicyRuleStateEnum.POLICY_REMOVED);
+            new PolicyRuleState(PolicyRuleStateEnum.POLICY_REMOVED, "Successfully set to REMOVED STATE");
 
     private final ContextService contextService;
     private final MonitoringService monitoringService;
@@ -115,6 +125,10 @@ public class PolicyServiceImpl implements PolicyService {
         this.policyRuleConditionFieldsGetter = policyRuleConditionFieldsGetter;
     }
 
+    private static PolicyRuleState createFailedPolicyRuleState(String message) {
+        return new PolicyRuleState(PolicyRuleStateEnum.POLICY_FAILED, message);
+    }
+
     private static String gen() {
         Random r = new Random(System.currentTimeMillis());
         return String.valueOf((1 + r.nextInt(2)) * 10000 + r.nextInt(10000));
@@ -449,11 +463,15 @@ public class PolicyServiceImpl implements PolicyService {
     private void validateDevice(PolicyRuleDevice policyRuleDevice) {
         final var deviceIds = policyRuleDevice.getDeviceIds();
         final var policyRuleBasic = policyRuleDevice.getPolicyRuleBasic();
+        final var policyRuleId = policyRuleBasic.getPolicyRuleId();
 
         final var invalidDeviceIds = returnInvalidDeviceIds(deviceIds);
         if (!invalidDeviceIds.isEmpty()) {
-            LOGGER.infof("Setting Policy Rule state to [%s]", FAILED_POLICYRULE_STATE.toString());
-            policyRuleBasic.setPolicyRuleState(FAILED_POLICYRULE_STATE);
+            var policyRuleState =
+                    createFailedPolicyRuleState(
+                            "The Devices of PolicyRuleDevice " + policyRuleId + " are not valid");
+            LOGGER.infof("Setting Policy Rule state to [%s]", policyRuleState.toString());
+            policyRuleBasic.setPolicyRuleState(policyRuleState);
             contextService.setPolicyRule(policyRuleBasic);
             return;
         }
@@ -462,8 +480,11 @@ public class PolicyServiceImpl implements PolicyService {
                 parsePolicyRuleCondition(policyRuleDevice.getPolicyRuleBasic());
 
         if (alarmDescriptorList.isEmpty()) {
-            LOGGER.infof("Setting Policy Rule state to [%s]", FAILED_POLICYRULE_STATE.toString());
-            policyRuleBasic.setPolicyRuleState(FAILED_POLICYRULE_STATE);
+            var policyRuleState =
+                    createFailedPolicyRuleState(
+                            "The PolicyRuleConditions of PolicyRuleDevice " + policyRuleId + " are not valid");
+            LOGGER.infof("Setting Policy Rule state to [%s]", policyRuleState.toString());
+            policyRuleBasic.setPolicyRuleState(policyRuleState);
             contextService.setPolicyRule(policyRuleBasic);
             return;
         }
@@ -490,7 +511,13 @@ public class PolicyServiceImpl implements PolicyService {
                                 validateService(policyRuleService);
                                 return;
                             } else {
-                                policyRuleBasic.setPolicyRuleState(FAILED_POLICYRULE_STATE);
+                                var policyRuleState =
+                                        createFailedPolicyRuleState(
+                                                "The requested PolicyRuleService to update: "
+                                                        + policyRuleBasic.getPolicyRuleId()
+                                                        + " is not valid");
+                                LOGGER.infof("Setting Policy Rule state to [%s]", policyRuleState.toString());
+                                policyRuleBasic.setPolicyRuleState(policyRuleState);
                                 contextService.setPolicyRule(policyRuleBasic);
                                 return;
                             }
@@ -511,7 +538,13 @@ public class PolicyServiceImpl implements PolicyService {
                                 validateDevice(policyRuleDevice);
                                 return;
                             } else {
-                                policyRuleBasic.setPolicyRuleState(FAILED_POLICYRULE_STATE);
+                                var policyRuleState =
+                                        createFailedPolicyRuleState(
+                                                "The requested PolicyRuleDevice to update: "
+                                                        + policyRuleBasic.getPolicyRuleId()
+                                                        + " is not valid");
+                                LOGGER.infof("Setting Policy Rule state to [%s]", policyRuleState.toString());
+                                policyRuleBasic.setPolicyRuleState(policyRuleState);
                                 contextService.setPolicyRule(policyRuleBasic);
                                 return;
                             }
@@ -536,8 +569,13 @@ public class PolicyServiceImpl implements PolicyService {
                                 if (invalidDeviceIds.isEmpty()) {
                                     LOGGER.info("All Device Ids are valid.");
                                 }
-
-                                policyRuleBasic.setPolicyRuleState(FAILED_POLICYRULE_STATE);
+                                var policyRuleState =
+                                        createFailedPolicyRuleState(
+                                                "The Service of PolicyRuleService "
+                                                        + policyRuleBasic.getPolicyRuleId()
+                                                        + " is not valid");
+                                LOGGER.infof("Setting Policy Rule state to [%s]", policyRuleState.toString());
+                                policyRuleBasic.setPolicyRuleState(policyRuleState);
                                 contextService.setPolicyRule(policyRuleBasic);
                                 return;
                             } else {
@@ -546,7 +584,13 @@ public class PolicyServiceImpl implements PolicyService {
                                 final var invalidDeviceIds = returnInvalidDeviceIds(deviceIds);
 
                                 if (!invalidDeviceIds.isEmpty()) {
-                                    policyRuleBasic.setPolicyRuleState(FAILED_POLICYRULE_STATE);
+                                    var policyRuleState =
+                                            createFailedPolicyRuleState(
+                                                    "The Devices of PolicyRuleService "
+                                                            + policyRuleBasic.getPolicyRuleId()
+                                                            + " are not valid");
+                                    LOGGER.infof("Setting Policy Rule state to [%s]", policyRuleState.toString());
+                                    policyRuleBasic.setPolicyRuleState(policyRuleState);
                                     contextService.setPolicyRule(policyRuleBasic);
                                     return;
                                 } else {
@@ -567,8 +611,13 @@ public class PolicyServiceImpl implements PolicyService {
                 parsePolicyRuleCondition(policyRuleService.getPolicyRuleBasic());
 
         if (alarmDescriptorList.isEmpty()) {
-            LOGGER.infof("Setting Policy Rule state to [%s]", FAILED_POLICYRULE_STATE.toString());
-            policyRuleBasic.setPolicyRuleState(FAILED_POLICYRULE_STATE);
+            var policyRuleState =
+                    createFailedPolicyRuleState(
+                            "The PolicyRuleConditions of PolicyRuleDevice "
+                                    + policyRuleBasic.getPolicyRuleId()
+                                    + " are not valid");
+            LOGGER.infof("Setting Policy Rule state to [%s]", policyRuleState.toString());
+            policyRuleBasic.setPolicyRuleState(policyRuleState);
             contextService.setPolicyRule(policyRuleBasic);
             return;
         }
diff --git a/src/policy/src/main/java/eu/teraflow/policy/Serializer.java b/src/policy/src/main/java/eu/teraflow/policy/Serializer.java
index 385328730a519c3d4460cff4f22a2d3e7daaa139..3fc25ff1c15a0e734e50a6fb907800f95716e7cb 100644
--- a/src/policy/src/main/java/eu/teraflow/policy/Serializer.java
+++ b/src/policy/src/main/java/eu/teraflow/policy/Serializer.java
@@ -1379,20 +1379,23 @@ public class Serializer {
         final var builder = Policy.PolicyRuleState.newBuilder();
 
         final var ruleState = policyRuleState.getRuleState();
+        final var policyRuleStateMessage = policyRuleState.getPolicyRuleStateMessage();
 
         final var serializedRuleState = serialize(ruleState);
 
         builder.setPolicyRuleState(serializedRuleState);
+        builder.setPolicyRuleStateMessage(policyRuleStateMessage);
 
         return builder.build();
     }
 
     public PolicyRuleState deserialize(Policy.PolicyRuleState serializedPolicyRuleState) {
         final var serializedRuleState = serializedPolicyRuleState.getPolicyRuleState();
+        final var serializedRuleStateMessage = serializedPolicyRuleState.getPolicyRuleStateMessage();
 
         final var ruleState = deserialize(serializedRuleState);
 
-        return new PolicyRuleState(ruleState);
+        return new PolicyRuleState(ruleState, serializedRuleStateMessage);
     }
 
     public PolicyCondition.NumericalOperator serialize(NumericalOperator numericalOperator) {
diff --git a/src/policy/src/main/java/eu/teraflow/policy/model/PolicyRuleState.java b/src/policy/src/main/java/eu/teraflow/policy/model/PolicyRuleState.java
index 5b3d39f6ef062ea6aafa7a304fd0b937d0cadf15..29911fec8c9b46ba87a04bff67fc986620d621b1 100644
--- a/src/policy/src/main/java/eu/teraflow/policy/model/PolicyRuleState.java
+++ b/src/policy/src/main/java/eu/teraflow/policy/model/PolicyRuleState.java
@@ -19,9 +19,11 @@ package eu.teraflow.policy.model;
 public class PolicyRuleState {
 
     private PolicyRuleStateEnum policyRuleStateEnum;
+    private String policyRuleStateMessage;
 
-    public PolicyRuleState(PolicyRuleStateEnum policyRuleStateEnum) {
+    public PolicyRuleState(PolicyRuleStateEnum policyRuleStateEnum, String policyRuleStateMessage) {
         this.policyRuleStateEnum = policyRuleStateEnum;
+        this.policyRuleStateMessage = policyRuleStateMessage;
     }
 
     public void setRuleState(PolicyRuleStateEnum policyRuleStateEnum) {
@@ -32,6 +34,14 @@ public class PolicyRuleState {
         return policyRuleStateEnum;
     }
 
+    public void setPolicyRuleStateMessage(String policyRuleStateMessage) {
+        this.policyRuleStateMessage = policyRuleStateMessage;
+    }
+
+    public String getPolicyRuleStateMessage() {
+        return this.policyRuleStateMessage;
+    }
+
     @Override
     public String toString() {
         return String.format(
diff --git a/src/policy/src/test/java/eu/teraflow/policy/PolicyRuleBasicValidationTest.java b/src/policy/src/test/java/eu/teraflow/policy/PolicyRuleBasicValidationTest.java
index 43db1b00b550914bd5a83552083cf6a26ce4e1ce..e4c9f1698b79001c34a357e18a96084e7ccaae3e 100644
--- a/src/policy/src/test/java/eu/teraflow/policy/PolicyRuleBasicValidationTest.java
+++ b/src/policy/src/test/java/eu/teraflow/policy/PolicyRuleBasicValidationTest.java
@@ -83,7 +83,7 @@ class PolicyRuleBasicValidationTestHelper {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_ADD_SERVICE_CONSTRAINT,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE, "1");
 
         assertThatExceptionOfType(NullPointerException.class)
                 .isThrownBy(
@@ -109,7 +109,7 @@ class PolicyRuleBasicValidationTestHelper {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_ADD_SERVICE_CONFIGRULE,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_ENFORCED);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_ENFORCED, "1");
 
         assertThatExceptionOfType(IllegalArgumentException.class)
                 .isThrownBy(
@@ -135,7 +135,7 @@ class PolicyRuleBasicValidationTestHelper {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_NO_ACTION,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_ENFORCED);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_ENFORCED, "1");
 
         assertThatExceptionOfType(IllegalArgumentException.class)
                 .isThrownBy(
@@ -161,7 +161,7 @@ class PolicyRuleBasicValidationTestHelper {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_SET_DEVICE_STATUS,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_INSERTED);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_INSERTED, "1");
 
         final var policyRuleId = UUID.randomUUID().toString();
 
@@ -184,7 +184,7 @@ class PolicyRuleBasicValidationTestHelper {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_ADD_SERVICE_CONFIGRULE,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_ENFORCED);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_ENFORCED, "1");
 
         final var policyRuleId = UUID.randomUUID().toString();
 
@@ -208,7 +208,7 @@ class PolicyRuleBasicValidationTestHelper {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_ADD_SERVICE_CONFIGRULE,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_REMOVED);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_REMOVED, "1");
 
         final var policyRuleId = UUID.randomUUID().toString();
 
@@ -236,7 +236,7 @@ class PolicyRuleBasicValidationTestHelper {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_ADD_SERVICE_CONFIGRULE,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_VALIDATED);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_VALIDATED, "1");
 
         final var policyRuleId = UUID.randomUUID().toString();
 
@@ -260,7 +260,7 @@ class PolicyRuleBasicValidationTestHelper {
                         NumericalOperator.POLICY_RULE_CONDITION_NUMERICAL_GREATER_THAN,
                         new IntegerKpiValue(3));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_PROVISIONED);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_PROVISIONED, "1");
 
         final var policyRuleId = UUID.randomUUID().toString();
 
@@ -285,7 +285,7 @@ class PolicyRuleBasicValidationTestHelper {
                         new IntegerKpiValue(3));
         final var policyRuleActions = Collections.<PolicyRuleAction>emptyList();
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_FAILED);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_FAILED, "1");
 
         final var policyRuleId = UUID.randomUUID().toString();
 
@@ -304,7 +304,8 @@ class PolicyRuleBasicValidationTestHelper {
     @Test
     void shouldCreatePolicyRuleBasicObject() {
         final var expectedPolicyRuleId = "expectedPolicyRuleId";
-        final var expectedPolicyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE);
+        final var expectedPolicyRuleState =
+                new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE, "1");
         final var expectedPriority = 3;
 
         final var firstKpiValue = new IntegerKpiValue(22);
@@ -345,7 +346,7 @@ class PolicyRuleBasicValidationTestHelper {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_SET_DEVICE_STATUS,
                         List.of("parameter1", "parameter2"));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE, "1");
 
         final var policyRuleBasic =
                 createPolicyRuleBasic(
diff --git a/src/policy/src/test/java/eu/teraflow/policy/PolicyRuleDeviceValidationTest.java b/src/policy/src/test/java/eu/teraflow/policy/PolicyRuleDeviceValidationTest.java
index 2ea0b2586f2e53c6c69915f714519b2ba1e6173c..1913830454198290a4ada76ce4e1116b27e1fd0a 100644
--- a/src/policy/src/test/java/eu/teraflow/policy/PolicyRuleDeviceValidationTest.java
+++ b/src/policy/src/test/java/eu/teraflow/policy/PolicyRuleDeviceValidationTest.java
@@ -100,7 +100,7 @@ class PolicyRuleDeviceValidationTest {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_ADD_SERVICE_CONSTRAINT,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE, "1");
 
         final var policyRuleBasic =
                 createPolicyRuleBasic(
@@ -127,7 +127,7 @@ class PolicyRuleDeviceValidationTest {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_ADD_SERVICE_CONFIGRULE,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE, "1");
 
         final var policyRuleBasic =
                 createPolicyRuleBasic(
@@ -156,7 +156,7 @@ class PolicyRuleDeviceValidationTest {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_SET_DEVICE_STATUS,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE, "1");
 
         final var policyRuleBasic =
                 createPolicyRuleBasic(
diff --git a/src/policy/src/test/java/eu/teraflow/policy/PolicyRuleServiceValidationTest.java b/src/policy/src/test/java/eu/teraflow/policy/PolicyRuleServiceValidationTest.java
index 3e4dc4fa5d346afb69f056de035ef3c9f315c650..ffa14b2d02618d54fea3ac51b407ff230b2ae6f9 100644
--- a/src/policy/src/test/java/eu/teraflow/policy/PolicyRuleServiceValidationTest.java
+++ b/src/policy/src/test/java/eu/teraflow/policy/PolicyRuleServiceValidationTest.java
@@ -106,7 +106,7 @@ class PolicyRuleServiceValidationTest {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_ADD_SERVICE_CONSTRAINT,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE, "1");
 
         final var deviceIds = createDeviceIds();
 
@@ -137,7 +137,7 @@ class PolicyRuleServiceValidationTest {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_ADD_SERVICE_CONFIGRULE,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE, "1");
 
         final var policyRuleBasic =
                 createPolicyRuleBasic(
@@ -167,7 +167,7 @@ class PolicyRuleServiceValidationTest {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_SET_DEVICE_STATUS,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE, "1");
 
         final var policyRuleBasic =
                 createPolicyRuleBasic(
@@ -201,7 +201,7 @@ class PolicyRuleServiceValidationTest {
                         PolicyRuleActionEnum.POLICY_RULE_ACTION_ADD_SERVICE_CONSTRAINT,
                         List.of(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
 
-        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE);
+        final var policyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE, "1");
 
         final var policyRuleBasic =
                 createPolicyRuleBasic(
diff --git a/src/policy/src/test/java/eu/teraflow/policy/SerializerTest.java b/src/policy/src/test/java/eu/teraflow/policy/SerializerTest.java
index fa9ae4d3c23689c935c335062550b997fdaaa042..f829146474a3f4deb90588983c6144cb741a40ff 100644
--- a/src/policy/src/test/java/eu/teraflow/policy/SerializerTest.java
+++ b/src/policy/src/test/java/eu/teraflow/policy/SerializerTest.java
@@ -146,7 +146,8 @@ class SerializerTest {
 
     private PolicyRuleBasic createPolicyRuleBasic() {
         final var expectedPolicyRuleId = "expectedPolicyRuleId";
-        final var expectedPolicyRuleState = new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE);
+        final var expectedPolicyRuleState =
+                new PolicyRuleState(PolicyRuleStateEnum.POLICY_EFFECTIVE, "Policy was effective");
         final var expectedPriority = 3;
 
         final var firstKpiValue = new IntegerKpiValue(22);
@@ -2276,7 +2277,7 @@ class SerializerTest {
     @Test
     void shouldSerializePolicyRuleState() {
         final var expectedRuleState = PolicyRuleStateEnum.POLICY_ACTIVE;
-        final var policyRuleState = new PolicyRuleState(expectedRuleState);
+        final var policyRuleState = new PolicyRuleState(expectedRuleState, "");
 
         final var serializedRuleState = serializer.serialize(expectedRuleState);
 
@@ -2293,7 +2294,7 @@ class SerializerTest {
     @Test
     void shouldDeserializePolicyRuleState() {
         final var expectedRuleState = PolicyRuleStateEnum.POLICY_ENFORCED;
-        final var expectedPolicyRuleState = new PolicyRuleState(expectedRuleState);
+        final var expectedPolicyRuleState = new PolicyRuleState(expectedRuleState, "");
 
         final var serializedPolicyRuleState = serializer.serialize(expectedPolicyRuleState);
 
diff --git a/src/policy/target/generated-sources/grpc/policy/Policy.java b/src/policy/target/generated-sources/grpc/policy/Policy.java
index 7c0a234520a45fb0cd45b66a31b26f8c79f64889..267ef0082348ecf940bef2905560095391e83b42 100644
--- a/src/policy/target/generated-sources/grpc/policy/Policy.java
+++ b/src/policy/target/generated-sources/grpc/policy/Policy.java
@@ -926,6 +926,18 @@ public final class Policy {
      * @return The policyRuleState.
      */
     policy.Policy.PolicyRuleStateEnum getPolicyRuleState();
+
+    /**
+     * <code>string policyRuleStateMessage = 2;</code>
+     * @return The policyRuleStateMessage.
+     */
+    java.lang.String getPolicyRuleStateMessage();
+    /**
+     * <code>string policyRuleStateMessage = 2;</code>
+     * @return The bytes for policyRuleStateMessage.
+     */
+    com.google.protobuf.ByteString
+        getPolicyRuleStateMessageBytes();
   }
   /**
    * Protobuf type {@code policy.PolicyRuleState}
@@ -941,6 +953,7 @@ public final class Policy {
     }
     private PolicyRuleState() {
       policyRuleState_ = 0;
+      policyRuleStateMessage_ = "";
     }
 
     @java.lang.Override
@@ -979,6 +992,12 @@ public final class Policy {
               policyRuleState_ = rawValue;
               break;
             }
+            case 18: {
+              java.lang.String s = input.readStringRequireUtf8();
+
+              policyRuleStateMessage_ = s;
+              break;
+            }
             default: {
               if (!parseUnknownField(
                   input, unknownFields, extensionRegistry, tag)) {
@@ -1030,6 +1049,44 @@ public final class Policy {
       return result == null ? policy.Policy.PolicyRuleStateEnum.UNRECOGNIZED : result;
     }
 
+    public static final int POLICYRULESTATEMESSAGE_FIELD_NUMBER = 2;
+    private volatile java.lang.Object policyRuleStateMessage_;
+    /**
+     * <code>string policyRuleStateMessage = 2;</code>
+     * @return The policyRuleStateMessage.
+     */
+    @java.lang.Override
+    public java.lang.String getPolicyRuleStateMessage() {
+      java.lang.Object ref = policyRuleStateMessage_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        policyRuleStateMessage_ = s;
+        return s;
+      }
+    }
+    /**
+     * <code>string policyRuleStateMessage = 2;</code>
+     * @return The bytes for policyRuleStateMessage.
+     */
+    @java.lang.Override
+    public com.google.protobuf.ByteString
+        getPolicyRuleStateMessageBytes() {
+      java.lang.Object ref = policyRuleStateMessage_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        policyRuleStateMessage_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
     private byte memoizedIsInitialized = -1;
     @java.lang.Override
     public final boolean isInitialized() {
@@ -1047,6 +1104,9 @@ public final class Policy {
       if (policyRuleState_ != policy.Policy.PolicyRuleStateEnum.POLICY_UNDEFINED.getNumber()) {
         output.writeEnum(1, policyRuleState_);
       }
+      if (!getPolicyRuleStateMessageBytes().isEmpty()) {
+        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, policyRuleStateMessage_);
+      }
       unknownFields.writeTo(output);
     }
 
@@ -1060,6 +1120,9 @@ public final class Policy {
         size += com.google.protobuf.CodedOutputStream
           .computeEnumSize(1, policyRuleState_);
       }
+      if (!getPolicyRuleStateMessageBytes().isEmpty()) {
+        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, policyRuleStateMessage_);
+      }
       size += unknownFields.getSerializedSize();
       memoizedSize = size;
       return size;
@@ -1076,6 +1139,8 @@ public final class Policy {
       policy.Policy.PolicyRuleState other = (policy.Policy.PolicyRuleState) obj;
 
       if (policyRuleState_ != other.policyRuleState_) return false;
+      if (!getPolicyRuleStateMessage()
+          .equals(other.getPolicyRuleStateMessage())) return false;
       if (!unknownFields.equals(other.unknownFields)) return false;
       return true;
     }
@@ -1089,6 +1154,8 @@ public final class Policy {
       hash = (19 * hash) + getDescriptor().hashCode();
       hash = (37 * hash) + POLICYRULESTATE_FIELD_NUMBER;
       hash = (53 * hash) + policyRuleState_;
+      hash = (37 * hash) + POLICYRULESTATEMESSAGE_FIELD_NUMBER;
+      hash = (53 * hash) + getPolicyRuleStateMessage().hashCode();
       hash = (29 * hash) + unknownFields.hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -1224,6 +1291,8 @@ public final class Policy {
         super.clear();
         policyRuleState_ = 0;
 
+        policyRuleStateMessage_ = "";
+
         return this;
       }
 
@@ -1251,6 +1320,7 @@ public final class Policy {
       public policy.Policy.PolicyRuleState buildPartial() {
         policy.Policy.PolicyRuleState result = new policy.Policy.PolicyRuleState(this);
         result.policyRuleState_ = policyRuleState_;
+        result.policyRuleStateMessage_ = policyRuleStateMessage_;
         onBuilt();
         return result;
       }
@@ -1302,6 +1372,10 @@ public final class Policy {
         if (other.policyRuleState_ != 0) {
           setPolicyRuleStateValue(other.getPolicyRuleStateValue());
         }
+        if (!other.getPolicyRuleStateMessage().isEmpty()) {
+          policyRuleStateMessage_ = other.policyRuleStateMessage_;
+          onChanged();
+        }
         this.mergeUnknownFields(other.unknownFields);
         onChanged();
         return this;
@@ -1384,6 +1458,82 @@ public final class Policy {
         onChanged();
         return this;
       }
+
+      private java.lang.Object policyRuleStateMessage_ = "";
+      /**
+       * <code>string policyRuleStateMessage = 2;</code>
+       * @return The policyRuleStateMessage.
+       */
+      public java.lang.String getPolicyRuleStateMessage() {
+        java.lang.Object ref = policyRuleStateMessage_;
+        if (!(ref instanceof java.lang.String)) {
+          com.google.protobuf.ByteString bs =
+              (com.google.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          policyRuleStateMessage_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>string policyRuleStateMessage = 2;</code>
+       * @return The bytes for policyRuleStateMessage.
+       */
+      public com.google.protobuf.ByteString
+          getPolicyRuleStateMessageBytes() {
+        java.lang.Object ref = policyRuleStateMessage_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          policyRuleStateMessage_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>string policyRuleStateMessage = 2;</code>
+       * @param value The policyRuleStateMessage to set.
+       * @return This builder for chaining.
+       */
+      public Builder setPolicyRuleStateMessage(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  
+        policyRuleStateMessage_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>string policyRuleStateMessage = 2;</code>
+       * @return This builder for chaining.
+       */
+      public Builder clearPolicyRuleStateMessage() {
+        
+        policyRuleStateMessage_ = getDefaultInstance().getPolicyRuleStateMessage();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>string policyRuleStateMessage = 2;</code>
+       * @param value The bytes for policyRuleStateMessage to set.
+       * @return This builder for chaining.
+       */
+      public Builder setPolicyRuleStateMessageBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+        
+        policyRuleStateMessage_ = value;
+        onChanged();
+        return this;
+      }
       @java.lang.Override
       public final Builder setUnknownFields(
           final com.google.protobuf.UnknownFieldSet unknownFields) {
@@ -9389,51 +9539,52 @@ public final class Policy {
       "\n\014policy.proto\022\006policy\032\rcontext.proto\032\026p" +
       "olicy_condition.proto\032\023policy_action.pro" +
       "to\"+\n\014PolicyRuleId\022\033\n\004uuid\030\001 \001(\0132\r.conte" +
-      "xt.Uuid\"G\n\017PolicyRuleState\0224\n\017policyRule" +
+      "xt.Uuid\"g\n\017PolicyRuleState\0224\n\017policyRule" +
       "State\030\001 \001(\0162\033.policy.PolicyRuleStateEnum" +
-      "\"\225\002\n\017PolicyRuleBasic\022*\n\014policyRuleId\030\001 \001" +
-      "(\0132\024.policy.PolicyRuleId\0220\n\017policyRuleSt" +
-      "ate\030\002 \001(\0132\027.policy.PolicyRuleState\022\020\n\010pr" +
-      "iority\030\003 \001(\r\0222\n\rconditionList\030\004 \003(\0132\033.po" +
-      "licy.PolicyRuleCondition\0220\n\017booleanOpera" +
-      "tor\030\005 \001(\0162\027.policy.BooleanOperator\022,\n\nac" +
-      "tionList\030\006 \003(\0132\030.policy.PolicyRuleAction" +
-      "\"\223\001\n\021PolicyRuleService\0220\n\017policyRuleBasi" +
-      "c\030\001 \001(\0132\027.policy.PolicyRuleBasic\022%\n\tserv" +
-      "iceId\030\002 \001(\0132\022.context.ServiceId\022%\n\ndevic" +
-      "eList\030\003 \003(\0132\021.context.DeviceId\"k\n\020Policy" +
-      "RuleDevice\0220\n\017policyRuleBasic\030\001 \001(\0132\027.po" +
-      "licy.PolicyRuleBasic\022%\n\ndeviceList\030\002 \003(\013" +
-      "2\021.context.DeviceId\"B\n\020PolicyRuleIdList\022" +
-      ".\n\020policyRuleIdList\030\001 \003(\0132\024.policy.Polic" +
-      "yRuleId\"Q\n\025PolicyRuleServiceList\0228\n\025poli" +
-      "cyRuleServiceList\030\001 \003(\0132\031.policy.PolicyR" +
-      "uleService\"N\n\024PolicyRuleDeviceList\0226\n\024po" +
-      "licyRuleDeviceList\030\001 \003(\0132\030.policy.Policy" +
-      "RuleDevice\";\n\016PolicyRuleList\022)\n\013policyRu" +
-      "les\030\001 \003(\0132\024.policy.PolicyRuleId*\377\001\n\023Poli" +
-      "cyRuleStateEnum\022\024\n\020POLICY_UNDEFINED\020\000\022\021\n" +
-      "\rPOLICY_FAILED\020\001\022\023\n\017POLICY_INSERTED\020\002\022\024\n" +
-      "\020POLICY_VALIDATED\020\003\022\026\n\022POLICY_PROVISIONE" +
-      "D\020\004\022\021\n\rPOLICY_ACTIVE\020\005\022\023\n\017POLICY_ENFORCE" +
-      "D\020\006\022\026\n\022POLICY_INEFFECTIVE\020\007\022\024\n\020POLICY_EF" +
-      "FECTIVE\020\010\022\022\n\016POLICY_UPDATED\020\t\022\022\n\016POLICY_" +
-      "REMOVED\020\n2\323\004\n\rPolicyService\022H\n\020PolicyAdd" +
-      "Service\022\031.policy.PolicyRuleService\032\027.pol" +
-      "icy.PolicyRuleState\"\000\022F\n\017PolicyAddDevice" +
-      "\022\030.policy.PolicyRuleDevice\032\027.policy.Poli" +
-      "cyRuleState\"\000\022K\n\023PolicyUpdateService\022\031.p" +
-      "olicy.PolicyRuleService\032\027.policy.PolicyR" +
-      "uleState\"\000\022I\n\022PolicyUpdateDevice\022\030.polic" +
+      "\022\036\n\026policyRuleStateMessage\030\002 \001(\t\"\225\002\n\017Pol" +
+      "icyRuleBasic\022*\n\014policyRuleId\030\001 \001(\0132\024.pol" +
+      "icy.PolicyRuleId\0220\n\017policyRuleState\030\002 \001(" +
+      "\0132\027.policy.PolicyRuleState\022\020\n\010priority\030\003" +
+      " \001(\r\0222\n\rconditionList\030\004 \003(\0132\033.policy.Pol" +
+      "icyRuleCondition\0220\n\017booleanOperator\030\005 \001(" +
+      "\0162\027.policy.BooleanOperator\022,\n\nactionList" +
+      "\030\006 \003(\0132\030.policy.PolicyRuleAction\"\223\001\n\021Pol" +
+      "icyRuleService\0220\n\017policyRuleBasic\030\001 \001(\0132" +
+      "\027.policy.PolicyRuleBasic\022%\n\tserviceId\030\002 " +
+      "\001(\0132\022.context.ServiceId\022%\n\ndeviceList\030\003 " +
+      "\003(\0132\021.context.DeviceId\"k\n\020PolicyRuleDevi" +
+      "ce\0220\n\017policyRuleBasic\030\001 \001(\0132\027.policy.Pol" +
+      "icyRuleBasic\022%\n\ndeviceList\030\002 \003(\0132\021.conte" +
+      "xt.DeviceId\"B\n\020PolicyRuleIdList\022.\n\020polic" +
+      "yRuleIdList\030\001 \003(\0132\024.policy.PolicyRuleId\"" +
+      "Q\n\025PolicyRuleServiceList\0228\n\025policyRuleSe" +
+      "rviceList\030\001 \003(\0132\031.policy.PolicyRuleServi" +
+      "ce\"N\n\024PolicyRuleDeviceList\0226\n\024policyRule" +
+      "DeviceList\030\001 \003(\0132\030.policy.PolicyRuleDevi" +
+      "ce\";\n\016PolicyRuleList\022)\n\013policyRules\030\001 \003(" +
+      "\0132\024.policy.PolicyRuleId*\377\001\n\023PolicyRuleSt" +
+      "ateEnum\022\024\n\020POLICY_UNDEFINED\020\000\022\021\n\rPOLICY_" +
+      "FAILED\020\001\022\023\n\017POLICY_INSERTED\020\002\022\024\n\020POLICY_" +
+      "VALIDATED\020\003\022\026\n\022POLICY_PROVISIONED\020\004\022\021\n\rP" +
+      "OLICY_ACTIVE\020\005\022\023\n\017POLICY_ENFORCED\020\006\022\026\n\022P" +
+      "OLICY_INEFFECTIVE\020\007\022\024\n\020POLICY_EFFECTIVE\020" +
+      "\010\022\022\n\016POLICY_UPDATED\020\t\022\022\n\016POLICY_REMOVED\020" +
+      "\n2\323\004\n\rPolicyService\022H\n\020PolicyAddService\022" +
+      "\031.policy.PolicyRuleService\032\027.policy.Poli" +
+      "cyRuleState\"\000\022F\n\017PolicyAddDevice\022\030.polic" +
       "y.PolicyRuleDevice\032\027.policy.PolicyRuleSt" +
-      "ate\"\000\022?\n\014PolicyDelete\022\024.policy.PolicyRul" +
-      "eId\032\027.policy.PolicyRuleState\"\000\022E\n\020GetPol" +
-      "icyService\022\024.policy.PolicyRuleId\032\031.polic" +
-      "y.PolicyRuleService\"\000\022C\n\017GetPolicyDevice" +
-      "\022\024.policy.PolicyRuleId\032\030.policy.PolicyRu" +
-      "leDevice\"\000\022K\n\024GetPolicyByServiceId\022\022.con" +
-      "text.ServiceId\032\035.policy.PolicyRuleServic" +
-      "eList\"\000b\006proto3"
+      "ate\"\000\022K\n\023PolicyUpdateService\022\031.policy.Po" +
+      "licyRuleService\032\027.policy.PolicyRuleState" +
+      "\"\000\022I\n\022PolicyUpdateDevice\022\030.policy.Policy" +
+      "RuleDevice\032\027.policy.PolicyRuleState\"\000\022?\n" +
+      "\014PolicyDelete\022\024.policy.PolicyRuleId\032\027.po" +
+      "licy.PolicyRuleState\"\000\022E\n\020GetPolicyServi" +
+      "ce\022\024.policy.PolicyRuleId\032\031.policy.Policy" +
+      "RuleService\"\000\022C\n\017GetPolicyDevice\022\024.polic" +
+      "y.PolicyRuleId\032\030.policy.PolicyRuleDevice" +
+      "\"\000\022K\n\024GetPolicyByServiceId\022\022.context.Ser" +
+      "viceId\032\035.policy.PolicyRuleServiceList\"\000b" +
+      "\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
@@ -9453,7 +9604,7 @@ public final class Policy {
     internal_static_policy_PolicyRuleState_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_policy_PolicyRuleState_descriptor,
-        new java.lang.String[] { "PolicyRuleState", });
+        new java.lang.String[] { "PolicyRuleState", "PolicyRuleStateMessage", });
     internal_static_policy_PolicyRuleBasic_descriptor =
       getDescriptor().getMessageTypes().get(2);
     internal_static_policy_PolicyRuleBasic_fieldAccessorTable = new