diff --git a/templates/gitlab-ci-docker.yml b/templates/gitlab-ci-docker.yml
index 83076d5a00ac1daa11e14e526ea50e2a9e869826..07881824666adfa576361b4daccd68ce0703cc84 100644
--- a/templates/gitlab-ci-docker.yml
+++ b/templates/gitlab-ci-docker.yml
@@ -13,14 +13,33 @@
 # program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth 
 # Floor, Boston, MA  02110-1301, USA.
 # =========================================================================================
-# default workflow rules
+# default workflow rules: Merge Request pipelines
 workflow:
   rules:
-    # exclude merge requests
-    - if: $CI_MERGE_REQUEST_ID
+    # prevent branch pipeline when an MR is open (prefer MR pipeline)
+    - if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
       when: never
     - when: always
 
+# test job prototype: implement adaptive pipeline rules
+.test-policy:
+  rules:
+    # on tag: auto & failing
+    - if: $CI_COMMIT_TAG
+    # on ADAPTIVE_PIPELINE_DISABLED: auto & failing
+    - if: '$ADAPTIVE_PIPELINE_DISABLED == "true"'
+    # on production or integration branch(es): auto & failing
+    - if: '$CI_COMMIT_REF_NAME =~ $PROD_REF || $CI_COMMIT_REF_NAME =~ $INTEG_REF'
+    # early stage (dev branch, no MR): manual & non-failing
+    - if: '$CI_MERGE_REQUEST_ID == null && $CI_OPEN_MERGE_REQUESTS == null'
+      when: manual
+      allow_failure: true
+    # Draft MR: auto & non-failing
+    - if: '$CI_MERGE_REQUEST_TITLE =~ /^Draft:.*/'
+      allow_failure: true
+    # else (Ready MR): auto & failing
+    - when: on_success
+
 variables:
   # variabilized tracking image
   TBC_TRACKING_IMAGE: "$CI_REGISTRY/to-be-continuous/tools/tracking:master"
@@ -431,12 +450,10 @@ docker-lint:
   script:
     - dockerfile_lint -f $DOCKER_FILE $DOCKER_LINT_ARGS
   rules:
-    # execute if DOCKER_LINT_ENABLED set
-    # on production or integration branches: 
-    - if: '$DOCKER_LINT_ENABLED == "true" && ($CI_COMMIT_REF_NAME =~ $PROD_REF || $CI_COMMIT_REF_NAME =~ $INTEG_REF)'
-    # else (development branches): allow failure
-    - if: '$DOCKER_LINT_ENABLED == "true"'
-      allow_failure: true
+    # disable if DOCKER_LINT_ENABLED not set
+    - if: '$DOCKER_LINT_ENABLED != "true"'
+      when: never
+    - !reference [.test-policy, rules]
 
 docker-hadolint:
   image:
@@ -469,16 +486,11 @@ docker-hadolint:
     # exclude if DOCKER_HADOLINT_DISABLED set
     - if: '$DOCKER_HADOLINT_DISABLED == "true"'
       when: never
-    # on production or integration branches: auto
-    - if: '$CI_COMMIT_REF_NAME =~ $PROD_REF || $CI_COMMIT_REF_NAME =~ $INTEG_REF'
-    # else (development branches): allow failure
-    - allow_failure: true
-
+    - !reference [.test-policy, rules]
 
 # ==================================================
 # Stage: package-build
 # ==================================================
-
 docker-kaniko-build:
   extends: .docker-kaniko-base
   stage: package-build
@@ -594,8 +606,9 @@ docker-healthcheck:
   rules:
     - if: '$DOCKER_HEALTHCHECK_DISABLED == "true"'
       when: never
-    - if: $DOCKER_DIND_BUILD
-
+    - if: '$DOCKER_DIND_BUILD == null || $DOCKER_DIND_BUILD == ""'
+      when: never
+    - !reference [.test-policy, rules]
 
 # Security audit with trivy
 # This is a non-blocking job, it will always return (code) 0
@@ -641,15 +654,11 @@ docker-trivy:
   rules:
     - if: '$DOCKER_TRIVY_DISABLED == "true"'
       when: never
-    - if: '($CI_COMMIT_REF_NAME =~ $PROD_REF || $CI_COMMIT_REF_NAME =~ $INTEG_REF)'
-    # allow failure on development branches:
-    - allow_failure: true
-
+    - !reference [.test-policy, rules]
 
 # ==================================================
 # Stage: publish
 # ==================================================
-
 # This stage only run when you put a new tag to the git repository (a good tag format would be x.x.x ex: 1.0.2, see https://semver.org/)
 # It will push the release tagged image to the chosen Registry
 docker-publish: